diff --git a/sources/.htaccess b/sources/.htaccess new file mode 100644 index 00000000..7f393511 --- /dev/null +++ b/sources/.htaccess @@ -0,0 +1,30 @@ +Options -Indexes +AddType application/x-java-archive .jar +AddType audio/ogg .oga +#SSLCipherSuite HIGH:AES256-SHA:AES128-SHA:RC4:!aNULL:!eNULL:!EDH + +# don't allow any web access to logfiles, even after rotation/compression + + + Require all denied + + + Order deny,allow + Deny from all + + + + + RewriteEngine on + # Protect repository directory from browsing + RewriteRule "(^|/)\.git" - [F] + RewriteRule "(^|/)store" - [F] + + # Rewrite current-style URLs of the form 'index.php?q=x'. + # Also place auth information into REMOTE_USER for sites running + # in CGI mode. + + RewriteCond %{REQUEST_FILENAME} !-f + RewriteCond %{REQUEST_FILENAME} !-d + RewriteRule ^(.*)$ index.php?q=$1 [E=REMOTE_USER:%{HTTP:Authorization},L,QSA] + diff --git a/sources/LICENSE b/sources/LICENSE new file mode 100644 index 00000000..40cc07bb --- /dev/null +++ b/sources/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2010-2015 Hubzilla +All rights reserved. + +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/sources/README.md b/sources/README.md new file mode 100644 index 00000000..ac62f721 --- /dev/null +++ b/sources/README.md @@ -0,0 +1,39 @@ + +Hubzilla +======== + +###Websites. Redefined. + + +![Hubzilla](images/ghash-32.png) + +**What are Hubs?** + +Hubs are independent general-purpose websites that not only connect with their associated members and viewers, but also connect together to exchange personal communications and other information with each other. +This allows hub members on any hub to securely and privately share anything; with anybody, on any hub - anywhere; or share stuff publicly with anybody on the internet if desired. + +**Hubzilla** is the server software which makes this possible. It is a sophisticated and unique combination of an open source content management system and a decentralised identity, communications, and permissions framework and protocol suite, built using common webserver technology (PHP/MySQL/Apache, although Mariadb or Postgres and Nginx could also be used - we're pretty easy). The end result is a level of systems integration, privacy control, and communications features that you wouldn't think are possible in either a content management system or a decentralised communications network. It also brings a new level of cooperation and privacy to the web and introduces the concept of personally owned "single sign-on" to web services across the entire internet. + +Hubzilla hubs are + +* decentralised +* inherently social +* optionally inter-networked with other hubs +* privacy-enabled (privacy exclusions work across the entire internet to any registered identity on any compatible hubs) + +Possible website applications include + +* decentralised social networking nodes +* personal cloud storage +* file dropboxes +* managing organisational communications and activities +* collaboration and community decision-making +* small business websites +* public and private media/file libraries +* blogs +* event promotion +* feed aggregation and republishing +* forums +* dating websites +* pretty much anything you can do on a traditional blog or community website, but that you could do better if you could easily connect it with other websites or privately share things across website boundaries. + diff --git a/sources/addon/adultphotoflag b/sources/addon/adultphotoflag new file mode 120000 index 00000000..33607d83 --- /dev/null +++ b/sources/addon/adultphotoflag @@ -0,0 +1 @@ +../extend/addon/matrix/adultphotoflag \ No newline at end of file diff --git a/sources/addon/bbmath b/sources/addon/bbmath new file mode 120000 index 00000000..86ee3399 --- /dev/null +++ b/sources/addon/bbmath @@ -0,0 +1 @@ +../extend/addon/matrix/bbmath \ No newline at end of file diff --git a/sources/addon/bookmarker b/sources/addon/bookmarker new file mode 120000 index 00000000..261dacde --- /dev/null +++ b/sources/addon/bookmarker @@ -0,0 +1 @@ +../extend/addon/matrix/bookmarker \ No newline at end of file diff --git a/sources/addon/buglink b/sources/addon/buglink new file mode 120000 index 00000000..2f80f00f --- /dev/null +++ b/sources/addon/buglink @@ -0,0 +1 @@ +../extend/addon/matrix/buglink \ No newline at end of file diff --git a/sources/addon/calc b/sources/addon/calc new file mode 120000 index 00000000..9a1a36ec --- /dev/null +++ b/sources/addon/calc @@ -0,0 +1 @@ +../extend/addon/matrix/calc \ No newline at end of file diff --git a/sources/addon/chords b/sources/addon/chords new file mode 120000 index 00000000..c6304590 --- /dev/null +++ b/sources/addon/chords @@ -0,0 +1 @@ +../extend/addon/matrix/chords \ No newline at end of file diff --git a/sources/addon/custom_home b/sources/addon/custom_home new file mode 120000 index 00000000..8a28b982 --- /dev/null +++ b/sources/addon/custom_home @@ -0,0 +1 @@ +../extend/addon/matrix/custom_home \ No newline at end of file diff --git a/sources/addon/diaspora b/sources/addon/diaspora new file mode 120000 index 00000000..fa8d50c9 --- /dev/null +++ b/sources/addon/diaspora @@ -0,0 +1 @@ +../extend/addon/matrix/diaspora \ No newline at end of file diff --git a/sources/addon/diaspost b/sources/addon/diaspost new file mode 120000 index 00000000..d846a76c --- /dev/null +++ b/sources/addon/diaspost @@ -0,0 +1 @@ +../extend/addon/matrix/diaspost \ No newline at end of file diff --git a/sources/addon/dirstats b/sources/addon/dirstats new file mode 120000 index 00000000..06de79c6 --- /dev/null +++ b/sources/addon/dirstats @@ -0,0 +1 @@ +../extend/addon/matrix/dirstats \ No newline at end of file diff --git a/sources/addon/donate b/sources/addon/donate new file mode 120000 index 00000000..3081929f --- /dev/null +++ b/sources/addon/donate @@ -0,0 +1 @@ +../extend/addon/matrix/donate \ No newline at end of file diff --git a/sources/addon/dwpost b/sources/addon/dwpost new file mode 120000 index 00000000..b662c5bb --- /dev/null +++ b/sources/addon/dwpost @@ -0,0 +1 @@ +../extend/addon/matrix/dwpost \ No newline at end of file diff --git a/sources/addon/embedly b/sources/addon/embedly new file mode 120000 index 00000000..5963a57e --- /dev/null +++ b/sources/addon/embedly @@ -0,0 +1 @@ +../extend/addon/matrix/embedly \ No newline at end of file diff --git a/sources/addon/extcron b/sources/addon/extcron new file mode 120000 index 00000000..2d02ef89 --- /dev/null +++ b/sources/addon/extcron @@ -0,0 +1 @@ +../extend/addon/matrix/extcron \ No newline at end of file diff --git a/sources/addon/flattrwidget b/sources/addon/flattrwidget new file mode 120000 index 00000000..8f227dec --- /dev/null +++ b/sources/addon/flattrwidget @@ -0,0 +1 @@ +../extend/addon/matrix/flattrwidget \ No newline at end of file diff --git a/sources/addon/fortunate b/sources/addon/fortunate new file mode 120000 index 00000000..9a51f156 --- /dev/null +++ b/sources/addon/fortunate @@ -0,0 +1 @@ +../extend/addon/matrix/fortunate \ No newline at end of file diff --git a/sources/addon/frphotos b/sources/addon/frphotos new file mode 120000 index 00000000..55d3abd8 --- /dev/null +++ b/sources/addon/frphotos @@ -0,0 +1 @@ +../extend/addon/matrix/frphotos \ No newline at end of file diff --git a/sources/addon/hexit b/sources/addon/hexit new file mode 120000 index 00000000..1c2ccebe --- /dev/null +++ b/sources/addon/hexit @@ -0,0 +1 @@ +../extend/addon/matrix/hexit \ No newline at end of file diff --git a/sources/addon/ijpost b/sources/addon/ijpost new file mode 120000 index 00000000..3ec48761 --- /dev/null +++ b/sources/addon/ijpost @@ -0,0 +1 @@ +../extend/addon/matrix/ijpost \ No newline at end of file diff --git a/sources/addon/irc b/sources/addon/irc new file mode 120000 index 00000000..22c5bb8e --- /dev/null +++ b/sources/addon/irc @@ -0,0 +1 @@ +../extend/addon/matrix/irc \ No newline at end of file diff --git a/sources/addon/jappixmini b/sources/addon/jappixmini new file mode 120000 index 00000000..8c035194 --- /dev/null +++ b/sources/addon/jappixmini @@ -0,0 +1 @@ +../extend/addon/matrix/jappixmini \ No newline at end of file diff --git a/sources/addon/js_upload b/sources/addon/js_upload new file mode 120000 index 00000000..49d474bc --- /dev/null +++ b/sources/addon/js_upload @@ -0,0 +1 @@ +../extend/addon/matrix/js_upload \ No newline at end of file diff --git a/sources/addon/ldapauth b/sources/addon/ldapauth new file mode 120000 index 00000000..3ca0d37b --- /dev/null +++ b/sources/addon/ldapauth @@ -0,0 +1 @@ +../extend/addon/matrix/ldapauth \ No newline at end of file diff --git a/sources/addon/libertree b/sources/addon/libertree new file mode 120000 index 00000000..7b5bbdf2 --- /dev/null +++ b/sources/addon/libertree @@ -0,0 +1 @@ +../extend/addon/matrix/libertree \ No newline at end of file diff --git a/sources/addon/likebanner b/sources/addon/likebanner new file mode 120000 index 00000000..7e971707 --- /dev/null +++ b/sources/addon/likebanner @@ -0,0 +1 @@ +../extend/addon/matrix/likebanner \ No newline at end of file diff --git a/sources/addon/ljpost b/sources/addon/ljpost new file mode 120000 index 00000000..55a53bc7 --- /dev/null +++ b/sources/addon/ljpost @@ -0,0 +1 @@ +../extend/addon/matrix/ljpost \ No newline at end of file diff --git a/sources/addon/mahjongg b/sources/addon/mahjongg new file mode 120000 index 00000000..0d6939f0 --- /dev/null +++ b/sources/addon/mahjongg @@ -0,0 +1 @@ +../extend/addon/matrix/mahjongg \ No newline at end of file diff --git a/sources/addon/mailhost b/sources/addon/mailhost new file mode 120000 index 00000000..fcfe7066 --- /dev/null +++ b/sources/addon/mailhost @@ -0,0 +1 @@ +../extend/addon/matrix/mailhost \ No newline at end of file diff --git a/sources/addon/morechoice b/sources/addon/morechoice new file mode 120000 index 00000000..b91fbcae --- /dev/null +++ b/sources/addon/morechoice @@ -0,0 +1 @@ +../extend/addon/matrix/morechoice \ No newline at end of file diff --git a/sources/addon/moremoods b/sources/addon/moremoods new file mode 120000 index 00000000..565a7690 --- /dev/null +++ b/sources/addon/moremoods @@ -0,0 +1 @@ +../extend/addon/matrix/moremoods \ No newline at end of file diff --git a/sources/addon/nofed b/sources/addon/nofed new file mode 120000 index 00000000..587029da --- /dev/null +++ b/sources/addon/nofed @@ -0,0 +1 @@ +../extend/addon/matrix/nofed \ No newline at end of file diff --git a/sources/addon/nsabait b/sources/addon/nsabait new file mode 120000 index 00000000..8f56590c --- /dev/null +++ b/sources/addon/nsabait @@ -0,0 +1 @@ +../extend/addon/matrix/nsabait \ No newline at end of file diff --git a/sources/addon/nsfw b/sources/addon/nsfw new file mode 120000 index 00000000..298fbb78 --- /dev/null +++ b/sources/addon/nsfw @@ -0,0 +1 @@ +../extend/addon/matrix/nsfw \ No newline at end of file diff --git a/sources/addon/openclipatar b/sources/addon/openclipatar new file mode 120000 index 00000000..32884213 --- /dev/null +++ b/sources/addon/openclipatar @@ -0,0 +1 @@ +../extend/addon/matrix/openclipatar \ No newline at end of file diff --git a/sources/addon/openstreetmap b/sources/addon/openstreetmap new file mode 120000 index 00000000..db03b9df --- /dev/null +++ b/sources/addon/openstreetmap @@ -0,0 +1 @@ +../extend/addon/matrix/openstreetmap \ No newline at end of file diff --git a/sources/addon/piwik b/sources/addon/piwik new file mode 120000 index 00000000..302a0298 --- /dev/null +++ b/sources/addon/piwik @@ -0,0 +1 @@ +../extend/addon/matrix/piwik \ No newline at end of file diff --git a/sources/addon/planets b/sources/addon/planets new file mode 120000 index 00000000..40fec349 --- /dev/null +++ b/sources/addon/planets @@ -0,0 +1 @@ +../extend/addon/matrix/planets \ No newline at end of file diff --git a/sources/addon/pumpio b/sources/addon/pumpio new file mode 120000 index 00000000..0c304c4f --- /dev/null +++ b/sources/addon/pumpio @@ -0,0 +1 @@ +../extend/addon/matrix/pumpio \ No newline at end of file diff --git a/sources/addon/qrator b/sources/addon/qrator new file mode 120000 index 00000000..8aa7e9b0 --- /dev/null +++ b/sources/addon/qrator @@ -0,0 +1 @@ +../extend/addon/matrix/qrator \ No newline at end of file diff --git a/sources/addon/rainbowtag b/sources/addon/rainbowtag new file mode 120000 index 00000000..492850e4 --- /dev/null +++ b/sources/addon/rainbowtag @@ -0,0 +1 @@ +../extend/addon/matrix/rainbowtag \ No newline at end of file diff --git a/sources/addon/randpost b/sources/addon/randpost new file mode 120000 index 00000000..4cd3e6e8 --- /dev/null +++ b/sources/addon/randpost @@ -0,0 +1 @@ +../extend/addon/matrix/randpost \ No newline at end of file diff --git a/sources/addon/redphotos b/sources/addon/redphotos new file mode 120000 index 00000000..93fa601a --- /dev/null +++ b/sources/addon/redphotos @@ -0,0 +1 @@ +../extend/addon/matrix/redphotos \ No newline at end of file diff --git a/sources/addon/redred b/sources/addon/redred new file mode 120000 index 00000000..3b7076b3 --- /dev/null +++ b/sources/addon/redred @@ -0,0 +1 @@ +../extend/addon/matrix/redred \ No newline at end of file diff --git a/sources/addon/rtof b/sources/addon/rtof new file mode 120000 index 00000000..77eb18b9 --- /dev/null +++ b/sources/addon/rtof @@ -0,0 +1 @@ +../extend/addon/matrix/rtof \ No newline at end of file diff --git a/sources/addon/sendzid b/sources/addon/sendzid new file mode 120000 index 00000000..0c4087fa --- /dev/null +++ b/sources/addon/sendzid @@ -0,0 +1 @@ +../extend/addon/matrix/sendzid \ No newline at end of file diff --git a/sources/addon/smiley_pack b/sources/addon/smiley_pack new file mode 120000 index 00000000..861a674f --- /dev/null +++ b/sources/addon/smiley_pack @@ -0,0 +1 @@ +../extend/addon/matrix/smiley_pack \ No newline at end of file diff --git a/sources/addon/smileybutton b/sources/addon/smileybutton new file mode 120000 index 00000000..59940c4f --- /dev/null +++ b/sources/addon/smileybutton @@ -0,0 +1 @@ +../extend/addon/matrix/smileybutton \ No newline at end of file diff --git a/sources/addon/startpage b/sources/addon/startpage new file mode 120000 index 00000000..63cd7668 --- /dev/null +++ b/sources/addon/startpage @@ -0,0 +1 @@ +../extend/addon/matrix/startpage \ No newline at end of file diff --git a/sources/addon/statistics_json b/sources/addon/statistics_json new file mode 120000 index 00000000..2f7b9159 --- /dev/null +++ b/sources/addon/statistics_json @@ -0,0 +1 @@ +../extend/addon/matrix/statistics_json \ No newline at end of file diff --git a/sources/addon/statusnet b/sources/addon/statusnet new file mode 120000 index 00000000..d0006418 --- /dev/null +++ b/sources/addon/statusnet @@ -0,0 +1 @@ +../extend/addon/matrix/statusnet \ No newline at end of file diff --git a/sources/addon/superblock b/sources/addon/superblock new file mode 120000 index 00000000..bf1e746f --- /dev/null +++ b/sources/addon/superblock @@ -0,0 +1 @@ +../extend/addon/matrix/superblock \ No newline at end of file diff --git a/sources/addon/tictac b/sources/addon/tictac new file mode 120000 index 00000000..a8c9ac94 --- /dev/null +++ b/sources/addon/tictac @@ -0,0 +1 @@ +../extend/addon/matrix/tictac \ No newline at end of file diff --git a/sources/addon/torch b/sources/addon/torch new file mode 120000 index 00000000..575d236e --- /dev/null +++ b/sources/addon/torch @@ -0,0 +1 @@ +../extend/addon/matrix/torch \ No newline at end of file diff --git a/sources/addon/tour b/sources/addon/tour new file mode 120000 index 00000000..39fef8f0 --- /dev/null +++ b/sources/addon/tour @@ -0,0 +1 @@ +../extend/addon/matrix/tour \ No newline at end of file diff --git a/sources/addon/twitter b/sources/addon/twitter new file mode 120000 index 00000000..6be8e2dc --- /dev/null +++ b/sources/addon/twitter @@ -0,0 +1 @@ +../extend/addon/matrix/twitter \ No newline at end of file diff --git a/sources/addon/upload_limits b/sources/addon/upload_limits new file mode 120000 index 00000000..4281a12a --- /dev/null +++ b/sources/addon/upload_limits @@ -0,0 +1 @@ +../extend/addon/matrix/upload_limits \ No newline at end of file diff --git a/sources/addon/visage b/sources/addon/visage new file mode 120000 index 00000000..3d5d20ef --- /dev/null +++ b/sources/addon/visage @@ -0,0 +1 @@ +../extend/addon/matrix/visage \ No newline at end of file diff --git a/sources/addon/wppost b/sources/addon/wppost new file mode 120000 index 00000000..3ac8fbc0 --- /dev/null +++ b/sources/addon/wppost @@ -0,0 +1 @@ +../extend/addon/matrix/wppost \ No newline at end of file diff --git a/sources/app/admin.apd b/sources/app/admin.apd new file mode 100644 index 00000000..dbd2f697 --- /dev/null +++ b/sources/app/admin.apd @@ -0,0 +1,4 @@ +url: $baseurl/admin +requires: admin +name: Site Admin +photo: $baseurl/app/admin.png diff --git a/sources/app/admin.png b/sources/app/admin.png new file mode 100644 index 00000000..cde922e8 Binary files /dev/null and b/sources/app/admin.png differ diff --git a/sources/app/bookmarks.apd b/sources/app/bookmarks.apd new file mode 100644 index 00000000..9581a220 --- /dev/null +++ b/sources/app/bookmarks.apd @@ -0,0 +1,4 @@ +url: $baseurl/bookmarks +requires: local_channel +name: View bookmarks +photo: $baseurl/app/bookmarks.png diff --git a/sources/app/bookmarks.png b/sources/app/bookmarks.png new file mode 100644 index 00000000..fffad332 Binary files /dev/null and b/sources/app/bookmarks.png differ diff --git a/sources/app/bugreport.apd b/sources/app/bugreport.apd new file mode 100644 index 00000000..3714f062 --- /dev/null +++ b/sources/app/bugreport.apd @@ -0,0 +1,3 @@ +url: https://github.com/redmatrix/hubzilla/issues +name: Bug Report +photo: $baseurl/app/bugreport.png diff --git a/sources/app/bugreport.png b/sources/app/bugreport.png new file mode 100644 index 00000000..4b59da18 Binary files /dev/null and b/sources/app/bugreport.png differ diff --git a/sources/app/channel.apd b/sources/app/channel.apd new file mode 100644 index 00000000..0b5400ae --- /dev/null +++ b/sources/app/channel.apd @@ -0,0 +1,4 @@ +url: $baseurl/channel/$nick +requires: local_channel +name: Channel Home +photo: $baseurl/app/home.png diff --git a/sources/app/chat.apd b/sources/app/chat.apd new file mode 100644 index 00000000..d4879c0b --- /dev/null +++ b/sources/app/chat.apd @@ -0,0 +1,4 @@ +url: $baseurl/chat/$nick +requires: local_channel +name: My chatrooms +photo: $baseurl/app/chat.png diff --git a/sources/app/chat.png b/sources/app/chat.png new file mode 100644 index 00000000..9d3fdebd Binary files /dev/null and b/sources/app/chat.png differ diff --git a/sources/app/connections.apd b/sources/app/connections.apd new file mode 100644 index 00000000..f4b5ad87 --- /dev/null +++ b/sources/app/connections.apd @@ -0,0 +1,4 @@ +url: $baseurl/connections +requires: local_channel +name: Connections +photo: $baseurl/app/connections.png diff --git a/sources/app/connections.png b/sources/app/connections.png new file mode 100644 index 00000000..6f610076 Binary files /dev/null and b/sources/app/connections.png differ diff --git a/sources/app/directory.apd b/sources/app/directory.apd new file mode 100644 index 00000000..c4a6f12d --- /dev/null +++ b/sources/app/directory.apd @@ -0,0 +1,3 @@ +url: $baseurl/directory +name: Directory +photo: $baseurl/app/directory.png diff --git a/sources/app/directory.png b/sources/app/directory.png new file mode 100644 index 00000000..659f6905 Binary files /dev/null and b/sources/app/directory.png differ diff --git a/sources/app/events.apd b/sources/app/events.apd new file mode 100644 index 00000000..dd725e17 --- /dev/null +++ b/sources/app/events.apd @@ -0,0 +1,4 @@ +url: $baseurl/events +requires: local_channel +name: Events +photo: $baseurl/app/events.png diff --git a/sources/app/events.png b/sources/app/events.png new file mode 100644 index 00000000..a5670fd1 Binary files /dev/null and b/sources/app/events.png differ diff --git a/sources/app/features.apd b/sources/app/features.apd new file mode 100644 index 00000000..521df479 --- /dev/null +++ b/sources/app/features.apd @@ -0,0 +1,4 @@ +url: $baseurl/settings/features +requires: local_channel +name: Features +photo: $baseurl/app/features.png diff --git a/sources/app/features.png b/sources/app/features.png new file mode 100644 index 00000000..5faf14bc Binary files /dev/null and b/sources/app/features.png differ diff --git a/sources/app/help.apd b/sources/app/help.apd new file mode 100644 index 00000000..ca7208e6 --- /dev/null +++ b/sources/app/help.apd @@ -0,0 +1,3 @@ +url: $baseurl/help +name: Help +photo: $baseurl/app/help.png diff --git a/sources/app/help.png b/sources/app/help.png new file mode 100644 index 00000000..6b9b1ccb Binary files /dev/null and b/sources/app/help.png differ diff --git a/sources/app/home.png b/sources/app/home.png new file mode 100644 index 00000000..4b45f2a7 Binary files /dev/null and b/sources/app/home.png differ diff --git a/sources/app/invite.apd b/sources/app/invite.apd new file mode 100644 index 00000000..96bafff1 --- /dev/null +++ b/sources/app/invite.apd @@ -0,0 +1,4 @@ +url: $baseurl/invite +requires: local_channel +name: Invite +photo: $baseurl/app/invite.png diff --git a/sources/app/invite.png b/sources/app/invite.png new file mode 100644 index 00000000..dbc2cbbf Binary files /dev/null and b/sources/app/invite.png differ diff --git a/sources/app/lang.apd b/sources/app/lang.apd new file mode 100644 index 00000000..afe04986 --- /dev/null +++ b/sources/app/lang.apd @@ -0,0 +1,3 @@ +url: $baseurl/lang +name: Language +photo: $baseurl/app/lang.png diff --git a/sources/app/lang.png b/sources/app/lang.png new file mode 100644 index 00000000..89a61c26 Binary files /dev/null and b/sources/app/lang.png differ diff --git a/sources/app/login.apd b/sources/app/login.apd new file mode 100644 index 00000000..e4cccbc7 --- /dev/null +++ b/sources/app/login.apd @@ -0,0 +1,4 @@ +url: $baseurl/login +requires: nologin +name: Login +photo: $baseurl/app/login.png diff --git a/sources/app/login.png b/sources/app/login.png new file mode 100644 index 00000000..4e5625ee Binary files /dev/null and b/sources/app/login.png differ diff --git a/sources/app/mail.apd b/sources/app/mail.apd new file mode 100644 index 00000000..b9fdb996 --- /dev/null +++ b/sources/app/mail.apd @@ -0,0 +1,4 @@ +url: $baseurl/message +requires: local_channel +name: Mail +photo: $baseurl/app/mail.png diff --git a/sources/app/mail.png b/sources/app/mail.png new file mode 100644 index 00000000..bbd9f844 Binary files /dev/null and b/sources/app/mail.png differ diff --git a/sources/app/manage.apd b/sources/app/manage.apd new file mode 100644 index 00000000..27938e4c --- /dev/null +++ b/sources/app/manage.apd @@ -0,0 +1,4 @@ +url: $baseurl/manage +requires: local_channel +name: Channel Manager +photo: $baseurl/app/manage.png diff --git a/sources/app/manage.png b/sources/app/manage.png new file mode 100644 index 00000000..38a4dcba Binary files /dev/null and b/sources/app/manage.png differ diff --git a/sources/app/matrix.apd b/sources/app/matrix.apd new file mode 100644 index 00000000..68188bfd --- /dev/null +++ b/sources/app/matrix.apd @@ -0,0 +1,4 @@ +url: $baseurl/network +requires: local_channel +name: Matrix +photo: $baseurl/app/matrix.png diff --git a/sources/app/matrix.png b/sources/app/matrix.png new file mode 100644 index 00000000..aba2c35d Binary files /dev/null and b/sources/app/matrix.png differ diff --git a/sources/app/mood.apd b/sources/app/mood.apd new file mode 100644 index 00000000..6f381fd4 --- /dev/null +++ b/sources/app/mood.apd @@ -0,0 +1,4 @@ +url: $baseurl/mood +requires: local_channel +name: Mood +photo: $baseurl/app/mood.png diff --git a/sources/app/mood.png b/sources/app/mood.png new file mode 100644 index 00000000..2a5c1aca Binary files /dev/null and b/sources/app/mood.png differ diff --git a/sources/app/photos.apd b/sources/app/photos.apd new file mode 100644 index 00000000..3422d520 --- /dev/null +++ b/sources/app/photos.apd @@ -0,0 +1,4 @@ +url: $baseurl/photos/$nick +requires: local_channel +name: Photos +photo: $baseurl/app/photos.png diff --git a/sources/app/photos.png b/sources/app/photos.png new file mode 100644 index 00000000..59b03828 Binary files /dev/null and b/sources/app/photos.png differ diff --git a/sources/app/poke.apd b/sources/app/poke.apd new file mode 100644 index 00000000..7e3bb4ff --- /dev/null +++ b/sources/app/poke.apd @@ -0,0 +1,4 @@ +url: $baseurl/poke +requires: local_channel +name: Poke +photo: $baseurl/app/poke.png diff --git a/sources/app/poke.png b/sources/app/poke.png new file mode 100644 index 00000000..9655d54f Binary files /dev/null and b/sources/app/poke.png differ diff --git a/sources/app/post.apd b/sources/app/post.apd new file mode 100644 index 00000000..780eed47 --- /dev/null +++ b/sources/app/post.apd @@ -0,0 +1,4 @@ +url: $baseurl/rpost?f=&body=%0A +requires: observer +name: Post +photo: $baseurl/app/post.png diff --git a/sources/app/post.png b/sources/app/post.png new file mode 100644 index 00000000..4a435558 Binary files /dev/null and b/sources/app/post.png differ diff --git a/sources/app/pphoto.apd b/sources/app/pphoto.apd new file mode 100644 index 00000000..302b85d9 --- /dev/null +++ b/sources/app/pphoto.apd @@ -0,0 +1,4 @@ +url: $baseurl/profile_photo +requires: local_channel +name: Profile Photo +photo: $baseurl/app/pphoto.png diff --git a/sources/app/pphoto.png b/sources/app/pphoto.png new file mode 100644 index 00000000..041ff1e0 Binary files /dev/null and b/sources/app/pphoto.png differ diff --git a/sources/app/probe.apd b/sources/app/probe.apd new file mode 100644 index 00000000..e1ab5fc4 --- /dev/null +++ b/sources/app/probe.apd @@ -0,0 +1,4 @@ +url: $baseurl/probe +requires: local_channel +name: Remote diagnostics +photo: $baseurl/app/probe.png diff --git a/sources/app/probe.png b/sources/app/probe.png new file mode 100644 index 00000000..21bd85cd Binary files /dev/null and b/sources/app/probe.png differ diff --git a/sources/app/profile.apd b/sources/app/profile.apd new file mode 100644 index 00000000..d353d574 --- /dev/null +++ b/sources/app/profile.apd @@ -0,0 +1,4 @@ +url: $baseurl/profile/$nick +requires: local_channel +name: View profile +photo: $baseurl/app/profile.png diff --git a/sources/app/profile.png b/sources/app/profile.png new file mode 100644 index 00000000..e6e137c8 Binary files /dev/null and b/sources/app/profile.png differ diff --git a/sources/app/randprof.apd b/sources/app/randprof.apd new file mode 100644 index 00000000..9534c77f --- /dev/null +++ b/sources/app/randprof.apd @@ -0,0 +1,6 @@ +url: $baseurl/randprof +name: Random Channel +target: randprof +photo: $baseurl/app/randprof.png + + diff --git a/sources/app/randprof.png b/sources/app/randprof.png new file mode 100644 index 00000000..7bb438dc Binary files /dev/null and b/sources/app/randprof.png differ diff --git a/sources/app/search.apd b/sources/app/search.apd new file mode 100644 index 00000000..ed48909b --- /dev/null +++ b/sources/app/search.apd @@ -0,0 +1,3 @@ +url: $baseurl/search +name: Search +photo: $baseurl/app/search.png diff --git a/sources/app/search.png b/sources/app/search.png new file mode 100644 index 00000000..505d93c3 Binary files /dev/null and b/sources/app/search.png differ diff --git a/sources/app/settings.apd b/sources/app/settings.apd new file mode 100644 index 00000000..fbb5eacd --- /dev/null +++ b/sources/app/settings.apd @@ -0,0 +1,4 @@ +url: $baseurl/settings +requires: local_channel +name: Settings +photo: $baseurl/app/settings.png diff --git a/sources/app/settings.png b/sources/app/settings.png new file mode 100644 index 00000000..2ba11a79 Binary files /dev/null and b/sources/app/settings.png differ diff --git a/sources/app/storage.apd b/sources/app/storage.apd new file mode 100644 index 00000000..c959a3cd --- /dev/null +++ b/sources/app/storage.apd @@ -0,0 +1,4 @@ +url: $baseurl/cloud/$nick +requires: local_channel +name: Files +photo: $baseurl/app/storage.png diff --git a/sources/app/storage.png b/sources/app/storage.png new file mode 100644 index 00000000..ad8b89f6 Binary files /dev/null and b/sources/app/storage.png differ diff --git a/sources/app/suggest.apd b/sources/app/suggest.apd new file mode 100644 index 00000000..f3d17e0e --- /dev/null +++ b/sources/app/suggest.apd @@ -0,0 +1,4 @@ +url: $baseurl/suggest +requires: local_channel +name: Suggest channels +photo: $baseurl/app/suggest.png diff --git a/sources/app/suggest.png b/sources/app/suggest.png new file mode 100644 index 00000000..ca918052 Binary files /dev/null and b/sources/app/suggest.png differ diff --git a/sources/app/webpages.apd b/sources/app/webpages.apd new file mode 100644 index 00000000..78e7abba --- /dev/null +++ b/sources/app/webpages.apd @@ -0,0 +1,4 @@ +url: $baseurl/webpages/$nick +requires: local_channel, webpages +name: Webpages +photo: $baseurl/app/webpages.png diff --git a/sources/app/webpages.png b/sources/app/webpages.png new file mode 100644 index 00000000..72a09183 Binary files /dev/null and b/sources/app/webpages.png differ diff --git a/sources/boot.php b/sources/boot.php new file mode 100755 index 00000000..458d676d --- /dev/null +++ b/sources/boot.php @@ -0,0 +1,2316 @@ +' . "\r\n" ); +define ( 'ATOM_TIME', 'Y-m-d\TH:i:s\Z' ); +//define ( 'NULL_DATE', '0000-00-00 00:00:00' ); +define ( 'TEMPLATE_BUILD_PATH', 'store/[data]/smarty3' ); + +define ( 'DIRECTORY_MODE_NORMAL', 0x0000); // This is technically DIRECTORY_MODE_TERTIARY, but it's the default, hence 0x0000 +define ( 'DIRECTORY_MODE_PRIMARY', 0x0001); +define ( 'DIRECTORY_MODE_SECONDARY', 0x0002); +define ( 'DIRECTORY_MODE_STANDALONE', 0x0100); + +// We will look for upstream directories whenever me make contact +// with other sites, but if this is a new installation and isn't +// a standalone hub, we need to seed the service with a starting +// point to go out and find the rest of the world. + +define ( 'DIRECTORY_REALM', 'RED_GLOBAL'); +define ( 'DIRECTORY_FALLBACK_MASTER', 'https://zothub.com'); + +$DIRECTORY_FALLBACK_SERVERS = array( + 'https://zothub.com', + 'https://zotid.net', + 'https://red.zottel.red', + 'https://redmatrix.info', + 'https://my.federated.social', + 'https://redmatrix.nl' +); + + +/** + * + * Image storage quality. Lower numbers save space at cost of image detail. + * For ease of upgrade, please do not change here. Change jpeg quality with + * $a->config['system']['jpeg_quality'] = n; + * in .htconfig.php, where n is netween 1 and 100, and with very poor results + * below about 50 + * + */ + +define ( 'JPEG_QUALITY', 100 ); +/** + * $a->config['system']['png_quality'] from 0 (uncompressed) to 9 + */ +define ( 'PNG_QUALITY', 8 ); + +/** + * Language detection parameters + */ + +define ( 'LANGUAGE_DETECT_MIN_LENGTH', 128 ); +define ( 'LANGUAGE_DETECT_MIN_CONFIDENCE', 0.01 ); + + +/** + * Default permissions for file-based storage (webDAV, etc.) + * These files will be owned by the webserver who will need write + * access to the "storage" folder. + * Ideally you should make this 700, however some hosted platforms + * may not let you change ownership of this directory so we're + * defaulting to both owner-write and group-write privilege. + * This should work for most cases without modification. + * Over-ride this in your .htconfig.php if you need something + * either more or less restrictive. + */ + +define ( 'STORAGE_DEFAULT_PERMISSIONS', 0770 ); + + +/** + * + * An alternate way of limiting picture upload sizes. Specify the maximum pixel + * length that pictures are allowed to be (for non-square pictures, it will apply + * to the longest side). Pictures longer than this length will be resized to be + * this length (on the longest side, the other side will be scaled appropriately). + * Modify this value using + * + * $a->config['system']['max_image_length'] = n; + * + * in .htconfig.php + * + * If you don't want to set a maximum length, set to -1. The default value is + * defined by 'MAX_IMAGE_LENGTH' below. + * + */ +define ( 'MAX_IMAGE_LENGTH', -1 ); + + +/** + * Not yet used + */ + +define ( 'DEFAULT_DB_ENGINE', 'MyISAM' ); + +/** + * SSL redirection policies + */ + +define ( 'SSL_POLICY_NONE', 0 ); +define ( 'SSL_POLICY_FULL', 1 ); +define ( 'SSL_POLICY_SELFSIGN', 2 ); // NOT supported in Red + + +/** + * log levels + */ + +define ( 'LOGGER_NORMAL', 0 ); +define ( 'LOGGER_TRACE', 1 ); +define ( 'LOGGER_DEBUG', 2 ); +define ( 'LOGGER_DATA', 3 ); +define ( 'LOGGER_ALL', 4 ); + +/** + * registration policies + */ + +define ( 'REGISTER_CLOSED', 0 ); +define ( 'REGISTER_APPROVE', 1 ); +define ( 'REGISTER_OPEN', 2 ); + + +/** + * site access policy + */ + +define ( 'ACCESS_PRIVATE', 0 ); +define ( 'ACCESS_PAID', 1 ); +define ( 'ACCESS_FREE', 2 ); +define ( 'ACCESS_TIERED', 3 ); + +/** + * relationship types + */ + +define ( 'CONTACT_IS_FOLLOWER', 1); +define ( 'CONTACT_IS_SHARING', 2); +define ( 'CONTACT_IS_FRIEND', 3); + + +/** + * DB update return values + */ + +define ( 'UPDATE_SUCCESS', 0); +define ( 'UPDATE_FAILED', 1); + + +define ( 'CLIENT_MODE_NORMAL', 0x0000); +define ( 'CLIENT_MODE_LOAD', 0x0001); +define ( 'CLIENT_MODE_UPDATE', 0x0002); + + +/** + * + * Channel pageflags + * + */ + +define ( 'PAGE_NORMAL', 0x0000 ); +define ( 'PAGE_HIDDEN', 0x0001 ); +define ( 'PAGE_AUTOCONNECT', 0x0002 ); +define ( 'PAGE_APPLICATION', 0x0004 ); +define ( 'PAGE_ALLOWCODE', 0x0008 ); +define ( 'PAGE_PREMIUM', 0x0010 ); +define ( 'PAGE_ADULT', 0x0020 ); +define ( 'PAGE_CENSORED', 0x0040 ); // Site admin has blocked this channel from appearing in casual search results and site feeds +define ( 'PAGE_SYSTEM', 0x1000 ); +define ( 'PAGE_HUBADMIN', 0x2000 ); // set this to indicate a preferred admin channel rather than the + // default channel of any accounts with the admin role. +define ( 'PAGE_REMOVED', 0x8000 ); + + +/** + * Photo usage types + */ + +define ( 'PHOTO_NORMAL', 0x0000 ); +define ( 'PHOTO_PROFILE', 0x0001 ); +define ( 'PHOTO_XCHAN', 0x0002 ); +define ( 'PHOTO_THING', 0x0004 ); +define ( 'PHOTO_COVER', 0x0010 ); + +define ( 'PHOTO_ADULT', 0x0008 ); +define ( 'PHOTO_FLAG_OS', 0x4000 ); + +/** + * Menu types + */ + +define ( 'MENU_SYSTEM', 0x0001 ); +define ( 'MENU_BOOKMARK', 0x0002 ); + +/** + * Network and protocol family types + */ + +define ( 'NETWORK_DFRN', 'dfrn'); // Friendica, Mistpark, other DFRN implementations +define ( 'NETWORK_ZOT', 'zot!'); // Zot! +define ( 'NETWORK_OSTATUS', 'stat'); // status.net, identi.ca, GNU-social, other OStatus implementations +define ( 'NETWORK_FEED', 'feed'); // RSS/Atom feeds with no known "post/notify" protocol +define ( 'NETWORK_DIASPORA', 'dspr'); // Diaspora +define ( 'NETWORK_MAIL', 'mail'); // IMAP/POP +define ( 'NETWORK_MAIL2', 'mai2'); // extended IMAP/POP +define ( 'NETWORK_FACEBOOK', 'face'); // Facebook API +define ( 'NETWORK_LINKEDIN', 'lnkd'); // LinkedIn +define ( 'NETWORK_XMPP', 'xmpp'); // XMPP +define ( 'NETWORK_MYSPACE', 'mysp'); // MySpace +define ( 'NETWORK_GPLUS', 'goog'); // Google+ + +define ( 'NETWORK_PHANTOM', 'unkn'); // Place holder + + +/** + * Permissions + */ + +define ( 'PERMS_R_STREAM', 0x00001); +define ( 'PERMS_R_PROFILE', 0x00002); +define ( 'PERMS_R_PHOTOS', 0x00004); +define ( 'PERMS_R_ABOOK', 0x00008); + +define ( 'PERMS_W_STREAM', 0x00010); +define ( 'PERMS_W_WALL', 0x00020); +define ( 'PERMS_W_TAGWALL', 0x00040); +define ( 'PERMS_W_COMMENT', 0x00080); +define ( 'PERMS_W_MAIL', 0x00100); +define ( 'PERMS_W_PHOTOS', 0x00200); +define ( 'PERMS_W_CHAT', 0x00400); +define ( 'PERMS_A_DELEGATE', 0x00800); + +define ( 'PERMS_R_STORAGE', 0x01000); +define ( 'PERMS_W_STORAGE', 0x02000); +define ( 'PERMS_R_PAGES', 0x04000); +define ( 'PERMS_W_PAGES', 0x08000); +define ( 'PERMS_A_REPUBLISH', 0x10000); +define ( 'PERMS_W_LIKE', 0x20000); + +// General channel permissions + +define ( 'PERMS_PUBLIC' , 0x0001 ); +define ( 'PERMS_NETWORK' , 0x0002 ); +define ( 'PERMS_SITE' , 0x0004 ); +define ( 'PERMS_CONTACTS' , 0x0008 ); +define ( 'PERMS_SPECIFIC' , 0x0080 ); +define ( 'PERMS_AUTHED' , 0x0100 ); +define ( 'PERMS_PENDING' , 0x0200 ); + + +// Address book flags + +define ( 'ABOOK_FLAG_BLOCKED' , 0x0001); +define ( 'ABOOK_FLAG_IGNORED' , 0x0002); +define ( 'ABOOK_FLAG_HIDDEN' , 0x0004); +define ( 'ABOOK_FLAG_ARCHIVED' , 0x0008); +define ( 'ABOOK_FLAG_PENDING' , 0x0010); +define ( 'ABOOK_FLAG_UNCONNECTED', 0x0020); +define ( 'ABOOK_FLAG_SELF' , 0x0080); +define ( 'ABOOK_FLAG_FEED' , 0x0100); + + +define ( 'MAIL_DELETED', 0x0001); +define ( 'MAIL_REPLIED', 0x0002); +define ( 'MAIL_ISREPLY', 0x0004); +define ( 'MAIL_SEEN', 0x0008); +define ( 'MAIL_RECALLED', 0x0010); +define ( 'MAIL_OBSCURED', 0x0020); + + +define ( 'ATTACH_FLAG_DIR', 0x0001); +define ( 'ATTACH_FLAG_OS', 0x0002); + + +define ( 'MENU_ITEM_ZID', 0x0001); +define ( 'MENU_ITEM_NEWWIN', 0x0002); +define ( 'MENU_ITEM_CHATROOM', 0x0004); + +/** + * Poll/Survey types + */ + +define ( 'POLL_SIMPLE_RATING', 0x0001); // 1-5 +define ( 'POLL_TENSCALE', 0x0002); // 1-10 +define ( 'POLL_MULTIPLE_CHOICE', 0x0004); +define ( 'POLL_OVERWRITE', 0x8000); // If you vote twice remove the prior entry + + +define ( 'UPDATE_FLAGS_UPDATED', 0x0001); +define ( 'UPDATE_FLAGS_FORCED', 0x0002); +define ( 'UPDATE_FLAGS_DELETED', 0x1000); + + +define ( 'DROPITEM_NORMAL', 0); +define ( 'DROPITEM_PHASE1', 1); +define ( 'DROPITEM_PHASE2', 2); + + +/** + * Maximum number of "people who like (or don't like) this" that we will list by name + */ + +define ( 'MAX_LIKERS', 10); + +/** + * Communication timeout + */ + +define ( 'ZCURL_TIMEOUT' , (-1)); + + +/** + * email notification options + */ + +define ( 'NOTIFY_INTRO', 0x0001 ); +define ( 'NOTIFY_CONFIRM', 0x0002 ); +define ( 'NOTIFY_WALL', 0x0004 ); +define ( 'NOTIFY_COMMENT', 0x0008 ); +define ( 'NOTIFY_MAIL', 0x0010 ); +define ( 'NOTIFY_SUGGEST', 0x0020 ); +define ( 'NOTIFY_PROFILE', 0x0040 ); +define ( 'NOTIFY_TAGSELF', 0x0080 ); +define ( 'NOTIFY_TAGSHARE', 0x0100 ); +define ( 'NOTIFY_POKE', 0x0200 ); + +define ( 'NOTIFY_SYSTEM', 0x8000 ); + +/** + * visual notification options + */ + +define ( 'VNOTIFY_NETWORK', 0x0001 ); +define ( 'VNOTIFY_CHANNEL', 0x0002 ); +define ( 'VNOTIFY_MAIL', 0x0004 ); +define ( 'VNOTIFY_EVENT', 0x0008 ); +define ( 'VNOTIFY_EVENTTODAY', 0x0010 ); +define ( 'VNOTIFY_BIRTHDAY', 0x0020 ); +define ( 'VNOTIFY_SYSTEM', 0x0040 ); +define ( 'VNOTIFY_INFO', 0x0080 ); +define ( 'VNOTIFY_ALERT', 0x0100 ); +define ( 'VNOTIFY_INTRO', 0x0200 ); +define ( 'VNOTIFY_REGISTER', 0x0400 ); + + + +/** + * Tag/term types + */ + +define ( 'TERM_UNKNOWN', 0 ); +define ( 'TERM_HASHTAG', 1 ); +define ( 'TERM_MENTION', 2 ); +define ( 'TERM_CATEGORY', 3 ); +define ( 'TERM_PCATEGORY', 4 ); +define ( 'TERM_FILE', 5 ); +define ( 'TERM_SAVEDSEARCH', 6 ); +define ( 'TERM_THING', 7 ); +define ( 'TERM_BOOKMARK', 8 ); +define ( 'TERM_HIERARCHY', 9 ); + +define ( 'TERM_OBJ_POST', 1 ); +define ( 'TERM_OBJ_PHOTO', 2 ); +define ( 'TERM_OBJ_PROFILE', 3 ); +define ( 'TERM_OBJ_CHANNEL', 4 ); +define ( 'TERM_OBJ_OBJECT', 5 ); +define ( 'TERM_OBJ_THING', 6 ); +define ( 'TERM_OBJ_APP', 7 ); + + +/** + * various namespaces we may need to parse + */ + +define ( 'NAMESPACE_ZOT', 'http://purl.org/zot' ); +define ( 'NAMESPACE_DFRN' , 'http://purl.org/macgirvin/dfrn/1.0' ); +define ( 'NAMESPACE_THREAD' , 'http://purl.org/syndication/thread/1.0' ); +define ( 'NAMESPACE_TOMB' , 'http://purl.org/atompub/tombstones/1.0' ); +define ( 'NAMESPACE_ACTIVITY', 'http://activitystrea.ms/spec/1.0/' ); +define ( 'NAMESPACE_ACTIVITY_SCHEMA', 'http://activitystrea.ms/schema/1.0/' ); +define ( 'NAMESPACE_MEDIA', 'http://purl.org/syndication/atommedia' ); +define ( 'NAMESPACE_SALMON_ME', 'http://salmon-protocol.org/ns/magic-env' ); +define ( 'NAMESPACE_OSTATUSSUB', 'http://ostatus.org/schema/1.0/subscribe' ); +define ( 'NAMESPACE_GEORSS', 'http://www.georss.org/georss' ); +define ( 'NAMESPACE_POCO', 'http://portablecontacts.net/spec/1.0' ); +define ( 'NAMESPACE_FEED', 'http://schemas.google.com/g/2010#updates-from' ); +define ( 'NAMESPACE_OSTATUS', 'http://ostatus.org/schema/1.0' ); +define ( 'NAMESPACE_STATUSNET', 'http://status.net/schema/api/1/' ); +define ( 'NAMESPACE_ATOM1', 'http://www.w3.org/2005/Atom' ); +define ( 'NAMESPACE_YMEDIA', 'http://search.yahoo.com/mrss/' ); + +/** + * activity stream defines + */ + +define ( 'ACTIVITY_LIKE', NAMESPACE_ACTIVITY_SCHEMA . 'like' ); +define ( 'ACTIVITY_DISLIKE', NAMESPACE_ZOT . '/activity/dislike' ); +define ( 'ACTIVITY_AGREE', NAMESPACE_ZOT . '/activity/agree' ); +define ( 'ACTIVITY_DISAGREE', NAMESPACE_ZOT . '/activity/disagree' ); +define ( 'ACTIVITY_ABSTAIN', NAMESPACE_ZOT . '/activity/abstain' ); +define ( 'ACTIVITY_ATTEND', NAMESPACE_ZOT . '/activity/attendyes' ); +define ( 'ACTIVITY_ATTENDNO', NAMESPACE_ZOT . '/activity/attendno' ); +define ( 'ACTIVITY_ATTENDMAYBE', NAMESPACE_ZOT . '/activity/attendmaybe' ); + +define ( 'ACTIVITY_OBJ_HEART', NAMESPACE_ZOT . '/activity/heart' ); + +define ( 'ACTIVITY_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'make-friend' ); +define ( 'ACTIVITY_REQ_FRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'request-friend' ); +define ( 'ACTIVITY_UNFRIEND', NAMESPACE_ACTIVITY_SCHEMA . 'remove-friend' ); +define ( 'ACTIVITY_FOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'follow' ); +define ( 'ACTIVITY_UNFOLLOW', NAMESPACE_ACTIVITY_SCHEMA . 'stop-following' ); +define ( 'ACTIVITY_JOIN', NAMESPACE_ACTIVITY_SCHEMA . 'join' ); + +define ( 'ACTIVITY_POST', NAMESPACE_ACTIVITY_SCHEMA . 'post' ); +define ( 'ACTIVITY_UPDATE', NAMESPACE_ACTIVITY_SCHEMA . 'update' ); +define ( 'ACTIVITY_TAG', NAMESPACE_ACTIVITY_SCHEMA . 'tag' ); +define ( 'ACTIVITY_FAVORITE', NAMESPACE_ACTIVITY_SCHEMA . 'favorite' ); + +define ( 'ACTIVITY_POKE', NAMESPACE_ZOT . '/activity/poke' ); +define ( 'ACTIVITY_MOOD', NAMESPACE_ZOT . '/activity/mood' ); + +define ( 'ACTIVITY_OBJ_COMMENT', NAMESPACE_ACTIVITY_SCHEMA . 'comment' ); +define ( 'ACTIVITY_OBJ_NOTE', NAMESPACE_ACTIVITY_SCHEMA . 'note' ); +define ( 'ACTIVITY_OBJ_PERSON', NAMESPACE_ACTIVITY_SCHEMA . 'person' ); +define ( 'ACTIVITY_OBJ_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'photo' ); +define ( 'ACTIVITY_OBJ_P_PHOTO', NAMESPACE_ACTIVITY_SCHEMA . 'profile-photo' ); +define ( 'ACTIVITY_OBJ_ALBUM', NAMESPACE_ACTIVITY_SCHEMA . 'photo-album' ); +define ( 'ACTIVITY_OBJ_EVENT', NAMESPACE_ACTIVITY_SCHEMA . 'event' ); +define ( 'ACTIVITY_OBJ_GROUP', NAMESPACE_ACTIVITY_SCHEMA . 'group' ); +define ( 'ACTIVITY_OBJ_TAGTERM', NAMESPACE_ZOT . '/activity/tagterm' ); +define ( 'ACTIVITY_OBJ_PROFILE', NAMESPACE_ZOT . '/activity/profile' ); +define ( 'ACTIVITY_OBJ_THING', NAMESPACE_ZOT . '/activity/thing' ); +define ( 'ACTIVITY_OBJ_LOCATION',NAMESPACE_ZOT . '/activity/location' ); +define ( 'ACTIVITY_OBJ_FILE', NAMESPACE_ZOT . '/activity/file' ); + +/** + * item weight for query ordering + */ + +define ( 'GRAVITY_PARENT', 0); +define ( 'GRAVITY_LIKE', 3); +define ( 'GRAVITY_COMMENT', 6); + +/** + * Account Flags + */ + +define ( 'ACCOUNT_OK', 0x0000 ); +define ( 'ACCOUNT_UNVERIFIED', 0x0001 ); +define ( 'ACCOUNT_BLOCKED', 0x0002 ); +define ( 'ACCOUNT_EXPIRED', 0x0004 ); +define ( 'ACCOUNT_REMOVED', 0x0008 ); +define ( 'ACCOUNT_PENDING', 0x0010 ); + +/** + * Account roles + */ + +define ( 'ACCOUNT_ROLE_ALLOWCODE', 0x0001 ); +define ( 'ACCOUNT_ROLE_SYSTEM', 0x0002 ); +define ( 'ACCOUNT_ROLE_DEVELOPER', 0x0004 ); +define ( 'ACCOUNT_ROLE_ADMIN', 0x1000 ); + +/** + * Item visibility + */ + +define ( 'ITEM_VISIBLE', 0x0000); +//define ( 'ITEM_HIDDEN', 0x0001); +define ( 'ITEM_BLOCKED', 0x0002); +define ( 'ITEM_MODERATED', 0x0004); +define ( 'ITEM_SPAM', 0x0008); +//define ( 'ITEM_DELETED', 0x0010); +define ( 'ITEM_UNPUBLISHED', 0x0020); +//define ( 'ITEM_WEBPAGE', 0x0040); // is a static web page, not a conversational item +define ( 'ITEM_DELAYED_PUBLISH', 0x0080); +define ( 'ITEM_BUILDBLOCK', 0x0100); // Named thusly to make sure nobody confuses this with ITEM_BLOCKED +//define ( 'ITEM_PDL', 0x0200); // Page Description Language - e.g. Comanche +define ( 'ITEM_BUG', 0x0400); // Is a bug, can be used by the internal bug tracker +define ( 'ITEM_PENDING_REMOVE', 0x0800); // deleted, notification period has lapsed +define ( 'ITEM_DOC', 0x1000); // hubzilla only, define here so that item import does the right thing + +define ( 'ITEM_TYPE_POST', 0 ); +define ( 'ITEM_TYPE_BLOCK', 1 ); +define ( 'ITEM_TYPE_PDL', 2 ); +define ( 'ITEM_TYPE_WEBPAGE', 3 ); +define ( 'ITEM_TYPE_BUG', 4 ); +define ( 'ITEM_TYPE_DOC', 5 ); + +define ( 'DBTYPE_MYSQL', 0 ); +define ( 'DBTYPE_POSTGRES', 1 ); + +/** + * + * Reverse the effect of magic_quotes_gpc if it is enabled. + * Please disable magic_quotes_gpc so we don't have to do this. + * See http://php.net/manual/en/security.magicquotes.disabling.php + * + */ + +function startup() { + error_reporting(E_ERROR | E_WARNING | E_PARSE); + + // Some hosting providers block/disable this + @set_time_limit(0); + + if(function_exists ('ini_set')) { + // This has to be quite large to deal with embedded private photos + @ini_set('pcre.backtrack_limit', 500000); + + // Use cookies to store the session ID on the client side + @ini_set('session.use_only_cookies', 1); + + // Disable transparent Session ID support + @ini_set('session.use_trans_sid', 0); + } + + if (get_magic_quotes_gpc()) { + $process = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST); + while (list($key, $val) = each($process)) { + foreach ($val as $k => $v) { + unset($process[$key][$k]); + if (is_array($v)) { + $process[$key][stripslashes($k)] = $v; + $process[] = &$process[$key][stripslashes($k)]; + } else { + $process[$key][stripslashes($k)] = stripslashes($v); + } + } + } + unset($process); + } +} + +/** + * class: App + * + * @brief Our main application structure for the life of this page. + * + * Primarily deals with the URL that got us here + * and tries to make some sense of it, and + * stores our page contents and config storage + * and anything else that might need to be passed around + * before we spit the page out. + * + */ +class App { + + public $install = false; // true if we are installing the software + + public $account = null; // account record of the logged-in account + public $channel = null; // channel record of the current channel of the logged-in account + public $observer = null; // xchan record of the page observer + public $profile_uid = 0; // If applicable, the channel_id of the "page owner" + public $poi = null; // "person of interest", generally a referenced connection + private $oauth_key = null; // consumer_id of oauth request, if used + public $layout = array(); // Comanche parsed template + public $pdl = null; + private $perms = null; // observer permissions + private $widgets = array(); // widgets for this page + //private $widgetlist = null; // widget ordering and inclusion directives + + public $groups; + public $language; + public $module_loaded = false; + public $query_string; + public $config; // config cache + public $page; + public $profile; + public $user; + public $cid; + public $contact; + public $contacts; + public $content; + public $data = array(); + public $error = false; + public $cmd; + public $argv; + public $argc; + public $module; + public $pager; + public $strings; + public $hooks; + public $timezone; + public $interactive = true; + public $plugins; + private $apps = array(); + public $identities; + public $css_sources = array(); + public $js_sources = array(); + public $theme_info = array(); + public $is_sys = false; + public $nav_sel; + + public $category; + + // Allow themes to control internal parameters + // by changing App values in theme.php + + public $sourcename = ''; + public $videowidth = 425; + public $videoheight = 350; + public $force_max_items = 0; + public $theme_thread_allow = true; + + /** + * @brief An array for all theme-controllable parameters + * + * Mostly unimplemented yet. Only options 'template_engine' and + * beyond are used. + */ + private $theme = array( + 'sourcename' => '', + 'videowidth' => 425, + 'videoheight' => 350, + 'force_max_items' => 0, + 'thread_allow' => true, + 'stylesheet' => '', + 'template_engine' => 'smarty3', + ); + + /** + * @brief An array of registered template engines ('name'=>'class name') + */ + public $template_engines = array(); + /** + * @brief An array of instanced template engines ('name'=>'instance') + */ + public $template_engine_instance = array(); + + private $ldelim = array( + 'internal' => '', + 'smarty3' => '{{' + ); + private $rdelim = array( + 'internal' => '', + 'smarty3' => '}}' + ); + + private $scheme; + private $hostname; + private $baseurl; + private $path; + + /** + * App constructor. + */ + function __construct() { + // we'll reset this after we read our config file + date_default_timezone_set('UTC'); + + $this->config = array('system'=>array()); + $this->page = array(); + $this->pager= array(); + + $this->query_string = ''; + + startup(); + + set_include_path( + 'include' . PATH_SEPARATOR + . 'library' . PATH_SEPARATOR + . 'library/langdet' . PATH_SEPARATOR + . '.' ); + + $this->scheme = 'http'; + if(x($_SERVER,'HTTPS') && $_SERVER['HTTPS']) + $this->scheme = 'https'; + elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443)) + $this->scheme = 'https'; + + if(x($_SERVER,'SERVER_NAME')) { + $this->hostname = $_SERVER['SERVER_NAME']; + + if(x($_SERVER,'SERVER_PORT') && $_SERVER['SERVER_PORT'] != 80 && $_SERVER['SERVER_PORT'] != 443) + $this->hostname .= ':' . $_SERVER['SERVER_PORT']; + /** + * Figure out if we are running at the top of a domain + * or in a sub-directory and adjust accordingly + */ + + $path = trim(dirname($_SERVER['SCRIPT_NAME']),'/\\'); + if(isset($path) && strlen($path) && ($path != $this->path)) + $this->path = $path; + } + + set_include_path("include/$this->hostname" . PATH_SEPARATOR . get_include_path()); + + if((x($_SERVER,'QUERY_STRING')) && substr($_SERVER['QUERY_STRING'], 0, 2) === "q=") { + $this->query_string = substr($_SERVER['QUERY_STRING'], 2); + // removing trailing / - maybe a nginx problem + if (substr($this->query_string, 0, 1) == "/") + $this->query_string = substr($this->query_string, 1); + } + if(x($_GET,'q')) + $this->cmd = trim($_GET['q'],'/\\'); + + // unix style "homedir" + + if(substr($this->cmd, 0, 1) === '~') + $this->cmd = 'channel/' . substr($this->cmd, 1); + + /* + * Break the URL path into C style argc/argv style arguments for our + * modules. Given "http://example.com/module/arg1/arg2", $this->argc + * will be 3 (integer) and $this->argv will contain: + * [0] => 'module' + * [1] => 'arg1' + * [2] => 'arg2' + * + * There will always be one argument. If provided a naked domain + * URL, $this->argv[0] is set to "home". + */ + + $this->argv = explode('/', $this->cmd); + $this->argc = count($this->argv); + if ((array_key_exists('0', $this->argv)) && strlen($this->argv[0])) { + $this->module = str_replace(".", "_", $this->argv[0]); + $this->module = str_replace("-", "_", $this->module); + } else { + $this->argc = 1; + $this->argv = array('home'); + $this->module = 'home'; + } + + /* + * See if there is any page number information, and initialise + * pagination + */ + + $this->pager['page'] = ((x($_GET,'page') && intval($_GET['page']) > 0) ? intval($_GET['page']) : 1); + $this->pager['itemspage'] = 60; + $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; + if($this->pager['start'] < 0) + $this->pager['start'] = 0; + $this->pager['total'] = 0; + + /* + * Detect mobile devices + */ + + $mobile_detect = new Mobile_Detect(); + $this->is_mobile = $mobile_detect->isMobile(); + $this->is_tablet = $mobile_detect->isTablet(); + + $this->head_set_icon('/images/rm-32.png'); + + BaseObject::set_app($this); + + /* + * register template engines + */ + $dc = get_declared_classes(); + foreach ($dc as $k) { + if (in_array("ITemplateEngine", class_implements($k))){ + $this->register_template_engine($k); + } + } + } + + function get_baseurl($ssl = false) { + if(is_array($this->config) + && array_key_exists('system',$this->config) + && is_array($this->config['system']) + && array_key_exists('baseurl',$this->config['system']) + && strlen($this->config['system']['baseurl'])) { + $url = $this->config['system']['baseurl']; + + return $url; + } + + $scheme = $this->scheme; + + $this->baseurl = $scheme . "://" . $this->hostname . ((isset($this->path) && strlen($this->path)) ? '/' . $this->path : '' ); + + return $this->baseurl; + } + + function set_baseurl($url) { + if(is_array($this->config) + && array_key_exists('system',$this->config) + && is_array($this->config['system']) + && array_key_exists('baseurl',$this->config['system']) + && strlen($this->config['system']['baseurl'])) { + $url = $this->config['system']['baseurl']; + } + + $parsed = @parse_url($url); + + $this->baseurl = $url; + + if($parsed) { + $this->scheme = $parsed['scheme']; + + $this->hostname = $parsed['host']; + if(x($parsed,'port')) + $this->hostname .= ':' . $parsed['port']; + if(x($parsed,'path')) + $this->path = trim($parsed['path'],'\\/'); + } + } + + function get_hostname() { + return $this->hostname; + } + + function set_hostname($h) { + $this->hostname = $h; + } + + function set_path($p) { + $this->path = trim(trim($p), '/'); + } + + function get_path() { + return $this->path; + } + + function set_account($acct) { + $this->account = $acct; + } + + function get_account() { + return $this->account; + } + + function set_channel($channel) { + $this->channel = $channel; + } + + function get_channel() { + return $this->channel; + } + + function set_observer($xchan) { + $this->observer = $xchan; + } + + + function get_observer() { + return $this->observer; + } + + function set_perms($perms) { + $this->perms = $perms; + } + + function get_perms() { + return $this->perms; + } + + function set_oauth_key($consumer_id) { + $this->oauth_key = $consumer_id; + } + + function get_oauth_key() { + return $this->oauth_key; + } + + function get_apps() { + return $this->apps; + } + + function set_apps($arr) { + $this->apps = $arr; + } + + function set_groups($g) { + $this->groups = $g; + } + + function get_groups() { + return $this->groups; + } + + function set_widget($title,$html, $location = 'aside') { + $this->widgets[] = array('title' => $title, 'html' => $html, 'location' => $location); + } + + function get_widgets($location = '') { + if($location && count($this->widgets)) { + $ret = array(); + foreach($this->widgets as $w) { + if ($w['location'] == $location) + $ret[] = $w; + } + $arr = array('location' => $location, 'widgets' => $ret); + call_hooks('get_widgets', $arr); + return $arr['widgets']; + } + $arr = array('location' => $location, 'widgets' => $this->widgets); + call_hooks('get_widgets', $arr); + return $arr['widgets']; + } + + function set_pager_total($n) { + $this->pager['total'] = intval($n); + } + + function set_pager_itemspage($n) { + $this->pager['itemspage'] = ((intval($n) > 0) ? intval($n) : 0); + $this->pager['start'] = ($this->pager['page'] * $this->pager['itemspage']) - $this->pager['itemspage']; + } + + function build_pagehead() { + + $user_scalable = ((local_channel()) ? get_pconfig(local_channel(),'system','user_scalable') : 1); + if ($user_scalable === false) + $user_scalable = 1; + + $interval = ((local_channel()) ? get_pconfig(local_channel(),'system','update_interval') : 80000); + if($interval < 10000) + $interval = 80000; + + if(! x($this->page,'title')) + $this->page['title'] = $this->config['system']['sitename']; + + /* put the head template at the beginning of page['htmlhead'] + * since the code added by the modules frequently depends on it + * being first + */ + $tpl = get_markup_template('head.tpl'); + $this->page['htmlhead'] = replace_macros($tpl, array( + '$user_scalable' => $user_scalable, + '$baseurl' => $this->get_baseurl(), + '$local_channel' => local_channel(), + '$generator' => PLATFORM_NAME . ' ' . RED_VERSION, + '$update_interval' => $interval, + '$icon' => head_get_icon(), + '$head_css' => head_get_css(), + '$head_js' => head_get_js(), + '$js_strings' => js_strings(), + '$zid' => get_my_address(), + '$channel_id' => $this->profile['uid'], + )) . $this->page['htmlhead']; + + // always put main.js at the end + $this->page['htmlhead'] .= head_get_main_js(); + } + + /** + * register template engine class + * if $name is "", is used class static property $class::$name + * @param string $class + * @param string $name + */ + function register_template_engine($class, $name = '') { + if ($name === ""){ + $v = get_class_vars( $class ); + if(x($v, "name")) $name = $v['name']; + } + if ($name === ""){ + echo "template engine $class cannot be registered without a name.\n"; + killme(); + } + $this->template_engines[$name] = $class; + } + + /** + * return template engine instance. If $name is not defined, + * return engine defined by theme, or default + * + * @param string $name Template engine name + * + * @return object Template Engine instance + */ + function template_engine($name = ''){ + if ($name !== "") { + $template_engine = $name; + } else { + $template_engine = 'smarty3'; + if (x($this->theme, 'template_engine')) { + $template_engine = $this->theme['template_engine']; + } + } + + if (isset($this->template_engines[$template_engine])){ + if(isset($this->template_engine_instance[$template_engine])){ + return $this->template_engine_instance[$template_engine]; + } else { + $class = $this->template_engines[$template_engine]; + $obj = new $class; + $this->template_engine_instance[$template_engine] = $obj; + return $obj; + } + } + + echo "template engine $template_engine is not registered!\n"; killme(); + } + + /** + * @brief Returns the active template engine. + * + * @return string + */ + function get_template_engine() { + return $this->theme['template_engine']; + } + + function set_template_engine($engine = 'smarty3') { + $this->theme['template_engine'] = $engine; + } + + function get_template_ldelim($engine = 'smarty3') { + return $this->ldelim[$engine]; + } + + function get_template_rdelim($engine = 'smarty3') { + return $this->rdelim[$engine]; + } + + function head_set_icon($icon) { + $this->data['pageicon'] = $icon; + } + + function head_get_icon() { + $icon = $this->data['pageicon']; + if(! strpos($icon,'://')) + $icon = z_root() . $icon; + return $icon; + } + +} // End App class + + +/** + * @brief Retrieve the App structure. + * + * Useful in functions which require it but don't get it passed to them + * + * @return App + */ +function get_app() { + global $a; + return $a; +} + + +/** + * @brief Multi-purpose function to check variable state. + * + * Usage: x($var) or $x($array, 'key') + * + * returns false if variable/key is not set + * if variable is set, returns 1 if has 'non-zero' value, otherwise returns 0. + * e.g. x('') or x(0) returns 0; + * + * @param string|array $s variable to check + * @param string $k key inside the array to check + * + * @return bool|int + */ +function x($s, $k = null) { + if($k != null) { + if((is_array($s)) && (array_key_exists($k, $s))) { + if($s[$k]) + return (int) 1; + return (int) 0; + } + return false; + } + else { + if(isset($s)) { + if($s) { + return (int) 1; + } + return (int) 0; + } + return false; + } +} + + +// called from db initialisation if db is dead. + +function system_unavailable() { + include('include/system_unavailable.php'); + system_down(); + killme(); +} + + +function clean_urls() { + global $a; + + // if($a->config['system']['clean_urls']) + return true; + // return false; +} + +function z_path() { + global $a; + + $base = $a->get_baseurl(); + if(! clean_urls()) + $base .= '/?q='; + + return $base; +} + +/** + * @brief Returns the baseurl. + * + * @see App::get_baseurl() + * + * @return string + */ +function z_root() { + global $a; + return $a->get_baseurl(); +} + +/** + * @brief Return absolut URL for given $path. + * + * @param string $path + * + * @return string + */ +function absurl($path) { + if(strpos($path, '/') === 0) + return z_path() . $path; + + return $path; +} + +function os_mkdir($path, $mode = 0777, $recursive = false) { + $oldumask = @umask(0); + $result = @mkdir($path, $mode, $recursive); + @umask($oldumask); + return $result; +} + +/** + * @brief Function to check if request was an AJAX (xmlhttprequest) request. + * + * @return boolean + */ +function is_ajax() { + return (!empty($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'); +} + + +// Primarily involved with database upgrade, but also sets the +// base url for use in cmdline programs which don't have +// $_SERVER variables, and synchronising the state of installed plugins. + +function check_config(&$a) { + + $build = get_config('system','db_version'); + if(! intval($build)) + $build = set_config('system','db_version',DB_UPDATE_VERSION); + + $saved = get_config('system','urlverify'); + if(! $saved) + set_config('system','urlverify',bin2hex(z_root())); + + if(($saved) && ($saved != bin2hex(z_root()))) { + // our URL changed. Do something. + + $oldurl = hex2bin($saved); + logger('Baseurl changed!'); + + $oldhost = substr($oldurl, strpos($oldurl, '//') + 2); + $host = substr(z_root(), strpos(z_root(), '//') + 2); + + $is_ip_addr = ((preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$host)) ? true : false); + $was_ip_addr = ((preg_match("/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/",$oldhost)) ? true : false); + // only change the url to an ip address if it was already an ip and not a dns name + if((! $is_ip_addr) || ($is_ip_addr && $was_ip_addr)) { + fix_system_urls($oldurl,z_root()); + set_config('system', 'urlverify', bin2hex(z_root())); + } + else + logger('Attempt to change baseurl from a DNS name to an IP address was refused.'); + } + + // This will actually set the url to the one stored in .htconfig, and ignore what + // we're passing - unless we are installing and it has never been set. + + $a->set_baseurl($a->get_baseurl()); + + // Make sure each site has a system channel. This is now created on install + // so we just need to keep this around a couple of weeks until the hubs that + // already exist have one + $syschan_exists = get_sys_channel(); + if (! $syschan_exists) + create_sys_channel(); + + if($build != DB_UPDATE_VERSION) { + $stored = intval($build); + if(! $stored) { + logger('Critical: check_config unable to determine database schema version'); + return; + } + $current = intval(DB_UPDATE_VERSION); + if(($stored < $current) && file_exists('install/update.php')) { + + load_config('database'); + + // We're reporting a different version than what is currently installed. + // Run any existing update scripts to bring the database up to current. + require_once('install/update.php'); + + // make sure that boot.php and update.php are the same release, we might be + // updating right this very second and the correct version of the update.php + // file may not be here yet. This can happen on a very busy site. + + if(DB_UPDATE_VERSION == UPDATE_VERSION) { + for($x = $stored; $x < $current; $x ++) { + if(function_exists('update_r' . $x)) { + // There could be a lot of processes running or about to run. + // We want exactly one process to run the update command. + // So store the fact that we're taking responsibility + // after first checking to see if somebody else already has. + + // If the update fails or times-out completely you may need to + // delete the config entry to try again. + + if(get_config('database','update_r' . $x)) + break; + set_config('database','update_r' . $x, '1'); + // call the specific update + + $func = 'update_r' . $x; + $retval = $func(); + if($retval) { + + // Prevent sending hundreds of thousands of emails by creating + // a lockfile. + + $lockfile = 'store/[data]/mailsent'; + + if ((file_exists($lockfile)) && (filemtime($lockfile) > (time() - 86400))) + return; + @unlink($lockfile); + //send the administrator an e-mail + file_put_contents($lockfile, $x); + + $email_tpl = get_intltext_template("update_fail_eml.tpl"); + $email_msg = replace_macros($email_tpl, array( + '$sitename' => $a->config['system']['sitename'], + '$siteurl' => $a->get_baseurl(), + '$update' => $x, + '$error' => sprintf( t('Update %s failed. See error logs.'), $x) + )); + + $subject = email_header_encode(sprintf(t('Update Error at %s'), $a->get_baseurl())); + + mail($a->config['system']['admin_email'], $subject, $email_msg, + 'From: Administrator' . '@' . $_SERVER['SERVER_NAME'] . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); + //try the logger + logger('CRITICAL: Update Failed: ' . $x); + } + else + set_config('database','update_r' . $x, 'success'); + } + } + set_config('system','db_version', DB_UPDATE_VERSION); + } + } + } + + /** + * + * Synchronise plugins: + * + * $a->config['system']['addon'] contains a comma-separated list of names + * of plugins/addons which are used on this system. + * Go through the database list of already installed addons, and if we have + * an entry, but it isn't in the config list, call the unload procedure + * and mark it uninstalled in the database (for now we'll remove it). + * Then go through the config list and if we have a plugin that isn't installed, + * call the install procedure and add it to the database. + * + */ + + $r = q("SELECT * FROM `addon` WHERE `installed` = 1"); + if($r) + $installed = $r; + else + $installed = array(); + + $plugins = get_config('system', 'addon'); + $plugins_arr = array(); + + if($plugins) + $plugins_arr = explode(',', str_replace(' ', '', $plugins)); + + $a->plugins = $plugins_arr; + + $installed_arr = array(); + + if(count($installed)) { + foreach($installed as $i) { + if(! in_array($i['name'], $plugins_arr)) { + unload_plugin($i['name']); + } + else { + $installed_arr[] = $i['name']; + } + } + } + + if(count($plugins_arr)) { + foreach($plugins_arr as $p) { + if(! in_array($p, $installed_arr)) { + load_plugin($p); + } + } + } + + load_hooks(); +} + + +function fix_system_urls($oldurl, $newurl) { + + require_once('include/crypto.php'); + + logger('fix_system_urls: renaming ' . $oldurl . ' to ' . $newurl); + + // Basically a site rename, but this can happen if you change from http to https for instance - even if the site name didn't change + // This should fix URL changes on our site, but other sites will end up with orphan hublocs which they will try to contact and will + // cause wasted communications. + // What we need to do after fixing this up is to send a revocation of the old URL to every other site that we communicate with so + // that they can clean up their hubloc tables (this includes directories). + // It's a very expensive operation so you don't want to have to do it often or after your site gets to be large. + + $r = q("select xchan.*, hubloc.* from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url like '%s'", + dbesc($oldurl . '%') + ); + + if($r) { + foreach($r as $rr) { + $channel_address = substr($rr['hubloc_addr'],0,strpos($rr['hubloc_addr'],'@')); + + // get the associated channel. If we don't have a local channel, do nothing for this entry. + + $c = q("select * from channel where channel_hash = '%s' limit 1", + dbesc($rr['hubloc_hash']) + ); + if(! $c) + continue; + + $parsed = @parse_url($newurl); + if(! $parsed) + continue; + $newhost = $parsed['host']; + + // sometimes parse_url returns unexpected results. + + if(strpos($newhost,'/') !== false) + $newhost = substr($newhost,0,strpos($newhost,'/')); + + $rhs = $newhost . (($parsed['port']) ? ':' . $parsed['port'] : ''); + + // paths aren't going to work. You have to be at the (sub)domain root + // . (($parsed['path']) ? $parsed['path'] : ''); + + // The xchan_url might point to another nomadic identity clone + + $replace_xchan_url = ((strpos($rr['xchan_url'],$oldurl) !== false) ? true : false); + + $x = q("update xchan set xchan_addr = '%s', xchan_url = '%s', xchan_connurl = '%s', xchan_follow = '%s', xchan_connpage = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_date = '%s' where xchan_hash = '%s'", + dbesc($channel_address . '@' . $rhs), + dbesc(($replace_xchan_url) ? str_replace($oldurl,$newurl,$rr['xchan_url']) : $rr['xchan_url']), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_connurl'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_follow'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_connpage'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_l'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_m'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_s'])), + dbesc(datetime_convert()), + dbesc($rr['xchan_hash']) + ); + + $y = q("update hubloc set hubloc_addr = '%s', hubloc_url = '%s', hubloc_url_sig = '%s', hubloc_host = '%s', hubloc_callback = '%s' where hubloc_hash = '%s' and hubloc_url = '%s'", + dbesc($channel_address . '@' . $rhs), + dbesc($newurl), + dbesc(base64url_encode(rsa_sign($newurl,$c[0]['channel_prvkey']))), + dbesc($newhost), + dbesc($newurl . '/post'), + dbesc($rr['xchan_hash']), + dbesc($oldurl) + ); + + $z = q("update profile set photo = '%s', thumb = '%s' where uid = %d", + dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_l'])), + dbesc(str_replace($oldurl,$newurl,$rr['xchan_photo_m'])), + intval($c[0]['channel_id']) + ); + + proc_run('php', 'include/notifier.php', 'refresh_all', $c[0]['channel_id']); + } + } +} + + +// wrapper for adding a login box. If $register == true provide a registration +// link. This will most always depend on the value of $a->config['system']['register_policy']. +// returns the complete html for inserting into the page + +function login($register = false, $form_id = 'main-login', $hiddens=false) { + $a = get_app(); + $o = ''; + $reg = false; + $reglink = get_config('system', 'register_link'); + if(! strlen($reglink)) + $reglink = 'register'; + + $reg = array( + 'title' => t('Create an account to access services and applications within the Hubzilla'), + 'desc' => t('Register'), + 'link' => (($register) ? $reglink : 'pubsites') + ); + + $dest_url = $a->get_baseurl(true) . '/' . $a->query_string; + + if(local_channel()) { + $tpl = get_markup_template("logout.tpl"); + } + else { +// There's no such thing as login_head.tpl, has never been in Red, removed from Friendica 1 Jun 2013... + +// $a->page['htmlhead'] .= replace_macros(get_markup_template("login_head.tpl"), array( +// '$baseurl' => $a->get_baseurl(true) +// )); + + $tpl = get_markup_template("login.tpl"); + if(strlen($a->query_string)) + $_SESSION['login_return_url'] = $a->query_string; + } + + $o .= replace_macros($tpl,array( + '$dest_url' => $dest_url, + '$logout' => t('Logout'), + '$login' => t('Login'), + '$form_id' => $form_id, + '$lname' => array('username', t('Email') , '', ''), + '$lpassword' => array('password', t('Password'), '', ''), + '$remember' => array('remember', t('Remember me'), '', '',array(t('No'),t('Yes'))), + '$hiddens' => $hiddens, + '$register' => $reg, + '$lostpass' => t('Forgot your password?'), + '$lostlink' => t('Password Reset'), + )); + + call_hooks('login_hook', $o); + + return $o; +} + + +/** + * @brief Used to end the current process, after saving session state. + */ +function killme() { + session_write_close(); + exit; +} + +/** + * @brief Redirect to another URL and terminate this process. + */ +function goaway($s) { + header("Location: $s"); + killme(); +} + +/** + * @brief Returns the entity id of locally logged in account or false. + * + * Returns numeric account_id if authenticated or 0. It is possible to be + * authenticated and not connected to a channel. + * + * @return int|bool account_id or false + */ +function get_account_id() { + if(get_app()->account) + return intval(get_app()->account['account_id']); + + return false; +} + +/** + * @brief Returns the entity id (channel_id) of locally logged in channel or false. + * + * Returns authenticated numeric channel_id if authenticated and connected to + * a channel or 0. Sometimes referred to as $uid in the code. + * + * Before 2.1 this function was called local_user(). + * + * @since 2.1 + * @return int|bool channel_id or false + */ +function local_channel() { + if((x($_SESSION, 'authenticated')) && (x($_SESSION, 'uid'))) + return intval($_SESSION['uid']); + + return false; +} + +/** + * local_user() got deprecated and replaced by local_channel(). + * + * @deprecated since v2.1, use local_channel() + * @see local_channel() + */ +function local_user() { + logger('local_user() is DEPRECATED, use local_channel()'); + return local_channel(); +} + + +/** + * @brief Returns a xchan_hash (visitor_id) of remote authenticated visitor + * or false. + * + * Returns authenticated string hash of Red global identifier (xchan_hash), if + * authenticated via remote auth, or an empty string. + * + * Before 2.1 this function was called remote_user(). + * + * @since 2.1 + * @return string|bool visitor_id or false + */ +function remote_channel() { + if((x($_SESSION, 'authenticated')) && (x($_SESSION, 'visitor_id'))) + return $_SESSION['visitor_id']; + + return false; +} + +/** + * remote_user() got deprecated and replaced by remote_channel(). + * + * @deprecated since v2.1, use remote_channel() + * @see remote_channel() + */ +function remote_user() { + logger('remote_user() is DEPRECATED, use remote_channel()'); + return remote_channel(); +} + + +/** + * Contents of $s are displayed prominently on the page the next time + * a page is loaded. Usually used for errors or alerts. + * + * @param string $s Text to display + */ +function notice($s) { + $a = get_app(); + if(! x($_SESSION, 'sysmsg')) $_SESSION['sysmsg'] = array(); + + // ignore duplicated error messages which haven't yet been displayed + // - typically seen as multiple 'permission denied' messages + // as a result of auto-reloading a protected page with &JS=1 + + if(in_array($s,$_SESSION['sysmsg'])) + return; + + if($a->interactive) { + $_SESSION['sysmsg'][] = $s; + } + +} + +/** + * Contents of $s are displayed prominently on the page the next time a page is + * loaded. Usually used for information. + * For error and alerts use notice(). + * + * @param string $s Text to display + */ +function info($s) { + $a = get_app(); + if(! x($_SESSION, 'sysmsg_info')) $_SESSION['sysmsg_info'] = array(); + if($a->interactive) + $_SESSION['sysmsg_info'][] = $s; +} + +/** + * @brief Wrapper around config to limit the text length of an incoming message + * + * @return int + */ +function get_max_import_size() { + return(intval(get_config('system', 'max_import_size'))); +} + + +/** + * + * Wrap calls to proc_close(proc_open()) and call hook + * so plugins can take part in process :) + * + * args: + * $cmd program to run + * next args are passed as $cmd command line + * + * e.g.: proc_run("ls","-la","/tmp"); + * + * $cmd and string args are surrounded with "" + */ +function proc_run($cmd){ + + $a = get_app(); + + $args = func_get_args(); + + $newargs = array(); + if(! count($args)) + return; + + // expand any arrays + + foreach($args as $arg) { + if(is_array($arg)) { + foreach($arg as $n) { + $newargs[] = $n; + } + } + else + $newargs[] = $arg; + } + + $args = $newargs; + + $arr = array('args' => $args, 'run_cmd' => true); + + call_hooks("proc_run", $arr); + if(! $arr['run_cmd']) + return; + + if(count($args) && $args[0] === 'php') + $args[0] = ((x($a->config,'system')) && (x($a->config['system'],'php_path')) && (strlen($a->config['system']['php_path'])) ? $a->config['system']['php_path'] : 'php'); + + for($x = 0; $x < count($args); $x++) + $args[$x] = escapeshellarg($args[$x]); + + $cmdline = implode($args," "); + + if(is_windows()) { + $cwd = getcwd(); + $cmd = "cmd /c start \"title\" /D \"$cwd\" /b $cmdline"; + proc_close(proc_open($cmd, array(), $foo)); + } + else + proc_close(proc_open($cmdline ." &", array(), $foo)); +} + +/** + * @brief Checks if we are running on M$ Windows. + * + * @return bool true if we run on M$ Windows + */ +function is_windows() { + return ((strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') ? true : false); +} + + +function current_theme(){ + $app_base_themes = array('redbasic'); + + $a = get_app(); + $page_theme = null; + + // Find the theme that belongs to the channel whose stuff we are looking at + + if($a->profile_uid && $a->profile_uid != local_channel()) { + $r = q("select channel_theme from channel where channel_id = %d limit 1", + intval($a->profile_uid) + ); + if($r) + $page_theme = $r[0]['channel_theme']; + } + + if(array_key_exists('theme', $a->layout) && $a->layout['theme']) + $page_theme = $a->layout['theme']; + + // Allow folks to over-rule channel themes and always use their own on their own site. + // The default is for channel themes to take precedence over your own on pages belonging + // to that channel. + + if($page_theme && local_channel() && local_channel() != $a->profile_url) { + if(get_pconfig(local_channel(),'system','always_my_theme')) + $page_theme = null; + } + + $is_mobile = $a->is_mobile || $a->is_tablet; + + $standard_system_theme = ((isset($a->config['system']['theme'])) ? $a->config['system']['theme'] : ''); + $standard_theme_name = ((isset($_SESSION) && x($_SESSION,'theme')) ? $_SESSION['theme'] : $standard_system_theme); + + if($is_mobile) { + if(isset($_SESSION['show_mobile']) && !$_SESSION['show_mobile']) { + $system_theme = $standard_system_theme; + $theme_name = $standard_theme_name; + } + else { + $system_theme = ((isset($a->config['system']['mobile_theme'])) ? $a->config['system']['mobile_theme'] : ''); + $theme_name = ((isset($_SESSION) && x($_SESSION,'mobile_theme')) ? $_SESSION['mobile_theme'] : $system_theme); + + if($theme_name === '' || $theme_name === '---' ) { + // user has selected to have the mobile theme be the same as the normal one + $system_theme = $standard_system_theme; + $theme_name = $standard_theme_name; + } + } + } + else { + $system_theme = $standard_system_theme; + $theme_name = $standard_theme_name; + + if($page_theme) + $theme_name = $page_theme; + } + + if($theme_name && + (file_exists('view/theme/' . $theme_name . '/css/style.css') || + file_exists('view/theme/' . $theme_name . '/php/style.php'))) + return($theme_name); + + foreach($app_base_themes as $t) { + if(file_exists('view/theme/' . $t . '/css/style.css') || + file_exists('view/theme/' . $t . '/php/style.php')) + return($t); + } + + $fallback = array_merge(glob('view/theme/*/css/style.css'),glob('view/theme/*/php/style.php')); + if(count($fallback)) + return (str_replace('view/theme/','', substr($fallback[0],0,-10))); + +} + + +/** + * @brief Return full URL to theme which is currently in effect. + * + * Provide a sane default if nothing is chosen or the specified theme does not exist. + * + * @param bool $installing default false + * + * @return string + */ +function current_theme_url($installing = false) { + global $a; + + $t = current_theme(); + + $opts = ''; + $opts = (($a->profile_uid) ? '?f=&puid=' . $a->profile_uid : ''); + $opts .= ((x($a->layout,'schema')) ? '&schema=' . $a->layout['schema'] : ''); + if(file_exists('view/theme/' . $t . '/php/style.php')) + return('view/theme/' . $t . '/php/style.pcss' . $opts); + + return('view/theme/' . $t . '/css/style.css'); +} + +/** + * @brief Check if current user has admin role. + * + * Check if the current user has ACCOUNT_ROLE_ADMIN. + * + * @return bool true if user is an admin + */ +function is_site_admin() { + $a = get_app(); + + if($_SESSION['delegate']) + return false; + + if((intval($_SESSION['authenticated'])) + && (is_array($a->account)) + && ($a->account['account_roles'] & ACCOUNT_ROLE_ADMIN)) + return true; + + return false; +} + +/** + * @brief Check if current user has developer role. + * + * Check if the current user has ACCOUNT_ROLE_DEVELOPER. + * + * @return bool true if user is a developer + */ +function is_developer() { + $a = get_app(); + if((intval($_SESSION['authenticated'])) + && (is_array($a->account)) + && ($a->account['account_roles'] & ACCOUNT_ROLE_DEVELOPER)) + return true; + + return false; +} + + +function load_contact_links($uid) { + $a = get_app(); + + $ret = array(); + + if(! $uid || x($a->contacts,'empty')) + return; + +// logger('load_contact_links'); + + $r = q("SELECT abook_id, abook_flags, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d ", + intval($uid) + ); + if($r) { + foreach($r as $rr){ + $ret[$rr['xchan_hash']] = $rr; + } + } + else + $ret['empty'] = true; + + $a->contacts = $ret; +} + + +/** + * @brief Returns querystring as string from a mapped array. + * + * @param array $params mapped array with query parameters + * @param string $name of parameter, default null + * + * @return string + */ +function build_querystring($params, $name = null) { + $ret = ''; + foreach($params as $key => $val) { + if(is_array($val)) { + if($name === null) { + $ret .= build_querystring($val, $key); + } else { + $ret .= build_querystring($val, $name . "[$key]"); + } + } else { + $val = urlencode($val); + if($name != null) { + $ret .= $name . "[$key]" . "=$val&"; + } else { + $ret .= "$key=$val&"; + } + } + } + return $ret; +} + + +// much better way of dealing with c-style args + +function argc() { + return get_app()->argc; +} + +function argv($x) { + if(array_key_exists($x,get_app()->argv)) + return get_app()->argv[$x]; + + return ''; +} + +function dba_timer() { + return microtime(true); +} + +/** + * @brief Returns xchan_hash from the observer. + * + * @return string Empty if no observer, otherwise xchan_hash from observer + */ +function get_observer_hash() { + $observer = get_app()->get_observer(); + if(is_array($observer)) + return $observer['xchan_hash']; + + return ''; +} + + +/** + * Returns the complete URL of the current page, e.g.: http(s)://something.com/network + * + * Taken from http://webcheatsheet.com/php/get_current_page_url.php + */ +function curPageURL() { + $pageURL = 'http'; + if ($_SERVER["HTTPS"] == "on") {$pageURL .= "s";} + $pageURL .= "://"; + if ($_SERVER["SERVER_PORT"] != "80" && $_SERVER["SERVER_PORT"] != "443") { + $pageURL .= $_SERVER["SERVER_NAME"].":".$_SERVER["SERVER_PORT"].$_SERVER["REQUEST_URI"]; + } else { + $pageURL .= $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"]; + } + return $pageURL; +} + +/** + * @brief Returns a custom navigation by name??? + * + * If no $navname provided load default page['nav'] + * + * @todo not fully implemented yet + * + * @param App $a global application object + * @param string $navname + * + * @return mixed + */ +function get_custom_nav(&$a, $navname) { + if (! $navname) + return $a->page['nav']; + // load custom nav menu by name here +} + +/** + * @brief Loads a page definition file for a module. + * + * If there is no parsed Comanche template already load a module's pdl file + * and parse it with Comanche. + * + * @param App &$a global application object + */ +function load_pdl(&$a) { + require_once('include/comanche.php'); + + if (! count($a->layout)) { + + $arr = array('module' => $a->module, 'layout' => ''); + call_hooks('load_pdl',$arr); + $s = $arr['layout']; + + $n = 'mod_' . $a->module . '.pdl' ; + $u = comanche_get_channel_id(); + if($u) + $s = get_pconfig($u, 'system', $n); + + if((! $s) && (($p = theme_include($n)) != '')) + $s = @file_get_contents($p); + if($s) { + comanche_parser($a, $s); + $a->pdl = $s; + } + } + +} + + +function exec_pdl(&$a) { + require_once('include/comanche.php'); + + if($a->pdl) { + comanche_parser($a, $a->pdl,1); + } +} + + +/** + * @brief build the page. + * + * Build the page - now that we have all the components + * + * @param App &$a global application object + */ +function construct_page(&$a) { + + exec_pdl($a); + + $comanche = ((count($a->layout)) ? true : false); + + require_once(theme_include('theme_init.php')); + + $installing = false; + + if ($a->module == 'setup') { + $installing = true; + } else { + nav($a); + } + + if ($comanche) { + if ($a->layout['nav']) { + $a->page['nav'] = get_custom_nav($a, $a->layout['nav']); + } + } + + if (($p = theme_include(current_theme() . '.js')) != '') + head_add_js($p); + + if (($p = theme_include('mod_' . $a->module . '.php')) != '') + require_once($p); + + require_once('include/js_strings.php'); + + if (x($a->page, 'template_style')) + head_add_css($a->page['template_style'] . '.css'); + else + head_add_css(((x($a->page, 'template')) ? $a->page['template'] : 'default' ) . '.css'); + + head_add_css('mod_' . $a->module . '.css'); + head_add_css(current_theme_url($installing)); + + head_add_js('mod_' . $a->module . '.js'); + + $a->build_pagehead(); + + $arr = $a->get_widgets(); + ksort($arr, SORT_NUMERIC); + if(count($arr)) { + foreach($arr as $x) { + if(! array_key_exists($x['location'], $a->page)) + $a->page[$x['location']] = ''; + + $a->page[$x['location']] .= $x['html']; + } + } + + // Let's say we have a comanche declaration '[region=nav][/region][region=content]$nav $content[/region]'. + // The text 'region=' identifies a section of the layout by that name. So what we want to do here is leave + // $a->page['nav'] empty and put the default content from $a->page['nav'] and $a->page['section'] + // into a new region called $a->data['content']. It is presumed that the chosen layout file for this comanche page + // has a '' element instead of a '
'. + + // This way the Comanche layout can include any existing content, alter the layout by adding stuff around it or changing the + // layout completely with a new layout definition, or replace/remove existing content. + + if($comanche) { + $arr = array('module' => $a->module, 'layout' => $a->layout); + call_hooks('construct_page', $arr); + $a->layout = $arr['layout']; + + foreach($a->layout as $k => $v) { + if((strpos($k, 'region_') === 0) && strlen($v)) { + if(strpos($v, '$region_') !== false) { + $v = preg_replace_callback('/\$region_([a-zA-Z0-9]+)/ism', 'comanche_replace_region', $v); + } + + // And a couple of convenience macros + if(strpos($v, '$htmlhead') !== false) { + $v = str_replace('$htmlhead', $a->page['htmlhead'], $v); + } + if(strpos($v, '$nav') !== false) { + $v = str_replace('$nav', $a->page['nav'], $v); + } + if(strpos($v, '$content') !== false) { + $v = str_replace('$content', $a->page['content'], $v); + } + + $a->page[substr($k, 7)] = $v; + } + } + } + + if($a->is_mobile || $a->is_tablet) { + if(isset($_SESSION['show_mobile']) && !$_SESSION['show_mobile']) { + $link = $a->get_baseurl() . '/toggle_mobile?f=&address=' . curPageURL(); + } + else { + $link = $a->get_baseurl() . '/toggle_mobile?f=&off=1&address=' . curPageURL(); + } + if ((isset($_SESSION) && $_SESSION['mobile_theme'] !='' && $_SESSION['mobile_theme'] !='---' ) || + (isset($a->config['system']['mobile_theme']) && !isset($_SESSION['mobile_theme']))) { + $a->page['footer'] .= replace_macros(get_markup_template("toggle_mobile_footer.tpl"), array( + '$toggle_link' => $link, + '$toggle_text' => t('toggle mobile') + )); + } + } + + $page = $a->page; + $profile = $a->profile; + + header("Content-type: text/html; charset=utf-8"); + + require_once(theme_include( + ((x($a->page, 'template')) ? $a->page['template'] : 'default' ) . '.php' ) + ); +} + +/** + * @brief Returns Hubzilla's root directory. + * + * @return string + */ +function appdirpath() { + return dirname(__FILE__); +} + +/** + * @brief Set a pageicon. + * + * @param string $icon + */ +function head_set_icon($icon) { + global $a; + + $a->data['pageicon'] = $icon; +// logger('head_set_icon: ' . $icon); +} + +/** + * @brief Get the pageicon. + * + * @return string absolut path to pageicon + */ +function head_get_icon() { + global $a; + + $icon = $a->data['pageicon']; + if(! strpos($icon, '://')) + $icon = z_root() . $icon; + + return $icon; +} + +/** + * @brief Return the Realm of the directory. + * + * @return string + */ +function get_directory_realm() { + if($x = get_config('system', 'directory_realm')) + return $x; + + return DIRECTORY_REALM; +} + +/** + * @brief Return the primary directory server. + * + * @return string + */ +function get_directory_primary() { + + $dirmode = intval(get_config('system','directory_mode')); + + if($dirmode == DIRECTORY_MODE_STANDALONE || $dirmode == DIRECTORY_MODE_PRIMARY) { + return z_root(); + } + + if($x = get_config('system', 'directory_primary')) + return $x; + + return DIRECTORY_FALLBACK_MASTER; +} + + +/** + * @brief return relative date of last completed poller execution. + */ +function get_poller_runtime() { + $t = get_config('system', 'lastpoll'); + return relative_date($t); +} + +function z_get_upload_dir() { + $upload_dir = get_config('system','uploaddir'); + if(! $upload_dir) + $upload_dir = ini_get('upload_tmp_dir'); + if(! $upload_dir) + $upload_dir = sys_get_temp_dir(); + return $upload_dir; +} + +function z_get_temp_dir() { + $temp_dir = get_config('system','tempdir'); + if(! $temp_dir) + $temp_dir = sys_get_temp_dir(); + return $upload_dir; +} + +function z_check_cert() { + $a = get_app(); + if(strpos(z_root(),'https://') !== false) { + $x = z_fetch_url(z_root() . '/siteinfo/json'); + if(! $x['success']) { + $recurse = 0; + $y = z_fetch_url(z_root() . '/siteinfo/json',false,$recurse,array('novalidate' => true)); + if($y['success']) + cert_bad_email(); + } + } +} + + +/** + * @brief Send email to admin if server has an invalid certificate. + * + * If a Hubzilla hub is available over https it must have a publicly valid + * certificate. + */ +function cert_bad_email() { + + $a = get_app(); + + $email_tpl = get_intltext_template("cert_bad_eml.tpl"); + $email_msg = replace_macros($email_tpl, array( + '$sitename' => $a->config['system']['sitename'], + '$siteurl' => $a->get_baseurl(), + '$error' => t('Website SSL certificate is not valid. Please correct.') + )); + + $subject = email_header_encode(sprintf(t('[hubzilla] Website SSL error for %s'), $a->get_hostname())); + mail($a->config['system']['admin_email'], $subject, $email_msg, + 'From: Administrator' . '@' . $a->get_hostname() . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); +} + + +/** + * @brief Send warnings every 3-5 days if cron is not running. + */ +function check_cron_broken() { + + $t = get_config('system','lastpollcheck'); + if(! $t) { + // never checked before. Start the timer. + set_config('system','lastpollcheck',datetime_convert()); + return; + } + if($t > datetime_convert('UTC','UTC','now - 3 days')) { + // Wait for 3 days before we do anything so as not to swamp the admin with messages + return; + } + + $d = get_config('system','lastpoll'); + if(($d) && ($d > datetime_convert('UTC','UTC','now - 3 days'))) { + // Scheduled tasks have run successfully in the last 3 days. + set_config('system','lastpollcheck',datetime_convert()); + return; + } + + $a = get_app(); + + $email_tpl = get_intltext_template("cron_bad_eml.tpl"); + $email_msg = replace_macros($email_tpl, array( + '$sitename' => $a->config['system']['sitename'], + '$siteurl' => $a->get_baseurl(), + '$error' => t('Cron/Scheduled tasks not running.'), + '$lastdate' => (($d)? $d : t('never')) + )); + + $subject = email_header_encode(sprintf(t('[hubzilla] Cron tasks not running on %s'), $a->get_hostname())); + mail($a->config['system']['admin_email'], $subject, $email_msg, + 'From: Administrator' . '@' . $a->get_hostname() . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); + set_config('system','lastpollcheck',datetime_convert()); + return; +} diff --git a/sources/doc/AdvancedSearch.md b/sources/doc/AdvancedSearch.md new file mode 100644 index 00000000..a67c1fc1 --- /dev/null +++ b/sources/doc/AdvancedSearch.md @@ -0,0 +1,53 @@ +Advanced Directory Search +========================= + + +Advanced Directory Search is enabled in "Expert Mode" from your Settings => Additional features page. + +On the Directory page an option named "Advanced" will apear in the "Find Channels" widget (typically in the sidebar). Clicking "Advanced" will open another search box for entering advanced search requests. + +Advanced requests include + +* name=xxx +[Channel name contains xxx] + +* address=xxx +[Channel address (webbie) contains xxx] + +* locale=xxx +[Locale (typically 'city') contains xxx] + +* region=xxx +[Region (state/territory) contains xxx] + +* postcode=xxx +[Postcode or zip code contains xxx] + +* country=xxx +[Country name contains xxx] + +* gender=xxx +[Gender contains xxx] + +* marital=xxx +[Marital status contains xxx] + +* sexual=xxx +[Sexual preference contains xxx] + +* keywords=xxx +[Keywords contain xxx] + +There are many reasons why a match may not return what you're looking for, as many channels do not provide detailed information in their default (public) profile, and many of these fields allow free-text input in several languages - and this may be difficult to match precisely. For instance you may have better results finding somebody in the USA with 'country=u' (along with some odd channels from Deutschland and Bulgaria and Australia) because this could be represented in a profile as US, U.S.A, USA, United States, etc... + +Future revisions of this tool may try to smooth over some of these difficulties. + +Requests may be joined together with 'and', 'or', and 'and not'. + +Terms containing spaces must be quoted. + +Example: + + name="charlie brown" and country=canada and not gender=female + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Comparison-of-activity-stream-networks.md b/sources/doc/Comparison-of-activity-stream-networks.md new file mode 100644 index 00000000..d76ae100 --- /dev/null +++ b/sources/doc/Comparison-of-activity-stream-networks.md @@ -0,0 +1,23 @@ +Comparison of different server-client networks providing activity streams to users +==================================== +The goal of this table was to provide an overview of the security and privacy provided by server-client networks providing activity-streams. + +| project | license | distributed | supports node isolation | server-to-server encryption | 1-click E2EE* | database encryption sceme | supports cloning[^5] | encryption of private messages | PFS chat | wall-to-wall interaction | supports post editing and unsend private message | other | +|-----------+---------------+-------------+-------------------------+-------------------------------------------+------------------------------------------+-----------------------------------------------------+-------------------------+-------------------------------------------------------------------------------------------------+-----------------------------------------------+--------------------------------------------------------------+--------------------------------------------------+------------------------------------------------------------------------------| +| hubzilla | ISC aka MIT | yes | yes | Zot (PKI) + TLS | yes (via JavaScript, AES-256) | content obfuscation, private keys hidden in the DB. | yes, partly implemented | impossible to message privately in plaintext | no | yes, multiple separated channels possible within one account | yes | privacy built in, run your own @ home, nodes are called hubs | +| diaspora | AGPLv3orlater | yes | no[^1] | PKI + SSL/TLS[^1] | no[^2] | mostly plaintext | no | ? | no | yes, no naming policy | no | nodes are called pods | +| facebook | proprietary | no | no | planned, probably not implemented yet[^3] | implemented but not offered to users[^4] | unknown | no, walled garden | no, 3-d party plugin Cryptocat and pidgin is availiable but the user is not informed about this | no, with Cryptocat: yes, with pidgin+OTR: yes | only one wall allowed | only post editing | "real name"-policy enforced, advertising-driven, for profit company US-based | +| twitter | proprietary | no | no | unknown | no | unknown, probably none | no, walled garden | no | no | yes | only post editing | advertising-driven, for profit company US-based | +| | | | | | | | | | | | | | + +This table was edited with emacs using org-mode. + +[^1]: https://wiki.diasporafoundation.org/Federation_protocol_overview + +[^2]: forks providing this exists + +[^3]: http://news.softpedia.com/news/Facebook-Aims-to-Encrypt-Everything-Between-Data-Centers-433091.shtml + +[^4]: http://www.computerworld.com/article/2488773/cybercrime-hacking/facebook-holds-back-on-end-to-end-encryption.html + +[^5]: see the hubzilla help files for details about this feature. diff --git a/sources/doc/Creating-Templates.md b/sources/doc/Creating-Templates.md new file mode 100644 index 00000000..6de627f3 --- /dev/null +++ b/sources/doc/Creating-Templates.md @@ -0,0 +1,93 @@ +Creating Page Templates +======================= + + +A page template for use with Comanche requires two files - a PHP template and a CSS file. Page templates will need to be installed by the system administrator of your site. + + +First choose a name. Here we'll create a template and call it "demo". + +You will need to create the files "view/php/demo.php" and "view/css/demo.css" to hold the PHP template and CSS respectively. + +To get a better idea of this process, let's look at an existing template - the "default" template. This is used by default throughout the application. + +view/php/default.php +==================== + + + + + <?php if(x($page,'title')) echo $page['title'] ?> + + + + + + +
+ +
+
+ +
+ + + + +Here's is the corresponding CSS file + +view/php/default.css +==================== + + + aside#region_1 { + display: block; + width: 210px; + position: absolute; + top: 65px; + left: 0; + margin-left: 10px; + } + + aside input[type='text'] { + width: 174px; + } + + + section { + position: absolute; + top: 65px; + left: 250px; + display: block; + right: 15px; + padding-bottom: 350px; + } + + +Some things you may notice when looking at these definitions: + +* We have not specified any CSS for the "nav", "right_aside", or "footer" regions. In this template "nav" and "footer" will be the full page width and we will let the size and placement of these elements be controlled by the theme. "right_aside" is not currently used. + +* There are elements on the page such as "page-footer" and "pause" for which there is no apparent content. This content will come from Javascript elements. + +* Our default template uses absolute positioning. Modern web design often uses "float" div containers so that scrollbars aren't typically needed when viewing on small-screen devices. + +To design a new template, it is best to start with an existing template, and modify it as desired. That is what we will do here. + +The way that Comanche provides content inside a specific region is by using a region tag. + + [region=aside][widget=profile][/widget][/region] + +This example will place a "profile" widget in the "aside" region. But what it actually does is place the HTML for the widget into a code variable **$page['aside']**. Our default page template defines a region on the page (the CSS positions this as an absolute sidebar) and then inserts the contents of $page['aside'] (if it exists). + +So if you wanted to create a template with a region named "foo", you would provide a place for it on the page, then include the contents of $page['foo'] wherever you wanted to use it, and then using Comanche, you could specify + + [region=foo][widget=profile][/widget][/region] + +and this would place a profile widget into the "foo" region you created. + +Use the CSS file to position the region on the page where desired and optionally control its size. + +[To be continued] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/DerivedTheme1.md b/sources/doc/DerivedTheme1.md new file mode 100644 index 00000000..805d6b61 --- /dev/null +++ b/sources/doc/DerivedTheme1.md @@ -0,0 +1,77 @@ +Creating a Derived Theme +======================== + +**Lesson 1** + +A derived theme takes most of the settings from its "parent" theme and lets you change a few things to your liking without creating an entire theme package. + + +To create a derived theme, first choose a name. For our example we'll call our theme 'mytheme'. Hopefully you'll be a bit more creative. But throughout this document, wherever you see 'mytheme', replace that with the name you chose. + +**Directory Structure** + +First you need to create a theme directory structure. We'll keep it simple. We need a php directory and a css directory. Here are the Unix/Linux commands to do this. Assume that 'mywebsite' is your top level $Projectname folder. + + + cd mywebsite + mkdir view/theme/mytheme + mkdir view/theme/mytheme/css + mkdir view/theme/mytheme/php + + +Great. Now we need a couple of files. The first one is your theme info file, which describes the theme. + +It will be called view/theme/mytheme/php/theme.php (clever name huh?) + +Inside it, put the following information - edit as needed + + theme_info['extends'] = 'redbasic'; + + + } + + +Remember to rename the mytheme_init function with your theme name. In this case we will be extending the theme 'redbasic'. + + +Now create another file. We call this a PCSS file, but it's really a PHP file. + +The file is called view/theme/mytheme/php/style.php + +In it, put the following: + + Display Settings as their default theme. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Developers.md b/sources/doc/Developers.md new file mode 100644 index 00000000..b19b4fc2 --- /dev/null +++ b/sources/doc/Developers.md @@ -0,0 +1,54 @@ +Developer Guide +=================== + +**Here is how you can join us.** + +First, get yourself a working git package on the system where you will be +doing development. + +Create your own github account. + +You may fork/clone the Red repository from [https://github.com/redmatrix/hubzilla.git](https://github.com/redmatrix/hubzilla.git). + +Follow the instructions provided here: [http://help.github.com/fork-a-repo/](http://help.github.com/fork-a-repo/) +to create and use your own tracking fork on github + +Then go to your github page and create a "Pull request" when you are ready +to notify us to merge your work. + +**Translations** + +Our translations are managed through Transifex. If you wish to help out translating the $Projectname to another language, sign up on transifex.com, visit [https://www.transifex.com/projects/p/red-matrix/](https://www.transifex.com/projects/p/red-matrix/) and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. + +[Translations - More Info](help/Translations) + +**Important** + +Please pull in any changes from the project repository and merge them with your work **before** issuing a pull request. We reserve the right to reject any patch which results in a large number of merge conflicts. This is especially true in the case of language translations - where we may not be able to understand the subtle differences between conflicting versions. + +Also - **test your changes**. Don't assume that a simple fix won't break something else. If possible get an experienced Red developer to review the code. + + +**Licensing** + +All code contributed to the project falls under the MIT license, unless otherwise specified. We will accept third-party code which falls under MIT, BSD and LGPL, but copyleft licensing (GPL, and AGPL) is only permitted in addons. It must be possible to completely remove the GPL (copyleft) code from the main project without breaking anything. + +**Coding Style** + +In the interests of consistency we adopt the following code styling. We may accept patches using other styles, but where possible please try to provide a consistent code style. We aren't going to argue or debate the merits of this style, and it is irrelevant what project 'xyz' uses. This is not project 'xyz'. This is a baseline to try and keep the code readable now and in the future. + +* All comments should be in English. + +* We use doxygen to generate documentation. This hasn't been consistently applied, but learning it and using it are highly encouraged. + +* Indentation is accomplished primarily with tabs using a tab-width of 4. + +* String concatenation and operators should be separated by whitespace. e.g. "$foo = $bar . 'abc';" instead of "$foo=$bar.'abc';" + +* Generally speaking, we use single quotes for string variables and double quotes for SQL statements. "Here documents" should be avoided. Sometimes using double quoted strings with variable replacement is the most efficient means of creating the string. In most cases, you should be using single quotes. + +* Use whitespace liberally to enhance readability. When creating arrays with many elements, we will often set one key/value pair per line, indented from the parent line appropriately. Lining up the assignment operators takes a bit more work, but also increases readability. + +* Generally speaking, opening braces go on the same line as the thing which opens the brace. They are the last character on the line. Closing braces are on a line by themselves. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Features.md b/sources/doc/Features.md new file mode 100644 index 00000000..5a1e8c74 --- /dev/null +++ b/sources/doc/Features.md @@ -0,0 +1,108 @@ +Extra Features +============== + +The default interface of the $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the [Extra Features](settings/features) link of your [Settings](settings) page. + +**Content Expiration** + +Remove posts/comments and/or private messages at a future time. An extra button is added to the post editor which asks you for an expiration. Typically this in "yyyy-mm-dd hh:mm" format, but in the English language you have a bit more freedom and can use most any recognisable date reference such as "next Thursday" or "+1 day". At the specified time (give or take approximately ten minutes based on the remote system's checking frequency) the post is removed. + +**Multiple Profiles** + +The ability to create multiple profiles which are visible only to specific persons or groups. Your default profile may be visible to anybody, but secondary profiles can all contain different or additional information and can only be seen by those to whom that profile is assigned. + +**Web Pages** + +Provides the ability to use web page design feaures and create custom webpages from your own content and also to design the pages with page layouts, custom menus, and content blocks. + +**Private Notes** + +On pages where it is available (your matrix page and personal web pages) provide a "widget" to create and store personal reminders and notes. + +**Enhanced Photo Albums** + +Provides a photo album viewer that is a bit prettier than the normal interface. + +**Extended Identity Sharing** + +By default your identity travels with you as you browse the matrix to remote sites - and they know who you are and can show you content that only you can see. With Extended Identity Sharing you can provide this information to any website you visit from within the matrix. + +**Expert Mode** + +This allows you to see some advanced configuration options that would confuse some people or cause support issues. In particular this can give you full control over theme features and colours - so that you can tweak a large number of settings of the display theme to your liking. + +**Premium Channel** + +This allows you to set restrictions and terms on those that connect with your channel. This may be used by celebrities or anybody else who wishes to describe their channel to people who wish to connect with it. In certain cases you may be asked for payment in order to connect. + + +**Richtext Editor** + +The status post editor is plaintext, but the matrix allows a wide range of markup using BBcode. The visual editor provides "what you see is what you get" for many of the most frequently used markup tags. + +**Post Preview** + +Allows previewing posts and comments exactly as they would look on the page before publishing them. + +**Channel Sources** + +Automatically import and re-publish channel content from other channels or feeds. This allows you to create sub-channels and super-channels from content provided elsewhere. The rules are that the content must be public, and the channel owner must give you permission to source their channel. + +**Even More Encryption** + +Private messages are encrypted during transport and storage. In this day and age, this encyption may not be enough if your communications are extremely sensitive. This options lets you provide optional encryption of content "end-to-end" with a shared secret key. How the recipient learns the secret key is completely up to you. You can provide a hint such as "the name of aunt Claire's first dog". + + +**Search by Date** + +This provides the ability to select posts by date ranges + +**Collections Filter** + +Enable widget to display stream posts only from selected collections. This also toggles the outbound permissions while you are viewing a collection. This is analogous to Google "circles" or Disapora "aspects". + +**Saved Searches** + +Provides a search widget on your matrix page which can save selected search terms for re-use. + +**Personal Tab** + +Enable tab to display only matrix posts that you've interacted with in some way, as an author or a contributor to the conversation. + +**New Tab** + +Enables a tab to display all new matrix activity as a firehose or timeline. + +**Affinity Tool** + +Filter matrix stream activity by the depth of your relationships + +**Edit Sent Posts** + +Edit and correct posts and comments after sending + +**Tagging** + +Ability to tag existing posts, including those written by others. + +**Post Categories** + +Add categories to your channel posts + +**Saved Folders** + +Ability to file posts under folders or tags for later recall + +**Dislike Posts** + +Ability to dislike posts/comments + +**Star Posts** + +Ability to mark special posts with a star indicator + +**Tag Cloud** + +Provide a personal tag cloud on your channel page + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Hooks.md b/sources/doc/Hooks.md new file mode 100644 index 00000000..90edff62 --- /dev/null +++ b/sources/doc/Hooks.md @@ -0,0 +1,136 @@ +Hooks - Complete List +===================== + + +* 'about_hook' +* 'account_settings' +* 'app_menu' +* 'atom_author' +* 'atom_entry' +* 'atom_feed' +* 'atom_feed_end' +* 'authenticate' +* 'avatar_lookup' +* 'bb2diaspora' +* 'bbcode' +* 'channel_remove' +* 'check_account_email' +* 'check_account_invite' +* 'check_account_password' +* 'connect_premium' +* 'connector_settings' +* 'contact_block_end' +* 'contact_edit' +* 'contact_edit_post' +* 'contact_photo_menu' +* 'contact_select_options' +* 'conversation_start' +* 'cron' +* 'directory_item' +* 'display_item' +* 'display_item' +* 'display_settings' +* 'display_settings_post' +* 'enotify' +* 'enotify_mail' +* 'enotify_store' +* 'event_created' +* 'event_updated' +* 'feature_enabled' +* 'feature_settings' +* 'feature_settings_post' +* 'follow' +* 'gender_selector' +* 'get_all_perms' +* 'get_features' +* 'get_widgets' +* 'global_permissions' +* 'home_content' +* 'home_init' +* 'html2bbcode' +* 'import_directory_profile' +* 'init_1' +* 'item_photo_menu' +* 'item_translate' +* 'jot_networks' +* 'jot_tool' +* 'logged_in' +* 'login_hook' +* 'logging_out' +* 'magic_auth' +* 'magic_auth_success' +* 'main_slider' +* 'marital_selector' +* 'mood_verbs' +* 'network_content_init' +* 'network_ping' +* 'network_tabs' +* 'network_to_name' +* 'notifier_end' +* 'notifier_normal' +* 'obj_verbs' +* 'oembed_probe' +* 'page_content_top' +* 'page_end' +* 'page_header' +* 'parse_atom' +* 'parse_link' +* 'pdl_selector' +* 'perm_is_allowed' +* 'personal_xrd' +* 'photo_post_end' +* 'photo_post_end' +* 'photo_upload_begin' +* 'photo_upload_end' +* 'photo_upload_file' +* 'photo_upload_form' +* 'poke_verbs' +* 'post_local' +* 'post_local_end' +* 'post_local_start' +* 'post_mail' +* 'post_mail_end' +* 'post_remote' +* 'post_remote_end' +* 'post_remote_update' +* 'post_remote_update_end' +* 'prepare_body' +* 'prepare_body_final' +* 'prepare_body_init' +* 'proc_run' +* 'profile_advanced' +* 'profile_edit' +* 'profile_post' +* 'profile_sidebar' +* 'profile_sidebar_enter' +* 'profile_tabs' +* 'register_account' +* 'render_location' +* 'settings_account' +* 'settings_form' +* 'settings_post' +* 'sexpref_selector' +* 'smilie' +* 'validate_channelname' +* 'webfinger' +* 'zid' +* 'zid_init' + +***General Module Hooks*** + +* $a->module . '_mod_aftercontent' +* $a->module . '_mod_aside' +* $a->module . '_mod_content' +* $a->module . '_mod_init' +* $a->module . '_mod_post' + +***General Selector Hooks*** + +* $a->module . '_post_' . $selname +* $a->module . '_post_' . $selname +* $a->module . '_post_' . $selname +* $a->module . '_pre_' . $selname +* $a->module . '_pre_' . $selname +* $a->module . '_pre_' . $selname + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Plugins.md b/sources/doc/Plugins.md new file mode 100644 index 00000000..90ff0fb7 --- /dev/null +++ b/sources/doc/Plugins.md @@ -0,0 +1,263 @@ + +Creating Plugins/Addons for the $Projectname +========================================== + + +So you want to make the $Projectname do something it doesn't already do. There are lots of ways. But let's learn how to write a plugin or addon. + + +In your $Projectname folder/directory, you will probably see a sub-directory called 'addon'. If you don't have one already, go ahead and create it. + + + mkdir addon + +Then figure out a name for your addon. You probably have at least a vague idea of what you want it to do. For our example I'm going to create a plugin called 'randplace' that provides a somewhat random location for each of your posts. The name of your plugin is used to find the functions we need to access and is part of the function names, so to be safe, use only simple text characters. + +Once you've chosen a name, create a directory beneath 'addon' to hold your working file or files. + + mkdir addon/randplace + +Now create your plugin file. It needs to have the same name, and it's a PHP script, so using your favourite editor, create the file + + addon/randplace/randplace.php + +The very first line of this file needs to be + + + * + */ + +These tags will be seen by the site administrator when he/she installs or manages plugins from the admin panel. There can be more than one author. Just add another line starting with 'Author:'. + +The typical plugin will have at least the following functions: + +* pluginname_load() +* pluginname_unload() + +In our case, we'll call them randplace_load() and randplace_unload(), as that is the name of our plugin. These functions are called whenever we wish to either initialise the plugin or remove it from the current webpage. Also if your plugin requires things like altering the database schema before it can run for the very first time, you would likely place these instructions in the functions named + +* pluginname_install() +* pluginname_uninstall() + + +Next we'll talk about **hooks**. Hooks are places in the $Projectname code where we allow plugins to do stuff. There are a [lot of these](help/Hooks), and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. + +We register hook handlers with the 'register_hook()' function. It takes 3 arguments. The first is the hook we wish to catch, the second is the filename of the file to find our handler function (relative to the base of your $Projectname installation), and the third is the function name of your handler function. So let's create our randplace_load() function right now. + + + function randplace_load() { + register_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook'); + + register_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings'); + register_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post'); + + } + + +So we're going to catch three events, 'post_local' which is triggered when a post is made on the local system, 'feature_settings' to set some preferences for our plugin, and 'feature_settings_post' to store those settings. + +Next we'll create an unload function. This is easy, as it just unregisters our hooks. It takes exactly the same arguments. + + function randplace_unload() { + unregister_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook'); + + unregister_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings'); + unregister_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post'); + + } + + +Hooks are called with two arguments. The first is always $a, which is our global App structure and contains a huge amount of information about the state of the web request we are processing; as well as who the viewer is, and what our login state is, and the current contents of the web page we're probably constructing. + +The second argument is specific to the hook you're calling. It contains information relevant to that particular place in the program, and often allows you to look at, and even change it. In order to change it, you need to add '&' to the variable name so it is passed to your function by reference. Otherwise it will create a copy and any changes you make will be lost when the hook process returns. Usually (but not always) the second argument is a named array of data structures. Please see the "hook reference" (not yet written as of this date) for details on any specific hook. Occasionally you may need to view the program source to see precisely how a given hook is called and how the results are processed. + +Let's go ahead and add some code to implement our post_local hook handler. + + function randplace_post_hook($a, &$item) { + + /** + * + * An item was posted on the local system. + * We are going to look for specific items: + * - A status post by a profile owner + * - The profile owner must have allowed our plugin + * + */ + + logger('randplace invoked'); + + if(! local_channel()) /* non-zero if this is a logged in user of this system */ + return; + + if(local_channel() != $item['uid']) /* Does this person own the post? */ + return; + + if(($item['parent']) || (! is_item_normal($item))) { + /* If the item has a parent, or isn't "normal", this is a comment or something else, not a status post. */ + return; + } + + /* Retrieve our personal config setting */ + + $active = get_pconfig(local_channel(), 'randplace', 'enable'); + + if(! $active) + return; + /** + * + * OK, we're allowed to do our stuff. + * Here's what we are going to do: + * load the list of timezone names, and use that to generate a list of world cities. + * Then we'll pick one of those at random and put it in the "location" field for the post. + * + */ + + $cities = array(); + $zones = timezone_identifiers_list(); + foreach($zones as $zone) { + if((strpos($zone,'/')) && (! stristr($zone,'US/')) && (! stristr($zone,'Etc/'))) + $cities[] = str_replace('_', ' ',substr($zone,strpos($zone,'/') + 1)); + } + + if(! count($cities)) + return; + $city = array_rand($cities,1); + $item['location'] = $cities[$city]; + + return; + } + + +Now let's add our functions to create and store preference settings. + + /** + * + * Callback from the settings post function. + * $post contains the global $_POST array. + * We will make sure we've got a valid user account + * and that only our own submit button was clicked + * and if so set our configuration setting for this person. + * + */ + + function randplace_settings_post($a,$post) { + if(! local_channel()) + return; + if($_POST['randplace-submit']) + set_pconfig(local_channel(),'randplace','enable',intval($_POST['randplace'])); + } + + + + /** + * + * Called from the Feature Setting form. + * The second argument is a string in this case, the HTML content region of the page. + * Add our own settings info to the string. + * + * For uniformity of settings pages, we use the following convention + *
+ *

title

+ * .... settings html - many elements will be floated... + *
+ * + *
+ */ + + + + function randplace_settings(&$a,&$s) { + + if(! local_channel()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + head_add_css('/addon/randplace/randplace.css'); + + /* Get the current state of our config variable */ + + $enabled = get_pconfig(local_channel(),'randplace','enable'); + + $checked = (($enabled) ? ' checked="checked" ' : ''); + + /* Add some HTML to the existing form */ + + $s .= '
'; + $s .= '

' . t('Randplace Settings') . '

'; + $s .= '
'; + $s .= ''; + $s .= ''; + $s .= '
'; + + /* provide a submit button */ + + $s .= '
'; + + } + + + + + +***Advanced Plugins*** + +Sometimes your plugins want to provide a range of new functionality which isn't provided at all or is clumsy to provide using hooks. In this case your plugin can also act as a 'module'. A module in our case refers to a structured webpage handler which responds to a given URL. Then anything which accesses that URL will be handled completely by your plugin. + +The key to this is to create a simple function named pluginname_module() which does nothing. + + function randplace_module() { return; } + +Once this function exists, the URL https://yoursite/randplace will access your plugin as a module. Then you can define functions which are called at various points to build a webpage just like the modules in the mod/ directory. The typical functions and the order which they are called is + + modulename_init($a) // (e.g. randplace_init($a);) called first - if you wish to emit json or xml, + // you should do it here, followed by killme() which will avoid the default action of building a webpage + modulename_aside($a) // Often used to create sidebar content + modulename_post($a) // Called whenever the page is accessed via the "post" method + modulename_content($a) // called to generate the central page content. This function should return a string + // consisting of the central page content. + +Your module functions have access to the URL path as if they were standalone programs in the Unix operating system. For instance if you visit the page + + https://yoursite/randplace/something/somewhere/whatever + +we will create an argc/argv list for use by your module functions + + $x = argc(); $x will be 4, the number of path arguments after the sitename + + for($x = 0; $x < argc(); $x ++) + echo $x . ' ' . argv($x); + + + 0 randplace + 1 something + 2 somewhere + 3 whatever + + +***Porting Friendica Plugins*** + +The $Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: + +* Friendica's pluginname_install() is pluginname_load() + +* Friendica's pluginname_uninstall() is pluginname_unload() + +The $Projectname has _install and _uninstall functions but these are used differently. + +* Friendica's "plugin_settings" hook is called "feature_settings" + +* Friendica's "plugin_settings_post" hook is called "feature_settings_post" + +Changing these will often allow your plugin to function, but please double check all your permission and identity code because the concepts behind it are completely different in the $Projectname. Many structured data names (especially DB schema columns) are also quite different. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Primary-Directory.md b/sources/doc/Primary-Directory.md new file mode 100644 index 00000000..37b0c043 --- /dev/null +++ b/sources/doc/Primary-Directory.md @@ -0,0 +1,47 @@ +#Primary Directory# + +By default, $Projectname will use available Directories on the web, which show you channels available around the world. + +There are certain scenarios where you might want your own directory-server that you can connect multiple hubs to. This will limit the channels that appear in all of your hubs to only channels on hubs connected to your directory-server. + + + +##Instuctions on how to set up one hub as the Primary Directory for a series of private hubs.## +*** + + +* On the hub that will be the Directory Server, open the .htconfig.php file and set: + + `$a->config['system']['directory_mode'] = DIRECTORY_MODE_PRIMARY;` + + + By default it should already be set as **DIRECTORY_MODE_NORMAL**, so just edit that line to say **DIRECTORY_MODE_PRIMARY** + +* Next, for each hub (including the Directory Server), from a terminal, cd into the folder where it is installed and run this : + + `util/config system directory_realm YOURREALMNAME` + + (**YOURREALMNAME** can be whatever you want your realm-name to be) + + then: + + `util/config system realm_token THEPASSWORD` + + (**THEPASSWORD** is whatever password you want for your realm) + + **NOTE:** Use the same realm-name and password for each hub + +* Lastly, for each "client" hub, (from a terminal) run: + + `util/config system directory_server https://theaddressofyourdirectoryserver.com` + +*** +Now when you view the directory of each hub, it should only show the channels that exist on the hubs in your realm. I have tested with two hubs so far, and it seems to be working fine. +Channels created in each hub are reflected in the Primary Directory, and subsequently in the directory of all client hubs + +##Issues## +*** + +When I created the first hub,it was up and running for an hour or so before I changed it to PRIMARY_MODE, and after changing it, there were a few channels from across the matrix still present in the directory. I deleted them from the xchan table and that seems to have fixed the issue. + + diff --git a/sources/doc/Privacy.md b/sources/doc/Privacy.md new file mode 100644 index 00000000..fd6df631 --- /dev/null +++ b/sources/doc/Privacy.md @@ -0,0 +1,73 @@ +#Privacy Policy + +##Summary + +Q: Who can see my content? + +A: By default ANYBODY on the internet, UNLESS you restrict it. The $Projectname allows you to choose the privacy level you desire. Restricted content will NOT be visible to spy networks and their advertisers. It will be protected against eavesdropping by outsiders - to the best of our ability. Hub administrators with sufficient skills and patience MAY be able to eavesdrop on some private communications but they must expend effort to do so. Privacy modes exist within the $Projectname which are even resistant to eavesdropping by skilled and determined hub administrators. + +Q: Can my content be censored? + +A: The $Projectname (the network) CANNOT censor your content. Server and hub administrators are subject to local laws and MAY remove objectionable content from their site/hub. Anybody MAY become a hub administrator, including you; and therefore publish content which might otherwise be censored. You still MAY be subject to local laws. + + +##Definitions + +**$Projectname** + +Otherwise referred to as "the network", the $Projectname is a collection of individual computers/servers (aka **hubs**) which connect together to form a larger cooperative network. + +**hub** + +An individual computer or server connected to the $Projectname. These are provided by a **hub administrator** and may be public or private, paid or free. + +**hub administrator** + +The system operator of an individual hub. + +##Policies + +**Public Information** + +Any information or anything posted by you within the $Projectname MAY be public or visible to anybody on the internet. To the extent possible, the $Projectname allows you to protect content and restrict who can view it. + +Your profile photo, your channel name, and the location (URL or network address) of your channel are visible to anybody on the internet and privacy controls will not affect the display of these items. + +You MAY additionally provide other profile information. Any information which you provide in your "default" or **public profile** MAY be transmitted to other hubs in the $Projectname and additionally MAY be displayed in the channel directory. You can restrict the viewing of this profile information. It may be restricted only to members of your hub, or only connections (friends), or other limited sets of viewers as you desire. If you wish for your profile to be restricted, you must set the appropriate privacy setting, or simply DO NOT provide additional information. + +**Content** + +Content you provide (status posts, photos, files, etc.) belongs to you. The $Projectname default is to publish content openly and visible to anybody on the internet (PUBLIC). You MAY control this in your channel settings and restrict the default permissions or you MAY restrict the visibility of any single published item separately (PRIVATE). The $Projectname developers will ensure that restricted content is ONLY visible to those in the restriction list - to the best of their ability. + +Content (especially status posts) that you share with other networks or that you have made visible to anybody on the internet (PUBLIC) cannot easily be taken back once it has been published. It MAY be shared with other networks and made available through RSS/Atom feeds. It may also be syndicated on other $Projectname sites. It MAY appear on spy networks and internet searches. If you do not wish this default behaviour please adjust your channel settings and restrict who can see your content. + +**Comments and Forum posts** + +Comments to posts that were created by others and posts which are designated as forum posts belong to you as the creator/author, but the distribution of these posts is not under your direct control. These posts/comments MAY be re-distributed to others, and MAY be visible to anybody on the internet. In the case of comments, the creator of the "first message" in the thread to which you are replying controls the distribution of all comments and replies to that message. + + +**Private Information** + +$Projectname developers will ensure that any content you provide which is designated as PRIVATE will be protected against eavesdropping - to the best of their ability. Private content is generally hidden or obscured even from hub administrators. It is also stripped from email notifications. It is difficult but NOT impossible for this content to be seen by a hub administrator. This is a side effect of the physical laws of the universe. Unfortunately, if a database needs to decrypt a post at display time, it must have the means to decrypt the post! End to end encryption is also provided and this CANNOT be seen, even by a determined administrator. + +##Identity Privacy + +Privacy for your identity is another aspect. Because you have a decentralized identity in the $Projectname, your privacy extends beyond your home hub. If you want to have complete control of your privacy and security you should run your own hub on a dedicated server. For many people, this is complicated and may stretch their technical abilities. So let's list a few precautions you can make to assure your privacy as much as possible. + +A decentralized identity has a lot of advantages and gives you al lot of interesting features, but you should be aware of the fact that your identity is known by other hubs in the $Projectname network. One of those advantages is that other channels can serve you customized content and allow you to see private things (such as private photos which others wish to share with you). Because of this those channels need to know who you are. But we understand that sometimes those other channels know more from you than you might desire. For instance the plug-in Visage that can tell a channel owner the last time you visit their profile. You can easily OPT-OUT of this low level and we think, harmless tracking. + +* You can enable [Do Not Track (DNT)](http://donottrack.us/) in your web browser. We respect this new privacy policy proposal. All modern browsers support DNT. You will find it in the privacy settings of your browsers or else you can consult the web browser's manual. This will not affect the functionality of the $Projectname. This setting is probably enough for most people. +*You can [disable publication](settings) of your channel in our channel directory. If you want people to find your channel, you should give your channel address directly to them. We think this is a good indication that you prefer extra privacy and automatically enable "Do Not Track" if this is the case. +* You can have a blocked hub. That means that all channels and content on that hub is not public, and not visible to the outside world. This is something only your hub administrator can do. We also respect this and automatically enable "Do Not Track" if it is set. + +###Censorship + +The $Projectname is a global network which is inclusive of all religions and cultures. This does not imply that every member of the network feels the same way you do on contentious issues, and some people may be STRONGLY opposed to the content you post. In general, if you wish to post something that you know may nor be universally acceptable, the best approach is to restrict the audience using privacy controls to a small circle of friends. + +The $Projectname as a network provider is unable to censor content. However, hub administrators MAY censor any content which appears on their hub to comply with local laws or even personal judgement. Their decision is final. If you have issues with any hub administrator, you may move your account and postings to another site which is more in line with your expectations. Please check (periodically) the [Terms of Service](help/TermsOfService) of your hub to learn about any rules or guidelines. If your content consists of material which is illegal or may cause issues, you are STRONGLY encouraged to host your own (become a hub administrator). You may still find that your content is blocked on some hubs, but the $Projectname as a network cannot block it from being posted. + +The $Projectname RECOMMENDS that hub administrators provide a grace period of 1-2 days between warning an account holder of content that needs to be removed and physically removing or disabling the account. This will give the content owner an opportunity to export their channel meta-data and import it to another site. In rare cases the content may be of such a nature to justify the immediate termination of the account. This is a hub decision, not a $Projectname decision. + +If you typically and regularly post content of an adult or offensive nature, you are STRONGLY encouraged to mark your account "NSFW" (Not Safe For Work). This will prevent the display of your profile photo in the directory except to viewers that have chosen to disable "safe mode". If your profile photo is found by directory administrators to be adult or offensive, the directory administrator MAY flag your profile photo as NSFW. There is currently no official mechanism to contest or reverse this decision, which is why you SHOULD mark your own account NSFW if it is likely to be inappropriate for general audiences. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/README.md b/sources/doc/README.md new file mode 100644 index 00000000..90585a90 --- /dev/null +++ b/sources/doc/README.md @@ -0,0 +1,42 @@ + +Hubzilla +======== + +###Websites. Redefined. + + +![Hubzilla](images/ghash-32.png) + +**What are Hubs?** + +Hubs are independent general-purpose websites that not only connect with their associated members and viewers, but also connect together to exchange personal communications and other information with each other. +This allows hub members on any hub to securely and privately share anything; with anybody, on any hub - anywhere; or share stuff publicly with anybody on the internet if desired. + +**Hubzilla** is the server software which makes this possible. It is a sophisticated and unique combination of an open source content management system and a decentralised identity, communications, and permissions framework and protocol suite, built using common webserver technology (PHP/MySQL/Apache, although Mariadb or Postgres and Nginx could also be used - we're pretty easy). The end result is a level of systems integration, privacy control, and communications features that you wouldn't think are possible in either a content management system or a decentralised communications network. It also brings a new level of cooperation and privacy to the web and introduces the concept of personally owned "single sign-on" to web services across the entire internet. + +Hubzilla hubs are + +* decentralised +* inherently social +* optionally inter-networked with other hubs +* privacy-enabled (privacy exclusions work across the entire internet to any registered identity on any compatible hubs) + +Possible website applications include + +* decentralised social networking nodes +* personal cloud storage +* file dropboxes +* managing organisational communications and activities +* collaboration and community decision-making +* small business websites +* public and private media/file libraries +* blogs +* event promotion +* feed aggregation and republishing +* forums +* dating websites +* pretty much anything you can do on a traditional blog or community website, but that you could do better if you could easily connect it with other websites or privately share things across website boundaries. + + + +This project is under development and is not yet available for general use. \ No newline at end of file diff --git a/sources/doc/Remove-Account.md b/sources/doc/Remove-Account.md new file mode 100644 index 00000000..a8ef733a --- /dev/null +++ b/sources/doc/Remove-Account.md @@ -0,0 +1,26 @@ +// this page is out of date... +Remove Account +============== + +It is presently not possible to remove an account without asking your site administrator for assistance. +We'll have better doco when somebody finishes that bit. + + +Remove Channel +============== + +Visit the URL + + https://yoursite/removeme + +(replace 'yoursite' with the domain name of your $Projectname site). + +You will need to confirm your password and the channel you are currently logged into will be removed. + +This is irreversible. + +If you have identity clones on other sites this only removes the channel instance which exists +on this site. + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Schema-development.md b/sources/doc/Schema-development.md new file mode 100644 index 00000000..e811bb8c --- /dev/null +++ b/sources/doc/Schema-development.md @@ -0,0 +1,81 @@ +Red development - a guide to the schema system +============================================== + + +A schema, in a nutshell, is a collection of settings for a bunch of variables to define +certain elements of a theme. A schema is loaded as though it were part of config.php +and has access to all the same information. Importantly, this means it is identity aware, +and can be used to do some interesting things. One could, for example, restrict options +by service class, or present different options to different members. + +By default, we filter only by whether or not expert mode is enabled. If expert mode is +enabled, all options are presented to the member. If it is not, only scheme, background +image, font face, and iconset are available as choices. + +A schema is loaded *after* the member's personal settings. Therefore, to allow a member +to overwrite a particular aspect of a schema you would use the following syntax: + + if (! $foo) + $foo = 'bar'; + +However, there are circumstances - particularly with positional elements - where it +may be desirable (or necessary) to override a member's settings. In this case, the syntax +is even simpler: + + $foo = 'bar'; + +Members will not thank you for this, however, so only use it when it is required. + +If no personal options are set, and no schema is selected, we will first try to load a schema +with the file name "default.php". This file should never be included with a theme. If it +is, merge conflicts will occur as people update their code. Rather, this should be defined +by administrators on a site by site basis. +default.php and default.css MUST be symlinks to existing scheme files. + +You schema does not need to - and should not - contain all of these values. Only the values +that differ from the defaults should be listed. This gives you some very powerful options +with very few lines of code. + +Note the options available differ with each theme. The options available with the Redbasic +theme are as follows: + +* nav_colour + The colour of the navigation bar. Options are red, black and silver. Alternatively, + one can set $nav_bg_1, $nav_bg_2, $nav_bg_3 and $nav_bg_4 to provide gradient and + hover effects. +* banner_colour + The font colour of the banner element. Accepts an RGB or Hex value. +* bgcolour + Set the body background colour. Accepts an RGB or Hex value. +* background_image + Sets a background image. Accepts a URL or path. +* item_colour + Set the background colour of items. Accepts an RGB or Hex value. +* item_opacity + Set the opacity of items. Accepts a value from 0.01 to 1 +* toolicon_colour + Set the colour of tool icons. Accepts an RGB or Hex value. +* toolicon_activecolour + Set the colour of active or hovered icon tools. +* font_size + Set the size of fonts in items and posts. Accepts px or em. +* body_font_size + Sets the size of fonts at the body level. Accepts px or em. +* font_colour + Sets the font colour. Accepts an RGB or Hex value. +* radius + Set the radius of corners. Accepts a numeral, and is always in px. +* shadow + Set the size of shadows shown with inline images. Accepts a numerical + value. Note shadows are not applied to smileys. +* converse_width + Set the maximum width of the content region in px. +* nav_min_opacity +* top_photo +* reply_photo + +If a your_schema_name.css file is found, the content of this file will be attached to the end of style.css. +This gives the schem developer the possiblity to override any style component. + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Tags-and-Mentions.md b/sources/doc/Tags-and-Mentions.md new file mode 100644 index 00000000..84442dd7 --- /dev/null +++ b/sources/doc/Tags-and-Mentions.md @@ -0,0 +1,26 @@ +Tags and Mentions +================= + +Like many other platforms, Red uses a special notation inside messages to indicate "tags" or contextual links to other entities. + +**Mentions** + +Channels are tagged by simply preceding their name with the @ character. Unless their system blocks unsolicited "mentions", the person tagged will likely receive a "Mention" post/activity or become a direct participant in the conversation in the case of public posts. + +When you start to mention somebody, it will create an auto-complete box to select from your immediate connections. Select one as appropriate. Some connections will be displayed in different colours. A light blue entry (using the default theme) indicates a channel which will redeliver to others if tagged. This is generally a conversation group or forum. But be aware that when tagged, the message will also go to anybody they choose, in addition to anybody you choose. + +**Private Mentions** + +If you wish to restrict a post to a single person or a number of people, you can do this by selecting channels or collections from the privacy tool. You can also just tag them with a privacy tag. A privacy tag is a name preceded by the two characters @! - and in addition to tagging these channels, will also change the privacy permissions of the post to include them (and perhaps restrict the post from "everybody" if this was the default). You can have more than one privacy tag, for instance @!bob and @!linda will send the post only to Bob and Linda (in addition to any recipients you selected with the privacy selector - if any). + +You may also tag public collections. When you create or edit a collection, there is a checkbox to allow the group members to be seen by others. If this box is checked for a collection and you tag (for instance) @!Friends - the post will be restricted to the Friends collection. Check that the collection is public before doing this - as there is no way to take back a post except to delete it. The collection name will appear in the post and will alert members of that collection that they are members of it. + + + +**Topical Tags** + +Topical tags are indicated by preceding the tag name with the # character. This will create a link in the post to a generalised site search for the term provided. For example, #cars will provide a search link for all posts mentioning 'cars' on your site. Topical tags are generally a minimum of three characters in length. Shorter search terms are not likely to yield any search results, although this depends on the database configuration. The same rules apply as with names that spaces within tags are represented by the underscore character. It is therefore not possible to create a tag whose target contains an underscore. + +Topical tags are also not linked if they are purely numeric, e.g. #1. If you wish to use a numerica hashtag, please add some descriptive text such as #2012-elections. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/TermsOfService.md b/sources/doc/TermsOfService.md new file mode 100644 index 00000000..97e9881a --- /dev/null +++ b/sources/doc/TermsOfService.md @@ -0,0 +1,5 @@ +Terms of Service +================ + +#include doc/SiteTOS.md; + diff --git a/sources/doc/Translations.md b/sources/doc/Translations.md new file mode 100644 index 00000000..d0fe489f --- /dev/null +++ b/sources/doc/Translations.md @@ -0,0 +1,93 @@ +Translating the $Projectname +========================== + +Translation Process +------------------- + +The strings used in the UI of Red is translated at [Transifex][1] and then +included in the git repository at github. If you want to help with translation +for any language, be it correcting terms or translating Red to a +currently not supported language, please register an account at transifex.com +and contact the Red translation team there. + +Translating Red is simple. Just use the online tool at transifex. If you +don't want to deal with git & co. that is fine, we check the status of the +translations regularly and import them into the source tree at github so that +others can use them. + +We do not include every translation from transifex in the source tree to avoid +a scattered and disturbed overall experience. As an uneducated guess we have a +lower limit of 50% translated strings before we include the language. This +limit is judging only by the amount of translated strings under the assumption +that the most prominent strings for the UI will be translated first by a +translation team. If you feel your translation useable before this limit, +please contact us and we will probably include your teams work in the source +tree. + +If you want to get your work into the source tree yourself, feel free to do so +and contact us with and question that arises. The process is simple and +Red ships with all the tools necessary. + +The location of the translated files in the source tree is + /view/LNG-CODE/ +where LNG-CODE is the language code used, e.g. de for German or fr for French. +For the email templates (the *.tpl files) just place them into the directory +and you are done. The translated strings come as a "messages.po" file from +transifex which needs to be translated into the PHP file Red uses. To do +so, place the file in the directory mentioned above and use the "po2php" +utility from the util directory of your Red installation. + +Assuming you want to convert the German localization which is placed in +view/de/messages.po you would do the following. + +1. Navigate at the command prompt to the base directory of your + Red installation + +2. Execute the po2php script, which will place the translation + in the strings.php file that is used by Red. + + $> php util/po2php.php view/de/messages.po + + The output of the script will be placed at view/de/strings.php where + froemdoca os expecting it, so you can test your translation mmediately. + +3. Visit your Red page to check if it still works in the language you + just translated. If not try to find the error, most likely PHP will give + you a hint in the log/warnings.about the error. + + For debugging you can also try to "run" the file with PHP. This should + not give any output if the file is ok but might give a hint for + searching the bug in the file. + + $> php view/de/strings.php + +4. commit the two files with a meaningful commit message to your git + repository, push it to your fork of the Red repository at github and + issue a pull request for that commit. + +Utilities +--------- + +Additional to the po2php script there are some more utilities for translation +in the "util" directory of the Red source tree. If you only want to +translate Red into another language you wont need any of these tools most +likely but it gives you an idea how the translation process of Red +works. + +For further information see the utils/README file. + +Known Problems +-------------- + +* Red uses the language setting of the visitors browser to determain the + language for the UI. Most of the time this works, but there are some known + quirks. +* the early translations are based on the friendica translations, if you + some rough translations please let us know or fix them at Transifex. + +Links +------ +[1]: http://www.transifex.com/projects/p/red-matrix/ + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Webpages.md b/sources/doc/Webpages.md new file mode 100644 index 00000000..dafd3661 --- /dev/null +++ b/sources/doc/Webpages.md @@ -0,0 +1,16 @@ +Creating Webpages +================= + +Red enables users to create static webpages. To activate this feature, enable the web pages feature in your Additional Features section. + +Once enabled, a new tab will appear on your channel page labelled "Webpages". Clicking this link will take you to the webpage editor. Here you can create a post using either BBCode or the rich text editor. + +Pages will be accessible at mydomain/page/username/pagelinktitle + +The "page link title" box allows a user to specify the "pagelinktitle" of this URL. If no page link title is set, we will set one for you automatically, using the message ID of the item. + +Beneath the page creation box, a list of existing pages will appear with an "edit" link. Clicking this will take you to an editor, similar to that of the post editor, where you can make changes to your webpages. + +If you are the admin of a site, you can specify a channel whose webpages we will use at key points around the site. Presently, the only place this is implemented is the home page. If you specify the channel "admin" and then the channel called "admin" creates a webpage called "home", we will display it's content on your websites home page. We expect this functionality to be extended to other areas in future. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/Widgets.md b/sources/doc/Widgets.md new file mode 100644 index 00000000..5cc7eab2 --- /dev/null +++ b/sources/doc/Widgets.md @@ -0,0 +1,123 @@ +Core Widgets +============ + +Some/many of these widgets have restrictions which may restrict the type of page where they may appear or may require login + + +* clock - displays the current time + * args: military (1 or 0) - use 24 hour time as opposed to AM/PM +
 
+ +* profile - displays a profile sidebar on pages which load profiles (pages with nickname in the URL) + +* tagcloud - display a tagcloud of webpage items + + * args: count - number of items to return (default 24) +
 
+ +* collections - collection selector for the current logged in channel + + * args: mode - one of "conversation", "group", "abook" depending on module +
 
+ +* suggestions - friend suggestions for the current logged on channel + +* follow - presents a text box for following another channel + +* notes - private notes area for the current logged in channel if private_notes feature is enabled + +* savedsearch - network/matrix search with save - must be logged in and savedsearch feature enabled + +* filer - select filed items from network/matrix stream - must be logged in + +* archive - date range selector for network and channel pages + * args: 'wall' - 1 or 0, limit to wall posts or network/matrix posts (default) +
 
+ +* fullprofile - same as profile currently + +* categories - categories filter (channel page) + +* tagcloud_wall - tagcloud for channel page only + * args: 'limit' - number of tags to return (default 50) +
 
+ +* catcloud_wall - tagcloud for channel page categories + * args: 'limit' - number of categories to return (default 50) +
 
+ +* affinity - affinity slider for network page - must be logged in + +* settings_menu - sidebar menu for settings page, must be logged in + +* mailmenu - sidebar menu for private message page - must be logged in + +* design_tools - design tools menu for webpage building pages, must be logged in + +* findpeople - tools to find other channels + +* photo_albums - list photo albums of the current page owner with a selector menu + +* vcard - mini profile sidebar for the person of interest (page owner, whatever) + +* dirsafemode - directory selection tool - only on directory pages + +* dirsort - directory selection tool - only on directory pages + +* dirtags - directory tool - only on directory pages + +* menu_preview - preview a menu - only on menu edit pages + +* chatroom_list - list of chatrooms for the page owner + +* bookmarkedchats - list of bookmarked chatrooms collected on this site for the current observer + +* suggestedchats - "interesting" chatrooms chosen for the current observer + +* item - displays a single webpage item by mid + * args: mid - message_id of webpage to display +
 
+ +* photo - display a single photo + * args: + * url - URL of photo, must be http or https + * zrl - use zid authenticated link + * style - CSS style string +
 
+ +* photo_rand - display a random photo from one of your photo albums. Photo permissions are honoured + * args: + * album - album name (very strongly recommended if you have lots of photos) + * scale - typically 0 (original size), 1 (640px), or 2 (320px) + * style - CSS style string + * channel_id - if not your own +
 
+ +* random_block - display a random block element from your webpage design tools collection. Permissions are honoured. + * args: + * contains - only return blocks which include the contains string in the block name + * channel_id - if not your own +
 
+ +* tasklist - provide a task or to-do list for the currently logged-in channel. + * args: + * all - display completed tasks if all is non-zero. +
 
+ + +Creating New Widgets +==================== + +If you want a widget named 'slugfish', create widget/slugfish.php containing + + + Connections. In the right column under "Developers," click the link to "Register an OAuth client application to use with this instance of StatusNet." This link may be found at your instance here: + +https://yourgnusocialinstance.org/settings/oauthapps + +Next, click the link to Register a new application. That brings up the new application form. Here's what to do on each field. + +Icon. I uploaded the $Projectname icon located at this link, after saving it to my computer: + +https://github.com/redmatrix/hubzilla/blob/master/images/rm-32.png + +Name. Give the application an appropriate name. I called mine hubzilla. You might prefer r2g. + +Description. Use this field to describe the purpose of the application. I put something to the effect of use for crossposting from $Projectname to GNUsocial. + + +Source URL. Put the main domain name of the Red site you're using. Don't forget to put the "s" in https://yourhubzillasite.com. If your Red installation is a subdomain, that would probably be called for. + +Organization. Since $Projectname is unorganized, I put that. If you use your installation for a group or business, that might be a good option. + +Homepage. If your group is using a subdomain, you probably want to put your main domain URI here. Since I'm on a hosted site, I put redmatrix.me. + +Callback URL. Leave blank. + +Type of application: select "desktop." + +Default access: select "Read-write." + +All fields except the callback URL must be filled in. + +Click on the save button. + +Then click on the icon or the name of the application for the information you'll need to insert over on $Projectname. + +***** + +Now open up a new tab or window and go to your $Projectname account, to Settings > Feature settings. Find the StatusNet Posting Settings. + +Insert the strings of numbers given on the GNUsocial site into the $Projectname fields for Consumer Key and Consumer Secret. + +The Base API Path (remember the trailing /) will be your instance domain, plus the /api/ following. It will probably look like this: + +https://yourgnusocialinstance.org/api/ + +In case of doubt check on your GNUsocial instance site in order to find the domain URLs of the Request token, Access token, and Authorization. It will be the first part of the domains, minus the /oauth/.... + +StatusNet application name: Insert the name you gave to the application over on the GNUsocial site. + +Click Submit. + +A button will appear for you to "Sign in to StatusNet." Click it and that will open a tab or window on the GNUsocial site for you to click "Allow." Once clicked and successfully authorized, a security code number will appear. Copy it and go back to the $Projectname app you just left and insert it in the field: "Copy the security code from StatusNet here." Click Submit. + +If successful, your information from the GNUsocial instance should appear in the $Projectname app. + +You now have several options to choose, if you desire, and those will need to be confirmed by clicking "Submit" also. The most interesting is "Send public postings to StatusNet by default." This option automatically sends any post of yours made in your $Projectname account to your GNUsocial instance. + +If you don't choose this option, you will have an option to send a post to your GNUsocial instance by first opening the post (by clicking in the post text area) and clicking on the lock icon next to the Share button. Select the GNUsocial icon made up of three colored dialog baloons. Close that window, then make your post. + +If all goes well, you have just cross-posted your $Projectname post to your account on a GNUsocial instance. + +#include doc/macros/addons_footer.bb; + diff --git a/sources/doc/api_functions.bb b/sources/doc/api_functions.bb new file mode 100644 index 00000000..e6cde3dc --- /dev/null +++ b/sources/doc/api_functions.bb @@ -0,0 +1,133 @@ +[b]Red Twitter API[/b] + +The "basic" Red web API is based on the Twitter API, as this provides instant compatibility with a huge number of third-party clients and applications without requiring any code changes on their part. It is also a super-set of the StatusNet version of the Twitter API, as this also has existing wide support. + +Red has a lot more capability that isn't exposed in the Twitter interfaces or where we are forced to "dumb-down" the API functions to work with the primitive Twitter/StatusNet communications and privacy model. So we plan to extend the Twitter API in ways that will allow Red-specific clients to make full use of Red features without being crippled. + +A dedicated Red API is also being developed to work with native data structures and permissions and which do not require translating to different privacy and permission models and storage formats. This will be described in other documents. The prefix for all of the native endpoints is 'api/red'. + +Red provides multiple channels accesible via the same login account. With Red, any API function which requires authentication will accept a parameter &channel={channel_nickname} - and will select that channel and make it current before executing the API command. By default, the default channel associated with an account is selected. + +Red also provides an extended permission model. In the absence of any Red specific API calls to set permissions, they will be set to the default permissions settings which are associated with the current channel. + +Red will probably never be able to support the Twitter 'api/friendships' functions fully because Red is not a social network and has no concept of "friendships" - it only recognises permissions to do stuff (or not do stuff as the case may be). + +Legend: T= Twitter, S= StatusNet, F= Friendica, R= Red, ()=Not yet working, J= JSON only (XML formats deprecated) + +Twitter API compatible functions: + + api/account/verify_credentials T,S,F,R + api/statuses/update T,S,F,R + api/users/show T,S,F,R + api/statuses/home_timeline T,S,F,R + api/statuses/friends_timeline T,S,F,R + api/statuses/public_timeline T,S,F,R + api/statuses/show T,S,F,R + api/statuses/retweet T,S,F,R + api/statuses/destroy T,S,F,(R) + api/statuses/mentions T,S,F,(R) + api/statuses/replies T,S,F,(R) + api/statuses/user_timeline T,S,F,(R) + api/favorites T,S,F,R + api/account/rate_limit_status T,S,F,R + api/help/test T,S,F,R + api/statuses/friends T,S,F,R + api/statuses/followers T,S,F,R + api/friends/ids T,S,F,R + api/followers/ids T,S,F,R + api/direct_messages/new T,S,F,R + api/direct_messages/conversation T,S,F,R + api/direct_messages/all T,S,F,R + api/direct_messages/sent T,S,F,R + api/direct_messages T,S,F,R + api/oauth/request_token T,S,F,R + api/oauth/access_token T,S,F,R + api/favorites T,S,R + api/favorites/create T,S,R + api/favorites/destroy T,S,R + +Twitter API functions supported by StatusNet but not currently by Friendica or Red + + api/statuses/retweets_of_me T,S + api/friendships/create T,S + api/friendships/destroy T,S + api/friendships/exists T,S + api/friendships/show T,S + api/account/update_location T,S + api/account/update_profile_background_image T,S + api/account/update_profile_image T,S + api/blocks/create T,S + api/blocks/destroy T,S + +Twitter API functions not currently supported by StatusNet + + api/statuses/retweeted_to_me T + api/statuses/retweeted_by_me T + api/direct_messages/destroy T + api/account/end_session T,(R) + api/account/update_delivery_device T + api/notifications/follow T + api/notifications/leave T + api/blocks/exists T + api/blocks/blocking T + api/lists T + +Statusnet compatible extensions to the Twitter API supported in both Friendica and Red + + api/statusnet/version S,F,R + api/statusnet/config S,F,R + +Friendica API extensions to the Twitter API supported in both Friendica and Red + + api/statuses/mediap F,R + +Red specific API extensions to the Twitter API not supported in Friendica + + api/account/logout R + api/export/basic R,J + api/friendica/config R + api/red/config R + api/friendica/version R + + api/red/version R + + api/red/channel/export/basic R,J + api/red/channel/stream R,J (currently post only) + api/red/albums R,J + api/red/photos R,J (option album=xxxx) + +Red proposed API extensions to the Twitter API + + api/statuses/edit (R),J + api/statuses/permissions (R),J + api/statuses/permissions/update (R),J + api/statuses/ids (R),J # search for existing message_id before importing a foreign post + api/files/show (R),J + api/files/destroy (R),J + api/files/update (R),J + api/files/permissions (R),J + api/files/permissions/update (R),J + api/pages/show (R),J + api/pages/destroy (R),J + api/pages/update (R),J + api/pages/permissions (R),J + api/pages/permissions/update (R),J + api/events/show (R),J + api/events/update (R),J + api/events/permissions (R),J + api/events/permissions/update (R),J + api/events/destroy (R),J + api/photos/show (R),J + api/photos/update (R),J + api/photos/permissions (R),J + api/photos/permissions/update (R),J + api/albums/destroy (R),J + api/albums/show (R),J + api/albums/update (R),J + api/albums/permissions (R),J + api/albums/permissions/update (R),J + api/albums/destroy (R),J + api/friends/permissions (R),J + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/api_posting.bb b/sources/doc/api_posting.bb new file mode 100644 index 00000000..fa955826 --- /dev/null +++ b/sources/doc/api_posting.bb @@ -0,0 +1,23 @@ +[b][size=xx-large]Posting to the Matrix via the API[/size][/b] + +The API allows you to post to the red# by HTTP POST request. Below you see an example using the command line tool cURL: + +[code]curl -ssl -u [color=blue]$E-Mail[/color]:[color=blue]$Password[/color] -d "[color=blue]$Parameters[/color]" [url][observer=1][observer.baseurl][/observer][observer=0]example.com[/observer]/api/statuses/update +[/url][/code] +[table][tr][td]$E-Mail:[/td][td]The E-Mail Adress you use to login[/td][/tr] +[tr][td]$Password:[/td][td]The Password you use to login[/td][/tr] +[tr][td]$Parameters:[/td][td]That's the interesting part, here you insert the content you want to send using the following parameters:[/td][/tr][/table] + +[ul] +[*]title: the title of the posting +[*]channel: the channel you want to post to +[*]category: a comma-seperated list of categories for the posting +[*]status: the content of the posting, formatted with BBCode + OR +[*]htmlstatus:the content of the posting, formatted in HTML. +[/ul] + + +Instead of calling [observer=1][observer.baseurl][/observer][observer=0]example.com[/observer]/api/statuses/update which returns a json (you could also add .json on the end to clarify) output, you can use [observer.baseurl]/api/statuses/update.xml to get an xml formatted return. + +Instead of Basic HTTP Authentification you could also use oAuth. diff --git a/sources/doc/bbcode.html b/sources/doc/bbcode.html new file mode 100644 index 00000000..4fe47842 --- /dev/null +++ b/sources/doc/bbcode.html @@ -0,0 +1,88 @@ +

BBcode reference

+
+

+
    +
  • [b]bold[/b] - bold
    +
  • [i]italic[/i] - italic
    +
  • [u]underlined[/u] - underlined
    +
  • [s]strike[/s] - strike
    +
  • [color=red]red[/color] - red
    +
  • [url=https://redmatrix.me]$Projectname[/url] $Projectname
    +
  • [img]https://redmatrix.me/images/default_profile_photos/rainbow_man/48.jpg[/img] Image/photo
    +
  • [img float=left]https://redmatrix.me/images/default_profile_photos/rainbow_man/48.jpg[/img] Image/photo
    +
    +
  • [img float=right]https://redmatrix.me/images/default_profile_photos/rainbow_man/48.jpg[/img] Image/photo
    +
    +
  • [code]code[/code] code
    +
  • [quote]quote[/quote]
    quote

    +
  • [quote=Author]Author? Me? No, no, no...[/quote]
    Author wrote:
    Author? Me? No, no, no...

    +
  • [nobb] may be used to escape bbcode.

+ +
You can make lists with:
+
    +
  • [list]
    +
  • [list=1]
    +
  • [list=i]
    +
  • [list=I]
    +
  • [list=a]
    +
  • [list=A]
    +
  • [ul]
    +
  • [ol] + +
For example:
[ul]
[*] First list element
[*] Second list element
[/ul]

Will render something like:
+
    +
  • First list element
    +
  • Second list element

+
There's also:
+
    +
  • [hr]
    +
  • [video]video URL[/video]
    +
  • [audio]audio URL[/audio]
    +
  • [table]
    +
  • [th]
    +
  • [td]
    +
  • [tr]
    +
  • [center]
    +
  • [font=courier]some text[/font] some text
    +

+
Tables? Yes!

[table border=1]
[tr]
[th]Tables now[/th]
[/tr]
[tr]
[td]Have headers[/td]
[/tr]
[/table]

Tables now
Have headers

All sizes,
From the [size=xx-small] - xx-small.
To the [size=xx-large] - xx-large.
To fit exactly 20px use [size=20].

+ +

$Projectname specific codes

+
    +
  • [&copy;] © This works for many HTML entities
  • +
  • [zrl]https://redmatrix.me[/zrl] Magic-auth version of [url] tag
  • +
  • [zmg]https://redmatrix.me/some/photo.jpg[/zmg] Magic-auth version of [img] tag
  • + +
  • [observer=1]Text to display if observer is authenticated in the matrix[/observer]
  • +
  • [observer=0]Text to display if observer is not authenticated in the matrix[/observer]
  • +
  • [observer.baseurl] website of observer
  • +
  • [observer.url] channel URL of observer
  • +
  • [observer.name] name of observer
  • +
  • [observer.address] address (zot-id) of observer
  • +
  • [observer.photo] profile photo of observer
  • + +
  • [spoiler] for hiding spoilers

  • + +
  • [rpost=title]Text to post[/rpost] The observer will be returned to their home hub to enter a post with the specified title and body. Both are optional
  • +
  • [qr]text to post[/qr] - create a QR code.
  • +
  • [toc] - create a table of content in a webpage. Please refer to the original jquery toc to get more explanations. +
      +
    • Optional param: 'data-toc'. If ommited the default is 'body'
    • +
    • Optional param: 'data-toc-headings'. If ommited the default is 'h1,h2,h3'
    • +
    • Full example: [toc data-toc='div.page-body' data-toc-headings='h1,h2']
    • +
    +
  • +
+
+

These require a suitable map plugin/addon such as openstreetmap or else the result will be blank

+
    +
  • [map] Generate an inline map using the current browser coordinates of the poster, if browser location is enabled
    +
  • [map=latitude,longitude] Generate a map using global coordinates.
    +
  • [map]Place Name[/map] Generate a map for a given named location. The first matching location is returned. For instance "Sydney" will usually return Sydney, Australia and not Sydney, Nova Scotia, Canada unless the more precise location is specified. It is highly recommended to use the post preview utility to ensure you have the correct location before submitting the post.
    +
+ +#include doc/macros/main_footer.bb; +
+ + + diff --git a/sources/doc/campaign.bb b/sources/doc/campaign.bb new file mode 100644 index 00000000..48f28f0c --- /dev/null +++ b/sources/doc/campaign.bb @@ -0,0 +1,237 @@ +[b]Initial Indiegg pitch[/b] + +[b][color= grey][size=20]What have we done, and what we hope to achieve[/size][/color][/b] + +[b][color= grey][size=18]Single-click sign on, nomadic identity, censorship-resistance, privacy, self-hosting[/size][/color][/b] + +We started the $Projectname project by asking ourselves a few questions: + +- Imagine if it was possible to just access the content of different web sites, without the need to enter usernames and passwords for every site. Such a feature would permit Single-Click user identification: the ability to access sites simply by clicking on links to remote sites. +Authentication just happens automagically behind the scenes. Forget about remembering multiple user names with multiple passwords when accessing different sites online. + +We liked this idea and went ahead with coding it immediately. Today, single-click sign is in alpha state. It needs more love, which means a solid three months of full-time development efforts. + +- Think of your Facebook, Twitter, WordPress, or any other website where you currently have an account. Now imagine being able to clone your account, to make an exact duplicate of it (with all of your friends, posts and settings), then export your cloned account into another server that is part of this communication network. After you're done, both of your accounts are synced from the time they were cloned. It doesn't matter where you log in (at your original location, or where you imported your clone). You see the same content, the same friends, posts, and account settings. +At that point, it is more appropriate to call your account an identity that is nomadic (it is not tied to one home, unless you choose to do so!). +It's 2013, our online presence no longer has to be tied to a single server, domain name or IP address. We should be able to clone and import our identities to other servers. In such a network, it should only matter who you are, not where you are. + +We're very intrigued by the possibilities nomadic identities open up for freedom, censorship-resistance, and identity resilience. Consider the following scenarios: + + -- Should a repressive government or corporation decide to delete your account, your cloned identity lives on, because it is located on another server, across the world, which is part of the same communication network. You can't be silenced! + + -- What if there is a server meltdown, and your identity goes off line. No problem, you log into your clone and all is good. + + -- Your server administrator can no longer afford to keep paying to support a free service (a labor love and principle, which all of us have participating in as system administrators of Friendica sites!). She notifies you that you must clone your account before the shutoff date. Rather than loose all your friends, and start from scratch by creating a new identity somewhere, you clone and move to another server. +We feel this is especially helpful for the free web, where administrators of FOSS community sites are often faced with difficult financial decisions. Since many of them rely on donations, sometimes servers have to be taken offline, when costs become prohibitive for the brave DIY souls running those server. Nomadic identities should relieve some of the pressures associated with such situations. + +At the same time, we are also thinking of solutions that would make it possible for people running Red hubs to be financially sustainable. To that end, we're starting to implement service classes in our code, which would allow administrators to structure paid levels of service, if they choose to do so. + +Today, nomadic identity is currently in alpha state. It also needs more love, which means a solid three months of full-time development efforts. + +- Imagine a social network that is censorship-resistant, and privacy-respecting by design. It is not controlled by one mega-corporation, and where users cannot be easily censored by oppressive governments. So, in addition to nomadic identities, we are talking about decentralization, open source, freely software, that can run on any hardware that supports a database and a modern web browser. And we mean "any hardware", from a self-hosted $35 Raspberry Pi, to the very latest Intel Xeon and AMD Bulldozer-powered server behemoths. + +We've realized that privacy requires full control over content. We should be able to delete, backup and download all of our content, as well as associated account/identity information. To this end, we have already implemented the initial version of account export and backup. + +Concerned about pages and pages of posts from months and years past? The solution should be simple: visit your settings page, specify that all content older than 7 days, with the exception of starred posts, should be automatically deleted. Done, the clutter is gone! (Consider also the privacy and anti-mass surveillance implications of this feature. PRISM disclosures have hinted that three-letter spying agencies around the world are recording all internet traffic and storing it for a few days at a time. We feel that automatic post expiration becomes a rather useful feature in this context, and implementing it is one of our near future priorities.) + +[b][color= grey][size=18]The Affinity Slider and Access Control Lists[/size][/color][/b] + +- What if the permissions and access control lists that help secure modern operating systems were extended into a communication network that lived on the internet? This means somebody could log into this network from their home site, and with the simple click of a few buttons dynamically sort who can have access to their online content on a very fine level: from restricting others from seeing your latest blog post, to sharing your bookmarks with the world. + +We've coded the initial version of such a new feature. It is called the "Affinity Slider", and in our very-alpha user interface it looks like this. +[img]https://friendicared.net/photo/b07b0262e3146325508b81a9d1ae4a1e-0.png[/img] + +{INSERT SCREENSHOT OF A MATRIX PAGE} + +Think of it as an easy way to filter content that you see, based on the degree of "closeness" to you. Move the slider to Friends, and only content coming from contacts you've tagged as friends is displayed on your home page. Uncluttering thousands of contacts, friends, RSS feeds, and other content should be a basic feature of modern communication on the web, but not at the expense of ease of use. + +In addition to the Affinity Slider, we also have the ACL (Access Control List). Say you want to share something with only 5 of your contacts (a blog, two friends from college, and two forums). You click on the padlock, choose the recipients, and that's it. Only those identities will recieve their posts. Furthermore, the post will be encrypted via PKI (pulic key encryption) to help maintain privacy. In the age of PRISM, we don't know all the details on what's safe out there, but we still think that privacy by design should be automatically present, invisible to the user, and easy to use. +Attaching permissions to any data that lives on this network, potentially solves a great many headaches, while achieving simplicity in communication. + +Think of it this way: the internet is nothing, but a bunch of permissions and a folder of data. You, the user controls the permissions and thus the data that is relevant to you. + +[b][color= grey][size=20]The Matrix is Born![/size][/color][/b] + +After asking and striving to answer a number of such questions, we realized that we were imagining a general purpose communication network with a number of unique, and potentially game-changing, features. We called it the $Projectname and started thinking of it as an over-lay on top of the internet as it exists today; an operating system re-invented as a communication network, with its own permissions, access control lists, protocol, connectors to others services, and open-ended possibilities via its API. The sum of the matrix is greater than it's parts. We're not building website, but a way for websites to link together and grow into something that is unique and ever-changing, with autonomy and privacy. + +It's a lot of work, for anyone. So far, we've got a team of a handful of volunteers, code geeks, brave early adopters, system administrators and other good people, willing to give the project a shot. We're motivated by our commitment to a free web, where privacy is built-in, and corporations don't have a stranglehold on our daily communication. + +We need your help to finish it and release it to the world! + +[b][color= grey][size=20]What have we written so far[/size][/color][/b] + +As of the today, the $Projectname is in developer preview (alpha) state. It is not ready for everyday use, but some of the initial set of core features are implemented (again, in alpha state). These include: + +- Zot, the protocol powering the matrix +- Single-signon logins. +- Nomadic identities +- Basic content manipulation: creation, deletion, rudimentary handling of photos, and media files +- A bare-bones outline of the API and user documentation. + + +[b][color= grey][size=20]Our TO-DO List[/size][/color][/b] + +However, in addition to finishing and polishing the above, there are a number of features that have to implemented to make the $Projectname ready for daily use. If we meet our fundraising goal, we hope to dive into the following road map, by order of priority: + +- A professionally designed user interface (UI), interface that is adaptive to any user level, from end users who want to use the Matrix as a social network, to tinkerers who will put together a customized blog using Comanche, to hackers who will develop and extend the matrix using a built-in code editor, that hooks to the API and the git. + +- Comanche, our new markup language, similar to BBCode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. You can read more about it on our github wiki: https://github.com/friendica/red/wiki/Comanche + +- A unique help system that lives in the matrix, but is not based on the principles of a search engine. We have some interesting ideas about decentralizing help documentation, without going down the road of distributed search engines. Here's a hint: We shouldn't be searching at all, we should just be filtering what's already there in new, and cunning ways. + +- An appropriate logo, along with professionally done documentation system, both for our API, as well as users. + +- WordPress-like single button software upgrades + +- A built-in development environment, using an integrated web-based code editor such as Ace9 + +[b][color= grey][size=20]What will the money be used for[/size][/color][/b] + +If we raise our targeted amount of funds, we plan to use it as follows: + +1) Fund 6 months {OR WHATEVER} of full time work for our current core developers, Mike, Thomas, and Tobias {ANYONE ELSE?] + +2) Pay a professional web developer to design an kick ass reference theme, along with a project logo. + +3) {WHAT ELSE?} + +[b][color= grey][size=20]Deadlines[/size][/color][/b] + +[b]March, 2014: $Projectname Beta with the following features[/b] + +- {LIST FEATURES} + +[b][color= grey][size=20]Who We Are[/size][/color][/b] + +Mike: {FILL IN BIO, reference Friendica, etc.} + +Thomas: {bio blurb} + +Tobias: {bio blurb} + +Arto: {documentation, etc.} + +{WHO ELSE? WE NEED A TEAM, AT LEAST 3-4 PEOPLE} + +[b][color= grey][size=20]What Do I Get as a Supporter?[/size][/color][/b] + +Our ability to reach 1.0 stable release depends on your generosity and support. We appreciate your help, regardless of the amount! Here's what we're thinking as far as different contribution levels go: + +[b]$1: {CATCHY TAGLINE}[/b] + +We'll list your name on our initial supporters list, a Hall of Fame of the matrix! + +[b]$5:[/b] + +[b]$10: [/b] + +[b]$16: [/b] + +You get one of your $Projectname t-shirts, as well as our undying gratitude. + +[b]$32: [/b] + +[b]$64 [/b] + +[b]128 [/b] + +[b]$256: [/b] + +[b]$512: [/b] + +[b]$1024 [/b] + +[b]$2048[/b] + +Each contributor at this level gets their own $Projectname virtual private server, installed, hosted and supported by us for a period of 1 year. + +[b][color= grey][size=20]Why are we so excited about the $Projectname?[/size][/color][/b] + +{SOMETHING ABOUT THE POTENTIAL IMPACT OF RED, ITS INNOVATIONS, ETC> + +[b][color= grey][size=20]Other Ways to Help[/size][/color][/b] + +We're a handful of volunteers, and we understand that not everyone can contribute by donating money. There are many other ways you can in getting the Matrix to version 1.0! + +First, you can checkout our source code on github: https://github.com/redmatrix/hubzilla + +Maybe you can dive in and help us out with some development. + +Second, you can install the current developer preview on a server and start compiling bug reports. + +Third, register at one of the public alpha Red hubs, and get a feel for what Red is trying to do! + +Perhaps you're good at writing and documenting stuff. Grab an account at one of the public alphas and give us a hand. + +[b][color= grey][size=20]Frequently Asked Questions[/size][/color][/b] + +[b]1. Is Red a social network?[/b] + +The $Projectname is not a social network. We're thinking of it as a general purpose communication network, with sharing, and public/private communications built into the matrix. + +[b]2. What is the difference between Red and Friendica?[/b] + +What's the difference between a passport, and a postcard? + +Friendica is really, really good at sending postcards. It can do all sorts of things with postcards. It can send them to your friends. It can send them to people you don't know. It can put them in an envelope and send them privately. It can run them through a photocopier and plaster them all over the internet. It can even take postcards in one language and convert them to many others so your friends who speak a different language can read them. + +What Friendica can't do, is wave a postcard at somebody and expect them to believe that holding this postcard prove you are who you say you are. Sure, if you've been sending somebody postcards, they might accept that it is you in the picture, but somebody who has never heard of you will not accept ownership of a postcard as proof of identity. + +The $Projectname offers a passport. + +You can still use it to send postcards. At the same time, when you wave your passport at somebody, they do accept it as proof of identity. No longer do you need to register at every single site you use. You already have an account - it's just not necessarily at our site - so we'll ask to see your passport instead. + +Once you've proven your identity, a Red hub lets you use our services, as though you'd registered with directly, and we'd verified your credentials as would have happened in the olden days. These resources can, of course, be anything at all. + +[b]2. Why did you choose PHP, instead of Ruby or Python?[/b] + +The reference implementation is in PHP. We chose PHP, because it is available everywhere, and is easily configurable. We understand the debates between proponents and opponents of PHP, Ruby and Python. Nothing prevents implementations of Zot and the matrix in those languages. In fact, people on the matrix have already started developing a version of Red in Python [SOURCE?], and there is talk about future implementations in C (aiming for blazing native performance) and Java. It's free and open source, so we feel it's only a matter of time, once Red is initially completed. + +[b]4. Other than PHP, what other technology does Red use?[/b] + +We use MySQL as our database (this include any forks such as, MariaDB or Percona), and any modern webserver (Apache, nginx, etc.). + +[b]5. How is the Affinity Slider different from Mozilla's Persona?[/b] +{COMPLETE} + +[b]6. Does the $Projectname use encryption? Details please![/b] + +Yes, we do our best to use free and open source encryption libraries to help achieve privacy from general, mass surveillance. + +Communication between web browsers and Red hubs is encrypted using SSL certificates. + +Private communication on the matrix is protected by AES symmetric encryption, which is itself protected by RSA PKI (public key encryption). By default, we use AES-256-CBC, and our RSA keys are set to 4096-bits. + +For more info on our initial implementation of encrypted communication, check out our source code at Github: https://github.com/friendica/red/blob/master/include/crypto.php + +[b]7. What do you mean by decentralization? [/b] + + +[b]8. Can I build my own website with in the $Projectname?[/b] + +Yes. The short explanation: We've got this spiffy idea we're calling "Comanche", which will allow non-programmers to build complete custom websites, and any such website will be able to connect to any other website or channel in the matrix. The goal of Comanche is to hide the technical complexities of communicating in the matrix, while encouraging people to use their creativity and put together their own unique presence on the matrix. + +The longer explanation: Comanche is a markup language, similar to bbcode, with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Description Language file (".pdl", pronounced "puddle") to create these pages. Bbcode is not a requirement; an XML PDL file could also be used. The tag delimiters would be different. Usage is the same. + +Additional information is available on our Github project wiki: https://github.com/friendica/red/wiki/Comanche + +Comanche is another one of our priorities for the next six months. + +[b]9. Where can I see some technical description of Zot?[/b] + +Our github wiki contains a number of high-level and technical descriptions of Zot, Comanche, and Red in general: https://github.com/friendica/red/wiki + +[b]10. What happens if you raise more than {TARGETED NUMBER}?[/b] + +Raising more than our initial goal of funds, will speed up our development efforts. More developers will be able to take time off from other jobs, and concentrate efforts on finishing Red. + +[b]11 Can I make a contribution via Bitcoin?[/b] + +{YES/NO} + +[b]12. I have additional Questions[/] + +Awesome. We'd be more than happy to chat. You can find us {HERE} + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/channels.bb b/sources/doc/channels.bb new file mode 100644 index 00000000..ff044654 --- /dev/null +++ b/sources/doc/channels.bb @@ -0,0 +1,30 @@ +[b]Channels[/b] + +Channels are simply collections of content stored in one place. A channel can represent anything. It could represent you, a website, a forum, photo albums, anything. For most people, their first channel with be "Me". + +The most important features for a channel that represents "me" are: + +Secure and private "spam free" communications + +Identity and "single-signon" across the entire network + +Privacy controls and permissions which extend to the entire network + +Directory services (like a phone book) + +In short, a channel that represents yourself is "me, on the internet". + +You will be required to create your first channel as part of the sign up process. You can also create additonal channels from the "Select channel" link. + +You will be asked to provide a channel name, and a short nick name. For a channel that represents yourself, it is a good idea to use your real name here to ensure your friends can find you, and connect to your channel. The short nickname will be used to generate a "webbie". This is a bit like a username, and will look like an email address, taking the form nickname@domain. You should put a little thought into what you want to use here. Imagine somebody asking for your webbie and having to tell them it is "llamas-are_kewl.123". "llamasarecool" would be a much better choice. + +Once you have created your channel, you will be taken to the settings page, where you can configure your channel, and set your default permissions. + +Once you have done this, your channel is ready to use. At [observer=1][observer.url][/observer][observer=0]example.com/channel/username[/observer] you will find your channel "stream". This is where your recent activity will appear, in reverse chronological order. If you post in the box marked "share", the entry will appear at the top of your stream. You will also find links to all the other communication areas for this channel here. The "About" tab contains your "profile", the photos page contain photo albums, and the events page contains events share by both yourself and your contacts. + +The "Matrix" page contains all recent posts from across the matrix, again in reverse chronologial order. The exact posts that appear here depend largely on your permissions. At their most permissive, you will receive posts from complete strangers. At the other end of the scale, you may see posts from only your friends - or if you're feeling really anti-social, only your own posts. + +As mentioned at the start, many other kinds of channel are possible, however, the creation procedure is the same. The difference between channels lies primarily in the permissions assigned. For example, a channel for sharing documents with colleagues at work would probably want more permissive settings for "Can write to my "public" file storage" than a personal account. For more information, see the permissions section. + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/checking_account_quota_usage.bb b/sources/doc/checking_account_quota_usage.bb new file mode 100644 index 00000000..ca7e070a --- /dev/null +++ b/sources/doc/checking_account_quota_usage.bb @@ -0,0 +1,20 @@ +[b]Checking your account quota usage (service limits usage)[/b] + +Your hub might implement service class limits, assigning limits to the total size of file, photo, channels, top-level posts, etc., that can be created by an account holder for a specific service level. + +Here's how you can quickly check how much of your assigned quota you're currently using: + +[b]Check file storage quota levels[/b] +Visit the following URL in your browser: +[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer] +[observer=0]example.com/filestorage/username[/observer] + +[b]Check uploaded photos storage quota levels[/b] +[observer=1][observer.baseurl]/photos/[observer.webname][/observer] +[observer=0]example.com/photos/username[/observer] + +Example: +[observer=1][observer.baseurl]/filestorage/[observer.webname][/observer] +[observer=0]example.com/filestorage/username[/observer] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/classRedmatrix_1_1Import_1_1Import-members.html b/sources/doc/classRedmatrix_1_1Import_1_1Import-members.html new file mode 100644 index 00000000..d5e2f927 --- /dev/null +++ b/sources/doc/classRedmatrix_1_1Import_1_1Import-members.html @@ -0,0 +1,131 @@ + + + + + + +The Hubzilla: Member List + + + + + + + + + + + + + +
+
+ + + + + + + +
+
The Hubzilla +
+
+
+ + + + + +
+
+ +
+
+
+ + \ No newline at end of file diff --git a/sources/doc/classRedmatrix_1_1Import_1_1Import.html b/sources/doc/classRedmatrix_1_1Import_1_1Import.html new file mode 100644 index 00000000..9a7128d6 --- /dev/null +++ b/sources/doc/classRedmatrix_1_1Import_1_1Import.html @@ -0,0 +1,446 @@ + + + + + + +The Hubzilla: Hubzilla\Import\Import Class Reference + + + + + + + + + + + + + +
+
+ + + + + + + +
+
The Hubzilla +
+
+
+ + + + + +
+
+ +
+
+
+ +
+ + + + +
+ +
+ +
+ +
+
Hubzilla\Import\Import Class Reference
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

 get_credentials ()
 
 get_itemlist ()
 
 get_item_ident ($item)
 
 get_item ($item_ident)
 
 get_taxonomy ($item_ident)
 
 get_children ($item_ident)
 
 convert_item ($item_ident)
 
 convert_taxonomy ($item_ident)
 
 convert_child ($child)
 
 store ($item, $update=false)
 
 run ()
 
+ + + + + + + +

+Protected Attributes

 $itemlist = null
 
 $src_items = null
 
 $items = null
 
+ + + +

+Private Attributes

 $credentials = null
 
+

Member Function Documentation

+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::convert_child ( $child)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::convert_item ( $item_ident)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::convert_taxonomy ( $item_ident)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::get_children ( $item_ident)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + +
Hubzilla\Import\Import::get_credentials ()
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::get_item ( $item_ident)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::get_item_ident ( $item)
+
+ +
+
+ +
+
+ + + + + + + +
Hubzilla\Import\Import::get_itemlist ()
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + + +
Hubzilla\Import\Import::get_taxonomy ( $item_ident)
+
+ +

Referenced by Hubzilla\Import\Import\run().

+ +
+
+ +
+
+ + + + + + + +
Hubzilla\Import\Import::run ()
+
+ +
+
+ +
+
+ + + + + + + + + + + + + + + + + + +
Hubzilla\Import\Import::store ( $item,
 $update = false 
)
+
+ +
+
+

Member Data Documentation

+ +
+
+ + + + + +
+ + + + +
Hubzilla\Import\Import::$credentials = null
+
+private
+
+
+ +
+
+ + + + + +
+ + + + +
Hubzilla\Import\Import::$itemlist = null
+
+protected
+
+
+ +
+
+ + + + + +
+ + + + +
Hubzilla\Import\Import::$items = null
+
+protected
+
+ +
+
+ +
+
+ + + + + +
+ + + + +
Hubzilla\Import\Import::$src_items = null
+
+protected
+
+ +
+
+
The documentation for this class was generated from the following file: +
+
\ No newline at end of file diff --git a/sources/doc/cloud.bb b/sources/doc/cloud.bb new file mode 100644 index 00000000..20498e6a --- /dev/null +++ b/sources/doc/cloud.bb @@ -0,0 +1,27 @@ +[b]Personal Cloud Storage[/b] + +The $Projectname provides an ability to store privately and/or share arbitrary files with friends. + +You may either upload files from your computer into your storage area, or copy them directly from the operating system using the WebDAV protocol. + +On many public servers there may be limits on disk usage. + +[b]File Attachments[/b] + +The quickest and easiest way to share files is through file attachments. In the row of icons below the status post editor is a tool to upload attachments. Click the tool, select a file and submit. After the file is uploaded, you will see an attachment code placed inside the text region. Do not edit this line or it may break the ability for your friends to see the attachment. You can use the post permissions dialogue box or privacy hashtags to restrict the visibility of the file - which will be set to match the permissions of the post your are sending. + +To delete attachments or change the permissions on the stored files, visit [observer.baseurl]/filestorage/{{username}}" replacing {{username}} with the nickname you provided during channel creation. + +[b]Web Access[/b] + +Your files are visible on the web at the location "cloud/{{username}}" to anybody who is allowed to view them. If the viewer has sufficient privileges, they may also have the ability to create new files and folders/directories. + +[b]WebDAV access[/b] + +See: [zrl=[baseurl]/help/cloud_desktop_clients]Cloud Desktop Clients[/zrl] + +[b]Permissions[/b] + +When using WebDAV, the file is created with your channel's default file permissions and this cannot be changed from within the operating system. It also may not be as restrictive as you would like. What we've found is that the preferred method of making files private is to first create folders or directories; then visit "filestorage/{{username}}"; select the directory and change the permissions. Do this before you put anything into the directory. The directory permissions take precedence so you can then put files or other folders into that container and they will be protected from unwanted viewers by the directory permissions. It is common for folks to create a "personal" or "private" folder which is restricted to themselves. You can use this as a personal cloud to store anything from anywhere on the web or any computer and it is protected from others. You might also create folders for "family" and "friends" with permission granted to appropriate collections of channels. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/cloud_desktop_clients.bb b/sources/doc/cloud_desktop_clients.bb new file mode 100644 index 00000000..2f099527 --- /dev/null +++ b/sources/doc/cloud_desktop_clients.bb @@ -0,0 +1,21 @@ +[b]Cloud Desktop Clients[/b] + +[b]Windows Clients[/b] + +[li][zrl=[baseurl]/help/dav_windows]Windows Internal Client[/zrl][/li] + + +[b]Linux Clients[/b] + +[li][zrl=[baseurl]/help/dav_mount]Command Line as a Filesystem[/zrl][/li] +[li][zrl=[baseurl]/help/dav_dolphin]Dolphin[/zrl][/li] +[li][zrl=[baseurl]/help/dav_konqueror]Konqueror[/zrl][/li] +[li][zrl=[baseurl]/help/dav_nautilus]Nautilus[/zrl][/li] +[li][zrl=[baseurl]/help/dav_nemo]Nemo[/zrl][/li] + + +[b]Server Notes[/b] + +Note: There have been reported issues with clients that use "chunked transfer encoding", which includes Apple iOS services, and also the "AnyClient" and "CyberDuck" tools. These work fine for downloads, but uploads often end up with files of zero size. This is caused by an incorrect implemention of chunked encoding in some current FCGI (fast-cgi) implementations. Apache running with PHP as a module does not have these issues, but when running under FCGI you may need to use alternative clients or use the web uploader. At the time of this writing the issue has been open and no updates provided for at least a year. If you encounter zero size files with other clients, please check the client notes; as there are occasional configuration issues which can also produce these symptoms. + +#include doc/macros/cloud_footer.bb; diff --git a/sources/doc/comanche.bb b/sources/doc/comanche.bb new file mode 100644 index 00000000..2eaa15de --- /dev/null +++ b/sources/doc/comanche.bb @@ -0,0 +1,220 @@ +[b]Comanche Page Description Language[/b] + +Comanche is a markup language similar to bbcode with which to create elaborate and complex web pages by assembling them from a series of components - some of which are pre-built and others which can be defined on the fly. Comanche uses a Page Decription Language to create these pages. + +Comanche primarily chooses what content will appear in various regions of the page. The various regions have names and these names can change depending on what layout template you choose. + +[b]Page Templates[/b] +Currently there are five layout templates, unless your site provides additional layouts. + +[code] + [b]default[/b] + The default template defines a "nav" region across the top, "aside" as a fixed width sidebar, + "content" for the main content region, and "footer" for a page footer. + + + [b]full[/b] + The full template defines the same as the default template with the exception that there is no "aside" region. + + + [b]choklet[/b] + The choklet template provides a number of fluid layout styles which can be specified by flavour: + + (default flavour) - a two column layout similar to the "default" template, but more fluid + bannertwo - a two column layout with a banner region, compatible with the "default" template on small displays + three - three column layout (adds a "right_aside" region to the default template) + edgestwo - two column layout with fixed side margins + edgesthree - three column layout with fixed side margins + full - three column layout with fixed side margins and adds a "header" region beneath the navigation bar + + [b]redable[/b] + A template for reading longer texts. Three columns: aside, content and right_aside. + For maximum readability it is advised to only use the middle content column. + + [b]zen[/b] + Gives you the freedom to do everything yourself. Just a blank page with a content region. + +[/code] + +To choose a layout template, use the 'template' tag. + +[code] + [template]full[/template] + +[/code] + +To choose the "choklet" template with the "three" flavour: + +[code] + [template=three]choklet[/template] + +[/code] + +The default template will be used if no other template is specified. The template can use any names it desires for content regions. You will be using 'region' tags to decide what content to place in the respective regions. + +Three "macros" have been defined for your use. +[code] + $htmlhead - replaced with the site head content. + $nav - replaced with the site navigation bar content. + $content - replaced with the main page content. + +[/code] + +By default, $nav is placed in the "nav" page region and $content is placed in the "content" region. You only need to use these macros if you wish to re-arrange where these items appear, either to change the order or to move them to other regions. + + +To select a theme for your page, use the 'theme' tag. +[code] + [theme]apw[/theme] + +[/code] +This will select the theme named "apw". By default your channel's preferred theme will be used. + +[code] + [theme=passion]apw[/theme] + +[/code] +This will select the theme named "apw" and select the "passion" schema (theme variant). + + +[b]Regions[/b] +Each region has a name, as noted above. You will specify the region of interest using a 'region' tag, which includes the name. Any content you wish placed in this region should be placed between the opening region tag and the closing tag. + +[code] + [region=htmlhead]....content goes here....[/region] + [region=aside]....content goes here....[/region] + [region=nav]....content goes here....[/region] + [region=content]....content goes here....[/region] + +[/code] + +[b]CSS and Javascript[/b] +We have the possibility to include javascript and css libraries in the htmlhead region. At present we make use of jquery (js), bootstrap (css/js) and foundation (css/js). +This will overwrite the selected themes htmlhead. + +[code] + [region=htmlhead] + [css]bootstrap[/css] + [js]jquery[/js] + [js]bootstrap[/js] + [/region] + +[/code] + +[b]Menus and Blocks[/b] +Your webpage creation tools allow you to create menus and blocks, in addition to page content. These provide a chunk of existing content to be placed in whatever regions and whatever order you specify. Each of these has a name which you define when the menu or block is created. + +[code] + [menu]mymenu[/menu] + +[/code] +This places the menu called "mymenu" at this location on the page, which must be inside a region. + +[code] + [menu=horizontal]mymenu[/menu] + +[/code] +This places the menu called "mymenu" at this location on the page, which must be inside a region. Additionally it applies the "horizontal" class to the menu. "horizontal" is defined in the redbasic theme. It may or may not be available in other themes. + +[code] + [menu][var=wrap]none[/var]mymenu[/menu] + +[/code] +The variable [var=wrap]none[/var] in a block removes the wrapping div element from the menu. + +[code] + [block]contributors[/block] +[/code] +This places a block named "contributors" in this region. + +[code] + [block=someclass]contributors[/block] + +[/code] +This places a block named "contributors" in this region. Additionally it applies the "someclass" class to the block. This replaces the default block classes "bblock widget". + +[code] + [block][var=wrap]none[/var]contributors[/block] + +[/code] +The variable [var=wrap]none[/var] in a block removes the wrapping div element from the block. + +[b]Widgets[/b] +Widgets are executable apps provided by the system which you can place on your page. Some widgets take arguments which allows you to tailor the widget to your purpose. (TODO: list available widgets and arguments). The base system provides + +[code] + profile - widget which duplicates the profile sidebar of your channel page. This widget takes no arguments + tagcloud - provides a tag cloud of categories + count - maximum number of category tags to list + +[/code] + +Widgets and arguments are specified with the 'widget' and 'var' tags. +[code] + [widget=recent_visitors][var=count]24[/var][/widget] + +[/code] + +This loads the "recent_visitors" widget and supplies it with the argument "count" set to "24". + +[b]Comments[/b] +The 'comment' tag is used to delimit comments. These comments will not appear on the rendered page. + +[code] + [comment]This is a comment[/comment] + +[/code] + +[b]Complex Example[/b] +[code] + [comment]use an existing page template which provides a banner region plus 3 columns beneath it[/comment] + + [template]3-column-with-header[/template] + + [comment]Use the "darknight" theme[/comment] + + [theme]darkknight[/theme] + + [comment]Use the existing site navigation menu[/comment] + + [region=nav]$nav[/region] + + [region=side] + + [comment]Use my chosen menu and a couple of widgets[/comment] + + [menu]myfavouritemenu[/menu] + + [widget=recent_visitors] + [var=count]24[/var] + [var=names_only]1[/var] + [/widget] + + [widget=tagcloud][/widget] + [block]donate[/block] + + [/region] + + + + [region=middle] + + [comment]Show the normal page content[/comment] + + $content + + [/region] + + + + [region=right] + + [comment]Show my condensed channel "wall" feed and allow interaction if the observer is allowed to interact[/comment] + + [widget]channel[/widget] + + [/region] + +[/code] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/connecting_to_channels.bb b/sources/doc/connecting_to_channels.bb new file mode 100644 index 00000000..be37eb25 --- /dev/null +++ b/sources/doc/connecting_to_channels.bb @@ -0,0 +1,19 @@ +[b]Connecting To Channels[/b] + +Connections in the $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? + +First, you need to find some channels to connect to. There are two primary ways of doing this. Firstly, setting the "Can send me their channel stream and posts" permission to "Anybody in this network" will bring posts from complete strangers to your matrix. This will give you a lot of public content and should hopefully help you find interesting, entertaing people, forums, and channels. + +The next thing you can do is look at the Directory. The directory is available on every $Projectname website which means searching from your own site will bring in results from the entire network. You can search by name, interest, location and keyword. This is incomplete, so we'll improve this paragraph later. + +To connect with other $Projectname channels: + +Visit their profile by clicking their photograph in the directory, matrix, or comments, and it will open their channel home page in the channel viewer. At the left hand side of the screen, you will usually see a link called "connect". Click it, and you're done. Depending on the settings of the channel you are connecting to, you may need to wait for them to approve your connection, but no further action is needed on your part. Once you've initiated the connection, you will be taken to the connection editor. This allows you to assign specific permissions for this channel. If you don't allow any permissions, communication will be very limited. There are some quick links which you can use to avoid setting individual permissions. To provide a social network environment, "Full Sharing" is recommended. You may review the settings that are applied with the quick links to ensure they are suitable for the channel you are connecting with and adjust if necessary. Then scroll to the bottom of the page and click "Submit". + +You may also connect with any channel by visiting the "Connections" page of your site or the Directory and typing their "webbie" into the "Add New Connection" field. Use this method if somebody tells you their webbie and you wish to connect with them. A webbie looks like an email address; for example "bob@example.com". The process is the same as connecting via the "Connect" button - you will then be taken to the connection editor to set permissions. + +[b]Premium Channels[/b] + +Some channels are designated "Premium Channels" and may require some action on your part before a connection can be established. The Connect button will for these channels will take you to a page which lists in detail what terms the channel owner has set. If the terms are accepted, the connection will then proceed normally. In some cases, such as with celebrities and world-reknowned publishers, this may involve payment. If you do not agree to the terms, the connection will not proceed, or it may proceed but with reduced permissions allowed on your interactions with that channel. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/connecting_to_channels.md b/sources/doc/connecting_to_channels.md new file mode 100644 index 00000000..60834c24 --- /dev/null +++ b/sources/doc/connecting_to_channels.md @@ -0,0 +1,34 @@ +# Connecting To Channels # + +Connections in the $Projectname can take on a great many different meanings. But let's keep it simple, you want to be friends with somebody like you are familiar with from social networking. How do you do it? + +First, you need to find some channels to connect to. There are two primary ways of doing this. Firstly, setting the "Can send me their channel stream and posts" permission to "Anybody in this network" will bring posts from complete strangers to your matrix. This will give you a lot of public content and should hopefully help you find interesting, entertaing people, forums, and channels. + +The next thing you can do is look at the Directory. The directory is available on every $Projectname website which means searching from your own site will bring in results from the entire network. You can search by name, interest, location and keyword. This is incomplete, so we'll improve this paragraph later. + +To connect with other $Projectname channels: + +Visit their profile by clicking their photograph in the directory, matrix, or comments, and it will open their channel home page in the channel viewer. At the left hand side of the screen, you will usually see a link called "connect". Click it, and you're done. Depending on the settings of the channel you are connecting to, you may need to wait for them to approve your connection, but no further action is needed on your part. Once you've initiated the connection, you will be taken to the connection editor. This allows you to assign specific permissions for this channel. If you don't allow any permissions, communication will be very limited. There are some quick links which you can use to avoid setting individual permissions. To provide a social network environment, "Full Sharing" is recommended. You may review the settings that are applied with the quick links to ensure they are suitable for the channel you are connecting with and adjust if necessary. Then scroll to the bottom of the page and click "Submit". + +You may also connect with any channel by visiting the "Connections" page of your site or the Directory and typing their "webbie" into the "Add New Connection" field. Use this method if somebody tells you their webbie and you wish to connect with them. A webbie looks like an email address; for example "bob@example.com". The process is the same as connecting via the "Connect" button - you will then be taken to the connection editor to set permissions. + +## Block/Ignore/Archive/Hide channels ## + +Channels in your address book can have statuses such as *blocked*, *ignored*, *archived* and *hidden*. From your connections page you can see tabs that display the channels with those statuses. From your edit connection pages you can change the statuses of a channel. + +Here's their meaning: + +**Blocked:** the channel can't read your items regardless of permissions, nor can it write to your channel. + +**Ignored:** the channel can read your items if it has permission, but can't write to your channel. + +**Hidden:** the channel does not show up in your profile's connections list, noone can see you're connected, but beware they may still show up to your other connections, for example in post replies. + +**Archived:** if a channel can't be reached for 30 days, it is automatically marked as archived. This keeps all the data but stops polling the channel for new information and removes it from autocomplete. If later you learn the channel has come back online, you may manually unarchive it. + + +## Premium Channels ## + +Some channels are designated "Premium Channels" and **may** require some action on your part before a connection can be established. The Connect button will for these channels will take you to a page which lists in detail what terms the channel owner has set. If the terms are accepted, the connection will then proceed normally. In some cases, such as with celebrities and world-reknowned publishers, this **may** involve payment. If you do not agree to the terms, the connection will not proceed, or it may proceed but with reduced permissions allowed on your interactions with that channel. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/credits.bb b/sources/doc/credits.bb new file mode 100644 index 00000000..5459c7d7 --- /dev/null +++ b/sources/doc/credits.bb @@ -0,0 +1,75 @@ +[b]Credits[/b] + +Mike Macgirvin +Fabio Comuni +Simon L'nu +marijus +Tobias Diekershoff +fabrixxm +tommy tomson +Simon +zottel +Christian Vogeley +jeroenpraat +Michael Vogel +erik +Zach Prezkuta +Paolo T +Michael Meer +Michael +Abinoam P. Marques Jr +Tobias Hößl +Alexander Kampmann +Olaf Conradi +Paolo Tacconi +tobiasd +Devlon Duthie +Zvi ben Yaakov (a.k.a rdc) +Alexandre Hannud Abdo +Olivier Migeot +Chris Case +Klaus Weidenbach +Michael Johnston +olivierm +Vasudev Kamath +pixelroot +Max Weller +duthied +Martin Schmitt +Sebastian Egbers +Erkan Yilmaz +sasiflo +Stefan Parviainen +Haakon Meland Eriksen +Oliver Hartmann (23n) +Erik Lundin +habeascodice +sirius +Charles +Tony Baldwin +Hauke Zuehl +Keith Fernie +Anne Walk +toclimb +Daniel Frank +Matthew Exon +Michal Supler +Tobias Luther +U-SOUND\mike +mrjive +nostupidzone +tonnerkiller +Antoine G +Christian Drechsler +Ludovic Grossard +Stanislav Lechev [0xAF] +aweiher +bufalo1973 +dsp1986 +felixgilles +ike +maase2 +mycocham +ndurchx +pafcu +Simó Albert i Beltran diff --git a/sources/doc/database.bb b/sources/doc/database.bb new file mode 100644 index 00000000..fe193cf7 --- /dev/null +++ b/sources/doc/database.bb @@ -0,0 +1,66 @@ +[h2]Database Tables[/h2] +[table] +[tr][th]Table[/th][th]Description[/th][/tr] +[tr][td][zrl=[baseurl]/help/database/db_abook]abook[/zrl][/td][td]connections of local channels[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_account]account[/zrl][/td][td]service provider account[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_addon]addon[/zrl][/td][td]registered plugins[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_app]app[/zrl][/td][td]personal app data[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_attach]attach[/zrl][/td][td]file attachments[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_auth_codes]auth_codes[/zrl][/td][td]OAuth usage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_cache]cache[/zrl][/td][td]OEmbed cache[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_channel]channel[/zrl][/td][td]local channels[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_chat]chat[/zrl][/td][td]chat room content[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_chatpresence]chatpresence[/zrl][/td][td]channel presence information for chat[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_chatroom]chatroom[/zrl][/td][td]data for the actual chat room[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_clients]clients[/zrl][/td][td]OAuth usage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_config]config[/zrl][/td][td]main configuration storage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_conv]conv[/zrl][/td][td]Diaspora private messages meta conversation structure[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_event]event[/zrl][/td][td]Events[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_fcontact]fcontact[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_ffinder]ffinder[/zrl][/td][td]friend suggestion stuff (obsolete)[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_fserver]fserver[/zrl][/td][td]obsolete[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_fsuggest]fsuggest[/zrl][/td][td]friend suggestion stuff (unused)[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_group_member]group_member[/zrl][/td][td]privacy groups (collections), group info[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_groups]groups[/zrl][/td][td]privacy groups (collections), member info[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_hook]hook[/zrl][/td][td]plugin hook registry[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_hubloc]hubloc[/zrl][/td][td]Red location storage, ties a hub location to an xchan[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_issue]issue[/zrl][/td][td]future bug/issue database[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_item]item[/zrl][/td][td]all posts and webpages[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_item_id]item_id[/zrl][/td][td]other identifiers on other services for posts[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_likes]likes[/zrl][/td][td]likes of 'things'[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_mail]mail[/zrl][/td][td]private messages[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_manage]manage[/zrl][/td][td]may be unused in Red, table of accounts that can "su" each other[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_menu]menu[/zrl][/td][td]webpage menu data[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_menu_item]menu_item[/zrl][/td][td]entries for webpage menus[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_notify]notify[/zrl][/td][td]notifications[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_obj]obj[/zrl][/td][td]object data for things (x has y)[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_outq]outq[/zrl][/td][td]Red output queue[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_pconfig]pconfig[/zrl][/td][td]personal (per channel) configuration storage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_photo]photo[/zrl][/td][td]photo storage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_poll]poll[/zrl][/td][td]data for polls[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_poll_elm]poll_elm[/zrl][/td][td]data for poll elements[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_profdef]profdef[/zrl][/td][td]custom profile field definitions[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_profext]profext[/zrl][/td][td]custom profile field data[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_profile]profile[/zrl][/td][td]channel profiles[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_profile_check]profile_check[/zrl][/td][td]DFRN remote auth use, may be obsolete[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_register]register[/zrl][/td][td]registrations requiring admin approval[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_session]session[/zrl][/td][td]web session storage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_shares]shares[/zrl][/td][td]shared item information[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_sign]sign[/zrl][/td][td]Diaspora signatures. To be phased out.[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_site]site[/zrl][/td][td]site table to find directory peers[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_source]source[/zrl][/td][td]channel sources data[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_spam]spam[/zrl][/td][td]unfinished[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_sys_perms]sys_perms[/zrl][/td][td]extensible permissions for OAuth[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_term]term[/zrl][/td][td]item taxonomy (categories, tags, etc.) table[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_tokens]tokens[/zrl][/td][td]OAuth usage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_updates]updates[/zrl][/td][td]directory sync updates[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_verify]verify[/zrl][/td][td]general purpose verification structure[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_vote]vote[/zrl][/td][td]vote data for polls[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xchan]xchan[/zrl][/td][td]list of known channels in the universe[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xchat]xchat[/zrl][/td][td]bookmarked chat rooms[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xconfig]xconfig[/zrl][/td][td]as pconfig but for channels with no local account[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xign]xign[/zrl][/td][td]channels ignored by friend suggestions[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xlink]xlink[/zrl][/td][td]"friends of friends" linkages derived from poco, also ratings storage[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xprof]xprof[/zrl][/td][td]if this hub is a directory server, contains basic public profile info of everybody in the network[/td][/tr] +[tr][td][zrl=[baseurl]/help/database/db_xtag]xtag[/zrl][/td][td]if this hub is a directory server, contains tags or interests of everybody in the network[/td][/tr] +[/table] diff --git a/sources/doc/database/db_abook.bb b/sources/doc/database/db_abook.bb new file mode 100644 index 00000000..a34e5199 --- /dev/null +++ b/sources/doc/database/db_abook.bb @@ -0,0 +1,55 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]abook_id[/td][td]Sequential ID[/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]abook_account[/td][td]account.account_id of the channel which owns this record[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]abook_channel[/td][td]channel.channel_id of the channel which owns this record[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]abook_xchan[/td][td]xchan.xchan_hash of the target identity (this channel's connection)[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]abook_my_perms[/td][td]bitfield of all specific permissions granted this connection[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]abook_their_perms[/td][td]bitfield of all permissions granted to you by this connection[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]abook_closeness[/td][td]"closeness" value for optional affinity tool, 0-99[/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]99[/td][td] +[/td][/tr] +[tr][td]abook_rating[/td][td]The channel owner's (public) rating of this connection -10 to +10, default 0 or unrated[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]abook_rating_text[/td][td]The channel owner's (public) rating of this connection free form text[/td][td]text[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]abook_created[/td][td]Datetime this record was created[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]abook_updated[/td][td]Datetime this record was modified[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]abook_connected[/td][td]datetime of last successful "poll" for this connection[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]abook_dob[/td][td]Datetime of connection's birthday converted from *their* timezone to UTC[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]abook_flags[/td][td]Bitfield containing blocked(0x1), ignored(0x2), hidden(0x4), archived(0x8), pending(0x10), unconnected(0x20), self(0x80), feed(0x100)[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]abook_profile[/td][td]profile.guid of profile to display to this connection if authenticated[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + + +Notes: + +ABOOK_FLAGS_BLOCKED - Bi-directional communications with this channel are blocked, regardless of other permissions. + +ABOOK_FLAGS_IGNORED - Incoming communications from this channel are blocked, regardless of other permissions. + +ABOOK_FLAGS_HIDDEN - This connection will not be shown as a connection to anybody but the channel owner + +ABOOK_FLAGS_ARCHIVED - This connection is likely non-functioning and the entry and conversations are preserved, but further polled communications will not be attempted. + +ABOOK_FLAGS_PENDING - A connection request was received from this channel but has not been approved by the channel owner, public communications may still be visible but no additional permissions have been granted. + +ABOOK_FLAGS_UNCONNECTED - currently unused. Projected usage is to indicate "one-way" connections which were insitgated on this end but are still pending on the remote end. + +ABOOK_FLAGS_SELF is a special case where the owner is the target. Every channel has one abook entry with ABOOK_FLAGS_SELF with a target abook_xchan set to channel.channel_hash . When this flag is present, abook_my_perms is the default permissions granted to all new connections and several other fields are unused. + +ABOOK_FLAGS_FEED - indicates this connection is an RSS/Atom feed and may trigger special handling. + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_account.bb b/sources/doc/database/db_account.bb new file mode 100644 index 00000000..354f2d3a --- /dev/null +++ b/sources/doc/database/db_account.bb @@ -0,0 +1,67 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]account_id[/td][td]table index[/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]account_parent[/td][td]for hierarchical accounts, the account_id of the parent to this one, if account_parent = account_id, this is the top level account[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]account_default_channel[/td][td]channel_id of channel to connect on login[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]account_salt[/td][td]complexity token for account_password[/td][td]char(32)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]account_password[/td][td]hashed password for this account[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]account_email[/td][td]essentially the login ID, although it is usually possible to login with a channel address[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]account_external[/td][td]Currently unused[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]account_language[/td][td]default language (closest available browser-accept language when account was created)[/td][td]char(16)[/td][td]NO[/td][td][/td][td]en[/td][td] +[/td][/tr] +[tr][td]account_created[/td][td]timestamp of account creation[/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]account_lastlog[/td][td]timestamp of last login (or daily update if "remember me" is in effect)[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]account_flags[/td][td]see notes[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]account_roles[/td][td]see notes[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]account_reset[/td][td]verification token for password reset[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]account_expires[/td][td]timestamp when account expires and will be deleted[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]account_expire_notified[/td][td]timestamp of last warning of account expiration[/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]account_service_class[/td][td]service class for this account, determines what if any limits/restrictions are in place[/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]account_level[/td][td]future use[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]account_password_changed[/td][td]timestamp of last password change - to limit account deletion for 48 hours to prevent malicious activity[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Notes: + + + +/** + * Account Flags + */ + +define ( 'ACCOUNT_OK', 0x0000 ); +define ( 'ACCOUNT_UNVERIFIED', 0x0001 ); +define ( 'ACCOUNT_BLOCKED', 0x0002 ); +define ( 'ACCOUNT_EXPIRED', 0x0004 ); +define ( 'ACCOUNT_REMOVED', 0x0008 ); +define ( 'ACCOUNT_PENDING', 0x0010 ); + +/** + * Account roles + */ + +define ( 'ACCOUNT_ROLE_ALLOWCODE', 0x0001 ); // 1 - this account can create content with PHP/Javascript +define ( 'ACCOUNT_ROLE_SYSTEM', 0x0002 ); // 2 - this is the special system account +define ( 'ACCOUNT_ROLE_DEVELOPER', 0x0004 ); +define ( 'ACCOUNT_ROLE_ADMIN', 0x1000 ); // 4096 - this account is an administrator + + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_addon.bb b/sources/doc/database/db_addon.bb new file mode 100644 index 00000000..afa06d56 --- /dev/null +++ b/sources/doc/database/db_addon.bb @@ -0,0 +1,24 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td]generated index[td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]name[/td][td]plugin base (file)name[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]version[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]installed[/td][td]currently always 1[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hidden[/td][td]currently unused[/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]timestamp[/td][td]file timestamp to check for reloads[/td][td]bigint(20)[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[tr][td]plugin_admin[/td][td]1 = has admin config, 0 = has no admin config[/td][td]tinyint(1)[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[/table] + +Notes: + +These are addons which have been enabled by the site administrator on the admin/plugin page + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_app.bb b/sources/doc/database/db_app.bb new file mode 100644 index 00000000..7076bffd --- /dev/null +++ b/sources/doc/database/db_app.bb @@ -0,0 +1,36 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td]generated index[/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]app_id[/td][td]hash identifying this app[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_sig[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]app_author[/td][td]xchan_hash of app creator[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]app_name[/td][td]name of app[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_desc[/td][td]optional description of app[/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]app_url[/td][td]target_url[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_photo[/td][td]app icon[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_version[/td][td]version of app[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_channel[/td][td]channel_id owning this instance of the app[/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]app_addr[/td][td]reddress/webbie of app creator[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]app_price[/td][td]free-form price field[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]app_page[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]app_requires[/td][td]currently unused[/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[/table] + +Storage for personal apps + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_attach.bb b/sources/doc/database/db_attach.bb new file mode 100644 index 00000000..4514c87f --- /dev/null +++ b/sources/doc/database/db_attach.bb @@ -0,0 +1,50 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td]generated index[/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]aid[/td][td]account_id of owner[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td]channel_id of owner[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hash[/td][td]hash for cross-site identification[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]creator[/td][td]xchan_hash of author/creator[/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]filename[/td][td]filename of original[/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]filetype[/td][td]mimetype[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]filesize[/td][td]size in bytes[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]revision[/td][td]for version control (partially implemented)[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]folder[/td][td]attach.hash of parent folder[/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]flags[/td][td]see notes[/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]data[/td][td]file data or pathname to stored data if ATTACH_FLAG_OS[/td][td]longblob[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td]creation time[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]edited[/td][td]last edit time[/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td]permissions[/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td]permissions[/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td]permissions[/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td]permissions[/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + + +Bitmasks + +define ( 'ATTACH_FLAG_DIR', 0x0001); This is a directory +define ( 'ATTACH_FLAG_OS', 0x0002); Data content is link to OS file containing data, if unset the data filed contains the file data + +permissions are xchan_hash or group_hash surrounded by angle chars. e.g. '' + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_auth_codes.bb b/sources/doc/database/db_auth_codes.bb new file mode 100644 index 00000000..c60f064a --- /dev/null +++ b/sources/doc/database/db_auth_codes.bb @@ -0,0 +1,19 @@ + +OAuth2 authorisation register - currently implemented but unused + +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]varchar(40)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]client_id[/td][td][/td][td]varchar(20)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]redirect_uri[/td][td][/td][td]varchar(200)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]expires[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]scope[/td][td][/td][td]varchar(250)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_cache.bb b/sources/doc/database/db_cache.bb new file mode 100644 index 00000000..02c292f2 --- /dev/null +++ b/sources/doc/database/db_cache.bb @@ -0,0 +1,15 @@ + +OEmbed information cache + +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]k[/td][td]horizontal width + url or resource[/td][td]char(255)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]v[/td][td]OEmbed response from site[/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]updated[/td][td]datetime of cache insertion[/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_channel.bb b/sources/doc/database/db_channel.bb new file mode 100644 index 00000000..215db3fb --- /dev/null +++ b/sources/doc/database/db_channel.bb @@ -0,0 +1,96 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]channel_account_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_primary[/td][td][/td][td]tinyint(1) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_address[/td][td][/td][td]char(255)[/td][td]NO[/td][td]UNI[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_guid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_guid_sig[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_timezone[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td]UTC[/td][td] +[/td][/tr] +[tr][td]channel_location[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_theme[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_startpage[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]channel_pubkey[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_prvkey[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_notifyflags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]65535[/td][td] +[/td][/tr] +[tr][td]channel_pageflags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_dirdate[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]channel_deleted[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]channel_max_anon_mail[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]10[/td][td] +[/td][/tr] +[tr][td]channel_max_friend_req[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]10[/td][td] +[/td][/tr] +[tr][td]channel_expire_days[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_passwd_reset[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]channel_default_group[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]channel_allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channel_r_stream[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_r_profile[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_r_photos[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_r_abook[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_stream[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_wall[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_tagwall[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_comment[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_mail[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_photos[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_chat[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_a_delegate[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_r_storage[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_storage[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_r_pages[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_pages[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_a_republish[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[tr][td]channel_w_like[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]128[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_chat.bb b/sources/doc/database/db_chat.bb new file mode 100644 index 00000000..6221f36e --- /dev/null +++ b/sources/doc/database/db_chat.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]chat_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]chat_room[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]chat_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]chat_text[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_chatpresence.bb b/sources/doc/database/db_chatpresence.bb new file mode 100644 index 00000000..cdc948a6 --- /dev/null +++ b/sources/doc/database/db_chatpresence.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]cp_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]cp_room[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]cp_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]cp_last[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]cp_status[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]cp_client[/td][td][/td][td]char(128)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_chatroom.bb b/sources/doc/database/db_chatroom.bb new file mode 100644 index 00000000..b2da762c --- /dev/null +++ b/sources/doc/database/db_chatroom.bb @@ -0,0 +1,28 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]cr_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]cr_aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]cr_uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]cr_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]cr_created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]cr_edited[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]cr_expire[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_clients.bb b/sources/doc/database/db_clients.bb new file mode 100644 index 00000000..d342b529 --- /dev/null +++ b/sources/doc/database/db_clients.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]client_id[/td][td][/td][td]varchar(20)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]pw[/td][td][/td][td]varchar(20)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]redirect_uri[/td][td][/td][td]varchar(200)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]icon[/td][td][/td][td]text[/td][td]YES[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_config.bb b/sources/doc/database/db_config.bb new file mode 100644 index 00000000..f32d3c25 --- /dev/null +++ b/sources/doc/database/db_config.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]cat[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]k[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]v[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_conv.bb b/sources/doc/database/db_conv.bb new file mode 100644 index 00000000..ba1ba7f0 --- /dev/null +++ b/sources/doc/database/db_conv.bb @@ -0,0 +1,22 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]guid[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]recips[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]creator[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]updated[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]subject[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_event.bb b/sources/doc/database/db_event.bb new file mode 100644 index 00000000..7c31d7fd --- /dev/null +++ b/sources/doc/database/db_event.bb @@ -0,0 +1,46 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]event_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]event_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]edited[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]start[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]finish[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]summary[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]description[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]location[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]type[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]nofinish[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]adjust[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]1[/td][td] +[/td][/tr] +[tr][td]ignore[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_fcontact.bb b/sources/doc/database/db_fcontact.bb new file mode 100644 index 00000000..9bd8c20f --- /dev/null +++ b/sources/doc/database/db_fcontact.bb @@ -0,0 +1,38 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]url[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]photo[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]request[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]nick[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]addr[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]batch[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]notify[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]poll[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]confirm[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]priority[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]network[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]alias[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]pubkey[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]updated[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_ffinder.bb b/sources/doc/database/db_ffinder.bb new file mode 100644 index 00000000..c20158d5 --- /dev/null +++ b/sources/doc/database/db_ffinder.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]cid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]fid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_fserver.bb b/sources/doc/database/db_fserver.bb new file mode 100644 index 00000000..4c4b0b53 --- /dev/null +++ b/sources/doc/database/db_fserver.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]server[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]posturl[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]key[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_fsuggest.bb b/sources/doc/database/db_fsuggest.bb new file mode 100644 index 00000000..9da1f2f6 --- /dev/null +++ b/sources/doc/database/db_fsuggest.bb @@ -0,0 +1,24 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]cid[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]url[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]request[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]photo[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]note[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_group_member.bb b/sources/doc/database/db_group_member.bb new file mode 100644 index 00000000..d31fa1ed --- /dev/null +++ b/sources/doc/database/db_group_member.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]gid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_groups.bb b/sources/doc/database/db_groups.bb new file mode 100644 index 00000000..03e4fe2d --- /dev/null +++ b/sources/doc/database/db_groups.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]visible[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]deleted[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_hook.bb b/sources/doc/database/db_hook.bb new file mode 100644 index 00000000..6e8e907a --- /dev/null +++ b/sources/doc/database/db_hook.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]hook[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]file[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]function[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]priority[/td][td][/td][td]int(11) unsigned[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_hubloc.bb b/sources/doc/database/db_hubloc.bb new file mode 100644 index 00000000..e4ab7159 --- /dev/null +++ b/sources/doc/database/db_hubloc.bb @@ -0,0 +1,38 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]hubloc_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]hubloc_guid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_guid_sig[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]hubloc_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]hubloc_addr[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_network[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_flags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hubloc_status[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hubloc_url[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_url_sig[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]hubloc_host[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_callback[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_connect[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]hubloc_sitekey[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]hubloc_updated[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]hubloc_connected[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_issue.bb b/sources/doc/database/db_issue.bb new file mode 100644 index 00000000..0a6f2912 --- /dev/null +++ b/sources/doc/database/db_issue.bb @@ -0,0 +1,20 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]issue_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]issue_created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]issue_updated[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]issue_assigned[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]issue_priority[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]issue_status[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]issue_component[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_item.bb b/sources/doc/database/db_item.bb new file mode 100644 index 00000000..b31823d6 --- /dev/null +++ b/sources/doc/database/db_item.bb @@ -0,0 +1,104 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]mid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]parent[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]parent_mid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]thr_parent[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]edited[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]expires[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]commented[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]received[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]changed[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]comments_closed[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]owner_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]author_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]source_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]mimetype[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]title[/td][td][/td][td]text[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]body[/td][td][/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]app[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]lang[/td][td][/td][td]char(64)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]revision[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]verb[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]obj_type[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]object[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]tgt_type[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]target[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]layout_mid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]postopts[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]route[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]llink[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]plink[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]resource_id[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]resource_type[/td][td][/td][td]char(16)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]attach[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]sig[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]diaspora_meta[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]location[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]coord[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]public_policy[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]comment_policy[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]item_restrict[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]item_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]item_private[/td][td][/td][td]tinyint(4)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_item_id.bb b/sources/doc/database/db_item_id.bb new file mode 100644 index 00000000..b77ae2d1 --- /dev/null +++ b/sources/doc/database/db_item_id.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]iid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]sid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]service[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_likes.bb b/sources/doc/database/db_likes.bb new file mode 100644 index 00000000..118c9a87 --- /dev/null +++ b/sources/doc/database/db_likes.bb @@ -0,0 +1,24 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]channel_id[/td][td][/td][td]int(11) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]liker[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]likee[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]iid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]verb[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]target_type[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]target_id[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]target[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_mail.bb b/sources/doc/database/db_mail.bb new file mode 100644 index 00000000..0628584a --- /dev/null +++ b/sources/doc/database/db_mail.bb @@ -0,0 +1,34 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]convid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]mail_flags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]from_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]to_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]account_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]title[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]body[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]attach[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]mid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]parent_mid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]expires[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_manage.bb b/sources/doc/database/db_manage.bb new file mode 100644 index 00000000..a0fdf5aa --- /dev/null +++ b/sources/doc/database/db_manage.bb @@ -0,0 +1,12 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_menu.bb b/sources/doc/database/db_menu.bb new file mode 100644 index 00000000..5b478115 --- /dev/null +++ b/sources/doc/database/db_menu.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]menu_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]menu_channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]menu_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]menu_desc[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]menu_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_menu_item.bb b/sources/doc/database/db_menu_item.bb new file mode 100644 index 00000000..b14aac5e --- /dev/null +++ b/sources/doc/database/db_menu_item.bb @@ -0,0 +1,28 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]mitem_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]mitem_link[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]mitem_desc[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]mitem_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]mitem_channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]mitem_menu_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]mitem_order[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_notify.bb b/sources/doc/database/db_notify.bb new file mode 100644 index 00000000..42f9350e --- /dev/null +++ b/sources/doc/database/db_notify.bb @@ -0,0 +1,36 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]hash[/td][td][/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]url[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]photo[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]date[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]msg[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]link[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]parent[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]seen[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]type[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]verb[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]otype[/td][td][/td][td]char(16)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_obj.bb b/sources/doc/database/db_obj.bb new file mode 100644 index 00000000..cc5e7559 --- /dev/null +++ b/sources/doc/database/db_obj.bb @@ -0,0 +1,26 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]obj_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]obj_page[/td][td][/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]obj_verb[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]obj_type[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]obj_obj[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]obj_channel[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_outq.bb b/sources/doc/database/db_outq.bb new file mode 100644 index 00000000..970f99de --- /dev/null +++ b/sources/doc/database/db_outq.bb @@ -0,0 +1,28 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]outq_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]outq_account[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]outq_channel[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]outq_driver[/td][td][/td][td]char(32)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]outq_posturl[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]outq_async[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]outq_delivered[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]outq_created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]outq_updated[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]outq_notify[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]outq_msg[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_pconfig.bb b/sources/doc/database/db_pconfig.bb new file mode 100644 index 00000000..2ac36e61 --- /dev/null +++ b/sources/doc/database/db_pconfig.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]cat[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]k[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]v[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_photo.bb b/sources/doc/database/db_photo.bb new file mode 100644 index 00000000..6a0cdf36 --- /dev/null +++ b/sources/doc/database/db_photo.bb @@ -0,0 +1,52 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]resource_id[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]edited[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]title[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]description[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]album[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]filename[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]type[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td]image/jpeg[/td][td] +[/td][/tr] +[tr][td]height[/td][td][/td][td]smallint(6)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]width[/td][td][/td][td]smallint(6)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]size[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]data[/td][td][/td][td]mediumblob[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]scale[/td][td][/td][td]tinyint(3)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]profile[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]photo_flags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]allow_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]allow_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_cid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]deny_gid[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_poll.bb b/sources/doc/database/db_poll.bb new file mode 100644 index 00000000..57d808b7 --- /dev/null +++ b/sources/doc/database/db_poll.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]poll_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]poll_channel[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]poll_desc[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]poll_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]poll_votes[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_poll_elm.bb b/sources/doc/database/db_poll_elm.bb new file mode 100644 index 00000000..fd649d5a --- /dev/null +++ b/sources/doc/database/db_poll_elm.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]pelm_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]pelm_poll[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]pelm_desc[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]pelm_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td][/td][td]0[/td][td] +[/td][/tr] +[tr][td]pelm_result[/td][td][/td][td]float[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_profdef.bb b/sources/doc/database/db_profdef.bb new file mode 100644 index 00000000..a0904fd7 --- /dev/null +++ b/sources/doc/database/db_profdef.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]field_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]field_type[/td][td][/td][td]char(16)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]field_desc[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]field_help[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]field_inputs[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_profext.bb b/sources/doc/database/db_profext.bb new file mode 100644 index 00000000..ada9dce2 --- /dev/null +++ b/sources/doc/database/db_profext.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]k[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]v[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_profile.bb b/sources/doc/database/db_profile.bb new file mode 100644 index 00000000..83db7571 --- /dev/null +++ b/sources/doc/database/db_profile.bb @@ -0,0 +1,94 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]profile_guid[/td][td][/td][td]char(64)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]profile_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]is_default[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]hide_friends[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]name[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]pdesc[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]chandesc[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]dob[/td][td][/td][td]char(32)[/td][td]NO[/td][td][/td][td]0000-00-00[/td][td] +[/td][/tr] +[tr][td]dob_tz[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]UTC[/td][td] +[/td][/tr] +[tr][td]address[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]locality[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]region[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]postal_code[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]country_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]hometown[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]gender[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]marital[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]with[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]howlong[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]sexual[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]politic[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]religion[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]keywords[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]likes[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]dislikes[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]about[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]summary[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]music[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]book[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]tv[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]film[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]interest[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]romance[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]work[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]education[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]contact[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]channels[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]homepage[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]photo[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]thumb[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]publish[/td][td][/td][td]tinyint(1)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_profile_check.bb b/sources/doc/database/db_profile_check.bb new file mode 100644 index 00000000..3be64c5d --- /dev/null +++ b/sources/doc/database/db_profile_check.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]cid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]dfrn_id[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]sec[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]expire[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_register.bb b/sources/doc/database/db_register.bb new file mode 100644 index 00000000..50672b5e --- /dev/null +++ b/sources/doc/database/db_register.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]password[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]language[/td][td][/td][td]char(16)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_session.bb b/sources/doc/database/db_session.bb new file mode 100644 index 00000000..d7ff0482 --- /dev/null +++ b/sources/doc/database/db_session.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]bigint(20) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]sid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]data[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]expire[/td][td][/td][td]bigint(20) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_shares.bb b/sources/doc/database/db_shares.bb new file mode 100644 index 00000000..be5255c0 --- /dev/null +++ b/sources/doc/database/db_shares.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]share_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]share_type[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]share_target[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]share_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_sign.bb b/sources/doc/database/db_sign.bb new file mode 100644 index 00000000..e80ea7ef --- /dev/null +++ b/sources/doc/database/db_sign.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]iid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]retract_iid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]signed_text[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]signature[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]signer[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_site.bb b/sources/doc/database/db_site.bb new file mode 100644 index 00000000..8dea4dae --- /dev/null +++ b/sources/doc/database/db_site.bb @@ -0,0 +1,28 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]site_url[/td][td][/td][td]char(255)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]site_access[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]site_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]site_update[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]site_pull[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]site_sync[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]site_directory[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]site_register[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]site_sellpage[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]site_location[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]site_realm[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_source.bb b/sources/doc/database/db_source.bb new file mode 100644 index 00000000..92850a82 --- /dev/null +++ b/sources/doc/database/db_source.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]src_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]src_channel_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]src_channel_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]src_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]src_patt[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_spam.bb b/sources/doc/database/db_spam.bb new file mode 100644 index 00000000..b75e1edd --- /dev/null +++ b/sources/doc/database/db_spam.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(11)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]spam[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]ham[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]term[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]date[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_sys_perms.bb b/sources/doc/database/db_sys_perms.bb new file mode 100644 index 00000000..04416a26 --- /dev/null +++ b/sources/doc/database/db_sys_perms.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]cat[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]k[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]v[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]public_perm[/td][td][/td][td]tinyint(1) unsigned[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_term.bb b/sources/doc/database/db_term.bb new file mode 100644 index 00000000..c0546cc6 --- /dev/null +++ b/sources/doc/database/db_term.bb @@ -0,0 +1,28 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]tid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]aid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]oid[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]otype[/td][td][/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]type[/td][td][/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]term[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]url[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]imgurl[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]term_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]parent_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_tokens.bb b/sources/doc/database/db_tokens.bb new file mode 100644 index 00000000..35da2458 --- /dev/null +++ b/sources/doc/database/db_tokens.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]varchar(40)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]secret[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]client_id[/td][td][/td][td]varchar(20)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]expires[/td][td][/td][td]bigint(20) unsigned[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]scope[/td][td][/td][td]varchar(200)[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_updates.bb b/sources/doc/database/db_updates.bb new file mode 100644 index 00000000..f2e25d84 --- /dev/null +++ b/sources/doc/database/db_updates.bb @@ -0,0 +1,20 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]ud_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]ud_hash[/td][td][/td][td]char(128)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]ud_guid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]ud_date[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]ud_last[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]ud_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]ud_addr[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_verify.bb b/sources/doc/database/db_verify.bb new file mode 100644 index 00000000..9d01181c --- /dev/null +++ b/sources/doc/database/db_verify.bb @@ -0,0 +1,18 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]channel[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]type[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]token[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]meta[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]created[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_vote.bb b/sources/doc/database/db_vote.bb new file mode 100644 index 00000000..0b9a423e --- /dev/null +++ b/sources/doc/database/db_vote.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]vote_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]vote_poll[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]vote_element[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]vote_result[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]vote_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xchan.bb b/sources/doc/database/db_xchan.bb new file mode 100644 index 00000000..fd1d6829 --- /dev/null +++ b/sources/doc/database/db_xchan.bb @@ -0,0 +1,44 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]xchan_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan_guid[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_guid_sig[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan_pubkey[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xchan_photo_mimetype[/td][td][/td][td]char(32)[/td][td]NO[/td][td][/td][td]image/jpeg[/td][td] +[/td][/tr] +[tr][td]xchan_photo_l[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_photo_m[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_photo_s[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_addr[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_url[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_connurl[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_follow[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_connpage[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_name[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_network[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_instance_url[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchan_flags[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]xchan_photo_date[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[tr][td]xchan_name_date[/td][td][/td][td]datetime[/td][td]NO[/td][td][/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xchat.bb b/sources/doc/database/db_xchat.bb new file mode 100644 index 00000000..0897408d --- /dev/null +++ b/sources/doc/database/db_xchat.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]xchat_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]xchat_url[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchat_desc[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchat_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xchat_edited[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xconfig.bb b/sources/doc/database/db_xconfig.bb new file mode 100644 index 00000000..111d1ce3 --- /dev/null +++ b/sources/doc/database/db_xconfig.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]cat[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]k[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]v[/td][td][/td][td]mediumtext[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xign.bb b/sources/doc/database/db_xign.bb new file mode 100644 index 00000000..e216e11c --- /dev/null +++ b/sources/doc/database/db_xign.bb @@ -0,0 +1,12 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]uid[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xlink.bb b/sources/doc/database/db_xlink.bb new file mode 100644 index 00000000..2eefec14 --- /dev/null +++ b/sources/doc/database/db_xlink.bb @@ -0,0 +1,16 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]xlink_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]xlink_xchan[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xlink_link[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xlink_rating[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]xlink_updated[/td][td][/td][td]datetime[/td][td]NO[/td][td]MUL[/td][td]0000-00-00 00:00:00[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xprof.bb b/sources/doc/database/db_xprof.bb new file mode 100644 index 00000000..d98fb3f1 --- /dev/null +++ b/sources/doc/database/db_xprof.bb @@ -0,0 +1,36 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]xprof_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xprof_age[/td][td][/td][td]tinyint(3) unsigned[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[tr][td]xprof_desc[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_dob[/td][td][/td][td]char(12)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_gender[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_marital[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_sexual[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_locale[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_region[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_postcode[/td][td][/td][td]char(32)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_country[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_keywords[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xprof_about[/td][td][/td][td]text[/td][td]NO[/td][td][/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xprof_homepage[/td][td][/td][td]char(255)[/td][td]NO[/td][td][/td][td][/td][td] +[/td][/tr] +[tr][td]xprof_hometown[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/database/db_xtag.bb b/sources/doc/database/db_xtag.bb new file mode 100644 index 00000000..1e6fb996 --- /dev/null +++ b/sources/doc/database/db_xtag.bb @@ -0,0 +1,14 @@ +[table] +[tr][th]Field[/th][th]Description[/th][th]Type[/th][th]Null[/th][th]Key[/th][th]Default[/th][th]Extra +[/th][/tr] +[tr][td]xtag_id[/td][td][/td][td]int(10) unsigned[/td][td]NO[/td][td]PRI[/td][td]NULL[/td][td]auto_increment +[/td][/tr] +[tr][td]xtag_hash[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td]NULL[/td][td] +[/td][/tr] +[tr][td]xtag_term[/td][td][/td][td]char(255)[/td][td]NO[/td][td]MUL[/td][td][/td][td] +[/td][/tr] +[tr][td]xtag_flags[/td][td][/td][td]int(11)[/td][td]NO[/td][td]MUL[/td][td]0[/td][td] +[/td][/tr] +[/table] + +Return to [zrl=[baseurl]/help/database]database documentation[/zrl] \ No newline at end of file diff --git a/sources/doc/dav_dolphin.bb b/sources/doc/dav_dolphin.bb new file mode 100644 index 00000000..a1ebba39 --- /dev/null +++ b/sources/doc/dav_dolphin.bb @@ -0,0 +1,9 @@ +[b]Using The Cloud - Dolphin[/b] + +Visit webdavs://example.com/cloud where "example.com" is the URL of your hub. + +When prompted for a username and password, enter your username (the first part of your webbie - no @ or domain name) and password for your normal account. + +Note, if you are already logged in to the web interface via Konqueror, you will not be prompted for further authentication. + +#include doc/macros/cloud_footer.bb; diff --git a/sources/doc/dav_konqueror.bb b/sources/doc/dav_konqueror.bb new file mode 100644 index 00000000..79108e1d --- /dev/null +++ b/sources/doc/dav_konqueror.bb @@ -0,0 +1,12 @@ +[b]Using The Cloud - Konqueror[/b] + +Simply visit webdavs://example.com/cloud after logging in to your hub, where "example.com" is the URL of your hub. + +No further authentication is required if you are logged in to your hub in the normal manner. + +Additionally, if one has authenticated at a different hub during their normal browser session, your identity will be passed to the cloud for these hubs too - meaning you can access any private files on any server, as long as you have permissions to see them, as long as you have visited that site earlier in your session. + +This functionality is normally restricted to the web interface, and is not available to any desktop software other than KDE. + +#include doc/macros/cloud_footer.bb; + diff --git a/sources/doc/dav_mount.bb b/sources/doc/dav_mount.bb new file mode 100644 index 00000000..d8cb2e08 --- /dev/null +++ b/sources/doc/dav_mount.bb @@ -0,0 +1,86 @@ +[b]Mounting As A Filesystem[/b] + +To install your cloud directory as a filesystem, you first need davfs2 installed. 99% of the time, this will be included in your distributions repositories. In Debian + +[code]apt-get install davfs2[/code] + +If you want to let normal users mount the filesystem + +[code] dpkg-reconfigure davfs2[/code] + +and select "yes" at the prompt. + +Now you need to add any user you want to be able to mount dav to the davfs2 group + +[code]usermod -aG davfs2 <DesktopUser>[/code] + +[b]Note:[/b] on some systems the user group may be different, i.e. - "network" +on Arch Linux. If in doubt, check the davfs documentation for your +particular OS. + +Edit /etc/fstab + +[code]nano /etc/fstab[/code] + + to include your cloud directory by adding + +[code] +[baseurl]/cloud/ /mount/point davfs user,noauto,uid=<DesktopUser>,file_mode=600,dir_mode=700 0 1 +[/code] + +Where [baseurl] is the URL of your hub, /mount/point is the location you want to mount the cloud, and <DesktopUser> is the user you log in to one your computer. Note that if you are mounting as a normal user (not root) the mount point must be in your home directory. + +For example, if I wanted to mount my cloud to a directory called 'cloud' in my home directory, and my username was bob, my fstab would be + +[code][baseurl]/cloud/ /home/bob/cloud davfs user,noauto,uid=bob,file_mode=600,dir_mode=700 0 1[/code] + +Now, create the mount point. + +[code]mkdir /home/bob/cloud[/code] + +and also create a directory file to store your credentials + +[code]mkdir /home/bob/.davfs2[/code] + +Create a file called 'secrets' + +[code]nano /home/bob/.davfs2/secrets[/code] + +and add your cloud login credentials + +[code] +[baseurl]/cloud <username> <password> +[/code] + +Where <username> and <password> are the username and password [i]for your hub[/i]. + +Don't let this file be writeable by anyone who doesn't need it with + +[code]chmod 600 /home/bob/.davfs2/secrets[/code] + +Finally, mount the drive. + +[code]mount [baseurl]/cloud[/code] + +You can now find your cloud at /home/bob/cloud and use it as though it were part of your local filesystem - even if the applications you are using have no dav support themselves. + +[b]Troubleshooting[/b] + +With some webservers and certain configurations, you may find davfs2 creating files with 0 bytes file size where other clients work just fine. This is generally caused by cache and locks. If you are affected by this issue, you need to edit your davfs2 configuration. + +[code]nano /etc/davfs2/davfs2.conf[/code] + +Your distribution will provide a sample configuration, and this file should already exist, however, most of it will be commented out with a # at the beginning of the line. + +First step is to remove locks. + +Edit the use_locks line so it reads [code]use_locks 0[/code]. + +Unmount your file system, remount your file system, and try copying over a file from the command line. Note you should copy a new file, and not overwrite an old one for this test. Leave it a minute or two then do [code]ls -l -h[/code] and check the file size of your new file is still greater than 0 bytes. If it is, stop there, and do nothing else. + +If that still doesn't work, disable the cache. Note that this has a performance impact so should only be done if disabling locks didn't solve your problem. Edit the cache_size and set it to [code]cache_size 0[/code] and also set file_refresh to [code]file_refresh 0[/code]. Unmount your filesystem, remount your file system, and test it again. + +If it [i]still[/i] doesn't work, there is one more thing you can try. (This one is caused by a bug in older versions of dav2fs itself, so updating to a new version may also help). Enable weak etag dropping by setting [code]drop_weak_etags 1[/code]. Unmount and remount your filesystem to apply the changes. + +#include doc/macros/cloud_footer.bb; + diff --git a/sources/doc/dav_nautilus.bb b/sources/doc/dav_nautilus.bb new file mode 100644 index 00000000..51663b6d --- /dev/null +++ b/sources/doc/dav_nautilus.bb @@ -0,0 +1,9 @@ +[b]Using The Cloud - Nautilus[/b] + +1. Open a File browsing window (that's Nautilus) +2. Select File > Connect to server from the menu +3. Type davs://<domain_name>/cloud/<your_username> and click Connect +4. You will be prompted for your username (same as above) and password +5. Your personal DAV directory will be shown in the window + +#include doc/macros/cloud_footer.bb; diff --git a/sources/doc/dav_nemo.bb b/sources/doc/dav_nemo.bb new file mode 100644 index 00000000..2c88b078 --- /dev/null +++ b/sources/doc/dav_nemo.bb @@ -0,0 +1,19 @@ +[b]Using The Cloud - Nemo[/b] + +For (file browser) Nemo 1.8.2 under Linux Mint 15, Cinnamon 1.8.8. Nemo ist the standard file browser there. + +1st way +type "davs://yourusername@friendicared.net/cloud" in the address bar + +2nd way +Menu > file > connect to server +Fill the dialog +- Server: friendicared.net +- Type: Secure WebDAV (https) +- Folder: /cloud +- Username: yourusername +- Passwort: yourpasswort + +Once open you can set a bookmark. + +#include doc/macros/cloud_footer.bb; diff --git a/sources/doc/dav_windows.bb b/sources/doc/dav_windows.bb new file mode 100644 index 00000000..0eaffd4d --- /dev/null +++ b/sources/doc/dav_windows.bb @@ -0,0 +1,11 @@ +[b]Using The Cloud - Windows Internal Client[/b] + +RedDav using Windows 7 graphical user interface wizard: +1. Left-click the Start-button to open the start menu. +2. Right-click the My computer icon to access its menu. +3. Left-click Map network drive... to open the connection dialog wizard. +4. Type #^[url=https://example.net/cloud/your_user_name]https://example.net/cloud/your_user_name[/url] in the textbox and click the Complete button where "example.net" is the URL of your hub. +5. Type your Red account's user name. IMPORTANT - NO at-sign or domain name. +6. Type your Red password + +#include doc/macros/cloud_footer.bb; diff --git a/sources/doc/de/about.bb b/sources/doc/de/about.bb new file mode 100644 index 00000000..313337f1 --- /dev/null +++ b/sources/doc/de/about.bb @@ -0,0 +1,23 @@ +[size=large][b]Was ist die Red-Matrix?[/b][/size] + +Die Red-Matrix ist ein dezentralisiertes Kommunikationsnetzwerk mit dem Ziel, Kommunikationsmöglichkeiten bereitzustellen, die Zensur umgehen, die Privatsphäre respektieren und somit frei sind von den Einschränkungen, die die heutigen kommerziellen Kommunikationsgiganten uns auferlegen. Diese stellen in erster Linie Spionagenetzwerke für zahlende Kunden aller Art zur Verfügung und monopolisieren und zentralisieren das ganze Internet – was ursprünglich eben gerade nicht unter den revolutionären Zielen war, die einst zum World Wide Web führten. + +Die Software der Red-Matrix ist frei, kostenlos und Open Source. Sie wurde entwickelt, um auf einem Raspberry Pi für € 30,– ebenso zu laufen wie auf den größten AMD- und Intel-Xeon-Multiprozessor-Servern. Sie kann für die Kommunikation zwischen einigen wenigen Einzelpersonen genutzt werden oder viele tausend Leute und mehr miteinander verbinden. + +Ein weiteres Ziel ist es, von Können und Ressourcen unabhängig zu sein. Die Red-Matrix ist für den einfachen Computernutzer ebenso leicht bedienbar wie für Systemadministratoren und Entwickler. + +Wie Du sie benutzt hängt davon ab, wie Du sie benutzen [i]willst.[/i] + +Die Red-Matrix ist in PHP geschrieben, dadurch ist es einfach, sie auf jedweder heutigen Hosting-Plattform zu installieren, inklusive Self-Hosting zu Hause, auf Shared Servern wie bei [url=https://uberspace.de/]Uberspace[/url], [url=http://mediatemple.com/]Media Temple[/url] und [url=http://www.dreamhost.com/]Dreamhost[/url], oder auf virtuellen und dedizierten Servern, wie es sie zum Beispiel bei [url=https://www.linode.com]Linode[/url], [url=http://greenqloud.com]GreenQloud[/url] oder [url=https://aws.amazon.com]Amazon AWS[/url] gibt. + +Mit anderen Worten, die Red-Matrix kann auf jeder Plattform laufen, die einen Web-Server, eine MySQL-kompatible Datenbank und PHP mitbringt. + +Dabei bietet Red einige einzigartige Leckerbissen: + +[b]Ein-Klick-Identifikation:[/b] Du kannst auf andere Server in der Red-Matrix zugreifen, indem Du einfach auf einen Link dorthin klickst. Die Authentifizierung wird ganz einfach automatisch hinter den Kulissen durchgeführt. Vergiss viele verschiedene Usernamen für verschiedene Seiten und die Passwörter dazu – das tut alles die Matrix für Dich. + +[b]Klone:[/b] Du kannst Deine Online-Identität (oder, wie wir sagen, einen Kanal) klonen. Sie ist nicht mehr länger an einen bestimmten Server, eine Domain oder eine IP-Adresse gebunden. Importiere sie einfach auf einem anderen Red-Server (oder Red-Hub) – direkt online oder mit Hilfe eines vorher generierten Exports. Wenn Dein primärer Hub plötzlich nicht mehr online ist, kein Problem, Deine Kontakte, Posts* und Nachrichten* sind automagisch weiterhin unter Deiner geklonten Identität verfügbar und zugreifbar. [i](*: nur Posts und Nachrichten, die nach dem Moment des Klonens erstellt wurden)[/i] + +[b]Privatsphäre:[/b] Red-Identitäten (Zot-IDs) können gelöscht, gesichert/heruntergeladen und geklont werden. Du hast volle Kontrolle über Deine Daten. Wenn Du Dich entscheidest, all Deine Daten und Deine Zot-ID zu löschen, musst Du nur auf einen Link klicken, und sie werden sofort von dem Server gelöscht. Keine Fragen, keine Umstände. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/de/channels.bb b/sources/doc/de/channels.bb new file mode 100644 index 00000000..1c963fc0 --- /dev/null +++ b/sources/doc/de/channels.bb @@ -0,0 +1,26 @@ +[size=large][b]Kanäle[/b][/size] + +Kanäle sind Sammlungen von Inhalten, die an einem Ort gespeichert werden. Ein Kanal kann alles mögliche repräsentieren. Zum Beispiel Dich, eine Website, ein Forum oder ein Fotoalbum. Normalerweise wird Dein erster Kanal Dich selbst repräsentieren. + +Die wichtigsten Funktionen für einen Kanal, der einen selbst repräsentiert, sind: + +[ul][*]Sichere und private, spamfreie Kommunikation +[*]Identifikation und automatisches Einloggen im gesamten Red-Matrix-Netzwerk +[*]Datenschutzeinstellungen und Zugriffsberechtigungen, die im gesamten Netzwerk gültig sind +[*]Verzeichnisdienste (ähnlich einem Telefonbuch)[/ul] + +Kurz gesagt, ein Kanal der Dich repräsentiert ist sozusagen „Ich im Internet“. + +Du musst Deinen ersten Kanal erstellen, während Du Dich anmeldest. Du kannst auch weitere Kanäle erstellen und zwischen ihnen wechseln, indem Du auf „Kanal-Manager“ im Menü unter Deinem Profilbild klickst. + +Du wirst nach einem Kanalnamen und einem kurzen Spitznamen gefragt. Für einen Kanal, der Dich repräsentiert, ist es eine gute Idee, hier Deinen Realnamen anzugeben, damit Deine Freunde Dich finden und sich mit Dir verbinden können. Der Spitzname wird genutzt, um Deinen „Webbie“ zu erstellen. Das ist so etwas wie ein Username und sieht aus wie eine E-Mail-Adresse, zum Beispiel spitzname@red-hub.de. Überlege ein bisschen, was Du als Spitzname nutzen willst. Stell Dir vor, Du wirst nach Deinem Webbie gefragt und musst Deinem Bekannten dann buchstabieren, dass Dein Webbie „llamas.sind-cool_274@example.com“ ist. „llamassindcool@exmaple.com“ wäre da viel einfacher gewesen. + +Nachdem Du Deinen Kanal erstellt hast, wirst Du zu den Einstellungen weitergeleitet. Hier kannst Du Deinen Kanal einrichten und die Standard-Berechtigungen setzen. + +Nachdem Du auch das getan hast, kannst Du Deinen Kanal verwenden. Unter der Addresse https://example.com/channel/spitzname [observer=1]( [observer.url] )[/observer] findest Du Deinen Kanal. Hier werden Deine letzten Aktivitäten gezeigt, die neuesten oben. Wenn Du etwas in die Textbox schreibst, in der „Teilen“ steht, wird der neue Eintrag ganz oben in Deinem Kanal auftauchen. Du findest hier auch Links zu den anderen Kommunikationsbereichen Deines Kanals. Der „Über“-Reiter enthält Dein Profil, der „Fotos“-Reiter Deine Fotoalben, und der Veranstaltungskalender enthält Termine und Veranstaltungen, die Du und Deine Kontakte geteilt haben. + +Die „Matrix“-Seite enthält alle neuen Beiträge aus der gesamten $Projectname, wieder die neuesten oben. Was genau zu sehen ist ist abhängig von den Zugriffsrechten. Falls die Zugriffsrechte Deines Kanals so eingestellt sind, dass jeder Beiträge in Deinen Stream stellen kann, wirst du auch Beiträge von Dir völlig unbekannten Personen hier sehen. Am anderen Ende der Skala kannst Du die Berechtigungen aber auch so einstellen, dass du nur die Beiträge deiner Freunde oder gar nur Deine eigenen siehst. + +Wie zu Anfang erwähnt sind viele Arten von Kanälen möglich, diese unterscheiden sich hauptsächlich durch die Berechtigungen. Das Anlegen dieser Kanäle unterscheidet sich dagegen nicht. Beispiel: Um einen Kanal zum Austausch von Dokumenten zu erstellen, wirst du vermutlich die Berechtigung „Kann in meinen öffentlichen Dateiordner schreiben“ freizügiger einstellen. Für weitere Informationen sieh bitte in der Hilfe unter Zugriffsrechte nach. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/de/features.bb b/sources/doc/de/features.bb new file mode 100644 index 00000000..6bee360e --- /dev/null +++ b/sources/doc/de/features.bb @@ -0,0 +1,186 @@ +[size=large][b]Features der $Projectname[/b][/size] + +Die $Projectname ist ein Allzweck-Kommunikationsnetzwerk mit einigen einzigartigen Features. Sie wurde für eine große Bandbreite von Nutzern entwickelt, von Nutzern sozialer Netzwerke über technisch nicht interessierte Blogger bis hin zu PHP-Experten und erfahrenen Systemadministratoren. + +Diese Seite listet einige der Kern-Features von Red auf, die in der offiziellen Distribution enthalten sind. Wie immer bei freier Open-Source-Software sind den Möglichkeiten keine Grenzen gesetzt. Beliebige Erweiterungen, Addons, Themes und Konfigurationen sind möglich. + +[h2]Entwickelt für Privatsphäre und Freiheit[/h2] + +Eines der Design-Ziele von Red ist einfache Kommunikations über das Web, ohne die Privatsphäre zu vernachlässigen, wenn die Nutzer das Wünschen. Um dieses Ziel zu erreichen, verfügt Red über einige Features, die beliebige Stufen des Privatsphäre-Schutzes ermöglichen: + +[b]Beziehungs-Tool[/b] + +Wenn Du in der $Projectname einen Kontakt hinzufügst (und das Beziehungs-Tool aktiviert hast), hast Du die Möglichkeit, einen „Grad der Freundschaft“ zu bestimmen. Bespiel: Wenn Du ein Blog eines Bekannten hinzufügst, könntest Du ihm den Freundschaftsgrad „Bekannte“ (Acquaintances) geben. + + +[img]https://friendicared.net/photo/b07b0262e3146325508b81a9d1ae4a1e-0.png[/img] + +Wenn Du aber den privaten Kanal eines Freundes hinzufügst, wäre der Freundschaftsgrad „Freunde“ vermutlich passender. + +Wenn Du allen Kontakten solche Freundschaftsgrade zugeordnet hast, kannst Du mit dem Beziehungs-Tool, das (sofern aktiviert) oben auf Deiner Matrix-Seite erscheint, bestimmen, welche Inhalte Du sehen willst. Indem Du die Schieberegler so einstellst, dass der linke auf „Ich“ und der rechte auf „Freunde“ steht, kannst Du dafür sorgen, dass nur Inhalte von Kontakten angezeigt werden, deren Freundschaftsgrad sich irgendwo im Bereich zwischen „Ich“, „Beste Freunde“ und „Freunde“ bewegt. Alle anderen Kontakte, zum Beispiel solche mit einem Freundschaftsgrad in der Nähe von „Bekannte“, werden nicht angezeigt. + +Das Beziehungs-Tool erlaubt blitzschnelles Filtern von großen Mengen Inhalt, gruppiert nach Freundschaftsgrad. + +[b]Zugriffsrechte[/b] + +Wenn Du Inhalte mit anderen teilst, hast Du die Option, den Zugriff darauf einzuschränken. Wenn Du auf das Schloss unterhalb des Beitrags-Editors klickst, kannst Du auswählen, wer diesen Beitrag sehen darf, indem Du einfach auf die Namen klickst. + +Diese Nachricht kann dann nur vom Absender und den eingestellten Empfängern betrachtet werden. Mit anderen Worten, sie erscheint nicht öffentlich auf einer Pinnwand. + +Solche Zugriffsrechte gibt es bei Beiträgen, Fotos, Terminen, Webseiten, Chat-Räumen und Dateien. + +[b]Ein Passwort für alle $Projectname-Server (Single Sign-on)[/b] + +Zugriffsrechte funktionieren in der gesamten $Projectname mit allen Kanälen. Die meisten Links, die innerhalb der $Projectname verlinken, enthalten deine Identität (zid), so dass der Zielserver Dich direkt anmelden kann. Du kannst Dich aber auch so auf jedem $Projectname-Server mit Deinem $Projectname-Identität anmelden und erhältst dann Zugriff auf die Inhalte, die für Dich freigegeben sind. + +Du loggst Dich nur einmal auf Deinem Heimatserver ein. Ab dann funktioniert die Authentifizierung gegenüber anderen $Projectname-Servern „magisch“ von selbst. + +[b]Dateiablage (Cloud) mit WebDAV-Zugriff[/b] + +Du kannst in Deinem persönlichen Speicherbereich Dateien hochladen und ihn sogar als Verzeichnis von Deinem lokalen Betriebssystem anzeigen lassen (via WebDAV). Die Dateien können über Zugriffsrechte bestimmten $Projectname-Mitgliedern (und den Mitgliedern mancher anderer Netze) zugänglich gemacht oder auch komplett öffentlich zur Verfügung gestellt werden. + +[b]Fotoalben[/b] + +Stelle Deine Fotos online in Alben zur Verfügung. Auch hier kann der Zugriff über die Zugriffsrechte eingeschränkt werden. + +[b]Terminkalender[/b] + +Im eingebauten Terminkalender kannst Du Termine erstellen und verwalten. Auch hier greifen die Zugriffsrechte für andere. Termine können im vcalendar/iCal-Format exportiert und mit anderen geteilt werden. Wenn Deine Kontakte ihren Geburtstag in ihr Profil eingetragen haben, werden diese Geburtstage automatisch zu Deinem Kalender hinzugefügt – mit entsprechender Anpassung der Zeitzone, so dass Du nie zu früh oder zu spät gratulierst. + +[b]Chat-Räume[/b] + +Du kannst Chaträume erstellen und über die Zugriffsrechte nur bestimmten Nutzern öffnen. Die Nachrichten sind sicherer verschlüsselt als es normalerweise bei Jabber/XMPP, IRC und anderen Instant Messengern üblich ist. Über Plugins ist es aber auch möglich, andere IM-Dienste aus der $Projectname heraus zu nutzen. + +[b]Erstellen von Webseiten[/b] + +In der $Projectname gibt es Werkzeuge für „Content Management“, mit denen Du einfache Webseiten erstellen kannst, aber auch komplexe Layouts, Menüs, Blöcke und Widgets. Auch hier greifen die Zugriffsrechte, so dass die entstandenen Seiten nur von denen betrachtet werden können, denen Du das Recht dazu eingeräumt hast. + +[b]Apps[/b] + +$Projectname-Mitglieder könnnen Apps erstellen und verteilen. Anders als bei anderen Systemen, bei denen man an den System-Anbieter gebunden ist, werden diese Apps komplett vom App-Anbieter kontrolliert, der auf Wunsch seine eigene Zugriffskontrolle und ein Bezahlsystem einbauen kann. Die meisten Apps in der $Projectname sind kostenlos. Sie sind sehr einfach und ohne große Programmierkenntnisse zu erstellen. + +[b]Layout[/b] + +Das Seiten-Layout basiert auf eine Beschreibungssprache namens Comanche. Die $Projectname ist selbst in Comanche-Layouts verfasst, die man verändern kann. Dadurch ist eine sehr starke Anpassung an die eigenen Bedürfnisse möglich, wie man sie so in Multi-User-Umgebungen normalerweise nicht findet. + +[b]Lesezeichen[/b] + +Du kannst Lesezeichen teilen, speichern und verwalten, direkt aus den Unterhaltungen mit anderen heraus. + +[b]Verschlüsselung privater Nachrichten[/b] + +Nachrichten mit eingeschränktem Empfängerkreis werden mit einem symmetrischen 256-bit-AES-CBC-Schlüssel verschlüsselt, der seinerseits mit Public-Key-Kryptografie auf Basis von 4096-bittigen RSA-Schlüsseln geschützt (nochmal verschlüsselt) wird, die mit dem sendenden Kanal verbunden sind. Diese Nachrichten werden auch auf anderen Red-Servern verschlüsselt gespeichert. + +Jeder Red-Kanal hat seinen eigenes 4096-bit-RSA-Schlüsselpaar, das erzeugt wird, wenn der Kanal erstellt wird. + +Zusätzlich können Nachrichten mit Ende-zu-Ende-Verschlüsselung versehen werden, so dass weder $Projectname-Server-Administratoren noch ISPs irgendetwas mitlesen können, solange sie nicht über das Passwort verfügen. + +Komplett öffentliche Nachrichten werden weder in der Datenbank noch bei der Übertragung verschlüsselt (abgesehen ggfs. von SSL). + +Private Nachrichten können gelöscht (zurückgezogen) werden, aber es kann natürlich nicht garantiert werden, dass der Empfänger sie nicht schon gelesen hat. + +Alle Nachrichten können mit einem „Verfallsdatum“ versehen werden. Zu diesem Zeitpunkt werden sie dann von den Servern der Empfänger gelöscht. + +[b]Verbindung zu anderen Diensten[/b] + +Neben Plugins, die das „crossposten“ zu diversen anderen Netzwerk erlauben, wird der Import von RSS/Atom-Feeds nativ unterstützt, auch, um mit diesen Inhalten spezielle Kanäle zu erstellen. Außerdem kann über das Diaspora-Protokoll mit Kontakten in den Netzwerken Friendica und Diaspora kommuniziert werden. Diese Unterstützung ist als experimentell eingestuft, da diese Netzwerke nicht die gleichen Möglichkeiten wie die $Projectname in Sachen Privatsphäre und Verschlüsselung bieten, so dass Kommunikation mit ihnen zu Privatsphäreproblemen führen könnte. + +Weiterhin wird OpenID auf experimenteller Ebene unterstützt und kann bei den Zugriffsrechten genutzt werden, um Inhalte für per OpenID authentifizierte Nutzer freizugeben. An dieser Funktion wird noch gearbeitet. + +Die Inhalte von Kanälen können als Quellen für andere Kanäle dienen (wenn der Kanalinhaber das erlaubt), so dass Themen-Kanäle mit den Inhalten von zwei oder mehr Kanälen erstellt werden können. + +[b]Sammlungen[/b] + +„Sammlungen“ sind unsere Implementation von Privatsphäregruppen, ähnlich den „Kreisen“ bei Google+ und den „Aspekten“ bei Diaspora. Sammlungen können zur Filterung der angezeigten Nachrichten genutzt werden (nur Threads anzeigen, die von einem Mitglied dieser Sammlung gestartet wurden), aber auch zum Setzen von Zugriffsrechten. + +[b]Verzeichnisdienste[/b] + +Wir stellen einfachen Zugriff auf ein Mitgliederverzeichnis zur Verfügung, samt einer dezentralen Möglichkeit, sich neue Kontakte basierend auf den eigenen vorschlagen zu lassen. Die Verzeichnis-Server sind normale $Projectname-Server, bei denen der Administrator sich entschieden hat, sie auch als Verzeichnis agieren zu lassen. Das benötigt mehr Ressourcen als eine normale $Projectname-Installation, deshalb ist das nicht voreingestellt. Die Verzeichnis-Server synchronisieren sich miteinander, so dass (abgesehen von einer gewissen Verzögerung bis zur nächsten Synchronisation) all Verzeichnis-Server aktuelle Informationen über das gesamte Netzwerk bereitstellen können. + +[b]TLS/SSL[/b] + +Red-Server, die TLS/SSL benutzen, verschlüsseln ihre Kommunikation vom Server zum Nutzer mit SSL. Nach den aktuellen Enthüllungen über das Umgehen von Verschlüsselung durch NSA, GHCQ und andere Dienste, sollte man jedoch nicht mehr davon ausgehen, dass diese Verbindungen nicht mitgelesen werden können. + +[b]Kanal-Einstellungen[/b] + +Wenn ein Kanal erstellt wird, muss eine bestimmte Zugriffsrechte-Kategorie (z.B. öffentliches Forum oder privater Kanal für soziales Netzwerken) ausgewählt werden, die dafür sorgt, dass sinnvolle Privatsphäre-Einstellungen für diese Art von Kanal ausgewählt werden. + +Wenn Du die Experten-Kategorie wählst, kannst Du detaillierte Zugriffseinstellungen für verschiedenste Aspekte der Kommunikation festlegen. Unter den „Sicherheits- und Privatsphäre-Einstellungen“ kann für jeden Punkt auf der linken Seite eine von 7-8 möglichen Optionen aus dem Menü gewählt werden. Daneben gibt es diverse weitere Einstellmöglichkeiten zum Thema Privatsphäre. + +[img]https://friendicared.net/photo/0f5be8da282858edd645b0a1a6626491.png[/img] + +Die Optionen für die einzelnen Punkte (z.B., wer Deine normalen Beiträge sehen kann) sind: +[ul][*]Niemand außer Du selbst +[*]Nur die, denen Du es explizit erlaubst +[*]Angenommene Verbindungen +[*]Beliebige Verbindungen +[*]Jeder auf diesem Website +[*]Alle Red-Nutzer +[*]Jeder authentifizierte +[*]Jeder im Internet[/ul] + +[b]Private und öffentliche Foren[/b] + +Foren sind Kanäle, in denen mehrere Nutzer als Autoren fungieren können; eine Nachricht eines entsprechend berechtigten Nutzers an das Forum wird an alle Foren-Mitglieder verteilt. Es gibt momentan zwei Arten, um auf diese Weise an ein Forum zu posten: 1) Direktes Posten auf der Kanal-Seite des Forums („wall-to-wall post“) oder 2) über @mention-Tags. Jeder kann Foren erstellen, und sie können für beliebige Zwecke genutzt werden. Das Kanal-Verzeichnis ermöglicht es, direkt nach öffentlichen Foren zu suchen. Private Foren können meist nur von den Mitgliedern beschickt und gelesen werden. + +[b]Klone[/b] + +Konten in der $Projectname werden auch als [i]nomadische Identitäten[/i] bezeichnet (eine ausführliche Erklärung dazu gibt es unter [url=[baseurl]/help/what_is_zot]What is Zot?[/url]). Nomadisch, weil bei anderen Diensten die Identität eines Nutzers an den Server oder die Plattform gebunden ist, auf der er ursprünglich erstellt wurde. Ein Facebook- oder Gmail-Konto ist and diese Dienste gekettet. Er funktioniert nicht ohne Facebook.com bzw. Gmail.com. + +Bei Red ist das anders. Sagen wir, Du hast eine Red-Indentität namens tina@redhub.com. Die kannst Du auf einen anderen Server klonen, mit dem gleichen oder einem anderen Namen, zum Beispiel lebtEwig@matrixserver.info. + +Beide Kanäle sind jetzt miteinander synchronisiert, das heißt, dass alle Kontakte und Einstellungen auf dem Klon immer die gleichen sind wie auf dem ursprünglichen Kanal. Es ist egal, ob Du eine Nachricht von dort aus oder vom Klon aus schickst. Alle Nachrichten sind in beiden Klonen vorhanden. + +Das ist ein ziemlich revolutionäres Feature, wenn man sich einige Szenarien dazu ansieht: + +[ul][*]Was passiert, wenn ein Server, auf dem sich Deine Identität befindet, plötzlich offline ist? Ohne Klone ist der Nutzer nicht in der Lage zu kommunzieren, bis der Server wieder online ist. Mit Klonen loggst Du Dich einfach bei Deinem geklonten Kanal ein und lebst glücklich bis an Dein Ende. +[*]Der Administrator Deines Red-Servers kann es sich nicht länger leisten, seinen für alle kostenlosen Server zu bezahlen. Er gibt bekannt, dass der Server in zwei Wochen vom Netz gehen wird. Zeit genug, um Deine Red-Kanäle auf andere Server zu klonen und somit Verbindungen und Freunde zu behalten. +[*]Was, wenn Dein Kanal staatlicher Zensur unterliegt? Dein Server-Admin wird gezwungen, Dein Konto und alle damit verbundenen Kanäle und Daten zu löschen. Durch Klone bietet die $Projectname Zensur-Resistenz. Wenn Du willst, kannst Du hunderte von Klonen haben, alle mit unterschiedlichen Namen und auf unterschiedlichen Servern überall im Internet.[/ul] + +Red bietet interessante, neue Möglichkeiten in Bezug auf die Privatsphäre. Mehr dazu unter „Tipps und Tricks zur privaten Kommunikation“. + +Klone unterliegen einigen Restriktionen. Eine vollständige Erklärung zum Klonen von Identitäten gibt es unter „Klone“. + +[b]Mehrere Profile[/b] + +Jeder Kanal kann beliebig viele Profile mit unterschiedlichen Informationen definieren. Dann kannst Du einstellen, wer von Deinen Kontakten welches Profil zu sehen bekommt. Das Default-Profil ist für alle anderen zu sehen und kann so auf nur wenige Informationen beschränkt werden, während Freunde und Bekannte mehr zu sehen bekommen. + +[b]Kanal-Backups[/b] + +In Red gibt es ein einfaches Ein-Klick-Backup, mit dem Du ein komplettes Backup Deiner Kanal-Einstellungen und Verbindungen herunterladen kannst. + +Solche Backups sind ein Weg, um Klone zu erstellen, und können genutzt werden, um einen Kanal wiederherzustellen. + +[b]Löschen von Konten[/b] + +Konten und Kanäle können sofort gelöscht werden, indem Du einfach auf einen Link klickst. Das wars. Alle damit verbundenen Inhalte werden aus der Matrix gelöscht (inklusiver aller Beiträge und sonstiger Inhalte, die von dem gelöschten Konto/Kanal erzeugt wurden). Je nach Anzahl Deiner Verbindungen kann es etwas dauern, bis die Inhalte auch von allen Servern Deiner Kontakte gelöscht werden, aber die Löschung wird so schnell wie sinnvoll möglich durchgeführt. + +[h2]Erstellen von Inhalten[/h2] + +[b]Beiträge schreiben[/b] + +Red unterstützt diverse verschiedene Wege, um Inhalte mit Auszeichnung (z.B. fett, kursiv, farbig etc.) zu erstellen. Voreinstellung ist die $Projectname-Variante von BBCode (wie in vielen Web-Foren) mit einigen Ergänzungen, die nur hier funktionieren. Du kannst auch Markdown benutzen, wenn Dir das leichter fällt. Bis vor kurzem konnte auch ein grafischer Editor eingesetzt werden, der jedoch große Probleme aufwies und deshalb entfernt wurde. Wir suchen gerade nach einer Alternative. + +Webseiten können neben BBCode und Markdown auch in HTML und Plain Text erstellt werden. + +[b]Inhalte löschen[/b] + +Alle Inhalte in der $Projectname bleiben unter der Kontrolle des Mitglieds (bzw. Kanals), der sie ursprünglich erstellt hat. Alle Beiträge können jederzeit gelöscht werden, egal, ob sie auf dem Heimat-Server des Nutzers oder auf einem anderen Server erstellt wurden, an dem der Nutzer via Zot angemeldet war. + +[b]Medien[/b] + +Genau wie jedes andere Blog-System, soziale Netzwerk oder Mikro-Blogging-Dienst unterstützt Red das Hochladen von Dateien, das Einbetten von Bildern und Videos und das Verlinken von Seiten. + +[b]Vorschau/Editieren[/b] + +Vor dem Absenden kann eine Vorschau von Beiträgen betrachtet werden. Außerdem können Beiträge auch nach dem Absenden noch verändert werden. + +[b]$Projectname erweitern[/b] + +Die $Projectname kann auf vielerlei Art erweitert werden: Durch Server-Anpassung, persönliche Anpassung, setzen von Optionen, Themes und Addons/Plugins. + +[b]API[/b] + +Es existiert eine API, die von beliebigen Programmen/Apps und Diensten genutzt werden kann. Sie basiert auf der ursprünglichen Twitter-API (für die es hunderte von Tools und Apps gibt). Sie wird aktuell erweitert, um Zugriff auf Möglichkeiten zu gewähren, die es nur in der $Projectname gibt. Authentifikation erfolgt über Login/Passwort oder OAuth. Eine Client-Registrierung für OAuth-Applikationen ist möglich. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/de/main.bb b/sources/doc/de/main.bb new file mode 100644 index 00000000..f310d0ab --- /dev/null +++ b/sources/doc/de/main.bb @@ -0,0 +1,86 @@ +[img][baseurl]/assets/hashlogo.png[/img] + +[zrl=[baseurl]/help/about]Was ist die RedMatrix?[/zrl] +Die RedMatrix ist eine dezentrale Kommunikations- und Publishing-Plattform. Sie ermöglicht Dir die volle Kontrolle über all Deine Kommunikation mit Hilfe von automatischer Verschlüsselung und detaillierter Zugriffskontrolle. Du, und [i]nur[/i] Du, entscheidest, wer Deine Beiträge sehen darf. + +[zrl=[baseurl]/help/features]Features der RedMatrix[/zrl] +Die RedMatrix funktioniert schon heute als ein globales verteiltes Netzwerk und beweist täglich ihre Vielseitigkeit und Skalierbarkeit auf kleinen Privatservern wie auch auf riesigen Sites. +Kommunikationsplattformen für Familien, verteilte Online-Communities, Support-Foren, Blogs und Homepages. Oder auch professionelle Inhalte-Anbieter mit kommerziellen Premium-Kanälen und eingeschränktem Zugriff – was immer Du willst, die RedMatrix unterstützt Dich in Deinem kreativen Schaffen. + +[zrl=[baseurl]/help/what_is_zot]Got Zot? Hast Du schon Zot? Wenn nicht wird es Zeit.[/zrl] +Zot ist das großartige neue Kommunikationsprotokoll, das extra für die RedMatrix entwickelt wurde. Als Mitglied bist Du dank „Nomadischer Identität“ nicht länger an einen einzigen Server oder Anbieter gebunden. Ziehe einfach auf einen anderen Server um und behalte dabei alle Deine Kontakte, oder klone Deinen Kanal und lasse ihn auf mehreren Servern gleichzeitig laufen – sollte einer davon plötzlich geschlossen werden, ist das kein Problem für Dich. Und bist Du erst Teil der RedMatrix, musst Du Dich nie wieder mehrfach anmelden, selbst wenn Du Seiten auf einem andere Red-Server betrachtest. Zot ist, was die RedMatrix besonders macht. + +[h3]Erste Schritte[/h3] +[zrl=[baseurl]/help/Privacy]Datenschutz[/zrl] +[zrl=[baseurl]/help/registration]Ein Konto registrieren[/zrl] +[zrl=[baseurl]/help/accounts_profiles_channels_basics]Du in der RedMatrix: Konten, Profile und Kanäle kurz erklärt[/zrl] +[zrl=[baseurl]/help/profiles]Profile[/zrl] +[zrl=[baseurl]/help/channels]Kanäle[/zrl] +[zrl=[baseurl]/help/roles]Zugriffsrechte-Kategorien und Kanaltypen[/zrl] +[zrl=[baseurl]/help/first-post]Dein erster Beitrag[/zrl] +[zrl=[baseurl]/help/connecting_to_channels]Sich mit anderen Kanälen verbinden[/zrl] +[zrl=[baseurl]/help/permissions]Zugriffsrechte und Verschlüsselung: Du hast alles unter Kontrolle[/zrl] +[zrl=[baseurl]/help/cloud]Cloud-Speicher[/zrl] +[zrl=[baseurl]/help/remove_account]Einen Kanal oder das ganze Konto löschen[/zrl] + +[h3]Hilfe für $Projectname-Mitglieder[/h3] +[zrl=[baseurl]/help/tags_and_mentions]Tags und Erwähnungen[/zrl] +[zrl=[baseurl]/help/webpages]Webseiten[/zrl] +[zrl=[baseurl]/help/bbcode]BBcode-Referenz für Posts und Kommentare[/zrl] +[zrl=[baseurl]/help/checking_account_quota_usage]Überprüfung der Kontenlimits[/zrl] +[zrl=[baseurl]/help/cloud_desktop_clients]Desktop-Anwendungen und die Cloud[/zrl] +[zrl=[baseurl]/help/AdvancedSearch]Fortgeschrittene Suche im Kanalverzeichnis[/zrl] +[zrl=[baseurl]/help/addons]Hilfe zu Addons[/zrl] +[zrl=[baseurl]/help/diaspora_compat]Kompatibilität zum Diaspora-Protokoll (zur Kommunikation mit Kontakten aus Diaspora und Friendica)[/zrl] +[zrl=[baseurl]/help/faq_members]FAQ für Mitglieder[/zrl] + +[h3]Hilfe für Administratoren[/h3] +[zrl=[baseurl]/help/install]Installation[/zrl] +[zrl=[baseurl]/help/red2pi]Red auf einem Raspberry Pi installieren[/zrl] +[zrl=[baseurl]/help/troubleshooting]Troubleshooting-Tipps[/zrl] +[zrl=[baseurl]/help/hidden_configs]Versteckte Konfigurations-Optionen[/zrl] +[zrl=[baseurl]/help/faq_admins]FAQ für Admins[/zrl] +[zrl=[baseurl]/help/service_classes]Serviceklassen[/zrl] + +[h3]Technische Dokumentation[/h3] +[zrl=[baseurl]/help/history]Die Geschichte von $Projectname[/zrl] +[zrl=[baseurl]/help/Zot---A-High-Level-Overview]Zot – ein grober Überblick[/zrl] +[zrl=[baseurl]/help/zot]Eine Einführung ins Zot-Protokoll[/zrl] +[zrl=[baseurl]/help/zot_structures]Zot-Strukturen[/zrl] +[zrl=[baseurl]/help/comanche]Seitenbeschreibung in Comanche[/zrl] +[zrl=[baseurl]/help/Creating-Templates]Vorlagen erstellen mit Comanche[/zrl] +[zrl=[baseurl]/help/Widgets]Widgets[/zrl] +[zrl=[baseurl]/help/plugins]Plugins[/zrl] +[zrl=[baseurl]/help/doco]Selbst Dokumentation beisteuern[/zrl] +[zrl=[baseurl]/help/DerivedTheme1]Einen Theme basierend auf einem anderen erstellen[/zrl] +[zrl=[baseurl]/help/schema_development]Schemata[/zrl] +[zrl=[baseurl]/help/Translations]Übersetzungen[/zrl] +[zrl=[baseurl]/help/developers]Entwickler[/zrl] +[zrl=[baseurl]/help/intro_for_developers]Einführung für Entwickler[/zrl] +[zrl=[baseurl]/help/database]Datenbank-Schema[/zrl] +[zrl=[baseurl]/help/api_functions]API-Funktionen[/zrl] +[zrl=[baseurl]/help/api_posting]Mit der API einen Beitrag erstellen[/zrl] +[zrl=[baseurl]/help/developer_function_primer]Übersicht der wichtigsten Red-Funktionen[/zrl] +[zrl=[baseurl]/doc/html/]Code-Referenz (mit doxygen generiert - setzt Cookies)[/zrl] +[zrl=[baseurl]/help/to_do_doco]To-Do-Liste für das Projekt Red-Dokumentation[/zrl] +[zrl=[baseurl]/help/to_do_code]To-Do-Liste für Entwickler[/zrl] +[zrl=[baseurl]/help/roadmap]Roadmap für Version 3[/zrl] +[zrl=[baseurl]/help/git_for_non_developers]Git für Nicht-Entwickler[/zrl] +[zrl=[baseurl]/help/dev_beginner]Schritt-für-Schritt-Einführung für neue Entwickler[/zrl] + +[h3]Häufig gestellte Fragen für Entwickler[/h3] +[zrl=[baseurl]/help/faq_developers]FAQ für Entwickler[/zrl] + +[h3]Externe Ressourcen[/h3] +[zrl=[baseurl]/help/external-resource-links]Links zu externen Ressourcen[/zrl] +[url=https://github.com/redmatrix/redmatrix]Haupt-Website[/url] +[url=https://github.com/redmatrix/redmatrix-addons]Addons-Website[/url] +[url=https://zothub.com/channel/one]Entwickler-Kanal[/url] +[url=https://federated.social/channel/postgres]Postgres-spezifischer Admin-Support-Kanal[/url] + +[url=[baseurl]/help/credits]$Projectname Credits[/url] + +[h3]Über diesen Red-Server[/h3] +[zrl=[baseurl]/help/TermsOfService]Nutzungsbedingungen dieses Red-Servers[/zrl] +[zrl=[baseurl]/siteinfo]Informationen zu diesem Server und der Red-Version[/zrl] +[zrl=[baseurl]/siteinfo/json]Detaillierte technische Informationen zu diesem Server im JSON-Format[/zrl] diff --git a/sources/doc/de/profiles.bb b/sources/doc/de/profiles.bb new file mode 100644 index 00000000..262aeb6e --- /dev/null +++ b/sources/doc/de/profiles.bb @@ -0,0 +1,40 @@ +[size=large][b]Profile[/b][/size] + +In Red kannst Du beliebig viele Profile anlegen. Du kannst mehrere Profile nutzen, um verschiedenen Kontakten und Profilbesuchern unterschiedliche Seiten Deiner Persönlichkeit zu zeigen. Das ist nicht das gleiche wie das Anlegen mehrerer [i]Kanäle.[/i] + +Mehrere Kanäle erlauben es, komplett voneinander getrennte Informationen zu verwalten. Du könntest zum Beispiel einen Kanal für Dich selbst anlegen, einen für Deinen Schwimmverein, einen für Dein Blog und so weiter und so fort. + +Ein Profil erlaubt es, unterschiedlichen Leuten unterschiedliche Informationen über einen Kanal zu präsentieren. Beispiel: In Deinem Standard-Profil, das alle Profilbesucher zu sehen bekommen, könnte nur Dein Vorname stehen, sonst keine weiteren Informationen. Freunde und Bekannte könnten Deinen kompletten Realnamen und Deine Postadresse zu sehen bekommen, und im Profil für Deinen engsten Freundeskreis könnten peinliche Hobbies und Trinkrekorde ihren Platz finden. + +Jeder Kanal hat ein Standard-Profil (öffentliches Profil), das vor niemandem versteckt werden kann (außer evtl. auf privaten Servern, die nicht mit der Matrix verbunden sind). Du kannst und solltest Dich in der Auswahl dessen, was Du im Standard-Profil von Dir preisgibst, stark einschränken. + +Trotzdem: Wenn Du willst, dass Freunde Dich finden können, macht es Sinn, folgende Informationen ins öffentliche Profil einzutragen: + +[ul][*] Deinen Realnamen oder zumindest einen Spitznamen, unter dem Dich jeder kennt +[*] Ein Foto, das auch wirklich Dich zeigt +[*] Deinen Wohnort, oder zumindest Land oder Bundesland[/ul] + +Wenn Du Leute kennenlernen möchtest, die ähnliche Interessen haben wie Du, nimm Dir einen Moment Zeit und füge einige Schlüsselwörter hinzu. Zum Beispiel „Musik, Linux, Fotografie“ oder was auch immer. Danach können andere dann im Verzeichnis suchen. Du kannst so viele Schlüsselwörter eingeben wie Du möchtest. + +Um alternative Profile zu erstellen, besuche zunächst die Seite [zrl=[baseurl]/settings/features]Einstellungen > Zusätzliche Funktionen[/zrl] und aktiviere dort „Mehrfachprofile“. Ohne diese Aktivierung hast Du nur ein Profil, nämlich Dein Standard-Profil. + +Klicke dann auf „Profile bearbeiten“ im Menü Deines Red-Servers. Dort kannst Du existierende Profile bearbeiten, Dein Profilfoto verändern, Dinge zu einem Profil hinzufügen oder ein neues Profil erstellen. Du kannst auch ein Profil „klonen“, wenn Du nur einige wenige Einträge ändern willst, ohne die ganzen Informationen noch einmal einzugeben. Klicke dazu auf das Profil, das Du klonen willst, und wähle dann „Dieses Profil klonen“. + +In der Liste Deiner Profile kannst Du auch bestimmen, wer ein bestimmtes Profil zu sehen bekommt. Klicke dazu auf „Sichtbarkeit bearbeiten“ neben dem Profil, um das es geht (gibt es nur bei Profilen, die nicht Dein Standard-Profil sind). Klicke dann auf die Bilder derjenigen Kontakte, die dieses Profil sehen sollen – sie sind dann oben zu sehen. Wenn Du oben auf ein Bild klickst, wird dieser Kontakt wieder aus der Gruppe derjenigen herausgenommen, die dieses Profil zu sehen bekommen. + +Hast Du einem Kontakt ein Profil zugeordnet, wird er immer dieses Profil sehen, wenn er sich Dein Profil ansieht. Besucht er Deinen Red-Server, ohne sich anzumelden, sieht er aber weiterhin Dein Standard-Profil. + +Auf der allgemeinen „Einstellungen“-Seite gibt es eine Einstellung, mit der Du festlegen kannst, ob Dein Standard-Profil in den Red-Verzeichnissen veröffentlicht werden soll. + +Wenn Du nicht möchtest, dass andere Dich finden können, ohne dass Du ihnen Deine Kanal-Adresse gibst, kannst Du so verhindern, dass Dein Profil veröffentlicht wird. + +[b]Schlüsselwörter und Verzeichnissuche[/b] + +Im Verzeichnis (Kanal-Anzeiger) kannst Du nach Leuten suchen, die ihre Profile veröffentlichen. Zum Beispiel, indem Du Namen oder Spitznamen eingibst. Aktuell werden nur das Namensfeld und die Schlüsselwörter durchsucht. Wenn Du Schlüsselwörter in Dein Standard-Profil einträgst, können Dich Leute mit ähnlichen Interessen finden. Sie werden außerdem bei den Kanal-Vorschlägen benutzt. Sie sind im Verzeichnis nicht direkt sichtbar, wohl aber auf Deiner Profil-Seite. + +Auf Deiner „Verbindungen“-Seite und im Verzeichnis (Kanal-Anzeiger) gibt es einen Link „Vorschläge“ bzw. „Kanal-Vorschläge“. Dort findest Du Kanäle, die gleiche oder ähnliche Schlüsselwörter im Profil haben wie Du. Je mehr Schlüsselwörter Du in Dein Standard-Profil einträgst, desto besser werden die Suchergebnisse. Sie sind nach Relevanz sortiert. + +Siehe auch: + +[zrl=[baseurl]/help/AdvancedSearch]Fortgeschrittene Suche[/zrl] +#include doc/macros/main_footer.bb; diff --git a/sources/doc/de/registration.bb b/sources/doc/de/registration.bb new file mode 100644 index 00000000..ebd18735 --- /dev/null +++ b/sources/doc/de/registration.bb @@ -0,0 +1,36 @@ +[size=large][b]Registrieren[/b][/size] + +Nicht alle Server in der Red-Matrix erlauben jedem, sich zu registrieren. Wenn eine Registrierung möglich ist, erscheint unter dem Anmelde-Formular ein Link mit dem Titel „Registrieren“, der Dich zur Registrierungs-Seite des Servers führt. Auf manchen Servern wirst Du auf einen anderen Server weitergeleitet, der Registrierungen erlaubt. Da alle Red-Server miteinander verbunden sind, ist es egal, auf welchem Du Dich registrierst. + +[b]Deine E-Mail-Adresse[/b] + +Bitte gib eine funktionierende E-Mail-Adresse an. Sie wird [b]nie[/b] veröffentlicht. Sie wird benutzt, um Dein Konto zu aktivieren, und wenn Du willst, kannst Du Dir an diese Adresse Benachrichtigungen schicken lassen, wenn Du neue Nachrichten oder Beiträge erhalten hast. Sie wird außerdem benutzt, um vergessene Passwörter wiederherstellen zu können. + +[b]Passwort[/b] + +Gib ein Passwort Deiner Wahl ein und wiederhole es in der zweiten Box, um sicherzugehen, dass Du Dich nicht vertippt hast. Da die Red-Matrix dezentralisierten Identitäsnachweis beherrscht, kannst Du Dich mit Deinem Konto auf vielen anderen Webseiten anmelden. + +[b]Nutzungsbedingungen[/b] + +Klicke auf den Link, um die [zrl=[baseurl]/help/TermsOfService]Nutzungsbedingungen[/zrl] dieses Servers zu lesen. Wenn Du sie gelesen hast, setze den Haken im Registrierungsformular, um sie zu akzeptieren. + +[b]Registrieren[/b] + +Wenn Du alles ausgefüllt hast, klicke auf den „Registrieren“-Knopf. Bei manchen Servern muss der Administrator Deiner Registrierung erst noch zustimmen, bevor Du Dein Konto nutzen kannst. Falls das der Fall ist, wird Dir das entsprechend angezeigt. Du erhältst dann eine E-Mail, wenn die Registrierung vollendet wurde. (Sicherheitshalber auch Spam-Ordner überprüfen!) + +[b]Einen Kanal anlegen[/b] + +Als nächstes kommst Du direkt auf den „Kanal hinzufügen“-Bildschirm. Dein erster Kanal wird normalerweise der sein, der Dich selbst repräsentiert. Es ist also sinnvoll, Deinen Namen oder Dein Pseudonym als Kanal-Namen zu verwenden. + +Der Kanal-Name ist der Titel oder eine kurze Beschreibung des Kanals. Der „Spitzname“ ist so etwas wie ein Benutzername. Was Du hier eingibst wird Teil Deiner Kanal-Adresse, die Andere benutzen, um sich mit Dir zu verbinden, und die Du selbst benutzt, um Dich auf anderen Servern anzumelden. Die Kanal-Adresse sieht aus wie eine E-Mail-Adresse, zum Beispiel so: spitzname@deinserver.xyz + +Wenn Dein Kanal angelegt ist, geht es direkt weiter zu den Einstellungen. Dort kannst Du Zugriffsrechte setzen, Funktionen zu- oder abschalten und so weiter. Diese Punkte werden auf den entsprechenden Hilfeseiten erklärt. + +Siehe auch +[zrl=[baseurl]/help/accounts_profiles_channels_basics]Grundlagen zu Identitäten in der $Projectname[/zrl] +[zrl=[baseurl]/help/accounts]Konten[/zrl] +[zrl=[baseurl]/help/profiles]Profile[/zrl] +[zrl=[baseurl]/help/permissions]Zugriffsrechte[/zrl] +[zrl=[baseurl]/help/remove_account]Konto löschen[/zrl] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/dev-function-overview.md b/sources/doc/dev-function-overview.md new file mode 100644 index 00000000..e228268d --- /dev/null +++ b/sources/doc/dev-function-overview.md @@ -0,0 +1,51 @@ +Red development - some useful basic functions +============================================= + + + +* get_account_id() + +Returns numeric account_id if authenticated or 0. It is possible to be authenticated and not connected to a channel. + +* local_channel() + +Returns authenticated numeric channel_id if authenticated and connected to a channel or 0. Sometimes referred to as $uid in the code. + +* remote_channel() + +Returns authenticated string hash of Red global identifier, if authenticated via remote auth, or an empty string. + +* get_app() + +Returns the global app structure ($a). + +* App::get_observer() + +(App:: is usually assigned to the global $a), so $a->get_observer() or get_app()->get_observer() - returns an xchan structure representing the current viewer if authenticated (locally or remotely). + +* get_config($family,$key), get_pconfig($uid,$family,$key) + +Returns the config setting for $family and $key or false if unset. + +* set_config($family,$key,$value), set_pconfig($uid,$family,$key,$value) + +Sets the value of config setting for $family and $key to $value. Returns $value. The config versions operate on system-wide settings. The pconfig versions get/set the values for a specific integer uid (channel_id). + +* dbesc() + +Always escape strings being used in DB queries. This function returns the escaped string. Integer DB parameters should all be proven integers by wrapping with intval() + +* q($sql,$var1...) + +Perform a DB query with the SQL statement $sql. printf style arguments %s and %d are replaced with variable arguments, which should each be appropriately dbesc() or intval(). SELECT queries return an array of results or false if SQL or DB error. Other queries return true if the command was successful or false if it wasn't. + +* t($string) + +Returns the translated variant of $string for the current language or $string (default 'en' language) if the language is unrecognised or a translated version of the string does not exist. + +* x($var), $x($array,$key) + +Shorthand test to see if variable $var is set and is not empty. Tests vary by type. Returns false if $var or $key is not set. +If variable is set, returns 1 if has 'non-zero' value, otherwise returns 0. -- e.g. x('') or x(0) returns 0; + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/dev_beginner.bb b/sources/doc/dev_beginner.bb new file mode 100644 index 00000000..72962571 --- /dev/null +++ b/sources/doc/dev_beginner.bb @@ -0,0 +1,419 @@ +[h2]You want to contribute code?[/h2] +[b]...and don't know how to start to...[/b] +[list] +[*] debug the red#matrix (php on the webserver), +[*] contribute code to the project, +[*] optionally - do it all from inside a virtual machine +[/list] +This manual was tested for Debian (Wheezy) as virtual machine on Lubuntu (Ubuntu 14.0) as host. + +Content + +[toc] + +[h2]Install a Virtual Machine (KVM)[/h2] + +[url=https://wiki.debian.org/KVM]Here[/url] the installation guide for Linux Debian. +The summary: +[list=1] +[*] install KVM +[code]# apt-get install qemu-kvm libvirt-bin[/code] +[*] add yourself to the group libvirt [code]# adduser libvirt[/code] +[*] install gui to manage virtual machines [code]# apt-get install virt-manager[/code] +[*] download an operating system to run inside the vm ([url=http://ftp.nl.debian.org/debian/dists/wheezy/main/installer-amd64/current/images/netboot/mini.iso]mini.iso[/url]) +[*] start the virt manager +- create new virtual machine (click on icon) +- choose your iso image (just downloaded) as installation source +- optional: configure the new vm: ram, cpu's,... +- start virtual machine > result: linux debian starts in a new window. +[*] (optional) avoid network errors after restart of host os +[code]# virsh net-start default +# virsh net-autostart default[/code] +[/list] + + +[h2]Install Apache Webserver[/h2] + +Open a terminal and make yourself root +[code]su -l[/code] + +Create the standard group for the Apache webserver +[code]groupadd www-data[/code] +might exist already + +[code]usermod -a -G www-data www-data[/code] + +Check if the system is really up to date +[code]apt-get update +apt-get upgrade[/code] + +Optional restart services after installation +[code]reboot[/code] + +If you restarted, make yourself root +[code]su -l[/code] + +Install Apache: [code] +apt-get install apache2 apache2-doc apache2-utils[/code] + +Open webbrowser on PC and check [url=localhost]localhost[/url] +Should show you a page like "It works" + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[h2]Install PHP, MySQL, phpMyAdmin[/h2] + +[h3]PHP, MySQL[/h3] + +[code]su -l +apt-get install libapache2-mod-php5 php5 php-pear php5-xcache php5-curl php5-mcrypt php5-xdebug +apt-get install php5-mysql +apt-get install mysql-server mysql-client[/code] +enter and note the mysql passwort + +Optional since its already enabled during phpmyadmin setup +[code] +php5enmod mcrypt +[/code] + +[h3]phpMyAdmin[/h3] + +Install php myadmin +[code]apt-get install phpmyadmin[/code] + +Configuring phpmyadmin +- Select apache2 (hint: use the tab key to select) +- Configure database for phpmyadmin with dbconfig-common?: Choose Yes + +(Source #^[url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + +[h3]Enable rewrite[/h3] + +The default installation of Apache2 comes with mod_rewrite installed. To check whether this is the case, verify the existence of /etc/apache2/mods-available/rewrite.load + +[code] +root@debian /var/www $ nano /etc/apache2/mods-available/rewrite.load +[/code] + + (You should find the content: LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so) +To enable and load mod_rewrite, do the rest of steps. +Create a symbolic link in /etc/apache2/mods-enabled + +[code] +cd /var/www +root@debian /var/www $ a2enmod rewrite +[/code] + +Then open up the following file, and replace every occurrence of "AllowOverride None" with "AllowOverride all". + +[code] +root@debian /var/www $nano /etc/apache2/apache2.conf +[/code] +or +[code] +root@debian:/var# gedit /etc/apache2/sites-enabled/000-default +[/code] + +Finally, restart Apache2. + +[code] +root@debian /var/www $service apache2 restart +[/code] + +[h3]Test installation[/h3] + +[code]cd /var/www[/code] + +create a php file to test the php installation[code]nano phpinfo.php[/code] + +Insert into the file: +[code] + +[/code] +(save CTRL+0, ENTER, CTRL+X) + +open webbrowser on PC and try #^[url=http://localhost/phpinfo.php]http://localhost/phpinfo.php[/url] (page shows infos on php) + +connect phpMyAdmin with MySQL database [code]nano /etc/apache2/apache2.conf +[/code] +- CTRL+V... to the end of the file +- Insert at the end of the file: (save CTRL+0, ENTER, CTRL+X)[code]Include /etc/phpmyadmin/apache.conf[/code] + +restart apache +[code]/etc/init.d/apache2 restart +apt-get update +apt-get upgrade +reboot[/code] + +[b]phpMyAdmin[/b] + +open webbrowser on PC and try #^[url=http://localhost/phpmyadmin]http://localhost/phpmyadmin[/url] + +(Source #^[url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + +[h3]Create an empty database... that is later used by the red#matrix[/h3] + + +open webbrowser on PC and try #^[url=http://localhost/phpmyadmin]http://localhost/phpmyadmin[/url] + +Create an empty database, for example named "red". +Create a database user, for example "red". +Grant all rights for the user "red" to the database "red". + +Note the access details (hostname, username, password, database name). + + +[h2]Fork the project on github[/h2] + +Please follow the instruction in the offiical [url=http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project] documentation[/url] of git. +It is a good idea to read the whole manual! Git is different to other version control systems in many ways. + +Now you should +[list] +[*] create an account at github.com +[*] fork https://github.com/redmatrix/hubzilla +[*] fork https://github.com/redmatrix/hubzilla-addons +[/list] + +If you not want to use GIT from the command line - there is a usefull Eclipse plugin named ""Eclipse Mylyn to GitHub connector". + + +[h2]Install RED and its Addons[/h2] + +[h3]Git at your computer / vm[/h3] + +You should have created an account on github and forked the projects befor you procceed. + +Delete the directory www +[code]root@debian:/var# rm -R www/ +[/code] + +Install git (and optionally git-gui a client gui) +[code]apt-get install git git-gui[/code] + +[h3]Download red#matri and addons[/h3] + +Download the main project red and red-addons +[code] +root@debian:/var# git clone https://github.com/yourname/red www +root@debian:/var# cd www/ +root@debian:/var/www# git clone https://github.com/yourname/red-addons addon +[/code] + +Make this extra folder +[code] +root@debian:/var/www# mkdir -p "store/[data]/smarty3" +[/code] + +Create .htconfig.php and make it writable by the webserver +[code] +root@debian:/var/www# touch .htconfig.php +root@debian:/var/www# chmod ou+w .htconfig.php +[/code] + +Make user www-data (webserver) is the owner all the project files +[code] +root@debian:/var/www# cd .. +root@debian:/var# chown -R www-data:www-data www/ +[/code] + +Add yourself ("surfer" in this example) to the group www-data. Why? Later you want to modify files in eclipse or in another editor. +Then make all files writable by the group www-date you are now a member of. +[code] +root@debian:/var# cd www/ +root@debian:/var/www# usermod -G www-data surfer +root@debian:/var# chmod -R g+w www/ +[/code] + +Restart the computer (or vm) +If you are still not able to modify the project files you can check the members of the group www-data with +[code] +cat /etc/group +[/code] + +[h3]Register yourself as admin[/h3] + +Open http://localhost and init the matrix + +Befor you register a first user switch off the registration mails. +Open /var/www/.htconfig.php +and make sure "0" is set in this line +[code] +$a->config['system']['verify_email'] = 0; +[/code] +You should be able to change the file as "yourself" (instead of using root or www-data). + +[h3]Cron and the poller[/h3] + +Important! +Run the poller to pick up the recent "public" postings of your friends +Set up a cron job or scheduled task to run the poller once every 5-10 +minutes to pick up the recent "public" postings of your friends + +[code] +crontab -e +[/code] + +Add +[code] +*/10 * * * * cd /var/www/; /usr/bin/php include/poller.php +[/code] + +If you don't know the path to PHP type +[code] +whereis php +[/code] + + +[h2]Debug the server via eclipse[/h2] + +[h3]Check the configuration of xdebug[/h3] + +You shoud already have installed xdebug in the steps befor +[code] +apt-get install php5-xdebug +[/code] + +Configuring Xdebug + +Open your terminal and type as root (su -l) +[code] +gedit /etc/php5/mods-available/xdebug.ini +[/code] + +if the file is empty try this location +[code] +gedit /etc/php5/conf.d/xdebug.ini +[/code] + +That command should open the text editor gedit with the Xdebug configuration file +At the end of the file content append the following text + +xdebug.remote_enable=on +xdebug.remote_handler=dbgp +xdebug.remote_host=localhost +xdebug.remote_port=9000 + +Save changes and close the editor. +In you terminal type to restart the web server. +[code] +service apache2 restart +[/code] + + +[h3]Install Eclipse and start debugging[/h3] + +Install eclipse. +Start eclipse with default worspace (or as you like) + +Install the PHP plugin +Menu > Help > Install new software... +Install "PHP Developnent Tools ..." + +Optionally - Install the GitHub connector plugin +Menu > Help > Install new software... +Install "Eclipse Mylyn to GitHub connector" + +Configure the PHP plugin +Menu > Window > Preferences... +> General > Webbrowser > Change to "Use external web browser" +> PHP > Debug > Debug Settings > PHP Debugger > Change to "XDebug" + +Create a new PHP project +Menu > File > New Project > Choose PHP > "PHP Project" +> Choose Create project at existing location" and "/var/www" + +Start debugging +Open index.php and "Debug as..." +Choose as Launch URL: "http://localhost/" + +Expected: +[list] +[*] The web browser starts +[*] The debugger will stop at the first php line +[/list] + + +[h2]Contribute your changes via github[/h2] + +[h3]Preparations[/h3] + +There is a related page in this docs: [zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl]. +As stated befor it is recommended to read the official documentation [url=http://git-scm.com/book/en/v2/GitHub-Contributing-to-a-Project]GitHub-Contributing-to-a-Project[/url] of git. + +Eclipse has a usefull plugin for GIT: "Eclipse Mylyn to GitHub connector". + +Make sure you have set your data +[code] +surfer@debian:/var/www$ git config --global user.name "Your Name" +surfer@debian:/var/www$ git config --global user.email "your@mail.com" +[/code] + +[h3]Your first contribution[/h3] + +Create a descriptive topic branch +[code] +surfer@debian:/var/www$ git checkout -b dev_beginning +[/code] + +Make sure your local repository is up-to-date with the main project. +Add the original repository as a remote named “upstream†if not done yet +[code] +surfer@debian:/var/www$ git remote add upstream https://github.com/redmatrix/hubzilla +[/code] + +Fetch the newest work from that remote +[code] +surfer@debian:/var/www$ git fetch upstream +surfer@debian:/var/www$ git merge upstream/master +[/code] + +Hint: You can list the branches +[code] +surfer@debian:/var/www$ git branch -v +[/code] + +Make your changes. In this example it is a new doc file. + +Check your modifications +[code] +surfer@debian:/var/www$ git status +[/code] + +Add (stage) the new file +[code] +surfer@debian:/var/www$ git add doc/dev_beginner.bb +[/code] + +Commit the changes to your local branch. This will open an editor to provide a message. +[code] +surfer@debian:/var/www$ git commit -a +[/code] + +Push back up to the same topic branch online +[code] +surfer@debian:/var/www$ git push +[/code] + +Now you can go to your (online) account at github and create the pull request. + +[h3]Following contributions[/h3] + +In case the main devolpers want you to change something. +Fetch the newest work from the remote upstream/master to be sure you have the latest changes. +[code] +surfer@debian:/var/www$ git fetch upstream +surfer@debian:/var/www$ git merge upstream/master +[/code] +Make your changes, test them, commit (to local repository), push (to online repository) +[code] +surfer@debian:/var/www$ git status +surfer@debian:/var/www$ git commit -a -m "added modification of branch" +surfer@debian:/var/www$ git push +[/code] + + +#include doc/macros/main_footer.bb; \ No newline at end of file diff --git a/sources/doc/developer_function_primer.bb b/sources/doc/developer_function_primer.bb new file mode 100644 index 00000000..37345444 --- /dev/null +++ b/sources/doc/developer_function_primer.bb @@ -0,0 +1,47 @@ +[b]Red development - some useful basic functions[/b] + +[b]get_account_id()[/b] + +Returns numeric account_id if authenticated or 0. It is possible to be authenticated and not connected to a channel. + +[b]local_channel()[/b] + +Returns authenticated numeric channel_id if authenticated and connected to a channel or 0. Sometimes referred to as $uid in the code. + +[b]remote_channel()[/b] + +Returns authenticated string hash of Red global identifier, if authenticated via remote auth, or an empty string. + +[b]get_app()[/b] + +Returns the global app structure ($a). + +[b]App::get_observer()[/b] + +(App:: is usually assigned to the global $a), so $a->get_observer() or get_app()->get_observer() - returns an xchan structure representing the current viewer if authenticated (locally or remotely). + +[b]get_config($family,$key), get_pconfig($uid,$family,$key), get_xconfig($xchan_hash,$family,$key)[/b] + +Returns the config setting for $family and $key or false if unset. + +[b] set_config($family,$key,$value), set_pconfig($uid,$family,$key,$value)[/b] + +Sets the value of config setting for $family and $key to $value. Returns $value. The config versions operate on system-wide settings. The pconfig versions get/set the values for a specific integer uid (channel_id). The xconfig version get/sets the value for a specific xchan hash - generally used for remote users. + +[b]dbesc()[/b] + +Always escape strings being used in DB queries. This function returns the escaped string. Integer DB parameters should all be proven integers by wrapping with intval() + +[b]q($sql,$var1...)[/b] + +Perform a DB query with the SQL statement $sql. printf style arguments %s and %d are replaced with variable arguments, which should each be appropriately dbesc() or intval(). SELECT queries return an array of results or false if SQL or DB error. Other queries return true if the command was successful or false if it wasn't. + +[b]t($string)[/b] + +Returns the translated variant of $string for the current language or $string (default 'en' language) if the language is unrecognised or a translated version of the string does not exist. + +[b]x($var), $x($array,$key)[/b] + +Shorthand test to see if variable $var is set and is not empty. Tests vary by type. Returns false if $var or $key is not set. If variable is set, returns 1 if has 'non-zero' value, otherwise returns 0. -- e.g. x('') or x(0) returns 0; + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/developers.bb b/sources/doc/developers.bb new file mode 100644 index 00000000..e9dddc69 --- /dev/null +++ b/sources/doc/developers.bb @@ -0,0 +1,70 @@ +[b]$Projectname Developer Guide[/b] + +We're pretty relaxed when it comes to developers. We don't have a lot of rules. Some of us are over-worked and if you want to help we're happy to let you help. That said, attention to a few guidelines will make the process smoother and make it easier to work together. We have developers from across the globe with different abilities and different cultural backgrounds and different levels of patience. Our primary rule is to respect others. Sometimes this is hard and sometimes we have very different opinions of how things should work, but if everybody makes an effort, we'll get along just fine. + +[b]Here is how you can join us.[/b] + +First, get yourself a working git package on the system where you will be +doing development. + +Create your own github account. + +You may fork/clone the Red repository from [url=https://github.com/redmatrix/hubzilla.git]https://github.com/redmatrix/hubzilla.git[/url] + +Follow the instructions provided here: [url=http://help.github.com/fork-a-repo/]http://help.github.com/fork-a-repo/[/url] +to create and use your own tracking fork on github + +Then go to your github page and create a "Pull request" when you are ready +to notify us to merge your work. + +[b]Translations[/b] + +Our translations are managed through Transifex. If you wish to help out translating the $Projectname to another language, sign up on transifex.com, visit [url=https://www.transifex.com/projects/p/red-matrix/]https://www.transifex.com/projects/p/red-matrix/[/url] and request to join one of the existing language teams or create a new one. Notify one of the core developers when you have a translation update which requires merging, or ask about merging it yourself if you're comfortable with git and PHP. We have a string file called 'messages.po' which is gettext compliant and a handful of email templates, and from there we automatically generate the application's language files. + +[zrl=[baseurl]/help/Translations]Translations - More Info[/zrl] + +[b]Important[/b] + +Please pull in any changes from the project repository and merge them with your work **before** issuing a pull request. We reserve the right to reject any patch which results in a large number of merge conflicts. This is especially true in the case of language translations - where we may not be able to understand the subtle differences between conflicting versions. + +Also - **test your changes**. Don't assume that a simple fix won't break something else. If possible get an experienced Red developer to review the code. + +Further documentation can be found at the Github wiki pages at: [url=https://github.com/friendica/red/wiki]https://github.com/friendica/red/wiki[/url] + +[b]Licensing[/b] + +All code contributed to the project falls under the MIT license, unless otherwise specified. We will accept third-party code which falls under MIT, BSD and LGPL, but copyleft licensing (GPL, and AGPL) is only permitted in addons. It must be possible to completely remove the GPL (copyleft) code from the main project without breaking anything. + +[b]Concensus Building[/b] + +Code changes which fix an obvious bug are pretty straight-forward. For instance if you click "Save" and the thing you're trying to save isn't saved, it's fairly obvious what the intended behaviour should be. Often when developing feature requests, it may affect large numbers of community members and it's possible that other members of the community won't agree with the need for the feature, or with your proposed implementation. They may not see something as a bug or a desirable feature. + +We encourage consensus building within the community when it comes to any feature which might be considered controversial or where there isn't unanimous decision that the proposed feature is the correct way to accomplish the task. The first place to pitch your ideas is to [url=https://zothub.com/channel/one]Channel One[/url]. Others may have some input or be able to point out facets of your concept which might be problematic in our environment. But also, you may encounter opposition to your plan. This doesn't mean you should stop and/or ignore the feature. Listen to the concerns of others and try and work through any implementation issues. + +There are places where opposition cannot be resolved. In these cases, please consider making your feature [b]optional[/b] or non-default behaviour that must be specifically enabled. This technique can often be used when a feature has significant but less than unanimous support. Those who desire the feature can turn it on and those who don't want it - will leave it turned off. + +If a feature uses other networks or websites and or is only seen as desirable by a small minority of the community, consider making the functionality available via an addon or plugin. Once again, those who don't desire the feature won't need to install it. Plugins are relatively easy to create and "hooks" can be easily added or modified if the current hooks do not do what is needed to allow your plugin to work. + + +[b]Coding Style[/b] + +In the interests of consistency we adopt the following code styling. We may accept patches using other styles, but where possible please try to provide a consistent code style. We aren't going to argue or debate the merits of this style, and it is irrelevant what project 'xyz' uses. This is not project 'xyz'. This is a baseline to try and keep the code readable now and in the future. + +[li] All comments should be in English.[/li] + +[li] We use doxygen to generate documentation. This hasn't been consistently applied, but learning it and using it are highly encouraged.[/li] + +[li] Indentation is accomplished primarily with tabs using a tab-width of 4.[/li] + +[li] String concatenation and operators should be separated by whitespace. e.g. "$foo = $bar . 'abc';" instead of "$foo=$bar.'abc';"[/li] + +[li] Generally speaking, we use single quotes for string variables and double quotes for SQL statements. "Here documents" should be avoided. Sometimes using double quoted strings with variable replacement is the most efficient means of creating the string. In most cases, you should be using single quotes.[/li] + +[li] Use whitespace liberally to enhance readability. When creating arrays with many elements, we will often set one key/value pair per line, indented from the parent line appropriately. Lining up the assignment operators takes a bit more work, but also increases readability.[/li] + +[li] Generally speaking, opening braces go on the same line as the thing which opens the brace. They are the last character on the line. Closing braces are on a line by themselves. [/li] + +[b]See Also[/b] +[zrl=[baseurl]/help/sql_conventions]SQL Conventions[/zrl] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/diaspora_compat.md b/sources/doc/diaspora_compat.md new file mode 100644 index 00000000..255b565a --- /dev/null +++ b/sources/doc/diaspora_compat.md @@ -0,0 +1,60 @@ +##Diaspora Compatibility + +Diaspora protocol compatibility is presently considered an ***experimental*** feature. It may not be available on all sites and presents some serious compatibility issues with hubzilla. At the moment these compatibility issues will be shared with "Friendica-over-Diaspora" protocol communications. + +Private mail retraction (unsend) will not be possible on Diaspora. + +Private posts and their associated comments are sent in plaintext email notifications in Diaspora and Friendica. This is a major privacy issue and affects any private communications you have where *any* member of the conversation is on another network. Be aware of it. + +Access control only works on posts and comments. Diaspora members will get permission denied trying to access any other access controlled hubzilla objects such as files, photos, webpages, chatrooms, etc. In the case of private photos that are linked to posts, they will see a "prohibited sign" instead of the photo. Diaspora has no concept of private media. There is no workaround except to make your media resources public (to everybody on the internet). + + +Edited posts will not be delivered. Diaspora members will see the original post/comment without edits. There is no mechanism in the protocol to update an existing post. We cannot delete it and submit another invisibly because the message-id will change and we need to keep the same message-id on our own network. The only workaround is to delete the post/comment and do it over. We may eventually provide a way to delete the out of date copy only from Diaspora and keep it intact on networks that can handle edits. + +Some comments from external services will not deliver to Diaspora, as they have no Diaspora service discovery. Currently this applies to comments from WordPress blogs which are imported into your stream; but will extend to most any service that has no Diaspora discover mechanism. + + +Nomadic identity will not work with Diaspora. We will eventually provide an **option** which will allow you to "start sharing" from all of your clones when you make the first connection. The Diaspora person does not have to accept this, but it will allow your communications to continue if they accept this connection. Without this option, if you go to another server from where you made the connection originally or you make the connection before creating the clone, you will need to make friends with them again from the new location. + +Post expiration is not supported on Diaspora. We will provide you an option to not send expiring posts to that network. In the future this may be provided with a remote delete request. + +End-to-end encryption is not supported. We will translate these posts into a lock icon, which can never be unlocked from the Diaspora side. + +Message verification will eventually be supported. + +Multiple profiles are not supported. Diaspora members can only see your default profile. + +Birthday events will not appear in Diaspora. Other events will be translated and sent as a post, but all times will either be in the origination channel's timezone or in GMT. We do not know the recipient's timezone because Diaspora doesn't have this concept. + +We currently allow tags to be hijacked by default. We will provide an option to allow you to prevent the other end of the network from hijacking your tags and point them at its own resources. + +Community tags will not work. We will send a tagging activity as a comment. It won't do anything. + +Privacy tags (@!somebody) will not be available to Diaspora members. These tags may have to be stripped or obscured to prevent them from being hijacked - which could result in privacy issues. + +Plus-tagged hubzilla forums should work from Diaspora. + +Premium channel redirects will not be sent. If you allow Diaspora connections, they will not see that you have a premium channel. + +You cannot use Diaspora channels as channel sources. + + +Dislikes of posts will be converted to comments and you will have the option to send these as comments or not send them to Diaspora (which does not provide dislike). Currently they are not sent. + +We will do the same for both likes and dislikes of comments. They can either be sent as comments or you will have the ability to prevent them from being transmitted to Diaspora. Currently they are not sent. + + +"observer tags" will be converted to empty text. + + +Embedded apps will be translated into links. + + +Embedded page design elements (work in progress) will be either stripped or converted to an error message. + +Diaspora members will not appear in the directory. + + +There are differences in oembed compatibility between the networks. Some embedded resources will turn into a link on one side or the other. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/doco.bb b/sources/doc/doco.bb new file mode 100644 index 00000000..7ca64cfe --- /dev/null +++ b/sources/doc/doco.bb @@ -0,0 +1,33 @@ +[b]Creating Documentation[/b] + +To contribute documentation, simply put some words in a cunning order, and make their existence known to a developer. You can do this literally anywhere as long as a developer can see it. Once made aware, somebody will check it in for you. You should try to avoid proprietary formats, or locations that require authentication with methods other than Zot in order to make it easy for a developer to access, but even this is not a strict requirement. + +If you wish to contribute directly, that's fine too. To contribute directly, documentation should be in one of the following formats: + +[li]Markdown[/li] +[li]BBCode[/li] +[li]HTML[/li] +[li]Plain Text[/li] + +Other formats are also allowed, but support for the format must be added to mod/help.php first. + +If editing a plain text file, please keep column width to 80. This is because plain text is used in instances where we may not have a working installation - the installation documentation, for example - and it should be easy to read these from a CLI text editor. + +The advantage of Markdown is that it is human readable. + +The advantage of BBCode is that it is identity aware. + +Therefore, if using BBCode, try to make the most of it: +[li]Use ZRL links where appropriate to ensure a link to another site retains authentication and keeps identity based documentation working[/li] +[li]Use baseurl or observer.baseurl tags where appropriate instead of example.com for authenticated viewers.[/li] +[li]Support non-authenticated users with observer=0 tags. We presently do not do this due to historical oversights. This needs adding everywhere[/li] + +[b]Translations[/b] + +To translate documentation, or provided documentation in languages other than English: +[li]Create a directory in doc/ with your two letter country code if it doesn't already exist (eg, doc/de/ for German or doc/fr/ for French)[/li] +[li]Create a document with the same filename as the English version, but with content in your own language. This allows us to fallback to the English if the translation for a particular page is not provided[/li] + +To create documentation that has no equivalent file in English, you can create a new file with a name of your choosing - but you'll also need to provide a localised version of the index page (main.bb in English) to make it accessible from the menu. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/encryption.bb b/sources/doc/encryption.bb new file mode 100644 index 00000000..9985f4b3 --- /dev/null +++ b/sources/doc/encryption.bb @@ -0,0 +1,18 @@ +[size=large]Builtin Automatic Encryption[/size] + +Full disclosure: The encryption $Projectname uses per default is not absolutely waterproof. There [i]are[/i] known procedures to circumvent it. [i]But[/i] this takes a lot of effort and needs to be done individually for each channel. And to make this clear: Other services store your messages in plaintext, therefore we regard this approach as a [i]significant[/i] improvement for your privacy. Plus you are always free to use further encryption and password protection if you so desire. + + +To explain this in more detail: + +- each channel has its key pair +- every non-public post is automatically encrypted +- optional password protect content via crypto-javascript browser-to-browser encryption (needs to be enabled in settings) Full disclosure: A rogue hub admin could injects malicious javascript-code (e.g. keylogging-abilities) into the code. Encrypt our stuff out of band with GPG, become a hub administrator yourself or use other means of communication if this worries you. + +So what is the scope of security? Full disclosure: This might be great, but it is not perfect. +- every non-public post is automatically encrypted but persons who have access to the site's database and files [i]may[/i] be able to decrypt everything by using these keys which obviously need to be stored on the server. To be clear: The encrypion keys are different for every channel and it is [i]quite an effort[/i] to do this. And again: Other services store your messages in plain text unencrypted. So this [i]is[/i] quite a significant win for your privacy. + +We believe that the NSA-level dragnet plaintext extracting mass surveillance is probably not possible due to the design of the zot protocol. Dedicated attacks including hacking into one hub to obtain the server logs and database only partly reveal what is going on between people communication between different hubs. We believe that this makes it much more expensive for state-level attackers to access your content in $Projectname. + + +We gladly accept help improving the security of the system and auditing it as well. diff --git a/sources/doc/external-resource-links.bb b/sources/doc/external-resource-links.bb new file mode 100644 index 00000000..412e8446 --- /dev/null +++ b/sources/doc/external-resource-links.bb @@ -0,0 +1,20 @@ +[b]External Resource Links[/b] + +[b][color= grey][size=24]External Links[/size][/color][/b] +[b]Third-Party Themes[/b] + +[*][url=https://github.com/omigeot/redstrap3]Redstrap[/url] +[*][url=https://bitbucket.org/tobiasd/red-clean]Clean[/url] +[*][url=https://github.com/tonybaldwin/redmatrixthemes/]nubasic[/url] +[*][url=https://github.com/deadsuperhero/redmatrix-themes]Sean Tilley's themes[/url] + +[b]Third-Party Addons[/b] +[*][url=https://abcentric.net/git/abcjsplugin.git]ABCjs integration - display scores in posts (WIP)[/url] +[b]Related Projects[/b] + +[*][url=https://addons.mozilla.org/en-US/firefox/addon/redshare/]Redshare for Firefox[/url] +[*][url=https://github.com/cvogeley/red-for-android]Red for Android[/url] +[*][url=https://github.com/zzottel/feed2red]feed2red.pl (posts Atom/RSS feeds to channel)[/url] +[*][url=https://wordpress.org/plugins/hubzilla-wp/]WordPress gateway (combine with wppost addon for full features)[/url] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/extra_features.bb b/sources/doc/extra_features.bb new file mode 100644 index 00000000..ed513eeb --- /dev/null +++ b/sources/doc/extra_features.bb @@ -0,0 +1,98 @@ +// multiple of these have been enabled by default. should we note this here somewhere, move it or remove them from this file? +[b]Features[/b] + +The default interface of the $Projectname was designed to be uncluttered. There are a huge number of extra features (some of which are extremely useful) which you can turn on and get the most of the application. These are found under the Extra Features link of your Settings page. + +[b]Content Expiration[/b] + +Remove posts/comments and/or private messages at a future time. An extra button is added to the post editor which asks you for an expiration. Typically this in "yyyy-mm-dd hh:mm" format, but in the English language you have a bit more freedom and can use most any recognisable date reference such as "next Thursday" or "+1 day". At the specified time (give or take approximately ten minutes based on the remote system's checking frequency) the post is removed. + +[b]Multiple Profiles[/b] + +The ability to create multiple profiles which are visible only to specific persons or groups. Your default profile may be visible to anybody, but secondary profiles can all contain different or additional information and can only be seen by those to whom that profile is assigned. + +[b]Web Pages[/b] + +Provides the ability to use web page design feaures and create custom webpages from your own content and also to design the pages with page layouts, custom menus, and content blocks. + +[b]Private Notes[/b] + +On pages where it is available (your matrix page and personal web pages) provide a "widget" to create and store personal reminders and notes. + +[b]Extended Identity Sharing[/b] + +By default your identity travels with you as you browse the matrix to remote sites - and they know who you are and can show you content that only you can see. With Extended Identity Sharing you can provide this information to any website you visit from within the matrix. + +[b]Expert Mode[/b] + +This allows you to see some advanced configuration options that would confuse some people or cause support issues. In particular this can give you full control over theme features and colours - so that you can tweak a large number of settings of the display theme to your liking. + +[b]Premium Channel[/b] + +This allows you to set restrictions and terms on those that connect with your channel. This may be used by celebrities or anybody else who wishes to describe their channel to people who wish to connect with it. In certain cases you may be asked for payment in order to connect. + +[b]Post Preview[/b] + +Allows previewing posts and comments exactly as they would look on the page before publishing them. + +[b]Channel Sources[/b] + +Automatically import and re-publish channel content from other channels or feeds. This allows you to create sub-channels and super-channels from content provided elsewhere. The rules are that the content must be public, and the channel owner must give you permission to source their channel. + +[b]Even More Encryption[/b] + +Private messages are encrypted during transport and storage. In this day and age, this encyption may not be enough if your communications are extremely sensitive. This options lets you provide optional encryption of content "end-to-end" with a shared secret key. How the recipient learns the secret key is completely up to you. You can provide a hint such as "the name of aunt Claire's first dog". + +[b]Search by Date[/b] + +This provides the ability to select posts by date ranges + +[b]Collections Filter[/b] + +Enable widget to display stream posts only from selected collections. This also toggles the outbound permissions while you are viewing a collection. This is analogous to Google "circles" or Disapora "aspects". + +[b]Saved Searches[/b] + +Provides a search widget on your matrix page which can save selected search terms for re-use. + +[b]Personal Tab[/b] + +Enable tab to display only matrix posts that you've interacted with in some way, as an author or a contributor to the conversation. + +[b]New Tab[/b] + +Enables a tab to display all new matrix activity as a firehose or timeline. + +[b]Affinity Tool[/b] + +Filter matrix stream activity by the depth of your relationships + +[b]Edit Sent Posts[/b] + +Edit and correct posts and comments after sending + +[b]Tagging[/b] + +Ability to tag existing posts, including those written by others. + +[b]Post Categories[/b] + +Add categories to your channel posts + +[b]Saved Folders[/b] + +Ability to file posts under folders or tags for later recall + +[b]Dislike Posts[/b] + +Ability to dislike posts/comments + +[b]Star Posts[/b] + +Ability to mark special posts with a star indicator + +[b]Tag Cloud[/b] + +Provide a personal tag cloud on your channel page + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/faq_admins.bb b/sources/doc/faq_admins.bb new file mode 100644 index 00000000..63418c1d --- /dev/null +++ b/sources/doc/faq_admins.bb @@ -0,0 +1,78 @@ +[size=large][b]The $Projectname FAQ[/b][/size] + +[toc] + +[h3]Is there a way to change the Admin account?[/h3] +[h3]Is there a way to have multiple administrators?[/h3] +Yes, but it's a bit messy at the moment as it is not yet exposed in the UI. To make an account an administrative account, +one needs to add 4096 to the account_roles entry in the account table of the database. Likewise, to remove administrative permissions, +one must subtract 4096 from the account roles. + +[h3]I can log in, but there are no posts or webpages[/h3] + +Most likely, your item table has crashed. Run the MySQL command [code]repair table item;[/code] + +[h3]Login doesn't work, immediately after login, the page reloads and I'm logged out[/h3] + +Most likely, your session table has crashed. Run the MySQL command [code]repair table session;[/code] + +[h3]When I switch theme, I sometimes get elements of one theme superimposed on top of the other[/h3] + +a) store/[data]/smarty3 isn't writeable by the webserver. Make it so. + +b) You're using Midori, or with certain themes, Konqueror in KHTML mode. + +[b]My network tab won't load, it appears to be caused by a photo or video[/h3] + +Your PHP memory limit is too low. Increase the size of the memory_limit directive in your php.ini + +Contrary to popular belief, the number of users on a hub doesn't make any difference to the required memory limit, rather, the content +of an individuals matrix counts. Streams with lots of photos and video require more memory than streams with lots of text. + +[h3]I have no communication with anybody[/h3] + +You're listening on port 443, but do not have a valid SSL certificate. Note this applies even if your baseurl is http. +Don't listen on port 443 if you cannot use it. It is strongly recommended to solve this problem by installing a browser +valid SSL certificate rather than disabling port 443. + +[h3]How do I update a non-Git install?[/h3] +1) Backup .htconfig.php +2) Backup everything in store/ +3) Backup any custom changes in mod/site/ and view/site +3) Delete your existing installation +4) Upload the new version. +5) Upload the new version of themes and addons. +6) Restore everything backed up earlier. + +[h3]What do I need to do when moving my hub to a different server[/h3] + +1) Git clone on the new server. Repeat the process for any custom themes, and addons. +2) Rsync .htconfig.php +3) Rsync everything in store/ +4) Rsync everything in mod/site/ and view/site (these will only exist if you have custom modules) +5) Dump and restore DB. + +[h3]How do I reinstall an existing hub on the same server?[/h3] + +1) [code]git reset --hard HEAD[/code] will reset all files to their upstream defaults. This will not reset any local files that do not also exist upstream. Eg, if you have local changes to mod/channel.php, this will reset them - but will not reset any changes in mod/site/channel.php +2) If you absolutely must reinstall - for example, if you need to upgrade operating system - follow the steps for moving to a different server, but instead of using rsync, backup and restore some other way. + +Do not reinstall a hub with a fresh database and fresh .htconfig.php unless as a very last resort. Creating a temporary account and ask for help via a support channel for non-trivial reinstalls is preferable to reinstalling fresh. + +[h3]How do I set the default homepage for logged out viewers?[/h3] + +Use the custom_home addon available in the main addons repository. + +[h3]What do the different directory mode settings mean?[/h3] +[code]// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory (all of your member's queries will be directed elsewhere) +// DIRECTORY_MODE_SECONDARY = caching directory or mirror (keeps in sync with realm primary [adds significant cron execution time]) +// DIRECTORY_MODE_PRIMARY = main directory server (you do not want this unless you are operating your own realm. one per realm.) +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services (only local site members in directory) +[/code] +- The default is NORMAL. This off-loads most directory services to a different server. The server used is the config:system/directory_server. This setting MAY be updated by the code to one of the project secondaries if the current server is unreachable. You should either be in control of this other server, or should trust it to use this setting. +- SECONDARY. This allows your local site to act as a directory server without exposing your member's queries to another server. It requires extra processing time during the cron polling, and is not recommended to be run on a shared web host. +- PRIMARY. This allows you to run a completely separate 'Network' of directory servers with your own Realm. By default, all servers are on the RED_GLOBAL realm unless the config:system/directory_realm setting is overridden. [i]Do not use this unless you have your own directory_realm.[/i] +- STANDALONE. This is like primary, except it's a 'Network' all on it's own without talking to any other servers. Use this if you have only one server and want to be segregated from the Red#Matrix directory listings. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/faq_developers.bb b/sources/doc/faq_developers.bb new file mode 100644 index 00000000..027efe8f --- /dev/null +++ b/sources/doc/faq_developers.bb @@ -0,0 +1,33 @@ +[size=large][b]Frequently Asked Questions For Developers[/b][/size] + +[toc] + + +[h3]What does $a mean?[/h3] +$a is a class defined in boot.php and passed all around $Projectname as a global reference variable. It defines everything necessary for the $Projectname application: Server variables, URL arguments, page structures, layouts, content, installed plugins, output device info, theme info, identity of the observer and (potential) page owner ... + +We don't ever create more than one instance and always modify the elements of the single instance. The mechanics of this are somewhat tricky. If you have a function that is passed $a and needs to modify $a you need to declare it as a reference with '&' e.g. + +[code]function foo(&$a) { $a->something = 'x'; // whatever }; + +*or* access it within your function as a global variable via get_app() + +function foo() { + $a = get_app(); + $a->something = 'x'; +} + + +function foo($a) { $a->something = 'x'; }; + +will *not* change the global app state. + +function foo() { + get_app()->something = 'x'; +} +[/code] + + + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/faq_members.bb b/sources/doc/faq_members.bb new file mode 100644 index 00000000..9d42d97a --- /dev/null +++ b/sources/doc/faq_members.bb @@ -0,0 +1,18 @@ +[size=large][b]The $Projectname FAQ[/b][/size] + +[toc] + + +[h3]I am able to edit a post's text after I saved it, but is there a way to change the permissions?[/h3] +Short anser: No, there isn't. There are reasons. You are able to change permissons to your files, photos and the likes, but not to posts after you have saved them. The main reason is: Once you have saved a post it is being distributed either to the public channel and from there to other $Projectname servers or to those you intended it to go. Just like you cannot reclaim something you gave to another person, you cannot change permissions to $Projectname posts. We would need to track everywhere your posting goes, keep track of everyone you allowed to see it and then keep track of from whom to delete it. +If a posting is public this is even harder, as the $Projectname is a global network and there is no way to follow a post, let alone reclaim it reliably. Other networks that may receive your post have no reliable way to delete or reclaim the post. + +[h3]I downloaded my channel and imported it (cloned my identity) to another site but there is no content, no posts, no photos. What is wrong???[/h3] +To be honest: Nothing. That's the way it is right now. Technically it is surely possible to take at least your own posts and maybe even files with you, but this has simply put not implemented yet. When creating this feature we thought that keeping all your contacts was more important. Your friends have already seen your old content. Once we find someone willing to implement this, it will be done. :) +[h3]I can't see private resources[/h3] +You have probably disabled third party cookies. You need to enable them for remote authentication to work. +[h3]There are a lot of foreign language posts. Let's auto-translate them.[/h3] +There are also a lot of [b]private[/b] foreign language posts and auto-translation services would require us to transmit these private messages to the translation service; and we don't know what they will do with them on their servers. Actually we do know thanks to Edward Snowden. Our best bet is a project called [b][i]Apertium[/i][/b] which is an open source translator we can install locally. It is currently missing German translations - which are the most requested translation in the matrix. Once again, this will be implemented when we find somebody who really wants to make it happen. + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/features.bb b/sources/doc/features.bb new file mode 100644 index 00000000..0a9bcee3 --- /dev/null +++ b/sources/doc/features.bb @@ -0,0 +1,208 @@ +[b][size=20]Features[/size][/b] + +[b][size=24]$Projectname in a Nutshell[/size][/b] + +TL;DR + +$Projectname provides distributed web publishing and social communications with [b]decentralised permissions[/b]. + +So what exactly are "decentralised permissions"? They give me the ability to share something on my website (photos, media, files, webpages, etc.) with specific people on completely different websites - but not necessarily [i]everybody[/i] on those websites; and they do not need a password on my website and do not need to login to my website to view the things I've shared with them. They have one password on their own website and "magic authentication" between affiliated websites in the network. Also, as it is decentralised, there is no third party which has the ability to bypass permissions and see everything in the network. + +$Projectname combines many features of traditional blogs, social networking and media, content management systems, and personal cloud storage into an easy to use framework. Each node in the matrix can operate standalone or link with other nodes to create a super-network; leaving privacy under the control of the original publisher. + +$Projectname is an open source webserver application written originally in PHP/MySQL and is easily installable by those with basic website administration skills. It is also easily extended via plugins and themes and other third-party tools. + +[b][size=24]$Projectname Features[/size][/b] + + +The $Projectname is a general-purpose web publishing and communication network, with several unique features. It is designed to be used by the widest range of people on the web, from non-technical bloggers, to expert PHP programmers and seasoned systems administrators. + +This page lists some of the core features of $Projectname that are bundled with the official release. As with most free and open source software, there may be many other extensions, additions, plugins, themes and configurations that are limited only by the needs and imagination of the members. + +[b][size=20]Built for Privacy and Freedom[/size][/b] + +One of the design goals of $Projectname is to enable easy communication on the web, while preserving privacy, if so desired by members. To achieve this goal, $Projectname includes a number of features allowing arbitrary levels of privacy: + +[b]Affinity Slider[/b] + +When adding connnections in $Projectname, members have the option of assigning "affinity" levels (how close your friendship is) to the new connection. For example, when adding someone who happens to be a person whose blog you follow, you could assign their channel an affinity level of "Acquaintances". + +On the other hand, when adding a friend's channel, they could be placed under the affinity level of "Friends". + +At this point, the $Projectname [i]Affinity Slider[/i] tool, which usually appears at the top of your "Matrix" page, adjusts the content on the page to include those within the desired affinity range. Channels outside that range will not be displayed, unless you adjust the slider to include them. + +The Affinity Slider allows instantaneous filtering of large amounts of content, grouped by levels of closeness. + +[b]Access Control Lists[/b] + +When sharing content, members have the option of restricting who sees the content. By clicking on the padlock underneath the sharing box, one may choose desired recipients of the post, by clicking on their names. + +Once sent, the message will be viewable only by the sender and the selected recipients. In other words, the message will not appear on any public walls. + +Access Control Lists may be applied to content and posts, photos, events, webpages, chatrooms and files. + +[b]Single Sign-on[/b] + +Access Control Lists work for all channels in the matrix due to our unique single sign-on technology. Most internal links provide an identity token which can be verified on other $Projectname sites and used to control access to private resources. You login once to your home hub. After that, authentication to all $Projectname resources is "magic". + + +[b]WebDAV enabled File Storage[/b] + +Files may be uploaded to your personal storage area using your operating system utilities (drag and drop in most cases). You may protect these files with Access Control Lists to any combination of $Projectname members (including some third party network members) or make them public. + +[b]Photo Albums[/b] + +Store photos in albums. All your photos may be protected by Access Control Lists. + +[b]Events Calendar[/b] + +Create and manage events and tasks, which may also be protected with Access Control Lists. Events can be imported/exported to other software using the industry standard vcalendar/iCal format and shared in posts with others. Birthday events are automatically added from your friends and converted to your correct timezone so that you will know precisely when the birthday occurs - no matter where you are located in the world in relation to the birthday person. Events are normally created with attendance counters so your friends and connections can RSVP instantly. + +[b]Chatrooms[/b] + +You may create any number of personal chatrooms and allow access via Access Control Lists. These are typically more secure than XMPP, IRC, and other Instant Messaging transports, though we also allow using these other services via plugins. + +[b]Webpage Building[/b] + +$Projectname has many "Content Management" creation tools for building webpages, including layout editing, menus, blocks, widgets, and page/content regions. All of these may be access controlled so that the resulting pages are private to their intended audience. + +[b]Apps[/b] + +Apps may be built and distributed by members. These are different from traditional "vendor lockin" apps because they are controlled completely by the author - who can provide access control on the destination app pages and charge accordingly for this access. Most apps in $Projectname are free and can be created easily by those with no programming skills. + +[b]Layout[/b] + +Page layout is based on a description language called Comanche. $Projectname is itself written in Comanche layouts which you can change. This allows a level of customisation you won't typically find in so-called "multi-user environments". + +[b]Bookmarks[/b] + +Share and save/manage bookmarks from links provided in conversations. + + +[b]Private Message Encryption and Privacy Concerns[/b] + +Messages marked [b]private[/b] are encrypted with AES-CBC 256-bit symmetric cipher, which is then protected (encrypted in turn) by public key cryptography, based on 4096-bit RSA keys, associated with the channel that is sending the message. + +These private messages are also stored in an encrypted form on remote systems. + +Each Red channel has it's own unique set of private and associated public RSA 4096-bit keys, generated when the channels is first created. + +Additionally, messages may be created utilising "end-to-end encryption" which cannot be read by $Projectname operators or ISPs or anybody who does not know the passcode. + +Public messages are generally not encrypted in transit or in storage. + +Private messages may be retracted (unsent) although there is no guarantee the recipient hasn't read it yet. + +Posts and messages may be created with an expiration date, at which time they will be deleted/removed on the recipient's site. + + +[b]Service Federation[/b] + +In addition to addon "cross-post connectors" to a variety of alternate networks, there is native support for importation of content from RSS/Atom feeds and using this to create special channels. Also, an experimental but working implementation of the Diaspora protocol allows communication with people on the Friendica and Diaspora decentralised social networks. This is currently marked experimental because these networks do not have the same level of privacy and encryption features and abilities as $Projectname and may present privacy risks. + +There is also experimental support for OpenID authentication which may be used in Access Control Lists. This is a work in progress. Your $Projectname hub may be used as an OpenID provider to authenticate you to external services which use this technology. + +Channels may have permissions to become "derivative channels" where two or more existing channels combine to create a new topical channel. + +[b]Collections[/b] + +"Collections" is our implementation of privacy groups, which is similar to Google "Circles" and Diaspora "Aspects". This allows you to filter your incoming stream by collections or groups, and automatically set the outbound Access Control List to only those in the Collection when you post. You may over-ride this at any time (prior to sending the post). + + +[b]Directory Services[/b] + +We provide easy access to a directory of members and provide decentralised tools capable of providing friend "suggestions". The directories are normal $Projectname sites which have chosen to accept the directory server role. This requires more resources than most typical sites so is not the default. Directories are synchronised and mirrored so that they all contain up-to-date information on the entire network (subject to normal propagation delays). + + +[b]TLS/SSL[/b] + +For $Projectname hubs that use TLS/SSL, client to server communications are encrypted via TLS/SSL. Given recent disclosures in the media regarding widespread, global surveillance and encryption circumvention by the NSA and GCHQ, it is reasonable to assume that HTTPS-protected communications may be compromised in various ways. Private communications are consequently encrypted at a higher level before sending offsite. + +[b]Channel Settings[/b] + +When a channel is created, a role is chosen which applies a number of pre-configured security and privacy settings. These are chosen for best practives to maintain privacy at the requested levels. + +If you choose a "custom" privacy role, each channel allows fine-grained permissions to be set for various aspects of communication. For example, under the "Security and Privacy Settings" heading, each aspect on the left side of the page, has six (6) possible viewing/access options, that can be selected by clicking on the dropdown menu. There are also a number of other privacy settings you may edit. + +The options are: + + - Nobody except yourself. + - Only those you specifically allow. + - Anybody in your address book. + - Anybody on this website. + - Anybody in this network. + - Anybody authenticated. + - Anybody on the Internet. + + +[b]Public and Private Forums[/b] + +Forums are typically channels which may be open to participation from multiple authors. There are currently two mechanisms to post to forums: 1) "wall-to-wall" posts and 2) via forum @mention tags. Forums can be created by anybody and used for any purpose. The directory contains an option to search for public forums. Private forums can only be posted to and often only seen by members. + + +[b]Account Cloning[/b] + +Accounts in the $Projectname are referred to as [i]nomadic identities[/i], because a member's identity is not bound to the hub where the identity was originally created. For example, when you create a Facebook or Gmail account, it is tied to those services. They cannot function without Facebook.com or Gmail.com. + +By contrast, say you've created a Red identity called [b]tina@redhub.com[/b]. You can clone it to another Red hub by choosing the same, or a different name: [b]liveForever@Some$ProjectnameHub.info[/b] + +Both channels are now synchronized, which means all your contacts and preferences will be duplicated on your clone. It doesn't matter whether you send a post from your original hub, or the new hub. Posts will be mirrored on both accounts. + +This is a rather revolutionary feature, if we consider some scenarios: + + - What happens if the hub where an identity is based suddenly goes offline? Without cloning, a member will not be able to communicate until that hub comes back online (no doubt many of you have seen and cursed the Twitter "Fail Whale"). With cloning, you just log into your cloned account, and life goes on happily ever after. + + - The administrator of your hub can no longer afford to pay for his free and public $Projectname hub. He announces that the hub will be shutting down in two weeks. This gives you ample time to clone your identity(ies) and preserve your Red relationships, friends and content. + + - What if your identity is subject to government censorship? Your hub provider may be compelled to delete your account, along with any identities and associated data. With cloning, the $Projectname offers [b]censorship resistance[/b]. You can have hundreds of clones, if you wanted to, all named different, and existing on many different hubs, strewn around the internet. + +Red offers interesting new possibilities for privacy. You can read more at the <<Private Communications Best Practices>> page. + +Some caveats apply. For a full explanation of identity cloning, read the <HOW TO CLONE MY IDENTITY>. + +[b]Multiple Profiles[/b] + +Any number of profiles may be created containing different information and these may be made visible to certain of your connections/friends. A "default" profile can be seen by anybody and may contain limited information, with more information available to select groups or people. This means that the profile (and site content) your beer-drinking buddies see may be different than what your co-workers see, and also completely different from what is visible to the general public. + +[b]Account Backup[/b] + +Red offers a simple, one-click account backup, where you can download a complete backup of your profile(s). + +Backups can then be used to clone or restore a profile. + +[b]Account Deletion[/b] + +Accounts can be immediately deleted by clicking on a link. That's it. All associated content is then deleted from the matrix (this includes posts and any other content produced by the deleted profile). Depending on the number of connections you have, the process of deleting remote content could take some time but it is scheduled to happen as quickly as is practical. + +[b][size=20]Content Creation[/size][/b] + +[b]Writing Posts[/b] + +Red supports a number of different ways of adding rich-text content. The default is a custom variant of BBcode, tailored for use in $Projectname. You may also enable the use of Markdown if you find that easier to work with. A visual editor may also be used. The traditional visual editor for $Projectname had some serious issues and has since been removed. We are currently looking for a replacement. + +When creating "Websites", content may be entered in HTML, Markdown, BBcode, and/or plain text. + +[b]Deletion of content[/b] +Any content created in the $Projectname remains under the control of the member (or channel) that originally created it. At any time, a member can delete a message, or a range of messages. The deletion process ensures that the content is deleted, regardless of whether it was posted on a channel's primary (home) hub, or on another hub, where the channel was remotely authenticated via Zot (the $Projectname communication and authentication protocol). + +[b]Media[/b] +Similar to any other modern blogging system, social network, or a micro-blogging service, Red supports the uploading of files, embedding of videos, linking web pages. + +[b]Previewing/Editing[/b] +Post can be previewed prior to sending and edited after sending. + +[b]Voting/Consensus[/b] +Posts can be turned into "consensus" items which allows readers to offer feedback, which is collated into "agree", "disagree", and "abstain" counters. This lets you gauge interest for ideas and create informal surveys. + + +[b]Extending $Projectname[/b] + +$Projectname can be extended in a number of ways, through site customisation, personal customisation, option setting, themes, and addons/plugins. + +[b]API[/b] + +An API is available for use by third-party services. This is based originally on the early Twitter API (for which hundreds of third-party tools exist). It is currently being extended to provide access to facilities and abilities which are specific to $Projectname. Access may be provided by login/password or OAuth and client registration of OAuth applications is provided. + + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/first-post.bb b/sources/doc/first-post.bb new file mode 100644 index 00000000..cf6ed5b4 --- /dev/null +++ b/sources/doc/first-post.bb @@ -0,0 +1,3 @@ +[size=large]Your first posting[/size] + +... to be written ... diff --git a/sources/doc/git_for_non_developers.bb b/sources/doc/git_for_non_developers.bb new file mode 100644 index 00000000..b0a62310 --- /dev/null +++ b/sources/doc/git_for_non_developers.bb @@ -0,0 +1,71 @@ +[b]Git For Non-Developers[/b] + +So you're handling a translation, or you're contributing to a theme, and every time you make a pull request you have to talk to one of the developers before your changes can be merged in? + +Chances are, you just haven't found a quick how-to explaining how to keep things in sync on your end. It's really very easy. + +After you've created a fork of the repo (just click "fork" at github), you need to clone your own copy. + +For the sake of examples, we'll assume you're working on a theme called redexample (which does not exist). + +[code]git clone https://github.com/username/red.git[/code] + +Once you've done that, cd into the directory, and add an upstream. + +[code] +cd red +git remote add upstream https://github.com/redmatrix/redmatrix +[/code] + +From now on, you can pull upstream changes with the command +[code]git fetch upstream[/code] + +Before your changes can be merged automatically, you will often need to merge upstream changes. + +[code] +git merge upstream/master +[/code] + +You should always merge upstream before pushing any changes, and [i]must[/i] merge upstream with any pull requests to make them automatically mergeable. + +99% of the time, this will all go well. The only time it won't is if somebody else has been editing the same files as you - and often, only if they have been editing the same lines of the same files. If that happens, that would be a good time to request help until you get the hang of handling your own merge conflicts. + +Then you just need to add your changes [code]git add view/theme/redexample/[/code] + +This will add all the files in view/theme/redexample and any subdirectories. If your particular files are mixed throughout the code, you should add one at a time. Try not to do git add -a, as this will add everything, including temporary files (we mostly, but not always catch those with a .gitignore) and any local changes you have, but did not intend to commit. + +Once you have added all the files you have changed, you need to commit them. [code]git commit[/code] + +This will open up an editor where you can describe the changes you have made. Save this file, and exit the editor. + +Finally, push the changes to your own git +[code]git push[/code] + +And that's it, your repo is up to date! + +All you need to do now is actually create the pull request. There are two ways to do this. + +The easy way, if you're using Github is to simply click the green button at the top of your own copy of the repository, enter a description of the changes, and click 'create pull request'. The +main repository, themes, and addons all have their main branch at Github, so this method can be used most of the time. + +Most people can stop here. + +Some projects in the extended RedMatrix ecosphere have no Github presence, to pull request these is a bit different - you'll have to create your pull request manually. Fortunately, this isn't +much harder. + +[code]git request-pull -p [/code] + +Start is the name of a commit to start at. This must exist upstream. Normally, you just want master. + +URL is the URL of [i]your[/i] repo. + +One can also specify . This defaults to HEAD. + +Example: +[code] +git request-pull master https://example.com/project +[/code] + +And simply send the output to the project maintainer. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/hidden_configs.bb b/sources/doc/hidden_configs.bb new file mode 100644 index 00000000..76213851 --- /dev/null +++ b/sources/doc/hidden_configs.bb @@ -0,0 +1,139 @@ +[b]Advanced Configurations for Administrators[/b] + +$Projectname contains many configuration options hidden from the main admin panel. + +These are generally options considered too niche, confusing, or advanced for +the average member. These settings can be activated from the the top level Red +directory with the syntax [code]util/config cat key value[/code] for a site +configuration, or [code]util/pconfig channel_id cat key value[/code] for a +member configuration. + +This document assumes you're an administrator. + +[b]pconfig[/b] + [b]system > user_scalable[/b] + Determine if the app is scalable on touch screens. Defaults to on, to + disable, set to zero - real zero, not just false. + [b]system > always_my_theme[/b] + Always use your own theme when viewing channels on the same hub. This + will break in some quite imaginative ways when viewing channels with + theme dependent Comanche. + [b]system > paranoia[/b] + Sets the security level of IP checking. If the IP address of a logged-in session changes + apply this level to determine if the account should be logged out as a security breach. + Options are: + 0 - no IP checking + 1 - check 3 octets + 2 - check 2 octets + 3 - check for any difference at all + [b]system > prevent_tag_hijacking[/b] + Prevent foreign networks hijacking hashtags in your posts and directing them at its own resources. + [b]system > blocked[/b] + An array of xchans blocked by this channel. Technically, this is a + hidden config and does belong here, however, addons (notably + superblock) have made this available in the UI. + [b]system > default_cipher[/b] + Set the default cipher used for E2EE items. + [b]system > network_page_default[/b] + Set default params when viewing the network page. This should contain + the same querystring as manual filtering. + [b]system > display_friend_count[/b] + Set the number of connections to display in the connections profile + widget. + [b]system > taganyone[/b] + Requires the config of the same name to be enabled. Allow the @mention tagging + of anyone, whether you are connected or not. This doesn't scale. + [b]system > startpage[/b] + Another of those technically hidden configs made available by addons. + Sets the default page to view when logging in. This is exposed to the + UI by the startpage addon. + [b]system > forcepublicuploads[/b] + Force uploaded photos to be public when uploaded as wall items. It + makes far more sense to just set your permissions properly in the first + place. Do that instead. + [b]system > do_not_track[/b] + As the browser header. This will break many identity based features. + You should really just set permissions that make sense. + +[b]Site config[/b] + [b]system > taganyone[/b] + Allow the @mention tagging of anyone whether you are connected or not. + [b]system > directorytags[/b] + Set the number of keyword tags displayed on the directory page. + [b]system > startpage[/b] + Set the default page to be taken to after a login for all channels at + this website. Can be overwritten by user settings. + [b]system > projecthome[/b] + Set the project homepage as the homepage of your hub. + [b]system > workflowchannelnext[/b] + The page to direct users to immediately after creating a channel. + [b]system > max_daily_registrations[/b] + Set the maximum number of new registrations allowed on any day. + Useful to prevent oversubscription after a bout of publicity + for the project. + [b]system > tos_url[/b] + Set an alternative link for the ToS location. + [b]system > block_public_search[/b] + Similar to block_public, except only blocks public access to + search features. Useful for sites that want to be public, but + keep getting hammered by search engines. + [b]system > paranoia[/b] + As the pconfig, but on a site-wide basis. Can be overwritten + by member settings. + [b]system > openssl_conf_file[/b] + Specify a file containing OpenSSL configuration. Read the code first. + If you can't read the code, don't play with it. + [b]system > optimize_items[/b] + Runs optimise_table during some tasks to keep your database nice and + defragmented. This comes at a performance cost while the operations + are running, but also keeps things a bit faster while it's not. + There also exist CLI utilities for performing this operation, which you + may prefer, especially if you're a large site. + [b]system > expire_limit + Don't expire any more than this number of posts per channel per + expiration run to keep from exhausting memory. Default 5000. + [b]system > dlogfile[/b] + Logfile to use for logging development errors. Exactly the same as + logger otherwise. This isn't magic, and requires your own logging + statements. Developer tool. + [b]system > authlog[/b] + Logfile to use for logging auth errors. Used to plug in to server + side software such as fail2ban. Auth failures are still logged to + the main logs as well. + [b]system > hide_in_statistics[/b] + Tell the red statistics servers to completely hide this hub in hub lists. + [b]system > reserved_channels[/b] + Don't allow members to register channels with this comma separated + list of names (no spaces) + [b]system > auto_follow[/b] + Make the first channel of an account auto-follow channels listed here - comma separated list of webbies (member@hub addresses). + [b]system > admin_email[/b] + Specifies the administrator's email for this site. This is initially set during install. + [b]system > cron_hour[/b] + Specify an hour in which to run cron_daily. By default with no config, this will run at midnight UTC. + [b]system > minimum_feedcheck_minutes[/b] + The minimum interval between polling RSS feeds. If this is lower than the cron interval, feeds will be polled with each cronjob + [b]system > blacklisted_sites[/b] + An array of specific hubs to block from this hub completely. + [b]system > ignore_imagick[/b] + Ignore imagick and use GD, even if imagick is installed on the server. Prevents some issues with PNG files in older versions of imagick. + [b]system > no_age_restriction[/b] + Do not restrict registration to people over the age of 13. This carries legal responsibilities in many countries to require that age be provided and to block all personal information from minors, so please check your local laws before changing. + [b]system > override_poll_lockfile[/b] + Ignore the lock file in the poller process to allow more than one process to run at a time. + [b]system > projecthome[/b] + Display the project page on your home page for logged out viewers. + [b]system > sellpage[/b] + A URL shown in the public sites list to sell your hub - display service classes, etc. + [b]randprofile > check[/b] + When requesting a random profile, check that it actually exists first + [b]randprofile > retry[/b] + Number of times to retry getting a random profile + [b]system > photo_cache_time[/b] + How long to cache photos, in seconds. Default is 86400 (1 day). + Longer time increases performance, but it also means it takes longer for changed permissions to apply. + [b]system > poco_rating_enable[/b] + Distributed reputation reporting and data collection may be disabled. If your site does not participate in distributed reputation you will also not be able to make use of the data from your connections on other sites. By default and in the absence of any setting it is enabled. Individual members can opt out by restricting who can see their connections or by not providing any reputation information for their connections. + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/history.md b/sources/doc/history.md new file mode 100644 index 00000000..32917712 --- /dev/null +++ b/sources/doc/history.md @@ -0,0 +1,50 @@ +Redmatrix History +================= + +Redmatrix is a collaborative effort by the Redmatrix community and based on work introduced in Friendica by the Friendica community. The core design, the project mission, and software base itself were created/written primarily by Mike Macgirvin and represent the culmination of over a decade of software design using variations of this platform and an evolving vision of the role of communication software in our lives. Many others have contributed to this work, both conceptually and in terms of actual code (way too many to list individually). + +##Mike Macgirvin -- Biography + +Mike Macgirvin is an American software engineer now living in Australia. He spent his early adult years designing and repairing semiconductor fabrication equipment for a number of companies as a self-described "machine wizard". In 1985 he became a research engineer at Stanford University for the Gravity Probe-B space mission and soon became a Unix systems administrator writing communication software and utilities; and becoming an expert in emerging internet technologies such as the now ubiquitous "World Wide Web". He authored an email "client" called "ML" which pioneered some advanced concepts in encryption, the ability to filter message streams into different "views", and multi-protocol support; and was an active proponent of and participant in the open source software *movement*. In 1996 he went to Netscape Communications to become tech lead on their Messaging Server and integrate this with Collabra (groupware) into a comprehensive communications server package. He stayed on after Netscape was acquired by America Online and was tech manager of the Groups@AOL project until 2001. + +During a layoff round, Mike was let go from America Online in August 2001 and purchased a music store in Mountain View, California later to be known as "Sonica Music Company". Opening a retail store for non-essential goods at the beginning of a prolonged economic downturn was in retrospect probably not the wisest career move. Sonica eventually folded; in late 2006. Mike returned to working on software and systems support full-time and was employed briefly at Symantec before moving to Australia in early 2007. He currently lives on a farm "out in the middle of nowhere" and is employed as a Computer Systems Officer at the University of Wollongong. + + +##Redmatrix - The Early Years + +The software which went into creating Redmatrix has been through three distinct historical phases. It began in 2003 when Mike Macgirvin was looking for a content management system to power the website for his music store and found the available solutions to be lacking in various respects. The project was born as the "PurpleHaze weblog" under the nom de plume "Nerdware Communications". It was a multi-user PHP/MySQL CMS which provided blogs, forums, photo albums, events and more. Initially it provided the basis for a social community and shopping for customers of the store, but was also linked to Mike's personal weblog running on another domain. The distinguishing characteristic of this software was the ability for so-called "normal users" to re-assemble the components and choose different content feeds - and in essence create their own personal "multi-user CMS" as a view. Their custom view was able to communicate with anybody else that used the system, but could be partitioned so that adult sites and motorcycle enthusiast sites would not be visible to each other and not clash (or in this case Mike's personal website and the music store website). This software was developed primarily from 2003 until 2008. + +In 2006 this software was used as the prototype for Symantec's "safeweb" reputation and community site. It was developed and enhanced until about 2008. A rewrite took place in 2008 named "Reflection" but work stagnated as the community dwindled. The need for content management systems and communications software dropped dramatically during this time as humans flocked to the new social aggregrators - Facebook and Twitter. + + +##Mistpark/Friendica + +In early 2010, Mike left Facebook, concerned at the company's increasing hold and control of personal information. In his words "Companies die. We watched it happen in the dot-com years. When they do, their databases are sold to the highest bidder.". Mike used some remnants of the old CMS project to create a decentralised social communications platform. This was launched in July 2010 as "Mistpark". The name was chosen as a tribute to his new home in the Southern Highlands of Australia. The key innovation in this project was the ability to authenticate remotely and invisibly to other decentralised instances of the software so to allow remote viewing of private photos and provide "wall-to-wall" posting across website instances. The lack of simple remote identity *provenance* was a serious limitation of other decentralised communication protocols. + +In late 2010, the name was changed to "Friendika". The name Friendika had some symbolic issues, since the suffix was common with "swastika" and "Amerika", both having negative connotations, however the dot-com domain was available. Friendica was in fact the first choice but the 'friendica.com' domain name was already registered. It became available a year later and the project was renamed to Friendica in late 2011. + +Soon after version 1 was released in July 2010 - providing basic social communications, the software also took on a new role - cross-service federation; which was first introduced in August and September 2010. Federation allowed the software to "behave as" a StatusNet site and friends and messages could communicate to the other service from their own platforms. It was also hoped to provide federation with Diaspora - a project with similar scope being developed in secret in New York and first released in November of that year. Over the course of the next year, the federation ability was extended to provide integrated communications from RSS feeds, to and from email, StatusNet, Facebook, Twitter, and the emerging Diaspora project. The software provided a single "view" of your entire social space no matter what provider you or your friends used. StatusNet and Diaspora were supported natively so that one account could access any of these services. Facebook and Twitter used "API federation" which required the person to have an account on those services with which to link. + +By July 2012, Twitter and Facebook had both changed their terms of service and essentially outlawed "API federation" in the way Friendica was using it. Diaspora announced they were changing their protocol and would not maintain compatibility nor provide any warning when compatibility would break (or documentation on the proposed changes). The creator of StatusNet was also leaving his project to create something new (pump.io). As the software's primary purpose by this time was "federation of different social services into one interface", this created a bit of a crisis. The federated social web was crumbling. Also of concern was that independent and decentralised social websites shut down frequently, requiring all their members to start over again on another site. Often the effort involved to do this seemed daunting - and many people ran back to the relative safety of the large corporate providers - Facebook, Twitter, and now Google+. + +Mike realised he did not want to be held hostage to the decisions that other projects and companies and independent websites make. Friendica could operate on its own without attaching to these other networks, but its vision and implementation of a federated social world depended on federation with others for its project identity - so this created an identity crisis. + +Mike had been working on this project for some time and there were a number of things which needed re-writing, including the base communication protocol which Friendica used (DFRN or the "Distributed Friends and Relations Network" protocol). These ideas were starting to emerge as a different method of communication he called "zot". Zot began as a way to create a common language for federated websites, but there was no interest in this ability and as mentioned, the federated web was crumbling. The first version was soon scrapped and zot was re-designed and re-ignited as a streamlined communication protocol which was location-independent; e.g. not tied to any website. This would allow people to carry on unaffected if their website operator shut down temporarily or permanently. They wouldn't have to make friends all over again, and permissions of everything on the system wouldn't have to be changed to allow bob@site1 to see something that was private to him, even though he was now bob@site2. This was a serious problem with decentralisation. People moved and their online identities were lost and had to be re-created from scratch and existing relationships destroyed and had to be created all over again. + + +##Redmatrix + +In July 2012, Mike left the Friendica project and began development of "zot" and a new base project called "red" in his somewhat elusive *spare time*. Red is Spanish for "network". It wasn't really a "social network" and especially not a "federated social network". It was just Red (technically "la red"), or "the network". Work began by removing all the "federation" components and going back to basics - communication and remote authentication. It was a major re-write and took roughly six months before even basic communication was re-established. It was also no longer compatible with Friendica - which had been given to the "Friendica community" and by this time (December 2012) was developing separately on its own track. + +It became clear during this time that the single most compelling feature of the project wasn't the social network at all, but the authentication layer and decentralised access control mechanisms. Combined with zot's location independence it created a new model for software which had never existed previously - decentralised identity-aware web publishing and single sign-on to any compatible provider across the web. These weren't *evolutionary*, they were **revolutionary**. One of the biggest flaws of the modern web is the reliance on different passwords for every service you use, or reliance on a single provider if you were to tie them to - say your Facebook login. Facebook can remove your account at any time. Gone. If you rely on their authentication for all your websites, your entire online identity - now gone. This is also what was missing from Friendica - a compelling software feature which could stand on its own, without requiring a social network and especially without requiring a federated social network with all the mentioned external dependencies. + +An early visitor to the project noted that he had some difficulty finding the project on Google because of the choice of name - "red". Yes, this was a poor decision in retrospect. We were buried on page 23,712 of the search results. The concept that was emerging around this identity-aware publishing was that of "a matrix of inter-connected thought streams", since we didn't have a concept of "people" and "friends". All were just connected "channels" with different ways to connect. So "Redmatrix" was chosen to give it a searchable name. It had nothing to do with the Matrix film and red and blue pills, though that is frequently cited (erronously); and in fact isn't a bad analogy. + +The concept of identity-aware content was alien to anything that existed previously on the web, so to make it useful we had to provide the ability to use it for content. It needed content publishing tools. This brought back concepts from the old "Content Management System" on which the software was originally based. To get it up and running quickly we created a markup language for webpages called "Comanche" which let you describe a page in high-level terms based on bbcode tags. We also added WebDAV so you could put decentralised access control on files and drag/drop from your operating system. So now you could have private photos, webpages, files, events, conversations, chatrooms - and they are visible to those you choose - no matter what site they use. All they need is zot. And your viewers could move to another site or just pop up at a different site any time they want and we don't care. And it **also** had a built-in social network; with lots of additional privacy and encryption features which were added even before the Snowden revelations gave them added urgency. + +Over time a few federation components re-emerged. The ability to view RSS feeds was important to many people. Diaspora never really managed to re-write their protocol, so that was re-implemented and allowed Redmatrix to connect with Diaspora and Friendica again (Friendica still had their Diaspora protocol intact, so this was the most common language now remaining on the free web - despite its faults). Diaspora communications aren't able to make use of the advanced identity features, but they work for basic communications. + +Mike stepped down as active coordinator for the project in early 2015. + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/html/index.php b/sources/doc/html/index.php new file mode 100644 index 00000000..4ef28aad --- /dev/null +++ b/sources/doc/html/index.php @@ -0,0 +1,22 @@ + + + +<<<<<<< HEAD + Hubzilla Doxygen API Documentation + + +

Hubzilla Doxygen API Documentation not rendered

+======= + $Projectname Doxygen API Documentation + + +

$Projectname Doxygen API Documentation not rendered

+>>>>>>> f866a42a42b9e12756353f5bb39a0f31a64bb26a +To get the Doxygen API Documentation you must render it with the program Doxygen (included in most distributions). +
+$ doxygen util/Doxyfile
+
+
+back + + diff --git a/sources/doc/install.bb b/sources/doc/install.bb new file mode 100644 index 00000000..e68b4a23 --- /dev/null +++ b/sources/doc/install.bb @@ -0,0 +1,4 @@ +#include install/INSTALL.txt; + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/install/sample-lighttpd.conf b/sources/doc/install/sample-lighttpd.conf new file mode 100644 index 00000000..db26c3b6 --- /dev/null +++ b/sources/doc/install/sample-lighttpd.conf @@ -0,0 +1,90 @@ +# See http://redmine.lighttpd.net/projects/lighttpd/wiki/Docs:ConfigurationOptions + +### LOAD MODULES +server.modules = ( + "mod_access", + "mod_accesslog", + "mod_fastcgi", + "mod_redirect", + "mod_rewrite" +) + +### BASIC STUFF +server.port = 80 + +server.username = "http" + +server.groupname = "http" + +server.document-root = "/path/to/your/www/files" #adjust to your setup + +server.errorlog = "/var/log/lighttpd/error.log" + +accesslog.filename = "/var/log/lighttpd/access.log" + +### DISABLE DIR LISTING +dir-listing.activate = "disable" + +### DISABLE REJECT EXPECT HEADER +### (needed for curl POST requests - otherwise they fail with error 417) +server.reject-expect-100-with-417 = "disable" + +### DEFINE SUPPORTED INDEX FILENAMES +index-file.names = ( + "index.html", + "index.htm", + "index.php" +) + +### DEFINE SUPPORTED MIME TYPES +mimetype.assign = ( + ".html" => "text/html", + ".htm" => "text/html", + ".css" => "text/css", + ".txt" => "text/plain", + ".svg" => "image/svg+xml", + ".jpg" => "image/jpeg", + ".png" => "image/png" +) + +### DONT EVER SERVE FILES WITH EXTENSION +static-file.exclude-extensions = ( ".php" ) + +### PHP WITH PHP-FPM +### (needs php-fpm installed and running) +fastcgi.server = ( + ".php" => ( + "localhost" => ( + "socket" => "/run/php-fpm/php-fpm.sock", + "broken-scriptfilename" => "enable", + "allow-x-sendfile" => "enable" + ) + ) +) + +### ENABLE SSL +$SERVER["socket"] == ":443" { + ssl.engine = "enable" + ssl.ca-file = "/etc/lighttpd/certs/ca-certs.crt" #adjust to your needs + ssl.pemfile = "/etc/lighttpd/certs/red-ssl.crt" #adjust to your needs + + ssl.use-compression = "disable" + ssl.use-sslv2 = "disable" + ssl.use-sslv3 = "disable" + ssl.cipher-list = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA" +} + +### RISTRICT ACCESS TO DIRECTORYS AND FILES +$HTTP["url"] =~ "\.(out|log|htaccess)$" { + url.access-deny = ("") +} + +$HTTP["url"] =~ "(^|/)\.git|(^|/)store" { + url.access-deny = ("") +} + +### URL REWRITE RULES +url.rewrite-if-not-file = ( + "^\/([^\?]*)\?(.*)$" => "/index.php?q=$1&$2", + "^\/(.*)$" => "/index.php?q=$1" +) diff --git a/sources/doc/install/sample-nginx.conf b/sources/doc/install/sample-nginx.conf new file mode 100644 index 00000000..e9a80d22 --- /dev/null +++ b/sources/doc/install/sample-nginx.conf @@ -0,0 +1,142 @@ +## +# Red Nginx configuration +# by Olaf Conradi +# +# On Debian based distributions you can add this file to +# /etc/nginx/sites-available +# +# Then customize to your needs. To enable the configuration +# symlink it to /etc/nginx/sites-enabled and reload Nginx using +# +# service nginx reload +## + +## +# You should look at the following URL's in order to grasp a solid understanding +# of Nginx configuration files in order to fully unleash the power of Nginx. +# +# http://wiki.nginx.org/Pitfalls +# http://wiki.nginx.org/QuickStart +# http://wiki.nginx.org/Configuration +## + +## +# This configuration assumes your domain is example.net +# You have a separate subdomain red.example.net +# You want all red traffic to be https +# You have an SSL certificate and key for your subdomain +# You have PHP FastCGI Process Manager (php5-fpm) running on localhost +# You have Red installed in /var/www/red +## + +server { + listen 80; + server_name red.example.net; + + index index.php; + root /var/www/red; + rewrite ^ https://red.example.net$request_uri? permanent; +} + +## +# Configure Red with SSL +# +# All requests are routed to the front controller +# except for certain known file types like images, css, etc. +# Those are served statically whenever possible with a +# fall back to the front controller (needed for avatars, for example) +## + +server { + listen 443 ssl; + server_name red.example.net; + + ssl on; + ssl_certificate /etc/nginx/ssl/red.example.net.chain.pem; + ssl_certificate_key /etc/nginx/ssl/example.net.key; + ssl_session_timeout 5m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-DSS-AES128-SHA256:DHE-DSS-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA:AES256-SHA:AES:CAMELLIA:DES-CBC3-SHA:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA:!DHE-RSA-AES128-GCM-SHA256:!DHE-RSA-AES256-GCM-SHA384:!DHE-RSA-AES128-SHA256:!DHE-RSA-AES256-SHA:!DHE-RSA-AES128-SHA:!DHE-RSA-AES256-SHA256:!DHE-RSA-CAMELLIA128-SHA:!DHE-RSA-CAMELLIA256-SHA; + ssl_prefer_server_ciphers on; + + fastcgi_param HTTPS on; + + index index.php; + charset utf-8; + root /var/www/red; + access_log /var/log/nginx/red.log; + #Uncomment the following line to include a standard configuration file + #Note that the most specific rule wins and your standard configuration + #will therefore *add* to this file, but not override it. + #include standard.conf + # allow uploads up to 20MB in size + client_max_body_size 20m; + client_body_buffer_size 128k; + + # rewrite to front controller as default rule + location / { + if ($is_args != "") { + rewrite ^/(.*) /index.php?q=$uri&$args last; + } + rewrite ^/(.*) /index.php?q=$uri last; + } + + # make sure webfinger and other well known services aren't blocked + # by denying dot files and rewrite request to the front controller + location ^~ /.well-known/ { + allow all; + rewrite ^/(.*) /index.php?q=$uri&$args last; + } + + # statically serve these file types when possible + # otherwise fall back to front controller + # allow browser to cache them + # added .htm for advanced source code editor library + location ~* \.(jpg|jpeg|gif|png|ico|css|js|htm|html|ttf|woff|svg)$ { + expires 30d; + try_files $uri /index.php?q=$uri&$args; + } + + # block these file types + location ~* \.(tpl|md|tgz|log|out)$ { + deny all; + } + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # or a unix socket + location ~* \.php$ { + # Zero-day exploit defense. + # http://forum.nginx.org/read.php?2,88845,page=3 + # Won't work properly (404 error) if the file is not stored on this + # server, which is entirely possible with php-fpm/php-fcgi. + # Comment the 'try_files' line out if you set up php-fpm/php-fcgi on + # another machine. And then cross your fingers that you won't get hacked. + try_files $uri =404; + + # NOTE: You should have "cgi.fix_pathinfo = 0;" in php.ini + fastcgi_split_path_info ^(.+\.php)(/.+)$; + + # With php5-cgi alone: + # fastcgi_pass 127.0.0.1:9000; + + # With php5-fpm: + fastcgi_pass unix:/var/run/php5-fpm.sock; + + include fastcgi_params; + fastcgi_index index.php; + fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; + } + + # deny access to all dot files + location ~ /\. { + deny all; + } + +#deny access to store + + location ~ /store { + deny all; + } + + +} diff --git a/sources/doc/intro_for_developers.bb b/sources/doc/intro_for_developers.bb new file mode 100644 index 00000000..b8a4e4eb --- /dev/null +++ b/sources/doc/intro_for_developers.bb @@ -0,0 +1,114 @@ +[b]Red Developer Guide[/b] + +[b]File system layout:[/b] + +[addon] optional addons/plugins + +[boot.php] Every process uses this to bootstrap the application structure + +[doc] Help Files + +[images] core required images + +[include] The "model" in MVC - (back-end functions), also contains PHP "executables" for background processing + +[index.php] The front-end controller for web access + +[install] Installation and upgrade files and DB schema + +[library] Third party modules (must be license compatible) + +[mod] Controller modules based on URL pathname (e.g. #^[url=http://sitename/foo]http://sitename/foo[/url] loads mod/foo.php) + +[mod/site/] site-specific mod overrides, excluded from git + +[util] translation tools, main English string database and other miscellaneous utilities + +[version.inc] contains current version (auto-updated via cron for the master repository and distributed via git) + +[view] theming and language files + +[view/(css,js,img,php,tpl)] default theme files + +[view/(en,it,es ...)] language strings and resources + +[view/theme/] individual named themes containing (css,js,img,php,tpl) over-rides + +[b]The Database:[/b] + + [li]abook - contact table, replaces Friendica 'contact'[/li] + [li]account - service provider account[/li] + [li]addon - registered plugins[/li] + [li]app - peronal app data[/li] + [li]attach - file attachments[/li] + [li]auth_codes - OAuth usage[/li] + [li]cache - OEmbed cache[/li] + [li]channel - replaces Friendica 'user'[/li] + [li]chat - chat room content[/li] + [li]chatpresence - channel presence information for chat[/li] + [li]chatroom - data for the actual chat room[/li] + [li]clients - OAuth usage[/li] + [li]config - main configuration storage[/li] + [li]conv - Diaspora private messages[/li] + [li]event - Events[/li] + [li]fcontact - friend suggestion stuff[/li] + [li]ffinder - friend suggestion stuff[/li] + [li]fserver - obsolete[/li] + [li]fsuggest - friend suggestion stuff[/li] + [li]groups - privacy groups[/li] + [li]group_member - privacy groups[/li] + [li]hook - plugin hook registry[/li] + [li]hubloc - Red location storage, ties a location to an xchan[/li] + [li]item - posts[/li] + [li]item_id - other identifiers on other services for posts[/li] + [li]likes - likes of 'things'[/li] + [li]mail - private messages[/li] + [li]manage - may be unused in Red, table of accounts that can "su" each other[/li] + [li]menu - channel menu data[/li] + [li]menu_item - items uses by channel menus[/li] + [li]notify - notifications[/li] + [li]notify-threads - need to factor this out and use item thread info on notifications[/li] + [li]obj - object data for things (x has y)[/li] + [li]outq - Red output queue[/li] + [li]pconfig - personal (per channel) configuration storage[/li] + [li]photo - photo storage[/li] + [li]poll - data for polls[/li] + [li]poll_elm - data for poll elements[/li] + [li]profdef - custom profile field definitions[/li] + [li]profext - custom profile field data[/li] + [li]profile - channel profiles[/li] + [li]profile_check - DFRN remote auth use, may be obsolete[/li] + [li]register - registrations requiring admin approval[/li] + [li]session - web session storage[/li] + [li]shares - shared item information[/li] + [li[sign - Diaspora signatures. To be phased out.[/li] + [li]site - site table to find directory peers[/li] + [li]source - channel sources data[/li] + [li]spam - unfinished[/li] + [li]sys_perms - extensible permissions for the sys channel[/li] + [li]term - item taxonomy (categories, tags, etc.) table[/li] + [li]tokens - OAuth usage[/li] + [li]updates - directory sync updates[/li] + [li]verify - general purpose verification structure[/li] + [li]vote - vote data for polls[/li] + [li]xchan - replaces 'gcontact', list of known channels in the universe[/li] + [li]xchat - bookmarked chat rooms[/li] + [li]xconfig - as pconfig but for channels with no local account[/li] + [li]xlink - "friends of friends" linkages derived from poco[/li] + [li]xprof - if this hub is a directory server, contains basic public profile info of everybody in the network[/li] + [li]xtag - if this hub is a directory server, contains tags or interests of everybody in the network[/li] + + +[b]How to theme Red - by Olivier Migeot[/b] + +This is a short documentation on what I found while trying to modify Red's appearance. + +First, you'll need to create a new theme. This is in /view/theme, and I chose to copy 'redbasic' since it's the only available for now. Let's assume I named it . + +Oh, and don't forget to rename the _init function in /php/theme.php to be _init() instead of redbasic_init(). + +At that point, if you need to add javascript or css files, add them to /js or /css, and then "register" them in _init() through head_add_js('file.js') and head_add_css('file.css'). + +Now you'll probably want to alter a template. These can be found in in /view/tpl OR view//tpl. All you should have to do is copy whatever you want to tweak from the first place to your theme's own tpl directory. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/macros/addons_footer.bb b/sources/doc/macros/addons_footer.bb new file mode 100644 index 00000000..32814c59 --- /dev/null +++ b/sources/doc/macros/addons_footer.bb @@ -0,0 +1,2 @@ +Return to the [zrl=[baseurl]/help/addons]Addons documentation[/zrl] +Return to the [zrl=[baseurl]/help/main]Main documentation[/zrl] diff --git a/sources/doc/macros/cloud_footer.bb b/sources/doc/macros/cloud_footer.bb new file mode 100644 index 00000000..798cc9ea --- /dev/null +++ b/sources/doc/macros/cloud_footer.bb @@ -0,0 +1,2 @@ +Return to the [zrl=[baseurl]/help/cloud]Cloud documentation[/zrl] +Return to the [zrl=[baseurl]/help/main]Main documentation page[/zrl] diff --git a/sources/doc/macros/de/addons_footer.bb b/sources/doc/macros/de/addons_footer.bb new file mode 100644 index 00000000..068bb7ec --- /dev/null +++ b/sources/doc/macros/de/addons_footer.bb @@ -0,0 +1,2 @@ +Zurück zur [zrl=[baseurl]/help/addons]Addons-Hilfe[/zrl] +Zurück zur [zrl=[baseurl]/help/main]Hilfe-Startseite[/zrl] diff --git a/sources/doc/macros/de/cloud_footer.bb b/sources/doc/macros/de/cloud_footer.bb new file mode 100644 index 00000000..921448a3 --- /dev/null +++ b/sources/doc/macros/de/cloud_footer.bb @@ -0,0 +1,2 @@ +Zurück zur [zrl=[baseurl]/help/cloud]Cloud-Hilfe[/zrl] +Zurück zur [zrl=[baseurl]/help/main]Hilfe-Startseite[/zrl] diff --git a/sources/doc/macros/de/main_footer.bb b/sources/doc/macros/de/main_footer.bb new file mode 100644 index 00000000..e7160362 --- /dev/null +++ b/sources/doc/macros/de/main_footer.bb @@ -0,0 +1 @@ +Zurück zur [zrl=[baseurl]/help/main]Hilfe-Startseite[/zrl] diff --git a/sources/doc/macros/de/troubleshooting_footer.bb b/sources/doc/macros/de/troubleshooting_footer.bb new file mode 100644 index 00000000..be8c13a2 --- /dev/null +++ b/sources/doc/macros/de/troubleshooting_footer.bb @@ -0,0 +1,2 @@ +Zurück zur [zrl=[baseurl]/help/troubleshooting]Troubleshooting-Startseite[/zrl] +Zurück zur [zrl=[baseurl]/help/troubleshooting]Hilfe-Startseite[/zrl] diff --git a/sources/doc/macros/main_footer.bb b/sources/doc/macros/main_footer.bb new file mode 100644 index 00000000..08f671de --- /dev/null +++ b/sources/doc/macros/main_footer.bb @@ -0,0 +1 @@ +Return to the [zrl=[baseurl]/help/main]Main documentation page[/zrl] diff --git a/sources/doc/macros/troubleshooting_footer.bb b/sources/doc/macros/troubleshooting_footer.bb new file mode 100644 index 00000000..c7603a62 --- /dev/null +++ b/sources/doc/macros/troubleshooting_footer.bb @@ -0,0 +1,2 @@ +[zrl=[baseurl]/help/troubleshooting]Troubleshooting documentation[/zrl] +[zrl=[baseurl]/help/troubleshooting]Documentation Main Page[/zrl] diff --git a/sources/doc/main.bb b/sources/doc/main.bb new file mode 100644 index 00000000..6998ee90 --- /dev/null +++ b/sources/doc/main.bb @@ -0,0 +1,86 @@ + +[zrl=[baseurl]/help/about][b]What is $Projectname?[/b][/zrl] +$Projectname is a decentralized communication and publishing platform that enables you to keep in control of your communication needs by automatic encryption and finely grained access control. It's you, and only you who decides who is allowed to see your stuff. + +[zrl=[baseurl]/help/features][b]$Projectname Features[/b][/zrl] + +$Projectname is already running as a global distributed network and proves its versatility and scalability from standalone to huge sites on a daily basis. +Think of standalone family communication platforms, distributed online communities, support forums, blogs and homepages. Or professional content providers with commercial premium channels and targeted content acces. Whatever you want, the $Projectname is there to cater to your creativity. + +[zrl=[baseurl]/help/what_is_zot][b]Got Zot? Well, you should.[/b][/zrl] +Zot is the great new communicaton protocol invented especially for $Projectname. As a member you are no longer bound to a single site or hub thanks to "Nomadic Identities". Migrate easily to another server and keep your contacts intact, or clone it and run the same channel on several servers. Just in case one of them might shut down, you don't lose out. Plus once you are inside $Projectname there is no need for you to authenticate twice, even when accessing another $Projectname site. Zot is what sets $Projectname apart. + +[h3]Getting Started[/h3] +[zrl=[baseurl]/help/Privacy]Privacy Policy[/zrl] +[zrl=[baseurl]/help/registration]Account Registration[/zrl] +[zrl=[baseurl]/help/accounts_profiles_channels_basics]You at the $Projectname: accounts, profiles and channels in short[/zrl] +[zrl=[baseurl]/help/profiles]Profiles[/zrl] +[zrl=[baseurl]/help/channels]Channels[/zrl] +[zrl=[baseurl]/help/roles]Permission roles and Channel types[/zrl] +[zrl=[baseurl]/help/first-post]Your first posting[/zrl] +[zrl=[baseurl]/help/connecting_to_channels]Connecting To Other Channels[/zrl] +[zrl=[baseurl]/help/permissions]Permissions And Encryption: You Are In Control[/zrl] +[zrl=[baseurl]/help/cloud]Cloud Storage[/zrl] +[zrl=[baseurl]/help/remove_account]Remove Channel or Account[/zrl] + +[h3]Members Help[/h3] +[zrl=[baseurl]/help/tags_and_mentions]Tags and Mentions[/zrl] +[zrl=[baseurl]/help/webpages]Web Pages[/zrl] +[zrl=[baseurl]/help/bbcode]BBcode reference for posts and comments[/zrl] +[zrl=[baseurl]/help/checking_account_quota_usage]Checking Account Quota Usage[/zrl] +[zrl=[baseurl]/help/cloud_desktop_clients]Cloud Desktop Clients[/zrl] +[zrl=[baseurl]/help/AdvancedSearch]Advanced Directory Search[/zrl] +[zrl=[baseurl]/help/addons]Help With Addons[/zrl] +[zrl=[baseurl]/help/diaspora_compat]Diaspora Communications Compatibility (Diaspora and Friendica)[/zrl] +[zrl=[baseurl]/help/faq_members]FAQ For Members[/zrl] + +[h3]Administrators Help[/h3] +[zrl=[baseurl]/help/install]Install[/zrl] +[zrl=[baseurl]/help/red2pi]Installing Red on the Raspberry Pi[/zrl] +[zrl=[baseurl]/help/troubleshooting]Troubleshooting Tips[/zrl] +[zrl=[baseurl]/help/hidden_configs]Tweaking $Projectname's Hidden Configurations[/zrl] +[zrl=[baseurl]/help/faq_admins]FAQ For Admins[/zrl] +[zrl=[baseurl]/help/service_classes]Service Classes[/zrl] + +[h3]Technical Documentation[/h3] +[zrl=[baseurl]/help/history]$Projectname history[/zrl] +[zrl=[baseurl]/help/Zot---A-High-Level-Overview]A high level overview of Zot[/zrl] +[zrl=[baseurl]/help/zot]An introduction to Zot[/zrl] +[zrl=[baseurl]/help/zot_structures]Zot Stuctures[/zrl] +[zrl=[baseurl]/help/comanche]Comanche Page Descriptions[/zrl] +[zrl=[baseurl]/help/Creating-Templates]Creating Comanche Templates[/zrl] +[zrl=[baseurl]/help/Widgets]Widgets[/zrl] +[zrl=[baseurl]/help/plugins]Plugins[/zrl] +[zrl=[baseurl]/help/doco]Contributing Documentation[/zrl] +[zrl=[baseurl]/help/DerivedTheme1]Creating Derivative Themes[/zrl] +[zrl=[baseurl]/help/schema_development]Schemas[/zrl] +[zrl=[baseurl]/help/Translations]Translations[/zrl] +[zrl=[baseurl]/help/developers]Developers[/zrl] +[zrl=[baseurl]/help/intro_for_developers]Intro for Developers[/zrl] +[zrl=[baseurl]/help/database]Database schema documantation[/zrl] +[zrl=[baseurl]/help/api_functions]API functions[/zrl] +[zrl=[baseurl]/help/api_posting]Posting to the red# using the API[/zrl] +[zrl=[baseurl]/help/developer_function_primer]Red Functions 101[/zrl] +[zrl=[baseurl]/doc/html/]Code Reference (Doxygen generated - sets cookies)[/zrl] +[zrl=[baseurl]/help/to_do_doco]To-Do list for the Red Documentation Project[/zrl] +[zrl=[baseurl]/help/to_do_code]To-Do list for Developers[/zrl] +[zrl=[baseurl]/help/roadmap]Version 3 roadmap[/zrl] +[zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl] +[zrl=[baseurl]/help/dev_beginner]Step-for-step manual for beginning developers[/zrl] + +[h3]Frequently Asked Questions For Developers[/h3] +[zrl=[baseurl]/help/faq_developers]FAQ For Developers[/zrl] + +[h3]External Resources[/h3] +[zrl=[baseurl]/help/external-resource-links]External Resource Links[/zrl] +[url=https://github.com/redmatrix/hubzilla]Main Website[/url] +[url=https://github.com/redmatrix/hubzilla-addons]Addon Website[/url] +[url=https://zothub.com/channel/one]Development Channel[/url] +[url=https://federated.social/channel/postgres]Postgres-specific $Projectname Admin Support Channel[/url] + +[url=[baseurl]/help/credits]$Projectname Credits[/url] + +[h3]About This $Projectname Hub[/h3] +[zrl=[baseurl]/help/TermsOfService]Terms of Service For This Hub[/zrl] +[zrl=[baseurl]/siteinfo]Hub Information (/siteinfo)[/zrl] +[zrl=[baseurl]/siteinfo/json]Detailed Technical Hub Information in JSON format(/siteinfo/json)[/zrl] diff --git a/sources/doc/nb-no/api_functions.md b/sources/doc/nb-no/api_functions.md new file mode 100644 index 00000000..f385dee0 --- /dev/null +++ b/sources/doc/nb-no/api_functions.md @@ -0,0 +1,138 @@ +Red Twitter API +=============== + +Det "grunnleggende" Red web API-et er basert på Twitter API-et, siden dette gir umiddelbar samhandling med et stort antall tredjepartsklienter og programmer uten å kreve noen kodeendring hos disse. Det er også et super-set av StatusNet-versjonen av Twitter API-et, siden den også har bred eksisterende støtte. + +Red har flere muligheter som ikke vises gjennom Twitter-grensesnittene, der vi tvinges til å gjøre API-funksjoner "dummere" for å kunne arbeide med den primitive kommunikasjons- og personvernmodellen i Twitter/StatusNet. Vi planlegger å utvide Twitter-API-et slik at Red-spesifikke klienter kan ta i bruk alle funksjoner i Red uten begrensninger. + +Et dedikert Red API som samvirker med egne datastrukturer og tillatelser er under utvikling, og dette krever ikke oversettelse til andre personvern- og tillatelsesmodeller og lagringsformater. Denne vil bli beskrevet i andre dokumenter. Prefikset for alle egne endepunkter er 'api/red'. + +Red tilbyr tilgang til flere kanaler via samme innloggingskonto. Med Red vil enhver API-funksjon som krever autentisering akseptere et parameter - &channel={channel_nickname} - og vil velge den kanalen og gjøre den gjeldende før utføring av API-kommandoen. Som standard er det standardkanalen i kontoen som velges. + +Red tilbyr også en utvidet tillatelsesmodell. Grunnet fraværet av Red-spesifikke API kall til å angi tillatelser, så vil disse innstillingene bli satt til standardtillatelsene assosiert med den gjeldende kanalen. + +Red vil antakelig aldri helt kunne støtte Twitter sine 'api/friendships' funksjoner, fordi Red er ikke et sosialt nettverk og har ikke innebygget noe konsept om "vennskap" - den gjenkjenner tillatelser til å gjøre ting (eller ikke gjøre ting hvis det er det som trengs). + +Tegnforklaring: T= Twitter, S= StatusNet, F= Friendica, R= Red, ()=Virker ikke ennå, J= kun JSON (XML-formater er avlegs) + + + +Twitter API kompatible funksjoner: + +* api/account/verify_credentials T,S,F,R +* api/statuses/update T,S,F,R +* api/users/show T,S,F,R +* api/statuses/home_timeline T,S,F,R +* api/statuses/friends_timeline T,S,F,R +* api/statuses/public_timeline T,S,F,R +* api/statuses/show T,S,F,R +* api/statuses/retweet T,S,F,R +* api/statuses/destroy T,S,F,(R) +* api/statuses/mentions T,S,F,(R) +* api/statuses/replies T,S,F,(R) +* api/statuses/user_timeline T,S,F,(R) +* api/favorites T,S,F,(R) +* api/account/rate_limit_status T,S,F,R +* api/help/test T,S,F,R +* api/statuses/friends T,S,F,R +* api/statuses/followers T,S,F,R +* api/friends/ids T,S,F,R +* api/followers/ids T,S,F,R +* api/direct_messages/new T,S,F,(R) +* api/direct_messages/conversation T,S,F,(R) +* api/direct_messages/all T,S,F,(R) +* api/direct_messages/sent T,S,F,(R) +* api/direct_messages T,S,F,(R) +* api/oauth/request_token T,S,F,R +* api/oauth/access_token T,S,F,R + + +Twitter API funksjoner støttet av StatusNet men for øyeblikket ikke av Friendica eller Red + +* api/favorites T,S +* api/favorites/create T,S +* api/favorites/destroy T,S +* api/statuses/retweets_of_me T,S +* api/friendships/create T,S +* api/friendships/destroy T,S +* api/friendships/exists T,S +* api/friendships/show T,S +* api/account/update_location T,S +* api/account/update_profile_background_image T,S +* api/account/update_profile_image T,S +* api/blocks/create T,S +* api/blocks/destroy T,S + +Twitter API funksjoner som for øyeblikket ikke er støttet av StatusNet + +* api/statuses/retweeted_to_me T +* api/statuses/retweeted_by_me T +* api/direct_messages/destroy T +* api/account/end_session T,(R) +* api/account/update_delivery_device T +* api/notifications/follow T +* api/notifications/leave T +* api/blocks/exists T +* api/blocks/blocking T +* api/lists T + + +StatusNet kompatible utvidelser til Twitter API-et støttet av både Friendica og Red + +* api/statusnet/version S,F,R +* api/statusnet/config S,F,R + +Friendica API utvidelser til Twitter API-et støttet av både Friendica og Red + +* api/statuses/mediap F,R + + +Red-spesifikke API utvidelser til Twitter API-et som ikke er støttet av Friendica + +* api/account/logout R +* api/export/basic R,J +* api/friendica/config R +* api/red/config R +* api/friendica/version R +* api/red/version R + +* api/red/channel/export/basic R,J +* api/red/channel/stream R,J (currently post only) +* api/red/albums R,J +* api/red/photos R,J (option album=xxxx) + + +Foreslåtte Red API utvidelser til Twitter API-et + +* api/statuses/edit (R),J +* api/statuses/permissions (R),J +* api/statuses/permissions/update (R),J +* api/statuses/ids (R),J # søk etter eksisterende message_id før importering av fremmed innlegg +* api/files/show (R),J +* api/files/destroy (R),J +* api/files/update (R),J +* api/files/permissions (R),J +* api/files/permissions/update (R),J +* api/pages/show (R),J +* api/pages/destroy (R),J +* api/pages/update (R),J +* api/pages/permissions (R),J +* api/pages/permissions/update (R),J +* api/events/show (R),J +* api/events/update (R),J +* api/events/permissions (R),J +* api/events/permissions/update (R),J +* api/events/destroy (R),J +* api/photos/show (R),J +* api/photos/update (R),J +* api/photos/permissions (R),J +* api/photos/permissions/update (R),J +* api/albums/destroy (R),J +* api/albums/show (R),J +* api/albums/update (R),J +* api/albums/permissions (R),J +* api/albums/permissions/update (R),J +* api/albums/destroy (R),J +* api/friends/permissions (R),J + + diff --git a/sources/doc/nomadic-identity.bb b/sources/doc/nomadic-identity.bb new file mode 100644 index 00000000..a062e58c --- /dev/null +++ b/sources/doc/nomadic-identity.bb @@ -0,0 +1 @@ +This still needs to be written. diff --git a/sources/doc/permissions.bb b/sources/doc/permissions.bb new file mode 100644 index 00000000..bcf3c43e --- /dev/null +++ b/sources/doc/permissions.bb @@ -0,0 +1,110 @@ +[b]Permissions[/b] + +Permissions in the $Projectname are more complete than you may be used to. This allows us to define more fine graded relationships than the black and white "this person is my friend, so they can do everything" or "this person is not my friend, so they can't do anything" permissions you may find elsewhere. + +[b]Default Permissions[/b] + +On your settings page, you will find a list of default permissions. These permissions are automatically applied to everybody unless you specify otherwise. The scope of these permissions varies from "Only me" to "Everybody" - though some scopes may not be available for some permissions. For example, you can't allow "anybody on the internet" to send you private messages, because we'd have no way to identify the sender, therefore no way to reply to them. + +We highly recommend that you use the "typical social network" settings when you create your first channel, as it allows others to communicate with you and help you out if you have difficulty. You will find that these settings allow you as much privacy as you desire - when you desire it; but also allow you to communicate in public if you choose to. You are free to use much more private settings once you have learned your way around. + +Be aware that altering the scope of who can see your "public" items is a more or less [b]permanent[/b] change. Your public items have no identified permissions attached to them - they are public. If you restrict who can see these items, there is no way of making any single item public ever again - without allowing access to every public item you ever created. You are certainly free to do this, but beware of the consequences. + +A more useful privacy setup is to leave "public" items visible to anybody on the internet; but force everything you create to be restricted. This can be done on your Channel Settings page by selecting the role "Social - restricted". This ensures a Default Privacy Group for all new contacts, and sets your Default Post Permissions to restrict all your posts to that group. We use the Default Post Permissions for everything you create - posts, photos, events, webpages, and everything else. However you can then edit the permissions when you create any individual thing and remove your default privacy group to make just that item visible to anybody. + + + +The scopes of permissions are: + +[li]Nobody Except Yourself. This is self explanatory. Only you will be allowed access.[/li] + +[li]Only those you specifically allow. By default, people you are not connected to, and all new contacts will have this permission denied. You will be able to make exceptions for individual channels on their contact edit screen.[/li] + +[li]Anybody in your address book. Anybody you do not know will have this permission denied, but anybody you accept as a contact will have this permission approved. This is the way most legacy platforms handle permissions.[/li] + +[li]Anybody On This Hub. Anybody using the same hub as you will have permission approved. Anybody who registered at a different hub will have this permission denied.[/li] + +[li]Anybody in this network. Anybody in the $Projectname will have this permission approved. Even complete strangers. However, anybody not logged in/authenticated will have this permission denied.[/li] + +[li]Anybody authenticated. This is similar to "anybody in this network" except that it can include anybody who can authenticate by any means - and therefore may include visitors from other networks.[/li] + +[li]Anybody on the internet. Completely public. This permission will be approved for anybody at all.[/li] + +The individual permissions are: + +[i]Can view my "public" stream and posts.[/i] + +This permision determines who can view your channel "stream" that is, the non-private posts that appear on the "home" tab when you're logged in. + +[i]Can view my "public" channel profile.[/i] + +This permission determines who can view your channel's profile. This refers to the "about" tab + +[i]Can view my "public" photo albums.[/i] + + This permission determines who can view your photo albums. Individual photographs may still be posted to a more private audience. + +[i]Can view my "public" address book.[/i] + +This permission determines who can view your contacts. These are the connections displayed in the "View connections" section. + +[i]Can view my "public" file storage.[/i] + +This permission determines who can view your public files stored in your cloud. + +[i]Can view my "public" pages.[/i] + +This permission determines who can view your public web pages. + +[i]Can send me their channel stream and posts.[/i] + +This permission determines whose posts you will view. If your channel is a personal channel (ie, you as a person), you would probably want to set this to "anyone in my address book" at a minimum. A personal notes channel would probably want to choose "nobody except myself". Setting this to "Anybody in the network" will show you posts from complete strangers, which is a good form of discovery. + +[i]Can post on my channel page ("wall").[/i] + +This permission determines who can write to your wall when clicking through to your channel. + +[i]Can comment on my posts.[/i] + +This permission determines who can comment on posts you create. Normally, you would want this to match your "can view my public stream and posts" permission + +[i]Can send me private mail messages.[/i] + +This determines who can send you private messages (zotmail). + +[i]Can post photos to my photo albums.[/i] + +This determines who can post photographs in your albums. This is very useful for forum-like channels where connections may not be connected to each other. + +[i]Can forward to all my channel contacts via post tags.[/i] + +Using @- mentions will reproduce a copy of your post on the profile specified, as though you posted on the channel wall. This determines if people can post to your channel in this way. + +[i]Can chat with me (when available).[/i] + +This determines who can join the public chat rooms created by your channel. + +[i]Can write to my "public" file storage.[/i] + +This determines who can upload files to your public file storage, or 'cloud'. + +[i]Can edit my "public" pages.[/i] + +This determines who can edit your webpages. This is useful for wikis or sites with multiple editors. + +[i]Can administer my channel resources.[/i] + +This determines who can have full control of your channel. This should normally be set to "nobody except myself". + +[i]Note:[/i] +Plugins/addons may provide special permission settings, so you may be offered additional permission settings beyond what is described here. + +If you have set any of these permissions to "only those I specifically allow", you may specify indivudal permissions on the connnection edit screen. + +[b]Affinity[/b] + +The connection edit screen offers a slider to select a degree of friendship with the connnection (this tool is enabled through the "Extra Features" tab of your Settings page). Think of this as a measure of how much you like or dislike them. 1 is for people you like, whose posts you want to see all the time. 99 is for people you don't care for, and whose posts you might only wish to look at occasionally. Once you've assigned a value here, you can use the affinity tool on the matrix page to filter content based on this number. + +The slider on the matrix page has both a minimum and maximum value. Posts will only be shown from people who fall between this range. Affinity has no relation to permissions, and is only useful in conjunction with the affinity tool feature. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/plugins.bb b/sources/doc/plugins.bb new file mode 100644 index 00000000..f7427603 --- /dev/null +++ b/sources/doc/plugins.bb @@ -0,0 +1,264 @@ +[b]Plugins[/b] + +So you want to make the $Projectname do something it doesn't already do. There are lots of ways. But let's learn how to write a plugin or addon. + + +In your $Projectname folder/directory, you will probably see a sub-directory called 'addon'. If you don't have one already, go ahead and create it. +[code] + mkdir addon +[/code] +Then figure out a name for your addon. You probably have at least a vague idea of what you want it to do. For our example I'm going to create a plugin called 'randplace' that provides a somewhat random location for each of your posts. The name of your plugin is used to find the functions we need to access and is part of the function names, so to be safe, use only simple text characters. + +Once you've chosen a name, create a directory beneath 'addon' to hold your working file or files. +[code] + mkdir addon/randplace +[/code] +Now create your plugin file. It needs to have the same name, and it's a PHP script, so using your favourite editor, create the file +[code] + addon/randplace/randplace.php +[/code] +The very first line of this file needs to be +[code] + <?php +[/code] +Then we're going to create a comment block to describe the plugin. There's a special format for this. We use /* ... */ comment-style and some tagged lines consisting of +[code] + /** + * + * Name: Random Place (here you can use better descriptions than you could in the filename) + * Description: Sample $Projectname plugin, Sets a random place when posting. + * Version: 1.0 + * Author: Mike Macgirvin <mike@zothub.com> + * + */ +[/code] +These tags will be seen by the site administrator when he/she installs or manages plugins from the admin panel. There can be more than one author. Just add another line starting with 'Author:'. + +The typical plugin will have at least the following functions: +[code] + pluginname_load() + pluginname_unload() +[/code] +In our case, we'll call them randplace_load() and randplace_unload(), as that is the name of our plugin. These functions are called whenever we wish to either initialise the plugin or remove it from the current webpage. Also if your plugin requires things like altering the database schema before it can run for the very first time, you would likely place these instructions in the functions named +[code] + pluginname_install() + pluginname_uninstall() +[/code] + +Next we'll talk about **hooks**. Hooks are places in the $Projectname code where we allow plugins to do stuff. There are a [lot of these](help/Hooks), and they each have a name. What we normally do is use the pluginname_load() function to register a "handler function" for any hooks you are interested in. Then when any of these hooks are triggered, your code will be called. + +We register hook handlers with the 'register_hook()' function. It takes 3 arguments. The first is the hook we wish to catch, the second is the filename of the file to find our handler function (relative to the base of your $Projectname installation), and the third is the function name of your handler function. So let's create our randplace_load() function right now. + +[code] + function randplace_load() { + register_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook'); + + register_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings'); + register_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post'); + + } +[/code] + +So we're going to catch three events, 'post_local' which is triggered when a post is made on the local system, 'feature_settings' to set some preferences for our plugin, and 'feature_settings_post' to store those settings. + +Next we'll create an unload function. This is easy, as it just unregisters our hooks. It takes exactly the same arguments. +[code] + function randplace_unload() { + unregister_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook'); + + unregister_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings'); + unregister_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post'); + + } +[/code] + +Hooks are called with two arguments. The first is always $a, which is our global App structure and contains a huge amount of information about the state of the web request we are processing; as well as who the viewer is, and what our login state is, and the current contents of the web page we're probably constructing. + +The second argument is specific to the hook you're calling. It contains information relevant to that particular place in the program, and often allows you to look at, and even change it. In order to change it, you need to add '&' to the variable name so it is passed to your function by reference. Otherwise it will create a copy and any changes you make will be lost when the hook process returns. Usually (but not always) the second argument is a named array of data structures. Please see the "hook reference" (not yet written as of this date) for details on any specific hook. Occasionally you may need to view the program source to see precisely how a given hook is called and how the results are processed. + +Let's go ahead and add some code to implement our post_local hook handler. +[code] + function randplace_post_hook($a, &$item) { + + /** + * + * An item was posted on the local system. + * We are going to look for specific items: + * - A status post by a profile owner + * - The profile owner must have allowed our plugin + * + */ + + logger('randplace invoked'); + + if(! local_channel()) /* non-zero if this is a logged in user of this system */ + return; + + if(local_channel() != $item['uid']) /* Does this person own the post? */ + return; + + if(($item['parent']) || (! is_item_normal($item))) { + /* If the item has a parent, or is not "normal", this is a comment or something else, not a status post. */ + return; + } + + /* Retrieve our personal config setting */ + + $active = get_pconfig(local_channel(), 'randplace', 'enable'); + + if(! $active) + return; + /** + * + * OK, we're allowed to do our stuff. + * Here's what we are going to do: + * load the list of timezone names, and use that to generate a list of world cities. + * Then we'll pick one of those at random and put it in the "location" field for the post. + * + */ + + $cities = array(); + $zones = timezone_identifiers_list(); + foreach($zones as $zone) { + if((strpos($zone,'/')) && (! stristr($zone,'US/')) && (! stristr($zone,'Etc/'))) + $cities[] = str_replace('_', ' ',substr($zone,strpos($zone,'/') + 1)); + } + + if(! count($cities)) + return; + $city = array_rand($cities,1); + $item['location'] = $cities[$city]; + + return; + } +[/code] + +Now let's add our functions to create and store preference settings. +[code] + /** + * + * Callback from the settings post function. + * $post contains the global $_POST array. + * We will make sure we've got a valid user account + * and that only our own submit button was clicked + * and if so set our configuration setting for this person. + * + */ + + function randplace_settings_post($a,$post) { + if(! local_channel()) + return; + if($_POST['randplace-submit']) + set_pconfig(local_channel(),'randplace','enable',intval($_POST['randplace'])); + } + + + + /** + * + * Called from the Feature Setting form. + * The second argument is a string in this case, the HTML content region of the page. + * Add our own settings info to the string. + * + * For uniformity of settings pages, we use the following convention + * <div class="settings-block"> + * <h3>title</h3> + * .... settings html - many elements will be floated... + * <div class="clear"></div> <!-- generic class which clears all floats --> + * <input type="submit" name="pluginnname-submit" class="settings-submit" ..... /> + * </div> + */ + + + + function randplace_settings(&$a,&$s) { + + if(! local_channel()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + head_add_css(/addon/randplace/randplace.css'); + + /* Get the current state of our config variable */ + + $enabled = get_pconfig(local_channel(),'randplace','enable'); + + $checked = (($enabled) ? ' checked="checked" ' : ''); + + /* Add some HTML to the existing form */ + + $s .= '<div class="settings-block">'; + $s .= '<h3>' . t('Randplace Settings') . '</h3>'; + $s .= '<div id="randplace-enable-wrapper">'; + $s .= '<label id="randplace-enable-label" for="randplace-checkbox">' . t('Enable Randplace Plugin') . '</label>'; + $s .= '<input id="randplace-checkbox" type="checkbox" name="randplace" value="1" ' . $checked . '/>'; + $s .= '</div><div class="clear"></div>'; + + /* provide a submit button */ + + $s .= '<div class="settings-submit-wrapper" ><input type="submit" name="randplace-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>'; + + } + +[/code] + + + +***Advanced Plugins*** + +Sometimes your plugins want to provide a range of new functionality which isn't provided at all or is clumsy to provide using hooks. In this case your plugin can also act as a 'module'. A module in our case refers to a structured webpage handler which responds to a given URL. Then anything which accesses that URL will be handled completely by your plugin. + +The key to this is to create a simple function named pluginname_module() which does nothing. +[code] + function randplace_module() { return; } +[/code] +Once this function exists, the URL #^[url=https://yoursite/randplace]https://yoursite/randplace[/url] will access your plugin as a module. Then you can define functions which are called at various points to build a webpage just like the modules in the mod/ directory. The typical functions and the order which they are called is +[code] + modulename_init($a) // (e.g. randplace_init($a);) called first - if you wish to emit json or xml, + // you should do it here, followed by killme() which will avoid the default action of building a webpage + modulename_aside($a) // Often used to create sidebar content + modulename_post($a) // Called whenever the page is accessed via the "post" method + modulename_content($a) // called to generate the central page content. This function should return a string + // consisting of the central page content. +[/code] +Your module functions have access to the URL path as if they were standalone programs in the Unix operating system. For instance if you visit the page +[code] + https://yoursite/randplace/something/somewhere/whatever +[/code] +we will create an argc/argv list for use by your module functions +[code] + $x = argc(); $x will be 4, the number of path arguments after the sitename + + for($x = 0; $x < argc(); $x ++) + echo $x . ' ' . argv($x); + + + 0 randplace + 1 something + 2 somewhere + 3 whatever +[/code] + +If you want to keep your plugin hidden from the siteinfo page, simply create a file called '.hidden' in your addon directory +[code] + touch addon//.hidden +[/code] + +***Porting Friendica Plugins*** + +The $Projectname uses a similar plugin architecture to the Friendica project. The authentication, identity, and permissions systems are completely different. Many Friendica can be ported reasonably easily by renaming a few functions - and then ensuring that the permissions model is adhered to. The functions which need to be renamed are: + +[li] Friendica's pluginname_install() is pluginname_load()[/li] + +[li] Friendica's pluginname_uninstall() is pluginname_unload()[/li] + +The $Projectname has _install and _uninstall functions but these are used differently. + +[li] Friendica's "plugin_settings" hook is called "feature_settings"[/li] + +[li] Friendica's "plugin_settings_post" hook is called "feature_settings_post"[/li] + +Changing these will often allow your plugin to function, but please double check all your permission and identity code because the concepts behind it are completely different in the $Projectname. Many structured data names (especially DB schema columns) are also quite different. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/problems-following-an-update.bb b/sources/doc/problems-following-an-update.bb new file mode 100644 index 00000000..3bc7e9a5 --- /dev/null +++ b/sources/doc/problems-following-an-update.bb @@ -0,0 +1,38 @@ +[b]Problems Following An Update[/b] + +A good 90% of all bugs encountered immediately after updating the code to the latest version are simple cache errors of one sort or another. If you update and find something very obvious is broken - like your matrix page doesn't load, notifications are missing, or comment boxes are missing - the chances are it's not a bug at all. Breaking basic functionality is the kind of thing developers tend to notice. + +If this happens to you, there are a few simple steps to take before resorting to the support forums: + +[b]Browser Cache[/b] + +Symptoms: Menus do not expand, ACL selector does not open, progress indicator does not display (or loops forever), Matrix and channel pages do not load. + +Force reload the page. Shift reload, or ctrl+f5. Occasionally, but very, very rarely, you will also need to clear the session data - which is achieved by restarting the browser. + +[b]FastCGI[/b] + +Symptoms: Incorrect variables. The basic UI mostly works, but displays incorrect content or is missing content entirely. + +If you're using php5-fpm, this problem is usually resolved with [code]service php5-fpm restart[/code] + +[b]Smarty Cache[/b] + +Symptoms: + +1) White Screen Of Death. This is most prevalent on the settings and admin pages. + +2) Missing icons, tabs, menus or features. + +We use the Smarty3 template engine to generate pages. These templates are compiled before they are displayed. Occasionally, a new or modified template will fail to overwrite the old compiled version. To clear the Smarty cache, delete all the files in store/[data]/smarty3/compiled [b]but do not delete the directory itself[/b]. Templates will then be recompiled on their next access. + +[b]Theme Issues[/b] + +There are many themes for The $Projectname. Only Redbasic is officialy supported by the core developers. This applies [i]even if a core developer happens to support an additional theme[/i]. This means new features are only guaranteed to work in Redbasic. + +Redbasic uses a few javascript libraries that are done differently, or entirely absent in other themes. This means new features may only work properly in Redbasic. Before reporting an issue, therefore, you should switch to Redbasic to see if it exists there. If the issue goes away, this is not a bug - it's a theme that isn't up to date. + +Should you report an issue with the theme developers then? No. Theme developers use their themes. Chances are, they know. Give them two or three days to catch up and [i]then[/i] report the issue if it's still not fixed. There are two workarounds for this situation. Firstly, you can temporarily use Redbasic. Secondly, most themes are open source too - open a pull request and make yourself a friend. + +#include doc/macros/troubleshooting_footer.bb; + diff --git a/sources/doc/profiles.bb b/sources/doc/profiles.bb new file mode 100644 index 00000000..cae51a9c --- /dev/null +++ b/sources/doc/profiles.bb @@ -0,0 +1,37 @@ +[b]Profiles[/b] + +Red has unlimited profiles. You may use different profiles to show different "sides of yourself" to different audiences. This is different to having different channels. Different channels allow for completely different sets of information. You may have a channel for yourself, a channel for your sports team, a channel for your website, or whatever else. A profile allows for finely graded "sides" of each channel. For example, your default public profile might say "Hello, I'm Fred, and I like laughing". You may show your close friends a profile that adds "and I also enjoy dwarf tossing". + +You always have a profile known as your "default" or "public" profile. This profile is always available to the general public and cannot be hidden (there may be rare exceptions on privately run or disconnected sites). You may, and probably should restrict the information you make available on your public profile. + +That said, if you want other friends to be able to find you, it helps to have the following information in your public profile... + +[ul][*]Your real name or at least a nickname everybody knows +[*]A photo of you +[*]Your location on the planet, at least to a country level.[/ul] + +In addition, if you'd like to meet people that share some general interests with you, please take a moment and add some "Keywords" to your profile. Such as "music, linux, photography" or whatever. You can add as many keywords as you like. + +To create an alternate profile, first go to [zrl=[baseurl]/settings/features]Settings > Additional Features[/zrl] and enable "Multiple Profiles" there, otherwise you won't have the ability to use more than just your default profile. + +Then select "Edit Profiles" from the menu of your $Projectname site. You may edit an existing profile, change the profile photo, add things to a profile or create a new profile. You may also create a "clone" of an existing profile if you only wish to change a few items but don't wish to enter all the information again. To do that, click on the profile you want to clone and choose "Clone this profile" there. + +In the list of your profiles, you can also choose the contacts who can see a specific profile. Just click on "Edit visibility" next to the profile in question (only available for the profiles that are not your default profile) and then click on user images to add them to or remove them from the group of people who can see this profile. + +Once a profile has been selected, when the person views your profile, they will see the private profile you have assigned. If they are not authenticated, they will see your public profile. + +There is a setting which allows you to publish your profile to a directory and ensure that it can be found by others. You can change this setting on the "Settings" page. + +If you do not wish to be found be people unless you give them your channel address, you may leave your profile unpublished. + +[b]Keywords and Directory Search[/b] + +On the directory page, you may search for people with published profiles. Currently, only the name field and the keywords are searched. You may also include such keywords in your default profile - which may be used to search for common interests with other members. Keywords are used in the channel suggestion tool and although they aren't visible in the directory, they are shown if people visit your profile page. + +On your Connnections page and in the directory there is a link to "Suggestions" or "Channel Suggestions", respectively. This will find channels who have matching and/or similar keywords. The more keywords you provide, the more relevant the search results that are returned. These are sorted by relevance. + +See Also + +[zrl=[baseurl]/help/AdvancedSearch]Advanced Searching[/zrl] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/red2pi.bb b/sources/doc/red2pi.bb new file mode 100644 index 00000000..18e7d325 --- /dev/null +++ b/sources/doc/red2pi.bb @@ -0,0 +1,342 @@ +[b]How to install the $Projectname on a Raspberry Pi[/b] + +You just bought a Raspberry Pi and want to run the RED Matrix with your own domain name? + +Then this page is for you! You will: +[list=1] +[*] Install Raspberry OS (Debian Linux) on a Raspberry +[*] Install Apache Web Server, PHP, MaySQL, phpMyAdmin +[*] Register a free domain (dynamic DNS) and use it for your hub +[*] Install $Projectname +[*] Keep your Raspberry Pi and $Projectname up-to-date +[*] TODO Setting up SSL +[*] TODO Running with SSL +[*] TODO Make the webserver less vulnarable to attacks +[/list] + +[size=large]1. Install Raspberry OS (Debian Linux)[/size] + +instructions under [url=http://www.raspberrypi.org/downloads]http://www.raspberrypi.org/downloads[/url] +This page links to the quick start containing detailed instruction. + +[b]Format SD card[/b] + +using the program gparted under Linux Mint 15 + +format as FAT32 + +[b]Download NOOBS (offline and network install)[/b] + +[url=http://downloads.raspberrypi.org/noobs]http://downloads.raspberrypi.org/noobs[/url] + +unzip + +copy unzipped files to SD card + +[b]Install Raspbian as OS on the Rasperry Pi[/b] + +connect with keyboard via USB + +connect with monitor via HDMI + +Insert SD card into Rasperry Pi + +Connect with power supply to switch on the Rasperry + +choose Raspbian as OS (> installs Raspbian....) + +wait for the coniguration program raspi-config (you can later start it by sudo raspi-config) + +[b]Configure Raspbian[/b] + +in raspi-config > advanced > choose to use ssh (!! You need this to connect to administrate your Pi from your PC !!) + +in raspi-config > change the password (of default user "pi" from "raspberry" to your password) + +in raspi-config (optional) > Internationalisation options > Change Locale > to de_DE.utf-8 utf-8 (for example) + +in raspi-config (optional) > Internationalisation options > Change Timezoe > set your timezone + +in raspi-config (optional) > Overlock > medium + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[b]More[/b] + +[code]sudo reboot[/code] + +Now its time to connect the Pi to the network. +[ul] +[*] pull out keyboard +[*] pull out monitor +[*] you even can pull out the power supply (USB) +[*] plug-in the network cable to the router +[*] plug-in the power supply again +[*] wait for a minute or to give the Pi time to boot and start ssh... +[/ul] + +On your PC connect to the Pi to administrate (here update it). +Open the console on the PC (Window: Start > cmd, Linux: Shell) + +Hint: use the router admin tool to find out the IP of your PI[code]ssh pi@192.168.178.37 +sudo apt-get update +sudo apt-get dist-upgrade[/code] + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + + +[size=large]2. Install Apache Web Server, PHP, MaySQL, phpMyAdmin[/size] + +[b]Install Apache Webserver[/b] + +[code]sudo bash +sudo groupadd www-data[/code] might exist already + +[code]sudo usermod -a -G www-data www-data +sudo apt-get update +sudo reboot[/code] + +wait... +reconnect via ssh, example: [code]ssh pi@192.168.178.37 +sudo apt-get install apache2 apache2-doc apache2-utils[/code] + +Open webbrowser on PC and check [url=http://192.168.178.37]http://192.168.178.37[/url] +Should show you a page like "It works" + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[b]Install PHP, MaySQL, phpMyAdmin[/b] + +[code]sudo bash +apt-get install libapache2-mod-php5 php5 php-pear php5-xcache php5-curl +apt-get install php5-mysql +apt-get install mysql-server mysql-client[/code] enter and note the mysql passwort + +[code]apt-get install phpmyadmin[/code] + +Configuring phpmyadmin +- Select apache2 +- Configure database for phpmyadmin with dbconfig-common?: Choose Yes + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[b]Test installation[/b] + +[code]cd /var/www[/code] + +create a php file to test the php installation[code]sudo nano phpinfo.php[/code] + +Insert into the file:[code] +<?php + phpinfo(); +?> +[/code] +(save CTRL+0, ENTER, CTRL+X) + +open webbrowser on PC and try [url=http://192.168.178.37/phpinfo.php]http://192.168.178.37/phpinfo.php[/url] (page shows infos on php) + +connect phpMyAdmin with MySQL database [code]nano /etc/apache2/apache2.conf[/code] +- CTRL+V... to the end of the file +- Insert at the end of the file: (save CTRL+0, ENTER, CTRL+X)[code]Include /etc/phpmyadmin/apache.conf[/code] + +restart apache[code]/etc/init.d/apache2 restart +sudo apt-get update +sudo apt-get upgrade +sudo reboot[/code] + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[b]phpMyAdmin[/b] + +open webbrowser on PC and try #^[url=http://192.168.178.37/phpmyadmin]http://192.168.178.37/phpmyadmin[/url] + +(Source [url=http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#]http://www.manfred-steger.de/tuts/20-der-eigene-webserver-mit-dem-raspberry-pi#[/url]) + + +[b]Create an empty database... that is later used by RED[/b] + +open webbrowser on PC and try #^[url=http://192.168.178.37/phpmyadmin]http://192.168.178.37/phpmyadmin[/url] + +Create an empty database + +Note the access details (hostname, username, password, database name). + + +[size=large]3. Selfhost[/size] + +(Source: #^[url=http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html]http://www.techjawab.com/2013/06/setup-dynamic-dns-dyndns-for-free-on.html[/url]) + +[url=http://freedns.afraid.org/signup/]http://freedns.afraid.org/signup/[/url] + +[b]Step 1[/b] +Register for a Free domain at #^[url=http://freedns.afraid.org/signup/]http://freedns.afraid.org/signup/[/url] +(We will take techhome.homenet.org in this guide) + +[b]Step 2[/b] + +Logon to FreeDNS (where you just registered) and goto #^[url=http://freedns.afraid.org/dynamic/]http://freedns.afraid.org/dynamic/[/url] +Right click on "Direct Link" and copy the URL and paste it somewhere. +You should notice a large and unique alpha-numeric key in the URL, make a note of it as shown below: +[code]http://freedns.afraid.org/dynamic/update.php?alphanumeric-key[/code] + + +[b]Step 3[/b] +Install inadyn using the following command:[code]sudo apt-get install inadyn[/code] + +[b]Step 4[/b] +Configure inadyn using the below steps:[code]sudo nano /etc/inadyn.conf[/code] +And add the following contains in it replacing the actual values: +[code] +--username [color=red]techhome[/color] +--password [color=red]mypassword[/color] +--update_period 3600 +--forced_update_period 14400 +--alias [color=red]techhome.homenet.org</b>,[color=red]alphanumeric key[/color] +--background +--dyndns_system default@freedns.afraid.org +--syslog + [/code] + + +[b]Step 5[/b] + +Now, we need to ensure that the DNS updater (Inadyn) runs automatically after every re-boot[code]export EDITOR=gedit && sudo crontab -e[/code] +Add the following line:[code]@reboot /usr/sbin/inadyn[/code] + + +[b]Step 6[/b] + +Reboot system and then run the following command to ensure inadyn is running:[code] +sudo reboot +ps -A | grep inadyn +[/code] +Now your host is ready and up for accessing from internet... +You can trying ssh-ing from another computer over the internet +[code]ssh username@techhome.homenet.org[/code] +Or, if any web server is running, then simply browse to #^[url=http://techhome.homenet.org]http://techhome.homenet.org[/url] +Or, you can just ping it to test ping techhome.homenet.org +To check the logs you can use this: +[code]more /var/log/messages |grep INADYN[/code] + + +[size=large]4. Install $Projectname[/size] + +(Source: [zrl=[baseurl]/help/Install][baseurl]/help/Install[/zrl]) + +Linux Appache document root is /var/www/ +Two files exist there (created by the steps above): index.html, phpinfo.php + + +[b]Install $Projectname and its Addons[/b] + +Cleanup: Remove the directory www/ (Git will not create files and folders in directories that are not empty.) Make sure you are in directory var[code]pi@pi /var $ cd /var[/code] + +Remove directory[code]pi@pi /var $ sudo rm -rf www/[/code] + +Download the sources of $Projectname from GIT +[code]pi@pi /var $ sudo git clone https://github.com/redmatrix/hubzilla.git www[/code] + +Download the sources of the addons from GIT +[code]pi@pi /var/www $ sudo git clone https://github.com/redmatrix/hubzilla-addons.git addon[/code] + +Make user www-data the owner of the whole web directory (including subdirectories and files) +(TODO: This step has to be proofed by the next installation.) +[code]pi@pi /var $ chown -R www-data:www-data /var/www/[/code] + +Check if you can update the sources from git[code] +pi@pi /var $ cd www +pi@pi /var/www $ git pull +[/code] + +Check if you can update the addons +[code]pi@pi /var/www $ cd addon/ +pi@pi /var/www/addon $ sudo git pull[/code] + +Make sure folder store/[data]/smarty3 exists and is writable by the webserver +[code]pi@pi /var/www $ sudo chmod ou+w "store/\[data\]/smarty3"[/code] + +Create .htconfig.php and is writable by the webserver +[code]pi@pi /var/www $ sudo touch .htconfig.php +pi@pi /var/www $ sudo chmod ou+w .htconfig.php[/code] + +[b]First start and initial configuration of your RED Matrix hub[/b] + +In browser open #^[zrl=http://einervonvielen.mooo.com/]http://einervonvielen.mooo.com/[/zrl] +(Replace einervonvielen.mooo.com by your domain, see chapter selfhost. Be patient. It takes time.) +(#^[zrl=http://einervonvielen.mooo.com/index.php?q=setup]http://einervonvielen.mooo.com/index.php?q=setup[/zrl]) + +There might be errors like the following. + +Error: libCURL PHP module required but not installed. +Solution: +apt-get install php5-curl + +Error: Apache webserver mod-rewrite module is required but not installed. +Solution +(Source: [url=http://xmodulo.com/2013/01/how-to-enable-mod_rewrite-in-apache2-on-debian-ubuntu.html]http://xmodulo.com/2013/01/how-to-enable-mod_rewrite-in-apache2-on-debian-ubuntu.html[/url]) +The default installation of Apache2 comes with mod_rewrite installed. To check whether this is the case, verify the existence of /etc/apache2/mods-available/rewrite.load +- pi@pi /var/www $ nano /etc/apache2/mods-available/rewrite.load + (You should find the contendt: LoadModule rewrite_module /usr/lib/apache2/modules/mod_rewrite.so) +To enable and load mod_rewrite, do the rest of steps. +Create a symbolic link in /etc/apache2/mods-enabled +- pi@pi /var/www $ sudo a2enmod rewrite +Then open up the following file, and replace every occurrence of "AllowOverride None" with "AllowOverride all". +- pi@pi /var/www $ sudo nano /etc/apache2/sites-available/default +Finally, restart Apache2. +- pi@pi /var/www $ sudo service apache2 restart + +Error store is writable (not checked) +Solution: +(TODO: Make writeable to group www-data only?) +pi@pi /var/www $ sudo mkdir store +pi@pi /var/www $ chown -R www-data:www-data /var/www/red/ +pi@pi /var/www $ sudo chmod ou+w view + +[b]More[/b] + +Set up a cron job to run the poller once every 15 minutes in order to perform background processing. +- pi@pi /var/www $ which php +Make sure you are in the document root directory of the webserver +- pi@pi /var/www $ cd /var/www/ +Try to execute the poller in order to make sure it works +- pi@pi /var/www $ /usr/bin/php include/poller.php +Create the cronjob +- pi@pi /var/www $ crontab -e +Enter +- */15 * * * * cd /var/www/; /usr/bin/php include/poller.php +- Save and exit. + +Prevent search engines from indexing your search pages. Why? This can cause heavy resource use. + +[code] +php util/config system block_public_search 1 +[/code] + + + +[size=large]5. Keep your Raspberry Pi and your $Projectname up-to-date[/size] + +Git update every day at 4 am and addons at 5 am every day +Try if the command is working +- pi@pi /var/www $ sudo git pull +Create the cronjob +- pi@pi /var/www $ crontab -e +Enter the following to update at 4:01 am every day +- 01 04 * * * cd /var/www/; sudo git pull +Enter the following to update the addons at 5:01 am every day +- 01 05 * * * cd /var/www/addon/; sudo git pull +Enter the following to update the Raspberry Pi (Raspbian OS = Debian) at 6:01 am every day +- 01 06 * * * sudo aptitude -y update && sudo aptitude -y safe-upgrade +Save and exit. + +[size=large]6. Running with SSL[/size] + +Follow the instructions here: +[url=https://github.com/friendica/friendica/wiki/Running-Friendica-with-SSL]https://github.com/friendica/friendica/wiki/Running-Friendica-with-SSL[/url] + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/registration.bb b/sources/doc/registration.bb new file mode 100644 index 00000000..31d69622 --- /dev/null +++ b/sources/doc/registration.bb @@ -0,0 +1,35 @@ +[size=large][b]Registration[/b][/size] + +Not all $Projectname sites allow open registration. If registration is allowed, you will see a "Register" link immediately below the login prompts on the site home page. Following this link will take you to the site Registration page. On some sites it may redirect you to another site which allow registrations. As all $Projectname sites are linked, it does not matter where your account resides. + +[b]Your Email Address[/b] + +Please provide a valid email address. Your email address is never published. This address will be used to activate your account, to (optionally) send email notifications for incoming messages or items, [i]and to recover lost passwords[/i]. + +[b]Password[/b] + +Enter a password of your choice, and repeat it in the second box to ensure it was typed correctly. As the $Projectname offers a decentralised identity, your account can log you in to many other websites. + +[b]Terms Of Service[/b] + +Click the link to read the site's [zrl=[baseurl]/help/TermsOfService]Terms of Service[/zrl]. Once you've read them, tick the box in the register form to confirm. + +[b]Register[/b] + +Once you have provided the necessary details, click the 'Register' button. Some sites may require administrator approval before the registration is processed, and you will be alerted if this is the case. Please watch your email (including spam folders) for your registration approval. + +[b]Create a Channel[/b] + +Next, you will be presented with the "Add a channel" screen. Normally, your first channel will be one that represents you - so using your own name (or psuedonym) as the channel name is a good idea. The channel name should be thought of as a title, or brief description of your channel. The "choose a short nickname" box is similar to a "username" field. We will use whatever you enter here to create a channel address, which other people will use to connect to you, and you will use to log in to other sites. This looks like an email address, and takes the form nickname@siteyouregisteredat.xyz + +When your channel is created you will be taken straight to your settings page where you can define permissions, enable features, etc. All these things are covered in the appropriate section of the helpfiles. + +See Also +[zrl=[baseurl]/help/accounts_profiles_channels_basics]The Basics about Identities within the $Projectname[/zrl] +[zrl=[baseurl]/help/accounts]Accounts[/zrl] +[zrl=[baseurl]/help/profiles]Profiles[/zrl] +[zrl=[baseurl]/help/permissions]Permissions[/zrl] +[zrl=[baseurl]/help/remove_account]Remove Account[/zrl] + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/remove_account.bb b/sources/doc/remove_account.bb new file mode 100644 index 00000000..704f0b94 --- /dev/null +++ b/sources/doc/remove_account.bb @@ -0,0 +1,27 @@ +[b]Remove Channel or Account[/b] + +[b]Remove Channel[/b] + +Go to the bottom of your channel settings page or visit the URL: + + [baseurl]/removeme + +You will need to confirm your password and the channel you are currently logged into will be removed. + +This is irreversible. + +If you have identity clones on other hubs this only removes by default the channel instance which exists on this hub. + +[b]Remove Account[/b] + +Go to the bottom of your account settings page or visit the URL: + + [baseurl]/removeaccount + +You will need to confirm your password and the account you are currently logged into will be removed. + +This is irreversible. + +All your channels will be deleted. If you have identity clones on other hubs this only removes by default the channels instances which exists on this hub. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/roadmap.bb b/sources/doc/roadmap.bb new file mode 100644 index 00000000..f57c76b7 --- /dev/null +++ b/sources/doc/roadmap.bb @@ -0,0 +1,59 @@ + + +Roadmap for $Projectname V3 + +*HZ = Hubzilla repository + + +Crypto + Convert E2EE to dynamic loading (on demand) using jQuery.getScript() [or other methods] to only load encryption libs when you require them. This should also support multiple encryption libraries (e.g. SJCL, others) triggered from the choice of algorithm and remain pluggable. + +Diaspora + Convert core Diaspora federation code into a plugin. This presents a number of challenges since it touches and special cases a lot of core functionality. (HZ - in progress) + +Subscriptions and business models + Build enough into core(/addons) to generate income (or at least try and cover costs) out of the box (in progress Habeas Codice) + +Merge all uploads into common DAV interface + Separate photo albums from photos and turn them into file directories. (HZ - done) + Upload everything direct to /store (HZ - done) + If photo, generate thumbnails and image resources (HZ - done) + Provide default upload folders with %y (and other?) macros for both photos and other file resources (HZ - done) + Allow "media" (anything that we can generate a thumbnail for) in the Photos section (and show thumbnails in the Files section where possible) (HZ - done) + + Resolve the "every photo has an item" confusion, perhaps every file should also - but only if we can explain it and separate them conceptually. + +Migration tools + Friendica importer + Diaspora importer (channel and connection import done, conversations and photos still in progress and waiting for support from Diaspora) + +Webpage design UI improvements + If practical, separate "conversation" sub-themes from overall themes so one can choose different conversation and content layouts within a base theme. + Make webpage building easy, with point-n-click selectors to build PDLs + bring back WYSIWYG, which ideally requires a JS abstraction layer so we can use any editor and change it based on mimetype + +Social Networking Federation + Friendica native mode? + Pump.io? + Others? + +Lists + Create a list object to contain arbitrary things for system use + Create a list object to contain arbitrary things for personal use + +Events + Recurring events + +Zot + Provide a way to sync web resources. This could be built on DAV except for preserving resource naming (guids) instead of filenames. + +API extensions + More, more, more. + +Evangelism + More documentation. More, more, more. + Libzot + +DNS abstraction for V3 + Allow a channel to live in an arbitrary "DNS" namespace, for instance "mike@core.hubzilla". Use our directories and zot to find the actual DNS location via redirection. This could potentially allow hubs to be hidden behind tor or alt-roots and accessible only via the matrix. + \ No newline at end of file diff --git a/sources/doc/roles.md b/sources/doc/roles.md new file mode 100644 index 00000000..5d8d0711 --- /dev/null +++ b/sources/doc/roles.md @@ -0,0 +1,66 @@ +Account Permission Roles +======================== + + +##Social + +**Mostly Public** + +The channel is a typical social networking profile. By default posts and published items are public, but one can over-ride this when creating the item and restrict it. You are listed in the directory. Your online presence and connections are visible to others. + + +**Restricted** + +By default all posts and published items are sent to your 'Friends' collection and not made public. New friends are added to this collection. You can over-ride this and create a public post or published item if you desire. You are listed in the directory. Your online presence (for chat) and your connections (friends) are visible to your profile viewers. + +**Private** + +By default all posts and published items are sent to your 'Friends' collection. New friends are added to this collection. You can over-ride this and create a public post or public item if you desire. You are NOT listed in the directory. Only your connections can see your other connections. Your online presence is hidden. + + +##Forum + +**Mostly Public** + +The channel is a typical forum. By default posts and published items are public. Members may post by @mention+ or wall-to-wall post. Posting photos and other published items is blocked. The channel is visible in the directory. Members are added automatically. + + +**Restricted** + +By default all posts and published items are sent to the channel's 'Friends' collection. New friends are added to this collection. Members may post by @mention+ or wall-to-wall post, but posts and replies may also be seen by other receipients of the top-level post who are not members. The channel is visible in the directory. Members must be manually added by the forum owner. + +**Private** + +By default all posts and published items are sent to your 'Friends' collection. New friends are added to this collection. The owner can over-ride this and create a public post or public item if desired. Members cannot. You are NOT listed in the directory. Only your connections can see your other connections. Your online presence is hidden. Members must be manually added by the forum owner. Posting by @mention+ is disabled. Posts can only be made via wall-to-wall posts, and sent to members of the 'Friends' collection. They are not publicly visible. + + +##Feed + + +**Public** + +Similiar to Social - Mostly Public, but tailored for RSS feed sources. Items may be freely republished and sourced. Online presence is meaningless, therefore hidden. New connections are automatically approved. + + +**Restricted** + +Not listed in directory. Online presence is meaningless, therefore hidden. Feed is published only to members of the 'Friends' collection. New connections are automatically added to this collections. Members must be manually approved by the channel owner. + + +##Special + +**Celebrity/Soapbox** + +Listed in directory. Communications are by default public. Online presence is hidden. No commenting or feedback of any form is allowed, though connections have the ability to "like" your profile. + + +**Group Repository** + +A public forum which allows members to post files/photos/webpages. + + +##Custom/Expert Mode + +Set all the privacy and permissions manually to suit your specific needs. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/schema_development.bb b/sources/doc/schema_development.bb new file mode 100644 index 00000000..3d4c84e8 --- /dev/null +++ b/sources/doc/schema_development.bb @@ -0,0 +1,78 @@ +[b]Red Development - A Guide To The Schema System[/b] + +A schema, in a nutshell, is a collection of settings for a bunch of variables to define +certain elements of a theme. A schema is loaded as though it were part of config.php +and has access to all the same information. Importantly, this means it is identity aware, +and can be used to do some interesting things. One could, for example, restrict options +by service class, or present different options to different members. + +By default, we filter only by whether or not expert mode is enabled. If expert mode is +enabled, all options are presented to the member. If it is not, only scheme, background +image, font face, and iconset are available as choices. + +A schema is loaded *after* the member's personal settings. Therefore, to allow a member +to overwrite a particular aspect of a schema you would use the following syntax: +[code] + if (! $foo) + $foo = 'bar'; +[/code] +However, there are circumstances - particularly with positional elements - where it +may be desirable (or necessary) to override a member's settings. In this case, the syntax +is even simpler: +[code] + $foo = 'bar'; +[/code] +Members will not thank you for this, however, so only use it when it is required. + +If no personal options are set, and no schema is selected, we will first try to load a schema +with the file name "default.php". This file should never be included with a theme. If it +is, merge conflicts will occur as people update their code. Rather, this should be defined +by administrators on a site by site basis. +default.php and default.css MUST be symlinks to existing scheme files. + +You schema does not need to - and should not - contain all of these values. Only the values +that differ from the defaults should be listed. This gives you some very powerful options +with very few lines of code. + +Note the options available differ with each theme. The options available with the Redbasic +theme are as follows: + +[li] nav_colour + The colour of the navigation bar. Options are red, black and silver. Alternatively, + one can set $nav_bg_1, $nav_bg_2, $nav_bg_3 and $nav_bg_4 to provide gradient and + hover effects.[/li] +[li] banner_colour + The font colour of the banner element. Accepts an RGB or Hex value.[/li] +[li] bgcolour + Set the body background colour. Accepts an RGB or Hex value.[/li] +[li] background_image + Sets a background image. Accepts a URL or path.[/li] +[li] item_colour + Set the background colour of items. Accepts an RGB or Hex value.[/li] +[li] item_opacity + Set the opacity of items. Accepts a value from 0.01 to 1[/li] +[li] toolicon_colour + Set the colour of tool icons. Accepts an RGB or Hex value.[/li] +[li] toolicon_activecolour + Set the colour of active or hovered icon tools.[/li] +[li] font_size + Set the size of fonts in items and posts. Accepts px or em.[/li] +[li] body_font_size + Sets the size of fonts at the body level. Accepts px or em.[/li] +[li] font_colour + Sets the font colour. Accepts an RGB or Hex value.[/li] +[li] radius + Set the radius of corners. Accepts a numeral, and is always in px.[/li] +[li] shadow + Set the size of shadows shown with inline images. Accepts a numerical + value. Note shadows are not applied to smileys.[/li] +[li] converse_width + Set the maximum width of the content region in px.[/li] +[li] nav_min_opacity[/li] +[li] top_photo[/li] +[li] reply_photo[/li] + +If a your_schema_name.css file is found, the content of this file will be attached to the end of style.css. +This gives the schem developer the possiblity to override any style component. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/service_classes.bb b/sources/doc/service_classes.bb new file mode 100644 index 00000000..e5d4ecfa --- /dev/null +++ b/sources/doc/service_classes.bb @@ -0,0 +1,37 @@ +[b]Service Classes[/b] + +Service classes allow you to set limits on system resources. A GUI to configure this is currently under development. + +As a temporary measure, the following commandline utilities can be used: + +Usage: + +[code]util/service_class[/code] +list service classes + +[code]util/config system default_service_class firstclass[/code] +set the default service class to 'firstclass' + +[code]util/service_class firstclass[/code] +list the services that are part of 'firstclass' service class + +[code]util/service_class firstclass photo_upload_limit 10000000[/code] +set firstclass total photo disk usage to 10 million bytes + +[code]util/service_class --account=5 firstclass[/code] +set account id 5 to service class 'firstclass' (with confirmation) + +[code]util/service_class --channel=blogchan firstclass[/code] +set the account that owns channel 'blogchan' to service class 'firstclass' (with confirmation) + +[b]current limits[/b] +photo_upload_limit - maximum total bytes for photos +total_items - maximum total toplevel posts +total_pages - maximum comanche pages +total_identities - maximum number of channels owned by account +total_channels - maximum number of connections +total_feeds - maximum number of rss feed connections +attach_upload_limit - maximum file upload storage (bytes) +minimum_feedcheck_minutes - lowest setting allowed for polling rss feeds +chatrooms - maximum chatrooms +chatters_inroom - maximum chatters per room diff --git a/sources/doc/sql_conventions.bb b/sources/doc/sql_conventions.bb new file mode 100644 index 00000000..f6a4e251 --- /dev/null +++ b/sources/doc/sql_conventions.bb @@ -0,0 +1,91 @@ +[h1]SQL Conventions[/h1] +[b]Intro[/b] +The following common SQL conventions appear throughout the code in many places. We use a simple DBA (DataBase Abstraction layer) to handle differences between databases. Please be sure to use only standards-compliant SQL. + +[b]Rule One[/b] +Worth Repeating: Don't use non-standard SQL. This goes for addons as well. If you do use non-standard SQL, and the dba funcs are insufficient, do a if()/switch() or similar for all currently supported databases. Currently nothing red# does requires non-standard SQL. + +[b]Using a format string[/b] +[li]Uses sprintf() +To be written +[code]// Example +$r = q("SELECT * FROM profile WHERE uid = %d", + local_channel() +); +[/code][/li] + +[b]Checking bit flags in a where clause[/b] +[li]You must explicitly convert integers to booleans. The easiest way to do this is to compare to 0. +[code]// Example +$r = q("SELECT abook_id, abook_flags, abook_my_perms, abook_their_perms, xchan_hash, xchan_photo_m, xchan_name, xchan_url from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d and not (abook_flags & %d)>0 ", + intval($uid), + intval(ABOOK_FLAG_SELF) +); +[/code] +[/li] +[li]Turning off a flag +[code]$y = q("update xchan set xchan_flags = (xchan_flags & ~%d) where (xchan_flags & %d)>0 and xchan_hash = '%s'", + intval(XCHAN_FLAGS_ORPHAN), + intval(XCHAN_FLAGS_ORPHAN), + dbesc($rr['hubloc_hash']) +);[/code] +[/li] +[li]Turning on a flag +[code]$y = q("update xchan set xchan_flags = (xchan_flags | %d) where xchan_hash = '%s'", + intval(XCHAN_FLAGS_ORPHAN), + dbesc($rr['hubloc_hash']) +);[/code] +[/li] + +[b]Using relative times (INTERVALs)[/b] +[li]Sometimes you want to compare something, like less than x days old. +[code]// Example +$r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_dob > %s + interval %s and abook_dob < %s + interval %s", + db_utcnow(), db_quoteinterval('7 day'), + db_utcnow(), db_quoteinterval('14 day') +);[/code] +[/li] +[b]Paged results[/b] +[li]To be written +[code]// Example +$r = q("SELECT * FROM mail WHERE uid=%d AND $sql_extra ORDER BY created DESC LIMIT %d OFFSET %d", + intval(api_user()), + intval($count), intval($start) +);[/code][/li] + +[b]NULL dates[/b] +[li]To be written +[code]// Example +$r = q("DELETE FROM mail WHERE expires != '%s' AND expires < %s ", + dbesc(NULL_DATE), + db_utcnow() +);[/code][/li] + +[b]Storing binary data[/b] +[li]To be written +[code]// Example +$x = q("update photo set data = '%s', height = %d, width = %d where resource_id = '%s' and uid = %d and scale = 0", + dbescbin($ph->imageString()), + intval($height), + intval($width), + dbesc($resource_id), + intval($page_owner_uid) +);[/code][/li] + +[b]Current timestamp[/b] +[li][code]// Example +$randfunc = db_getfunc('rand'); +$r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_connected > %s - interval %s order by $randfunc limit 1", + db_utcnow(), db_quoteinterval('30 day') +);[/code][/li] + +[b]SQL Function and Operator Abstraction[/b] +[li]Sometimes the same function or operator has a different name/symbol in each database. You use db_getfunc('funcname') to look them up. The string is [i]not[/i] case-sensitive; do [i]not[/i] include parens. +[code]// Example +$randfunc = db_getfunc('rand'); +$r = q("select xchan_url from xchan left join hubloc on hubloc_hash = xchan_hash where hubloc_connected > %s - interval %s order by $randfunc limit 1", + db_utcnow(), db_quoteinterval('30 day') +);[/code][/li] + +#include doc/macros/main_footer.bb; \ No newline at end of file diff --git a/sources/doc/sv/main.bb b/sources/doc/sv/main.bb new file mode 100644 index 00000000..eb35b0b3 --- /dev/null +++ b/sources/doc/sv/main.bb @@ -0,0 +1,84 @@ +[img][baseurl]/assets/hashlogo.png[/img] + +[zrl=[baseurl]/help/about][b]Vad är $Projectname?[/b][/zrl] +$Projectname är en decentraliserad publicerings- och kommunikationsplattform som möjliggör att du behåller kontrollen över dina kommunikationer med hjälp av automatisk kryptering och fininställbar behörighetskontroll. Det är du, och bara du, som beslutar vem som är behörig att ta del av ditt innehåll. + +[zrl=[baseurl]/help/features][b]$Projectname funktioner[/b][/zrl] +$Projectname används redan och bildar ett globalt distribuerad närverk och bevisar* dagligen sin skalbarhet och diversitet i allt från installationer med en kanal till installationer med många användare och många kanaler med en stor mängd innehåll. +Föreställ dig isolerade familjekommunikationsplatformer, distribuerade nätforum med fildelning, hjälpforum, bloggar och hemsidor. Eller proffesionellt anpassade innehållsleverantörer med kommersiella premium* kanaler och målriktat innehållsstyrning. Vad du än önskar så finns $Projectname för att stödja dig i förverkligande av din kreativitet. + +[zrl=[baseurl]/help/what_is_zot][b]Har du Zot? Skaffa det, direkt.[/b][/zrl] +Zot är en fantastisk ny kommunikationsprotokoll uppfunnit speciellt för $Projectname. Som medlem är du inte längre bunden till en enskild sida eller hub tack vara "nomadiska identiteter". Flytt lätt till en annan server och håll dina kontakter och förbindelser intakta eller klona och kör den samma kanal på flera servrar simultant. I tillfälle av att en av dem stänger ner så går du inte miste om något. Plus när du är loggat in i $Projectname så är det inga flera inloggningar även när du kontakter andra hubbar i nätverket. Zot är det som gör $Projectname till något särskilt värdefullt/som urskiljer $Projectname från mängden. + +[h3]Kom igång[/h3] +[zrl=[baseurl]/help/Privacy]Privacy Policy[/zrl] +[zrl=[baseurl]/help/registration]Account Registration[/zrl] +[zrl=[baseurl]/help/accounts_profiles_channels_basics]You at the $Projectname: accounts, profiles and channels in short[/zrl] +[zrl=[baseurl]/help/profiles]Profiles[/zrl] +[zrl=[baseurl]/help/channels]Channels[/zrl] +[zrl=[baseurl]/help/sv/roles]Behörighetsförval för kanaler[/zrl] +[zrl=[baseurl]/help/first-post]Your first posting[/zrl] +[zrl=[baseurl]/help/connecting_to_channels]Connecting To Other Channels[/zrl] +[zrl=[baseurl]/help/permissions]Permissions And Encryption: You Are In Control[/zrl] +[zrl=[baseurl]/help/cloud]Cloud Storage[/zrl] +[zrl=[baseurl]/help/remove_account]Remove Channel or Account[/zrl] + +[h3]Hjälp till medlemmar[/h3] +[zrl=[baseurl]/help/tags_and_mentions]Tags and Mentions[/zrl] +[zrl=[baseurl]/help/webpages]Web Pages[/zrl] +[zrl=[baseurl]/help/bbcode]BBcode reference for posts and comments[/zrl] +[zrl=[baseurl]/help/checking_account_quota_usage]Checking Account Quota Usage[/zrl] +[zrl=[baseurl]/help/cloud_desktop_clients]Cloud Desktop Clients[/zrl] +[zrl=[baseurl]/help/AdvancedSearch]Advanced Directory Search[/zrl] +[zrl=[baseurl]/help/addons]Help With Addons[/zrl] +[zrl=[baseurl]/help/diaspora_compat]Diaspora Communications Compatibility (Diaspora and Friendica)[/zrl] +[zrl=[baseurl]/help/faq_members]FAQ For Members[/zrl] + +[h3]Hjälp till administratorer[/h3] +[zrl=[baseurl]/help/install]Install[/zrl] +[zrl=[baseurl]/help/debian_install]Easy Install on Debian via script[/zrl] +[zrl=[baseurl]/help/red2pi]Installing Red on the Raspberry Pi[/zrl] +[zrl=[baseurl]/help/troubleshooting]Troubleshooting Tips[/zrl] +[zrl=[baseurl]/help/hidden_configs]Tweaking $Projectname's Hidden Configurations[/zrl] +[zrl=[baseurl]/help/faq_admins]FAQ For Admins[/zrl] + +[h3]Teknisk dokumentation[/h3] +[zrl=[baseurl]/help/history]$Projectname history[/zrl] +[zrl=[baseurl]/help/Zot---A-High-Level-Overview]A high level overview of Zot[/zrl] +[zrl=[baseurl]/help/zot]An introduction to Zot[/zrl] +[zrl=[baseurl]/help/zot_structures]Zot Stuctures[/zrl] +[zrl=[baseurl]/help/comanche]Comanche Page Descriptions[/zrl] +[zrl=[baseurl]/help/Creating-Templates]Creating Comanche Templates[/zrl] +[zrl=[baseurl]/help/Widgets]Core Widgets[/zrl] +[zrl=[baseurl]/help/plugins]Plugins[/zrl] +[zrl=[baseurl]/help/doco]Contributing Documentation[/zrl] +[zrl=[baseurl]/help/DerivedTheme1]Creating Derivative Themes[/zrl] +[zrl=[baseurl]/help/schema_development]Schemas[/zrl] +[zrl=[baseurl]/help/Translations]Translations[/zrl] +[zrl=[baseurl]/help/developers]Developers[/zrl] +[zrl=[baseurl]/help/intro_for_developers]Intro for Developers[/zrl] +[zrl=[baseurl]/help/api_functions]API functions[/zrl] +[zrl=[baseurl]/help/api_posting]Posting to the red# using the API[/zrl] +[zrl=[baseurl]/help/developer_function_primer]Red Functions 101[/zrl] +[zrl=[baseurl]/doc/html/]Code Reference (doxygen generated - sets cookies)[/zrl] +[zrl=[baseurl]/help/to_do_doco]To-Do list for the Red Documentation Project[/zrl] +[zrl=[baseurl]/help/to_do_code]To-Do list for Developers[/zrl] +[zrl=[baseurl]/help/roadmap]Version 3 roadmap[/zrl] +[zrl=[baseurl]/help/git_for_non_developers]Git for Non-Developers[/zrl] +[zrl=[baseurl]/help/dev_beginner]Sep-for-step manual for beginning developers[/zrl] + +[h3]FAQ för utvecklare[/h3] +[zrl=[baseurl]/help/faq_developers]FAQ For Developers[/zrl] + +[h3]Externa resurser[/h3] +[zrl=[baseurl]/help/external-resource-links]External Resource Links[/zrl] +[url=https://github.com/friendica/red]Main Website[/url] +[url=https://github.com/friendica/red-addons]Addon Website[/url] +[url=https://zothub.com/channel/one]Development Channel[/url] + +[url=[baseurl]/help/credits]$Projectname Credits[/url] + +[h3]About This $Projectname Hub[/h3] +[zrl=[baseurl]/help/TermsOfService]Terms of Service For This Hub[/zrl] +[zrl=[baseurl]/siteinfo]Hub Information (/siteinfo)[/zrl] +[zrl=[baseurl]/siteinfo_json]Detailed Technical Hub Information (/siteinfo_json)[/zrl] diff --git a/sources/doc/sv/roles.md b/sources/doc/sv/roles.md new file mode 100644 index 00000000..f01b2a2f --- /dev/null +++ b/sources/doc/sv/roles.md @@ -0,0 +1,57 @@ +Kanaltyper och deras behörighetsförval +======================== + + +##Socialt + +**Övervägande offentlig** + +Kanalen är en typisk social nätverksprofil. Som standard är inlägg och publicerade filer offentliga men du kan ändra detta när du skapar innehållet i systemet och begränsa tillgången. Du är listat i katalogen. Din närvarostatus (för chatt) och dina kontakter (vänner) är synliga för andra. + +**Begränsad** + +Som standard delas alla inlägg och publicerade filer med din 'Friends'-krets* och är inte offentligt tillgängliga. Nya vänner läggs till denna krets. Du kan ändra detta och skapa offentliga inlägg eller filer om du så önskar. Du är listat i katalogen. Din närvarostatus (för chatt) och dina kontakter (vänner) är synliga för andra. + +**Privat** + +Som standard delas alla inlägg och publicerade filer med din 'Friends'-krets* och är inte offentligt tillgängliga. Nya vänner läggs till denna krets. Du kan ändra detta och skapa offentliga inlägg eller filer om du så önskar. Du är INTE listat i katalogen. Din närvarostatus är dold. + +##Forum + +**Övervägande offentlig** + +Kanalen är ett typiskt forum. Som standard är inlägg och publicerade filer offentliga. Forummedlemmar kan dela innehåll med forumet via @omnämnaden+ eller vägg-till-vägg inlägg. Skapandet av foton och andra filer är blockerad. Kanalen är listat i katalogen. Medlemmar läggs till automatisk. + +**Begränsad** + +Som standard delas alla inlägg och publicerade filer med din 'Friends'-krets* och är inte offentligt tillgängliga. Forummedlemmar kan dela innehåll med forumet via @omnämnaden+ eller vägg-till-vägg inlägg, men inlägg och svar kan också ses av andra mottagare av toppnivåinlägget. Skapandet av foton och andra filer är blockerad. Kanalen är listat i katalogen. Medlemmar måste läggas till av kanalägaren. + +**Privat** + +Som standard delas alla inlägg och publicerade filer med forumets medlemmar och är inte offentligt tillgängliga. Ägaren av forumet kan dela inlägg eller filer offentligt, men det kan inte medlemmarna. Inlägg kan endast skapas via vägg-till-vägg. Delning av innehåll med forumet via @omnämnaden+ är inaktiverad. Skapandet av foton och andra filer är blockerad. Kanalen är INTE listat i katalogen. Medlemmar måste läggas till av kanalägaren. + +##RSS-flöde + +**Offentlig** + +Lik socialt - övervägande offentlig, men specialanpassad till källor av RSS-flöden*. RSS-innehållet kan fritt delas och källhänvisas i systemet. Närvarostatus är meningslöst och därför inaktiverad. Nya kontakter läggs till automatisk. + +**Begränsad** + +Specialanpassad till källor av RSS-flöden*. RSS-innehållet delas endast med kanalens kontakter. Närvarostatus är meningslöst och därför inaktiverad. Kanalen är INTE listat i katalogen. Kontakter måste läggas till av kanalägaren. + +##Special + +**Berömdheter/envägskanal** + +Kanalen är en speciell social nätverksprofil anpassad till envägskontakt med anhängare. Din närvarostatus är dold. Kommentarer och återkoppling är inaktiverad. Som standard är inlägg och publicerade filer offentliga men du kan ändra detta när du skapar innehållet och begränsa tillgången. Kanalen är listat i katalogen. + +**Grupputrymme** + +Ett offentligt forum som möjliggör för medlemmar att dela filer, foton och webbsidor. + +##Specialanpassad/Expertläge + +Ställ själv in allt ihop så det passar till dina specifika önskemål. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/tags_and_mentions.bb b/sources/doc/tags_and_mentions.bb new file mode 100644 index 00000000..d638492b --- /dev/null +++ b/sources/doc/tags_and_mentions.bb @@ -0,0 +1,69 @@ +[b]Tags And Mentions[/b] + +Like many other platforms, Red uses a special notation inside messages to indicate "tags" or contextual links to other entities. + +[b]Mentions[/b] + +Channels are tagged by simply preceding their name with the @ character. + +[code] +@Jack +[/code] + +When you start to mention somebody, it will create an auto-complete box to select from your immediate connections. Select one as appropriate. + +If the person mentioned is in the list of recipients for the post, they will receive a tag notification. + + +[b]Deliverable Mentions[/b] + +Some connections in the mention auto-complete box behave differently than others. If you mention a channel which provides "re-delivery of mentions" it will also send the post to all of that channel's default delivery connections. This is how one posts to "forums". The auto-complete box will provide two entries for these channels, one will mention just the channel. The other will invoke re-delivery and be listed as the channel's "network". + +[code] +@Gardening - mention the Gardening forum +[/code] + +[code] +@Gardening+ - mention the Gardening Forum and also post to the Gardening "network" (e.g. all the forum members; if you have permission to do so) +[/code] + + + +[b]Private Mentions[/b] + +If you wish to restrict a post to a single person or a number of people, you can do this by selecting channels or collections from the privacy tool. You can also just tag them with a privacy tag. A privacy tag is a name preceded by the two characters @! - and in addition to tagging these channels, will also change the privacy permissions of the post to only include them. You can have more than one privacy tag, for instance @!bob and @!linda will send the post only to Bob and Linda. This mechanism over-rides the privacy selector. + +You may also tag public collections. When you create or edit a collection, there is a checkbox to allow the group members to be seen by others. If this box is checked for a collection and you tag (for instance) @!Friends - the post will be restricted to the Friends collection. Check that the collection is public before doing this - as there is no way to take back a post except to delete it. The collection name will appear in the post and will alert members of that collection that they are members of it. + + +[b]Mentions and Comments[/b] + +The above mechanisms only apply to "top-level" posts you create. Mentioning a channel with any of the above mechanisms has no effect in comments, except that the mentioned channel may receive a notification if they were already included as a recipient in the conversation. + + + + +[b]Topical Tags[/b] + +Topical tags are indicated by preceding the tag name with the # character. This will create a link in the post to a generalised site search for the term provided. For example, #[zrl=https://friendicared.net/search?tag=cars]cars[/zrl] will provide a search link for all posts mentioning 'cars' on your site. Topical tags are generally a minimum of three characters in length. Shorter search terms are not likely to yield any search results, although this depends on the database configuration. + +Topical tags are also not linked if they are purely numeric, e.g. #1. If you wish to use a numeric hashtag, please add some descriptive text such as #[zrl=https://friendicared.net/search?tag=2012-elections]2012-elections[/zrl]. + + +[b]Spaces in Tags and Mentions[/b] + +Where possible please use the auto-complete window to select tag and mention recipients, because it will generate a coded tag which uniquely identifies one channel. Names are sometimes ambiguous. However, you can "manually" tag a channel by matching the channel name or address. + +[code] +@Robert Johnson +[/code] + +will tag Robert Johnson, but we can only match one space. If the name was "Blind Lemon Jefferson" it won't be found unless you enclose the entire name in double quotes or change the spaces to underscores. + +[code] +@"Blind Lemon Jefferson" +@Blind_Lemon_Jefferson +[/code] + +are both equivalent. +#include doc/macros/main_footer.bb; diff --git a/sources/doc/to_do_code.bb b/sources/doc/to_do_code.bb new file mode 100644 index 00000000..7fb6da85 --- /dev/null +++ b/sources/doc/to_do_code.bb @@ -0,0 +1,51 @@ +[b]Project Code To-Do List[/b] + +We need much more than this, but here are areas where developers can help. Please edit this page when items are finished. Another place for developers to start is with the issues list. + +[li]Documentation - see Red Documentation Project To-Do List[/li] +[li]Include TOS link in registration/verification email[/li] +[li](done) forum widget with unread counts (requires the DB schema changes from v3/hubzilla to be viable)[/li] +[li]Create bug tracker module[/li] +[li]translation plugins - moses or apertium[/li] +[li]plugins - provide 'disable' which is softer than 'uninstall' for those plugins which create additional DB tables[/li] +[li]Infinite scroll improvements (i.e. embedded page links) see http://scrollsample.appspot.com/items [/li] +[li]Finish the anti-spam bayesian engine[/li] +[li]implement an email permission denied bounce message from the sys channel[/li] +[li]provide a way for xchans with a certain network type to upgrade (unknown to rss, rss to statusnet, friendica-over-diaspora to friendica, for instance) based on new knowledge and/or redmatrix ability[/li] +[li](done - HZ) If DAV folders exist, add an option to the Settings page to set a default folder for attachment uploads.[/li] +[li]Integrate the "open site" list with the register page[/li] +[li]implement oembed provider interface[/li] +[li]refactor the oembed client interface so that we can safely sandbox remote content[/li] +[li]Many modern social apps now have both a profile photo and a "cover photo". Add support for this. [/li] +[li]Write more webpage layouts[/li] +[li]Write more webpage widgets[/li] +[li]restricted access OAuth clients[/li] +[li](Advanced) create a UI for building Comanche pages[/li] +[li](less advanced) create a way to preview Comanche results on a preview page while editing on another page[/li] +[li](done - HZ) Extend WebDAV to provide desktop access to photo albums[/li] +[li]External post connectors - create standard interface[/li] +[li]External post connectors, add popular services[/li] +[li](in progress Habeas Codice) service classes - provide a pluggable subscription payment gateway for premium accounts[/li] +[li](in progress Habeas Codice) service classes - account overview page showing resources consumed by channel. With special consideration this page can also be accessed at a meta level by the site admin to drill down on problematic accounts/channels.[/li] +[li]Events module - fix permissions on events, and provide JS translation support for the calendar overview (done); integrate with calDAV[/li] +[li]Uploads - integrate #^[url=https://github.com/blueimp/jQuery-File-Upload]https://github.com/blueimp/jQuery-File-Upload[/url][/li] +[li]Import/export - include events, things, etc.[/li] +[li]API extensions, for Twitter API - search, friending, threading. For Red API, lots of stuff[/li] +[li]OAuth permission extensions[/li] +[li]Import channel from Diaspora/Friendica (Diaspora partially done)[/li] +[li]MediaGoblin photo "crosspost" connector[/li] +[li]Create management page/UI for extensible profile fields[/li] +[li]Create interface to include/exclude and re-order standard profile fields[/li] +[li]Provide a mechanism to share page design elements in posts (just like apps) (done)[/li] +[li]App taxonomy[/li] +[li]Customisable App collection pages[/li] +[li]replace the tinymce visual editor and/or make the visual editor pluggable and responsive to different output formats. We probably want library/bbedit for bbcode. This needs a fair bit of work to catch up with our "enhanced bbcode", but start with images, links, bold and highlight and work from there.[/li] +[li]Photos module - turn photos into normal conversations and fix tagging[/li] +[li]Create mobile clients for the top platforms - which involves extending the API so that we can do stuff far beyond the current crop of Twitter/Statusnet clients. Ditto for mobile themes. We can probably use something like the Friendica Android app as a base to start from.[/li] +[li](in progress Habeas Codice) Implement owned and exchangeable "things".[/li] +[li]Family Account creation - using service classes (an account holder can create a certain number of sub-accounts which are all tied to their subscription - if the subscription lapses they all go away).[/li] +[li]Put mod_admin under Comanche[/li] + +In many cases some of the work has already been started and code exists so that you needn't start from scratch. Please contact one of the developer channels like Channel One (one@zothub.com) before embarking and we can tell you what we already have and provide some insights on how we envision these features fitting together. + +Return to the [url=[baseurl]/help/main]Main documentation page[/url] diff --git a/sources/doc/to_do_doco.bb b/sources/doc/to_do_doco.bb new file mode 100644 index 00000000..d0f595b3 --- /dev/null +++ b/sources/doc/to_do_doco.bb @@ -0,0 +1,23 @@ +[b]Documentation To-Do List[/b] + +[b]Documentation we need to write[/b] + + Database schema detailed descriptions + + Complete plugin hook documentation + + API documentation + + Function and code documentation (doxygen) + + New Member guide + + "Extra Feature" reference, description of each + + Detailed Personal Settings Documentation + + Administration Guide (post-install) + + Administration Guide (pre-install) + +Return to the [url=[baseurl]/help/main]Main documentation page[/url] diff --git a/sources/doc/to_do_doco.md b/sources/doc/to_do_doco.md new file mode 100644 index 00000000..018b9efa --- /dev/null +++ b/sources/doc/to_do_doco.md @@ -0,0 +1,31 @@ +# Documentation To-Do List # + +## How to contribute documentation ## + +Documentation files are in */doc*. + +When help is first accessed, the file loaded is *main.bb*. That file contains case sensitive links without an extension. The extensions is added automatically if the file is found, first *.md* then *.bb*. + +For translating documentation, create a directory in */doc* named by the language code, copy the files and translate the content. + +## Documentation we need to write ## + +* Database schema detailed descriptions + +* Complete plugin hook documentation + +* API documentation + +* Function and code documentation (doxygen) + +* New Member guide + +* "Extra Feature" reference, description of each + +* Detailed Personal Settings Documentation + +* Administration Guide (post-install) + +* Administration Guide (pre-install) + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/troubleshooting.bb b/sources/doc/troubleshooting.bb new file mode 100644 index 00000000..1a2bd7f1 --- /dev/null +++ b/sources/doc/troubleshooting.bb @@ -0,0 +1,21 @@ +[b]Troubleshooting[/b] + +[li][zrl=[baseurl]/help/problems-following-an-update]Problems following an update[/zrl][/li] + +When reporting issues, please try to provide as much detail as may be necessary for developers to reproduce the issue and provide the complete text of all error messages. + +The system logfile is an extremely useful resource for tracking down things that go wrong. This can be enabled in the admin/log configuration page. A loglevel setting of LOGGER_DEBUG is preferred for stable production sites. Most things that go wrong with communications or storage are listed here. A setting of LOGGER_DATA provides [b]much[/b] more detail, but may fill your disk. In either case we recommend the use of logrotate on your operating system to cycle logs and discard older entries. + +At the bottom of your .htconfig.php file are several lines (commented out) which enable PHP error logging. This reports issues with code syntax and executing the code and is the first place you should look for issues which result in a "white screen" or blank page. This is typically the result of code/syntax problems. +Database errors are reported to the system logfile, but we've found it useful to have a file in your top-level directory called dbfail.out which [b]only[/b] collects database related issues. If the file exists and is writable, database errors will be logged to it as well as to the system logfile. + +In the case of "500" errors, the issues may often be logged in your webserver logs, often /var/log/apache2/error.log or something similar. Consult your operating system documentation. + +We encourage you to try to the best of your abilities to use these logs combined with the source code in your possession to troubleshoot issues and find their cause. The community is often able to help, but only you have access to your site logfiles and it is considered a security risk to share them. + + +If a code issue has been uncovered, please report it on the project bugtracker (https://github.com/redmatrix/hubzilla/issues). Again provide as much detail as possible to avoid us going back and forth asking questions about your configuration or how to duplicate the problem, so that we can get right to the problem and figure out what to do about it. You are also welcome to offer your own solutions and submit patches. In fact we encourage this as we are all volunteers and have little spare time available. The more people that help, the easier the workload for everybody. It's OK if your solution isn't perfect. Every little bit helps and perhaps we can improve on it. + +#include doc/macros/troubleshooting_footer.bb; +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/webpages.bb b/sources/doc/webpages.bb new file mode 100644 index 00000000..040ad0c5 --- /dev/null +++ b/sources/doc/webpages.bb @@ -0,0 +1,90 @@ +[b]Creating Web Pages[/b] + +Red enables users to create static webpages. To activate this feature, enable the web pages feature in your Additional Features section. + +Once enabled, a new tab will appear on your channel page labelled "Webpages". Clicking this link will take you to the webpage editor. +Pages will be accessible at mydomain/page/username/pagelinktitle + +The "page link title" box allows a user to specify the "pagelinktitle" of this URL. If no page link title is set, we will set one for you automatically, using the message ID of the item. + +Beneath the page creation box, a list of existing pages will appear with an "edit" link. Clicking this will take you to an editor, similar to that of the post editor, where you can make changes to your webpages. + + +[b]Using Blocks[/b] + +Blocks can be parts of webpages. The basic HTML of a block looks like this +[code] +
+ Block Content +
+ +[/code] + +If a block has text/html content type it can also contain menu elements. Sample content of +[code] +

HTML block content

+ [menu]menuname[/menu] + +[/code] +will produce HTML like this +[code] +
+

HTML block content

+
+ +
+
+ +[/code] + +Via the $content macro a block can also contain the actual webpage content. For this create a block with only +[code] + $content + +[/code]as content. + +To make a block appear in the webpage it must be defined in the page layout inside a region. +[code] + [region=aside] + [block]blockname[/block] + [/region] + +[/code] + +The block appearance can be manipulated in the page layout. + +Custom classes can be assigned +[code] + [region=aside] + [block=myclass]blockname[/block] + [/region] + +[/code] +will produce this HTML +[code] +
+ Block Content +
+ +[/code] + +Via the wrap variable a block can be stripped off its wrapping
tag +[code] + [region=aside] + [block][var=wrap]none[/var]blockname[/block] + [/region] + +[/code] +will produce this HTML +[code] + Block Content + +[/code] + + +#include doc/macros/main_footer.bb; + diff --git a/sources/doc/what_is_zot.bb b/sources/doc/what_is_zot.bb new file mode 100644 index 00000000..50df9e39 --- /dev/null +++ b/sources/doc/what_is_zot.bb @@ -0,0 +1,61 @@ +[b]What is Zot?[/b] + +Zot is the protocol that powers the $Projectname, providing three core capabilities: Communications, Identity, and Access Control. + +The functionality it provides can also be described as follows: + + - a relationship online is just a bunch of permissions + - the internet is just another folder + +[b][size=20]Communications[/size][/b] + +Zot is a revolutionary protocol which provides [i]decentralised communications[/i] and [i]identity management[/i] across the matrix. The resulting platform can provide web services comparable to those offered by large corporate providers, but without the large corporate provider and their associated privacy issues, insatiable profit drive, and walled-garden mentality. + +Communications and social networking are an integral part of the matrix. Any channel (and any services provided by that channel) can make full use of feature-rich social communications on a global scale. These communications may be public or private - and private communications comprise not only fully encrypted transport, but also encrypted storage to help protect against accidental snooping and disclosure by rogue system administrators and internet service providers. + +Zot allows a wide array of background services in the matrix, from offering friend suggestions, to directory services. You can also perform other things which would typically only be possibly on a centralized provider - such as "Wall to Wall" posts. Priivate/multiple profiles can be easily created, and web content can be tailored to the viewer via the [i]Affinity Slider[/i]. + +You won't find these features at all on other decentralized communication services. In addition to providing hub (server) decentralization, perhaps the most innovative and interesting Zot feature is its provision of [i]decentralized identity[/i] services. + +[b][size=20]Identity[/size][/b] + +Zot's identity layer is unique. It provides [i]invisible single sign-on[/i] across all sites in the matrix. + +It also provides [i]nomadic identity[/i], so that your communications with friends, family, and or anyone else you're communicating with won't be affected by the loss of your primary communication node - either temporarily or permanently. + +The important bits of your identity and relationships can be backed up to a thumb drive, or your laptop, and may appear at any node in the matrix at any time - with all your friends and preferences intact. + +Crucially, these nomadic instances are kept in sync so any instance can take over if another one is compromised or damaged. This protects you against not only major system failure, but also temporary site overloads and governmental manipulation or censorship. + +Nomadic identity, single sign-on, and Red's decentralization of hubs, we believe, introduce a high degree of degree of [i]resiliency[/i] and [i]persistence[/i] in internet communications, that are sorely needed amidst global trends towards corporate centralization, as well as mass and indiscriminate government surveillance and censorship. + +As you browse the matrix, viewing channels and their unique content, you are seamlessly authenticated as you go, even across completely different server hubs. No passwords to enter. Nothing to type. You're just greeted by name on every new site you visit. + +How does Zot do that? We call it [i]magic-auth[/i], because Red hides the details of the complexities that go into single sign-on logins, and nomadic identities, from the experience of browsing on the matrix. This is one of the design goals of Red: to increase privacy, and freedom on the web, while reducing the complexity and tedium brought by the need to enter new passwords and user names for every different sight that someone might visit online. + +You login only once on your home hub (or any nomadic backup hub you have chosen). This allows you to access any authenticated services provided anywhere in the matrix - such as shopping, blogs, forums, and access to private information. This is just like the services offered by large corporate providers with huge user databases; however you can be a member of this community, as well as a server on this network using a $35 Rasberry Pi. Your password isn't stored on a thousand different sites, or even worse, only on a few sites like Google and Facebook, beyond your direct control. + +You cannot be silenced. You cannot be removed from the matrix, unless you yourself choose to exit it. + +[b][size=20]Access Control[/size][/b] + +Zot's identity layer allows you to provide fine-grained permissions to any content you wish to publish - and these permissions extend across the $Projectname. This is like having one super huge website made up of an army of small individual websites - and where each channel in the matrix can completely control their privacy and sharing preferences for any web resources they create. + +Currently, the matrix supports communications, photo albums, events, and files. This will be extended in the future to provide content management services (web pages) and cloud storage facilities, such as WebDAV and multi-media libraries. Every object and how it is shared and with whom is completely under your control. + +This type of control is available on large corporate providers such as Facebook and Google, because they own the user database. Within the matrix, there is no need for a huge user databaseon your machine - because the matrix [i]is[/i] your user database. It has what is essentially infinite capacity (limited by the total number of hubs online across the internet), and is spread amongst hundreds, and potentially millions of computers. + +Access can be granted or denied for any resource, to any channel, or any group of channels; anywhere within the matrix. Others can access your content if you permit them to do so, and they do not even need to have an account on your hub. Your private photos cannot be viewed, because permission really work; they are not an addon that was added as an afterthought. If you aren't on the list of allowed viewers for a particular photo, you aren't going to look at it. + +[b][size=18]Additional Resources and Links[/size][/b] + +For more detailed, technical information about Zot, check out the following links: + + - [url=https://github.com/friendica/red/wiki/Zot---A-High-Level-Overview]A high level overview[/url] + + - [url=https://github.com/friendica/red/wiki/zot]Zot development specification[/url] + + - [url=https://github.com/redmatrix/hubzilla/blob/master/include/zot.php]Zot reference implementation in PHP[/url] + + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/zot.md b/sources/doc/zot.md new file mode 100644 index 00000000..f8881c55 --- /dev/null +++ b/sources/doc/zot.md @@ -0,0 +1,400 @@ +Intro to Zot +============ + +Zot is a JSON-based web framework for implementing secure decentralised communications and services. + +It differs from many other communication protocols by building communications on top of a decentralised identity and authentication framework. + +The authentication component is similar to OpenID conceptually but is insulated from DNS-based identities. Where possible remote authentication is silent and invisible. This provides a mechanism for internet scale distributed access control which is unobtrusive. + +For example, + +Jaquelina wishes to share photos with Roberto from her blog at "jaquelina.com.xyz", but to nobody else. Roberto maintains his own family website at "roberto.com.xyz". Zot allows Jaquelina to create an access list containing "Roberto" and allow Roberto unhindered access to the photos but without allowing Roberto's brother Marco to see the photos. + +Roberto will only login once to his own website at roberto.com.xyz using his password. After this, no further passwords will be asked for. Marco may also have an account on roberto.com.xyz, but he is not allowed to see Jaquelina's photos. + + +Additionally, zot allows Roberto to use another site - gadfly.com.xyz, and after login to gadfly.com.xyz he can also access Jaquelina's private photos. Jaquelina does not have to do anything extra to allow this, as she has already given access rights of her private photos to Roberto - no matter what site he is logged into. + +Zot also allows basic messaging and communications with anybody else on the Zot network. + +In order to provide this functionality, zot creates a decentralised globally unique identifier for each node on the network. This global identifier is not linked inextricably to DNS, providing the requisite mobility. Many existing decentralised communications frameworks provide the communication aspect, but do not provide remote access control and authentication. Additionally most of these are based on 'webfinger' such that in our example, Roberto would only be recognised if he accessed Jaquelina's photos from roberto.com.xyz - but not from gadfly.com.xyz. + + +The primary issues zot addresses are + +* completely decentralised communications +* insulation from DNS based identity +* node mobility +* invisible or reduced "interaction" remote authentication +* high performance + +We will rely on DNS-based user@host addresses as a "user-friendly" mechanism to let people know where you are, specifically on a named host with a given username, and communication will be carried out to DNS entities using TCP and the web. + +But the underlying protocol will provide an abstraction layer on top of this, so that a communications node (e.g. "identity") can move to an alternate DNS location and (to the best of our ability) gracefully recover from site re-locations and/or maintain pre-existing communication relationships. A side effect of this requirement is the ability to communicate from alternate/multiple DNS locations and service providers and yet maintain a single online identity. + +We will call this overlay network the "grid". Servers attached to this network are known as "hubs" and may support any number of individual identities. + +An identity does not necessarily correspond to a person. It is just something which requires the ability to communicate within the grid. + +The ability to recover will be accomplished by communication to the original location when creating a new or replacement identity, or as a fallback from a stored file describing the identity and their contacts in the case where the old location no longer responds. + +At least on the short term, the mobility of existing content is not a top priority. This may or may not take place at a later stage. The most important things we want to keep are your identity and your friends. + +Addresses which are shared amongst people are user@host, and which describe the **current** local account credentials for a given identity. These are DNS based addresses and used as a seed to locate a given identity within the grid. The machine communications will bind this address to a globally unique ID. A single globally unique ID may be attached or bound to any number of DNS locations. Once an identity has been mapped or bound to a DNS location, communications will consist of just knowing the globally unique address, and what DNS (url) is being used currently (in order to call back and verify/complete the current communication). These concepts will be specified in better detail. + +In order for an identity to persist across locations, one must be able to provide or recover + +* the globally unique ID for that identity +* the private key assigned to that identity +* (if the original server no longer exists) an address book of contacts for that identity. + +This information will be exportable from the original server via API, and/or downloadable to disk or thumb-drive. + +We may also attempt to recover with even less information, but doing so is prone to account hijacking and will require that your contacts confirm the change. + +In order to implement high performance communications, the data transfer format for all aspects of zot is JSON. XML communications require way too much overhead. + +Bi-directional encryption is based on RSA 4096-bit keys expressed in DER/ASN.1 format using the PKCS#8 encoding variant, with AES-256-CBC used for block encryption of variable length or large items. + +Some aspects of well known "federation protocols" (webfinger, salmon, activitystreams, portablecontacts, etc.) may be used in zot, but we are not tied to them and will not be bound by them. The $Projectname project is attempting some rather novel developments in decentralised communications and if there is any need to diverge from such "standard protocols" we will do so without question or hesitation. + +In order to create a globally unique ID, we will base it on a whirlpool hash of the identity URL of the origination node and a psuedo-random number, which should provide us with a 256 bit ID with an extremely low probability of collision (256 bits represents approximately 115 quattuorviginitillion or 1.16 X 10^77 unique numbers). This will be represented in communications as a base64url-encoded string. We will not depend on probabilities however and the ID must also be attached to a public key with public key cryptography used to provide an assurance of identity which has not been copied or somehow collided in whirlpool hash space. + +Basing this ID on DNS provides a globally unique seed, which would not be the case if it was based completely on psuedo-random number generation. + +We will refer to the encoded globally unique uid string as zot_uid + +As there may be more than one DNS location attached/bound to a given zot_uid identity, delivery processes should deliver to all of them - as we do not know for sure which hub instance may be accessed at any given time. However we will designate one DNS location as "primary" and which will be the preferred location to view web profile information. + +We must also provide the ability to change the primary to a new location. A look-up of information on the current primary location may provide a "forwarding pointer" which will tell us to update our records and move everything to the new location. There is also the possibility that the primary location is defunct and no longer responding. In that case, a location which has already been mapped to this zot_uid can seize control, and declare itself to be primary. In both cases the primary designation is automatically approved and moved. A request can also be made from a primary location which requests that another location be removed. + +In order to map a zot_uid to a second (or tertiary) location, we require a secure exchange which verifies that the new location is in possession of the private key for this zot_uid. Security of the private key is thus essential to avoid hijacking of identities. + +Communications will then require + +* zot_uid (string) +* uid_sig +* callback (current location zot endpoint url) +* callback_sig +* spec (int) + +passed with every communique. The spec is a revision number of the applicable zot spec so that communications can be maintained with hubs using older and perhaps incompatible protocol specifications. Communications are verified using a stored public key which was copied when the connection to this zot_uid was first established. + +Key revocation and replacement must take place from the primary hub. The exact form for this is still being worked out, but will likely be a notification to all other bound hubs to "phone home" (to the primary hub) and request a copy of the new key. This communique should be verified using a site or hub key; as the original identity key may have been compromised and cannot be trusted. + +In order to eliminate confusion, there should be exactly one canonical url for any hub, so that these can be indexed and referenced without ambiguity. + +So as to avoid ambiguity of scheme, it is strongly encouraged that all addresses to be https with a "browser valid" cert and a single valid host component (either www.domain.ext or domain.ext, but not both), which is used in all communications. Multiple URLs may be provided locally, but only one unique URL should be used for all zot communications within the grid. + +Test installation which do not connect to the public grid may use non-SSL, but all traffic flowing over public networks should be safe from session-hijacking, preferably with a "browser recognised" cert. + +Where possible, zot encourages the use of "batching" to minimise network traffic between two hubs. This means that site 'A' can send multiple messages to site 'B' in a single transaction, and also consolidate deliveries of identical messages to multiple recipients on the same hub. + +Messages themselves may or may not be encrypted in transit, depending on the private nature of the messages. SSL (strongly encouraged) provides unconditional encryption of the data stream, however there is little point in encrypting public communications which have been designated as having unrestricted visibility. The encryption of data storage and so-called "end-to-end encryption" is outside the scope of zot. It is presumed that hub operators will take adequate safeguards to ensure the security of their data stores and these are functions of application and site integrity as opposed to protocol integrity. + + +## Messages + +Given the constraints listed previously, a zot communique should therefore be a json array of individual messages. These can be mixed and combined within the same transmission. + +Each message then requires: + +* type +* (optional) recipient list + +Lack of a recipient list would indicate an unencrypted public or site level message. The recipient list would contain an array of zot_uid with an individual decryption key, and a common iv. The decryption key is encoded with the recipient identity's public key. The iv is encrypted with the sender's private key. + +All messages should be digitally signed by the sender. + +The type can be one of (this list is extensible): + +* post (or activity) +* mail +* identity +* authenticate + +Identity messages have no recipients and notify the system social graph of an identity update, which could be a new or deleted identity, a new or deleted location, or a change in primary hub. The signature for these messages uses system keys as opposed to identity-specific keys. + +Posts include many different types of activities, such as top-level posts, likes/dislikes, comments, tagging activities, etc. These types are indicated within the message sturcture. + +authenticate messages result in mutual authentication and browser redirect to protected resources on the remote hub such as the ability to post wall-to-wall messages and view private photo albums and events, etc. + +## Discovery + +A well-known url is used to probe a hub for zot capabilities and identity lookups, including the discovery of public keys, profile locations, profile photos, and primary hub location. + +The location for this service is /.well-known/zot-info - and must be available at the root of the chosen domain. + +To perform a lookup, a POST request is made to the discovery location with the following parameters: + +Required: + +address => an address on the target system such as "john" + +Optional + +target => the zot "guid" of the observer for evaluating permissions + +target_sig => an RSA signature (base64url encoded) of the guid + +key => The public key needed to verify the signature + +With no target provided, the permissions returned will be generic permissions +for unknown or unauthenticated observers + +Example of discovery packet for 'mike@zothub.com' + + { + + "success": true, + "guid": "sebQ-IC4rmFn9d9iu17m4BXO-kHuNutWo2ySjeV2SIW1LzksUkss12xVo3m3fykYxN5HMcc7gUZVYv26asx-Pg", + "guid_sig": "Llenlbl4zHo6-g4sa63MlQmTP5dRCrsPmXHHFmoCHG63BLq5CUZJRLS1vRrrr_MNxr7zob_Ykt_m5xPKe5H0_i4pDj-UdP8dPZqH2fqhhx00kuYL4YUMJ8gRr5eO17vsZQ3XxTcyKewtgeW0j7ytwMp6-hFVUx_Cq08MrXas429ZrjzaEwgTfxGnbgeQYQ0R5EXpHpEmoERnZx77VaEahftmdjAUx9R4YKAp13pGYadJOX5xnLfqofHQD8DyRHWeMJ4G1OfWPSOlXfRayrV_jhnFlZjMU7vOdQwHoCMoR5TFsRsHuzd-qepbvo3pzvQZRWnTNu6oPucgbf94p13QbalYRpBXKOxdTXJrGdESNhGvhtaZnpT9c1QVqC46jdfP0LOX2xrVdbvvG2JMWFv7XJUVjLSk_yjzY6or2VD4V6ztYcjpCi9d_WoNHruoxro_br1YO3KatySxJs-LQ7SOkQI60FpysfbphNyvYMkotwUFI59G08IGKTMu3-GPnV1wp7NOQD1yzJbGGEGSEEysmEP0SO9vnN45kp3MiqbffBGc1r4_YM4e7DPmqOGM94qksOcLOJk1HNESw2dQYWxWQTBXPfOJT6jW9_crGLMEOsZ3Jcss0XS9KzBUA2p_9osvvhUKuKXbNztqH0oZIWlg37FEVsDs_hUwUJpv2Ar09k4", + "key": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA7QCwvuEIwCHjhjbpz3Oc\ntyei/Pz9nDksNbsc44Cm8jxYGMXsTPFXDZYCcCB5rcAhPPdZSlzaPkv4vPVcMIrw\n5cdX0tvbwa3rNTng6uFE7qkt15D3YCTkwF0Y9FVZiZ2Ko+G23QeBt9wqb9dlDN1d\nuPmu9BLYXIT/JXoBwf0vjIPFM9WBi5W/EHGaiuqw7lt0qI7zDGw77yO5yehKE4cu\n7dt3SakrXphL70LGiZh2XGoLg9Gmpz98t+gvPAUEotAJxIUqnoiTA8jlxoiQjeRK\nHlJkwMOGmRNPS33awPos0kcSxAywuBbh2X3aSqUMjcbE4cGJ++/13zoa6RUZRObC\nZnaLYJxqYBh13/N8SfH7d005hecDxWnoYXeYuuMeT3a2hV0J84ztkJX5OoxIwk7S\nWmvBq4+m66usn6LNL+p5IAcs93KbvOxxrjtQrzohBXc6+elfLVSQ1Rr9g5xbgpub\npSc+hvzbB6p0tleDRzwAy9X16NI4DYiTj4nkmVjigNo9v2VPnAle5zSam86eiYLO\nt2u9YRqysMLPKevNdj3CIvst+BaGGQONlQalRdIcq8Lin+BhuX+1TBgqyav4XD9K\nd+JHMb1aBk/rFLI9/f2S3BJ1XqpbjXz7AbYlaCwKiJ836+HS8PmLKxwVOnpLMbfH\nPYM8k83Lip4bEKIyAuf02qkCAwEAAQ==\n-----END PUBLIC KEY-----\n", + "name": "Mike Macgirvin", + "name_updated": "2012-12-06 04:59:13", + "address": "mike@zothub.com", + "photo_mimetype": "image/jpeg", + "photo": "https://zothub.com/photo/profile/l/1", + "photo_updated": "2012-12-06 05:06:11", + "url": "https://zothub.com/channel/mike", + "connections_url": "https://zothub.com/poco/mike", + "target": "", + "target_sig": "", + "searchable": false, + "permissions": { + "view_stream": true, + "view_profile": true, + "view_photos": true, + "view_contacts": true, + "view_storage": true, + "view_pages": true, + "send_stream": false, + "post_wall": false, + "post_comments": false, + "post_mail": false, + "post_photos": false, + "tag_deliver": false, + "chat": false, + "write_storage": false, + "write_pages": false, + "delegate": false + }, + "profile": { + "description": "Freedom Fighter", + "birthday": "0000-05-14", + "next_birthday": "2013-05-14 00:00:00", + "gender": "Male", + "marital": "It's complicated", + "sexual": "Females", + "locale": "", + "region": "", + "postcode": "", + "country": "Australia" + }, + "locations": [ + { + "host": "zothub.com", + "address": "mike@zothub.com", + "primary": true, + "url": "https://zothub.com", + "url_sig": "eqkB_9Z8nduBYyyhaSQPPDN1AhSm5I4R0yfcFxPeFpuu17SYk7jKD7QzvmsyahM5Kq7vDW6VE8nx8kdFYpcNaurqw0_IKI2SWg15pGrhkZfrCnM-g6A6qbCv_gKCYqXvwpSMO8SMIO2mjQItbBrramSbWClUd2yO0ZAceq3Z_zhirCK1gNm6mGRJaDOCuuTQNb6D66TF80G8kGLklv0o8gBfxQTE12Gd0ThpUb5g6_1L3eDHcsArW_RWM2XnNPi_atGNyl9bS_eLI2TYq0fuxkEdcjjYx9Ka0-Ws-lXMGpTnynQNCaSFqy-Fe1aYF7X1JJVJIO01LX6cCs-kfSoz29ywnntj1I8ueYldLB6bUtu4t7eeo__4t2CUWd2PCZkY3PKcoOrrnm3TJP5_yVFV_VpjkcBCRj3skjoCwISPcGYrXDufJxfp6bayGKwgaCO6QoLPtqqjPGLFm-fbn8sVv3fYUDGilaR3sFNxdo9mQ3utxM291XE2Pd0jGgeUtpxZSRzBuhYeOybu9DPusID320QbgNcbEbEImO8DuGIxuVRartzEXQF4WSYRdraZzbOqCzmU0O55P836JAfrWjgxTQkXlYCic-DBk-iE75JeT72smCtZ4AOtoFWCjZAABCw42J7JELY9APixZXWriKtjy6JI0G9d3fs6r7SrXr1JMy0", + "callback": "https://zothub.com/post", + "sitekey": "-----BEGIN PUBLIC KEY-----\nMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA1IWXwd/BZuevq8jzNFoR\n3VkenduQH2RpR3Wy9n4+ZDpbrUKGJddUGm/zUeWEdKMVkgyllVA/xHdB7jdyKs1X\nuIet9mIdnzvhdLO/JFD5hgbNG2wpSBIUY6aSNeCFTzszqXmuSXMW5U0Ef5pCbzEA\nnhoCoGL1KAgPqyxnGKUlj7q2aDwC9IRNtAqNyFQL67oT91vOQxuMThjlDhbR/29Q\ncYR4i1RzyahgEPCnHCPkT2GbRrkAPjNZAdlnk9UesgP16o8QB3tE2j50TVrbVc/d\nYRbzC56QMPP9UgUsapNeSJBHji75Ip/E5Eg/kfJC/HEQgyCqjCGfb7XeUaeQ7lLO\nqc7CGuMP+Jqr/cE54/aSHg8boTwxkMp11Ykb+ng17fl57MHTM2RJ99qZ1KBkXezR\nuH1lyvjzeJPxEFr9rkUqc4GH74/AgfbgaFvQc8TS7ovEa5I/7Pg04m7vLSEYc6UF\nYJYxXKrzmZT2TDoKeJzaBBx5MFLhW19l68h9dQ8hJXIpTP0hJrpI+Sr6VUAEfFQC\ndIDRiFcgjz6j7T/x8anqh63/hpsyf2PMYph1+4/fxtSCWJdvf+9jCRM8F1IDfluX\n87gm+88KBNaklYpchmGIohbjivJyru41CsSLe0uinQFvA741W00w6JrcrOAX+hkS\nRQuK1dDVwGKoIY85KtTUiMcCAwEAAQ==\n-----END PUBLIC KEY-----\n" + } + ], + "site": { + "url": "https://zothub.com", + "directory_mode": "primary", + "directory_url": "https://zothub.com/dirsearch" + } + + } + + + +Discovery returns a JSON array with the following components: + +'success' => ('1' or '') Operation was successful if '1'. Otherwise an optional 'message' may be present indicating the source of error. + +'guid' => the guid of the address on the target system + +'guid_sig' => the base64url encoded RSA signature of the guid, signed with the private key associated with that guid. + +'key' => the public key associated with that guid + +'name' => channel name + +'name_updated' => MySQL style timestamp '2012-01-01 00:00:00' when the name was last changed (UTC) + +'address' => "webbie" or user@host address associated with this channel + +'photo' => URL of a profile photo for this channel (ideally 175x175) + +'photo_mimetype' => content-type of the profile photo + +'photo_updated' => MySQL style timestamp when photo was last updated (UTC) + +'url' => location of channel homepage + +'connections_url' => location of Portable Contacts (extended for zot) URL for this channel + +'target' => if a permissions target was specified, it is mirrored + +'target_sig' => if a permissions target was specified, the signature is mirrored. + +'searchable' => ('1' or '') '1' indicates this entry can be searched in a directory + +###Permissions + + +'permisssions' => extensible array of permissions appropriate to this target, values are '1' or '' + + Permissions may include: + +* view_stream + +* view_profile + +* view_photos + +* view_contacts + +* view_storage + +* view_pages + +* send_stream + +* post_wall + +* post_comments + +* post_mail + +* post_photos + +* tag_deliver + +* chat + +* write_storage + +* write_pages + +* delegate + + + +###Profile + + +'profile' => array of important profile fields + +* description + +* birthday YYYY-MM-DD , all fields are optional, any field (such as year) may be zero + +* next_birthday => MySQL datetime string representing the next upcoming birthday, converted from the channel's default timezone to UTC. + +* gender (free form) + +* marital (marital status) + +* sexual (preference) + +* locale (city) + +* region (state) + +* postcode + +* country + + +###Locations + + +'locations' => array of registered locations (DNS locations) this channel may be visible or may be posting from + +Each location is an array of + +'host' => DNS hostname, e.g. example.com + +'address' => the webbie or user@host identifier associated with this location + +'primary' => ('1' or '') whether or not this is the primary location for this channel where files and web pages are generally found + +'url' => url of the root of this DNS location e.g. https://example.com + +'url_sig' => base64url encoded RSA signature of the URL, signed with the channel private key + +'callback' => zot communications endpoint on this site, usually https://example.com/post + +'sitekey' => public key of this site/host + + +###Site + + +'site' => array providing the directory role of the site responding to this request + +'url' => url of this site e.g. https://example.com + +'directory_mode' => one of 'primary', 'secondary', 'normal', or 'standalone' + +'directory_url' => if this is a directory server or standalone, the URL for the directory search module + + + +Magic Auth +========== + + +So-called "magic auth" takes place by a special exchange. On the remote computer, a redirection is made to the zot endpoint with special GET parameters. + +Endpoint: https://example.com/post/name + +where 'name' is the left hand side of the channel webbie, for instance 'mike' where the webbie is 'mike@zothub.com' + +Additionally four parameters are supplied: + +* auth => the webbie of the person requesting access +* dest => the desired destination URL (urlencoded) +* sec => a random string which is also stored locally for use during the verification phase. +* version => the zot revision + +When this packet is received, a zot message is initiated to the auth identity: + + + { + "type":"auth_check", + "sender":{ + "guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA", + "guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q", + "url":"http:\/\/podunk.edu", + "url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY" + }, + "recipients":{ + { + "guid":"ZHSqb3yGar3TYV_o9S-JkD-6o_V4DhUcxtv0VeyX8Kj_ENHPI_M3SyAUucU835-mIayGMmTpqJz3ujPkcavVhA", + "guid_sig":"JsAAXigNghTkkbq8beGMJjj9LBKZn28hZ-pHSsoQuwYWvBJ2lSnfc4r9l--WgO6sucH-SR6RiBo78eWn1cZrh_cRMu3x3LLx4y-tjixg-oOOgtZakkBg4vmOhkKPkci0mFtzvUrpY4YHySqsWTuPwRx_vOlIYIGEY5bRXpnkNCoC8J4EJnRucDrgSARJvA8QQeQQL0H4mWEdGL7wlsZp_2VTC6nEMQ48Piu6Czu5ThvLggGPDbr7PEMUD2cZ0jE4SeaC040REYASq8IdXIEDMm6btSlGPuskNh3cD0AGzH2dMciFtWSjmMVuxBU59U1I6gHwcxYEV6BubWt_jQSfmA3EBiPhKLyu02cBMMiOvYIdJ3xmpGoMY1Cn__vhHnx_vEofFOIErb6nRzbD-pY49C28AOdBA5ffzLW3ss99d0A-6GxZmjsyYhgJu4tFUAa7JUl84tMbq28Tib0HW6qYo6QWw8K1HffxcTpHtwSL5Ifx0PAoGMJsGDZDD1y_r9a4vH5pjqmGrjL3RXJJUy-m4eLV5r7xMWXsxjqu3D8r04_dcw4hwwexpMT1Nwf8CTB0TKb8ElgeOpDFjYVgrqMYWP0XdhatcFtAJI7gsS-JtzsIwON9Kij66-VAkqy_z1IXI0ziyqV1yapSVYoUV1vMScRZ_nMqwiB5rEDx-XLfzko" + } + } + "callback":"\/post", + "version":1, + "secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467", + "secret_sig":"eKV968b1sDkOVdSMi0tLRtOhQw4otA8yFKaVg6cA4I46_zlAQGbFptS-ODiZlSAqR7RiiZQv4E2uXCKar52dHo0vvNKbpOp_ezWYcwKRu1shvAlYytsflH5acnDWL-FKOOgz5zqLLZ6cKXFMoR1VJGG_Od-DKjSwajyV9uVzTry58Hz_w0W2pjxwQ-Xv11rab5R2O4kKSW77YzPG2R5E6Q7HN38FrLtyWD_ai3K9wlsFOpwdYC064dk66X7BZtcIbKtM6zKwMywcfJzvS5_0U5yc5GGbIY_lY6SViSfx9shOKyxkEKHfS29Ynk9ATYGnwO-jnlMqkJC7t149H-sI9hYWMkLuCzaeLP56k2B2TmtnYvE_vHNQjzVhTwuHCIRVr-p6nplQn_P3SkOpYqPi3k_tnnOLa2d3Wtga8ClEY90oLWFJC3j2UkBf_VEOBNcg-t5XO3T-j9O4Sbk96k1Qoalc-QlznbGx4bOVsGkRBBMiH4YUqiiWB_OkFHtdqv7dqGeC-u-B4u9IxzYst46vvmyA3O-Q4APSZ1RY8ITUH0jLTbh6EAV7Oki8pIbOg0t56p-8RlanOZqmFvR-grVSc7Ak1ZcD8NACmvidUpa1B7WEvRcOeffx9lype0bt5XenDnMyx6szevwxZIiM8qGM2lsSk4fu8HI9cW0mLywzZT0" + } + + +auth_check messages MUST be encrypted with AES256CBC. This message is sent to the origination site, which checks the 'secret' to see if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the destination channel's private key and base64url encoded. If everything checks out, a json packet is returned: + + { + "success":1, + "confirm":"q0Ysovd1uQRsur2xG9Tg6bC23ynzw0191SkVd7CJcYoaePy6e_v0vnmPg2xBUtIaHpx_aSuhgAkd3aVjPeaVBmts6aakT6a_yAEy7l2rBydntu2tvrHhoVqRNOmw0Q1tI6hwobk1BgK9Pm0lwOeAo8Q98BqIJxf47yO9pATa0wktOg6a7LMogC2zkkhwOV5oEqjJfeHeo27TiHr1e2WaphfCusjmk27V_FAYTzw05HvW4SPCx55EeeTJYIwDfQwjLfP4aKV-I8HQCINt-2yxJvzH7Izy9AW-7rYU0Il_gW5hrhIS5MTM12GBXLVs2Ij1CCLXIs4cO0x6e8KEIKwIjf7iAu60JPmnb_fx4QgBlF2HLw9vXMwZokor8yktESoGl1nvf5VV5GHWSIKAur3KPS2Tb0ekNh-tIk9u-xob4d9eIf6tge_d3aq1LcAtrDBDLk8AD0bho5zrVuTmZ9k-lBVPr_DRHSV_dlpu088j3ThaBsuV1olHK3vLFRhYCDIO0CqqK5IuhqtRNnRaqhlNN6fQUHpXk2SwHiJ2W36RCYMTnno6ezFk_tN-RA2ly-FomNZoC5FPA9gFwoJR7ZmVFDmUeK3bW-zYTA5vu15lpBPnt7Up_5rZKkr0WQVbhWJmylqOuwuNWbn3SrMQ8rYFZ23Tv300cOfKVgRBaePWQb4" + } + +'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the base64url encoded whirlpool hash of the source guid and guid_sig; signed with the source channel private key. This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. + +#include doc/macros/main_footer.bb; diff --git a/sources/doc/zot_structures.md b/sources/doc/zot_structures.md new file mode 100644 index 00000000..e8a65ff1 --- /dev/null +++ b/sources/doc/zot_structures.md @@ -0,0 +1,62 @@ +Zot Structures +============== + +**Zot signatures** +All signed data in zot is accomplished by performing an RSA sign operation using the private key of the initiator. The binary result is then base64url encoded for transport. + +**Zot encryption** + +Encryption is currently provided by AES256CBC, though additional algorithms MAY be supported. A 32-octet key and 16-octet initialisation vector are randomly generated. The desired data is then encrypted using these generated strings and the result base64url encoded. Then we build an array: + + data: the base64url encoded encrypted data + alg: The chosen algorithm, in this case the string 'aes256cbc'. + key: The randomly generated key, RSA encrypted using the recipients public key, and the result base64url encoded + iv: The randomly generated IV, RDSA encrypted using the recipient's public key, and the result base64url encoded + + + +**The zot basic packet** + +Used for initiating a dialogue with another zot site. This packet MAY be encrypted. The presence of an array element 'iv' indicates encryption has been applied. When sending an 'auth_check' packet type, this packet MUST be encrypted, using the public key of the destination site (the site key, as opposed to a sender key). + + + { + "type":"notify", + "sender":{ + "guid":"kgVFf_1_SSbyqH-BNWjWuhAvJ2EhQBTUdw-Q1LwwssAntr8KTBgBSzNVzUm9_RwuDpxI6X8me_QQhZMf7RfjdA", + "guid_sig":"PT9-TApzpm7QtMxC63MjtdK2nUyxNI0tUoWlOYTFGke3kNdtxSzSvDV4uzq_7SSBtlrNnVMAFx2_1FDgyKawmqVtRPmT7QSXrKOL2oPzL8Hu_nnVVTs_0YOLQJJ0GYACOOK-R5874WuXLEept5-KYg0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q", + "url":"http:\/\/podunk.edu", + "url_sig":"T8Bp7j5DHHhQDCFcAHXfuhUfGk2P3inPbImwaXXF1xJd3TGgluoXyyKDx6WDm07x0hqbupoAoZB1qBP3_WfvWiJVAK4N1FD77EOYttUEHZ7L43xy5PCpojJQmkppGbPJc2jnTIc_F1vvGvw5fv8gBWZvPqTdb6LWF6FLrzwesZpi7j2rsioZ3wyUkqb5TDZaNNeWQrIEYXrEnWkRI_qTSOzx0dRTsGO6SpU1fPWuOOYMZG8Nh18nay0kLpxReuHCiCdxjXRVvk5k9rkcMbDBJcBovhiSioPKv_yJxcZVBATw3z3TTE95kGi4wxCEenxwhSpvouwa5b0hT7NS4Ay70QaxoKiLb3ZjhZaUUn4igCyZM0h6fllR5I6J_sAQxiMYD0v5ouIlb0u8YVMni93j3zlqMWdDUZ4WgTI7NNbo8ug9NQDHd92TPmSE1TytPTgya3tsFMzwyq0LZ0b-g-zSXWIES__jKQ7vAtIs9EwlPxqJXEDDniZ2AJ6biXRYgE2Kd6W_nmI7w31igwQTms3ecXe5ENI3ckEPUAq__llNnND7mxp5ZrdXzd5HHU9slXwDShYcW3yDeQLEwAVomTGSFpBrCX8W77n9hF3JClkWaeS4QcZ3xUtsSS81yLrp__ifFfQqx9_Be89WVyIOoF4oydr08EkZ8zwlAsbZLG7eLXY" + }, + "callback":"\/post", + "version":1, + "secret":"1eaa6613699be6ebb2adcefa5379c61a3678aa0df89025470fac871431b70467", + "secret_sig":"0uShifsvhHnxnPIlDM9lWuZ1hSJTrk3NN9Ds6AKpyNRqf3DUdz81-Xvs8I2kj6y5vfFtm-FPKAqu77XP05r74vGaWbqb1r8zpWC7zxXakVVOHHC4plG6rLINjQzvdSFKCQb5R_xtGsPPfvuE24bv4fvN4ZG2ILvb6X4Dly37WW_HXBqBnUs24mngoTxFaPgNmz1nDQNYQu91-ekX4-BNaovjDx4tP379qIG3-NygHTjFoOMDVUvs-pOPi1kfaoMjmYF2mdZAmVYS2nNLWxbeUymkHXF8lT_iVsJSzyaRFJS1Iqn7zbvwH1iUBjD_pB9EmtNmnUraKrCU9eHES27xTwD-yaaH_GHNc1XwXNbhWJaPFAm35U8ki1Le4WbUVRluFx0qwVqlEF3ieGO84PMidrp51FPm83B_oGt80xpvf6P8Ht5WvVpytjMU8UG7-js8hAzWQeYiK05YTXk-78xg0AO6NoNe_RSRk05zYpF6KlA2yQ_My79rZBv9GFt4kUfIxNjd9OiV1wXdidO7Iaq_Q" + } + + +Type: is the message type. One of 'notify', 'purge' refresh' 'force_refresh', 'auth_check', 'ping' or 'pickup'. The packet contents vary by message type. Here we will describe the 'notify' packet. + +Sender is an array of four components. + +The guid of the sender is typically a 64 character base64url encoded string. This is generated when an identity is created and an attempt is made that it be unique; though this isn't required. + +The guid_sig is the RSA signature of the guid, signed by the sender's private key. + +url is the base url of the location this post is originating from. + +url_sig is the RSA signature of url, signed by the sender's private key. + + +These four elements provide a portable identity. We can contact the URL provided and download a zot info packet to obtain the public key of the sender, and use that to verify the sender guid and the posting URL signatures. + + +callback is a string to be appended onto the url which identifies the zot communications endpoint on this system. It is typically the string "/post". + +version is the zot protocol identifier, to allow future protocol revisions to co-exist. + +secret is a 64-char string which is randomly generated by the sending site. + +secret_sig is the RSA signature of the secret, signed with the sender's private key. + +#include doc/macros/main_footer.bb; diff --git a/sources/extend/addon/matrix/README.md b/sources/extend/addon/matrix/README.md new file mode 100644 index 00000000..ffb55595 --- /dev/null +++ b/sources/extend/addon/matrix/README.md @@ -0,0 +1,6 @@ +hubzilla-addons +================ + +These are addons for hubzilla sites (see https://github.com/redmatrix/hubzilla ) + + diff --git a/sources/extend/addon/matrix/adultphotoflag/adultphotoflag.php b/sources/extend/addon/matrix/adultphotoflag/adultphotoflag.php new file mode 100755 index 00000000..a8b1371a --- /dev/null +++ b/sources/extend/addon/matrix/adultphotoflag/adultphotoflag.php @@ -0,0 +1,28 @@ + + + */ + +function adultphotoflag_load() { + register_hook('get_features','addon/adultphotoflag/adultphotoflag.php','adultphotoflag_get_features'); +} + +function adultphotoflag_unload() { + unregister_hook('get_features','addon/adultphotoflag/adultphotoflag.php','adultphotoflag_get_features'); +} + +function adultphotoflag_get_features(&$a,&$b) { + + $b['tools'][] = array( + 'adult_photo_flagging', + t('Flag Adult Photos'), + t('Provide photo edit option to hide inappropriate photos from default album view'),false); + +} + diff --git a/sources/extend/addon/matrix/bbmath/README b/sources/extend/addon/matrix/bbmath/README new file mode 100644 index 00000000..e2e9f62c --- /dev/null +++ b/sources/extend/addon/matrix/bbmath/README @@ -0,0 +1,3 @@ +Adds a new tag, [tex] that can be used in bbcode. Note that you still also have to use $...$ to get equations correct, i.e. [tex] doesn't eneter math-mode by default. + +Requires images and tmp directory in your Red root directory (e.g. /var/www/red). Must be writable by server (e.g chown -R www-data tmp images). Also requires latex and imagemagick to be installed. diff --git a/sources/extend/addon/matrix/bbmath/bbmath.php b/sources/extend/addon/matrix/bbmath/bbmath.php new file mode 100644 index 00000000..118772dd --- /dev/null +++ b/sources/extend/addon/matrix/bbmath/bbmath.php @@ -0,0 +1,22 @@ + + * + */ + +require_once('phplatex.php'); +function bbmath_load() { + register_hook('bbcode','addon/bbmath/bbmath.php','bbmath_bbcode'); + +} +function bbmath_unload() { + unregister_hook('bbcode','addon/bbmath/bbmath.php','bbmath_bbcode'); +} + +function bbmath_bbcode($a,&$text) { + $text = preg_replace_callback('|\[tex\](.*?)\[/tex\]|',function($m) { return texify($m[1]); },$text); +} diff --git a/sources/extend/addon/matrix/bbmath/gpl.txt b/sources/extend/addon/matrix/bbmath/gpl.txt new file mode 100644 index 00000000..d511905c --- /dev/null +++ b/sources/extend/addon/matrix/bbmath/gpl.txt @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/sources/extend/addon/matrix/bbmath/phplatex.php b/sources/extend/addon/matrix/bbmath/phplatex.php new file mode 100644 index 00000000..cf10cd94 --- /dev/null +++ b/sources/extend/addon/matrix/bbmath/phplatex.php @@ -0,0 +1,139 @@ +300) $dpi=300; + + $back=phplatex_colorhex($br,$bg,$bb); + $fore=phplatex_colorhex($r,$g,$b); + + # Figure out TeX, either to get the right cache entry or to, you know, compile + # Semi-common (ams) symbol packages are included. + $totex = "\\documentclass[14pt,landscape]{extarticle}\n". + "\\usepackage{color}\n". + "\\usepackage{amsmath}\n\\usepackage{amsfonts}\n\\usepackage{amssymb}\n". + $extraprelude."\n". + "\\pagestyle{empty}\n". #removes header/footer; necessary for trim + "\\begin{document}\n". + "\\color[rgb]{".$r.",".$g.",".$b."}\n". + "\\pagecolor[rgb]{".$br.",".$bg.",".$bb."}\n". + $string."\n". + "\\end{document}\n"; + + $strhash = sha1($totex).'.'.$dpi; #file cache entry string: 40-char hash string plus size + $stralt = str_replace("&","&", preg_replace("/[\"\n]/","",$string)); #stuck in the alt and title attributes + #May need some extra safety. + $heredir=getcwd(); + + #Experiment: Tries to adjust vertical positioning, so that rendered TeX text looks natural enough inline with HTML text + #Only descenders are really a problem since HTML's leeway is upwards. + #TODO: This can always use more work. + # Avoid using characters that are part of TeX commands. + # Some things vary per font, e.g. the slash. In the default CM it is a descender, in Times and others it isn't. + $ascenders ="/(b|d|f|h|i|j|k|l|t|A|B|C|D|E|F|G|H|I|J|L|K|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z|\[|\]|\\{|\\}|\(|\)|\/|0|1|2|3|4|5|6|7|8|9|\\#|\*|\?|'|\\\\'|\\\\`|\\\\v)/"; + $monoliners="/(a|c|e|m|n|o|r|s|u|v|w|x|z|-|=|\+|:|.)/"; + $descenders="/(g|j|p|\/|q|y|Q|,|;|\[|\]|\\{|\\}|\(|\)|\#|\\\\LaTeX|\\\\TeX|\\\\c\{)/"; + $deepdescenders="/(\[|\]|\\{|\\}|\(|\)|\\int)/"; + + $ba = preg_match_all($ascenders, $string,$m); + $bm = preg_match_all($monoliners, $string,$m); + $bd = preg_match_all($descenders, $string,$m); + $dd = preg_match_all($deepdescenders, $string,$m); + if ($dd>0) $verticalalign="vertical-align: -25%"; # deep descenders: move down + else if ($bd>0 && $ba==0) $verticalalign="vertical-align: -15%"; # descenders: move down + else if ($bd==0 && $ba>0) $verticalalign="vertical-align: 0%"; # ascenders only: move up/do nothing? + else if ($bd==0 && $ba==0) $verticalalign="vertical-align: 0%"; # neither vertical-align: 0% + else $verticalalign="vertical-align: -15%"; # both ascender and regular descender + + #check image cache, return link if exists + #the vertical-align is to fix text baseline/descender(/tail) details in and on-average sort of way + if (file_exists($heredir.'/images/'.$strhash.'.'.$imgfmt)) + return ''.$stralt.''; + + + #chdir to have superfluous files be created in tmp. (you stiill have to empty this yourself) + error_reporting(0); # not checking existence myself, that would be double. + if (chdir("tmp")===FALSE) { return '[directory access error, fix permissions]'; } #I should chech whether file creation is allowed to give a nice error for that problem case + error_reporting(E_ERROR | E_WARNING | E_PARSE | E_NOTICE); # TODO: set old value + + $tfn = tempnam(getcwd(), 'PTX'); #file in tmp dir + + #write temporary .tex file + if ( ($tex = fopen($tfn.'.tex', "w"))==FALSE) { return '[file access error] '.phplatex_cleantmp($tfn,$heredir); } + fwrite($tex, $totex); + fclose($tex); + + + #Run latex to create a .dvi. Have it try to fix minor errors instead of breaking/pausing on them. + exec($path_to_latex.' --interaction=nonstopmode '.$tfn.'.tex'); + if (!file_exists($tfn.".dvi")) { + $log = file_get_contents($tfn.'.log'); #The log always exists, but now it's actually interesting since it'll contain an error + return '[latex error, code follows]
'.$totex.'

Log file:

'.$log.'

'.phplatex_cleantmp($tfn,$heredir); + } + + + #DVI -> PostScript. Since dvips uses lpr, which may be configured to actually print by default, force writing to a file with -o + exec($path_to_dvips.' '.$tfn.'.dvi -o '.$tfn.'.ps'); + if ( !file_exists($tfn.'.ps')) { + return '[dvi2ps error] '.phplatex_cleantmp($tfn,$heredir); + } + + + #PostScript -> image. Trim based on corner pixel, and set transparent color. + exec($path_to_convert.' -transparent-color "#'.$back.'" -colorspace RGB -density '.$dpi.' -trim +page '.$tfn.'.ps -transparent "#'.$back.'" '.$tfn.'.'.$imgfmt); + #Note: +page OR -page +0+0 OR +repage moves the image to the cropped area (kills offset) + #Older code tried: exec('/usr/bin/mogrify -density 90 -trim +page -format $imgfmt '.$tfn.'.ps'); + # It seems some versions of convert may not have -trim. Old versions? + + if (!file_exists($tfn.'.'.$imgfmt)) { + return '[image convert error] '.phplatex_cleantmp($tfn,$heredir); + } + + #Copy result image to chache. + copy($tfn.'.'.$imgfmt, $heredir.'/images/'.$strhash.'.'.$imgfmt); + + #Clean up temporary files, and return link to just-created image + return phplatex_cleantmp($tfn,$heredir).'LaTeX formula: '.$stralt.''; +} +?> diff --git a/sources/extend/addon/matrix/bookmarker/bookmarker.php b/sources/extend/addon/matrix/bookmarker/bookmarker.php new file mode 100755 index 00000000..41a86350 --- /dev/null +++ b/sources/extend/addon/matrix/bookmarker/bookmarker.php @@ -0,0 +1,41 @@ + + * + */ + +function bookmarker_install() { + register_hook('prepare_body', 'addon/bookmarker/bookmarker.php', 'bookmarker_prepare_body', 10); +} + + +function bookmarker_uninstall() { + unregister_hook('prepare_body', 'addon/bookmarker/bookmarker.php', 'bookmarker_prepare_body'); +} + +function bookmarker_prepare_body(&$a,&$b) { + + + if(get_pconfig(local_channel(),'bookmarker','disable')) + return; + + if(! strpos($b['html'],'bookmark-identifier')) + return; + + if(! function_exists('redbasic_init')) + return; + + $id = $b['item']['id']; + if(local_channel()) + $link = ' '; + else + $link = ' '; + + $b['html'] = str_replace('#^',$link,$b['html']); + +} diff --git a/sources/extend/addon/matrix/buglink/bug-x.gif b/sources/extend/addon/matrix/buglink/bug-x.gif new file mode 100755 index 00000000..10936caa Binary files /dev/null and b/sources/extend/addon/matrix/buglink/bug-x.gif differ diff --git a/sources/extend/addon/matrix/buglink/buglink.php b/sources/extend/addon/matrix/buglink/buglink.php new file mode 100755 index 00000000..a237601b --- /dev/null +++ b/sources/extend/addon/matrix/buglink/buglink.php @@ -0,0 +1,15 @@ + + */ + + +function buglink_load() { register_hook('page_end', 'addon/buglink/buglink.php', 'buglink_active'); } + + +function buglink_unload() { unregister_hook('page_end', 'addon/buglink/buglink.php', 'buglink_active'); } + +function buglink_active(&$a,&$b) { $b .= ''; } diff --git a/sources/extend/addon/matrix/buglink/lang/C/messages.po b/sources/extend/addon/matrix/buglink/lang/C/messages.po new file mode 100644 index 00000000..260c583a --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/C/messages.po @@ -0,0 +1,22 @@ +# ADDON buglink +# Copyright (C) +# This file is distributed under the same license as the Friendica buglink addon package. +# +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-02-27 05:01-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: buglink.php:15 +msgid "Report Bug" +msgstr "" diff --git a/sources/extend/addon/matrix/buglink/lang/ca/strings.php b/sources/extend/addon/matrix/buglink/lang/ca/strings.php new file mode 100644 index 00000000..01fc9adb --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/ca/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Informar de problema"; diff --git a/sources/extend/addon/matrix/buglink/lang/cs/strings.php b/sources/extend/addon/matrix/buglink/lang/cs/strings.php new file mode 100644 index 00000000..a1cd51f4 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/cs/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Nahlásit chybu"; diff --git a/sources/extend/addon/matrix/buglink/lang/de/strings.php b/sources/extend/addon/matrix/buglink/lang/de/strings.php new file mode 100644 index 00000000..cf96a178 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/de/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Fehlerreport erstellen"; diff --git a/sources/extend/addon/matrix/buglink/lang/eo/strings.php b/sources/extend/addon/matrix/buglink/lang/eo/strings.php new file mode 100644 index 00000000..00d95a40 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/eo/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Skribi cimraporton"; diff --git a/sources/extend/addon/matrix/buglink/lang/es/strings.php b/sources/extend/addon/matrix/buglink/lang/es/strings.php new file mode 100644 index 00000000..fe632488 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/es/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Informe de errores"; diff --git a/sources/extend/addon/matrix/buglink/lang/fr/strings.php b/sources/extend/addon/matrix/buglink/lang/fr/strings.php new file mode 100644 index 00000000..0075fb0d --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/fr/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Signaler un bug"; diff --git a/sources/extend/addon/matrix/buglink/lang/is/strings.php b/sources/extend/addon/matrix/buglink/lang/is/strings.php new file mode 100644 index 00000000..7b3823a6 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/is/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Tilkynna bilun"; diff --git a/sources/extend/addon/matrix/buglink/lang/it/strings.php b/sources/extend/addon/matrix/buglink/lang/it/strings.php new file mode 100644 index 00000000..90df28fe --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/it/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Segnala un Bug"; diff --git a/sources/extend/addon/matrix/buglink/lang/nb-no/strings.php b/sources/extend/addon/matrix/buglink/lang/nb-no/strings.php new file mode 100644 index 00000000..ec212e9a --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/nb-no/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = ""; diff --git a/sources/extend/addon/matrix/buglink/lang/pl/strings.php b/sources/extend/addon/matrix/buglink/lang/pl/strings.php new file mode 100644 index 00000000..8229e7a6 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/pl/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "ZgÅ‚oÅ› problem"; diff --git a/sources/extend/addon/matrix/buglink/lang/pt-br/strings.php b/sources/extend/addon/matrix/buglink/lang/pt-br/strings.php new file mode 100644 index 00000000..6283d77e --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/pt-br/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Relate um Bug"; diff --git a/sources/extend/addon/matrix/buglink/lang/ru/strings.php b/sources/extend/addon/matrix/buglink/lang/ru/strings.php new file mode 100644 index 00000000..c4223648 --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/ru/strings.php @@ -0,0 +1,3 @@ +strings["Report Bug"] = "Сообщить об ошибке"; diff --git a/sources/extend/addon/matrix/buglink/lang/sv/strings.php b/sources/extend/addon/matrix/buglink/lang/sv/strings.php new file mode 100644 index 00000000..ab4fa67a --- /dev/null +++ b/sources/extend/addon/matrix/buglink/lang/sv/strings.php @@ -0,0 +1,2 @@ +strings["Report Bug"] = "报案程åºé”™è¯¯"; diff --git a/sources/extend/addon/matrix/calc/calc.apd b/sources/extend/addon/matrix/calc/calc.apd new file mode 100644 index 00000000..8171ce06 --- /dev/null +++ b/sources/extend/addon/matrix/calc/calc.apd @@ -0,0 +1,3 @@ +url: $baseurl/calc +name: Calculator +photo: $baseurl/addon/calc/calc.png diff --git a/sources/extend/addon/matrix/calc/calc.php b/sources/extend/addon/matrix/calc/calc.php new file mode 100755 index 00000000..2935b4a2 --- /dev/null +++ b/sources/extend/addon/matrix/calc/calc.php @@ -0,0 +1,368 @@ + + */ + + +function calc_load() { + register_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); +} + +function calc_unload() { + unregister_hook('app_menu', 'addon/calc/calc.php', 'calc_app_menu'); + +} + +function calc_app_menu($a,&$b) { + $b['app_menu'][] = ''; +} + + +function calc_module() {} + + + + +function calc_init($a) { + +$x = <<< EOT + + + +EOT; +$a->page['htmlhead'] .= $x; +} + +function calc_content($app) { + +$o = ''; + +$o .= <<< EOT + + +

Calculator

+

+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + +
+ +EOT; +return $o; + +} diff --git a/sources/extend/addon/matrix/calc/calc.png b/sources/extend/addon/matrix/calc/calc.png new file mode 100644 index 00000000..e7d15c8c Binary files /dev/null and b/sources/extend/addon/matrix/calc/calc.png differ diff --git a/sources/extend/addon/matrix/chords/README.md b/sources/extend/addon/matrix/chords/README.md new file mode 100644 index 00000000..a45e9730 --- /dev/null +++ b/sources/extend/addon/matrix/chords/README.md @@ -0,0 +1,9 @@ +Chord Generator +=============== + +Before enabling the plugin compile the chord generator binary. + + g++ chord-generator.cpp -o chord + +The example is for Linux. Compilation instructions may vary on Windows or other platforms. + diff --git a/sources/extend/addon/matrix/chords/chord b/sources/extend/addon/matrix/chords/chord new file mode 100755 index 00000000..b6c8a495 Binary files /dev/null and b/sources/extend/addon/matrix/chords/chord differ diff --git a/sources/extend/addon/matrix/chords/chord-generator.cpp b/sources/extend/addon/matrix/chords/chord-generator.cpp new file mode 100755 index 00000000..6a7f2c09 --- /dev/null +++ b/sources/extend/addon/matrix/chords/chord-generator.cpp @@ -0,0 +1,1133 @@ +// +// I have been messing around with this program now for a couple weeks +// and thought it might be useful to someone. Given a chord by name, +// it generates all possible ways to play that chord on a guitar and +// scores them based on things like finger span, root as bass note, +// number of open strings, etc (see below). Then it prints the top +// 50 it found (or more, you can set it). The program is pretty +// configurable if you can stand to read the stuff at the top where +// all the #define's are. Currently it prints out the score, and the +// pieces that made up the score...you may want to get rid of the +// extra info, but I found it interesting. +// +// It generates some wild chords and some interesting versions that +// I have NEVER seen before. Probably a great program to find inversions +// and stuff (especially if you lower the score given for having a root +// note 1st). The program could easily be modified to do Drop D tuning +// or any other alternate tuning, and I think it could do other instruments +// without much change, but I have not tried. +// +// I have been having fun playing with this, if you make a changes or +// fixes I would appreciate a copy. Other than that, this is public +// domain, have a party. Oh yeah, the code is C++... +// +// Thanks, +// Rick Eesley +// re@warren.mentorg.com +// +// +// +// Chords can be built like: | = seperate fields, [ ... ] = range of values +// <> = nothing +// +// [<--optional--->] +// [<--repeating-->] +// [A...G] | <> | <> | <> | # | +// | # | min | maj | | +// | b | m | add | | +// | | sus2 | aug | | +// | | sus4 | dim | | +// | | dim | + | | +// | | aug | - | | +// | | | # | +// | | | b | +// | | | / | +// +// Legal chord names: A A7 Amaj7 Amaj9 Ammaj7 Aadd4 Asus2Add4 E7b13b11 ... +// Does not do: C/G which is a c chord with a g root, just find a c +// chord and pick out a g root you like for those... +// Does not do: E5 (that's not a chord, just 2 notes) +// +// + + +#undef DEBUG +int lefty = 0; + +////////////////////////////////////////////////////////////////////// +// Scoring a chord is influenced by these multipliers, change them around +// to your own preferences +////////////////////////////////////////////////////////////////////// + +// +// Score for where this lands on the fretboard (Lower is better) +// score += (15 - AverageFret) * POSITION_SCORE; +#define POSITION_SCORE 20 + +// Score for minimal span (ie: chord covering from fret 2 to fret 4 has +// a span of 2. Open strings do NOT count in span, this is a measure +// of whether a chord is playable +// The maximum span allowed is set by the #define MAXSPAN +// score += (MAXSPAN - span) * SPAN_SCORE; +#define SPAN_SCORE 12 + +// This score is for total Span (ie: includes open strings, which span +// does not. +// score += (15 - tspan) * TSPAN_SCORE; +#define TSPAN_SCORE 3 + +// This score is for number of open strings (I like them). +// score += numberOfOpens * OPENS_SCORE +#define OPENS_SCORE 10 + +// This score multiplier is the score to add if the most bass string +// is the root note +// score += ROOT_SCORE +#define ROOT_SCORE 50 + +// This score multipier is used to penalize for adjacent notes +// score += ADJ_SCORE * (5-adjNotes) +// THe five is the max number of adjacent strings possible (duh...) +#define ADJ_SCORE 9 + +// This is the maximum finger reach, if this is bumped up to five or +// more you get a zillion more fingers (mainly 'cause 5 takes you to +// the notes on the next string...so leave it probably +#define MAXSPAN 4 + +// This is number of top scores to keep, something < 20 leaves out +// too much, 100 is a lot to look at...but I am going with it... +#define CHORDSTACK 250 + +// +// These are different types of scores, NUMSCORETYPES MUST be set to the +// number of these types, so if any are added change it TOO! +// Add any new scores onto the end, the total MUST be the 0th element +// +#define NUMSCORETYPES 7 + +#define SCORE_TOTAL 0 +#define SCORE_SPAN 1 +#define SCORE_TOTALSPAN 2 +#define SCORE_OPENSTRINGS 3 +#define SCORE_FIRSTROOT 4 +#define SCORE_LOWONNECK 5 +#define SCORE_ADJNOTES 6 + +// Just in case someone wants to port this to banjo or mandolin or something +#define NUM_STRINGS 6 + + +#include +#include +#include +#include + +/* A A# B C C# D D# E F F# G G# */ +/* A Bb B C Db D Eb E F Gb G Ab */ +/* 0 1 2 3 4 5 6 7 8 9 10 11 */ + +/* STRINGS ARE: E=0, A=1, D=2, G=3, B=4, E=5 IN ORDER */ + +// This can be reset for alternate tunings, this is EADGBE tuning +// here: + + int openStrings[NUM_STRINGS] = { 7, 0, 5, 10, 2, 7 }; + +static char *strNotes[] = { "A ", "A#", "B ", "C ", "C#", "D ", + "D#", "E ", "F ", "F#", "G ", "G#" }; + +// +// This class contains a decode chord, and can take a string and turn +// it into a chord. A chord is a triad or greater here. The code is +// decoded from a string into notes in the c array (notes: are A=0, A#=1, +// and so on. The longest chord you can possibly have is 12 notes which +// would be every note in an octave, since chords are typical 3 to 5 +// notes, remaining notes in the c[] array are set to -1 +// +class Chord +{ + public: + // String set to last error + char errorStr[64]; + + // Notes that are in the chord -1 should be ignored + int notes[12]; + + // NOtes that are optional have a 1, otherwise a zero + int optional[12]; + + // ------------------ MEMBER FUNCTIONS ---------------------------- + + // Clears last chord + void clear(); + + // Decodes input string into notes[] array, return error string + int findChord(char *s); + + // Print last error message from chord parse + void printError(); + + // Prints out notes[] array to screen + void print(char *chordName); + + // Is the note note in the chord + int inChord(int note); + + // Is this chord covered by the array of notes (ie: Does the + // array contain all the notes of the chord + int covered(int *noteArray); + + // Return the root note of the chord + int getRoot() { return notes[0]; } + + // Given a chord string, return the note that starts it (and recognize + // sharps and flats (b and #) + int get_base(char *s); + + // Get a note offset from another... + int note_offset(int base, int offset) { + if((! base) && (offset == (-1))) + return(11); + return ((base + offset) % 12); + } +} ; + +// +// This class holds a fingering for a chord, as well as a score for that +// fingering. This class also keeps the CHORDSTACK (ie: 100) best version +// of that chord to print out in sorted order (best score 1st). +// +class Fretboard +{ + public: + + // Score of current chord, held in an array so we can track the + // components of the score (see the SCORE_ defines in the begining + // of this file + int score[NUMSCORETYPES]; + + // Fretboard of the current chord, fretboard[0] is the low (bass) E + // string. A fretboard value of 0 is an open string, -1 is an + // X'ed out string (not strung) + int fretboard[NUM_STRINGS]; + + // Notes of the current fretboard fingering for a chord + int notes[NUM_STRINGS]; + + // The best fret layouts so far based on score + int bestFrets[CHORDSTACK][NUM_STRINGS]; + + // The best fret layout note sets so far based on score + int bestNotes[CHORDSTACK][NUM_STRINGS]; + + // The best scores + int bestScores[CHORDSTACK][NUMSCORETYPES]; + + // Keep track of stack sDepth to speed it up! + int sDepth; + + // ------------------ MEMBER FUNCTIONS ---------------------------- + + // Construct one + Fretboard(); + + // Given a chord (and the current fretboard state) score this doggie + // and leave the score value in score + void getScore(Chord &chord); + + // Print the current Fretboard state (not the stack) + void print(); + + // Print the fretboard stack + void printStack(); + + // Iterate over different fretboard variations for a chord + void iterate(Chord &chord); + + // Take the current fretboard state and put it into the stack + void addToBest(); + + // Get the span of the current chord, excluding open string + int getSpan(); + + // Get the span of the current chord, INCLUDING open string + int getTotalSpan(); +}; + +// +// Before building a chord, clear the notes and optional arrays +// +void +Chord::clear() +{ + for (int i = 0; i < 12; i++) + { + notes[i] = -1; + optional[i] = 0; + } +} + +// +// Print out the last error string +// +void +Chord::printError() +{ + printf("Error: %s\n", errorStr); +} + +// +// I dunno, our C++ compiler at work did not have strupr, so heres mine +// +void +myStrupr(char *s) +{ + while (*s) + { + if (islower(*s)) + *s = toupper(*s); + s++; + } +} + +// +// Decodes input string into notes[] array, return error string +// always: 0 = root, 1 = 3rd, 2 = 5th +// Also sets the optional array in parallel with the notes[] +// +int +Chord::findChord(char *s) +{ + clear(); + + // up case the string + myStrupr(s); + + // DECODE ROOT NOTE : A - G + notes[0] = get_base(s); + s++; + + // CHECK FOR SHARP OR FLAT ROOT NOTE + if (*s == '#') s++; + if (*s == 'B') s++; + + // MODIFY THE ROOT BY M, MIN, SUS2, SUS4, or diminished + if (!strncmp(s, "MIN", 3 )) + { + notes[1] = note_offset(notes[0], 3); + s += 3; + optional[2] = 1; + } + else if (!strncmp(s, "MAJ", 3)) + { + // Do nothing, but stops program from seeing the + // first m in maj as a minor (see next line)...so give a normal 3rd + notes[1] = note_offset(notes[0], 4); + optional[2] = 1; + } + else if (!strncmp(s, "M", 1)) + { + notes[1] = note_offset(notes[0], 3); + s += 1; + optional[2] = 1; + } + else if (!strncmp(s, "SUS", 1)) + { + s += 3; // go past sus + if (*s == '2') + notes[1] = note_offset(notes[0], 2); + else if (*s == '4') + notes[1] = note_offset(notes[0], 5); + else + { + strcpy(errorStr, "sus must be followed by 2 or 4"); + return 1; + } + s++; // Go past 2 or 4 + optional[2] = 1; + } + else if ((!strncmp(s, "DIM", 3 )) && (!isdigit(s[3]))) + { + // If it is diminished, just return (no other stuff allowed)/ + notes[1] = note_offset(notes[0], 3); + notes[2] = note_offset(notes[0], 6); + notes[3] = note_offset(notes[0], 9); + return 0; + } + else if ((!strncmp(s, "AUG", 3 )) && (!isdigit(s[3]))) + { + // If it is diminished, just return (no other stuff allowed)/ + notes[1] = note_offset(notes[0], 4); + notes[2] = note_offset(notes[0], 8); + return 0; + } + else + { + notes[1] = note_offset(notes[0], 4); + // optional[1] = 1; + // optional[2] = 1; + } + + notes[2] = note_offset(notes[0], 7); + + + // At this point, the 1,3,5 triad or variant is built, now add onto + // it until the string end is reached... + // Next note to add is index = 3... + int index = 3; + enum homeboy { NORMAL, MAJ, ADD, AUG, DIM } mtype ; + char lbuf[10]; + + while (*s) + { + // FIrst, check the mtype of modifier, ie: Aug, Maj, etc... + mtype = NORMAL; + if (!strncmp(s, "MAJ", 3)) + { + mtype = MAJ; + s += 3; + } + else if (!strncmp(s, "ADD", 3)) + { + mtype = ADD; + s += 3; + } + else if (!strncmp(s, "AUG", 3)) + { + mtype = AUG ; + s += 3; + } + else if (!strncmp(s, "DIM", 3)) + { + mtype = DIM; + s += 3; + } + else if ( *s == '+' ) + { + mtype = AUG; + s += 1; + } + else if ( *s == '-' ) + { + mtype = DIM; + s += 1; + } + else if ( *s == '#' ) + { + mtype = AUG; + s += 1; + } + else if ( *s == 'B' ) + { + mtype = DIM; + s += 1; + } + else if ( *s == '/' ) + { + mtype = ADD; + s += 1; + } + // Now find the number... + if (isdigit(*s)) + { + lbuf[0] = *s++; + lbuf[1] = '\0'; + } + else + { + sprintf(errorStr, "Expecting number, got %s", s); + return 1; + } + // 2nd digit? + if (isdigit(*s)) + { + lbuf[1] = *s++; + lbuf[2] = '\0'; + } + + int number = atoi(lbuf); + + switch (number) + { + case 7 : + notes[index] = note_offset(notes[0], 10); + break; + case 9 : + notes[index] = note_offset(notes[0], 2); + + // put the 7th in 2nd so it can be maj'ed if need be... + if ((mtype == NORMAL) || (mtype == MAJ)) + { + index++; + notes[index] = note_offset(notes[0], 10); + optional[index] = 1; // 7th is optional, unless it is maj! + } + + break; + case 11 : + notes[index] = note_offset(notes[0], 5); + + // put the 7th in 2nd so it can be maj'ed if need be... + if ((mtype == NORMAL) || (mtype == MAJ)) + { + index++; + notes[index] = note_offset(notes[0], 10); + optional[index] = 1; // 7th is optional, unless it is maj! + } + + break; + case 13 : + notes[index] = note_offset(notes[0], 9); + index++; + notes[index] = note_offset(notes[0], 5); + optional[index] = 1; // 7th is optional, unless it is maj! + index++; + notes[index] = note_offset(notes[0], 2); + optional[index] = 1; // 7th is optional, unless it is maj! + + // put the 7th in 2nd so it can be maj'ed if need be... + if ((mtype == NORMAL) || (mtype == MAJ)) + { + index++; + notes[index] = note_offset(notes[0], 10); + optional[index] = 1; // 7th is optional, unless it is maj! + } + + break; + case 2: + notes[index] = note_offset(notes[0], 2); + break; + case 4: + notes[index] = note_offset(notes[0], 5); + break; + case 6: + notes[index] = note_offset(notes[0], 9); + break; + case 5: + notes[index] = note_offset(notes[0], 7); + break; + default: + sprintf(errorStr, "Cannot do number: %d\n", number); + return 1; + } + + switch (mtype) + { + case DIM: + notes[index] = note_offset(notes[index], -1); + break; + case MAJ: + // It is a major, so not optional + optional[index] = 0; + case AUG : + notes[index] = note_offset(notes[index], 1); + break; + case NORMAL: + case ADD: + break; + default: + break; + } + + index++; + } + return 0; +} + +// +// Print out chord by name +// +void +Chord::print(char *cname) +{ + printf("Notes for chord '%s': ", cname); + for (int i = 0; i < 12; i++) + { + if (notes[i] != -1) + printf("%s ", strNotes[notes[i]]); + } + printf("\n\n"); +} + +// +// Are all the notes in this chord covered by the notes in the +// noteArray, it is not necessary to cover the notes in the optional +// array of the chord +// +int +Chord::covered(int *noteArray) +{ + // noteArray is an array of notes this chord has, it is NUM_STRINGS notes + // long (like a guitar fretboard dude...unused notes may be set + // to -1 (which wont compare since -1 is tossed... + + for (int i = 0; i < 12; i++) + { + if (notes[i] != -1) + { + int gotIt = 0; + for (int j = 0; j < NUM_STRINGS; j++) + { + if (noteArray[j] == notes[i]) + { + gotIt = 1; + break; + } + } + // If it was not found, and it is NOT optional, then it is + // not covered + if ((gotIt == 0) && (optional[i] == 0)) + return 0; + } + } + return 1; +} + + +// +// Is the given note in the chord +// +int +Chord::inChord(int note) +{ + for (int i = 0; i < 12; i++) + { + // Check if we are off the end of the notes set + if (notes[i] == -1) + return 0; + // Check if the note was found + if (note == notes[i]) + return 1; + } + // Did not find out, return 0 + return 0; +} + +// +// Given a chord string, pick off the root (either C or C# or Cb)...and +// return that integer value (A = 0) +// +int +Chord::get_base(char *s) +{ + + static int halfsteps[] = { 0, 2, 3, 5, 7, 8, 10 }; + + if ((*s < 'A') || (*s > 'G')) + return 0; + + if (s[1] == '#') + return ( note_offset(halfsteps[s[0] - 'A'], 1)); + else if (s[1] == 'B') + return ( note_offset(halfsteps[s[0] - 'A'], -1)); + else + return ( halfsteps[s[0] - 'A']); +} + + +// +// Print out the current fretboard +// +void +Fretboard::print() +{ + printf("SCORE: %3d ", score[SCORE_TOTAL]); + printf( + " SPN: %2d TSPN: %2d OS: %2d ROOT: %2d LOW %2d ADJ %2d", + score[SCORE_SPAN], score[SCORE_TOTALSPAN], score[SCORE_OPENSTRINGS], + score[SCORE_FIRSTROOT], score[SCORE_LOWONNECK], + score[SCORE_ADJNOTES]); + + printf(" FB: "); + for (int i = 0; i < NUM_STRINGS; i++) + { + if (fretboard[i] != -1) + printf(" %2d", fretboard[i]); + else + printf(" X"); + } + + printf(" NT: "); + for (int i = 0; i < NUM_STRINGS; i++) + if (notes[i] != -1) + printf(" %s", strNotes[notes[i]]); + else + printf(" X "); + printf("\n"); +} + +// +// Construct a fretboard -- reset to the openStrings, clear the stack +// and reset all the bestScores to -1 +// +Fretboard::Fretboard() +{ + sDepth = 0; + score[0] = 0; + for (int i = 0; i < NUM_STRINGS; i++) + { + notes[i] = openStrings[i]; + fretboard[i] = 0; + } + for (int i = 0; i < CHORDSTACK; i++) + { + bestScores[i][0] = -1; + } +} + +// +// Get the span of this chord, don't count open strings +// +int +Fretboard::getSpan() +{ + int min = 100, max = 0; + for (int i = 0; i < NUM_STRINGS; i++) + { + // Dont count X strings or open strings + if (fretboard[i] <= 0) + continue; + if (fretboard[i] > max) max = fretboard[i]; + if (fretboard[i] < min) min = fretboard[i]; + } + if (min == 100) + // All open strings, took awhile to catch this bug + return 0; + else + return (max - min); +} + +// +// Get the span of this chord, DO count open strings +// +int +Fretboard::getTotalSpan() +{ + int min = 100, max = 0; + for (int i = 0; i < NUM_STRINGS; i++) + { + // Dont count X strings + if (fretboard[i] < 0) + continue; + if (fretboard[i] > max) max = fretboard[i]; + if (fretboard[i] < min) min = fretboard[i]; + } + if (min == -1) + min = 0; + return (max - min); +} + +// +// Add this chord to the best (if there is room in the stack) +// +void +Fretboard::addToBest() +{ + // CHORDSTACK is the sDepth of keepers... +#ifdef DEBUG + printf("ATB: "); + this->print(); +#endif + + int i; + + // NOTE: at the start, bestScores is full of -1's, so any reall + // real score will be better (worst score is 0) + for (i = 0; i < sDepth; i++) + { + if (score[0] > bestScores[i][0]) + break; + } + + // If score was not better than any in the stack just return + if (i >= CHORDSTACK) + return ; + // MOve down old guys to make room for the new guy + for (int j = CHORDSTACK - 1; j >= i; j--) + { + for (int q = 0; q < NUM_STRINGS; q++) + { + bestFrets[j][q] = bestFrets[j - 1][q]; + bestNotes[j][q] = bestNotes[j - 1][q]; + } + for (int q = 0; q < NUMSCORETYPES; q++) + bestScores[j][q] = bestScores[j - 1][q]; + } + + for (int q = 0; q < NUM_STRINGS; q++) + { + bestFrets[i][q] = fretboard[q]; + bestNotes[i][q] = notes[q]; + } + for (int q = 0; q < NUMSCORETYPES; q++) + bestScores[i][q] = score[q]; + + sDepth++; + if (sDepth > CHORDSTACK) + sDepth--; +} + +// +// Print out the stack to the screen +// +void +Fretboard::printStack() +{ + static char *strNotes[] = { "A ", "A#", "B ", "C ", "C#", "D ", + "D#", "E ", "F ", "F#", "G ", "G#" }; + + + for (int f = 0; f < sDepth; f++) + { + printf("\n\n "); + + if(lefty) { + for (int i = NUM_STRINGS - 1; i >= 0; i--) + if (bestNotes[f][i] != -1) + printf(" %s", strNotes[bestNotes[f][i]]); + else + printf(" X "); + } + else { + for (int i = 0; i < NUM_STRINGS; i++) + if (bestNotes[f][i] != -1) + printf(" %s", strNotes[bestNotes[f][i]]); + else + printf(" X "); + } + printf("\n"); + if(lefty) { + for (int i = NUM_STRINGS - 1; i >= 0; i--) + if (bestFrets[f][i] != -1) + printf(" %2d", bestFrets[f][i]); + else + printf(" X"); + + } + else { + for (int i = 0; i < NUM_STRINGS; i++) + + if (bestFrets[f][i] != -1) + printf(" %2d", bestFrets[f][i]); + else + printf(" X"); + } + + printf("\n\n"); + + + int highest = 0; + + for(int i = 0; i < NUM_STRINGS; i++) + if(bestFrets[f][i] > highest) + highest = bestFrets[f][i]; + + printf("\n"); + + for(int i = 0; i <= (highest + 1); i ++) { + if(lefty) { + for (int x = NUM_STRINGS-1; x >= 0; x--) { + if(i == 0) { + if(bestFrets[f][x] == -1) + printf(" X"); + else + if(bestFrets[f][x] == 0) + printf(" 0"); + else + printf(" "); + } + else { + if(bestFrets[f][x] == i) + printf(" *"); + else + printf(" |"); + } + } + } + else { + + for (int x = 0; x < NUM_STRINGS; x++) { + if(i == 0) { + if(bestFrets[f][x] == -1) + printf(" X"); + else + if(bestFrets[f][x] == 0) + printf(" 0"); + else + printf(" "); + } + else { + if(bestFrets[f][x] == i) + printf(" *"); + else + printf(" |"); + } + } + } + printf("\n ---------------- %2d\n",i); + + + + + } + } +} + + +// +// Get the score for this chord +// +void +Fretboard::getScore(Chord &chord) +{ + + // First, points for small span (excluding opens) + score[SCORE_SPAN] = (MAXSPAN - getSpan()) * SPAN_SCORE; + + // Then, points for small total span + score[SCORE_TOTALSPAN] = (15 - getTotalSpan()) * 3; + + score[SCORE_OPENSTRINGS] = 0; + // Points for open strings + for (int i = 0; i < NUM_STRINGS; i++) + { + if (fretboard[i] == 0) + { + score[SCORE_OPENSTRINGS] += OPENS_SCORE; + } + } + + // Points for first string being the root ... + score[SCORE_FIRSTROOT] = 0; + int i; + for (i = 0; (fretboard[i] == -1) && (i < NUM_STRINGS) ; i++) + ; + if (notes[i] == chord.getRoot()) + { + score[SCORE_FIRSTROOT] = ROOT_SCORE; + } + + // Points for being low on the neck... + int sum = 0, cnt = 0; + for (i = 0; i < NUM_STRINGS; i++) + { + // Don't count X strings or open strings + if (fretboard[i] > 0) + { + sum += fretboard[i]; + cnt++; + } + } + if (cnt) + score[SCORE_LOWONNECK] = (int)(15 - ((double) sum / (double) cnt)) + * POSITION_SCORE; + else + score[SCORE_LOWONNECK] = 15 * POSITION_SCORE; + + + int adjNotes = 0; + for (i = 0; i < 5; i++) + { + if ((notes[i] != -1) && (notes[i] == notes[i + 1])) + adjNotes++; + } + score[SCORE_ADJNOTES] = (ADJ_SCORE * (5 - adjNotes)); + + // FInally, total up the score + score[SCORE_TOTAL] = 0; + for (i = 1; i < NUMSCORETYPES; i++) + score[SCORE_TOTAL] += score[i]; +} + + +// +// Iterate over all fretboard config's for this chord, call addToBest +// with any good ones (ie: < span, etc etc...) +// +void +Fretboard::iterate(Chord &chord) +{ + int string = 0; + + // Start notes setup, increment up the neck for each string until + // you find a note that is in this chord (may be an open note) + for (int i = 0; i < NUM_STRINGS; i++) + { + while (! chord.inChord(notes[i])) + { + fretboard[i]++; + notes[i] = ( notes[i] + 1 ) % 12; + } + } + + // Back up the first note one...so the loop will work + fretboard[0] = -1; + + // While we are still on the fretboard! + while (string < NUM_STRINGS) + { + + // increment the current string + fretboard[string]++; + if (fretboard[string] == 0) + notes[string] = openStrings[string]; + else + notes[string] = ( notes[string] + 1 ) % 12; + + while (! chord.inChord(notes[string])) + { + fretboard[string]++; + notes[string] = ( notes[string] + 1 ) % 12; + } + + if (fretboard[string] > 15) + { + + // Before turning over the 3rd string from the bass, try + // to make a chord with the bass string, and 2nd from + // bass string X'ed out...(ie: set to -1) + if (string == 0) + { + + notes[0] = fretboard[0] = -1; + int span = getSpan(); + if ((span < MAXSPAN) && chord.covered(notes)) + { + getScore(chord); + addToBest(); + } + } + + if (string == 1) + { + int store = notes[0]; + int fstore = fretboard[0]; + notes[1] = fretboard[1] = -1; + notes[0] = fretboard[0] = -1; + int span = getSpan(); + if ((span < MAXSPAN) && chord.covered(notes)) + { + getScore(chord); + addToBest(); + } + // Restore the notes you X'ed out + notes[0] = store; + fretboard[0] = fstore; + } + + fretboard[string] = 0; + notes[string] = openStrings[string]; + while (! chord.inChord(notes[string])) + { + fretboard[string]++; + notes[string] = chord.note_offset(notes[string], 1); + } + string++; + continue; + } + +#ifdef DEBUG + printf("TRY: "); this->print(); +#endif + + string = 0; + int span = getSpan(); + if (span >= MAXSPAN) + { +#ifdef DEBUG + printf("Rejected for span\n"); +#endif + continue; + } + if (!chord.covered(notes)) + { +#ifdef DEBUG + printf("Rejected for coverage\n"); +#endif + continue; + } + + getScore(chord); + + addToBest(); + } +} + +// +// uh, main +// +int main(int argc, char **argv) +{ + char buf[256], buf2[256]; + + if(argc > 1) + { + strcpy(buf, argv[1]); + if(argc > 3) { + if(! strcmp(argv[3],"lefty")) { + lefty = 1; + + } + + + } + + if(argc > 2) { + if(! strcmp(argv[2],"dadgad")) { + openStrings[0] = 5; + openStrings[1] = 0; + openStrings[2] = 5; + openStrings[3] = 10; + openStrings[4] = 0; + openStrings[5] = 5; + } + if(! strcmp(argv[2],"openg")) { + openStrings[0] = 5; + openStrings[1] = 10; + openStrings[2] = 5; + openStrings[3] = 10; + openStrings[4] = 2; + openStrings[5] = 5; + + } + if(! strcmp(argv[2],"opene")) { + openStrings[0] = 7; + openStrings[1] = 2; + openStrings[2] = 7; + openStrings[3] = 11; + openStrings[4] = 2; + openStrings[5] = 7; + + } + if(! strcmp(argv[2],"lefty")) { + lefty = 1; + + } + } + + + // Allocate it for DOS/WINDOWS, to avoid stack overflow (weak) + Fretboard *fb = new Fretboard; ; + Chord chord; + + + // findChord upppercases the input string, so save a copy + strcpy(buf2, buf); + + if (chord.findChord(buf)) + { + chord.printError(); + + } + else { + chord.print(buf2); + fb->iterate(chord); + + fb->printStack(); + } + delete fb; + } + return 0; +} + diff --git a/sources/extend/addon/matrix/chords/chords.apd b/sources/extend/addon/matrix/chords/chords.apd new file mode 100644 index 00000000..2ab5b99d --- /dev/null +++ b/sources/extend/addon/matrix/chords/chords.apd @@ -0,0 +1,3 @@ +url: $baseurl/chords +name: Guitar Chords +photo: $baseurl/addon/chords/chords.png diff --git a/sources/extend/addon/matrix/chords/chords.php b/sources/extend/addon/matrix/chords/chords.php new file mode 100755 index 00000000..93bdbd94 --- /dev/null +++ b/sources/extend/addon/matrix/chords/chords.php @@ -0,0 +1,129 @@ + + */ + + +function chords_load() { + register_hook('app_menu', 'addon/chords/chords.php', 'chords_app_menu'); +} + +function chords_unload() { + unregister_hook('app_menu', 'addon/chords/chords.php', 'chords_app_menu'); + +} + +function chords_app_menu($a,&$b) { + $b['app_menu'][] = ''; +} + + +function chords_module() {} + + +function chords_content($a) { + + +$o .= '

Guitar Chords

'; +$o .= 'The complete online guitar chord dictionary
'; +$args = ''; +$l = ''; + +if($_SERVER['REQUEST_METHOD'] == 'POST') { + if(isset($_POST['chord']) && strlen($_POST['chord'])) + $args .= escapeshellarg(ucfirst(trim($_POST['chord']))); + if((strlen($args)) && (isset($_POST['tuning'])) && (strlen($_POST['tuning']))) + $args .= ' '.escapeshellarg($_POST['tuning']); + if((strlen($args)) && (isset($_POST['lefty']))) + $args .= ' lefty'; +} + +if((! strlen($args)) && (! stristr(basename($_SERVER['QUERY_STRING']),'chords')) && strlen(basename($_SERVER['QUERY_STRING']))) + $args = escapeshellarg(ucfirst(basename($_SERVER['QUERY_STRING']))); + +$tunings = array("","openg", "opene", "dadgad"); +$tnames = array("Em11 [Standard] (EADGBE)", + "G/D [Drop D] (DGDGBD)","Open E (EBEG#BE)","Dsus4 (DADGAD)"); +$t = ((isset($_POST['tuning'])) ? $_POST['tuning'] : ''); +if(isset($_POST['lefty']) && $_POST['lefty'] == '1') + $l = 'checked="checked"'; + + $ch = ((isset($_POST['chord'])) ? $_POST['chord'] : ''); +$o .= <<< EOT + +
+Chord name: (ex: Em7) +  Tuning: +Left-Handed: +
+ +
+

+EOT; + +if(strlen($args)) { + $o .= '
';
+  $o .= shell_exec("addon/chords/chord ".$args);
+  $o .=  '
'; +} +else { + +$o .= <<< EOT + +

+This is a fairly comprehensive and complete guitar chord dictionary which will list most of the available ways to play a certain chord, starting from the base of the fingerboard up to a few frets beyond the twelfth fret (beyond which everything repeats). A couple of non-standard tunings are provided for the benefit of slide players, etc. +

+

+Chord names start with a root note (A-G) and may include sharps (#) and flats (b). This software will parse most of the standard naming conventions such as maj, min, dim, sus(2 or 4), aug, with optional repeating elements. +

+

+Valid examples include A, A7, Am7, Amaj7, Amaj9, Ammaj7, Aadd4, Asus2Add4, E7b13b11 ... +

+Quick Reference:
+ +EOT; + +$keys = array('A','Bb','B', 'C','Db','D','Eb','E','F','Gb','G','Ab'); +$o .= ''; +$o .= ""; +foreach($keys as $k) + $o .= ""; +$o .= ""; +foreach($keys as $k) + $o .= ""; +$o .= ""; +foreach($keys as $k) + $o .= ""; +$o .= ""; +$o .= "
$k
{$k}m
{$k}7
"; + +} + +return $o; + +} + + + + + + + + + + diff --git a/sources/extend/addon/matrix/chords/chords.png b/sources/extend/addon/matrix/chords/chords.png new file mode 100644 index 00000000..9427943f Binary files /dev/null and b/sources/extend/addon/matrix/chords/chords.png differ diff --git a/sources/extend/addon/matrix/custom_home/README.md b/sources/extend/addon/matrix/custom_home/README.md new file mode 100644 index 00000000..10f8f867 --- /dev/null +++ b/sources/extend/addon/matrix/custom_home/README.md @@ -0,0 +1,12 @@ +Configure a custom page to be used for a logged out user when viewing the home page. + +util/config system custom_home landingpage + +landingpage is a relative link. + +EG, util/config system custom_home channel/me will send logged out users to example.com/channel/me + +To set a random channel (replacing random_channel_home) use: + +util/config system custom_home random + diff --git a/sources/extend/addon/matrix/custom_home/custom_home.php b/sources/extend/addon/matrix/custom_home/custom_home.php new file mode 100644 index 00000000..5335f8a2 --- /dev/null +++ b/sources/extend/addon/matrix/custom_home/custom_home.php @@ -0,0 +1,40 @@ + + */ + + +function custom_home_load() { + register_hook('home_mod_content', 'addon/custom_home/custom_home.php', 'custom_home_home'); + logger("loaded custom_home"); +} + +function custom_home_unload() { + unregister_hook('home_mod_content', 'addon/custom_home/custom_home.php', 'custom_home_home'); + unregister_hook('home_content', 'addon/custom_home/custom_home.php', 'custom_home_home'); + logger("removed custom_home"); +} + +function custom_home_home(&$a, &$o){ + + $x = get_config('system','custom_home'); + if($x) { + if ($x == "random") { + $rand = db_getfunc('rand'); + $r = q("select channel_address from channel where channel_r_stream = 1 and channel_address != 'sys' order by $rand limit 1"); + $x = z_root() . '/channel/' . $r[0]['channel_address']; + } + else { + $x = z_root() . '/' . $x; + } + + goaway(zid($x)); + } + +//If nothing is set + return $o; +} + diff --git a/sources/extend/addon/matrix/diaspora/diaspora.php b/sources/extend/addon/matrix/diaspora/diaspora.php new file mode 100755 index 00000000..8501faa4 --- /dev/null +++ b/sources/extend/addon/matrix/diaspora/diaspora.php @@ -0,0 +1,3329 @@ +',''), + array('',''), + $msg['message']); + + + $parsed_xml = parse_xml_string($msg['message'],false); + + $xmlbase = $parsed_xml->post; + +// logger('diaspora_dispatch: ' . print_r($xmlbase,true), LOGGER_DATA); + + + if($xmlbase->request) { + $ret = diaspora_request($importer,$xmlbase->request); + } + elseif($xmlbase->status_message) { + $ret = diaspora_post($importer,$xmlbase->status_message,$msg); + } + elseif($xmlbase->profile) { + $ret = diaspora_profile($importer,$xmlbase->profile,$msg); + } + elseif($xmlbase->comment) { + $ret = diaspora_comment($importer,$xmlbase->comment,$msg); + } + elseif($xmlbase->like) { + $ret = diaspora_like($importer,$xmlbase->like,$msg); + } + elseif($xmlbase->asphoto) { + $ret = diaspora_asphoto($importer,$xmlbase->asphoto,$msg); + } + elseif($xmlbase->reshare) { + $ret = diaspora_reshare($importer,$xmlbase->reshare,$msg); + } + elseif($xmlbase->retraction) { + $ret = diaspora_retraction($importer,$xmlbase->retraction,$msg); + } + elseif($xmlbase->signed_retraction) { + $ret = diaspora_signed_retraction($importer,$xmlbase->signed_retraction,$msg); + } + elseif($xmlbase->relayable_retraction) { + $ret = diaspora_signed_retraction($importer,$xmlbase->relayable_retraction,$msg); + } + elseif($xmlbase->photo) { + $ret = diaspora_photo($importer,$xmlbase->photo,$msg); + } + elseif($xmlbase->conversation) { + $ret = diaspora_conversation($importer,$xmlbase->conversation,$msg); + } + elseif($xmlbase->message) { + $ret = diaspora_message($importer,$xmlbase->message,$msg); + } + else { + logger('diaspora_dispatch: unknown message type: ' . print_r($xmlbase,true)); + } + return $ret; +} + + +function diaspora_is_blacklisted($s) { + + $bl1 = get_config('system','blacklisted_sites'); + if(is_array($bl1) && $bl1) { + foreach($bl1 as $bl) { + if($bl && strpos($s,$bl) !== false) { + logger('diaspora_is_blacklisted: blacklisted ' . $s); + return true; + } + } + } + return false; +} + +function diaspora_process_outbound(&$a, &$arr) { + +/* + + We are passed the following array from the notifier, providing everything we need to make delivery decisions. + + $arr = array( + 'channel' => $channel, + 'env_recips' => $env_recips, + 'recipients' => $recipients, + 'item' => $item, + 'target_item' => $target_item, + 'hub' => $hub, + 'top_level_post' => $top_level_post, + 'private' => $private, + 'followup' => $followup, + 'relay_to_owner' => $relay_to_owner, + 'uplink' => $uplink, + 'cmd' => $cmd, + 'expire' => $expire, + 'mail' => $mail, + 'location' => $location, + 'fsuggest' => $fsuggest, + 'normal_mode' => $normal_mode, + 'packet_type' => $packet_type, + 'walltowall' => $walltowall, + ); +*/ + + + // allow this to be set per message + + if(strpos($arr['target_item']['postopts'],'nodspr') !== false) + return; + + $allowed = get_pconfig($arr['channel']['channel_id'],'system','diaspora_allowed'); + + if(! intval($allowed)) { + logger('mod-diaspora: disallowed for channel ' . $arr['channel']['channel_name']); + return; + } + + + if($arr['location']) + return; + + + $target_item = $arr['target_item']; + + if($target_item && array_key_exists('item_obscured',$target_item) && intval($target_item['item_obscured'])) { + $key = get_config('system','prvkey'); + if($target_item['title']) + $target_item['title'] = crypto_unencapsulate(json_decode($target_item['title'],true),$key); + if($target_item['body']) + $target_item['body'] = crypto_unencapsulate(json_decode($target_item['body'],true),$key); + } + + + + if($arr['env_recips']) { + $hashes = array(); + + // re-explode the recipients, but only for this hub/pod + + foreach($arr['env_recips'] as $recip) + $hashes[] = "'" . $recip['hash'] . "'"; + + $r = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where hubloc_url = '%s' + and xchan_hash in (" . implode(',', $hashes) . ") and xchan_network in ('diaspora', 'friendica-over-diaspora') ", + dbesc($arr['hub']['hubloc_url']) + ); + + if(! $r) { + logger('diaspora_process_outbound: no recipients'); + return; + } + + foreach($r as $contact) { + + if($arr['mail']) { + diaspora_send_mail($arr['item'],$arr['channel'],$contact); + continue; + } + + if(! $arr['normal_mode']) + continue; + + // special handling for followup to public post + // all other public posts processed as public batches further below + + if((! $arr['private']) && ($arr['followup'])) { + diaspora_send_followup($target_item,$arr['channel'],$contact, true); + continue; + } + + if(! $contact['xchan_pubkey']) + continue; + + if(intval($target_item['item_deleted']) + && (($target_item['mid'] === $target_item['parent_mid']) || $arr['followup'])) { + // send both top-level retractions and relayable retractions for owner to relay + diaspora_send_retraction($target_item,$arr['channel'],$contact); + continue; + } + elseif($arr['followup']) { + // send comments and likes to owner to relay + diaspora_send_followup($target_item,$arr['channel'],$contact); + continue; + } + + elseif($target_item['mid'] !== $target_item['parent_mid']) { + // we are the relay - send comments, likes and relayable_retractions + // (of comments and likes) to our conversants + diaspora_send_relay($target_item,$arr['channel'],$contact); + continue; + } + elseif($arr['top_level_post']) { + diaspora_send_status($target_item,$arr['channel'],$contact); + continue; + } + } + } + else { + // public message + + $contact = $arr['hub']; + + if(intval($target_item['item_deleted']) + && ($target_item['mid'] === $target_item['parent_mid'])) { + // top-level retraction + logger('delivery: diaspora retract: ' . $loc); + diaspora_send_retraction($target_item,$arr['channel'],$contact,true); + return; + } + elseif($target_item['mid'] !== $target_item['parent_mid']) { + // we are the relay - send comments, likes and relayable_retractions to our conversants + logger('delivery: diaspora relay: ' . $loc); + diaspora_send_relay($target_item,$arr['channel'],$contact,true); + return; + } + elseif($arr['top_level_post']) { + logger('delivery: diaspora status: ' . $loc); + diaspora_send_status($target_item,$arr['channel'],$contact,true); + return; + } + + } + +} + + +function diaspora_handle_from_contact($contact_hash) { + + logger("diaspora_handle_from_contact: contact id is " . $contact_hash, LOGGER_DEBUG); + + $r = q("SELECT xchan_addr from xchan where xchan_hash = '%s' limit 1", + dbesc($contact_hash) + ); + if($r) { + return $r[0]['xchan_addr']; + } + return false; +} + +function diaspora_get_contact_by_handle($uid,$handle) { + + if(diaspora_is_blacklisted($handle)) + return false; + require_once('include/identity.php'); + + $sys = get_sys_channel(); + if(($sys) && ($sys['channel_id'] == $uid)) { + $r = q("SELECT * FROM xchan where xchan_addr = '%s' limit 1", + dbesc($handle) + ); + } + else { + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where xchan_addr = '%s' and abook_channel = %d limit 1", + dbesc($handle), + intval($uid) + ); + } + + return (($r) ? $r[0] : false); +} + +function find_diaspora_person_by_handle($handle) { + + $person = false; + $refresh = false; + + if(diaspora_is_blacklisted($handle)) + return false; + + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($handle) + ); + if($r) { + $person = $r[0]; + logger('find_diaspora_person_by handle: in cache ' . print_r($r,true), LOGGER_DATA); + if($person['xchan_name_date'] < datetime_convert('UTC','UTC', 'now - 1 month')) { + logger('Updating Diaspora cached record for ' . $handle); + $refresh = true; + } + } + + if((! $person) || ($refresh)) { + + // try webfinger. Make sure to distinguish between diaspora, + // hubzilla w/diaspora protocol and friendica w/diaspora protocol. + + $result = discover_by_webbie($handle); + if($result) { + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc(str_replace('acct:','',$handle)) + ); + if($r) { + $person = $r[0]; + logger('find_diaspora_person_by handle: discovered ' . print_r($r,true), LOGGER_DATA); + } + } + } + + return $person; +} + + +function get_diaspora_key($handle) { + logger('Fetching diaspora key for: ' . $handle, LOGGER_DEBUG); + $r = find_diaspora_person_by_handle($handle); + return(($r) ? $r['xchan_pubkey'] : ''); +} + + +function diaspora_pubmsg_build($msg,$channel,$contact,$prvkey,$pubkey) { + + $a = get_app(); + + logger('diaspora_pubmsg_build: ' . $msg, LOGGER_DATA); + + $handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); + + + $b64url_data = base64url_encode($msg,false); + + $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data); + + $type = 'application/xml'; + $encoding = 'base64url'; + $alg = 'RSA-SHA256'; + + $signable_data = $data . '.' . base64url_encode($type,false) . '.' + . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false) ; + + $signature = rsa_sign($signable_data,$prvkey); + $sig = base64url_encode($signature,false); + +$magic_env = <<< EOT + + +
+ $handle +
+ + base64url + RSA-SHA256 + $data + $sig + +
+EOT; + + logger('diaspora_pubmsg_build: magic_env: ' . $magic_env, LOGGER_DATA); + return $magic_env; + +} + + + + +function diaspora_msg_build($msg,$channel,$contact,$prvkey,$pubkey,$public = false) { + $a = get_app(); + + if($public) + return diaspora_pubmsg_build($msg,$channel,$contact,$prvkey,$pubkey); + + logger('diaspora_msg_build: ' . $msg, LOGGER_DATA); + + // without a public key nothing will work + + if(! $pubkey) { + logger('diaspora_msg_build: pubkey missing: contact id: ' . $contact['abook_id']); + return ''; + } + + $inner_aes_key = random_string(32); + $b_inner_aes_key = base64_encode($inner_aes_key); + $inner_iv = random_string(16); + $b_inner_iv = base64_encode($inner_iv); + + $outer_aes_key = random_string(32); + $b_outer_aes_key = base64_encode($outer_aes_key); + $outer_iv = random_string(16); + $b_outer_iv = base64_encode($outer_iv); + + $handle = $channel['channel_address'] . '@' . get_app()->get_hostname(); + + $padded_data = pkcs5_pad($msg,16); + $inner_encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $padded_data, MCRYPT_MODE_CBC, $inner_iv); + + $b64_data = base64_encode($inner_encrypted); + + + $b64url_data = base64url_encode($b64_data,false); + $data = str_replace(array("\n","\r"," ","\t"),array('','','',''),$b64url_data); + + $type = 'application/xml'; + $encoding = 'base64url'; + $alg = 'RSA-SHA256'; + + $signable_data = $data . '.' . base64url_encode($type,false) . '.' + . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false) ; + + logger('diaspora_msg_build: signable_data: ' . $signable_data, LOGGER_DATA); + + $signature = rsa_sign($signable_data,$prvkey); + $sig = base64url_encode($signature,false); + +$decrypted_header = <<< EOT + + $b_inner_iv + $b_inner_aes_key + $handle + +EOT; + + $decrypted_header = pkcs5_pad($decrypted_header,16); + + $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $outer_aes_key, $decrypted_header, MCRYPT_MODE_CBC, $outer_iv); + + $outer_json = json_encode(array('iv' => $b_outer_iv,'key' => $b_outer_aes_key)); + + $encrypted_outer_key_bundle = ''; + openssl_public_encrypt($outer_json,$encrypted_outer_key_bundle,$pubkey); + + $b64_encrypted_outer_key_bundle = base64_encode($encrypted_outer_key_bundle); + + logger('outer_bundle: ' . $b64_encrypted_outer_key_bundle . ' key: ' . $pubkey, LOGGER_DATA); + + $encrypted_header_json_object = json_encode(array('aes_key' => base64_encode($encrypted_outer_key_bundle), + 'ciphertext' => base64_encode($ciphertext))); + $cipher_json = base64_encode($encrypted_header_json_object); + + $encrypted_header = '' . $cipher_json . ''; + +$magic_env = <<< EOT + + + $encrypted_header + + base64url + RSA-SHA256 + $data + $sig + + +EOT; + + logger('diaspora_msg_build: magic_env: ' . $magic_env, LOGGER_DATA); + return $magic_env; + +} + +/** + * + * diaspora_decode($importer,$xml) + * array $importer -> from user table + * string $xml -> urldecoded Diaspora salmon + * + * Returns array + * 'message' -> decoded Diaspora XML message + * 'author' -> author diaspora handle + * 'key' -> author public key (converted to pkcs#8) + * + * Author and key are used elsewhere to save a lookup for verifying replies and likes + */ + + +function diaspora_decode($importer,$xml) { + + $public = false; + $basedom = parse_xml_string($xml); + + $children = $basedom->children('https://joindiaspora.com/protocol'); + + if($children->header) { + $public = true; + $author_link = str_replace('acct:','',$children->header->author_id); + } + else { + + $encrypted_header = json_decode(base64_decode($children->encrypted_header)); + + $encrypted_aes_key_bundle = base64_decode($encrypted_header->aes_key); + $ciphertext = base64_decode($encrypted_header->ciphertext); + + $outer_key_bundle = ''; + openssl_private_decrypt($encrypted_aes_key_bundle,$outer_key_bundle,$importer['channel_prvkey']); + + $j_outer_key_bundle = json_decode($outer_key_bundle); + + $outer_iv = base64_decode($j_outer_key_bundle->iv); + $outer_key = base64_decode($j_outer_key_bundle->key); + + $decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $outer_key, $ciphertext, MCRYPT_MODE_CBC, $outer_iv); + + + $decrypted = pkcs5_unpad($decrypted); + + /** + * $decrypted now contains something like + * + * + * 8e+G2+ET8l5BPuW0sVTnQw== + * UvSMb4puPeB14STkcDWq+4QE302Edu15oaprAQSkLKU= + +***** OBSOLETE + + * + * Ryan Hughes + * acct:galaxor@diaspora.pirateship.org + * + +***** CURRENT + + * galaxor@diaspora.priateship.org + +***** END DIFFS + + * + */ + + logger('decrypted: ' . $decrypted, LOGGER_DATA); + $idom = parse_xml_string($decrypted,false); + + $inner_iv = base64_decode($idom->iv); + $inner_aes_key = base64_decode($idom->aes_key); + + $author_link = str_replace('acct:','',$idom->author_id); + + } + + $dom = $basedom->children(NAMESPACE_SALMON_ME); + + // figure out where in the DOM tree our data is hiding + + if($dom->provenance->data) + $base = $dom->provenance; + elseif($dom->env->data) + $base = $dom->env; + elseif($dom->data) + $base = $dom; + + if(! $base) { + logger('mod-diaspora: unable to locate salmon data in xml '); + http_status_exit(400); + } + + + // Stash the signature away for now. We have to find their key or it won't be good for anything. + $signature = base64url_decode($base->sig); + + // unpack the data + + // strip whitespace so our data element will return to one big base64 blob + $data = str_replace(array(" ","\t","\r","\n"),array("","","",""),$base->data); + + + // stash away some other stuff for later + + $type = $base->data[0]->attributes()->type[0]; + $keyhash = $base->sig[0]->attributes()->keyhash[0]; + $encoding = $base->encoding; + $alg = $base->alg; + + $signed_data = $data . '.' . base64url_encode($type,false) . '.' . base64url_encode($encoding,false) . '.' . base64url_encode($alg,false); + + + // decode the data + $data = base64url_decode($data); + + + if($public) { + $inner_decrypted = $data; + } + else { + + // Decode the encrypted blob + + $inner_encrypted = base64_decode($data); + $inner_decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128, $inner_aes_key, $inner_encrypted, MCRYPT_MODE_CBC, $inner_iv); + $inner_decrypted = pkcs5_unpad($inner_decrypted); + } + + if(! $author_link) { + logger('mod-diaspora: Could not retrieve author URI.'); + http_status_exit(400); + } + + // Once we have the author URI, go to the web and try to find their public key + // (first this will look it up locally if it is in the fcontact cache) + // This will also convert diaspora public key from pkcs#1 to pkcs#8 + + logger('mod-diaspora: Fetching key for ' . $author_link ); + $key = get_diaspora_key($author_link); + + if(! $key) { + logger('mod-diaspora: Could not retrieve author key.'); + http_status_exit(400); + } + + $verify = rsa_verify($signed_data,$signature,$key); + + if(! $verify) { + logger('mod-diaspora: Message did not verify. Discarding.'); + http_status_exit(400); + } + + logger('mod-diaspora: Message verified.'); + + return array('message' => $inner_decrypted, 'author' => $author_link, 'key' => $key); + +} + + +/* sender is now sharing with recipient */ + +function diaspora_request($importer,$xml) { + + $a = get_app(); + + $sender_handle = unxmlify($xml->sender_handle); + $recipient_handle = unxmlify($xml->recipient_handle); + + if(! $sender_handle || ! $recipient_handle) + return; + + + // Do we already have an abook record? + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$sender_handle); + + if($contact && $contact['abook_id']) { + + // perhaps we were already sharing with this person. Now they're sharing with us. + // That makes us friends. Maybe. + + // Please note some of these permissions such as PERMS_R_PAGES are impossible for Disapora. + // They cannot authenticate to our system. + + $newperms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES; + + $r = q("update abook set abook_their_perms = %d where abook_id = %d and abook_channel = %d", + intval($newperms), + intval($contact['abook_id']), + intval($importer['channel_id']) + ); + + return; + } + + $ret = find_diaspora_person_by_handle($sender_handle); + + if((! $ret) || (! strstr($ret['xchan_network'],'diaspora'))) { + logger('diaspora_request: Cannot resolve diaspora handle ' . $sender_handle . ' for ' . $recipient_handle); + return; + } + + +//FIXME +/* + if(feature_enabled($channel['channel_id'],'premium_channel')) { + $myaddr = $importer['channel_address'] . '@' . get_app()->get_hostname(); + $cnv = random_string(); + $mid = random_string(); + + $msg = t('You have started sharing with a $Projectname premium channel.'); + $msg .= t('$Projectname premium channels are not available for sharing with Diaspora members. This sharing request has been blocked.') . "\r"; + + $msg .= t('Please do not reply to this message, as this channel is not sharing with you and any reply will not be seen by the recipient.') . "\r"; + + $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); + $signed_text = $mid . ';' . $cnv . ';' . $msg . ';' + . $created . ';' . $myaddr . ';' . $cnv; + + $sig = base64_encode(rsa_sign($signed_text,$importer['channel_prvkey'],'sha256')); + + $conv = array( + 'guid' => xmlify($cnv), + 'subject' => xmlify(t('Sharing request failed.')), + 'created_at' => xmlify($created), + 'diaspora_handle' => xmlify($myaddr), + 'participant_handles' => xmlify($myaddr . ';' . $sender_handle) + ); + + $msg = array( + 'guid' => xmlify($mid), + 'parent_guid' => xmlify($cnv), + 'parent_author_signature' => xmlify($sig), + 'author_signature' => xmlify($sig), + 'text' => xmlify($msg), + 'created_at' => xmlify($created), + 'diaspora_handle' => xmlify($myaddr), + 'conversation_guid' => xmlify($cnv) + ); + + $conv['messages'] = array($msg); + $tpl = get_markup_template('diaspora_conversation.tpl'); + $xmsg = replace_macros($tpl, array('$conv' => $conv)); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$importer,$ret,$importer['channel_prvkey'],$ret['xchan_pubkey'],false))); + + diaspora_transmit($importer,$ret,$slap,false); + return; + } + +*/ +// End FIXME + + + $role = get_pconfig($channel['channel_id'],'system','permissions_role'); + if($role) { + $x = get_role_perms($role); + if($x['perms_auto']) + $default_perms = $x['perms_accept']; + } + if(! $default_perms) + $default_perms = intval(get_pconfig($importer['channel_id'],'system','autoperms')); + + $their_perms = PERMS_R_STREAM|PERMS_R_PROFILE|PERMS_R_PHOTOS|PERMS_R_ABOOK|PERMS_W_STREAM|PERMS_W_COMMENT|PERMS_W_MAIL|PERMS_W_CHAT|PERMS_R_STORAGE|PERMS_R_PAGES; + + + $closeness = get_pconfig($importer['channel_id'],'system','new_abook_closeness'); + if($closeness === false) + $closeness = 80; + + + $r = q("insert into abook ( abook_account, abook_channel, abook_xchan, abook_my_perms, abook_their_perms, abook_closeness, abook_created, abook_updated, abook_connected, abook_dob, abook_pending) values ( %d, %d, '%s', %d, %d, %d, '%s', '%s', '%s', '%s', %d )", + intval($importer['channel_account_id']), + intval($importer['channel_id']), + dbesc($ret['xchan_hash']), + intval($default_perms), + intval($their_perms), + intval($closeness), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(NULL_DATE), + intval(($default_perms) ? 0 : 1) + ); + + + if($r) { + logger("New Diaspora introduction received for {$importer['channel_name']}"); + + $new_connection = q("select * from abook left join xchan on abook_xchan = xchan_hash left join hubloc on hubloc_hash = xchan_hash where abook_channel = %d and abook_xchan = '%s' order by abook_created desc limit 1", + intval($importer['channel_id']), + dbesc($ret['xchan_hash']) + ); + if($new_connection) { + require_once('include/enotify.php'); + notification(array( + 'type' => NOTIFY_INTRO, + 'from_xchan' => $ret['xchan_hash'], + 'to_xchan' => $importer['channel_hash'], + 'link' => z_root() . '/connedit/' . $new_connection[0]['abook_id'], + )); + + + if($default_perms) { + // Send back a sharing notification to them + diaspora_share($importer,$new_connection[0]); + + } + + $clone = array(); + foreach($new_connection[0] as $k => $v) { + if(strpos($k,'abook_') === 0) { + $clone[$k] = $v; + } + } + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + build_sync_packet($importer['channel_id'], array('abook' => array($clone))); + + } + } + + // find the abook record we just created + + $contact_record = diaspora_get_contact_by_handle($importer['channel_id'],$sender_handle); + + if(! $contact_record) { + logger('diaspora_request: unable to locate newly created contact record.'); + return; + } + + /** If there is a default group for this channel, add this member to it */ + + if($importer['channel_default_group']) { + require_once('include/group.php'); + $g = group_rec_byhash($importer['channel_id'],$importer['channel_default_group']); + if($g) + group_add_member($importer['channel_id'],'',$contact_record['xchan_hash'],$g['id']); + } + + return; +} + + + +function diaspora_post($importer,$xml,$msg) { + + $a = get_app(); + $guid = notags(unxmlify($xml->guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $app = notags(xmlify($xml->provider_display_name)); + + + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) + return; + + + + if(! $app) { + if(strstr($contact['xchan_network'],'friendica')) + $app = 'Friendica'; + else + $app = 'Diaspora'; + } + + + $search_guid = ((strlen($guid) == 64) ? $guid . '%' : $guid); + + $r = q("SELECT id FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($search_guid) + ); + + if($r) { + // check dates if post editing is implemented + logger('diaspora_post: message exists: ' . $guid); + return; + } + + $created = unxmlify($xml->created_at); + $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); + + $body = diaspora2bb($xml->raw_message); + + if($xml->photo) { + $body = '[img]' . $xml->photo->remote_photo_path . $xml->photo->remote_photo_name . '[/img]' . "\n\n" . $body; + $body = scale_external_images($body); + } + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($body) > $maxlen) { + $body = mb_substr($body,0,$maxlen,'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + +//WTF? FIXME + // Add OEmbed and other information to the body +// $body = add_page_info_to_body($body, false, true); + + $datarray = array(); + + + // Look for tags and linkify them + $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); + + $datarray['term'] = array(); + + if($results) { + foreach($results as $result) { + $success = $result['success']; + if($success['replaced']) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + } + } + + $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $mtch[2], + 'url' => $mtch[1] + ); + } + } + + $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + // don't include plustags in the term + $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $term, + 'url' => $mtch[1] + ); + } + } + + + + + $plink = service_plink($contact,$guid); + + + $datarray['uid'] = $importer['channel_id']; + + $datarray['verb'] = ACTIVITY_POST; + $datarray['mid'] = $datarray['parent_mid'] = $guid; + + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); + $datarray['item_private'] = $private; + + $datarray['plink'] = $plink; + + $datarray['author_xchan'] = $contact['xchan_hash']; + $datarray['owner_xchan'] = $contact['xchan_hash']; + + $datarray['body'] = $body; + + $datarray['app'] = $app; + + $datarray['item_unseen'] = 1; + $datarray['item_thread_top'] = 1; + + $tgroup = tgroup_check($importer['channel_id'],$datarray); + + if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $tgroup)) { + logger('diaspora_post: Ignoring this author.'); + return 202; + } + + if(! post_is_importable($datarray,$contact)) { + logger('diaspora_post: filtering this author.'); + return 202; + } + + $result = item_store($datarray); + return; + +} + + +function get_diaspora_reshare_xml($url,$recurse = 0) { + + $x = z_fetch_url($url); + if(! $x['success']) + $x = z_fetch_url(str_replace('https://','http://',$url)); + if(! $x['success']) { + logger('get_diaspora_reshare_xml: unable to fetch source url ' . $url); + return; + } + logger('get_diaspora_reshare_xml: source: ' . $x['body'], LOGGER_DEBUG); + + $source_xml = parse_xml_string($x['body'],false); + + if(! $source_xml) { + logger('get_diaspora_reshare_xml: unparseable result from ' . $url); + return ''; + } + + if($source_xml->post->status_message) { + return $source_xml; + } + + // see if it's a reshare of a reshare + + if($source_xml->post->reshare) + $xml = $source_xml->post->reshare; + else + return false; + + if($xml->root_diaspora_id && $xml->root_guid && $recurse < 15) { + $orig_author = notags(unxmlify($xml->root_diaspora_id)); + $orig_guid = notags(unxmlify($xml->root_guid)); + $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; + $y = get_diaspora_reshare_xml($source_url,$recurse+1); + if($y) + return $y; + } + return false; +} + + + +function diaspora_reshare($importer,$xml,$msg) { + + logger('diaspora_reshare: init: ' . print_r($xml,true), LOGGER_DATA); + + $a = get_app(); + $guid = notags(unxmlify($xml->guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + + + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) + return; + + $search_guid = ((strlen($guid) == 64) ? $guid . '%' : $guid); + $r = q("SELECT id FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($search_guid) + ); + if($r) { + logger('diaspora_reshare: message exists: ' . $guid); + return; + } + + $orig_author = notags(unxmlify($xml->root_diaspora_id)); + $orig_guid = notags(unxmlify($xml->root_guid)); + + $source_url = 'https://' . substr($orig_author,strpos($orig_author,'@')+1) . '/p/' . $orig_guid . '.xml'; + $orig_url = 'https://'.substr($orig_author,strpos($orig_author,'@')+1).'/posts/'.$orig_guid; + + $source_xml = get_diaspora_reshare_xml($source_url); + + if($source_xml->post->status_message) { + $body = diaspora2bb($source_xml->post->status_message->raw_message); + + $orig_author = notags(unxmlify($source_xml->post->status_message->diaspora_handle)); + $orig_guid = notags(unxmlify($source_xml->post->status_message->guid)); + + + // Checking for embedded pictures + if($source_xml->post->status_message->photo->remote_photo_path && + $source_xml->post->status_message->photo->remote_photo_name) { + + $remote_photo_path = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_path)); + $remote_photo_name = notags(unxmlify($source_xml->post->status_message->photo->remote_photo_name)); + + $body = '[img]'.$remote_photo_path.$remote_photo_name.'[/img]'."\n".$body; + + logger('diaspora_reshare: embedded picture link found: '.$body, LOGGER_DEBUG); + } + + $body = scale_external_images($body); + + // Add OEmbed and other information to the body +// $body = add_page_info_to_body($body, false, true); + } + else { + // Maybe it is a reshare of a photo that will be delivered at a later time (testing) + logger('diaspora_reshare: no reshare content found: ' . print_r($source_xml,true)); + $body = ""; + //return; + } + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($body) > $maxlen) { + $body = mb_substr($body,0,$maxlen,'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + $person = find_diaspora_person_by_handle($orig_author); + + if($person) { + $orig_author_name = $person['xchan_name']; + $orig_author_link = $person['xchan_url']; + $orig_author_photo = $person['xchan_photo_m']; + } + + + $created = unxmlify($xml->created_at); + $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); + + $datarray = array(); + + // Look for tags and linkify them + $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); + + $datarray['term'] = array(); + + if($results) { + foreach($results as $result) { + $success = $result['success']; + if($success['replaced']) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + } + } + + $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $mtch[2], + 'url' => $mtch[1] + ); + } + } + + $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + // don't include plustags in the term + $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $term, + 'url' => $mtch[1] + ); + } + } + + + + + + $newbody = "[share author='" . urlencode($orig_author_name) + . "' profile='" . $orig_author_link + . "' avatar='" . $orig_author_photo + . "' link='" . $orig_url + . "' posted='" . datetime_convert('UTC','UTC',unxmlify($source_xml->post->status_message->created_at)) + . "' message_id='" . unxmlify($source_xml->post->status_message->guid) + . "']" . $body . "[/share]"; + + + $plink = service_plink($contact,$guid); + + $datarray['uid'] = $importer['channel_id']; + $datarray['mid'] = $datarray['parent_mid'] = $guid; + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); + $datarray['item_private'] = $private; + $datarray['plink'] = $plink; + $datarray['owner_xchan'] = $contact['xchan_hash']; + $datarray['author_xchan'] = $contact['xchan_hash']; + + $datarray['body'] = $newbody; + $datarray['app'] = 'Diaspora'; + + + + $tgroup = tgroup_check($importer['channel_id'],$datarray); + + if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream')) && (! $tgroup)) { + logger('diaspora_post: Ignoring this author.'); + return 202; + } + + + $result = item_store($datarray); + + return; + +} + + +function diaspora_asphoto($importer,$xml,$msg) { + logger('diaspora_asphoto called'); + + $a = get_app(); + $guid = notags(unxmlify($xml->guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) + return; + + if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream'))) { + logger('diaspora_asphoto: Ignoring this author.'); + return 202; + } + + $message_id = $diaspora_handle . ':' . $guid; + $r = q("SELECT `id` FROM `item` WHERE `uid` = %d AND `uri` = '%s' AND `guid` = '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($message_id), + dbesc($guid) + ); + if(count($r)) { + logger('diaspora_asphoto: message exists: ' . $guid); + return; + } + + // allocate a guid on our system - we aren't fixing any collisions. + // we're ignoring them + + $g = q("select * from guid where guid = '%s' limit 1", + dbesc($guid) + ); + if(! count($g)) { + q("insert into guid ( guid ) values ( '%s' )", + dbesc($guid) + ); + } + + $created = unxmlify($xml->created_at); + $private = ((unxmlify($xml->public) == 'false') ? 1 : 0); + + if(strlen($xml->objectId) && ($xml->objectId != 0) && ($xml->image_url)) { + $body = '[url=' . notags(unxmlify($xml->image_url)) . '][img]' . notags(unxmlify($xml->objectId)) . '[/img][/url]' . "\n"; + $body = scale_external_images($body,false); + } + elseif($xml->image_url) { + $body = '[img]' . notags(unxmlify($xml->image_url)) . '[/img]' . "\n"; + $body = scale_external_images($body); + } + else { + logger('diaspora_asphoto: no photo url found.'); + return; + } + + $plink = service_plink($contact,$guid); + + $datarray = array(); + + $datarray['uid'] = $importer['channel_id']; + $datarray['contact-id'] = $contact['id']; + $datarray['wall'] = 0; + $datarray['network'] = NETWORK_DIASPORA; + $datarray['guid'] = $guid; + $datarray['uri'] = $datarray['parent-uri'] = $message_id; + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert('UTC','UTC',$created); + $datarray['private'] = $private; + $datarray['parent'] = 0; + $datarray['plink'] = $plink; + $datarray['owner-name'] = $contact['name']; + $datarray['owner-link'] = $contact['url']; + //$datarray['owner-avatar'] = $contact['thumb']; + $datarray['owner-avatar'] = ((x($contact,'thumb')) ? $contact['thumb'] : $contact['photo']); + $datarray['author-name'] = $contact['name']; + $datarray['author-link'] = $contact['url']; + $datarray['author-avatar'] = $contact['thumb']; + $datarray['body'] = $body; + + $datarray['app'] = 'Diaspora/Cubbi.es'; + + $message_id = item_store($datarray); + + //if($message_id) { + // q("update item set plink = '%s' where id = %d", + // dbesc($a->get_baseurl() . '/display/' . $importer['nickname'] . '/' . $message_id), + // intval($message_id) + // ); + //} + + return; + +} + + + + + + +function diaspora_comment($importer,$xml,$msg) { + + $a = get_app(); + $guid = notags(unxmlify($xml->guid)); + $parent_guid = notags(unxmlify($xml->parent_guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $target_type = notags(unxmlify($xml->target_type)); + $text = unxmlify($xml->text); + $author_signature = notags(unxmlify($xml->author_signature)); + + $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); + if(! $contact) { + logger('diaspora_comment: cannot find contact: ' . $msg['author']); + return; + } + + + + $pubcomment = get_pconfig($importer['channel_id'],'system','diaspora_public_comments'); + + // by default comments on public posts are allowed from anybody on Diaspora. That is their policy. + // Once this setting is set to something we'll track your preference and it will over-ride the default. + + if($pubcomment === false) + $pubcomment = 1; + + // Friendica is currently truncating guids at 64 chars + $search_guid = $parent_guid; + if(strlen($parent_guid) == 64) + $search_guid = $parent_guid . '%'; + + $r = q("SELECT * FROM item WHERE uid = %d AND mid LIKE '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($search_guid) + ); + if(! $r) { + logger('diaspora_comment: parent item not found: parent: ' . $parent_guid . ' item: ' . $guid); + return; + } + + $parent_item = $r[0]; + + if(intval($parent_item['item_private'])) + $pubcomment = 0; + + $search_guid = $guid; + if(strlen($guid) == 64) + $search_guid = $guid . '%'; + + + $r = q("SELECT * FROM item WHERE uid = %d AND mid like '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($search_guid) + ); + if($r) { + logger('diaspora_comment: our comment just got relayed back to us (or there was a guid collision) : ' . $guid); + return; + } + + + + /* How Diaspora performs comment signature checking: + + - If an item has been sent by the comment author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner should check + the author_signature, then create a parent_author_signature before relaying the comment on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the psuedo-salmon + */ + + $signed_data = $guid . ';' . $parent_guid . ';' . $text . ';' . $diaspora_handle; + $key = $msg['key']; + + if($parent_author_signature) { + // If a parent_author_signature exists, then we've received the comment + // relayed from the top-level post owner. There's no need to check the + // author_signature if the parent_author_signature is valid + + $parent_author_signature = base64_decode($parent_author_signature); + + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_comment: top-level owner verification failed.'); + return; + } + } + else { + // If there's no parent_author_signature, then we've received the comment + // from the comment creator. In that case, the person is commenting on + // our post, so he/she must be a contact of ours and his/her public key + // should be in $msg['key'] + + if($importer['system']) { + // don't relay to the sys channel + logger('diaspora_comment: relay to sys channel blocked.'); + return; + } + + $author_signature = base64_decode($author_signature); + + if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { + logger('diaspora_comment: comment author verification failed.'); + return; + } + } + + // Phew! Everything checks out. Now create an item. + + // Find the original comment author information. + // We need this to make sure we display the comment author + // information (name and avatar) correctly. + + if(strcasecmp($diaspora_handle,$msg['author']) == 0) + $person = $contact; + else { + $person = find_diaspora_person_by_handle($diaspora_handle); + + if(! is_array($person)) { + logger('diaspora_comment: unable to find author details'); + return; + } + } + + + $body = diaspora2bb($text); + + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($body) > $maxlen) { + $body = mb_substr($body,0,$maxlen,'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + + $datarray = array(); + + // Look for tags and linkify them + $results = linkify_tags(get_app(), $body, $importer['channel_id'], true); + + $datarray['term'] = array(); + + if($results) { + foreach($results as $result) { + $success = $result['success']; + if($success['replaced']) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + } + } + + $cnt = preg_match_all('/@\[url=(.*?)\](.*?)\[\/url\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $mtch[2], + 'url' => $mtch[1] + ); + } + } + + $cnt = preg_match_all('/@\[zrl=(.*?)\](.*?)\[\/zrl\]/ism',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + // don't include plustags in the term + $term = ((substr($mtch[2],-1,1) === '+') ? substr($mtch[2],0,-1) : $mtch[2]); + $datarray['term'][] = array( + 'uid' => $importer['channel_id'], + 'type' => TERM_MENTION, + 'otype' => TERM_OBJ_POST, + 'term' => $term, + 'url' => $mtch[1] + ); + } + } + + $datarray['uid'] = $importer['channel_id']; + $datarray['verb'] = ACTIVITY_POST; + $datarray['mid'] = $guid; + $datarray['parent_mid'] = $parent_item['mid']; + + // set the route to that of the parent so downstream hubs won't reject it. + $datarray['route'] = $parent_item['route']; + + // No timestamps for comments? OK, we'll the use current time. + $datarray['changed'] = $datarray['created'] = $datarray['edited'] = datetime_convert(); + $datarray['item_private'] = $parent_item['item_private']; + + $datarray['owner_xchan'] = $parent_item['owner_xchan']; + $datarray['author_xchan'] = $person['xchan_hash']; + + $datarray['body'] = $body; + + if(strstr($person['xchan_network'],'friendica')) + $app = 'Friendica'; + else + $app = 'Diaspora'; + + $datarray['app'] = $app; + + if(! $parent_author_signature) { + $key = get_config('system','pubkey'); + $x = array('signer' => $diaspora_handle, 'body' => $text, + 'signed_text' => $signed_data, 'signature' => base64_encode($author_signature)); + $datarray['diaspora_meta'] = json_encode($x); + } + + + + // So basically if something arrives at the sys channel it's by definition public and we allow it. + // If $pubcomment and the parent was public, we allow it. + // In all other cases, honour the permissions for this Diaspora connection + + $tgroup = tgroup_check($importer['channel_id'],$datarray); + + if((! $importer['system']) && (! $pubcomment) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments')) && (! $tgroup)) { + logger('diaspora_comment: Ignoring this author.'); + return 202; + } + + + + + $result = item_store($datarray); + + if($result && $result['success']) + $message_id = $result['item_id']; + + if(intval($parent_item['item_origin']) && (! $parent_author_signature)) { + // if the message isn't already being relayed, notify others + // the existence of parent_author_signature means the parent_author or owner + // is already relaying. + + proc_run('php','include/notifier.php','comment-import',$message_id); + } + + if($result['item_id']) { + $r = q("select * from item where id = %d limit 1", + intval($result['item_id']) + ); + if($r) + send_status_notifications($result['item_id'],$r[0]); + } + + return; +} + + + + +function diaspora_conversation($importer,$xml,$msg) { + + $a = get_app(); + + $guid = notags(unxmlify($xml->guid)); + $subject = notags(unxmlify($xml->subject)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $participant_handles = notags(unxmlify($xml->participant_handles)); + $created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at))); + + $parent_uri = $diaspora_handle . ':' . $guid; + + $messages = $xml->message; + + if(! count($messages)) { + logger('diaspora_conversation: empty conversation'); + return; + } + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); + if(! $contact) { + logger('diaspora_conversation: cannot find contact: ' . $msg['author']); + return; + } + + + if(! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_mail')) { + logger('diaspora_conversation: Ignoring this author.'); + return 202; + } + + $conversation = null; + + $c = q("select * from conv where uid = %d and guid = '%s' limit 1", + intval($importer['channel_id']), + dbesc($guid) + ); + if(count($c)) + $conversation = $c[0]; + else { + $r = q("insert into conv (uid,guid,creator,created,updated,subject,recips) values(%d, '%s', '%s', '%s', '%s', '%s', '%s') ", + intval($importer['channel_id']), + dbesc($guid), + dbesc($diaspora_handle), + dbesc(datetime_convert('UTC','UTC',$created_at)), + dbesc(datetime_convert()), + dbesc($subject), + dbesc($participant_handles) + ); + if($r) + $c = q("select * from conv where uid = %d and guid = '%s' limit 1", + intval($importer['channel_id']), + dbesc($guid) + ); + if(count($c)) + $conversation = $c[0]; + } + if(! $conversation) { + logger('diaspora_conversation: unable to create conversation.'); + return; + } + + foreach($messages as $mesg) { + + $reply = 0; + + $msg_guid = notags(unxmlify($mesg->guid)); + $msg_parent_guid = notags(unxmlify($mesg->parent_guid)); + $msg_parent_author_signature = notags(unxmlify($mesg->parent_author_signature)); + $msg_author_signature = notags(unxmlify($mesg->author_signature)); + $msg_text = unxmlify($mesg->text); + $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($mesg->created_at))); + $msg_diaspora_handle = notags(unxmlify($mesg->diaspora_handle)); + $msg_conversation_guid = notags(unxmlify($mesg->conversation_guid)); + if($msg_conversation_guid != $guid) { + logger('diaspora_conversation: message conversation guid does not belong to the current conversation. ' . $xml); + continue; + } + + $body = diaspora2bb($msg_text); + + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($body) > $maxlen) { + $body = mb_substr($body,0,$maxlen,'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + + $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; + + $author_signature = base64_decode($msg_author_signature); + + if(strcasecmp($msg_diaspora_handle,$msg['author']) == 0) { + $person = $contact; + $key = $msg['key']; + } + else { + $person = find_diaspora_person_by_handle($msg_diaspora_handle); + + if(is_array($person) && x($person,'xchan_pubkey')) + $key = $person['xchan_pubkey']; + else { + logger('diaspora_conversation: unable to find author details'); + continue; + } + } + + if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { + logger('diaspora_conversation: verification failed.'); + continue; + } + + if($msg_parent_author_signature) { + $owner_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($mesg->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; + + $parent_author_signature = base64_decode($msg_parent_author_signature); + + $key = $msg['key']; + + if(! rsa_verify($owner_signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_conversation: owner verification failed.'); + continue; + } + } + + $r = q("select id from mail where mid = '%s' limit 1", + dbesc($message_id) + ); + if(count($r)) { + logger('diaspora_conversation: duplicate message already delivered.', LOGGER_DEBUG); + continue; + } + + if($subject) + $subject = str_rot47(base64url_encode($subject)); + if($body) + $body = str_rot47(base64url_encode($body)); + + q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_obscured`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s')", + intval($importer['channel_id']), + intval($conversation['id']), + dbesc($person['xchan_hash']), + dbesc($importer['channel_hash']), + dbesc($subject), + dbesc($body), + intval(1), + dbesc($msg_guid), + dbesc($parent_uri), + dbesc($msg_created_at) + ); + + q("update conv set updated = '%s' where id = %d", + dbesc(datetime_convert()), + intval($conversation['id']) + ); + + require_once('include/enotify.php'); +/****** +//FIXME + + notification(array( + 'type' => NOTIFY_MAIL, + 'notify_flags' => $importer['notify-flags'], + 'language' => $importer['language'], + 'to_name' => $importer['username'], + 'to_email' => $importer['email'], + 'uid' =>$importer['importer_uid'], + 'item' => array('subject' => $subject, 'body' => $body), + 'source_name' => $person['name'], + 'source_link' => $person['url'], + 'source_photo' => $person['thumb'], + 'verb' => ACTIVITY_POST, + 'otype' => 'mail' + )); +*******/ + + } + + return; +} + +function diaspora_message($importer,$xml,$msg) { + + $a = get_app(); + + $msg_guid = notags(unxmlify($xml->guid)); + $msg_parent_guid = notags(unxmlify($xml->parent_guid)); + $msg_parent_author_signature = notags(unxmlify($xml->parent_author_signature)); + $msg_author_signature = notags(unxmlify($xml->author_signature)); + $msg_text = unxmlify($xml->text); + $msg_created_at = datetime_convert('UTC','UTC',notags(unxmlify($xml->created_at))); + $msg_diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $msg_conversation_guid = notags(unxmlify($xml->conversation_guid)); + + $parent_uri = $msg_parent_guid; + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg_diaspora_handle); + if(! $contact) { + logger('diaspora_message: cannot find contact: ' . $msg_diaspora_handle); + return; + } + + if(($contact['rel'] == CONTACT_IS_FOLLOWER) || ($contact['blocked']) || ($contact['readonly'])) { + logger('diaspora_message: Ignoring this author.'); + return 202; + } + + $conversation = null; + + $c = q("select * from conv where uid = %d and guid = '%s' limit 1", + intval($importer['channel_id']), + dbesc($msg_conversation_guid) + ); + if($c) + $conversation = $c[0]; + else { + logger('diaspora_message: conversation not available.'); + return; + } + + $reply = 0; + + $subject = $conversation['subject']; + $body = diaspora2bb($msg_text); + + + $maxlen = get_max_import_size(); + + if($maxlen && mb_strlen($body) > $maxlen) { + $body = mb_substr($body,0,$maxlen,'UTF-8'); + logger('message length exceeds max_import_size: truncated'); + } + + + + $message_id = $msg_diaspora_handle . ':' . $msg_guid; + + $author_signed_data = $msg_guid . ';' . $msg_parent_guid . ';' . $msg_text . ';' . unxmlify($xml->created_at) . ';' . $msg_diaspora_handle . ';' . $msg_conversation_guid; + + + $author_signature = base64_decode($msg_author_signature); + + $person = find_diaspora_person_by_handle($msg_diaspora_handle); + if(is_array($person) && x($person,'xchan_pubkey')) + $key = $person['xchan_pubkey']; + else { + logger('diaspora_message: unable to find author details'); + return; + } + + if(! rsa_verify($author_signed_data,$author_signature,$key,'sha256')) { + logger('diaspora_message: verification failed.'); + return; + } + + $r = q("select id from mail where mid = '%s' and channel_id = %d limit 1", + dbesc($message_id), + intval($importer['channel_id']) + ); + if($r) { + logger('diaspora_message: duplicate message already delivered.', LOGGER_DEBUG); + return; + } + + $key = get_config('system','pubkey'); + if($subject) + $subject = str_rot47(base64url_encode($subject)); + if($body) + $body = str_rot47(base64url_encode($body)); + + q("insert into mail ( `channel_id`, `convid`, `from_xchan`,`to_xchan`,`title`,`body`,`mail_obscured`,`mid`,`parent_mid`,`created`) values ( %d, %d, '%s', '%s', '%s', '%s', '%d','%s','%s','%s')", + intval($importer['channel_id']), + intval($conversation['id']), + dbesc($person['xchan_hash']), + dbesc($importer['xchan_hash']), + dbesc($subject), + dbesc($body), + intval(1), + dbesc($msg_guid), + dbesc($parent_uri), + dbesc($msg_created_at) + ); + + q("update conv set updated = '%s' where id = %d", + dbesc(datetime_convert()), + intval($conversation['id']) + ); + + return; +} + + +function diaspora_photo($importer,$xml,$msg) { + + $a = get_app(); + + logger('diaspora_photo: init',LOGGER_DEBUG); + + $remote_photo_path = notags(unxmlify($xml->remote_photo_path)); + + $remote_photo_name = notags(unxmlify($xml->remote_photo_name)); + + $status_message_guid = notags(unxmlify($xml->status_message_guid)); + + $guid = notags(unxmlify($xml->guid)); + + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + + $public = notags(unxmlify($xml->public)); + + $created_at = notags(unxmlify($xml_created_at)); + + logger('diaspora_photo: status_message_guid: ' . $status_message_guid, LOGGER_DEBUG); + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); + if(! $contact) { + logger('diaspora_photo: contact record not found: ' . $msg['author'] . ' handle: ' . $diaspora_handle); + return; + } + + if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'send_stream'))) { + logger('diaspora_photo: Ignoring this author.'); + return 202; + } + + $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($status_message_guid) + ); + if(! $r) { + logger('diaspora_photo: attempt = ' . $attempt . '; status message not found: ' . $status_message_guid . ' for photo: ' . $guid); + return; + } + +// $parent_item = $r[0]; + +// $link_text = '[img]' . $remote_photo_path . $remote_photo_name . '[/img]' . "\n"; + +// $link_text = scale_external_images($link_text, true, +// array($remote_photo_name, 'scaled_full_' . $remote_photo_name)); + +// if(strpos($parent_item['body'],$link_text) === false) { +// $r = q("update item set `body` = '%s', `visible` = 1 where `id` = %d and `uid` = %d", +// dbesc($link_text . $parent_item['body']), +// intval($parent_item['id']), +// intval($parent_item['uid']) +// ); +// } + + return; +} + + + + +function diaspora_like($importer,$xml,$msg) { + + $a = get_app(); + $guid = notags(unxmlify($xml->guid)); + $parent_guid = notags(unxmlify($xml->parent_guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $target_type = notags(unxmlify($xml->target_type)); + $positive = notags(unxmlify($xml->positive)); + $author_signature = notags(unxmlify($xml->author_signature)); + + $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); + + // likes on comments not supported here and likes on photos not supported by Diaspora + +// if($target_type !== 'Post') +// return; + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$msg['author']); + if(! $contact) { + logger('diaspora_like: cannot find contact: ' . $msg['author'] . ' for channel ' . $importer['channel_name']); + return; + } + + + if((! $importer['system']) && (! perm_is_allowed($importer['channel_id'],$contact['xchan_hash'],'post_comments'))) { + logger('diaspora_like: Ignoring this author.'); + return 202; + } + + $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($parent_guid) + ); + if(! count($r)) { + logger('diaspora_like: parent item not found: ' . $guid); + return; + } + + $parent_item = $r[0]; + + $r = q("SELECT * FROM `item` WHERE `uid` = %d AND `mid` = '%s' LIMIT 1", + intval($importer['channel_id']), + dbesc($guid) + ); + if(count($r)) { + if($positive === 'true') { + logger('diaspora_like: duplicate like: ' . $guid); + return; + } + // Note: I don't think "Like" objects with positive = "false" are ever actually used + // It looks like "RelayableRetractions" are used for "unlike" instead + if($positive === 'false') { + logger('diaspora_like: received a like with positive set to "false"...ignoring'); + // perhaps call drop_item() + // FIXME--actually don't unless it turns out that Diaspora does indeed send out "false" likes + // send notification via proc_run() + return; + } + } + + $i = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($parent_item['author_xchan']) + ); + if($i) + $item_author = $i[0]; + + // Note: I don't think "Like" objects with positive = "false" are ever actually used + // It looks like "RelayableRetractions" are used for "unlike" instead + if($positive === 'false') { + logger('diaspora_like: received a like with positive set to "false"'); + logger('diaspora_like: unlike received with no corresponding like...ignoring'); + return; + } + + + /* How Diaspora performs "like" signature checking: + + - If an item has been sent by the like author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner should check + the author_signature, then create a parent_author_signature before relaying the like on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the salmon + */ + + // 2014-09-10 let's try this: signatures are failing. I'll try and make a signable string from + // the parameters in the order they were presented in the post. This is how D* creates the signable string. + + + $signed_data = $positive . ';' . $guid . ';' . $target_type . ';' . $parent_guid . ';' . $diaspora_handle; + + $key = $msg['key']; + + if($parent_author_signature) { + // If a parent_author_signature exists, then we've received the like + // relayed from the top-level post owner. There's no need to check the + // author_signature if the parent_author_signature is valid + + $parent_author_signature = base64_decode($parent_author_signature); + + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + if (intval(get_config('system','ignore_diaspora_like_signature'))) + logger('diaspora_like: top-level owner verification failed. Proceeding anyway.'); + else { + logger('diaspora_like: top-level owner verification failed.'); + return; + } + } + } + else { + // If there's no parent_author_signature, then we've received the like + // from the like creator. In that case, the person is "like"ing + // our post, so he/she must be a contact of ours and his/her public key + // should be in $msg['key'] + + $author_signature = base64_decode($author_signature); + + if(! rsa_verify($signed_data,$author_signature,$key,'sha256')) { + if (intval(get_config('system','ignore_diaspora_like_signature'))) + logger('diaspora_like: like creator verification failed. Proceeding anyway'); + else { + logger('diaspora_like: like creator verification failed.'); + return; + } + } + } + + logger('diaspora_like: signature check complete.',LOGGER_DEBUG); + + // Phew! Everything checks out. Now create an item. + + // Find the original comment author information. + // We need this to make sure we display the comment author + // information (name and avatar) correctly. + if(strcasecmp($diaspora_handle,$msg['author']) == 0) + $person = $contact; + else { + $person = find_diaspora_person_by_handle($diaspora_handle); + + if(! is_array($person)) { + logger('diaspora_like: unable to find author details'); + return; + } + } + + $uri = $diaspora_handle . ':' . $guid; + + $activity = ACTIVITY_LIKE; + + $post_type = (($parent_item['resource_type'] === 'photo') ? t('photo') : t('status')); + + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $parent_item['plink'])); + $objtype = (($parent_item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $body = $parent_item['body']; + + + $object = json_encode(array( + 'type' => $post_type, + 'id' => $parent_item['mid'], + 'parent' => (($parent_item['thr_parent']) ? $parent_item['thr_parent'] : $parent_item['parent_mid']), + 'link' => $links, + 'title' => $parent_item['title'], + 'content' => $parent_item['body'], + 'created' => $parent_item['created'], + 'edited' => $parent_item['edited'], + 'author' => array( + 'name' => $item_author['xchan_name'], + 'address' => $item_author['xchan_addr'], + 'guid' => $item_author['xchan_guid'], + 'guid_sig' => $item_author['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), + array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), + ), + )); + + + $bodyverb = t('%1$s likes %2$s\'s %3$s'); + + $arr = array(); + + $arr['uid'] = $importer['channel_id']; + $arr['aid'] = $importer['channel_account_id']; + $arr['mid'] = $guid; + $arr['parent_mid'] = $parent_item['mid']; + $arr['owner_xchan'] = $parent_item['owner_xchan']; + $arr['author_xchan'] = $person['xchan_hash']; + + $ulink = '[url=' . $contact['url'] . ']' . $contact['name'] . '[/url]'; + $alink = '[url=' . $parent_item['author-link'] . ']' . $parent_item['author-name'] . '[/url]'; + $plink = '[url='. z_root() .'/display/'.$guid.']'.$post_type.'[/url]'; + $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); + + $arr['app'] = 'Diaspora'; + + // set the route to that of the parent so downstream hubs won't reject it. + $arr['route'] = $parent_item['route']; + + $arr['item_private'] = $parent_item['item_private']; + $arr['verb'] = $activity; + $arr['obj_type'] = $objtype; + $arr['object'] = $object; + + if(! $parent_author_signature) { + $key = get_config('system','pubkey'); + $x = array('signer' => $diaspora_handle, 'body' => $text, + 'signed_text' => $signed_data, 'signature' => base64_encode($author_signature)); + $arr['diaspora_meta'] = json_encode($x); + } + + $x = item_store($arr); + + if($x) + $message_id = $x['item_id']; + + // if the message isn't already being relayed, notify others + // the existence of parent_author_signature means the parent_author or owner + // is already relaying. The parent_item['origin'] indicates the message was created on our system + + if(intval($parent_item['item_origin']) && (! $parent_author_signature)) + proc_run('php','include/notifier.php','comment-import',$message_id); + + return; +} + +function diaspora_retraction($importer,$xml) { + + + $guid = notags(unxmlify($xml->guid)); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + $type = notags(unxmlify($xml->type)); + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) + return; + + if($type === 'Person') { + require_once('include/Contact.php'); + contact_remove($importer['channel_id'],$contact['abook_id']); + } + elseif($type === 'Post') { + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc('guid'), + intval($importer['channel_id']) + ); + if(count($r)) { + if(link_compare($r[0]['author_xchan'],$contact['xchan_hash'])) { + drop_item($r[0]['id'],false); + } + } + } + + return 202; + // NOTREACHED +} + +function diaspora_signed_retraction($importer,$xml,$msg) { + + + $guid = notags(unxmlify($xml->target_guid)); + $diaspora_handle = notags(unxmlify($xml->sender_handle)); + $type = notags(unxmlify($xml->target_type)); + $sig = notags(unxmlify($xml->target_author_signature)); + + $parent_author_signature = (($xml->parent_author_signature) ? notags(unxmlify($xml->parent_author_signature)) : ''); + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) { + logger('diaspora_signed_retraction: no contact ' . $diaspora_handle . ' for ' . $importer['channel_id']); + return; + } + + + $signed_data = $guid . ';' . $type ; + $key = $msg['key']; + + /* How Diaspora performs relayable_retraction signature checking: + + - If an item has been sent by the item author to the top-level post owner to relay on + to the rest of the contacts on the top-level post, the top-level post owner checks + the author_signature, then creates a parent_author_signature before relaying the item on + - If an item has been relayed on by the top-level post owner, the contacts who receive it + check only the parent_author_signature. Basically, they trust that the top-level post + owner has already verified the authenticity of anything he/she sends out + - In either case, the signature that get checked is the signature created by the person + who sent the salmon + */ + + if($parent_author_signature) { + + $parent_author_signature = base64_decode($parent_author_signature); + + if(! rsa_verify($signed_data,$parent_author_signature,$key,'sha256')) { + logger('diaspora_signed_retraction: top-level post owner verification failed'); + return; + } + + } + else { + + $sig_decode = base64_decode($sig); + + if(! rsa_verify($signed_data,$sig_decode,$key,'sha256')) { + logger('diaspora_signed_retraction: retraction owner verification failed.' . print_r($msg,true)); + return; + } + } + + if($type === 'StatusMessage' || $type === 'Comment' || $type === 'Like') { + $r = q("select * from item where mid = '%s' and uid = %d limit 1", + dbesc($guid), + intval($importer['channel_id']) + ); + if($r) { + if($r[0]['author_xchan'] == $contact['xchan_hash']) { + + drop_item($r[0]['id'],false, DROPITEM_PHASE1); + + // Now check if the retraction needs to be relayed by us + // + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select item_flags from item where parent = %d and id = %d limit 1", + $r[0]['parent'], + $r[0]['parent'] + ); + if($p) { + if(intval($p[0]['item_origin']) && (! $parent_author_signature)) { + + // the existence of parent_author_signature would have meant the parent_author or owner + // is already relaying. + + logger('diaspora_signed_retraction: relaying relayable_retraction'); + proc_run('php','include/notifier.php','drop',$r[0]['id']); + } + } + } + } + } + else + logger('diaspora_signed_retraction: unknown type: ' . $type); + + return 202; + // NOTREACHED +} + +function diaspora_profile($importer,$xml,$msg) { + + $a = get_app(); + $diaspora_handle = notags(unxmlify($xml->diaspora_handle)); + + + if($diaspora_handle != $msg['author']) { + logger('diaspora_post: Potential forgery. Message handle is not the same as envelope sender.'); + return 202; + } + + $contact = diaspora_get_contact_by_handle($importer['channel_id'],$diaspora_handle); + if(! $contact) + return; + + if($contact['blocked']) { + logger('diaspora_post: Ignoring this author.'); + return 202; + } + + $name = unxmlify($xml->first_name) . ((strlen($xml->last_name)) ? ' ' . unxmlify($xml->last_name) : ''); + $image_url = unxmlify($xml->image_url); + $birthday = unxmlify($xml->birthday); + + + $handle_parts = explode("@", $diaspora_handle); + if($name === '') { + $name = $handle_parts[0]; + } + + if( preg_match("|^https?://|", $image_url) === 0) { + $image_url = "http://" . $handle_parts[1] . $image_url; + } + + require_once('include/photo/photo_driver.php'); + + $images = import_profile_photo($image_url,$contact['xchan_hash']); + + // Generic birthday. We don't know the timezone. The year is irrelevant. + + $birthday = str_replace('1000','1901',$birthday); + + $birthday = datetime_convert('UTC','UTC',$birthday,'Y-m-d'); + + // this is to prevent multiple birthday notifications in a single year + // if we already have a stored birthday and the 'm-d' part hasn't changed, preserve the entry, which will preserve the notify year + + if(substr($birthday,5) === substr($contact['bd'],5)) + $birthday = $contact['bd']; + + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s' ", + dbesc($name), + dbesc(datetime_convert()), + dbesc($images[0]), + dbesc($images[1]), + dbesc($images[2]), + dbesc($images[3]), + dbesc(datetime_convert()), + intval($contact['xchan_hash']) + ); + + return; + +} + +function diaspora_share($owner,$contact) { + $a = get_app(); + + $allowed = get_pconfig($owner['channel_id'],'system','diaspora_allowed'); + if($allowed === false) + $allowed = 1; + + if(! intval($allowed)) { + logger('diaspora_share: disallowed for channel ' . $importer['channel_name']); + return; + } + + + + $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + + if(! array_key_exists('xchan_hash',$contact)) { + $c = q("select * from xchan left join hubloc on xchan_hash = hubloc_hash where xchan_hash = '%s' limit 1", + dbesc($contact['hubloc_hash']) + ); + if(! $c) { + logger('diaspora_share: ' . $contact['hubloc_hash'] . ' not found.'); + return; + } + $contact = $c[0]; + } + + $theiraddr = $contact['xchan_addr']; + + $tpl = get_markup_template('diaspora_share.tpl'); + $msg = replace_macros($tpl, array( + '$sender' => $myaddr, + '$recipient' => $theiraddr + )); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey']))); + return(diaspora_transmit($owner,$contact,$slap, false)); +} + +function diaspora_unshare($owner,$contact) { + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + + $tpl = get_markup_template('diaspora_retract.tpl'); + $msg = replace_macros($tpl, array( + '$guid' => $owner['channel_guid'], + '$type' => 'Person', + '$handle' => $myaddr + )); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey']))); + + return(diaspora_transmit($owner,$contact,$slap, false)); +} + + +function diaspora_send_status($item,$owner,$contact,$public_batch = false) { + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + + if(intval($item['id']) != intval($item['parent'])) { + logger('attempted to send a comment as a top-level post'); + return; + } + + $images = array(); + + $title = $item['title']; + $body = bb2diaspora_itembody($item,true); + +/* + // We're trying to match Diaspora's split message/photo protocol but + // all the photos are displayed on D* as links and not img's - even + // though we're sending pretty much precisely what they send us when + // doing the same operation. + // Commented out for now, we'll use bb2diaspora to convert photos to markdown + // which seems to get through intact. + + $cnt = preg_match_all('|\[img\](.*?)\[\/img\]|',$body,$matches,PREG_SET_ORDER); + if($cnt) { + foreach($matches as $mtch) { + $detail = array(); + $detail['str'] = $mtch[0]; + $detail['path'] = dirname($mtch[1]) . '/'; + $detail['file'] = basename($mtch[1]); + $detail['guid'] = $item['guid']; + $detail['handle'] = $myaddr; + $images[] = $detail; + $body = str_replace($detail['str'],$mtch[1],$body); + } + } +*/ + + if(intval($item['item_consensus'])) { + $poll = replace_macros(get_markup_template('diaspora_consensus.tpl'), array( + '$guid_q' => '10000000', + '$question' => t('Please choose'), + '$guid_y' => '00000001', + '$agree' => t('Agree'), + '$guid_n' => '0000000F', + '$disagree' => t('Disagree'), + '$guid_a' => '00000000', + '$abstain' => t('Abstain') + )); + } + elseif($item['resource_type'] === 'event' && $item['resource_id']) { + $poll = replace_macros(get_markup_template('diaspora_consensus.tpl'), array( + '$guid_q' => '1000000', + '$question' => t('Please choose'), + '$guid_y' => '0000001', + '$agree' => t('I will attend'), + '$guid_n' => '000000F', + '$disagree' => t('I will not attend'), + '$guid_a' => '0000000', + '$abstain' => t('I may attend') + )); + } + else + $poll = ''; + + $public = (($item['item_private']) ? 'false' : 'true'); + + require_once('include/datetime.php'); + $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); + + // Detect a share element and do a reshare + // see: https://github.com/Raven24/diaspora-federation/blob/master/lib/diaspora-federation/entities/reshare.rb + if (!$item['item_private'] AND ($ret = diaspora_is_reshare($item["body"]))) { + $tpl = get_markup_template('diaspora_reshare.tpl'); + $msg = replace_macros($tpl, array( + '$root_handle' => xmlify($ret['root_handle']), + '$root_guid' => $ret['root_guid'], + '$guid' => $item['mid'], + '$handle' => xmlify($myaddr), + '$public' => $public, + '$created' => $created, + '$provider' => (($item['app']) ? $item['app'] : t('$projectname')) + )); + } else { + $tpl = get_markup_template('diaspora_post.tpl'); + $msg = replace_macros($tpl, array( + '$body' => xmlify($body), + '$guid' => $item['mid'], + '$poll' => $poll, + '$handle' => xmlify($myaddr), + '$public' => $public, + '$created' => $created, + '$provider' => (($item['app']) ? $item['app'] : t('$projectname')) + )); + } + + logger('diaspora_send_status: '.$owner['channel_name'].' -> '.$contact['xchan_name'].' base message: ' . $msg, LOGGER_DATA); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); + + $return_code = diaspora_transmit($owner,$contact,$slap,$public_batch); + +// logger('diaspora_send_status: guid: '.$item['mid'].' result '.$return_code, LOGGER_DEBUG); + + if(count($images)) { + diaspora_send_images($item,$owner,$contact,$images,$public_batch); + } + + return $return_code; +} + +function diaspora_is_reshare($body) { + + $body = trim($body); + + // Skip if it isn't a pure repeated messages + // Does it start with a share? + if(strpos($body, "[share") > 0) + return(false); + + // Does it end with a share? + if(strlen($body) > (strrpos($body, "[/share]") + 8)) + return(false); + + $attributes = preg_replace("/\[share(.*?)\]\s?(.*?)\s?\[\/share\]\s?/ism","$1",$body); + // Skip if there is no shared message in there + if ($body == $attributes) + return(false); + + $profile = ""; + preg_match("/profile='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $profile = $matches[1]; + + preg_match('/profile="(.*?)"/ism', $attributes, $matches); + if ($matches[1] != "") + $profile = $matches[1]; + + $ret= array(); + + $ret["root_handle"] = preg_replace("=https?://(.*)/u/(.*)=ism", "$2@$1", $profile); + if (($ret["root_handle"] == $profile) OR ($ret["root_handle"] == "")) + return(false); + + $link = ""; + preg_match("/link='(.*?)'/ism", $attributes, $matches); + if ($matches[1] != "") + $link = $matches[1]; + + preg_match('/link="(.*?)"/ism', $attributes, $matches); + if ($matches[1] != "") + $link = $matches[1]; + + $ret["root_guid"] = preg_replace("=https?://(.*)/posts/(.*)=ism", "$2", $link); + if (($ret["root_guid"] == $link) OR ($ret["root_guid"] == "")) + return(false); + + return($ret); +} + +function diaspora_send_images($item,$owner,$contact,$images,$public_batch = false) { + $a = get_app(); + if(! count($images)) + return; + $mysite = substr($a->get_baseurl(),strpos($a->get_baseurl(),'://') + 3) . '/photo'; + + $tpl = get_markup_template('diaspora_photo.tpl'); + foreach($images as $image) { + if(! stristr($image['path'],$mysite)) + continue; + $resource = str_replace('.jpg','',$image['file']); + $resource = substr($resource,0,strpos($resource,'-')); + + $r = q("select * from photo where `resource_id` = '%s' and `uid` = %d limit 1", + dbesc($resource), + intval($owner['uid']) + ); + if(! $r) + continue; + $public = (($r[0]['allow_cid'] || $r[0]['allow_gid'] || $r[0]['deny_cid'] || $r[0]['deny_gid']) ? 'false' : 'true' ); + $msg = replace_macros($tpl,array( + '$path' => xmlify($image['path']), + '$filename' => xmlify($image['file']), + '$msg_guid' => xmlify($image['guid']), + '$guid' => xmlify($r[0]['resource_id']), + '$handle' => xmlify($image['handle']), + '$public' => xmlify($public), + '$created_at' => xmlify(datetime_convert('UTC','UTC',$r[0]['created'],'Y-m-d H:i:s \U\T\C')) + )); + + + logger('diaspora_send_photo: base message: ' . $msg, LOGGER_DATA); + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); + + diaspora_transmit($owner,$contact,$slap,$public_batch); + } + +} + +function diaspora_send_followup($item,$owner,$contact,$public_batch = false) { + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); + $theiraddr = $contact['xchan_addr']; + + // Diaspora doesn't support threaded comments, but some + // versions of Diaspora (i.e. Diaspora-pistos) support + // likes on comments + if(($item['verb'] === ACTIVITY_LIKE || $item['verb'] === ACTIVITY_DISLIKE) && $item['thr_parent']) { + $p = q("select mid, parent_mid from item where mid = '%s' limit 1", + dbesc($item['thr_parent']) + ); + } + else { + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select * from item where parent = %d and id = %d limit 1", + intval($item['parent']), + intval($item['parent']) + ); + } + if($p) + $parent = $p[0]; + else + return; + + + if(($item['verb'] === ACTIVITY_LIKE) && ($parent['mid'] === $parent['parent_mid'])) { + $tpl = get_markup_template('diaspora_like.tpl'); + $like = true; + $target_type = 'Post'; + $positive = 'true'; + + if(intval($item['item_deleted'])) + logger('diaspora_send_followup: received deleted "like". Those should go to diaspora_send_retraction'); + } + else { + $tpl = get_markup_template('diaspora_comment.tpl'); + $like = false; + } + + if($item['diaspora_meta'] && ! $like) { + $diaspora_meta = json_decode($item['diaspora_meta'],true); + if($diaspora_meta) { + if(array_key_exists('iv',$diaspora_meta)) { + $key = get_config('system','prvkey'); + $meta = json_decode(crypto_unencapsulate($diaspora_meta,$key),true); + } + else + $meta = $diaspora_meta; + } + $signed_text = $meta['signed_text']; + $authorsig = $meta['signature']; + $signer = $meta['signer']; + $text = $meta['body']; + } + else { + $text = bb2diaspora_itembody($item); + + // sign it + + if($like) + $signed_text = $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $positive . ';' . $myaddr; + else + $signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $myaddr; + + $authorsig = base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256')); + + } + + $msg = replace_macros($tpl,array( + '$guid' => xmlify($item['mid']), + '$parent_guid' => xmlify($parent['mid']), + '$target_type' =>xmlify($target_type), + '$authorsig' => xmlify($authorsig), + '$body' => xmlify($text), + '$positive' => xmlify($positive), + '$handle' => xmlify($myaddr) + )); + + logger('diaspora_followup: base message: ' . $msg, LOGGER_DATA); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); + + + return(diaspora_transmit($owner,$contact,$slap,$public_batch)); +} + + +function diaspora_send_relay($item,$owner,$contact,$public_batch = false) { + + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); + + $text = bb2diaspora_itembody($item); + + $body = $text; + + // Diaspora doesn't support threaded comments, but some + // versions of Diaspora (i.e. Diaspora-pistos) support + // likes on comments + + if($item['verb'] === ACTIVITY_LIKE && $item['thr_parent']) { + $p = q("select * from item where mid = '%s' limit 1", + dbesc($item['thr_parent']) + ); + } + else { + // The first item in the `item` table with the parent id is the parent. However, MySQL doesn't always + // return the items ordered by `item`.`id`, in which case the wrong item is chosen as the parent. + // The only item with `parent` and `id` as the parent id is the parent item. + $p = q("select * from item where parent = %d and id = %d limit 1", + intval($item['parent']), + intval($item['parent']) + ); + } + + if($p) + $parent = $p[0]; + else { + logger('diaspora_send_relay: no parent'); + return; + } + + $like = false; + $relay_retract = false; + $sql_sign_id = 'iid'; + + if( intval($item['item_deleted'])) { + $relay_retract = true; + + $target_type = ( ($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); + + $sql_sign_id = 'retract_iid'; + $tpl = get_markup_template('diaspora_relayable_retraction.tpl'); + } + elseif($item['verb'] === ACTIVITY_LIKE) { + $like = true; + + $target_type = ( $parent['mid'] === $parent['parent_mid'] ? 'Post' : 'Comment'); +// $positive = (intval($item['item_deleted']) ? 'false' : 'true'); + $positive = 'true'; + + $tpl = get_markup_template('diaspora_like_relay.tpl'); + } + else { // item is a comment + $tpl = get_markup_template('diaspora_comment_relay.tpl'); + } + + $diaspora_meta = (($item['diaspora_meta']) ? json_decode($item['diaspora_meta'],true) : ''); + if($diaspora_meta) { + if(array_key_exists('iv',$diaspora_meta)) { + $key = get_config('system','prvkey'); + $meta = json_decode(crypto_unencapsulate($diaspora_meta,$key),true); + } + else + $meta = $diaspora_meta; + $sender_signed_text = $meta['signed_text']; + $authorsig = $meta['signature']; + $handle = $meta['signer']; + $text = $meta['body']; + } + else + logger('diaspora_send_relay: original author signature not found'); + + /* Since the author signature is only checked by the parent, not by the relay recipients, + * I think it may not be necessary for us to do so much work to preserve all the original + * signatures. The important thing that Diaspora DOES need is the original creator's handle. + * Let's just generate that and forget about all the original author signature stuff. + * + * Note: this might be more of an problem if we want to support likes on comments for older + * versions of Diaspora (diaspora-pistos), but since there are a number of problems with + * doing that, let's ignore it for now. + * + * + */ +// bug - nomadic identity may/will affect diaspora_handle_from_contact + if(! $handle) { + if($item['author_xchan'] === $owner['channel_hash']) + $handle = $owner['channel_address'] . '@' . substr($a->get_baseurl(), strpos($a->get_baseurl(),'://') + 3); + else + $handle = diaspora_handle_from_contact($item['author_xchan']); + } + if(! $handle) { + logger('diaspora_send_relay: no handle'); + return; + } + + if(! $sender_signed_text) { + if($relay_retract) + $sender_signed_text = $item['mid'] . ';' . $target_type; + elseif($like) + $sender_signed_text = $positive . ';' . $item['mid'] . ';' . $target_type . ';' . $parent['mid'] . ';' . $handle; + else + $sender_signed_text = $item['mid'] . ';' . $parent['mid'] . ';' . $text . ';' . $handle; + } + + // Sign the relayable with the top-level owner's signature + // + // We'll use the $sender_signed_text that we just created, instead of the $signed_text + // stored in the database, because that provides the best chance that Diaspora will + // be able to reconstruct the signed text the same way we did. This is particularly a + // concern for the comment, whose signed text includes the text of the comment. The + // smallest change in the text of the comment, including removing whitespace, will + // make the signature verification fail. Since we translate from BB code to Diaspora's + // markup at the top of this function, which is AFTER we placed the original $signed_text + // in the database, it's hazardous to trust the original $signed_text. + + $parentauthorsig = base64_encode(rsa_sign($sender_signed_text,$owner['channel_prvkey'],'sha256')); + + if(! $text) + logger('diaspora_send_relay: no text'); + + $msg = replace_macros($tpl,array( + '$guid' => xmlify($item['mid']), + '$parent_guid' => xmlify($parent['mid']), + '$target_type' =>xmlify($target_type), + '$authorsig' => xmlify($authorsig), + '$parentsig' => xmlify($parentauthorsig), + '$body' => xmlify($text), + '$positive' => xmlify($positive), + '$handle' => xmlify($handle) + )); + + logger('diaspora_send_relay: base message: ' . $msg, LOGGER_DATA); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); + + return(diaspora_transmit($owner,$contact,$slap,$public_batch)); + +} + + + +function diaspora_send_retraction($item,$owner,$contact,$public_batch = false) { + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); + + // Check whether the retraction is for a top-level post or whether it's a relayable + if( $item['mid'] !== $item['parent_mid'] ) { + + $tpl = get_markup_template('diaspora_relay_retraction.tpl'); + $target_type = (($item['verb'] === ACTIVITY_LIKE) ? 'Like' : 'Comment'); + } + else { + + $tpl = get_markup_template('diaspora_signed_retract.tpl'); + $target_type = 'StatusMessage'; + } + + $signed_text = $item['mid'] . ';' . $target_type; + + $msg = replace_macros($tpl, array( + '$guid' => xmlify($item['mid']), + '$type' => xmlify($target_type), + '$handle' => xmlify($myaddr), + '$signature' => xmlify(base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256'))) + )); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($msg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],$public_batch))); + + return(diaspora_transmit($owner,$contact,$slap,$public_batch)); +} + +function diaspora_send_mail($item,$owner,$contact) { + + $a = get_app(); + $myaddr = $owner['channel_address'] . '@' . get_app()->get_hostname(); + + $r = q("select * from conv where id = %d and uid = %d limit 1", + intval($item['convid']), + intval($item['channel_id']) + ); + + if(! count($r)) { + logger('diaspora_send_mail: conversation not found.'); + return; + } + $cnv = $r[0]; + + $conv = array( + 'guid' => xmlify($cnv['guid']), + 'subject' => xmlify($cnv['subject']), + 'created_at' => xmlify(datetime_convert('UTC','UTC',$cnv['created'],'Y-m-d H:i:s \U\T\C')), + 'diaspora_handle' => xmlify($cnv['creator']), + 'participant_handles' => xmlify($cnv['recips']) + ); + + if(array_key_exists('mail_obscured',$item) && intval($item['mail_obscured'])) { + if($item['title']) + $item['title'] = base64url_decode(str_rot47($item['title'])); + if($item['body']) + $item['body'] = base64url_decode(str_rot47($item['body'])); + } + + + $body = bb2diaspora($item['body']); + $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); + + $signed_text = $item['mid'] . ';' . $cnv['guid'] . ';' . $body . ';' + . $created . ';' . $myaddr . ';' . $cnv['guid']; + + $sig = base64_encode(rsa_sign($signed_text,$owner['channel_prvkey'],'sha256')); + + $msg = array( + 'guid' => xmlify($item['mid']), + 'parent_guid' => xmlify($cnv['guid']), + 'parent_author_signature' => (($item['reply']) ? null : xmlify($sig)), + 'author_signature' => xmlify($sig), + 'text' => xmlify($body), + 'created_at' => xmlify($created), + 'diaspora_handle' => xmlify($myaddr), + 'conversation_guid' => xmlify($cnv['guid']) + ); + + if($item['reply']) { + $tpl = get_markup_template('diaspora_message.tpl'); + $xmsg = replace_macros($tpl, array('$msg' => $msg)); + } + else { + $conv['messages'] = array($msg); + $tpl = get_markup_template('diaspora_conversation.tpl'); + $xmsg = replace_macros($tpl, array('$conv' => $conv)); + } + + logger('diaspora_conversation: ' . print_r($xmsg,true), LOGGER_DATA); + + $slap = 'xml=' . urlencode(urlencode(diaspora_msg_build($xmsg,$owner,$contact,$owner['channel_prvkey'],$contact['xchan_pubkey'],false))); + + return(diaspora_transmit($owner,$contact,$slap,false)); + + +} + +function diaspora_transmit($owner,$contact,$slap,$public_batch,$queue_run=false) { + + + $allowed = get_pconfig($owner['channel_id'],'system','diaspora_allowed'); + if($allowed === false) + $allowed = 1; + + if(! intval($allowed)) { + return 200; + } + + if($public_batch) + $dest_url = $contact['hubloc_callback'] . '/public'; + else + $dest_url = $contact['hubloc_callback'] . '/users/' . $contact['hubloc_guid']; + + logger('diaspora_transmit: URL: ' . $dest_url, LOGGER_DEBUG); + + if(intval(get_config('system','diaspora_test'))) + return 200; + + $a = get_app(); + $logid = random_string(4); + + logger('diaspora_transmit: ' . $logid . ' ' . $dest_url, LOGGER_DEBUG); + + $hash = random_string(); + + $interval = ((get_config('system','delivery_interval') !== false) + ? intval(get_config('system','delivery_interval')) : 2 ); + + q("insert into outq ( outq_hash, outq_account, outq_channel, outq_driver, outq_posturl, outq_async, outq_created, outq_updated, outq_notify, outq_msg ) values ( '%s', %d, %d, '%s', '%s', %d, '%s', '%s', '%s', '%s' )", + dbesc($hash), + intval($owner['account_id']), + intval($owner['channel_id']), + dbesc('post'), + dbesc($dest_url), + intval(1), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + dbesc(''), + dbesc($slap) + ); + + proc_run('php','include/deliver.php',$hash); + if($interval) + @time_sleep_until(microtime(true) + (float) $interval); + +} + + +function diaspora_follow_allow(&$a, &$b) { + + $b['allowed'] = intval(get_pconfig($b['channel_id'],'system','diaspora_allowed')); + +} + + +function diaspora_discover(&$a,&$b) { + + require_once('include/network.php'); + + $result = array(); + $network = null; + $diaspora = false; + + $diaspora_base = ''; + $diaspora_guid = ''; + $diaspora_key = ''; + $dfrn = false; + + $x = old_webfinger($webbie); + if($x) { + logger('old_webfinger: ' . print_r($x,true)); + foreach($x as $link) { + if($link['@attributes']['rel'] === NAMESPACE_DFRN) + $dfrn = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'salmon') + $notify = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === NAMESPACE_FEED) + $poll = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://microformats.org/profile/hcard') + $hcard = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://webfinger.net/rel/profile-page') + $profile = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://portablecontacts.net/spec/1.0') + $poco = unamp($link['@attributes']['href']); + if($link['@attributes']['rel'] === 'http://joindiaspora.com/seed_location') { + $diaspora_base = unamp($link['@attributes']['href']); + $diaspora = true; + } + if($link['@attributes']['rel'] === 'http://joindiaspora.com/guid') { + $diaspora_guid = unamp($link['@attributes']['href']); + $diaspora = true; + } + if($link['@attributes']['rel'] === 'diaspora-public-key') { + $diaspora_key = base64_decode(unamp($link['@attributes']['href'])); + if(strstr($diaspora_key,'RSA ')) + $pubkey = rsatopem($diaspora_key); + else + $pubkey = $diaspora_key; + $diaspora = true; + } + } + + if($diaspora && $diaspora_base && $diaspora_guid) { + $guid = $diaspora_guid; + $diaspora_base = trim($diaspora_base,'/'); + + $notify = $diaspora_base . '/receive'; + + if(strpos($webbie,'@')) { + $addr = str_replace('acct:', '', $webbie); + $hostname = substr($webbie,strpos($webbie,'@')+1); + } + $network = 'diaspora'; + // until we get a dfrn layer, we'll use diaspora protocols for Friendica, + // but give it a different network so we can go back and fix these when we get proper support. + // It really should be just 'friendica' but we also want to distinguish + // between Friendica sites that we can use D* protocols with and those we can't. + // Some Friendica sites will have Diaspora disabled. + if($dfrn) + $network = 'friendica-over-diaspora'; + if($hcard) { + $vcard = scrape_vcard($hcard); + $vcard['nick'] = substr($webbie,0,strpos($webbie,'@')); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($addr) + ); + + /** + * + * Diaspora communications are notoriously unreliable and receiving profile update messages (indeed any messages) + * are pretty much random luck. We'll check the timestamp of the xchan_name_date at a higher level and refresh + * this record once a month; because if you miss a profile update message and they update their profile photo or name + * you're otherwise stuck with stale info until they change their profile again - which could be years from now. + * + */ + + if($r) { + $r = q("update xchan set xchan_name = '%s', xchan_network = '%s', xchan_name_date = '%s' where xchan_hash = '%s' limit 1", + dbesc($vcard['fn']), + dbesc($network), + dbesc(datetime_convert()), + dbesc($addr) + ); + } + else { + + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_pubkey, xchan_addr, xchan_url, xchan_name, xchan_network, xchan_instance_url, xchan_name_date ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ", + dbesc($addr), + dbesc($guid), + dbesc($pubkey), + dbesc($addr), + dbesc($profile), + dbesc($vcard['fn']), + dbesc($network), + dbesc(z_root()), + dbescdate(datetime_convert()) + ); + } + + $r = q("select * from hubloc where hubloc_hash = '%s' limit 1", + dbesc($webbie) + ); + + if(! $r) { + + $r = q("insert into hubloc ( hubloc_guid, hubloc_hash, hubloc_addr, hubloc_network, hubloc_url, hubloc_host, hubloc_callback, hubloc_updated, hubloc_primary ) values ('%s','%s','%s','%s','%s','%s','%s','%s', 1)", + dbesc($guid), + dbesc($addr), + dbesc($addr), + dbesc($network), + dbesc(trim($diaspora_base,'/')), + dbesc($hostname), + dbesc($notify), + dbescdate(datetime_convert()) + ); + } + $photos = import_profile_photo($vcard['photo'],$addr); + $r = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", + dbescdate(datetime_convert('UTC','UTC',$arr['photo_updated'])), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($addr) + ); + return true; + + } + + return false; + +/* + $vcard['fn'] = notags($vcard['fn']); + $vcard['nick'] = str_replace(' ','',notags($vcard['nick'])); + + $result['name'] = $vcard['fn']; + $result['nick'] = $vcard['nick']; + $result['guid'] = $guid; + $result['url'] = $profile; + $result['hostname'] = $hostname; + $result['addr'] = $addr; + $result['batch'] = $batch; + $result['notify'] = $notify; + $result['poll'] = $poll; + $result['request'] = $request; + $result['confirm'] = $confirm; + $result['poco'] = $poco; + $result['photo'] = $vcard['photo']; + $result['priority'] = $priority; + $result['network'] = $network; + $result['alias'] = $alias; + $result['pubkey'] = $pubkey; + + logger('probe_url: ' . print_r($result,true), LOGGER_DEBUG); + + return $result; + +*/ + +/* Sample Diaspora result. + +Array +( + [name] => Mike Macgirvin + [nick] => macgirvin + [guid] => a9174a618f8d269a + [url] => https://joindiaspora.com/u/macgirvin + [hostname] => joindiaspora.com + [addr] => macgirvin@joindiaspora.com + [batch] => + [notify] => https://joindiaspora.com/receive + [poll] => https://joindiaspora.com/public/macgirvin.atom + [request] => + [confirm] => + [poco] => + [photo] => https://joindiaspora.s3.amazonaws.com/uploads/images/thumb_large_fec4e6eef13ae5e56207.jpg + [priority] => + [network] => diaspora + [alias] => + [pubkey] => -----BEGIN PUBLIC KEY----- +MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtihtyIuRDWkDpCA+I1UaQ +jI4S7k625+A7EEJm+pL2ZVSJxeCKiFeEgHBQENjLMNNm8l8F6blxgQqE6ZJ9Spa7f +tlaXYTRCrfxKzh02L3hR7sNA+JS/nXJaUAIo+IwpIEspmcIRbD9GB7Wv/rr+M28uH +31EeYyDz8QL6InU/bJmnCdFvmEMBQxJOw1ih9tQp7UNJAbUMCje0WYFzBz7sfcaHL +OyYcCOqOCBLdGucUoJzTQ9iDBVzB8j1r1JkIHoEb2moUoKUp+tkCylNfd/3IVELF9 +7w1Qjmit3m50OrJk2DQOXvCW9KQxaQNdpRPSwhvemIt98zXSeyZ1q/YjjOwG0DWDq +AF8aLj3/oQaZndTPy/6tMiZogKaijoxj8xFLuPYDTw5VpKquriVC0z8oxyRbv4t9v +8JZZ9BXqzmayvY3xZGGp8NulrfjW+me2bKh0/df1aHaBwpZdDTXQ6kqAiS2FfsuPN +vg57fhfHbL1yJ4oDbNNNeI0kJTGchXqerr8C20khU/cQ2Xt31VyEZtnTB665Ceugv +kp3t2qd8UpAVKl430S5Quqx2ymfUIdxdW08CEjnoRNEL3aOWOXfbf4gSVaXmPCR4i +LSIeXnd14lQYK/uxW/8cTFjcmddsKxeXysoQxbSa9VdDK+KkpZdgYXYrTTofXs6v+ +4afAEhRaaY+MCAwEAAQ== +-----END PUBLIC KEY----- + +) +*/ + + + + + } +} + + +function diaspora_feature_settings_post(&$a,&$b) { + + if($_POST['diaspora-submit']) { + set_pconfig(local_channel(),'system','diaspora_allowed',intval($_POST['dspr_allowed'])); + set_pconfig(local_channel(),'system','diaspora_public_comments',intval($_POST['dspr_pubcomment'])); + set_pconfig(local_channel(),'system','prevent_tag_hijacking',intval($_POST['dspr_hijack'])); + info( t('Diaspora Protocol Settings updated.') . EOL); + } +} + + +function diaspora_feature_settings(&$a,&$s) { + $dspr_allowed = get_pconfig(local_channel(),'system','diaspora_allowed'); + $pubcomments = get_pconfig(local_channel(),'system','diaspora_public_comments'); + if($pubcomments === false) + $pubcomments = 1; + $hijacking = get_pconfig(local_channel(),'system','prevent_tag_hijacking'); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('dspr_allowed', t('Enable the (experimental) Diaspora protocol for this channel'), $dspr_allowed, '', $yes_no), + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('dspr_pubcomment', t('Allow any Diaspora member to comment on your public posts'), $pubcomments, '', $yes_no), + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('dspr_hijack', t('Prevent your hashtags from being redirected to other sites'), $hijacking, '', $yes_no), + )); + + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('diaspora', '' . t('Diaspora Protocol Settings'), '', t('Submit')), + '$content' => $sc + )); + + return; + +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/diaspora/p.php b/sources/extend/addon/matrix/diaspora/p.php new file mode 100644 index 00000000..3df8cd55 --- /dev/null +++ b/sources/extend/addon/matrix/diaspora/p.php @@ -0,0 +1,52 @@ +get_hostname(); + + $item = $r[0]; + + $title = $item['title']; + $body = bb2diaspora_itembody($item); + $created = datetime_convert('UTC','UTC',$item['created'],'Y-m-d H:i:s \U\T\C'); + + $tpl = get_markup_template('diaspora_post.tpl'); + $msg = replace_macros($tpl, array( + '$body' => xmlify($body), + '$guid' => $item['mid'], + '$handle' => xmlify($myaddr), + '$public' => 'true', + '$created' => $created, + '$provider' => (($item['app']) ? $item['app'] : t('$projectname')) + )); + + header('Content-type: text/xml'); + echo $msg; + killme(); +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/diaspora/receive.php b/sources/extend/addon/matrix/diaspora/receive.php new file mode 100644 index 00000000..0c73a57c --- /dev/null +++ b/sources/extend/addon/matrix/diaspora/receive.php @@ -0,0 +1,69 @@ +token_regex = '/content="(.*?)" name="csrf-token/'; + + $this->pod = $pod; + $this->cookiejar = tempnam(sys_get_temp_dir(), 'cookies'); + } + + function _fetch_token() { + $ch = curl_init(); + + curl_setopt ($ch, CURLOPT_URL, $this->pod . "/stream"); + curl_setopt ($ch, CURLOPT_COOKIEFILE, $this->cookiejar); + curl_setopt ($ch, CURLOPT_COOKIEJAR, $this->cookiejar); + curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); + + $output = curl_exec ($ch); + curl_close($ch); + + // Token holen und zurückgeben + preg_match($this->token_regex, $output, $matches); + return $matches[1]; + } + + function login($username, $password) { + $datatopost = array( + 'user[username]' => $username, + 'user[password]' => $password, + 'authenticity_token' => $this->_fetch_token() + ); + + $poststr = http_build_query($datatopost); + + // Adresse per cURL abrufen + $ch = curl_init(); + + curl_setopt ($ch, CURLOPT_URL, $this->pod . "/users/sign_in"); + curl_setopt ($ch, CURLOPT_COOKIEFILE, $this->cookiejar); + curl_setopt ($ch, CURLOPT_COOKIEJAR, $this->cookiejar); + curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt ($ch, CURLOPT_POST, true); + curl_setopt ($ch, CURLOPT_POSTFIELDS, $poststr); + + curl_exec ($ch); + $info = curl_getinfo($ch); + curl_close($ch); + + if($info['http_code'] != 302) { + throw new Exception('Login error '.print_r($info, true)); + } + + // Das Objekt zurückgeben, damit man Aurufe verketten kann. + return $this; + } + + function post($text, $provider = "diasphp") { + // post-daten vorbereiten + $datatopost = json_encode(array( + 'aspect_ids' => 'public', + 'status_message' => array('text' => $text, + 'provider_display_name' => $provider) + )); + + // header vorbereiten + $headers = array( + 'Content-Type: application/json', + 'accept: application/json', + 'x-csrf-token: '.$this->_fetch_token() + ); + + // Adresse per cURL abrufen + $ch = curl_init(); + + curl_setopt ($ch, CURLOPT_URL, $this->pod . "/status_messages"); + curl_setopt ($ch, CURLOPT_COOKIEFILE, $this->cookiejar); + curl_setopt ($ch, CURLOPT_COOKIEJAR, $this->cookiejar); + curl_setopt ($ch, CURLOPT_FOLLOWLOCATION, false); + curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt ($ch, CURLOPT_POST, true); + curl_setopt ($ch, CURLOPT_POSTFIELDS, $datatopost); + curl_setopt ($ch, CURLOPT_HTTPHEADER, $headers); + + curl_exec ($ch); + $info = curl_getinfo($ch); + curl_close($ch); + + if($info['http_code'] != 201) { + throw new Exception('Post error '.print_r($info, true)); + } + + // Ende der möglichen Kette, gib mal "true" zurück. + return true; + } +} +?> diff --git a/sources/extend/addon/matrix/diaspost/diaspora.png b/sources/extend/addon/matrix/diaspost/diaspora.png new file mode 100644 index 00000000..96665916 Binary files /dev/null and b/sources/extend/addon/matrix/diaspost/diaspora.png differ diff --git a/sources/extend/addon/matrix/diaspost/diaspost.css b/sources/extend/addon/matrix/diaspost/diaspost.css new file mode 100755 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/diaspost/diaspost.php b/sources/extend/addon/matrix/diaspost/diaspost.php new file mode 100755 index 00000000..b4200fc8 --- /dev/null +++ b/sources/extend/addon/matrix/diaspost/diaspost.php @@ -0,0 +1,337 @@ + + */ + +function diaspost_load() { + register_hook('post_local', 'addon/diaspost/diaspost.php', 'diaspost_post_local'); + register_hook('notifier_normal', 'addon/diaspost/diaspost.php', 'diaspost_send'); + register_hook('jot_networks', 'addon/diaspost/diaspost.php', 'diaspost_jot_nets'); + register_hook('feature_settings', 'addon/diaspost/diaspost.php', 'diaspost_settings'); + register_hook('feature_settings_post', 'addon/diaspost/diaspost.php', 'diaspost_settings_post'); + +} +function diaspost_unload() { + unregister_hook('post_local', 'addon/diaspost/diaspost.php', 'diaspost_post_local'); + unregister_hook('notifier_normal', 'addon/diaspost/diaspost.php', 'diaspost_send'); + unregister_hook('jot_networks', 'addon/diaspost/diaspost.php', 'diaspost_jot_nets'); + unregister_hook('feature_settings', 'addon/diaspost/diaspost.php', 'diaspost_settings'); + unregister_hook('feature_settings_post', 'addon/diaspost/diaspost.php', 'diaspost_settings_post'); + +} + + +function diaspost_jot_nets(&$a,&$b) { + if((! local_channel()) || (! perm_is_allowed(local_channel(),'','view_stream'))) + return; + + $diaspost_post = get_pconfig(local_channel(),'diaspost','post'); + if(intval($diaspost_post) == 1) { + $diaspost_defpost = get_pconfig(local_channel(),'diaspost','post_by_default'); + $selected = ((intval($diaspost_defpost) == 1) ? ' checked="checked" ' : ''); + $b .= '
' . t('Post to Diaspora') . '
'; + } +} + +function diaspost_queue_hook(&$a,&$b) { + $hostname = $a->get_hostname(); + + $qi = q("SELECT * FROM `queue` WHERE `network` = '%s'", + dbesc(NETWORK_DIASPORA2) + ); + if(! count($qi)) + return; + + require_once('include/queue_fn.php'); + + foreach($qi as $x) { + if($x['network'] !== NETWORK_DIASPORA2) + continue; + + logger('diaspost_queue: run'); + + $r = q("SELECT `user`.* FROM `user` LEFT JOIN `contact` on `contact`.`uid` = `user`.`uid` + WHERE `contact`.`self` = 1 AND `contact`.`id` = %d LIMIT 1", + intval($x['cid']) + ); + if(! count($r)) + continue; + + $userdata = $r[0]; + + $diaspost_username = get_pconfig($userdata['uid'],'diaspost','diaspost_username'); + $diaspost_password = z_unobscure(get_pconfig($userdata['uid'],'diaspost','diaspost_password')); + $diaspost_url = get_pconfig($userdata['uid'],'diaspost','diaspost_url'); + + $success = false; + + if($diaspost_url && $diaspost_username && $diaspost_password) { + require_once("addon/diaspost/diasphp.php"); + + logger('diaspost_queue: able to post for user '.$diaspost_username); + + $z = unserialize($x['content']); + + $post = $z['post']; + + logger('diaspost_queue: post: '.$post, LOGGER_DATA); + + try { + logger('diaspost_queue: prepare', LOGGER_DEBUG); + $conn = new Diasphp($diaspost_url); + logger('diaspost_queue: try to log in '.$diaspost_username, LOGGER_DEBUG); + $conn->login($diaspost_username, $diaspost_password); + logger('diaspost_queue: try to send '.$body, LOGGER_DEBUG); + $conn->post($post, $hostname); + + logger('diaspost_queue: send '.$userdata['uid'].' success', LOGGER_DEBUG); + + $success = true; + + remove_queue_item($x['id']); + } catch (Exception $e) { + logger("diaspost_queue: Send ".$userdata['uid']." failed: ".$e->getMessage(), LOGGER_DEBUG); + } + } else + logger('diaspost_queue: send '.$userdata['uid'].' missing username or password', LOGGER_DEBUG); + + if (!$success) { + logger('diaspost_queue: delayed'); + update_queue_time($x['id']); + } + } +} + +function diaspost_settings(&$a,&$s) { + + if(! local_channel()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + //$a->page['htmlhead'] .= '' . "\r\n"; + + /* Get the current state of our config variables */ + + $enabled = get_pconfig(local_channel(),'diaspost','post'); + $checked = (($enabled) ? '1' : false); + $css = (($enabled) ? '' : '-disabled'); + + $def_enabled = get_pconfig(local_channel(),'diaspost','post_by_default'); + + $def_checked = (($def_enabled) ? 1 : false); + + $diaspost_username = get_pconfig(local_channel(), 'diaspost', 'diaspost_username'); + $diaspost_password = z_unobscure(get_pconfig(local_channel(), 'diaspost', 'diaspost_password')); + $diaspost_url = get_pconfig(local_channel(), 'diaspost', 'diaspost_url'); + + $status = ""; + + if ($diaspost_username AND $diaspost_password AND $diaspost_url) { + try { + require_once("addon/diaspost/diasphp.php"); + + $conn = new Diasphp($diaspost_url); + $conn->login($diaspost_username, $diaspost_password); + } catch (Exception $e) { + $status = t("Can't login to your Diaspora account. Please check username and password and ensure you used the complete address (including http...)"); + } + } + + /* Add some HTML to the existing form */ + if ($status) { + $sc .= '
'; + $sc .= '' . $status . ''; + $sc .= '
'; + } + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('diaspost', t('Enable Diaspost Post Plugin'), $checked, '', array(t('No'),t('Yes'))), + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('diaspost_username', t('Diaspora username'), $diaspost_username, '') + )); + + $sc .= replace_macros(get_markup_template('field_password.tpl'), array( + '$field' => array('diaspost_password', t('Diaspora password'), $diaspost_password, '') + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('diaspost_url', t('Diaspora site URL'), $diaspost_url, 'Example: https://joindiaspora.com') + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('diaspost_bydefault', t('Post to Diaspora by default'), $def_checked, '', array(t('No'),t('Yes'))), + )); + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('diaspost', '' . t('Diaspost Post Settings'), '', t('Submit')), + '$content' => $sc + )); + + return; +} + + +function diaspost_settings_post(&$a,&$b) { + + if(x($_POST,'diaspost-submit')) { + + set_pconfig(local_channel(),'diaspost','post',intval($_POST['diaspost'])); + set_pconfig(local_channel(),'diaspost','post_by_default',intval($_POST['diaspost_bydefault'])); + set_pconfig(local_channel(),'diaspost','diaspost_username',trim($_POST['diaspost_username'])); + set_pconfig(local_channel(),'diaspost','diaspost_password',z_obscure(trim($_POST['diaspost_password']))); + set_pconfig(local_channel(),'diaspost','diaspost_url',trim($_POST['diaspost_url'])); + + } + +} + +function diaspost_post_local(&$a,&$b) { + + if($b['created'] != $b['edited']) + return; + + if(! perm_is_allowed($b['uid'],'','view_stream')) + return; + + + if((! local_channel()) || (local_channel() != $b['uid'])) + return; + + if($b['item_private']) + return; + + $diaspost_post = intval(get_pconfig(local_channel(),'diaspost','post')); + + $diaspost_enable = (($diaspost_post && x($_REQUEST,'diaspost_enable')) ? intval($_REQUEST['diaspost_enable']) : 0); + + if($_REQUEST['api_source'] && intval(get_pconfig(local_channel(),'diaspost','post_by_default'))) + $diaspost_enable = 1; + + if(! $diaspost_enable) + return; + + if(strlen($b['postopts'])) + $b['postopts'] .= ','; + $b['postopts'] .= 'diaspost'; +} + + + + +function diaspost_send(&$a,&$b) { + $hostname = 'hubzilla ' . '(' . $a->get_hostname() . ')'; + + logger('diaspost_send: invoked',LOGGER_DEBUG); + + if($b['mid'] != $b['parent_mid']) + return; + + if((! is_item_normal($b)) || $b['item_private'] || ($b['created'] !== $b['edited'])) + return; + + + if(! perm_is_allowed($b['uid'],'','view_stream')) + return; + + + if(! strstr($b['postopts'],'diaspost')) + return; + + + logger('diaspost_send: prepare posting', LOGGER_DEBUG); + + $diaspost_username = get_pconfig($b['uid'],'diaspost','diaspost_username'); + $diaspost_password = z_unobscure(get_pconfig($b['uid'],'diaspost','diaspost_password')); + $diaspost_url = get_pconfig($b['uid'],'diaspost','diaspost_url'); + + if($diaspost_url && $diaspost_username && $diaspost_password) { + + logger('diaspost_send: all values seem to be okay', LOGGER_DEBUG); + + require_once('include/bb2diaspora.php'); + $tag_arr = array(); + $tags = ''; + $x = preg_match_all('/\#\[(.*?)\](.*?)\[/',$b['tag'],$matches,PREG_SET_ORDER); + + if($x) { + foreach($matches as $mtch) { + $tag_arr[] = $mtch[2]; + } + } + if(count($tag_arr)) + $tags = implode(',',$tag_arr); + + $title = $b['title']; + $body = $b['body']; + // Insert a newline before and after a quote + $body = str_ireplace("[quote", "\n\n[quote", $body); + $body = str_ireplace("[/quote]", "[/quote]\n\n", $body); + + // strip bookmark indicators + + $body = preg_replace('/\#\^\[([zu])rl/i', '[$1rl', $body); + + $body = preg_replace('/\#\^http/i', 'http', $body); + + + if(intval(get_pconfig($item['uid'],'system','prevent_tag_hijacking'))) { + $new_tag = html_entity_decode('⋕',ENT_COMPAT,'UTF-8'); + $new_mention = html_entity_decode('@',ENT_COMPAT,'UTF-8'); + + // #-tags + $body = preg_replace('/\#\[url/i', $new_tag . '[url', $body); + $body = preg_replace('/\#\[zrl/i', $new_tag . '[zrl', $body); + // @-mentions + $body = preg_replace('/\@\!?\[url/i', $new_mention . '[url', $body); + $body = preg_replace('/\@\!?\[zrl/i', $new_mention . '[zrl', $body); + } + + // remove multiple newlines + do { + $oldbody = $body; + $body = str_replace("\n\n\n", "\n\n", $body); + } while ($oldbody != $body); + + // convert to markdown + $body = bb2diaspora($body, false, true); + + // Adding the title + if(strlen($title)) + $body = "## ".html_entity_decode($title)."\n\n".$body; + + require_once("addon/diaspost/diasphp.php"); + + try { + logger('diaspost_send: prepare', LOGGER_DEBUG); + $conn = new Diasphp($diaspost_url); + logger('diaspost_send: try to log in '.$diaspost_username, LOGGER_DEBUG); + $conn->login($diaspost_username, $diaspost_password); + logger('diaspost_send: try to send '.$body, LOGGER_DEBUG); + + //throw new Exception('Test'); + $conn->post($body, $hostname); + + logger('diaspost_send: success'); + } catch (Exception $e) { + logger("diaspost_send: Error submitting the post: " . $e->getMessage()); + +// logger('diaspost_send: requeueing '.$b['uid'], LOGGER_DEBUG); + +// $r = q("SELECT `id` FROM `contact` WHERE `uid` = %d AND `self`", $b['uid']); +// if (count($r)) +// $a->contact = $r[0]["id"]; + +// $s = serialize(array('url' => $url, 'item' => $b['id'], 'post' => $body)); +// require_once('include/queue_fn.php'); +// add_to_queue($a->contact,NETWORK_DIASPORA2,$s); +// notice(t('Diaspost post failed. Queued for retry.').EOL); + } + } +} diff --git a/sources/extend/addon/matrix/dirstats/dirstats.php b/sources/extend/addon/matrix/dirstats/dirstats.php new file mode 100644 index 00000000..21780eef --- /dev/null +++ b/sources/extend/addon/matrix/dirstats/dirstats.php @@ -0,0 +1,204 @@ + +*/ + +function dirstats_load() { + register_hook('cron_daily', 'addon/dirstats/dirstats.php', 'dirstats_cron'); +} +function dirstats_unload() { + unregister_hook('cron_daily', 'addon/dirstats/dirstats.php', 'dirstats_cron'); +} +function dirstats_module() {} + + +function dirstats_init() { + if(! get_config('dirstats','hubcount')) + dirstats_cron($a,$b); + +} + +function dirstats_content(&$a) { + + $hubcount = get_config('dirstats','hubcount'); + $zotcount = get_config('dirstats','zotcount'); + $friendicacount = get_config('dirstats','friendicacount'); + $diasporacount = get_config('dirstats','diasporacount'); + $channelcount = get_config('dirstats','channelcount'); + $friendicachannelcount = get_config('dirstats','friendicachannelcount'); + $diasporachannelcount = get_config('dirstats','diasporachannelcount'); + $over35s = get_config('dirstats','over35s'); + $under35s = get_config('dirstats','under35s'); + $average = get_config('dirstats','averageage'); + $chatrooms = get_config('dirstats','chatrooms'); + $tags = get_config('dirstats','tags'); + + $ob = $a->get_observer(); + $observer = $ob['xchan_hash']; + // Requested by Martin + $fountainofyouth = get_xconfig($observer, 'dirstats', 'averageage'); + if (intval($fountainofyouth)) + $average = $fountainofyouth; + +if (argv(1) == 'json') { + $dirstats = array ( + 'hubcount' => $hubcount, + 'zotcount' => $zotcount, + 'friendicacount' => $friendicacount, + 'diasporacount' => $diasporacount, + 'channelcount' => $channelcount, + 'friendicachannelcount' => $friendicachannelcount, + 'diasporachannelcount' => $diasporachannelcount, + 'over35s' => $over35s, + 'under35s' => $under35s, + 'average' => $average, + 'chatrooms' => $chatrooms, + 'tags' => $tags + ); + echo json_return_and_die($dirstats); + } + + // Used by Hubzilla News + elseif (argv(1) == 'genpost' && get_config('dirstats','allowfiledump')) { + $result = '[b]Hub count[/b] : ' . $hubcount . "\xA" . + '[b]Hubzilla Hubs[/b] : ' . $zotcount . "\xA" . + '[b]Friendica Hubs[/b] : ' . $friendicacount . "\xA" . + '[b]Diaspora Pods[/b] : ' . $diasporacount . "\xA" . + '[b]Hubzilla Channels[/b] : ' . $channelcount . "\xA" . + '[b]Friendica Profiles[/b] : ' . $friendicachannelcount . "\xA" . + '[b]Diaspora Profiles[/b] : ' . $diasporachannelcount . "\xA" . + '[b]People aged 35 and above[/b] : ' . $over35s . "\xA" . + '[b]People aged 34 and below[/b] : ' . $under35s . "\xA" . + '[b]Average Age[/b] : ' . $average . "\xA" . + '[b]Known Chatrooms[/b] : ' . $chatrooms . "\xA" . + '[b]Unique Profile Tags[/b] : ' . $tags . "\xA"; + + file_put_contents('genpost', $result); + } +else { + $tpl = get_markup_template( "dirstats.tpl", "addon/dirstats/" ); + return replace_macros($tpl, array( + '$title' => t('Hubzilla Directory Stats'), + '$hubtitle' => t('Total Hubs'), + '$hubcount' => $hubcount, + '$zotlabel' => t('Hubzilla Hubs'), + '$zotcount' => $zotcount, + '$friendicalabel' => t('Friendica Hubs'), + '$friendicacount' => $friendicacount, + '$diasporalabel' => t('Diaspora Pods'), + '$diasporacount' => $diasporacount, + '$zotchanlabel' => t('Hubzilla Channels'), + '$channelcount' => $channelcount, + '$friendicachanlabel' => t('Friendica Channels'), + '$friendicachannelcount' => $friendicachannelcount, + '$diasporachanlabel' => t('Diaspora Channels'), + '$diasporachannelcount' => $diasporachannelcount, + '$over35label' => t('Aged 35 and above'), + '$over35s' => $over35s, + '$under35label' => t('Aged 34 and under'), + '$under35s' => $under35s, + '$averageagelabel' => t('Average Age'), + '$average' => $average, + '$chatlabel' => t('Known Chatrooms'), + '$chatrooms' => $chatrooms, + '$tagslabel' => t('Known Tags'), + '$tags' => $tags, + '$disclaimer' => t('Please note Diaspora and Friendica statistics are merely those **this directory** is aware of, and not all those known in the network. This also applies to chatrooms,') + )); + } +} +function dirstats_cron(&$a, $b) { + // Some hublocs are immortal and won't ever die - they all have null date for hubloc_connected and hubloc_updated + $r = q("SELECT count(distinct hubloc_host) as total FROM `hubloc` where not (hubloc_flags & %d) > 0 and not (hubloc_connected = %d and hubloc_updated = %d)", + intval(HUBLOC_FLAGS_DELETED), + dbesc(NULL_DATE), + dbesc(NULL_DATE) + ); + if ($r) { + $hubcount = $r[0]['total']; + set_config('dirstats','hubcount',$hubcount); + } + + $r = q("SELECT count(distinct hubloc_host) as total FROM `hubloc` where hubloc_network = 'zot' and not (hubloc_flags & %d) > 0 and not (hubloc_connected = %d and hubloc_updated = %d)", + intval(HUBLOC_FLAGS_DELETED), + dbesc(NULL_DATE), + dbesc(NULL_DATE) + + ); + if ($r) { + $zotcount = $r[0]['total']; + set_config('dirstats','zotcount',$zotcount); + } + $r = q("SELECT count(distinct hubloc_host) as total FROM `hubloc` where hubloc_network = 'friendica-over-diaspora'"); + if ($r){ + $friendicacount = $r[0]['total']; + set_config('dirstats','friendicacount',$friendicacount); + } + $r = q("SELECT count(distinct hubloc_host) as total FROM `hubloc` where hubloc_network = 'diaspora'"); + if ($r) { + $diasporacount = $r[0]['total']; + set_config('dirstats','diasporacount',$diasporacount); + } + $r = q("SELECT count(distinct xchan_hash) as total FROM `xchan` where xchan_network = 'zot' and not (xchan_flags & %d) > 0", + intval(XCHAN_FLAGS_DELETED) + ); + if ($r) { + $channelcount = $r[0]['total']; + set_config('dirstats','channelcount',$channelcount); + } + $r = q("SELECT count(distinct xchan_hash) as total FROM `xchan` where xchan_network = 'friendica-over-diaspora'"); + if ($r) { + $friendicachannelcount = $r[0]['total']; + set_config('dirstats','friendicachannelcount',$friendicachannelcount); + } + $r = q("SELECT count(distinct xchan_hash) as total FROM `xchan` where xchan_network = 'diaspora'"); + if ($r) { + $diasporachannelcount = $r[0]['total']; + set_config('dirstats','diasporachannelcount',$diasporachannelcount); + } + $r = q("select count(xprof_hash) as total from `xprof` where xprof_age >=35"); + if ($r) { + $over35s = $r[0]['total']; + set_config('dirstats','over35s',$over35s); + } + $r = q("select count(xprof_hash) as total from `xprof` where xprof_age <=34 and xprof_age >=1"); + if ($r) { + $under35s = $r[0]['total']; + set_config('dirstats','under35s',$under35s); + } + + $r = q("select sum(xprof_age) as sum from xprof"); + if ($r) { + $rr = q("select count(xprof_hash) as total from `xprof` where xprof_age >=1"); + $total = $r[0]['sum']; + $number = $rr[0]['total']; + if($number) + $average = $total / $number; + else + $average = 0; + set_config('dirstats','averageage',$average); + } + + $r = q("select count(distinct xchat_url) as total from `xchat`"); + if ($r) { + $chatrooms = $r[0]['total']; + set_config('dirstats','chatrooms',$chatrooms); + } + $r = q("select count(distinct xtag_term) as total from `xtag`"); + if ($r) { + $tags = $r[0]['total']; + set_config('dirstats','tags',$tags); + } +} diff --git a/sources/extend/addon/matrix/dirstats/view/tpl/dirstats.tpl b/sources/extend/addon/matrix/dirstats/view/tpl/dirstats.tpl new file mode 100644 index 00000000..f1c3a132 --- /dev/null +++ b/sources/extend/addon/matrix/dirstats/view/tpl/dirstats.tpl @@ -0,0 +1,20 @@ +
+

{{$title}}

+
    {{$hubtitle}} : {{$hubcount}}
+
    {{$zotlabel}} : {{$zotcount}}
+
    {{$friendicalabel}} : {{$friendicacount}}
+
    {{$diasporalabel}} : {{$diasporacount}}
+

+
    {{$zotchanlabel}} : {{$channelcount}}
+
    {{$friendicachanlabel}} : {{$friendicachannelcount}}
+
    {{$diasporachanlabel}} : {{$diasporachannelcount}}
+

+
    {{$over35label}} : {{$over35s}}
+
    {{$under35label}} : {{$under35s}}
+
    {{$averageagelabel}} : {{$average}}
+

+
    {{$chatlabel}} : {{$chatrooms}}
+
    {{$tagslabel}} : {{$tags}}
+ +

{{$disclaimer}}

+
diff --git a/sources/extend/addon/matrix/donate/donate.apd b/sources/extend/addon/matrix/donate/donate.apd new file mode 100644 index 00000000..eff602d3 --- /dev/null +++ b/sources/extend/addon/matrix/donate/donate.apd @@ -0,0 +1,3 @@ +url: $baseurl/donate +name: Support Hubzilla +photo: $baseurl/addon/donate/donate.png diff --git a/sources/extend/addon/matrix/donate/donate.php b/sources/extend/addon/matrix/donate/donate.php new file mode 100644 index 00000000..1eb6d57d --- /dev/null +++ b/sources/extend/addon/matrix/donate/donate.php @@ -0,0 +1,75 @@ +' . t('The Redmatrix/Hubzilla projects are provided primarily by volunteers giving their time and expertise - and often paying out of pocket for services they share with others.') . '

'; +$text .= '

' . t('There is no corporate funding and no ads, and we do not collect and sell your personal information. (We don\'t control your personal information - you do.)') . '

'; +$text .= '

' . t('Help support our ground-breaking work in decentralisation, web identity, and privacy.') . '

'; + +$text .= '

' . t('Your donations keep servers and services running and also helps us to provide innovative new features and continued development.') . '

'; + +$o = replace_macros(get_markup_template('donate.tpl','addon/donate'),array( + '$header' => t('Donate'), + '$text' => $text, + '$choice' => t('Choose a project, developer, or public hub to support with a one-time donation'), + '$onetime' => t('Donate Now'), + '$repeat' => t('Or become a project sponsor (Hubzilla Project only)'), + '$note' => t('Please indicate if you would like your first name or full name (or nothing) to appear in our sponsor listing'), + '$subscribe' => t('Sponsor'), + '$contributors' => $contributors, + '$sponsors' => $sponsors, + '$thanks' => t('Special thanks to: '), +)); + +call_hooks('donate_plugin',$o); + +return $o; + +} diff --git a/sources/extend/addon/matrix/donate/donate.png b/sources/extend/addon/matrix/donate/donate.png new file mode 100644 index 00000000..d932f001 Binary files /dev/null and b/sources/extend/addon/matrix/donate/donate.png differ diff --git a/sources/extend/addon/matrix/donate/tipping.jpg b/sources/extend/addon/matrix/donate/tipping.jpg new file mode 100644 index 00000000..f370ece7 Binary files /dev/null and b/sources/extend/addon/matrix/donate/tipping.jpg differ diff --git a/sources/extend/addon/matrix/donate/view/tpl/donate.tpl b/sources/extend/addon/matrix/donate/view/tpl/donate.tpl new file mode 100644 index 00000000..6382cc6f --- /dev/null +++ b/sources/extend/addon/matrix/donate/view/tpl/donate.tpl @@ -0,0 +1,64 @@ +

{{$header}}

+ +
{{$text}}
+ +
+ +Donations + +
+
+ +
+ + +
{{$choice}}
+
+ + +


+ + + + + +
+ +


+ +

+{{$repeat}} +

+

+{{$note}} +

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

+{{$thanks}} +
    +{{foreach $sponsors as $s}} +
  • {{$s}}
  • +{{/foreach}} +
diff --git a/sources/extend/addon/matrix/dwpost/dwpost.css b/sources/extend/addon/matrix/dwpost/dwpost.css new file mode 100644 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/dwpost/dwpost.php b/sources/extend/addon/matrix/dwpost/dwpost.php new file mode 100644 index 00000000..a4b999f0 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/dwpost.php @@ -0,0 +1,229 @@ + + * Author: Michael Johnston + * Author: Cat Gray + */ + +require_once('include/permissions.php'); + +function dwpost_load() { + register_hook('post_local', 'addon/dwpost/dwpost.php', 'dwpost_post_local'); + register_hook('notifier_normal', 'addon/dwpost/dwpost.php', 'dwpost_send'); + register_hook('jot_networks', 'addon/dwpost/dwpost.php', 'dwpost_jot_nets'); + register_hook('feature_settings', 'addon/dwpost/dwpost.php', 'dwpost_settings'); + register_hook('feature_settings_post', 'addon/dwpost/dwpost.php', 'dwpost_settings_post'); + +} +function dwpost_unload() { + unregister_hook('post_local', 'addon/dwpost/dwpost.php', 'dwpost_post_local'); + unregister_hook('notifier_normal', 'addon/dwpost/dwpost.php', 'dwpost_send'); + unregister_hook('jot_networks', 'addon/dwpost/dwpost.php', 'dwpost_jot_nets'); + unregister_hook('feature_settings', 'addon/dwpost/dwpost.php', 'dwpost_settings'); + unregister_hook('feature_settings_post', 'addon/dwpost/dwpost.php', 'dwpost_settings_post'); + +} + + +function dwpost_jot_nets(&$a,&$b) { + if((! local_channel()) || (! perm_is_allowed(local_channel(),'','view_stream'))) + return; + + $dw_post = get_pconfig(local_channel(),'dwpost','post'); + if(intval($dw_post) == 1) { + $dw_defpost = get_pconfig(local_channel(),'dwpost','post_by_default'); + $selected = ((intval($dw_defpost) == 1) ? ' checked="checked" ' : ''); + $b .= '
' + . t('Post to Dreamwidth') . '
'; + } +} + + +function dwpost_settings(&$a,&$s) { + + if(! local_channel()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + //$a->page['htmlhead'] .= '' . "\r\n"; + + /* Get the current state of our config variables */ + + $enabled = get_pconfig(local_channel(),'dwpost','post'); + + $checked = (($enabled) ? 1 : false); + + $def_enabled = get_pconfig(local_channel(),'dwpost','post_by_default'); + + $def_checked = (($def_enabled) ? 1 : false); + + $dw_username = get_pconfig(local_channel(), 'dwpost', 'dw_username'); + $dw_password = z_unobscure(get_pconfig(local_channel(), 'dwpost', 'dw_password')); + + + /* Add some HTML to the existing form */ + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('dwpost', t('Enable Dreamwidth Post Plugin'), $checked, '', array(t('No'),t('Yes'))), + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('dw_username', t('Dreamwidth username'), $dw_username, '') + )); + + $sc .= replace_macros(get_markup_template('field_password.tpl'), array( + '$field' => array('dw_password', t('Dreamwidth password'), $dw_password, '') + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('dw_bydefault', t('Post to Dreamwidth by default'), $def_checked, '', array(t('No'),t('Yes'))), + )); + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('dwpost',t('Dreamwidth Post Settings'), '', t('Submit')), + '$content' => $sc + )); + +} + + +function dwpost_settings_post(&$a,&$b) { + + if(x($_POST,'dwpost-submit')) { + + set_pconfig(local_channel(),'dwpost','post',intval($_POST['dwpost'])); + set_pconfig(local_channel(),'dwpost','post_by_default',intval($_POST['dw_bydefault'])); + set_pconfig(local_channel(),'dwpost','dw_username',trim($_POST['dw_username'])); + set_pconfig(local_channel(),'dwpost','dw_password',z_obscure(trim($_POST['dw_password']))); + + } + +} + +function dwpost_post_local(&$a,&$b) { + + // This can probably be changed to allow editing by pointing to a different API endpoint + + if($b['edit']) + return; + + if((! local_channel()) || (local_channel() != $b['uid'])) + return; + + if($b['item_private'] || $b['parent']) + return; + + logger('Dreamwidth xpost invoked'); + + $dw_post = intval(get_pconfig(local_channel(),'dwpost','post')); + + $dw_enable = (($dw_post && x($_REQUEST,'dwpost_enable')) ? intval($_REQUEST['dwpost_enable']) : 0); + + if($_REQUEST['api_source'] && intval(get_pconfig(local_channel(),'dwpost','post_by_default'))) + $dw_enable = 1; + + if(! $dw_enable) + return; + + if(strlen($b['postopts'])) + $b['postopts'] .= ','; + $b['postopts'] .= 'dwpost'; +} + + + + +function dwpost_send(&$a,&$b) { + + if((! is_item_normal($b)) || $b['item_private'] || ($b['created'] !== $b['edited'])) + return; + + if(! perm_is_allowed($b['uid'],'','view_stream')) + return; + + if(! strstr($b['postopts'],'dwpost')) + return; + + if($b['parent'] != $b['id']) + return; + + // dreamwidth post in the LJ user's timezone. + // Hopefully the person's Friendica account + // will be set to the same thing. + + $tz = 'UTC'; + + $x = q("select channel_timezone from channel where channel_id = %d limit 1", + intval($b['uid']) + ); + if($x && strlen($x[0]['channel_timezone'])) + $tz = $x[0]['channel_timezone']; + + $dw_username = get_pconfig($b['uid'],'dwpost','dw_username'); + $dw_password = z_unobscure(get_pconfig($b['uid'],'dwpost','dw_password')); + $dw_blog = 'http://www.dreamwidth.org/interface/xmlrpc'; + + if($dw_username && $dw_password && $dw_blog) { + + require_once('include/bbcode.php'); + require_once('include/datetime.php'); + + $title = $b['title']; + $post = bbcode($b['body']); + $post = xmlify($post); + $tags = dwpost_get_tags($b['tag']); + + $date = datetime_convert('UTC',$tz,$b['created'],'Y-m-d H:i:s'); + $year = intval(substr($date,0,4)); + $mon = intval(substr($date,5,2)); + $day = intval(substr($date,8,2)); + $hour = intval(substr($date,11,2)); + $min = intval(substr($date,14,2)); + + $xml = <<< EOT + +LJ.XMLRPC.postevent + + +year$year +mon$mon +day$day +hour$hour +min$min +event$post +username$dw_username +password$dw_password +subject$title +lineendingsunix +ver1 +props + +useragentFriendica +taglist$tags + + + + + +EOT; + + logger('dwpost: data: ' . $xml, LOGGER_DATA); + + if($dw_blog !== 'test') + $x = z_post_url($dw_blog,$xml,array('headers' => array("Content-Type: text/xml"))); + logger('posted to dreamwidth: ' . print_r($x,true), LOGGER_DEBUG); + + } +} + +function dwpost_get_tags($post) +{ + preg_match_all("/\]([^\[#]+)\[/",$post,$matches); + $tags = implode(', ',$matches[1]); + return $tags; +} diff --git a/sources/extend/addon/matrix/dwpost/lang/C/messages.po b/sources/extend/addon/matrix/dwpost/lang/C/messages.po new file mode 100644 index 00000000..6bed922f --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/C/messages.po @@ -0,0 +1,46 @@ +# ADDON dwpost +# Copyright (C) +# This file is distributed under the same license as the Friendica dwpost addon package. +# +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-02-27 05:01-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: dwpost.php:39 +msgid "Post to Dreamwidth" +msgstr "" + +#: dwpost.php:70 +msgid "Dreamwidth Post Settings" +msgstr "" + +#: dwpost.php:72 +msgid "Enable dreamwidth Post Plugin" +msgstr "" + +#: dwpost.php:77 +msgid "dreamwidth username" +msgstr "" + +#: dwpost.php:82 +msgid "dreamwidth password" +msgstr "" + +#: dwpost.php:87 +msgid "Post to dreamwidth by default" +msgstr "" + +#: dwpost.php:93 +msgid "Submit" +msgstr "" diff --git a/sources/extend/addon/matrix/dwpost/lang/ca/strings.php b/sources/extend/addon/matrix/dwpost/lang/ca/strings.php new file mode 100644 index 00000000..6ad56a9b --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/ca/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Missatge a Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Configuració d'enviaments a Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Habilitat el plugin d'enviaments a Dreamwidth"; +$a->strings["dreamwidth username"] = "Nom d'usuari a Dreamwidth"; +$a->strings["dreamwidth password"] = "Contrasenya a Dreamwidth"; +$a->strings["Post to dreamwidth by default"] = "Enviar per defecte a Dreamwidth"; +$a->strings["Submit"] = "Enviar"; diff --git a/sources/extend/addon/matrix/dwpost/lang/cs/strings.php b/sources/extend/addon/matrix/dwpost/lang/cs/strings.php new file mode 100644 index 00000000..e01db0d1 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/cs/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Poslat na Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Nastavení Dreamwidth příspÄ›vků"; +$a->strings["Enable dreamwidth Post Plugin"] = "Povolit dreamwidth Plugin"; +$a->strings["dreamwidth username"] = "dreamwidth uživatelské jméno"; +$a->strings["dreamwidth password"] = "dreamwidth heslo"; +$a->strings["Post to dreamwidth by default"] = "DefaultnÄ› umístit na dreamwidth"; +$a->strings["Submit"] = "Odeslat"; diff --git a/sources/extend/addon/matrix/dwpost/lang/de/strings.php b/sources/extend/addon/matrix/dwpost/lang/de/strings.php new file mode 100644 index 00000000..2e3ba985 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/de/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "In Dreamwidth veröffentlichen"; +$a->strings["Dreamwidth Post Settings"] = "Dreamwidth Veröffentlichungs-Einstellungen"; +$a->strings["Enable dreamwidth Post Plugin"] = "Dreamwidth Post Plugin aktivieren"; +$a->strings["dreamwidth username"] = "Dreamwidth Benutzername"; +$a->strings["dreamwidth password"] = "Dreamwidth Passwort"; +$a->strings["Post to dreamwidth by default"] = "Standardmäßig bei Dreamwidth veröffentlichen"; +$a->strings["Submit"] = "Senden"; diff --git a/sources/extend/addon/matrix/dwpost/lang/eo/strings.php b/sources/extend/addon/matrix/dwpost/lang/eo/strings.php new file mode 100644 index 00000000..967d4b9b --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/eo/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "AfiÅi al Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Agordoj por AfiÅoj al Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Åœalti la Dreamwidth Kromprogramon"; +$a->strings["dreamwidth username"] = "Dreamwidth salutnomo"; +$a->strings["dreamwidth password"] = "Dreamwidth pasvorto"; +$a->strings["Post to dreamwidth by default"] = "DefaÅ­lte afiÅi al Dreamwidth"; +$a->strings["Submit"] = "Sendi"; diff --git a/sources/extend/addon/matrix/dwpost/lang/es/strings.php b/sources/extend/addon/matrix/dwpost/lang/es/strings.php new file mode 100644 index 00000000..11e6ff59 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/es/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Publicar en Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Configuración de las publicaciones en Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Activar el módulo de publicación en Dreamwidth"; +$a->strings["dreamwidth username"] = "Nombre de usuario de Dreamwidth"; +$a->strings["dreamwidth password"] = "Contraseña de Dreamwidth"; +$a->strings["Post to dreamwidth by default"] = "Publicar en Dreamwidth por defecto"; +$a->strings["Submit"] = "Envíar"; diff --git a/sources/extend/addon/matrix/dwpost/lang/fr/strings.php b/sources/extend/addon/matrix/dwpost/lang/fr/strings.php new file mode 100644 index 00000000..729bb028 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/fr/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Poster vers Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Réglages Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Activer \"Poster vers Dreamwidth\""; +$a->strings["dreamwidth username"] = "Nom d'utilisateur Dreamwidth"; +$a->strings["dreamwidth password"] = "Mot de passe"; +$a->strings["Post to dreamwidth by default"] = "Poster vers Dreamwidth par défaut"; +$a->strings["Submit"] = "Envoyer"; diff --git a/sources/extend/addon/matrix/dwpost/lang/is/strings.php b/sources/extend/addon/matrix/dwpost/lang/is/strings.php new file mode 100644 index 00000000..96f1f78b --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/is/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = ""; +$a->strings["Dreamwidth Post Settings"] = ""; +$a->strings["Enable dreamwidth Post Plugin"] = ""; +$a->strings["dreamwidth username"] = ""; +$a->strings["dreamwidth password"] = ""; +$a->strings["Post to dreamwidth by default"] = ""; +$a->strings["Submit"] = "Senda inn"; diff --git a/sources/extend/addon/matrix/dwpost/lang/it/strings.php b/sources/extend/addon/matrix/dwpost/lang/it/strings.php new file mode 100644 index 00000000..a47497aa --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/it/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Posta su Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Impostazioni post Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Abilita il plugin dreamwidth"; +$a->strings["dreamwidth username"] = "dreamwidth username"; +$a->strings["dreamwidth password"] = "Password dreamwidth"; +$a->strings["Post to dreamwidth by default"] = "Invia a dreamwidth per impostazione predefinita"; +$a->strings["Submit"] = "Invia"; diff --git a/sources/extend/addon/matrix/dwpost/lang/nb-no/strings.php b/sources/extend/addon/matrix/dwpost/lang/nb-no/strings.php new file mode 100644 index 00000000..37677e6d --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/nb-no/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = ""; +$a->strings["Dreamwidth Post Settings"] = ""; +$a->strings["Enable dreamwidth Post Plugin"] = ""; +$a->strings["dreamwidth username"] = ""; +$a->strings["dreamwidth password"] = ""; +$a->strings["Post to dreamwidth by default"] = ""; +$a->strings["Submit"] = "Lagre"; diff --git a/sources/extend/addon/matrix/dwpost/lang/pl/strings.php b/sources/extend/addon/matrix/dwpost/lang/pl/strings.php new file mode 100644 index 00000000..237c95d9 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/pl/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Opublikuj na Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = ""; +$a->strings["Enable dreamwidth Post Plugin"] = ""; +$a->strings["dreamwidth username"] = ""; +$a->strings["dreamwidth password"] = ""; +$a->strings["Post to dreamwidth by default"] = ""; +$a->strings["Submit"] = "Potwierdź"; diff --git a/sources/extend/addon/matrix/dwpost/lang/pt-br/strings.php b/sources/extend/addon/matrix/dwpost/lang/pt-br/strings.php new file mode 100644 index 00000000..329cf9e3 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/pt-br/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "Publicar no Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Configurações de publicação no Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Habilitar o plugin de publicação no Dreamwidth"; +$a->strings["dreamwidth username"] = "Nome de usuário do Dreamwidth"; +$a->strings["dreamwidth password"] = "Senha do Dreamwidth"; +$a->strings["Post to dreamwidth by default"] = "Publicar no Dreamwidth por padrão"; +$a->strings["Submit"] = "Enviar"; diff --git a/sources/extend/addon/matrix/dwpost/lang/ru/strings.php b/sources/extend/addon/matrix/dwpost/lang/ru/strings.php new file mode 100644 index 00000000..98b08781 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/ru/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = ""; +$a->strings["Dreamwidth Post Settings"] = "Dreamwidth наÑтройки Ñообщений"; +$a->strings["Enable dreamwidth Post Plugin"] = "Включить dreamwidth плагин Ñообщений"; +$a->strings["dreamwidth username"] = "dreamwidth Ð¸Ð¼Ñ Ð¿Ð¾Ð»ÑŒÐ·Ð¾Ð²Ð°Ñ‚ÐµÐ»Ñ"; +$a->strings["dreamwidth password"] = "dreamwidth пароль"; +$a->strings["Post to dreamwidth by default"] = ""; +$a->strings["Submit"] = "Подтвердить"; diff --git a/sources/extend/addon/matrix/dwpost/lang/sv/strings.php b/sources/extend/addon/matrix/dwpost/lang/sv/strings.php new file mode 100644 index 00000000..3ec569a7 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/sv/strings.php @@ -0,0 +1,3 @@ +strings["Submit"] = "Spara"; diff --git a/sources/extend/addon/matrix/dwpost/lang/zh-cn/strings.php b/sources/extend/addon/matrix/dwpost/lang/zh-cn/strings.php new file mode 100644 index 00000000..93e075c6 --- /dev/null +++ b/sources/extend/addon/matrix/dwpost/lang/zh-cn/strings.php @@ -0,0 +1,9 @@ +strings["Post to Dreamwidth"] = "转播到Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Dreamwidth转播设置"; +$a->strings["Enable dreamwidth Post Plugin"] = "使Dreamwidth转播æ’件å¯ç”¨"; +$a->strings["dreamwidth username"] = "Dreamwidth用户å"; +$a->strings["dreamwidth password"] = "Dreamwidth密ç "; +$a->strings["Post to dreamwidth by default"] = "默认地转播到Dreamwidth"; +$a->strings["Submit"] = "æ交"; diff --git a/sources/extend/addon/matrix/embedly/embedly.php b/sources/extend/addon/matrix/embedly/embedly.php new file mode 100644 index 00000000..924c21dd --- /dev/null +++ b/sources/extend/addon/matrix/embedly/embedly.php @@ -0,0 +1,25 @@ + + * + */ + +function embedly_load() { + register_hook('oembed_probe','addon/embedly/embedly.php','embedly_oembed_probe'); +} + +function embedly_unload() { + unregister_hook('oembed_probe','addon/embedly/embedly.php','embedly_oembed_probe'); +} + +function embedly_oembed_probe($a,$b) { + // try oohembed service + $ourl = "http://oohembed.com/oohembed/?url=".$b['url'].'&maxwidth=' . $b['videowidth']; + $result = z_fetch_url($ourl); + if($result['success']) + $b['embed'] = $result['body']; +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/extcron/extcron.php b/sources/extend/addon/matrix/extcron/extcron.php new file mode 100755 index 00000000..85169fe1 --- /dev/null +++ b/sources/extend/addon/matrix/extcron/extcron.php @@ -0,0 +1,22 @@ + + * + * Notes: External service needs to make a web request to http(s)://yoursite/extcron + */ + +function extcron_load() {} + +function extcron_unload() {} + +function extcron_module() {} + +function extcron_init(&$a) { + proc_run('php','include/poller.php'); + killme(); +} diff --git a/sources/extend/addon/matrix/extcron/lang/C/messages.po b/sources/extend/addon/matrix/extcron/lang/C/messages.po new file mode 100644 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/flattrwidget/CHANGELOG b/sources/extend/addon/matrix/flattrwidget/CHANGELOG new file mode 100644 index 00000000..fd5f3538 --- /dev/null +++ b/sources/extend/addon/matrix/flattrwidget/CHANGELOG @@ -0,0 +1,3 @@ +2013-09-22 Version 0.1 Tobias Diekershoff + initial version of the widget + * add a flattr button to left or right aside of the channel view diff --git a/sources/extend/addon/matrix/flattrwidget/README.md b/sources/extend/addon/matrix/flattrwidget/README.md new file mode 100644 index 00000000..9fc30baf --- /dev/null +++ b/sources/extend/addon/matrix/flattrwidget/README.md @@ -0,0 +1,76 @@ +Flattr Widget for The Hubzilla +================================ +This widget is ment to add a [flattr][1] button for one thing to the +left/right aside area of a red# channel. For example this could be the flattr +thing for your blog (on a blog channel). + +What can be configured? + +* static button from your server or dynamic button generated using the flattr + API +* left or right aside area +* URL and Title of the thing you want to be flattred. + + If none are set, the channel URL and the title "_Channel Name_ on The Red + Matrix" will be used. + +There will also be a widget that adds the flattr button to each posting +separetely. + +Screenshots +----------- +_At the moment the screenshots will only show in your red# admin panel._ + +![Dynamic flattr button in channel view](/addon/flattrwidget/img/red-flattr-widget.png) + +Dynamic flattr button generated from the flattr API displaying the number of +flattrs received. + +![Static flattr button in channel view](/addon/flattrwidget/img/red-flattr-widget2.png) + +Static flattr buttton, the image is hosted on your server for privacy of the +visitors. + +Feedback +-------- + +You can send feedback, bug reports etc, for this widget to [my red# stuff +feedback channel][3], you can also leave a flattr there if you like. + +Author +------ + +Original Author: [Tobias Diekershoff][TD] + +License +------- + +This widget id licensed under the [MIT][2] license. + +Copyright (c) 2013, Tobias Diekershoff + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +The _flattr_ button located in the img directory was retrieved from the flattr +homepage. + +[1]: https://flattr.com +[2]: http://opensource.org/licenses/mit-license.php +[3]: https://diekershoff.de/channel/basredstuff +[TD]: https://diekershoff.de/channel/bavatar diff --git a/sources/extend/addon/matrix/flattrwidget/flattrwidget.php b/sources/extend/addon/matrix/flattrwidget/flattrwidget.php new file mode 100644 index 00000000..e0c0f87e --- /dev/null +++ b/sources/extend/addon/matrix/flattrwidget/flattrwidget.php @@ -0,0 +1,129 @@ + + * Maintainer: Tobias Diekershoff + */ + +function flattrwidget_load() { + register_hook('construct_page', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_construct_page'); + register_hook('feature_settings', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_settings'); + register_hook('feature_settings_post', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_settings_post'); +} + +function flattrwidget_unload() { + unregister_hook('construct_page', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_construct_page'); + unregister_hook('feature_settings', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_settings'); + unregister_hook('feature_settings_post', 'addon/flattrwidget/flattrwidget.php', 'flattrwidget_settings_post'); +} + +function flattrwidget_construct_page(&$a,&$b) { + if (! $b['module']=='channel') + return; + $id = $a->profile['profile_uid']; + $enable = intval(get_pconfig($id,'flattrwidget','enable')); + if (! $enable) + return; + $a->page['htmlhead'] .= ''; + // get alignment and static/dynamic from the settings + // align is either "aside" or "right_aside" + // sd is either static or dynamic + $lr = get_pconfig( $id, 'flattrwidget', 'align'); + $sd = get_pconfig( $id, 'flattrwidget', 'sd'); + // title of the thing for the things page on flattr + $ftitle = get_pconfig( $id, 'flattrwidget', 'title'); + // URL of the thing + $thing = get_pconfig( $id, 'flattrwidget', 'thing'); + // flattr user the thing belongs to + $user = get_pconfig( $id, 'flattrwidget', 'user'); + // title for the flattr button itself + $title = t('Flattr this!'); + // construct the link for the button + $link = 'https://flattr.com/submit/auto?user_id='.$user.'&url=' . rawurlencode($thing).'&title='.rawurlencode($ftitle); + if ($sd == 'static') { + // static button graphic from the img folder + $img = $a->get_baseurl() .'/addon/flattrwidget/img/flattr-badge-large.png'; + $code = ''.$title.''; + } else { + $code = ''; + // dynamic button from flattr API + } + // put the widget content together + $flattrwidget = '
'.$code.'
'; + // place the widget into the selected aside area + if ($lr=='right_aside') { + $b['layout']['region_right_aside'] = $flattrwidget . $b['layout']['region_right_aside']; + } else { + $b['layout']['region_aside'] = $flattrwidget . $b['layout']['region_aside']; + } +} +function flattrwidget_settings_post($a,$s) { + if(! local_channel() || (! x($_POST,'flattrwidget-submit'))) + return; + $c = $a->get_channel(); + set_pconfig( local_channel(), 'flattrwidget', 'align', $_POST['flattrwidget-align'] ); + set_pconfig( local_channel(), 'flattrwidget', 'sd', $_POST['flattrwidget-static'] ); + $thing = $_POST['flattrwidget-thing']; + if ($thing == '') { + $thing = $a->get_baseurl().'/channel/'.$c['channel_address']; + } + set_pconfig( local_channel(), 'flattrwidget', 'thing', $thing); + set_pconfig( local_channel(), 'flattrwidget', 'user', $_POST['flattrwidget-user']); + $ftitle = $_POST['flattrwidget-thingtitle']; + if ($ftitle == '') { + $ftitle = $c['channel_name'].' on The Hubzilla'; + } + set_pconfig( local_channel(), 'flattrwidget', 'title', $ftitle); + set_pconfig( local_channel(), 'flattrwidget', 'enable', intval($_POST['flattrwidget-enable'])); + info(t('Flattr widget settings updated.').EOL); +} +function flattrwidget_settings(&$a,&$s) { + $id = local_channel(); + if (! $id) + return; + + //$a->page['htmlhead'] .= ''; + $lr = get_pconfig( $id, 'flattrwidget', 'align'); + $sd = get_pconfig( $id, 'flattrwidget', 'sd'); + $thing = get_pconfig( $id, 'flattrwidget', 'thing'); + $user = get_pconfig( $id, 'flattrwidget', 'user'); + $ftitle = get_pconfig( $id, 'flattrwidget', 'title'); + $enable = intval(get_pconfig(local_channel(),'flattrwidget','enable')); + $enable_checked = (($enable) ? 1 : false); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('flattrwidget-user', t('Flattr user'), $user, '') + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('flattrwidget-thing', t('URL of the Thing to flattr'), $thing, t('If empty channel URL is used')) + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('flattrwidget-thingtitle', t('Title of the Thing to flattr'), $ftitle, t('If empty "channel name on The Hubzilla" will be used')) + )); + + $sc .= replace_macros(get_markup_template('field_select.tpl'), array( + '$field' => array('flattrwidget-static', t('Static or dynamic flattr button'), $sd, '', array('static'=>t('static'), 'dynamic'=>t('dynamic'))) + )); + + $sc .= replace_macros(get_markup_template('field_select.tpl'), array( + '$field' => array('flattrwidget-align', t('Alignment of the widget'), $lr, '', array('aside'=>t('left'), 'right_aside'=>t('right'))) + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('flattrwidget-enable', t('Enable Flattr widget'), $enable_checked, '', array(t('No'),t('Yes'))), + )); + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('flattrwidget',t('Flattr Widget Settings'), '', t('Submit')), + '$content' => $sc + )); + + +} diff --git a/sources/extend/addon/matrix/flattrwidget/img/flattr-badge-large.png b/sources/extend/addon/matrix/flattrwidget/img/flattr-badge-large.png new file mode 100644 index 00000000..11053058 Binary files /dev/null and b/sources/extend/addon/matrix/flattrwidget/img/flattr-badge-large.png differ diff --git a/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget.png b/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget.png new file mode 100644 index 00000000..c7226382 Binary files /dev/null and b/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget.png differ diff --git a/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget2.png b/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget2.png new file mode 100644 index 00000000..84b886e7 Binary files /dev/null and b/sources/extend/addon/matrix/flattrwidget/img/red-flattr-widget2.png differ diff --git a/sources/extend/addon/matrix/flattrwidget/style.css b/sources/extend/addon/matrix/flattrwidget/style.css new file mode 100644 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/fortunate/README b/sources/extend/addon/matrix/fortunate/README new file mode 100644 index 00000000..8297cf41 --- /dev/null +++ b/sources/extend/addon/matrix/fortunate/README @@ -0,0 +1,7 @@ +This addon requires a fortune server. You may use the DB supplied here to create one. + +gunzip the fortunate.sql.gz and import into your database. +Copy cookie.php to the top level Friendica directory. +Edit fortunate.php and change FORTUNATE_SERVER definition to your hostname. Change the http in that file to https if your server doesn't support http. + +Many additional options are available if you examine cookie.php - a clever developer can provide a settings page to tailor this to one's liking. Also several languages are supported, and it would be convenient to set this to the current Friendica language if that is amongst those supported. \ No newline at end of file diff --git a/sources/extend/addon/matrix/fortunate/cookie.php b/sources/extend/addon/matrix/fortunate/cookie.php new file mode 100644 index 00000000..a4be4ef0 --- /dev/null +++ b/sources/extend/addon/matrix/fortunate/cookie.php @@ -0,0 +1,351 @@ +real_escape_string($_GET['lang']); + +if(strlen($_GET['pattern'])) + $pattern = @$db->real_escape_string($_GET['pattern']); + +if(strlen($_GET['regex'])) + $regex = @$db->real_escape_string($_GET['regex']); + +if(strlen($_GET['db'])) + $table = @$db->real_escape_string($_GET['db']); +else + $table = ''; + +if($length < 0) + $length = 0; +if($numlines < 0) + $numlines = 0; + +function do_query($table,$length,$numlines,$adult,$cat,$limit,$lang,$pattern,$regex,$equal) { + global $db; + $rnd = mt_rand(); + $r = array(); + + $typesql = (($table) ? " WHERE `category` = '$table' " : " WHERE 1 "); + $lengthsql = (($length) ? " AND LENGTH(`text`) < $length " : "" ); + + if($adult == 2) + $adultsql = " AND offensive = 1 "; + elseif($adult == 1) + $adultsql = ""; + else + $adultsql = " AND offensive = 0 "; + + + if($numlines) + $lengthsql .= + " AND (LENGTH(`text`) - LENGTH(REPLACE(`text`,\"\n\",\"\"))) <= $numlines "; + + $langsql = (($lang === 'any') ? '' : " AND lang = '$lang' "); + + $patsql = ''; + if(strlen($pattern)) + $patsql = " AND MATCH text AGAINST ('$pattern') "; + + $regexsql = ''; + if(strlen($regex)) + $regexsql = " AND text REGEXP '$regex' "; + + $eqsql = ''; + + if($equal) { + $catsavail = array(); + $res = @$db->query("SELECT DISTINCT ( `category` ) FROM `fortune` + $typesql + $adultsql + $lengthsql + $langsql + $patsql + $regexsql "); + if($res->num_rows) { + while($x = $res->fetch_array(MYSQL_ASSOC)) + $catsavail[] = $x['category']; + + $eqsql = " AND `category` = '" + . $catsavail[mt_rand(0,$res->num_rows - 1)] . "' "; + } + } + + $order = (($patsql && $limit == 1) ? "" : "ORDER BY RAND($rnd)" ); + + $result = @$db->query("SELECT `text`, `category` FROM `fortune` + $typesql + $adultsql + $lengthsql + $langsql + $patsql + $regexsql + $eqsql + $order + LIMIT $limit"); + + if($result->num_rows) { + while($x = $result->fetch_array(MYSQL_ASSOC)) + $r[] = fortune_to_html($x['text']) + .(($cat) ? "
[{$x['category']}]
" : ""); + } + return $r; +} + + +function do_stats($table,$length,$numlines,$adult,$cat,$limit,$lang,$pattern,$regex,$equal) { + global $db; + $rnd = mt_rand(); + $r = array(); + + $typesql = (($table) ? " WHERE `category` = '$table' " : " WHERE 1 "); + $lengthsql = (($length) ? " AND LENGTH(`text`) < $length " : "" ); + + if($adult == 2) + $adultsql = " AND offensive = 1 "; + elseif($adult == 1) + $adultsql = ""; + else + $adultsql = " AND offensive = 0 "; + + + if($numlines) + $lengthsql .= + " AND (LENGTH(`text`) - LENGTH(REPLACE(`text`,\"\n\",\"\"))) <= $numlines "; + + $langsql = " AND lang = '$lang' "; + + $patsql = ''; + if(strlen($pattern)) + $patsql = " AND MATCH text AGAINST ('$pattern') "; + + $regexsql = ''; + if(strlen($regex)) + $regexsql = " AND text REGEXP '$regex' "; + + $eqsql = ''; + + $result = @$db->query("SELECT `text`, `category` FROM `fortune` + $typesql + $adultsql + $lengthsql + $langsql + $patsql + $regexsql + $eqsql"); + + + echo '
' . $result->num_rows . ' matching quotations.
'; + + + $res = @$db->query("SELECT DISTINCT ( `category` ) FROM `fortune` + $typesql + $adultsql + $lengthsql + $langsql + $patsql + $regexsql "); + if($res->num_rows) { + echo '
Matching Databases:
'; + while($x = $res->fetch_array(MYSQL_ASSOC)) + echo $x['category'].'
'; + + } + else + echo '
No matching databases using those search parameters - please refine your options.
'; + + +} + + +function fortune_to_html($s) { + + // First pass - escape all the HTML entities, and while we're at it + // get rid of any MS-DOS end-of-line characters and expand tabs to + // 8 non-breaking spaces, and translate linefeeds to
. + // We also get rid of ^G which used to sound the terminal beep or bell + // on ASCII terminals and were humourous in some fortunes. + // We could map these to autoplay a short sound file but browser support + // is still sketchy and then there's the issue of where to locate the + // URL, and a lot of people find autoplay sounds downright annoying. + // So for now, just remove them. + + $s = str_replace( + array("&", + "<", + ">", + '"', + "\007", + "\t", + "\r", + "\n"), + + array("&", + "<", + ">", + """, + "", + "        ", + "", + "
"), + $s); + // Replace pseudo diacritics + // These were used to produce accented characters. For instance an accented + // e would have been encoded by '^He - the backspace moving the cursor + // backward so both the single quote and the e would appear in the same + // character position. Umlauts were quite clever - they used a double quote + // as the accent mark over a normal character. + + $s = preg_replace("/'\010([a-zA-Z])/","&\\1acute;",$s); + $s = preg_replace("/\"\010([a-zA-Z])/","&\\1uml;",$s); + $s = preg_replace("/\`\010([a-zA-Z])/","&\\1grave;",$s); + $s = preg_replace("/\^\010([a-zA-Z])/","&\\1circ;",$s); + $s = preg_replace("/\~\010([a-zA-Z])/","&\\1tilde;",$s); + + // Ignore multiple underlines for the same character. These were + // most useful when sent to a line printer back in the day as it + // would type over the same character a number of times making it + // much darker (e.g. bold). I think there are only one or two + // instances of this in the current (2008) fortune cookie database. + + $s = preg_replace("/(_\010)+/","_\010",$s); + // Map the characters which sit underneath a backspace. + // If you can come up with a regex to do all of the following + // madness - be my guest. + // It's not as simple as you think. We need to take something + // that has been backspaced over an arbitrary number of times + // and wrap a forward looking matching number of characters in + // HTML, whilst deciding if it's intended as an underline or + // strikeout sequence. + + // Essentially we produce a string of '1' and '0' characters + // the same length as the source text. + // Any position which is marked '1' has been backspaced over. + + $cursor = 0; + $dst = $s; + $bs_found = false; + for($x = 0; $x < strlen($s); $x ++) { + if($s[$x] == "\010" && $cursor) { + $bs_found = true; + $cursor --; + $dst[$cursor] = '1'; + $dst[$x] = '0'; + $continue; + } + else { + if($bs_found) { + $bs_found = false; + $cursor = $x; + } + $dst[$cursor] = '0'; + $cursor ++; + } + + } + + $out = ''; + $strike = false; + $bold = false; + + // Underline sequence, convert to bold to avoid confusion with links. + // These were generally used for emphasis so it's a reasonable choice. + // Please note that this logic will fail if there is an underline sequence + // and also a strikeout sequence in the same fortune. + + if(strstr($s,"_\010")) { + $len = 0; + for($x = 0; $x < strlen($s); $x ++) { + if($dst[$x] == '1') { + $len ++; + $bold = true; + } + else { + if($bold) { + $out .= ''; + while($s[$x] == "\010") + $x ++; + $out .= substr($s,$x,$len); + $out .= ''; + $x = $x + $len - 1; + $len = 0; + $bold = false; + } + else + $out .= $s[$x]; + } + } + } + + // These aren't seen very often these days - simulation of + // backspace/replace. You could occasionally see the original text + // on slower terminals before it got replaced. Once modems reached + // 4800/9600 baud in the late 70's and early 80's the effect was + // mostly lost - but if you find a really old fortune file you might + // encounter a few of these. + + else { + for($x = 0; $x < strlen($s); $x ++) { + if($dst[$x] == '1') { + if($strike) + $out .= $s[$x]; + else + $out .= ''.$s[$x]; + $strike = true; + } + else { + if($strike) + $out .= ''; + $strike = false; + $out .= $s[$x]; + } + } + } + + // Many of the underline sequences are also wrapped in asterisks, + // which was yet another way of marking ASCII as 'bold'. + // So if it's an underline sequence, and there are asterisks + // on both ends, strip the asterisks as we've already emboldened the text. + + $out = preg_replace('/\*([^<]*<\/strong>)\*/',"\\1",$out); + + // Finally, remove the backspace characters which we don't need anymore. + + return str_replace("\010","",$out); +} + +$result1 = do_query($table,$length,$numlines,$adult,$cat,1,$lang,$pattern,$regex,$equal); + +if(count($result1)) + echo $result1[0]; + +if($stats) + do_stats($table,$length,$numlines,$adult,$cat,1,$lang,$pattern,$regex,$equal); + + diff --git a/sources/extend/addon/matrix/fortunate/fortunate.apd b/sources/extend/addon/matrix/fortunate/fortunate.apd new file mode 100644 index 00000000..d1c72473 --- /dev/null +++ b/sources/extend/addon/matrix/fortunate/fortunate.apd @@ -0,0 +1,3 @@ +url: $baseurl/fortunate +name: Fortunate +photo: $baseurl/addon/fortunate/fortunate.png diff --git a/sources/extend/addon/matrix/fortunate/fortunate.css b/sources/extend/addon/matrix/fortunate/fortunate.css new file mode 100644 index 00000000..61813b7d --- /dev/null +++ b/sources/extend/addon/matrix/fortunate/fortunate.css @@ -0,0 +1,7 @@ +.fortunate { + margin-top: 25px; + margin-left: 100px; + margin-bottom: 25px; + color: #000088; + font-size: 14px; +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/fortunate/fortunate.php b/sources/extend/addon/matrix/fortunate/fortunate.php new file mode 100644 index 00000000..5b0f47ac --- /dev/null +++ b/sources/extend/addon/matrix/fortunate/fortunate.php @@ -0,0 +1,43 @@ + + */ + + +function fortunate_load() { + register_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); + +} + +function fortunate_unload() { + unregister_hook('page_end', 'addon/fortunate/fortunate.php', 'fortunate_fetch'); +} + +function fortunate_module(){} + + +function fortunate_fetch(&$a,&$b) { + + $fort_server = get_config('fortunate','server'); + if(! $fort_server) + return; + + $a->page['htmlhead'] .= '' . "\r\n"; + + $s = z_fetch_url('http://' . $fort_server . '/cookie.php?numlines=4&equal=1&rand=' . mt_rand()); + if($s['success']) + $b .= '
' . $s['body'] . '
'; + +} + +function fortunate_content(&$a) { + +// $o = ''; +// fortunate_fetch($a,$o); +// return $o; + +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/fortunate/fortunate.png b/sources/extend/addon/matrix/fortunate/fortunate.png new file mode 100644 index 00000000..894a94c7 Binary files /dev/null and b/sources/extend/addon/matrix/fortunate/fortunate.png differ diff --git a/sources/extend/addon/matrix/fortunate/fortunemod.sql.gz b/sources/extend/addon/matrix/fortunate/fortunemod.sql.gz new file mode 100644 index 00000000..2ce0e557 Binary files /dev/null and b/sources/extend/addon/matrix/fortunate/fortunemod.sql.gz differ diff --git a/sources/extend/addon/matrix/frphotos/frphotohelper.php b/sources/extend/addon/matrix/frphotos/frphotohelper.php new file mode 100644 index 00000000..c2edc3e3 --- /dev/null +++ b/sources/extend/addon/matrix/frphotos/frphotohelper.php @@ -0,0 +1,75 @@ +get_channel(); + + $fr_server = $_REQUEST['fr_server']; + $fr_username = $_REQUEST['fr_username']; + $fr_password = $_REQUEST['fr_password']; + + $cookies = 'store/[data]/frphoto_cookie_' . $channel['channel_address']; + + if($fr_server && $fr_username && $fr_password) { + + $ch = curl_init($fr_server . '/api/friendica/photos/list'); + + curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1); + curl_setopt ($ch, CURLOPT_COOKIEFILE, $cookies); + curl_setopt ($ch, CURLOPT_COOKIEJAR, $cookies); + curl_setopt($ch, CURLOPT_HTTPAUTH, CURLAUTH_BASIC); + curl_setopt($ch, CURLOPT_USERPWD, $fr_username . ':' . $fr_password); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_USERAGENT, 'Hubzilla'); + + $output = curl_exec($ch); + curl_close($ch); + + $j = json_decode($output,true); + +// echo print_r($j,true); + + $total = 0; + if(count($j)) { + foreach($j as $jj) { + + $r = q("select uid from photo where resource_id = '%s' and uid = %d limit 1", + dbesc($jj), + intval($channel['channel_id']) + ); + if($r) + continue; + + $total ++; + proc_run('php','addon/frphotos/frphotohelper.php',$jj, $channel['channel_address'], urlencode($fr_server)); + sleep(3); + } + } + if($total) { + set_pconfig(local_channel(),'frphotos','complete','1'); + } + @unlink($cookies); + goaway(z_root() . '/photos/' . $channel['channel_address']); + } +} + + +function frphotos_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied') . EOL); + return; + } + + if(intval(get_pconfig(local_channel(),'frphotos','complete'))) { + info('Friendica photos have already been imported into this channel.'); + return; + } + + $o = replace_macros(get_markup_template('frphotos.tpl','addon/frphotos'),array( + '$header' => t('Friendica Photo Album Import'), + '$desc' => t('This will import all your Friendica photo albums to this Red channel.'), + '$fr_server' => array('fr_server', t('Friendica Server base URL'),'',''), + '$fr_username' => array('fr_username', t('Friendica Login Username'),'',''), + '$fr_password' => array('fr_password', t('Friendica Login Password'),'',''), + '$submit' => t('Submit'), + )); + return $o; +} diff --git a/sources/extend/addon/matrix/frphotos/view/tpl/frphotos.tpl b/sources/extend/addon/matrix/frphotos/view/tpl/frphotos.tpl new file mode 100644 index 00000000..b8e97882 --- /dev/null +++ b/sources/extend/addon/matrix/frphotos/view/tpl/frphotos.tpl @@ -0,0 +1,13 @@ +

{{$header}}

+ +

{{$desc}}

+ +
+ +{{include file="field_input.tpl" field=$fr_server}} +{{include file="field_input.tpl" field=$fr_username}} +{{include file="field_password.tpl" field=$fr_password}} + + +
+ diff --git a/sources/extend/addon/matrix/hexit/hexit.apd b/sources/extend/addon/matrix/hexit/hexit.apd new file mode 100644 index 00000000..af0b05fb --- /dev/null +++ b/sources/extend/addon/matrix/hexit/hexit.apd @@ -0,0 +1,3 @@ +url: $baseurl/hexit +name: Hexit +photo: $baseurl/addon/hexit/hexit.png diff --git a/sources/extend/addon/matrix/hexit/hexit.php b/sources/extend/addon/matrix/hexit/hexit.php new file mode 100644 index 00000000..bd9b7204 --- /dev/null +++ b/sources/extend/addon/matrix/hexit/hexit.php @@ -0,0 +1,185 @@ + +/** + * A function for converting hex <-> dec w/o loss of precision. + * + * The problem is that parseInt("0x12345...") isn't precise enough to convert + * 64-bit integers correctly. + * + * Internally, this uses arrays to encode decimal digits starting with the least + * significant: + * 8 = [8] + * 16 = [6, 1] + * 1024 = [4, 2, 0, 1] + */ + +// Adds two arrays for the given base (10 or 16), returning the result. +// This turns out to be the only "primitive" operation we need. +function add(x, y, base) { + var z = []; + var n = Math.max(x.length, y.length); + var carry = 0; + var i = 0; + while (i < n || carry) { + var xi = i < x.length ? x[i] : 0; + var yi = i < y.length ? y[i] : 0; + var zi = carry + xi + yi; + z.push(zi % base); + carry = Math.floor(zi / base); + i++; + } + return z; +} + +// Returns a*x, where x is an array of decimal digits and a is an ordinary +// JavaScript number. base is the number base of the array x. +function multiplyByNumber(num, x, base) { + if (num < 0) return null; + if (num == 0) return []; + + var result = []; + var power = x; + while (true) { + if (num & 1) { + result = add(result, power, base); + } + num = num >> 1; + if (num === 0) break; + power = add(power, power, base); + } + + return result; +} + +function parseToDigitsArray(str, base) { + var digits = str.split(''); + var ary = []; + for (var i = digits.length - 1; i >= 0; i--) { + var n = parseInt(digits[i], base); + if (isNaN(n)) return null; + ary.push(n); + } + return ary; +} + +function convertBase(str, fromBase, toBase) { + var digits = parseToDigitsArray(str, fromBase); + if (digits === null) return null; + + var outArray = []; + var power = [1]; + for (var i = 0; i < digits.length; i++) { + // invariant: at this point, fromBase^i = power + if (digits[i]) { + outArray = add(outArray, multiplyByNumber(digits[i], power, toBase), toBase); + } + power = multiplyByNumber(fromBase, power, toBase); + } + + var out = ''; + for (var i = outArray.length - 1; i >= 0; i--) { + out += outArray[i].toString(toBase); + } + return out; +} + +function decToHex(decStr) { + var hex = convertBase(decStr, 10, 16); + return hex ? '0x' + hex : null; +} + +function hexToDec(hexStr) { + if (hexStr.substring(0, 2) === '0x') hexStr = hexStr.substring(2); + hexStr = hexStr.toLowerCase(); + return convertBase(hexStr, 16, 10); +} + + + + function str_or_null(x) { + return x === null ? 'null' : x; + } + + // "1.234e+5" -> "12340" + function expandExponential(x) { + var pos = x.indexOf("e"); + if (pos === -1) pos = x.indexOf("E"); + if (pos === -1) return x; + + var base = x.substring(0, pos); + var pow = parseInt(x.substring(pos + 1), 10); + if (pow < 0) return x; // not supported. + + var dotPos = base.indexOf('.'); + if (dotPos === -1) dotPos = base.length; + + var ret = base.replace('.', ''); + while (ret.length < dotPos + pow) ret += '0'; + return ret; + } + + function boldDifference(correct, actual) { + for (var i = 0, j = 0; i < correct.length && j < actual.length; i++, j++) { + if (correct[i] !== actual[j]) { + break; + } + } + if (j < actual.length) { + return actual.substring(0, j) + '' + actual.substring(j) + ''; + } else { + return actual; + } + } + + function convert() { + var input = document.getElementById("in").value; + if (input) { + var aHex = str_or_null(decToHex(input)); + var aDec = str_or_null(hexToDec(input)); + var bHex = '0x' + (parseInt(input, 10)).toString(16); + var bDec = "" + expandExponential("" +parseInt(input, 16)); + + var html = '

To Decimal(' + input + ') = ' + aDec + '

'; + html += '

To Hex(' + input + ') = ' + aHex + '

'; + document.getElementById('result').innerHTML = html; + } + } + convert(); + + + + +

Hexit

+ +

Type in a hex or decimal string:

+ +

+ + + +EOT; + +return $o; +} diff --git a/sources/extend/addon/matrix/hexit/hexit.png b/sources/extend/addon/matrix/hexit/hexit.png new file mode 100644 index 00000000..990f7ead Binary files /dev/null and b/sources/extend/addon/matrix/hexit/hexit.png differ diff --git a/sources/extend/addon/matrix/ijpost/ijpost.css b/sources/extend/addon/matrix/ijpost/ijpost.css new file mode 100644 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/ijpost/ijpost.php b/sources/extend/addon/matrix/ijpost/ijpost.php new file mode 100644 index 00000000..863a2b05 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/ijpost.php @@ -0,0 +1,229 @@ + + * Author: Michael Johnston + * Author: Cat Gray + */ + +require_once('include/permissions.php'); + +function ijpost_load() { + register_hook('post_local', 'addon/ijpost/ijpost.php', 'ijpost_post_local'); + register_hook('notifier_normal', 'addon/ijpost/ijpost.php', 'ijpost_send'); + register_hook('jot_networks', 'addon/ijpost/ijpost.php', 'ijpost_jot_nets'); + register_hook('feature_settings', 'addon/ijpost/ijpost.php', 'ijpost_settings'); + register_hook('feature_settings_post', 'addon/ijpost/ijpost.php', 'ijpost_settings_post'); + +} +function ijpost_unload() { + unregister_hook('post_local', 'addon/ijpost/ijpost.php', 'ijpost_post_local'); + unregister_hook('notifier_normal', 'addon/ijpost/ijpost.php', 'ijpost_send'); + unregister_hook('jot_networks', 'addon/ijpost/ijpost.php', 'ijpost_jot_nets'); + unregister_hook('feature_settings', 'addon/ijpost/ijpost.php', 'ijpost_settings'); + unregister_hook('feature_settings_post', 'addon/ijpost/ijpost.php', 'ijpost_settings_post'); + +} + + +function ijpost_jot_nets(&$a,&$b) { + if((! local_channel()) || (! perm_is_allowed(local_channel(),'','view_stream'))) + return; + + $ij_post = get_pconfig(local_channel(),'ijpost','post'); + if(intval($ij_post) == 1) { + $ij_defpost = get_pconfig(local_channel(),'ijpost','post_by_default'); + $selected = ((intval($ij_defpost) == 1) ? ' checked="checked" ' : ''); + $b .= '
' + . t('Post to Insanejournal') . '
'; + } +} + + +function ijpost_settings(&$a,&$s) { + + if(! local_channel()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + //$a->page['htmlhead'] .= '' . "\r\n"; + + /* Get the current state of our config variables */ + + $enabled = get_pconfig(local_channel(),'ijpost','post'); + + $checked = (($enabled) ? 1 : false); + + $def_enabled = get_pconfig(local_channel(),'ijpost','post_by_default'); + + $def_checked = (($def_enabled) ? 1 : false); + + $ij_username = get_pconfig(local_channel(), 'ijpost', 'ij_username'); + $ij_password = z_unobscure(get_pconfig(local_channel(), 'ijpost', 'ij_password')); + + + /* Add some HTML to the existing form */ + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('ijpost', t('Enable InsaneJournal Post Plugin'), $checked, '', array(t('No'),t('Yes'))), + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('ij_username', t('InsaneJournal username'), $ij_username, '') + )); + + $sc .= replace_macros(get_markup_template('field_password.tpl'), array( + '$field' => array('ij_password', t('InsaneJournal password'), $ij_password, '') + )); + + $sc .= replace_macros(get_markup_template('field_checkbox.tpl'), array( + '$field' => array('ij_bydefault', t('Post to InsaneJournal by default'), $def_checked, '', array(t('No'),t('Yes'))), + )); + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('ijpost',t('InsaneJournal Post Settings'), '', t('Submit')), + '$content' => $sc + )); + +} + + +function ijpost_settings_post(&$a,&$b) { + + if(x($_POST,'ijpost-submit')) { + + set_pconfig(local_channel(),'ijpost','post',intval($_POST['ijpost'])); + set_pconfig(local_channel(),'ijpost','post_by_default',intval($_POST['ij_bydefault'])); + set_pconfig(local_channel(),'ijpost','ij_username',trim($_POST['ij_username'])); + set_pconfig(local_channel(),'ijpost','ij_password',z_obscure(trim($_POST['ij_password']))); + info( t('Insane Journal Settings saved.') . EOL); + } + +} + +function ijpost_post_local(&$a,&$b) { + + // This can probably be changed to allow editing by pointing to a different API endpoint + + if($b['edit']) + return; + + if((! local_channel()) || (local_channel() != $b['uid'])) + return; + + if($b['item_private'] || $b['parent']) + return; + + $ij_post = intval(get_pconfig(local_channel(),'ijpost','post')); + + $ij_enable = (($ij_post && x($_REQUEST,'ijpost_enable')) ? intval($_REQUEST['ijpost_enable']) : 0); + + if($_REQUEST['api_source'] && intval(get_pconfig(local_channel(),'ijpost','post_by_default'))) + $ij_enable = 1; + + if(! $ij_enable) + return; + + if(strlen($b['postopts'])) + $b['postopts'] .= ','; + $b['postopts'] .= 'ijpost'; +} + + + + +function ijpost_send(&$a,&$b) { + + if((! is_item_normal($b)) || $b['item_private'] || ($b['created'] !== $b['edited'])) + return; + + if(! perm_is_allowed($b['uid'],'','view_stream')) + return; + + if(! strstr($b['postopts'],'ijpost')) + return; + + if($b['parent'] != $b['id']) + return; + + logger('Insanejournal xpost invoked'); + + // insanejournal post in the LJ user's timezone. + // Hopefully the person's Friendica account + // will be set to the same thing. + + $tz = 'UTC'; + + $x = q("select channel_timezone from channel where channel_id = %d limit 1", + intval($b['uid']) + ); + if($x && strlen($x[0]['channel_timezone'])) + $tz = $x[0]['channel_timezone']; + + $ij_username = get_pconfig($b['uid'],'ijpost','ij_username'); + $ij_password = z_unobscure(get_pconfig($b['uid'],'ijpost','ij_password')); + $ij_blog = 'http://www.insanejournal.com/interface/xmlrpc'; + + if($ij_username && $ij_password && $ij_blog) { + + require_once('include/bbcode.php'); + require_once('include/datetime.php'); + + $title = $b['title']; + $post = bbcode($b['body']); + $post = xmlify($post); + $tags = ijpost_get_tags($b['tag']); + + $date = datetime_convert('UTC',$tz,$b['created'],'Y-m-d H:i:s'); + $year = intval(substr($date,0,4)); + $mon = intval(substr($date,5,2)); + $day = intval(substr($date,8,2)); + $hour = intval(substr($date,11,2)); + $min = intval(substr($date,14,2)); + + $xml = <<< EOT + +LJ.XMLRPC.postevent + + +year$year +mon$mon +day$day +hour$hour +min$min +event$post +username$ij_username +password$ij_password +subject$title +lineendingsunix +ver1 +props + +useragentHubzilla +taglist$tags + + + + + +EOT; + + logger('ijpost: data: ' . $xml, LOGGER_DATA); + + if($ij_blog !== 'test') + $x = z_post_url($ij_blog,$xml,array('headers' => array("Content-Type: text/xml"))); + logger('posted to insanejournal: ' . print_r($x,true), LOGGER_DEBUG); + + } +} + +function ijpost_get_tags($post) +{ + preg_match_all("/\]([^\[#]+)\[/",$post,$matches); + $tags = implode(', ',$matches[1]); + return $tags; +} diff --git a/sources/extend/addon/matrix/ijpost/lang/C/messages.po b/sources/extend/addon/matrix/ijpost/lang/C/messages.po new file mode 100644 index 00000000..4f62c23a --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/C/messages.po @@ -0,0 +1,46 @@ +# ADDON ijpost +# Copyright (C) +# This file is distributed under the same license as the Friendica ijpost addon package. +# +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: \n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2013-02-27 05:01-0500\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ijpost.php:39 +msgid "Post to Insanejournal" +msgstr "" + +#: ijpost.php:70 +msgid "InsaneJournal Post Settings" +msgstr "" + +#: ijpost.php:72 +msgid "Enable InsaneJournal Post Plugin" +msgstr "" + +#: ijpost.php:77 +msgid "InsaneJournal username" +msgstr "" + +#: ijpost.php:82 +msgid "InsaneJournal password" +msgstr "" + +#: ijpost.php:87 +msgid "Post to InsaneJournal by default" +msgstr "" + +#: ijpost.php:93 +msgid "Submit" +msgstr "" diff --git a/sources/extend/addon/matrix/ijpost/lang/ca/strings.php b/sources/extend/addon/matrix/ijpost/lang/ca/strings.php new file mode 100644 index 00000000..b5382615 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/ca/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Enviament a Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Ajustos d'Enviament a Insanejournal"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Habilita el Plugin d'Enviaments a Insanejournal"; +$a->strings["InsaneJournal username"] = "Nom d'usuari de Insanejournal"; +$a->strings["InsaneJournal password"] = "Contrasenya de Insanejournal"; +$a->strings["Post to InsaneJournal by default"] = "Enviar per defecte a Insanejournal"; +$a->strings["Submit"] = "Enviar"; diff --git a/sources/extend/addon/matrix/ijpost/lang/cs/strings.php b/sources/extend/addon/matrix/ijpost/lang/cs/strings.php new file mode 100644 index 00000000..8e40419a --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/cs/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Odeslat na Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Nastavení příspÄ›vků pro InsaneJournal"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Povolit Insanejournal plugin"; +$a->strings["InsaneJournal username"] = "Insanejournal uživatelské jméno"; +$a->strings["InsaneJournal password"] = "Insanejournal heslo"; +$a->strings["Post to InsaneJournal by default"] = "DefaultnÄ› zasílat příspÄ›vky na InsaneJournal"; +$a->strings["Submit"] = "Odeslat"; diff --git a/sources/extend/addon/matrix/ijpost/lang/de/strings.php b/sources/extend/addon/matrix/ijpost/lang/de/strings.php new file mode 100644 index 00000000..319a9743 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/de/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Auf InsaneJournal posten."; +$a->strings["InsaneJournal Post Settings"] = "InsaneJournal Beitrags-Einstellungen"; +$a->strings["Enable InsaneJournal Post Plugin"] = "InsaneJournal Plugin aktivieren"; +$a->strings["InsaneJournal username"] = "InsaneJournal Benutzername"; +$a->strings["InsaneJournal password"] = "InsaneJournal Passwort"; +$a->strings["Post to InsaneJournal by default"] = "Standardmäßig auf InsaneJournal posten."; +$a->strings["Submit"] = "Senden"; diff --git a/sources/extend/addon/matrix/ijpost/lang/eo/strings.php b/sources/extend/addon/matrix/ijpost/lang/eo/strings.php new file mode 100644 index 00000000..11698887 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/eo/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "AfiÅi al Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Agordoj pri Insaenejournal AfiÅoj"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Åœalti la InsaneJournal afiÅo kromprogramon."; +$a->strings["InsaneJournal username"] = "Salutnomo ĉe InsaneJournal"; +$a->strings["InsaneJournal password"] = "Pasvorto ĉe InsaneJournal"; +$a->strings["Post to InsaneJournal by default"] = "DefaÅ­lte afiÅi ĉe InsaneJournal"; +$a->strings["Submit"] = "Sendi"; diff --git a/sources/extend/addon/matrix/ijpost/lang/es/strings.php b/sources/extend/addon/matrix/ijpost/lang/es/strings.php new file mode 100644 index 00000000..4468be83 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/es/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Publicar en Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Configuración de publicación en Insanejournal"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Activar el módulo de publicación en Insanejournal"; +$a->strings["InsaneJournal username"] = "Nombre de usuario de Insanejournal"; +$a->strings["InsaneJournal password"] = "Contraseña de Insanejournal"; +$a->strings["Post to InsaneJournal by default"] = "Publicar en Insanejournal por defecto"; +$a->strings["Submit"] = "Envíar"; diff --git a/sources/extend/addon/matrix/ijpost/lang/fr/strings.php b/sources/extend/addon/matrix/ijpost/lang/fr/strings.php new file mode 100644 index 00000000..7db58ccf --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/fr/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Publier vers InsaneJournal"; +$a->strings["InsaneJournal Post Settings"] = "Réglages InsaneJournal"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Activer le connecteur InsaneJournal"; +$a->strings["InsaneJournal username"] = "Utilisateur InsaneJournal"; +$a->strings["InsaneJournal password"] = "Mot de passe InsaneJournal"; +$a->strings["Post to InsaneJournal by default"] = "Publier sur InsaneJournal par défaut"; +$a->strings["Submit"] = "Envoyer"; diff --git a/sources/extend/addon/matrix/ijpost/lang/is/strings.php b/sources/extend/addon/matrix/ijpost/lang/is/strings.php new file mode 100644 index 00000000..b79f347e --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/is/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = ""; +$a->strings["InsaneJournal Post Settings"] = ""; +$a->strings["Enable InsaneJournal Post Plugin"] = ""; +$a->strings["InsaneJournal username"] = ""; +$a->strings["InsaneJournal password"] = ""; +$a->strings["Post to InsaneJournal by default"] = ""; +$a->strings["Submit"] = "Senda inn"; diff --git a/sources/extend/addon/matrix/ijpost/lang/it/strings.php b/sources/extend/addon/matrix/ijpost/lang/it/strings.php new file mode 100644 index 00000000..f82132ce --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/it/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Invia a Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Impostazioni Invio a InsaneJournal "; +$a->strings["Enable InsaneJournal Post Plugin"] = "Abilita il plugin Invio a InsaneJournal"; +$a->strings["InsaneJournal username"] = "Nome utente InsaneJournal"; +$a->strings["InsaneJournal password"] = "Password InsaneJournal"; +$a->strings["Post to InsaneJournal by default"] = "Invia sempre a InsaneJournal"; +$a->strings["Submit"] = "Invia"; diff --git a/sources/extend/addon/matrix/ijpost/lang/nb-no/strings.php b/sources/extend/addon/matrix/ijpost/lang/nb-no/strings.php new file mode 100644 index 00000000..2eaa62e3 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/nb-no/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = ""; +$a->strings["InsaneJournal Post Settings"] = ""; +$a->strings["Enable InsaneJournal Post Plugin"] = ""; +$a->strings["InsaneJournal username"] = ""; +$a->strings["InsaneJournal password"] = ""; +$a->strings["Post to InsaneJournal by default"] = ""; +$a->strings["Submit"] = "Lagre"; diff --git a/sources/extend/addon/matrix/ijpost/lang/pl/strings.php b/sources/extend/addon/matrix/ijpost/lang/pl/strings.php new file mode 100644 index 00000000..5b6ec674 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/pl/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Opublikuj na Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = ""; +$a->strings["Enable InsaneJournal Post Plugin"] = ""; +$a->strings["InsaneJournal username"] = ""; +$a->strings["InsaneJournal password"] = ""; +$a->strings["Post to InsaneJournal by default"] = ""; +$a->strings["Submit"] = "Potwierdź"; diff --git a/sources/extend/addon/matrix/ijpost/lang/pt-br/strings.php b/sources/extend/addon/matrix/ijpost/lang/pt-br/strings.php new file mode 100644 index 00000000..4dce00fc --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/pt-br/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "Publicar no InsaneJournal"; +$a->strings["InsaneJournal Post Settings"] = "Configurações da publicação no InsaneJournal"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Habilitar o plugin de publicação no InsaneJournal"; +$a->strings["InsaneJournal username"] = "Nome de usuário do InsaneJournal"; +$a->strings["InsaneJournal password"] = "Senha do InsaneJournal"; +$a->strings["Post to InsaneJournal by default"] = "Publicar no InsaneJournal por padrão"; +$a->strings["Submit"] = "Enviar"; diff --git a/sources/extend/addon/matrix/ijpost/lang/ru/strings.php b/sources/extend/addon/matrix/ijpost/lang/ru/strings.php new file mode 100644 index 00000000..0109f8a6 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/ru/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = ""; +$a->strings["InsaneJournal Post Settings"] = ""; +$a->strings["Enable InsaneJournal Post Plugin"] = "Включить InsaneJournal плагин Ñообщений"; +$a->strings["InsaneJournal username"] = ""; +$a->strings["InsaneJournal password"] = ""; +$a->strings["Post to InsaneJournal by default"] = ""; +$a->strings["Submit"] = "Подтвердить"; diff --git a/sources/extend/addon/matrix/ijpost/lang/sv/strings.php b/sources/extend/addon/matrix/ijpost/lang/sv/strings.php new file mode 100644 index 00000000..3ec569a7 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/sv/strings.php @@ -0,0 +1,3 @@ +strings["Submit"] = "Spara"; diff --git a/sources/extend/addon/matrix/ijpost/lang/zh-cn/strings.php b/sources/extend/addon/matrix/ijpost/lang/zh-cn/strings.php new file mode 100644 index 00000000..f2a04712 --- /dev/null +++ b/sources/extend/addon/matrix/ijpost/lang/zh-cn/strings.php @@ -0,0 +1,9 @@ +strings["Post to Insanejournal"] = "转播到Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Insanejournal转播设置"; +$a->strings["Enable InsaneJournal Post Plugin"] = "使InsaneJournal转播æ’件å¯ç”¨"; +$a->strings["InsaneJournal username"] = "InsaneJournal用户å"; +$a->strings["InsaneJournal password"] = "InsaneJournal密ç "; +$a->strings["Post to InsaneJournal by default"] = "默认地转播到InsaneJournal"; +$a->strings["Submit"] = "æ交"; diff --git a/sources/extend/addon/matrix/irc/irc.apd b/sources/extend/addon/matrix/irc/irc.apd new file mode 100644 index 00000000..12189e78 --- /dev/null +++ b/sources/extend/addon/matrix/irc/irc.apd @@ -0,0 +1,3 @@ +url: $baseurl/irc +name: IRC Chat +photo: $baseurl/addon/irc/irc.png diff --git a/sources/extend/addon/matrix/irc/irc.css b/sources/extend/addon/matrix/irc/irc.css new file mode 100644 index 00000000..e69de29b diff --git a/sources/extend/addon/matrix/irc/irc.php b/sources/extend/addon/matrix/irc/irc.php new file mode 100644 index 00000000..b9d3a4a0 --- /dev/null +++ b/sources/extend/addon/matrix/irc/irc.php @@ -0,0 +1,119 @@ + +*/ + +/* enable in admin->plugins + * you will then have "irc chatroom" listed at yoursite/apps + * and the app will run at yoursite/irc + * documentation at http://tonybaldwin.me/hax/doku.php?id=friendica:irc + * admin can set popular chans, auto connect chans in settings->plugin settings + */ + +function irc_load() { + register_hook('app_menu', 'addon/irc/irc.php', 'irc_app_menu'); + register_hook('feature_settings', 'addon/irc/irc.php', 'irc_addon_settings'); + register_hook('feature_settings_post', 'addon/irc/irc.php', 'irc_addon_settings_post'); +} + +function irc_unload() { + unregister_hook('app_menu', 'addon/irc/irc.php', 'irc_app_menu'); + unregister_hook('feature_settings', 'addon/irc/irc.php', 'irc_addon_settings'); + unregister_hook('feature_settings_post', 'addon/irc/irc.php', 'irc_addon_settings_post'); + +} + + +function irc_addon_settings(&$a,&$s) { + + if(! is_site_admin()) + return; + + /* Add our stylesheet to the page so we can make our settings look nice */ + + //$a->page['htmlhead'] .= '' . "\r\n"; + + /* setting popular channels, auto connect channels */ + $sitechats = get_config('irc','sitechats'); /* popular channels */ + $autochans = get_config('irc','autochans'); /* auto connect chans */ + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('autochans', t('Channels to auto connect'), $sitechats, t('Comma separated list')) + )); + + $sc .= replace_macros(get_markup_template('field_input.tpl'), array( + '$field' => array('sitechats', t('Popular Channels'), $autochans, t('Comma separated list')) + )); + + $s .= replace_macros(get_markup_template('generic_addon_settings.tpl'), array( + '$addon' => array('irc', t('IRC Settings'), '', t('Submit')), + '$content' => $sc + )); + + return; + +} + +function irc_addon_settings_post(&$a,&$b) { + if(! is_site_admin()) + return; + + if($_POST['irc-submit']) { + set_config('irc','autochans',trim($_POST['autochans'])); + set_config('irc','sitechats',trim($_POST['sitechats'])); + /* stupid pop-up thing */ + info( t('IRC settings saved.') . EOL); + } +} + +function irc_app_menu($a,&$b) { +$b['app_menu'][] = ''; +} + + +function irc_module() { +return; +} + + +function irc_content(&$a) { + + $baseurl = $a->get_baseurl() . '/addon/irc'; + $o = ''; + + /* set the list of popular channels */ + $sitechats = get_config('irc','sitechats'); + if($sitechats) + $chats = explode(',',$sitechats); + else + $chats = array('hubzilla','friendica','chat','chatback','hottub','ircbar','dateroom','debian'); + + + $a->page['aside'] .= '

' . t('Popular Channels') . '

    '; + foreach($chats as $chat) { + $a->page['aside'] .= '
  • ' . '#' . $chat . '
  • '; + } + $a->page['aside'] .= '
'; + + /* setting the channel(s) to auto connect */ + $autochans = get_config('irc','autochans'); + if($autochans) + $channels = $autochans; + else + $channels = ((x($_GET,'channels')) ? $_GET['channels'] : 'hubzilla'); + +/* add the chatroom frame and some html */ + $o .= <<< EOT +

IRC chat

+

A beginner's guide to using IRC. [en]

+ +EOT; + +return $o; + +} + + diff --git a/sources/extend/addon/matrix/irc/irc.png b/sources/extend/addon/matrix/irc/irc.png new file mode 100644 index 00000000..0e4b185d Binary files /dev/null and b/sources/extend/addon/matrix/irc/irc.png differ diff --git a/sources/extend/addon/matrix/jappixmini/MIT.txt b/sources/extend/addon/matrix/jappixmini/MIT.txt new file mode 100644 index 00000000..2517727f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/MIT.txt @@ -0,0 +1,7 @@ +You may distribute all files which are not within the jappix/ folder under the following conditions: + +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/sources/extend/addon/matrix/jappixmini/README b/sources/extend/addon/matrix/jappixmini/README new file mode 100644 index 00000000..0bda660f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/README @@ -0,0 +1,27 @@ +Jappix Mini Plugin +================== + +This quick-and-dirty addon allows you to add a Jabber-based, Facebook-like chat +to Hubzilla. It uses Jappix Mini. + +It is necessary to use a BOSH host - so to use this plugin, each users need to +know the address of a BOSH host that works with his account. +It is recommended that you install your own BOSH server and recommend it using +the configuration help field. If it is on the same server, you can also deactivate the +BOSH proxy. This should improve the performance. + +The addon has an experimental autosubscribe and autosuggest functionality which +tries to add your Hubzilla contacts to your roster automatically. + +Limitations: + - Jabber passwords can only be encrypted if they are at most 39 characters + long. + +Notes on the license +-------------------- + +The license of this addon is AGPL, as required by Jappix Mini. If you make +modifications to the addon, you are responsible for providing a proper facility +for downloading the changed source code. +Moreover, it may be necessary that you publish the source code of the Friendica +application and all other used addons if you do not use standard versions. diff --git a/sources/extend/addon/matrix/jappixmini/jappix/AUTHORS b/sources/extend/addon/matrix/jappixmini/jappix/AUTHORS new file mode 100644 index 00000000..0086eb6a --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/AUTHORS @@ -0,0 +1,54 @@ +Jappix - An open social platform +These are the authors of Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 15/01/12 + +------------------------------------------------- + +Here are the Jappix contributors, who coded or translated the application (Codingteam.net nicknames): + +# DEVELOPERS + - am0ur3ux + - LinkMauve + - Maranda + - Mathieui + - Olivier + - sim6 + - Vanaryon + +# TRANSLATORS + - allan + - Arsimael + - Belzeneph + - Catdarko + - Cerritus + - chunzu + - ebraminio + - Finkregh + - hamano + - JanCBorchardt + - jarda + - joeka + - kr2ysiek + - krohn + - Lenwe + - LinkMauve + - Liverbool + - lwj + - m1st + - Maime + - Maranda + - mbajur + - mentalo + - mkwm + - Otourly + - pocamon + - quimi + - sahwar + - Vanaryon + - vitalyster + - Zash diff --git a/sources/extend/addon/matrix/jappixmini/jappix/COPYING b/sources/extend/addon/matrix/jappixmini/jappix/COPYING new file mode 100644 index 00000000..84ae389f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/COPYING @@ -0,0 +1,662 @@ + 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/sources/extend/addon/matrix/jappixmini/jappix/INSTALL b/sources/extend/addon/matrix/jappixmini/jappix/INSTALL new file mode 100644 index 00000000..652c1be7 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/INSTALL @@ -0,0 +1,23 @@ +Jappix - An open social platform +These are the installation instructions for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 15/09/10 + +------------------------------------------------- + +It's very simple to install Jappix on your webserver, you just have to follow these things: + +# INSTALLATION + - The HTTP server : http://codingteam.net/project/jappix/doc/HttpServer + - The XMPP server : http://codingteam.net/project/jappix/doc/XmppServer + - The BOSH server : http://codingteam.net/project/jappix/doc/BoshServer + - The Jappix app. : http://codingteam.net/project/jappix/doc/JappixApp + +# MORE + - The whole documentation is available at : http://codingteam.net/project/jappix/doc + +Now, you can use Jappix. Happy socializing! diff --git a/sources/extend/addon/matrix/jappixmini/jappix/README b/sources/extend/addon/matrix/jappixmini/jappix/README new file mode 100644 index 00000000..49cbf974 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/README @@ -0,0 +1,20 @@ +Jappix - An open social platform +This is the readme file for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 18/02/11 + +------------------------------------------------- + +Please refer to the installation instructions that are located in the INSTALL file to process the Jappix installation. + +The Jappix Project official service: https://www.jappix.com/ +The Jappix Project website: https://project.jappix.com/ +The Jappix Project panel: http://codingteam.net/project/jappix + +Jappix is released under the terms of the AGPL license. See COPYING for details. + +Have fun with Jappix! diff --git a/sources/extend/addon/matrix/jappixmini/jappix/THANKS b/sources/extend/addon/matrix/jappixmini/jappix/THANKS new file mode 100644 index 00000000..a5b12227 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/THANKS @@ -0,0 +1,27 @@ +Jappix - An open social platform +These are the special thanks for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/02/11 + +------------------------------------------------- + +We would like to thanks the authors of these tools, coming from other projects: + +# PROJECTS + - Base64 http://rumkin.com + - DrawSVGChart http://codingteam.net/project/codingteam + - idzXHR http://www.iadvize.com/plugin_strophe_xmpp.html + - JSJaC http://blog.jwchat.org/jsjac/ + - jQuery http://jquery.com/ + - jQuery Form http://jquery.malsup.com/form/ + - jQuery Timers http://plugins.jquery.com/project/timers + - jXHR http://mulletxhr.com/ + - Mobile Detect http://code.google.com/p/php-mobile-detect/ + - JSMin http://github.com/rgrove/jsmin-php/ + - PHP-gettext https://launchpad.net/php-gettext + - Silk icons http://www.famfamfam.com/lab/icons/silk/ + - Smileys http://www.gajim.org/ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/VERSION b/sources/extend/addon/matrix/jappixmini/jappix/VERSION new file mode 100644 index 00000000..76892598 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/VERSION @@ -0,0 +1 @@ +Spaco [0.9] diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/adhoc.css b/sources/extend/addon/matrix/jappixmini/jappix/css/adhoc.css new file mode 100644 index 00000000..68d0383f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/adhoc.css @@ -0,0 +1,26 @@ +/* + +Jappix - An open social platform +This is the Ad-Hoc CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 20/12/10 + +*/ + +#adhoc .content { + padding: 10px 0 10px 0; +} + +#adhoc .adhoc-head { + background-color: #f1f6fd; + border: 1px #9dc4fc solid; + width: 598px; + height: 18px; + font-size: 0.9em; + margin: 0 10px 12px 10px; + padding: 6px 10px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/anonymous.css b/sources/extend/addon/matrix/jappixmini/jappix/css/anonymous.css new file mode 100644 index 00000000..f61a79c6 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/anonymous.css @@ -0,0 +1,29 @@ +/* + +Jappix - An open social platform +This is the anonymous mode CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 06/11/10 + +*/ + +#top-content { + min-width: 500px !important; +} + +#main-content { + min-width: 490px !important; + min-height: 450px !important; +} + +#left-content { + display: none; +} + +#right-content { + left: 0; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/archives.css b/sources/extend/addon/matrix/jappixmini/jappix/css/archives.css new file mode 100644 index 00000000..5e60a8be --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/archives.css @@ -0,0 +1,93 @@ +/* + +Jappix - An open social platform +This is the archives CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 19/12/10 + +*/ + +#archives .content { + padding: 10px 0 10px 0; +} + +#archives .filter { + background-color: #e9f1fd; + border-right: 1px solid #9dc4fc; + width: 180px; + padding: 12px; + position: absolute; + top: 0; + left: 0; + bottom: 0; + float: left; + border-top-left-radius: 4px; + border-bottom-left-radius: 4px; + -moz-border-radius-topleft: 4px; + -moz-border-radius-bottomleft: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-bottom-left-radius: 4px; +} + +#archives .filter .friend { + margin-bottom: 12px; +} + +#archives .filter .friend { + height: 210px; + width: 180px; + float: none; +} + +#archives .current, +#archives .logs { + position: absolute; + bottom: 0; + right: 0; + left: 204px; +} + +#archives .current { + background-color: #e4eef9; + border-bottom: 1px solid #9dc4fc; + font-size: 0.9em; + height: 16px; + padding: 6px; + top: 0; +} + +#archives .current span { + height: 16px; + overflow: hidden; +} + +#archives .current .name { + max-width: 160px; + font-weight: bold; + float: left; +} + +#archives .current .time { + color: #47646a; + font-size: 0.95em; + float: right; +} + +#archives .logs { + color: black; + font-size: 0.9em; + overflow: auto; + padding: 8px 10px 0; + float: left; + position: absolute; + top: 29px; +} + +#archives .logs a { + color: black; + text-decoration: underline; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/board.css b/sources/extend/addon/matrix/jappixmini/jappix/css/board.css new file mode 100644 index 00000000..91e6dcf9 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/board.css @@ -0,0 +1,47 @@ +/* + +Jappix - An open social platform +This is the board CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 26/08/11 + +*/ + +#board .one-board { + display: none; + position: fixed; + top: 0; + left: 0; + right: 0; + height: 18px; + z-index: 10000; + font-size: 0.92em; + padding: 6px 8px; + box-shadow: 0 0 8px #5c5c5c; + -moz-box-shadow: 0 0 8px #5c5c5c; + -webkit-box-shadow: 0 0 8px #5c5c5c; +} + +#board .one-board:hover { + cursor: pointer; +} + +#board .one-board.visible { + display: block; +} + +#board .one-board.error { + background-color: rgb(241,160,160); + background-color: rgba(241,160,160,0.9); + color: #420c0c; +} + +#board .one-board.info { + background-color: rgb(248,246,186); + background-color: rgba(248,246,186,0.9); + color: #2f2a02; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/buddylist.css b/sources/extend/addon/matrix/jappixmini/jappix/css/buddylist.css new file mode 100644 index 00000000..3bfa70cb --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/buddylist.css @@ -0,0 +1,530 @@ +/* + +Jappix - An open social platform +This is the buddy-list CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 31/08/11 + +*/ + +#buddy-list { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + color: #919191; + padding: 15px 6px 4px 6px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 0 6px #5c5c5c; + -moz-box-shadow: 0 0 6px #5c5c5c; + -webkit-box-shadow: 0 0 6px #5c5c5c; +} + +#buddy-list .content { + background: #e8f1f3; + background: -moz-linear-gradient(top, #e8f1f3, #e4edef); + background: -webkit-gradient(linear, left top, left bottom, from(#e8f1f3), to(#e4edef)); + color: #666666; + height: 207px; + padding: 4px 4px 0 4px; + overflow-x: hidden; + overflow-y: auto; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + -moz-border-radius-topleft: 3px; + -moz-border-radius-topright: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-top-right-radius: 3px; +} + +#buddy-list .one-group { + margin-bottom: 10px; +} + +#buddy-list .one-group a.group { + color: #202c2f; + font-size: 0.8em; + margin: 3px 6px; + padding-left: 12px; + max-height: 15px; + text-decoration: none; + overflow: hidden; + display: block; +} + +#buddy-list .one-group a.group.plus { + background-position: -4px -1143px; +} + +#buddy-list .one-group a.group.minus { + background-position: -4px -1162px; +} + +#buddy-list .one-group a.group:hover { + cursor: pointer; +} + +#buddy-list .hidden-buddy, +#buddy-list .foot-edit-finish, +.buddy-conf-more-display-available { + display: none; +} + +#buddy-list .buddy { + width: 100%; + height: 50px; + margin-bottom: 4px; +} + +#buddy-list .buddy-click { + background: #d9e7ea; + width: 100%; + height: 100%; + overflow: hidden; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#buddy-list .buddy-click:hover, +#buddy-list .buddy-click:focus { + background: #cedee1; + cursor: pointer; +} + +#buddy-list .buddy-click:active { + background: #c3d3d7; +} + +#buddy-list .gateway { + height: 27px; +} + +#buddy-list .gateway .name { + margin-left: 0; +} + +#buddy-list .gateway .buddy-presence { + float: left; + overflow: hidden; + width: 0; + margin: 0 4px; +} + +#buddy-list .avatar-container { + float: left; + text-align: center; + margin: 3px; + width: 46px; + height: 46px; +} + +#buddy-list .avatar { + max-width: 44px; + max-height: 44px; +} + +#buddy-list .name { + margin: 4px 3px 5px 56px; +} + +#buddy-list .buddy-name { + height: 17px; + font-weight: bold; + font-size: 0.8em; + color: #264249; + margin: 5px 0 5px 2px; + overflow: hidden; +} + +#buddy-list .buddy.blocked p.buddy-name { + text-decoration: line-through; +} + +#buddy-list .buddy-presence { + height: 14px; + font-size: 0.7em; + color: #3a585e; + padding: 2px 0 0 16px; + margin-top: -3px; +} + +#buddy-list .unavailable, +#page-switch .unavailable, +#page-engine p.bc-infos span.show.unavailable { + background-position: 0 -153px; +} + +#buddy-list .available, +#page-engine p.bc-infos span.show.available, +#page-engine .list .available, +#page-engine .list .chat, +#page-switch .available, +#my-infos .f-presence a[data-value=available] span { + background-position: 0 -169px; +} + +#buddy-list .away, +#page-engine p.bc-infos span.show.away, +#page-engine .list .away, +#page-switch .away, +#my-infos .f-presence a[data-value=away] span { + background-position: 0 -185px; +} + +#buddy-list .busy, +#page-engine p.bc-infos span.show.busy, +#page-engine .list .xa, +#page-engine .list .dnd, +#page-switch .busy, +#my-infos .f-presence a[data-value=xa] span { + background-position: 0 -201px; +} + +#buddy-list .error, +#page-switch .error, +#page-engine p.bc-infos span.show.error { + background-position: 0 -217px; +} + +#buddy-list .buddy-infos { + position: absolute; + z-index: 100; + width: 337px; + color: white; + font-size: 0.8em; +} + +.buddy-infos-subarrow { + background-position: 0 -241px; + opacity: 0.8; + width: 9px; + height: 20px; + margin-top: 12px; + float: left; +} + +.buddy-infos-subitem { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.8); + padding: 8px 10px; + width: 308px; + text-shadow: 0 1px 1px black; + float: left; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.manage-infos p.bm-authorize, +#rosterx .oneresult span.action.add { + background-position: 0 -1181px; +} + +.manage-infos p.bm-remove, +#rosterx .oneresult span.action.delete, +#attach div.one-file a.remove { + background-position: 0 -1200px; +} + +.manage-infos p.bm-remove { + margin-bottom: 18px; +} + +.manage-infos p.bm-rename { + background-position: 0 -1216px; +} + +.manage-infos p.bm-group { + background-position: 0 -1241px; +} + +.manage-infos div.bm-choose { + max-height: 95px; + margin: 0 0 8px 102px; + overflow: auto; +} + +.manage-infos div.bm-choose label { + float: left; + clear: both; + margin-bottom: 1px; +} + +.manage-infos div.bm-choose input { + float: left; +} + +.manage-infos div.bm-choose input[type=checkbox] { + margin: 0 6px 0 0; +} + +.manage-infos div.bm-choose div { + clear: both; +} + +.manage-infos p.bm-rename, +.manage-infos p.bm-group { + height: 26px; +} + +.manage-infos p.bm-rename label, +.manage-infos p.bm-group label { + width: 80px; + padding-top: 3px; + float: left; +} + +.manage-infos p.bm-rename input, +.manage-infos p.bm-group input { + float: left; + width: 155px; +} + +.manage-infos a.save { + float: right; + margin: 4px; +} + +.buddy-infos-subitem p { + margin: 6px 0; + padding-left: 22px; + height: 16px; + overflow: hidden; +} + +.buddy-infos-subitem a { + color: white; + text-decoration: underline; +} + +.tune-note { + background-position: 0 -676px; +} + +.location-world { + background-position: 0 -658px; +} + +.view-individual { + background-position: 0 -34px; +} + +.edit-buddy { + background-position: 0 -1008px; +} + +#buddy-list .filter { + background-color: white; + border-top: 1px solid #b8c2c4; + height: 15px; + padding: 2px 4px; + font-size: 0.8em; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-bottomright: 3px; + -webkit-border-bottom-left-radius: 3px; + -webkit-border-bottom-right-radius: 3px; +} + +#buddy-list .filter input { + border: none; + color: #273a3f; + width: 211px; + padding: 0; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; +} + +#buddy-list .filter a { + display: none; + background-color: #9a2d2d; + color: white; + height: 13px; + width: 13px; + margin-top: 1px; + font-size: 0.8em; + text-align: center; + text-decoration: none; + float: right; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#buddy-list .filter a:hover, +#buddy-list .filter a:focus { + background-color: #8c2121; +} + +#buddy-list .filter a:active { + background-color: #7e1919; +} + +#buddy-list .foot { + padding: 9px 1px 3px; +} + +#buddy-list .buddy-list-icon { + height: 16px; + width: 16px; + margin: -3px 5px 0 0; + float: left; +} + +#buddy-list .buddy-list-icon a.talk-images { + height: 16px; + width: 16px; + display: block; +} + +#buddy-list .add, +#page-engine .text .tools-add { + background-position: 0 -1047px; +} + +#buddy-list .join { + background-position: 0 -1065px; +} + +#buddy-list .groupchat, +#page-switch .groupchat-default { + background-position: 0 -1082px; +} + +#buddy-list .more { + background-position: 0 -1100px; +} + +#buddy-list .foot-edit-finish a { + color: white; + font-size: 0.8em; + margin: -3px 4px 0 0; + float: right; + display: block; +} + +#buddy-list .foot-edit-finish a:hover, +#buddy-list .foot-edit-finish a:focus { + text-decoration: underline; + cursor: pointer; +} + +.buddy-conf-item { + position: absolute; + width: 263px; + color: white; + z-index: 9998; + text-align: left; + font-size: 0.8em; + margin-left: -10px; +} + +.buddy-conf-item:hover { + cursor: default; +} + +.buddy-conf-subarrow { + background-position: 0 -241px; + opacity: 0.8; + height: 10px; + width: 18px; + margin-left: 9px; +} + +.buddy-conf-subitem { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.8); + padding: 10px; + text-shadow: 0 1px 1px black; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.buddy-conf-p { + margin-bottom: 4px; + width: 220px; + font-weight: bold; + float: left; +} + +.buddy-conf-input { + padding-top: 2px; +} + +.buddy-conf-text { + font-size: 11px; + clear: both; + margin-bottom: 3px; +} + +.buddy-conf-text a { + color: white; +} + +.buddy-conf-text a:hover, +.buddy-conf-text a:focus { + cursor: pointer; + text-decoration: underline; +} + +.buddy-conf-text a.buddy-conf-add-search { + text-decoration: underline; + margin-top: 6px; + display: block; +} + +.buddy-conf-select { + font-size: 1.1em; + clear: both; + margin-bottom: 8px; + width: 180px; + height: 23px; +} + +.join-jid { + width: 220px; + margin-top: 5px; +} + +.add-contact-jid, +.add-contact-name, +.add-contact-gateway { + width: 156px; + margin-bottom: 4px; +} + +.add-contact-name-get { + font-size: 0.8em; + display: none; +} + +.buddy-conf-subitem label { + clear: both; +} + +.buddy-conf-subitem label span { + width: 76px; + height: 14px; + margin-top: 3px; + overflow: hidden; + float: left; +} + +#buddy-conf-join ul { + width: 224px; + max-height: 160px; + left: 10px; + top: 51px; +} + +.buddy-conf-join-select { + margin: 8px 0 0 0; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/channel.css b/sources/extend/addon/matrix/jappixmini/jappix/css/channel.css new file mode 100644 index 00000000..671d25ea --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/channel.css @@ -0,0 +1,545 @@ +/* + +Jappix - An open social platform +This is the channel CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 26/08/11 + +*/ + +#channel .top div.update { + position: absolute; + top: 12px; + left: 115px; + right: 15px; + bottom: 15px; + border-radius: 20px; + -moz-border-radius: 20px; + -webkit-border-radius: 20px; +} + +#channel .top p { + font-size: 0.9em; + margin-bottom: 10px; +} + +#channel .top h2 { + font-size: 1.6em; + margin-bottom: 10px; + color: #232323; +} + +#channel .top a { + font-size: 0.9em; + color: #232323; +} + +#channel .top.individual div.update { + right: 36px; +} + +#channel .top.individual div.shortcuts, +#userinfos .main-infos div.shortcuts { + width: 16px; + float: right; +} + +#channel .top.individual div.shortcuts { + margin: 2px 5px 0 0; +} + +#channel .top.individual div.shortcuts a, +#userinfos .main-infos div.shortcuts a { + height: 16px; + width: 16px; + margin-bottom: 4px; + display: block; +} + +#channel .top.individual div.shortcuts a.message, +#userinfos .main-infos a.message { + background-position: 0 -1717px; +} + +#channel .top.individual div.shortcuts a.chat, +#userinfos .main-infos a.chat { + background-position: 0 -1737px; +} + +#channel .top.individual div.shortcuts a.command, +#userinfos .main-infos a.command { + background-position: 0 -1758px; +} + +#channel .microblog-body { + height: 20px; + margin-right: 50px; +} + +#channel .microblog-body input { + width: 100%; + height: 100%; + padding: 8px; +} + +#channel .one-microblog-icon { + position: absolute; + top: 38px; + right: 0; +} + +#channel div.update .one-microblog-icon, +#channel div.update .postit { + width: 16px; + height: 16px; + display: block; +} + +#channel div.update .attach { + background-position: 0 -79px; + display: none; +} + +#attach { + position: absolute; + width: 263px; + margin-left: -227px; + color: white; + font-size: 0.85em; + z-index: 9998; + text-align: left; + display: none; +} + +#attach p { + margin-bottom: 6px !important; +} + +#attach input[type=submit] { + margin: 8px 0 6px 0; +} + +#attach .wait { + float: right; + margin: 7px 5px; +} + +#attach div.one-file { + height: 16px; + margin-top: 2px; +} + +#attach div.one-file a.link { + color: white; + width: 215px; + height: 14px; + margin-left: 2px; + overflow: hidden; + float: left; +} + +#attach div.one-file a.remove { + width: 16px; + height: 16px; + float: left; +} + +.attach-subarrow { + background-position: 0 -241px; + opacity: 0.8; + height: 10px; + width: 18px; + margin-left: 226px; +} + +.attach-subitem { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.8); + padding: 10px; + text-shadow: 0 1px 1px black; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.attach-p { + font-weight: bold; + float: left; +} + +#channel .one-update { + margin-bottom: 12px; + padding: 6px 6px 8px 6px; + border-bottom: 1px dotted #d0d0d0; + min-height: 50px; + color: black; + position: relative; + display: none; +} + +#channel .one-update .avatar-container { + text-align: center; + margin-right: 16px; + float: left; + height: 50px; + width: 50px; +} + +#channel .one-update .avatar-container:hover { + cursor: pointer; +} + +#channel .one-update img.avatar { + max-height: 50px; + max-width: 50px; +} + +#channel .one-update div.body { + margin-left: 65px; + opacity: 0.8; +} + +#channel .one-update:hover div.body { + opacity: 1; +} + +#channel .one-update a.repeat { + background-position: 0 -1681px; + height: 16px; + width: 16px; + margin-right: 4px; + float: left; +} + +#channel .one-update span a { + text-decoration: underline; +} + +#channel .one-update p { + display: block; + margin: 0 12px 5px 0; +} + +#channel .one-update p b.name:hover { + cursor: pointer; + text-decoration: underline; +} + +#channel .one-update p.infos { + font-size: 0.9em; +} + +#channel .one-update p.infos a.geoloc { + background-position: 0 -1778px; + color: #363636; + margin-left: 18px; + padding-left: 14px; +} + +#channel .one-update p.infos a.geoloc:hover, +#channel .one-update p.infos a.geoloc:focus, +#channel .one-update p.infos a.geoloc:active { + color: #141414; +} + +#channel .one-update p.file { + font-size: 0.9em; + margin: 6px 0 5px 10px; +} + +#channel .one-update p.file a.link, +#inbox .inbox-new-file a.file { + min-height: 16px; + padding-left: 22px; + text-decoration: underline; + display: block; +} + +#channel .one-update p.file a.link { + margin-top: 4px; +} + +#channel p.file a, +#inbox .inbox-new-file a.file { + background-position: 0 -988px; +} + +#channel p.file a.audio, +#inbox .inbox-new-file a.file.audio { + background-position: 0 -899px; +} + +#channel p.file a.image, +#inbox .inbox-new-file a.file.image { + background-position: 0 -917px; +} + +#channel p.file a.video, +#inbox .inbox-new-file a.file.video { + background-position: 0 -935px; +} + +#channel p.file a.document, +#inbox .inbox-new-file a.file.document { + background-position: 0 -953px; +} + +#channel p.file a.package, +#inbox .inbox-new-file a.file.package { + background-position: 0 -971px; +} + +#channel .one-update p.file a.thumb img { + border: 1px solid #a2a2a2; + max-width: 140px; + max-height: 105px; + margin: 4px 10px 2px 0; + padding: 1px; +} + +#channel .one-update p.file a.thumb img:hover { + border-color: #464646; +} + +#channel .one-update div.comments, +.popup.large div.comments { + width: 410px; + margin: 2px 0 2px 76px; +} + +#channel .one-update div.comments div.arrow, +.popup.large div.comments div.arrow { + background-position: 0 -1702px; + width: 20px; + height: 8px; + margin-left: 20px; + display: block; +} + +#channel .one-update div.comments div.comments-content, +.popup.large div.comments div.comments-content { + background-color: #e5ebec; + color: black; + font-size: 0.9em; + text-shadow: 0 1px 0 white; +} + +#channel .one-update div.comments input, +.popup.large div.comments input { + width: 356px; + margin: 6px 0; + padding: 4px 5px; +} + +#channel .one-update div.comments span.icon, +.popup.large div.comments span.icon { + background-position: 0 -1082px; + height: 16px; + width: 16px; + margin: 10px; + float: left; +} + +#channel .one-update div.comments .one-comment.loading span.icon, +.popup.large div.comments .one-comment.loading span.icon { + margin: 0 10px 0 0; +} + +#channel .one-update div.comments .one-comment, +.popup.large div.comments .one-comment { + border-bottom: 1px solid #f4f4f4; + padding: 4px 8px 0px 8px; + position: relative; + display: block; +} + +#channel .one-update div.comments .one-comment.compose, +.popup.large div.comments .one-comment.compose { + border-bottom: 2px solid #f4f4f4; + height: 36px; + padding: 0; +} + +#channel .one-update div.comments .one-comment.new, +.popup.large div.comments .one-comment.new { + display: none; +} + +#channel .one-update div.comments a.one-comment, +.popup.large div.comments a.one-comment { + text-decoration: none; +} + +#channel .one-update div.comments a.one-comment:hover, +#channel .one-update div.comments a.one-comment:focus, +.popup.large div.comments a.one-comment:hover, +.popup.large div.comments a.one-comment:focus { + text-decoration: underline; +} + +#channel .one-update div.comments .one-comment.loading, +.popup.large div.comments .one-comment.loading { + padding-bottom: 5px; +} + +#channel .one-update div.comments .one-comment div.marker, +.popup.large div.comments .one-comment div.marker { + background-color: #6d8387; + width: 2px; + position: absolute; + top: 0; + left: 0; + bottom: 0; +} + +#channel .one-update div.comments .one-comment .avatar-container, +.popup.large div.comments .one-comment .avatar-container { + text-align: center; + width: 30px; + height: 30px; + margin: 2px 8px 0 0; + float: left; +} + +#channel .one-update div.comments .one-comment .avatar-container:hover, +.popup.large div.comments .one-comment .avatar-container:hover { + cursor: pointer; +} + +#channel .one-update div.comments .one-comment img.avatar, +.popup.large div.comments .one-comment img.avatar { + max-height: 30px; + max-width: 30px; +} + +#channel .one-update div.comments .one-comment .comment-container, +.popup.large div.comments .one-comment .comment-container { + float: left; +} + +#channel .one-update div.comments .one-comment a.name, +.popup.large div.comments .one-comment a.name { + font-weight: bold; + text-decoration: none; + font-size: 0.95em; + padding-bottom: 2px; + float: left; +} + +#channel .one-update div.comments .one-comment a.name:hover, +#channel .one-update div.comments .one-comment a.name:focus, +.popup.large div.comments .one-comment a.name:hover, +.popup.large div.comments .one-comment a.name:focus { + text-decoration: underline; +} + +#channel .one-update div.comments .one-comment span.date, +#channel .one-update div.comments .one-comment a.remove, +.popup.large div.comments .one-comment span.date, +.popup.large div.comments .one-comment a.remove { + font-size: 0.85em; + float: right; +} + +#channel .one-update div.comments .one-comment.me:hover span.date, +.popup.large div.comments .one-comment.me:hover span.date { + display: none; +} + +#channel .one-update div.comments .one-comment.me a.remove, +.popup.large div.comments .one-comment.me a.remove { + display: none; +} + +#channel .one-update div.comments .one-comment.me:hover a.remove, +.popup.large div.comments .one-comment.me:hover a.remove { + display: block; +} + +#channel .one-update div.comments .one-comment p.body, +.popup.large div.comments .one-comment p.body { + clear: both; +} + +#channel a.more { + background-position: 0 -334px; + color: black; + height: 16px; + text-decoration: none; + margin: -2px 0 0 4px; + padding: 0 0 14px 20px; + display: block; + visibility: hidden; +} + +#channel a.more:hover, +#channel a.more:focus { + text-decoration: underline; +} + +#channel a.mbtool { + width: 11px; + height: 11px; + display: none; + position: absolute; + right: 0; +} + +#channel .one-update:hover a.mbtool { + display: block; +} + +#channel a.mbtool:hover, +#channel a.mbtool:focus { + text-decoration: none; +} + +#channel a.mbtool.profile { + background-position: -1px -1333px; + top: 24px; +} + +#channel a.mbtool.repost { + background-position: -1px -1354px; +} + +#channel a.mbtool.remove { + background-position: -1px -1312px; +} + +#channel a.mbtool.repost, +#channel a.mbtool.remove { + top: 6px; +} + +#channel .footer { + bottom: 0; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; +} + +#channel .footer div { + margin-left: 5px; + padding-left: 24px; + min-height: 16px; + font-size: 0.85em; + width: auto !important; +} + +#channel .footer .sync { + background-position: 0 -804px; + display: none; +} + +#channel .footer .unsync { + background-position: 0 -830px; + display: none; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/directory.css b/sources/extend/addon/matrix/jappixmini/jappix/css/directory.css new file mode 100644 index 00000000..34b32312 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/directory.css @@ -0,0 +1,16 @@ +/* + +Jappix - An open social platform +This is the directory tool CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 13/02/11 + +*/ + +#directory .content { + padding: 10px 0 10px 0; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/discovery.css b/sources/extend/addon/matrix/jappixmini/jappix/css/discovery.css new file mode 100644 index 00000000..f66456b6 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/discovery.css @@ -0,0 +1,61 @@ +/* + +Jappix - An open social platform +This is the discovery CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 13/02/11 + +*/ + +#discovery .content { + padding: 10px 0 10px 0; +} + +#discovery .content p { + margin: 5px 10px 5px 10px; + text-align: justify; + font-size: 0.85em; +} + +#discovery .discovery-head, +#directory .directory-head, +#rosterx .rosterx-head, +#privacy .privacy-head { + width: 606px; + height: 24px; + margin: 0 10px 10px 10px; + padding: 6px; + background: #f1f6fd; + border: 1px #9dc4fc solid; +} + +#discovery .disco-server-text, +#directory .directory-server-text { + float: left; + font-size: 0.9em; + margin: 3px; +} + +#discovery .disco-server-input, +#directory .directory-server-input { + float: right; + width: 200px; + padding: 2px; + height: 18px; + float: right; + margin-right: 10px; + padding: 2px; +} + +#discovery .disco-category { + display: none; + margin-bottom: 22px; +} + +#discovery .disco-category-title { + font-weight: bold; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/favorites.css b/sources/extend/addon/matrix/jappixmini/jappix/css/favorites.css new file mode 100644 index 00000000..5d3fd51d --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/favorites.css @@ -0,0 +1,179 @@ +/* + +Jappix - An open social platform +This is the favorites CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 28/12/10 + +*/ + +#favorites .content { + padding: 10px 0 10px 0; +} + +#favorites .fedit-head-select { + min-width: 190px; + max-width: 210px; +} + +#favorites .switch-fav { + margin: 0 10px 0 10px; + width: 200px; + height: 355px; + border-right: 1px #c0c0c0 dotted; + float: left; +} + +#favorites .room-switcher { + width: 188px; + height: 18px; + border-bottom: 1px #9dc4fc solid; + float: left; + padding: 10px 6px; + font-size: 0.9em; +} + +#favorites .room-switcher:hover { + background-color: #e9f1fd; + cursor: pointer; +} + +#favorites .room-switcher:active { + background-color: #f1f6fd; +} + +#favorites .switch-fav .icon { + float: left; + height: 16px; + width: 16px; + margin: 0 8px 0 0; +} + +#favorites .switch-fav .room-list .list-icon { + background-position: 0 -855px; +} + +#favorites .switch-fav .room-search .search-icon { + background-position: 0 -876px; +} + +#favorites .static-fav { + width: 385px; + height: 335px; + margin: 0 10px 0 0; + padding: 10px; + float: right; +} + +#favorites .favorites-search { + display: none; +} + +#favorites .static-fav-head { + width: 393px; + margin: -10px; +} + +#favorites .static-fav-results { + width: 406px; + height: 314px; + margin: 10px -10px -10px -10px; + padding: 6px 0 0 0; +} + +#favorites .fedit-line { + height: 30px; + font-size: 0.9em; + padding: 10px 0 4px 4px; + border-bottom: 1px #9dc4fc solid; +} + +#favorites .fedit-line:hover { + background: #e9f1fd; +} + +#favorites label { + width: 140px; + margin-top: 3px; +} + +#favorites input { + height: 18px; + width: 186px; + margin-top: 0; + padding: 2px; +} + +#favorites .fedit-select { + min-width: 160px; +} + +#favorites .fedit-actions { + margin: 10px 0 0; + font-size: 0.9em; + float: right; +} + +#favorites input[type=checkbox] { + margin-top: 5px; +} + +#favorites .fedit-terminate { + float: right; +} + +#favorites .fedit-add { + display: block; +} + +#favorites .fedit-edit { + background-position: 2px -1240px; +} + +#favorites .fedit-remove { + margin: 0 8px 0 0; +} + +#favorites .add, +.popup .results .one-button.one-add { + background-position: 3px -1177px; +} + +#favorites .remove, +#inbox .remove { + background-position: 3px -1196px; +} + +#favorites .join, +#inbox .reply, +#inbox .send, +.popup .results .one-button.one-chat { + background-position: 3px -124px; +} + +#favorites .one-button, +#inbox .one-button, +.popup .results .one-button { + padding-left: 20px !important; + font-size: 0.98em; +} + +#favorites .fsearch-results { + overflow: auto; +} + +#favorites .room-name { + margin: 4px 2px 5px; + max-width: 210px; + float: left; +} + +#favorites .fsearch-noresults { + display: none; + font-size: 0.9em; + font-weight: bold; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/home.css b/sources/extend/addon/matrix/jappixmini/jappix/css/home.css new file mode 100644 index 00000000..789ea4d9 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/home.css @@ -0,0 +1,579 @@ +/* + +Jappix - An open social platform +This is the home CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 15/01/12 + +*/ + +#home { + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + min-height: 550px; + min-width: 875px; +} + +#home .corporation, +#home .corporation .corp_network, +#home .locale, +#home .obsolete { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.70); + color: white; + position: absolute; + top: 0; + text-shadow: 0 0 1px black; + z-index: 100; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-bottomright: 3px; + -webkit-border-bottom-left-radius: 3px; + -webkit-border-bottom-right-radius: 3px; +} + +#home .corporation { + background-position: 9px -357px; + left: 12px; + height: 26px; + width: 34px; +} + +#home .corporation.hovered { + height: 28px; + border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; +} + +#home .corporation .corp_network { + width: 180px; + padding: 10px 12px; + top: 28px; + display: none; + border-top-right-radius: 3px; + -moz-border-radius-topright: 3px; + -webkit-border-top-right-radius: 3px; +} + +#home .corporation.hovered .corp_network { + display: block; +} + +#home .corporation .corp_network h2 { + font-size: 1.1em; + margin: 14px 0 4px 0; +} + +#home .corporation .corp_network h2.nomargin { + margin-top: 0; +} + +#home .corporation .corp_network a { + font-size: 0.8em; + margin: 2px 0; + padding: 2px 6px; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#home .corporation .corp_network a span { + margin: 2px 0; + display: block; +} + +#home .corporation .corp_network a span.name { + font-weight: bold; +} + +#home .corporation .corp_network a span.desc { + font-size: 0.9em; + margin-left: 2px; +} + +#home .locale { + left: 52px; + font-size: 0.8em; +} + +#home .locale .current { + height: 19px; + padding: 3px 12px 4px 12px; + font-weight: bold; +} + +#home .locale .current:hover { + cursor: default; +} + +#home .locale .current .current_align { + height: 19px; + vertical-align: middle; + display: table-cell; +} + +#home .locale .list { + margin: 2px 0 2px; +} + +#home .locale .list a, +#home .corporation .corp_network a { + color: white; + text-decoration: none; + display: block; +} + +#home .locale .list a { + padding: 3px 10px; +} + +#home .locale .list a:hover, +#home .locale .list a:focus, +#home .corporation .corp_network a:hover, +#home .corporation .corp_network a:focus { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); + cursor: pointer; +} + +#home .locale .list a:active, +#home .corporation .corp_network a:active { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.14); +} + +#home .obsolete { + height: 60px; + padding: 4px 10px; + right: 12px; + font-size: 0.9em; + font-weight: bold; + display: none; +} + +#home .obsolete a { + height: 33px; + width: 33px; + margin: 5px 2px 0 0; + float: left; +} + +#home .obsolete a:hover, +#home .obsolete a:focus { + opacity: 0.8; +} + +#home .obsolete a:active { + opacity: 0.6; +} + +#home .obsolete a.firefox { + background-position: 1px 0; +} + +#home .obsolete a.chrome { + background-position: -34px 0; +} + +#home .obsolete a.safari { + background-position: -68px 0; +} + +#home .obsolete a.opera { + background-position: -101px 0; +} + +#home .obsolete a.ie { + background-position: -135px 0; +} + +#home .plane { + background-position: 0 -384px; + width: 507px; + height: 328px; + position: absolute; + left: 0; + top: 60px; +} + +#home .main { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + position: absolute; + top: 50%; + margin-top: -200px; + width: 800px; + height: 400px; + left: 50%; + margin-left: -400px; + z-index: 50; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; + box-shadow: 0 0 35px #5c5c5c; + -moz-box-shadow: 0 0 35px #5c5c5c; + -webkit-box-shadow: 0 0 35px #5c5c5c; +} + +#home .left { + float: left; + width: 350px; + height: 370px; + margin: 15px 0 15px 15px; + color: white; + text-align: center; + text-shadow: 0 1px 1px black; +} + +#home .left .logo { + background-position: 0 0; + float: left; + margin: 30px 20px; + width: 311px; + height: 113px; +} + +#home .left p.upper { + margin: 12px 0 20px 0; +} + +#home .left p.secondary { + margin: 8px 0 0 16px; + font-size: 0.9em; + width: 320px; +} + +#home .right { + background: #e4eef9; + background: -moz-linear-gradient(top, #e4eef9, #C5E1FF); + background: -webkit-gradient(linear, left top, left bottom, from(#e4eef9), to(#C5E1FF)); + float: right; + width: 385px; + height: 350px; + margin: 15px 15px 15px 0; + padding: 10px; + font-size: 13px; + text-align: justify; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + box-shadow: 0 0 20px black; + -moz-box-shadow: 0 0 20px black; + -webkit-box-shadow: 0 0 20px black; +} + +#home .right h1 { + font-size: 16px; + padding-bottom: 4px; + border-bottom: 1px black dotted; +} + +#home .right p { + margin-bottom: 4px; +} + +#home .right p a { + border-width: 0 0 1px 0; + border-style: dotted; + border-color: black; +} + +#home .right p a:hover, +#home .right p a:focus { + border-style: solid; + text-decoration: none; +} + +#home .right button { + display: block; + margin-left: 22px; + width: 342px; + height: 64px; + text-decoration: none; + font-weight: bold; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} + +#home .right button:hover { + cursor: pointer; +} + +#home .right button span { + float: left; +} + +#home .right button span.home-images { + height: 16px; + width: 16px; + margin: 5px 7px 7px 24px; +} + +#home .right button span.text { + padding-left: 20px; + font-size: 1.5em; +} + +#home .right .login { + background-color: #72d071; + background-position: 0 0; + border: 1px solid #5cb55c; + margin-top: 22px; + box-shadow: 0 0 10px #89e389; + -moz-box-shadow: 0 0 10px #89e389; + -webkit-box-shadow: 0 0 10px #89e389; +} + +#home .right .login:hover, +#home .right .login:focus { + border: 1px solid #419141; + box-shadow: 0 0 15px #72d071; + -moz-box-shadow: 0 0 15px #72d071; + -webkit-box-shadow: 0 0 15px #72d071; +} + +#home .right .login:active { + background-color: #97e896; + background-position: 0 -80px; +} + +#home .right .login span.text { + color: #2d612d; + text-shadow: 1px 1px 1px #5cb55c; +} + +#home .right .login span.home-images { + background-position: 0 -230px; +} + +#home .right .register { + background-color: #f6ef82; + background-position: 0 -160px; + border: 1px solid #e3db56; + margin-top: 15px; + box-shadow: 0 0 15px #f1e968; + -moz-box-shadow: 0 0 15px #f1e968; + -webkit-box-shadow: 0 0 15px #f1e968; +} + +#home .right .register:hover, +#home .right .register:focus { + border: 1px solid #d2c93f; + box-shadow: 0 0 15px #e0d743; + -moz-box-shadow: 0 0 15px #e0d743; + -webkit-box-shadow: 0 0 15px #e0d743; +} + +#home .right .register:active { + background-color: #fdf7af; + background-position: 0 -240px; +} + +#home .right .register span.text { + color: #6d6813; + text-shadow: 1px 1px 1px #dbd56e; +} + +#home .right .register span.home-images { + background-position: 0 -204px; +} + +#home .right p.notice { + margin-top: 24px; + font-size: 0.9em; +} + +#home .right .navigation { + clear: both; + width: 385px; + border-top: 1px black dotted; + position: absolute; + text-align: right; + bottom: 25px; + right: 25px; + padding-top: 6px; +} + +#home .right .navigation a { + margin-left: 9px; + color: black; + text-decoration: none; + font-size: 0.9em; + height: 12px; + padding: 0 0 4px 20px; + float: right; +} + +#home .right .navigation a:hover, +#home .right .navigation a:focus { + text-decoration: underline; +} + +#home .right .navigation a.unencrypted { + background-position: 0 -256px; +} + +#home .right .navigation a.encrypted { + background-position: 0 -282px; +} + +#home .right .navigation a.project { + background-position: 0 -126px; +} + +#home .right .navigation a.manager { + background-position: 0 -152px; +} + +#home .right .navigation a.mobile { + background-position: 0 -178px; +} + +#home a.advanced { + background-position: 0 -334px; + font-size: 0.9em; + height: 16px; + margin-bottom: 10px; + padding-left: 16px; + display: block; +} + +#home fieldset.advanced { + display: none; +} + +#home .anonymouser input[type=text] { + width: 160px; +} + +#home .homediv.registerer .success a { + font-weight: bold; + text-decoration: underline; +} + +#home fieldset { + border: 1px solid black; + margin: 12px 0 12px 0; + padding: 5px 0 4px 0; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#home legend { + font-size: 0.9em; + margin: 0 0 0 15px; + padding: 0 2px; + text-transform: uppercase; +} + +#home label { + width: 110px; + display: block; + float: left; + clear: both; + margin: 0 0 5px 12px; +} + +#home input, +#home select { + float: left; + margin-bottom: 5px; +} + +#home input[type=text], +#home input[type=password], +#home select { + width: 140px; + margin-top: -2px; +} + +#home input[type=submit] { + min-width: 120px; + float: right; +} + +#home span.jid { + display: block; + float: left; + margin: 0 4px; +} + +#home input.nick, #home input.server { + width: 110px; +} + +#home .info { + padding: 6px; + position: absolute; + bottom: 62px; + right: 35px; + border-width: 1px; + border-style: dotted; + clear: both; + width: 350px; +} + +#home .info.success { + background-color: #aee578; + border-color: #85b05c; + display: none; +} + +#home .info.fail { + background-color: #f19d9d; + border-color: #b34f4f; +} + +#home .info.report { + background-color: #f3f48b; + border-color: #c9c66b; + display: none; +} + +#home .info.report span { + text-decoration: underline; +} + +#home .notice.simple { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.7); + color: white; + font-size: 0.9em; + text-decoration: none; + text-shadow: 0 1px 0 black; + position: fixed; + bottom: 0; + left: 0; + right: 0; + padding: 8px 20px; + z-index: 100; + box-shadow: 0 0 25px #ababab; + -moz-box-shadow: 0 0 25px #ababab; + -webkit-box-shadow: 0 0 25px #ababab; +} + +#home .notice.simple .title { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.4); + background-position: 8px -299px; + border-width: 0 1px 1px 1px; + border-style: solid; + border-color: #141414; + font-weight: bold; + padding: 8px 8px 8px 30px; +} + +#home .notice.simple .text { + margin-left: 20px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/ie.css b/sources/extend/addon/matrix/jappixmini/jappix/css/ie.css new file mode 100644 index 00000000..8808b50b --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/ie.css @@ -0,0 +1,146 @@ +/* + +Jappix - An open social platform +These are all the IE compliant CSS classes + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 22/04/11 + +*/ + +/* rgba(255,255,255,0.9) */ +.search ul { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#edffffff,endColorstr=#edffffff); +} + +/* rgba(255,255,255,0.3) */ +a.finish:active, +#manager-buttons input:active, +#install-buttons input:active { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#49ffffff,endColorstr=#49ffffff); +} + +/* rgba(255,255,255,0.2) */ +a.finish:hover, +a.finish:focus, +#manager-buttons input:hover, +#manager-buttons input:focus, +#install-buttons input:hover, +#install-buttons input:focus, +.notifications-content .one-notification:active { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#33ffffff,endColorstr=#33ffffff); +} + +/* rgba(255,255,255,0.14) */ +#home .locale .list a:active { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#2fffffff,endColorstr=#2fffffff); +} + +/* rgba(255,255,255,0.1) */ +#home .locale .list a:hover, +#home .locale .list a:focus, +a.finish, +a.finish.disabled:hover, +a.finish.disabled:focus, +a.finish.disabled:active, +#manager-buttons input, +#install-buttons input, +.notifications-content .one-notification:hover, +.notifications-content .one-notification:focus { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#20ffffff,endColorstr=#20ffffff); +} + +/* rgba(255,239,104,0.8) */ +.popup .infos { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#deffef68,endColorstr=#deffef68); +} + +/* rgba(225,160,20,0.3) */ +.search ul li.hovered { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#46e1a014,endColorstr=#46e1a014); +} + +/* rgba(248,246,186,0.9) */ +#board .one-board.info { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#edf8f6ba,endColorstr=#edf8f6ba); +} + +/* rgba(241,160,160,0.9) */ +#board .one-board.error { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#edf1a0a0,endColorstr=#edf1a0a0); +} + +/* rgba(234,234,234,0.8) */ +#page-engine .chatstate { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#deeaeaea,endColorstr=#deeaeaea); +} + +/* rgba(20,20,20,0.6) */ +#home .locale, +#home .obsolete, +#home .notice.simple { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#a0141414,endColorstr=#a0141414); +} + +/* rgba(20,20,20,0.8) */ +#home .main, +#reconnect .pane, +#my-infos, +#right-content, +#buddy-list, +#manager, +#install { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#de141414,endColorstr=#de141414); +} + +/* rgba(20,20,20,0.9) */ +.popup { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#ed141414,endColorstr=#ed141414); +} + +/* rgba(0,0,0,0.2) */ +#install-top .step { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#33000000,endColorstr=#33000000); +} + +/* rgba(0,0,0,0.6) */ +.lock { + background: url(../img/others/lock.png) repeat !important; +} + +/* rgba(0,0,0,0.8) */ +#page-engine .tooltip-subitem, +.attach-subitem, +.buddy-infos-subitem, +.buddy-conf-subitem, +.tools-content-subitem { + background: transparent; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr=#de000000,endColorstr=#de000000); +} + +/* Fix a fieldset padding bug */ +legend { + margin-bottom: 5px !important; +} + +/* Fix an opacity bug */ +a.finish.disabled { + filter: alpha(opacity = 20) !important; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/images.css b/sources/extend/addon/matrix/jappixmini/jappix/css/images.css new file mode 100644 index 00000000..2dfb756f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/images.css @@ -0,0 +1,89 @@ +/* + +Jappix - An open social platform +This is the images CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/01/12 + +*/ + +.body-images { + background-image: url(../img/sprites/background.png); + background-repeat: repeat; + background-color: #93c5fa; +} + +.install-images { + background-image: url(../img/sprites/install.png); + background-repeat: no-repeat; +} + +.home-images { + background-image: url(../img/sprites/home.png); + background-repeat: no-repeat; +} + +.browsers-images { + background-image: url(../img/sprites/browsers.png); + background-repeat: no-repeat; +} + +.buttons-images { + background-image: url(../img/sprites/buttons.png); + background-repeat: repeat-x; +} + +.talk-images { + background-image: url(../img/sprites/talk.png); + background-repeat: no-repeat; +} + +.smileys-images { + background-image: url(../img/sprites/smileys.png); + background-repeat: no-repeat; +} + +.welcome-images { + background-image: url(../img/sprites/welcome.png); + background-repeat: no-repeat; +} + +.me-images { + background-image: url(../img/sprites/me.png); + background-repeat: no-repeat; +} + +.manager-images { + background-image: url(../img/sprites/manager.png); + background-repeat: no-repeat; +} + +.mobile-images { + background-image: url(../img/sprites/mobile.png); + background-repeat: no-repeat; +} + +.wait-small { + background-image: url(../img/wait/wait-small.gif); + background-repeat: no-repeat; + height: 16px; + width: 16px; +} + +.wait-medium { + background-image: url(../img/wait/wait-medium.png); + background-repeat: no-repeat; + height: 24px; + width: 24px; +} + +.wait-big { + background-image: url(../img/wait/wait-big.gif); + background-repeat: no-repeat; + height: 30px; + width: 30px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/inbox.css b/sources/extend/addon/matrix/jappixmini/jappix/css/inbox.css new file mode 100644 index 00000000..1ef05886 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/inbox.css @@ -0,0 +1,202 @@ +/* + +Jappix - An open social platform +This is the inbox CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 28/12/10 + +*/ + +#inbox .content { + padding: 10px 0 10px 0; +} + +#inbox .content p { + margin: 3px 10px; + text-align: justify; + font-size: 0.9em; +} + +#inbox .inbox-results { + height: 310px; + width: 620px; + margin: -5px 0 0 10px; + padding: 6px 0 0 0; + overflow: auto; +} + +#inbox .message-unread { + background-color: #E9F1FD; +} + +#inbox .one-message { + font-size: 0.9em; + border-bottom: 1px #b2c7cb solid; +} + +#inbox .message-head { + padding: 6px 0 7px 4px; + overflow: hidden; +} + +#inbox .message-head:hover { + background-color: #e9f1fd; + cursor: pointer; +} + +#inbox .message-head:active { + background-color: #f1f6fd; +} + +#inbox .one-message.message-reading, +#inbox .one-message.message-reading .message-head { + background-color: #f1f6fd; +} + +#inbox .avatar-container { + float: left; + width: 40px; + height: 40px; + margin-right: 7px; + text-align: center; + background-repeat: no-repeat; +} + +#inbox .avatar { + max-width: 40px; + max-height: 40px; +} + +#inbox .message-jid, +#inbox .message-subject { + float: left; + margin: 0 2px; + overflow: hidden; +} + +#inbox .message-jid { + width: 165px; + font-weight: bold; +} + +#inbox .message-subject { + width: 355px; +} + +#inbox .message-truncated { + color: #42646b; + font-size: 0.8em; + margin: 23px 0 0 49px; +} + +#inbox .message-body { + padding: 8px 5px 5px 5px; +} + +#inbox .message-body a { + text-decoration: underline; +} + +#inbox .message-meta { + margin-top: 6px; + padding: 3px 4px; + border-top: 1px #b2c7cb dotted; +} + +#inbox .message-meta span.date { + color: #28474e; + font-size: 0.8em; + margin: 10px 0 0 4px; + float: left; +} + +#inbox .message-meta a { + font-size: 0.98em; + margin: 5px; + float: right; + display: block; +} + +#inbox .inbox-noresults { + font-weight: bold; + display: none; +} + +#inbox .a-show-messages { + display: none; +} + +#inbox .inbox-new { + display: none; + height: 300px; + width: 620px; + margin: -5px 0 0 10px; + padding: 16px 0 0 0; +} + +#inbox .inbox-new-block { + border-top: 1px #686868 dotted; + padding-top: 9px; + min-height: 32px; + clear: both; +} + +#inbox .inbox-new-text { + float: left; + width: 100px; +} + +#inbox .inbox-new-textarea { + width: 460px; + height: 109px; + margin-bottom: 10px; + float: left; +} + +#inbox .inbox-new input { + float: left; +} + +#inbox .inbox-new-to ul { + width: 264px; + max-height: 168px; + font-size: 0.9em; + left: 120px; + top: 31px; +} + +#inbox .inbox-new-to-input { + width: 260px; +} + +#inbox .inbox-new-subject-input { + width: 380px; +} + +#inbox .inbox-new-file a { + display: block; + float: left; +} + +#inbox .inbox-new-file a.file { + font-size: 0.85em; + height: 16px; + max-width: 320px; + margin: 3px 0 15px 013px; + overflow: hidden; +} + +#inbox .inbox-new-file a.one-button { + font-size: 0.85em; + margin: -2px 0 0 25px; +} + +#inbox .inbox-new-send a { + font-size: 0.85em; + float: right; + display: block; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/install.css b/sources/extend/addon/matrix/jappixmini/jappix/css/install.css new file mode 100644 index 00000000..9dbde3fc --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/install.css @@ -0,0 +1,285 @@ +/* + +Jappix - An open social platform +This is the install CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 08/06/11 + +*/ + +body { + color: white; +} + +#install { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + width: 800px; + margin: 35px auto; + padding-bottom: 17px; + border-radius: 6px; + -moz-border-radius: 6px; + -webkit-border-radius: 6px; + box-shadow: 0 0 35px #5c5c5c; + -moz-box-shadow: 0 0 35px #5c5c5c; + -webkit-box-shadow: 0 0 35px #5c5c5c; +} + +#install a { + color: black; + text-decoration: underline; +} + +#install .clear { + clear: both; +} + +#install fieldset { + border: 1px solid black; + margin: 22px 0 15px 0; + padding: 7px 2px 5px 2px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#install legend { + font-size: 0.9em; + margin: 0 0 0 15px; + padding: 0 2px; + text-transform: uppercase; +} + +#install label { + width: 200px; + display: block; + float: left; + clear: both; + margin: 0 0 9px 12px; +} + +#install input { + float: left; + margin-bottom: 5px; +} + +#install input[type=text], +#install input[type=url], +#install input[type=password] { + margin-top: -2px; + padding: 3px; + font-size: 0.95em; + min-width: 220px; +} + +#install input.icon { + padding-left: 24px; + min-width: 199px; + max-height: 18px; +} + +#install input.icon#user_name { + background-position: 4px -204px; +} + +#install input.icon#user_password { + background-position: 4px -226px; +} + +#install input.icon#user_repassword { + background-position: 4px -248px; +} + +#install-top { + padding: 30px 45px; +} + +#install-top .logo { + background-position: 0 0; + min-width: 88px; + height: 36px; + padding: 32px 0 0 66px; + font-size: 32px; + color: white; + text-transform: lowercase; + float: left; + text-shadow: 0 1px 1px black; +} + +#install-top .step { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.2); + border: 2px solid white; + padding: 6px 21px; + font-size: 2.7em; + text-shadow: 0 1px 1px black; + float: right; + border-radius: 40px; + -moz-border-radius: 40px; + -webkit-border-radius: 40px; + box-shadow: 0 0 10px #202020; + -moz-box-shadow: 0 0 10px #202020; + -webkit-box-shadow: 0 0 10px #202020; +} + +#install-top .step span { + font-size: 0.6em; +} + +#install-content { + background: #e4eef9; + background: -moz-linear-gradient(top, #e4eef9, #d0e5fa); + background: -webkit-gradient(linear, left top, left bottom, from(#e4eef9), to(#d0e5fa)); + color: black; + font-size: 0.9em; + margin: 0 10px; + padding: 20px 24px; + min-height: 260px; + clear: both; + right: 10px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 20px #202020; + -moz-box-shadow: 0 0 20px #202020; + -webkit-box-shadow: 0 0 20px #202020; +} + +#install-content h3 { + padding-left: 24px; + margin-bottom: 15px; +} + +#install-content h3.start { + background-position: 0 -73px; +} + +#install-content h3.storage { + background-position: 0 -95px; +} + +#install-content h3.account { + background-position: 0 -117px; +} + +#install-content h3.main { + background-position: 0 -139px; +} + +#install-content h3.hosts { + background-position: 0 -161px; +} + +#install-content h3.services { + background-position: 0 -183px; +} + +#install-content p { + margin-bottom: 10px; +} + +#install-content .info { + color: black; + border-width: 1px; + border-style: dashed; + padding: 6px 8px; + display: block; + text-decoration: none; +} + +#install-content .info.smallspace { + margin: 14px 0 10px 0; +} + +#install-content .info.bigspace { + margin: 35px 0 20px 0; +} + +#install-content .info.first { + margin-top: 28px; +} + +#install-content .info.last { + margin-bottom: 28px; +} + +#install-content .info.neutral { + background-color: #f0f19d; + border-color: #b3ad4f; +} + +#install-content a.info.neutral:hover, +#install-content a.info.neutral:focus { + background-color: #eced96; +} + +#install-content a.info.neutral:active { + background-color: #e9ea93; +} + +#install-content .info.success { + background-color: #a8dca9; + border-color: #5e9f5f; +} + +#install-content a.info.success:hover, +#install-content a.info.success:focus { + background-color: #a0d5a1; +} + +#install-content a.info.success:active { + background-color: #9ad09b; +} + +#install-content .info.fail { + background-color: #f19d9d; + border-color: #b34f4f; +} + +#install-content ol { + margin: 20px 30px; +} + +#install-content ol li { + margin-bottom: 1px; +} + +#install-buttons { + margin-top: 22px; +} + +#install-buttons input { + border: 1px solid white; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); + color: white; + padding: 4px 8px; + margin-right: 20px; + text-shadow: 0 1px 1px black; + float: right; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 5px #202020; + -moz-box-shadow: 0 0 5px #202020; + -webkit-box-shadow: 0 0 5px #202020; +} + +#install-buttons input:hover, +#install-buttons input:focus { + cursor: pointer; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.2); + box-shadow: 0 0 15px #202020; + -moz-box-shadow: 0 0 15px #202020; + -webkit-box-shadow: 0 0 15px #202020; +} + +#install-buttons input:active { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.3); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/integratebox.css b/sources/extend/addon/matrix/jappixmini/jappix/css/integratebox.css new file mode 100644 index 00000000..b5cb9c9f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/integratebox.css @@ -0,0 +1,34 @@ +/* + +Jappix - An open social platform +This is the integratebox CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 06/11/10 + +*/ + +#integratebox .top { + height: 40px; +} + +#integratebox .content { + text-align: center; + height: 385px; +} + +#integratebox .one-media img { + max-height: 385px; + max-width: 640px; +} + +#integratebox .one-media a img { + border: none; +} + +#integratebox .one-media audio { + margin-top: 170px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/jquery.datepicker.css b/sources/extend/addon/matrix/jappixmini/jappix/css/jquery.datepicker.css new file mode 100644 index 00000000..264cd544 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/jquery.datepicker.css @@ -0,0 +1,148 @@ +/* + +Jappix - An open social platform +This is the datepicker CSS stylesheet + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 28/12/10 + +*/ + +div.datepicker { + position: relative; + font-family: Arial, Helvetica, sans-serif; + font-size: 12px; + width: 196px; + height: 147px; + position: absolute; + cursor: default; + top: 0; + left: 0; + display: none; +} + +.datepickerHidden { + display: none; +} + +div.datepicker table { + border-collapse:collapse; +} + +div.datepicker a { + text-decoration: none; + cursor: default; + outline: none; +} + +div.datepicker table td { + text-align: right; + padding: 0; + margin: 0; +} + +div.datepicker th { + text-align: center; + color: #47646a; + font-weight: normal; +} + +div.datepicker tbody th { + text-align: left; +} + +div.datepicker tbody a { + display: block; +} + +.datepickerDays a { + width: 20px; + line-height: 16px; + height: 16px; + padding-right: 2px; +} + +.datepickerYears a, +.datepickerMonths a { + width: 44px; + line-height: 36px; + height: 36px; + text-align: center; +} + +td.datepickerNotInMonth { + background: #c7d1d4; +} + +tbody.datepickerDays td.datepickerSelected { + background: #b0bdc1; +} + +tbody.datepickerYears td.datepickerSelected, +tbody.datepickerMonths td.datepickerSelected { + background: #9daaae; +} + +div.datepicker a:hover, +div.datepicker a:focus { + color: #3d7682; +} + +div.datepicker tbody th { + text-align: left; +} + +.datepickerSpace div { + width: 20px; +} + +.datepickerGoNext a, +.datepickerGoPrev a, +.datepickerMonth a { + text-align: center; + height: 20px; + line-height: 20px; +} + +.datepickerGoNext a { + float: right; + width: 20px; +} + +.datepickerGoPrev a { + float: left; + width: 20px; +} + +table.datepickerViewDays tbody.datepickerMonths, +table.datepickerViewDays tbody.datepickerYears { + display: none; +} + +table.datepickerViewMonths tbody.datepickerDays, +table.datepickerViewMonths tbody.datepickerYears, +table.datepickerViewMonths tr.datepickerDoW { + display: none; +} + +table.datepickerViewYears tbody.datepickerDays, +table.datepickerViewYears tbody.datepickerMonths, +table.datepickerViewYears tr.datepickerDoW { + display: none; +} + +td.datepickerDisabled a, +td.datepickerDisabled.datepickerNotInMonth a { + color: #333; +} + +td.datepickerSpecial a { + background: #700; +} + +td.datepickerSpecial.datepickerSelected a { + background: #a00; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/main.css b/sources/extend/addon/matrix/jappixmini/jappix/css/main.css new file mode 100644 index 00000000..68254814 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/main.css @@ -0,0 +1,131 @@ +/* + +Jappix - An open social platform +This is the main CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 05/10/11 + +*/ + +* { + margin: 0; + padding: 0; +} + +body { + font: normal 14.4px Helvetica, Verdana, sans-serif; + text-shadow: 0 0 5px white; +} + +h1 { + margin-bottom: 15px; +} + +a { + text-decoration: none; + color: black; + outline-style: none; +} + +a:hover, +a:focus { + cursor: pointer; + text-decoration: underline; +} + +legend { + color: black; +} + +input, +textarea { + background-color: white; + border: 1px solid #636363; + font-size: 0.95em; + padding: 2px; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; + box-shadow: inset 0 3px 10px #dcdcdc; + -moz-box-shadow: inset 0 3px 10px #dcdcdc; + -webkit-box-shadow: inset 0 3px 10px #dcdcdc; +} + +textarea { + font-size: 1.1em; +} + +input:focus, +input[type=submit]:hover, +input[type=reset]:hover, +textarea:focus { + border: 1px solid #e1a014; + box-shadow: inset 0 3px 10px #edd9bc; + -moz-box-shadow: inset 0 3px 10px #edd9bc; + -webkit-box-shadow: inset 0 3px 10px #edd9bc; +} + +input[type=submit], +input[type=reset] { + cursor: pointer; +} + +input[type=submit]:active, +input[type=reset]:active { + box-shadow: inset 0 3px 15px #e1a753; + -moz-box-shadow: inset 0 3px 15px #e1a753; + -webkit-box-shadow: inset 0 3px 15px #e1a753; +} + +input[disabled], +textarea[disabled] { + background-color: #f3f3f3; + border: 1px solid #989898; +} + +input:placeholder { + color: #67787c !important; +} + +input:-moz-placeholder { + color: #67787c !important; +} + +input::-webkit-input-placeholder { + color: #67787c !important; +} + +input.placeholder { + color: #67787c !important; +} + +input[type=checkbox] { + margin-top: 2px; +} + +input[type=checkbox], +input[type=radio] { + background: transparent none !important; + border: 0 none !important; +} + +.please-complete, +.please-complete:hover, +.please-complete:focus { + border: 1px #ac2525 solid !important; + box-shadow: inset 0 3px 10px #f39c9c !important; + -moz-box-shadow: inset 0 3px 10px #f39c9c !important; + -webkit-box-shadow: inset 0 3px 10px #f39c9c !important; +} + +.hidden { + display: none !important; +} + +.clear { + clear: both !important; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/manager.css b/sources/extend/addon/matrix/jappixmini/jappix/css/manager.css new file mode 100644 index 00000000..c1dd358c --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/manager.css @@ -0,0 +1,543 @@ +/* + +Jappix - An open social platform +This is the manager CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 31/08/11 + +*/ + +#manager { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + width: 945px; + margin: 0 auto 25px; + padding-bottom: 17px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + box-shadow: 0 0 35px #5c5c5c; + -moz-box-shadow: 0 0 35px #5c5c5c; + -webkit-box-shadow: 0 0 35px #5c5c5c; +} + +#manager a { + color: black; + text-decoration: underline; +} + +#manager .clear { + clear: both; +} + +#manager fieldset { + border: 1px solid black; + margin: 22px 0 15px 0; + padding: 7px 2px 5px 2px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#manager legend { + font-size: 0.9em; + margin: 0 0 0 15px; + padding: 0 2px; + text-transform: uppercase; +} + +#manager label { + width: 200px; + display: block; + float: left; + clear: both; + margin: 0 0 9px 12px; +} + +#manager label.master { + text-decoration: underline; +} + +#manager input, +#manager select { + float: left; + margin-bottom: 5px; +} + +#manager input[type=radio] { + margin: 2px 8px 5px 0; +} + +#manager input[type=text], +#manager input[type=url], +#manager input[type=password], +#manager select { + margin-top: -2px; + font-size: 0.95em; +} + +#manager input[type=text], +#manager input[type=url], +#manager input[type=password] { + padding: 3px; + min-width: 220px; +} + +#manager input.icon { + padding-left: 24px; + min-width: 199px; + max-height: 18px; +} + +#manager input.icon#admin_name { + background-position: 4px -510px; +} + +#manager input.icon#admin_password, +#manager input.icon#user_repassword { + background-position: 4px -532px; +} + +#manager input.icon#user_name, +#manager input.icon#music_artist { + background-position: 4px -554px; +} + +#manager input.icon#user_password { + background-position: 4px -576px; +} + +#manager input.icon#music_title { + background-position: 4px -598px; +} + +#manager input.icon#music_album { + background-position: 4px -620px; +} + +#manager input.icon#background_image_color, +#manager input.icon#background_color_color { + background-position: 4px -641px; +} + +#manager select { + min-width: 160px; + max-width: 230px; +} + +#manager-top { + padding: 25px 45px 30px; +} + +#manager-top .logo { + background-position: 0 0; + min-width: 89px; + height: 40px; + padding: 28px 0 0 65px; + font-size: 32px; + color: white; + text-transform: lowercase; + float: left; + text-shadow: 0 1px 1px black; +} + +#manager-top .meta { + background-color: #e0eaec; + font-size: 0.9em; + padding: 12px 7px 12px 14px; + float: right; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 10px #202020; + -moz-box-shadow: 0 0 10px #202020; + -webkit-box-shadow: 0 0 10px #202020; +} + +#manager-top .meta span { + margin-right: 10px; + color: black; +} + +#manager-top .meta a { + background-color: #f1f6fd; + border: 1px solid #b9cbcf; + color: #224249; + padding: 4px 8px 4px 21px; + margin-left: 2px; + text-decoration: none; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#manager-top .meta a:hover, +#manager-top .meta a:focus { + border: 1px solid #95b1b7; +} + +#manager-top .meta a:active { + border: 1px solid #77989f; +} + +#manager-top .meta a.logout { + background-position: 3px -69px; +} + +#manager-top .meta a.close { + background-position: 3px -90px; +} + +#manager-tabs { + margin-left: 12px; +} + +#manager-tabs a { + background-color: #d9e7ea; + color: #204249; + width: 107px; + height: 17px; + padding: 4px 4px 4px 16px; + margin-left: 4px; + font-size: 0.94em; + text-decoration: none; + overflow: hidden; + float: left; + border-top-right-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-top-left-radius: 3px; +} + +#manager-tabs a:hover, +#manager-tabs a:focus { + background-color: #cedee1; + text-decoration: none; +} + +#manager-tabs a:active { + background-color: #c3d3d7; + text-decoration: none; +} + +#manager-tabs a.tab-active { + background-color: #e4eef9 !important; +} + +#manager-content { + background: #e4eef9; + background: -moz-linear-gradient(top, #e4eef9, #d0e5fa); + background: -webkit-gradient(linear, left top, left bottom, from(#e4eef9), to(#d0e5fa)); + color: black; + font-size: 0.9em; + margin: 0 10px; + padding: 20px 24px; + min-height: 260px; + clear: both; + right: 10px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 20px #202020; + -moz-box-shadow: 0 0 20px #202020; + -webkit-box-shadow: 0 0 20px #202020; +} + +#manager-content h3 { + padding-left: 24px; + margin-bottom: 15px; +} + +#manager-content h3.login { + background-position: 0 -466px; +} + +#manager-content h3.statistics { + background-position: 0 -203px; +} + +#manager-content h3.configuration { + background-position: 0 -224px; +} + +#manager-content h3.hosts { + background-position: 0 -246px; +} + +#manager-content h3.storage { + background-position: 0 -268px; +} + +#manager-content h3.design { + background-position: 0 -290px; +} + +#manager-content h3.users { + background-position: 0 -312px; +} + +#manager-content h3.updates { + background-position: 0 -334px; +} + +#manager-content h4 { + border-top: 1px dotted black; + padding-top: 5px; + margin: 20px 0 14px; + clear: both; +} + +#manager-content ul, +#manager-content ol { + width: 380px; + margin: 8px 0 20px 18px; +} + +#manager-content li { + margin-bottom: 3px; +} + +#manager-content li.total { + margin-bottom: 14px; +} + +#manager-content li b { + width: 190px; + float: left; +} + +#manager-content li span { + margin-left: 10px; + float: left; +} + +#manager-content ul.stats, +#manager-content ol.stats { + float: left; +} + +#manager-content object.stats { + border: 1px dotted #bed4d9; + width: 450px; + height: 270px; + margin-bottom: 20px; + float: right; +} + +#manager-content p, +#manager-content div { + margin-bottom: 10px; +} + +#manager-content .info { + color: black; + border-width: 1px; + border-style: dashed; + padding: 6px 8px; + display: block; + text-decoration: none; +} + +#manager-content .info.bottomspace { + margin-bottom: 16px; +} + +#manager-content .info.smallspace { + margin: 14px 0 10px 0; +} + +#manager-content .info.bigspace { + margin: 35px 0 20px 0; +} + +#manager-content .info.neutral { + background-color: #f0f19d; + border-color: #b3ad4f; +} + +#manager-content a.info.neutral:hover, +#manager-content a.info.neutral:focus { + background-color: #eced96; +} + +#manager-content a.info.neutral:active { + background-color: #e9ea93; +} + +#manager-content .info.success { + background-color: #a8dca9; + border-color: #5e9f5f; +} + +#manager-content a.info.success:hover, +#manager-content a.info.success:focus { + background-color: #a0d5a1; +} + +#manager-content a.info.success:active { + background-color: #9ad09b; +} + +#manager-content .info.fail { + background-color: #f19d9d; + border-color: #b34f4f; +} + +#manager-content a.info.fail:hover, +#manager-content a.info.fail:focus { + background-color: #ea9595; +} + +#manager-content a.info.fail:active { + background-color: #e59090; +} + +#manager-content .browse { + margin: 2px 0 6px; + max-height: 243px; + overflow: auto; +} + +#manager-content .browse .one-browse { + padding: 5px 10px 5px 34px; + height: 17px; +} + +#manager-content .browse .user { + background-position: 9px -111px; +} + +#manager-content .browse .other { + background-position: 9px -133px; +} + +#manager-content .browse .folder { + background-position: 9px -178px; +} + +#manager-content .browse .audio { + background-position: 9px -154px; +} + +#manager-content .browse .alert { + background-position: 9px -353px; +} + +#manager-content .browse .image { + background-position: 9px -374px; +} + +#manager-content .browse .video { + background-position: 9px -397px; +} + +#manager-content .browse .document { + background-position: 9px -418px; +} + +#manager-content .browse .package { + background-position: 9px -441px; +} + +#manager-content .browse .previous { + background-position: 9px -485px; + margin-bottom: 4px; +} + +#manager-content .browse div { + margin: 0; +} + +#manager-content .browse input { + float: right; + margin: 1px 0; +} + +#manager-content .browse .odd { + background-color: #e9f1fd; +} + +#manager-content .browse .even { + background-color: #f1f6fd; +} + +#manager-content .sub { + border-left: 1px solid black; + margin: 5px 0 20px 22px; + padding-left: 12px; + clear: both; +} + +#manager span.logo_links a { + width: 16px; + height: 16px; + margin-right: 6px; + float: left; +} + +#manager span.logo_links a.remove { + background-position: 0 -688px; +} + +#manager span.logo_links a.view { + background-position: 0 -666px; +} + +#manager-content .clear { + margin: 0; +} + +#manager-content textarea.notice-text { + height: 70px; + width: 600px; + margin-left: 4px; + padding: 5px; + font-size: 1.2em; +} + +#manager-buttons { + margin-top: 22px; +} + +#manager-buttons input { + border: 1px solid white; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); + color: white; + padding: 4px 8px; + margin-left: -12px; + margin-right: 20px; + font-size: 1em; + text-shadow: 0 1px 1px black; + float: right; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 5px #202020; + -moz-box-shadow: 0 0 5px #202020; + -webkit-box-shadow: 0 0 5px #202020; +} + +#manager-buttons input:hover, +#manager-buttons input:focus { + cursor: pointer; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.2); + box-shadow: 0 0 15px #202020; + -moz-box-shadow: 0 0 15px #202020; + -webkit-box-shadow: 0 0 15px #202020; +} + +#manager-buttons input:active { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.3); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/me.css b/sources/extend/addon/matrix/jappixmini/jappix/css/me.css new file mode 100644 index 00000000..2ff74fbd --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/me.css @@ -0,0 +1,49 @@ +/* + +Jappix - An open social platform +This is the Jappix Me tool CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/01/12 + +*/ + +#me .content { + padding: 10px 0; +} + +#me .logo { + background-position: 0 0; + width: 300px; + height: 61px; + margin: 20px auto 0 auto; + display: block; +} + +#me .infos { + margin-top: 30px; +} + +#me .infos p { + margin-top: 8px; +} + +#me .infos p.infos-title { + margin-top: 0; +} + +#me .infos a { + text-decoration: underline; +} + +#me a.go { + text-align: center; + font-weight: bold; + width: 300px; + margin: 30px auto 0 auto; + padding: 8px 12px; + display: block; +} \ No newline at end of file diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/mini-ie.css b/sources/extend/addon/matrix/jappixmini/jappix/css/mini-ie.css new file mode 100644 index 00000000..d8f4b908 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/mini-ie.css @@ -0,0 +1,73 @@ +/* + +Jappix - An open social platform +This is the Jappix Mini legacy IE CSS stylesheet + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 20/03/11 + +*/ + +#jappix_mini { + width: expression(document.documentElement.clientWidth - 150 + 'px') !important; + position: absolute !important; + bottom: auto !important; + right: auto !important; + top: expression(((document.documentElement.clientHeight - this.offsetHeight) + (ignoreMiniTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)) + 'px') !important; + left: expression((150 + this.offsetWidth - (document.documentElement.clientWidth ? document.documentElement.clientWidth : document.body.clientWidth) + (ignoreMiniLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft)) + 'px') !important; +} + +#jappix_mini .jm_images { + background-image: url(../img/sprites/mini.gif) !important; +} + +#jappix_mini .jm_images_animate { + background-image: url(../img/sprites/animate.gif) !important; +} + +#jappix_mini a.jm_button { + width: 1px !important; +} + +#jappix_mini div.jm_roster { + right: -1px !important; + bottom: 23px !important; +} + +#jappix_mini div.jm_roster div.jm_buddies { + height: expression(this.scrollHeight > (document.documentElement.clientHeight - 70) ? (document.documentElement.clientHeight - 70) + 'px' : 'auto') !important; +} + +#jappix_mini a.jm_pane { + height: 12px !important; + overflow-y: hidden !important; +} + +#jappix_mini a.jm_button.jm_clicked { + background-image: none !important; +} + +#jappix_mini div.jm_conversations a.jm_clicked { + border-right: none !important; + padding: 7px 6px 6px 6px !important; +} + +#jappix_mini div.jm_chat-content { + bottom: 23px !important; + right: -2px !important; +} + +#jappix_popup { + height: expression(document.documentElement.clientHeight + 'px') !important; + width: expression(document.documentElement.clientWidth + 'px') !important; + position: absolute !important; + top: expression(((ignorePopupTop = document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop)) + 'px') !important; + left: expression(((ignorePopupLeft = document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft)) + 'px') !important; +} + +#jappix_popup div.jm_prompt { + position: absolute !important; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/mini.css b/sources/extend/addon/matrix/jappixmini/jappix/css/mini.css new file mode 100644 index 00000000..7ad6058b --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/mini.css @@ -0,0 +1,540 @@ +/* + +Jappix - An open social platform +This is the Jappix Mini CSS stylesheet + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, Julien +Last revision: 16/01/12 + +*/ + +#jappix_mini, +#jappix_popup { + font: normal 11px helvetica, "Lucida Grande", "Lucida Sans", "Lucida Sans Unicode", Arial, sans-serif; +} + +#jappix_mini { + margin-left: 130px; + position: fixed; + bottom: 0; + right: 20px; + z-index: 999; +} + +#jappix_mini *, +#jappix_popup * { + border: none; + color: black; + width: auto; + height: auto; + margin: 0; + padding: 0; + overflow: visible; + font-size: 11px; + text-align: left; + text-transform: none; + text-shadow: none; + opacity: 1.0; + border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; + box-shadow: none; + -moz-box-shadow: none; + -webkit-box-shadow: none; +} + +#jappix_mini .jm_images { + background-image: url(../img/sprites/mini.png); + background-repeat: no-repeat; +} + +#jappix_mini .jm_images_animate { + background-image: url(../img/sprites/animate.png); + background-repeat: no-repeat; +} + +#jappix_mini a { + text-decoration: none; + cursor: pointer; +} + +#jappix_mini a:hover { + cursor: pointer; +} + +#jappix_mini div.jm_position { + float: right; +} + +#jappix_mini a.jm_pane { + background-color: #f4f4f4; + background-position: 0 -100px; + background-repeat: repeat-x; + border-color: #999999; + border-style: solid; + border-width: 1px 1px 0 1px; + font-weight: bold; + outline-style: none; + display: block; + padding: 6px; + height: 24px; +} + +#jappix_mini a.jm_pane:hover { + background: white; +} + +#jappix_mini a.jm_pane:hover, +#jappix_mini a.jm_pane:focus { + border-color: #666666; +} + +#jappix_mini div.jm_starter, +#jappix_mini div.jm_conversations, +#jappix_mini div.jm_conversation { + float: left; + position: relative; +} + +#jappix_mini div.jm_conversation { + width: 153px; +} + +#jappix_mini a.jm_chat-tab { + border-width: 1px 0 0 1px; + width: 140px; + float: right; + overflow: hidden; +} + +#jappix_mini a.jm_chat-tab.jm_clicked { + background: white; + position: relative; + border-top: none; + border-left: 1px solid #999999; + padding-top: 7px; +} + +#jappix_mini a.jm_chat-tab span.jm_notify { + position: absolute; + top: 6px; + right: 9px; +} + +#jappix_mini a.jm_chat-tab span.jm_notify span { + float: left; +} + +#jappix_mini a.jm_chat-tab span.jm_notify span.jm_notify_left { + background-position: 0 -360px; +} + +#jappix_mini a.jm_chat-tab span.jm_notify span.jm_notify_right { + background-position: -7px -360px; +} + +#jappix_mini a.jm_chat-tab span.jm_notify span.jm_notify_left, +#jappix_mini a.jm_chat-tab span.jm_notify span.jm_notify_right { + height: 16px; + width: 7px; +} + +#jappix_mini a.jm_chat-tab span.jm_notify span.jm_notify_middle { + background-color: #c60505; + color: white; + font-size: 0.85em; + height: 14px; + padding-top: 2px; +} + +#jappix_mini div.jm_conversation.jm_type_groupchat span.jm_name { + margin-left: 4px; +} + +#jappix_mini div.jm_chat-content { + background-color: white; + border: 1px solid #999999; + height: 300px; + width: 260px; + position: absolute; + right: -1px; + bottom: 25px; + display: none; +} + +#jappix_mini div.jm_actions { + background-color: #565d5e; + border-bottom: 1px solid #3a3a3a; + height: 24px; + padding: 4px 6px; + font-weight: bold; + overflow: hidden; +} + +#jappix_mini div.jm_actions span.jm_nick { + color: white; + height: 16px; + width: 225px; + overflow: hidden; + float: left; +} + +#jappix_mini div.jm_actions a.jm_one-action { + background-color: #727879; + margin: 0 -2px 0 5px; + height: 15px; + width: 15px; + outline-style: none; + float: right; +} + +#jappix_mini div.jm_actions a.jm_one-action:hover, +#jappix_mini div.jm_actions a.jm_one-action:focus { + background-color: #7f8788; +} + +#jappix_mini div.jm_actions a.jm_one-action:active { + background-color: #8c9293; +} + +#jappix_mini div.jm_actions a.jm_logo { + background-position: 7px 2px; + width: 81px; + height: 22px; + margin: -4px 0 0 -2px; + outline-style: none; + float: left; +} + +#jappix_mini div.jm_actions a.jm_logo:hover, +#jappix_mini div.jm_actions a.jm_logo:focus { + background-color: #636a6b; +} + +#jappix_mini div.jm_actions a.jm_logo:active { + background-color: #707677; +} + +#jappix_mini div.jm_actions a.jm_close { + background-position: 1px -341px; +} + +#jappix_mini div.jm_actions a.jm_join { + background-position: 0 -327px; +} + +#jappix_mini div.jm_received-messages { + background-color: white; + padding: 5px 0 4px; + height: 242px; + overflow: auto; +} + +#jappix_mini div.jm_received-messages p { + margin: 3px 0; + word-wrap: break-word; +} + +#jappix_mini div.jm_received-messages p, +#jappix_mini div.jm_received-messages a { + color: black !important; +} + +#jappix_mini div.jm_received-messages div.jm_group { + margin: 2px 6px 9px 6px; + padding-bottom: 8px; + border-bottom: 1px solid #eaeaea; +} + +#jappix_mini div.jm_received-messages div.jm_system-message p, +#jappix_mini div.jm_received-messages div.jm_system-message a { + color: #053805 !important; + font-style: italic !important; +} + +#jappix_mini div.jm_received-messages p a { + text-decoration: underline; +} + +#jappix_mini div.jm_received-messages b { + margin-bottom: 3px; + display: block; +} + +#jappix_mini div.jm_received-messages b.jm_me { + color: #123a5c; +} + +#jappix_mini div.jm_received-messages b.jm_him { + color: #801e1e; +} + +#jappix_mini div.jm_received-messages span.jm_date { + font-size: 0.8em; + float: right; + display: none; +} + +#jappix_mini div.jm_received-messages div.jm_group:hover span.jm_date { + display: block; +} + +#jappix_mini input.jm_send-messages { + background-color: white; + border-color: #999999; + border-style: solid; + border-width: 1px 0 0 0; + padding: 5px; + width: 250px; + min-height: 14px; +} + +#jappix_mini div.jm_disabled div.jm_chat-content, +#jappix_mini div.jm_disabled input.jm_send-messages, +#jappix_mini div.jm_disabled a.jm_pane { + background: #f3f3f3 !important; +} + +#jappix_mini div.jm_disabled input.jm_send-messages { + color: #9d9d9d; +} + +#jappix_mini div.jm_roster { + background-color: white; + border: 1px solid #999999; + width: 160px; + position: absolute; + right: 0; + bottom: 25px; + display: none; +} + +#jappix_mini div.jm_roster div.jm_buddies { + width: 100%; + max-height: 300px; + padding: 5px 0; + overflow: auto; +} + +#jappix_mini div.jm_roster div.jm_grouped { + margin: 2px 0; +} + +#jappix_mini div.jm_roster div.jm_grouped div.jm_name { + margin-bottom: 2px; + padding: 4px 8px 0; + font-weight: bold; +} + +#jappix_mini a.jm_friend { + border-color: white; + border-style: solid; + border-width: 1px 0; + outline-style: none; + padding: 6px; + display: block; +} + +#jappix_mini a.jm_friend.jm_offline { + display: none; +} + +#jappix_mini a.jm_friend:hover, +#jappix_mini a.jm_friend:focus { + background-color: #888888; + border-color: #494949; + color: white; +} + +#jappix_mini a.jm_friend:hover span.jm_presence, +#jappix_mini a.jm_friend:focus span.jm_presence { + background-position: 0 -84px; +} + +#jappix_mini a.jm_button { + padding: 6px 10px; + position: relative; + z-index: 1; +} + +#jappix_mini a.jm_button.jm_clicked { + background: white; + border-top: none; + border-left: 1px solid #999999; + border-right: 1px solid #999999; + padding: 7px 10px 6px 10px; +} + +#jappix_mini span.jm_animate { + background-position: 0 0; + width: 111px; + height: 102px; + position: absolute; + top: -100px; + left: -74px; + z-index: 1; + display: block; +} + +#jappix_mini span.jm_counter { + background-position: 0 -288px; + color: #333333; + height: 16px; + padding-left: 25px; + display: block; +} + +#jappix_mini span.jm_counter.jm_error { + background-position: 0 -305px; +} + +#jappix_mini span.jm_presence { + display: block; + height: 16px; + width: 16px; + margin-right: 4px; + float: left; +} + +#jappix_mini span.jm_name { + color: #272727; + height: 14px; + width: 105px; + overflow: hidden; + float: left; +} + +#jappix_mini .jm_available, +#jappix_mini .jm_chat { + background-position: 0 -20px; +} + +#jappix_mini .jm_away { + background-position: 0 -36px; +} + +#jappix_mini .jm_xa, +#jappix_mini .jm_dnd { + background-position: 0 -52px; +} + +#jappix_mini .jm_unavailable { + background-position: 0 -68px; +} + +#jappix_mini .jm_smiley { + border: 0 none; + height: 16px; + width: 16px; + vertical-align: bottom; +} + +#jappix_mini .jm_smiley-wink { + background-position: 0 -148px; +} + +#jappix_mini .jm_smiley-waii { + background-position: 0 -164px; +} + +#jappix_mini .jm_smiley-unhappy { + background-position: 0 -180px; +} + +#jappix_mini .jm_smiley-tongue { + background-position: 0 -196px; +} + +#jappix_mini .jm_smiley-surprised { + background-position: 0 -212px; +} + +#jappix_mini .jm_smiley-smile { + background-position: 0 -228px; +} + +#jappix_mini .jm_smiley-happy { + background-position: 0 -244px; +} + +#jappix_mini .jm_smiley-grin { + background-position: 0 -260px; +} + +#jappix_popup { + background: url(../img/others/blank.gif) repeat; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; + z-index: 999; +} + +#jappix_popup div.jm_prompt { + background-color: #565d5e; + border: 1px solid #3a3a3a; + width: 346px; + position: fixed; + top: 50%; + left: 50%; + margin-left: -175px; + padding: 16px 2px 2px 2px; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; + box-shadow: 0 0 35px #232323; + -moz-box-shadow: 0 0 35px #232323; + -webkit-box-shadow: 0 0 35px #232323; +} + +#jappix_popup div.jm_prompt form { + background-color: white; + border: 1px solid #3a3a3a; + width: 332px; + padding: 6px; +} + +#jappix_popup div.jm_prompt form input { + background-color: #f9f9f9; + border: 1px solid #666666; + font-size: 1.1em; + padding: 1px 2px; +} + +#jappix_popup div.jm_prompt form input:hover, +#jappix_popup div.jm_prompt form input:focus { + border: 1px solid #202020; +} + +#jappix_popup div.jm_prompt form input.jm_text { + width: 326px; + margin: 6px 0; + display: block; +} + +#jappix_popup div.jm_prompt form input.jm_submit { + text-align: center; + margin-left: 3px; + float: right; +} + +#jappix_popup div.jm_prompt form input.jm_submit:hover, +#jappix_popup div.jm_prompt form input.jm_submit:focus { + background-color: #f3f3f3; + cursor: pointer; +} + +#jappix_popup div.jm_prompt form input.jm_submit:active { + background-color: #e8e8e8; +} + +#jappix_popup div.jm_prompt div.jm_clear { + clear: both; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/mobile.css b/sources/extend/addon/matrix/jappixmini/jappix/css/mobile.css new file mode 100644 index 00000000..ed44cc03 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/mobile.css @@ -0,0 +1,288 @@ +/* + +Jappix - An open social platform +This is the Jappix Mobile CSS stylesheet + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 05/10/11 + +*/ + +/* BEGIN GENERAL STYLE */ + +* { + margin: 0; + padding: 0; +} + +body { + font: normal 14.4px Helvetica, Verdana, sans-serif; + background-color: #dcdcdc; + margin: 0 auto; + text-align: center; + min-width: 200px; + min-height: 260px; +} + +a { + color: black; +} + +/* END GENERAL STYLE */ + +/* BEGIN HEADER STYLE */ + +.header { + background-color: #2d2d2d; + border-bottom: 1px solid #6d6d6d; + color: #405964; + padding: 6px 0; + height: 30px; +} + +.header div { + background-position: 0 0; + width: 83px; + height: 30px; +} + +/* END HEADER STYLE */ + +/* BEGIN HOME STYLE */ + +#home .header div { + margin: 0 auto; +} + +#home .notification { + padding: 2px; + margin-top: -1px; +} + +#noscript { + background: #86a2ff; + border-bottom: 1px solid #5890d6; + color: #1e4b82; +} + +#error { + background: #ff8686; + border-bottom: 1px solid #d65858; + color: #821e1e; + display: none; +} + +#info { + background: #f3eba7; + border-bottom: 1px solid #d9d085; + color: #5e5616; + display: none; +} + +#home .login { + padding: 8px 0; + margin: 30px 0 30px 0; +} + +#home .login input { + margin-top: 5px; + padding: 2px; +} + +#home .login input.xid, +#home .login input.password { + display: block; + margin: 4px auto; + font-size: 0.85em; + padding: 4px; + background-color: white; + border: 1px solid #636363; + width: 150px; + padding-left: 24px; +} + +#home .login input.xid { + background-position: 4px -30px; +} + +#home .login input.password { + background-position: 4px -53px; +} + +#home .login label { + margin-bottom: 12px; + display: block; +} + +#home .login label input { + margin-right: 4px; +} + +#home a { + font-size: 0.8em; +} + +/* END HOME STYLE */ + +/* BEGIN TALK STYLE */ + +#talk .header div, +#chat .header div { + float: left; + margin-left: 7px; +} + +#talk .header button, +#chat .header button { + float: right; + margin-right: 7px; + padding: 2px; +} + +#talk a.one-buddy { + display: none; + background-color: #87a5ab; + border-bottom: 1px solid #5b8088; + text-shadow: 1px 1px 1px #5b8088; + text-decoration: none; + color: white; + outline-style: none; + padding: 10px 0; +} + +#talk a.one-buddy:hover { + cursor: pointer; +} + +#talk a.available, +#talk a.chat { + background-color: #83b187; + border-bottom: 1px solid #4d8252; + text-shadow: 1px 1px 1px #4d8252; +} + +#talk a.available:hover, +#talk a.chat:hover, +#talk a.available:focus, +#talk a.chat:focus { + background-color: #89c68e; +} + +#talk a.available:active, +#talk a.chat:active { + background-color: #90d496; +} + +#talk a.away { + background-color: #e0be7b; + border-bottom: 1px solid #ae8941; + text-shadow: 1px 1px 1px #ae8941; +} + +#talk a.away:hover, +#talk a.away:focus { + background-color: #eac784; +} + +#talk a.away:active { + background-color: #f3d294; +} + +#talk a.xa, +#talk a.dnd { + background-color: #db8989; + border-bottom: 1px solid #a24343; + text-shadow: 1px 1px 1px #a24343; +} + +#talk a.xa:hover, +#talk a.dnd:hover, +#talk a.xa:focus, +#talk a.dnd:focus { + background-color: #e89797; +} + +#talk a.xa:active, +#talk a.dnd:active { + background-color: #ef9f9f; +} + +/* END TALK STYLE */ + +/* BEGIN CHAT STYLE */ + +#chat { + display: none; +} + +#chat .one-chat, +#chat .one-chat p, +#chat .one-chat div, +#chat .one-chat input { + position: absolute; + bottom: 0; + right: 0; +} + +#chat .one-chat { + top: 43px; + left: 0; +} + +#chat .one-chat p { + background-color: #87a5ab; + border-bottom: 1px solid #5b8088; + text-shadow: 1px 1px 1px #5b8088; + color: white; + top: 0; + left: 0; + height: 18px; + padding: 2px 0; + font-size: 0.9em; +} + +#chat .one-chat div { + border-bottom: 1px solid #cbcbcb; + top: 23px; + left: 0; + bottom: 25px; + overflow: auto; + text-align: left; +} + +#chat .one-chat span { + display: block; + font-size: 0.85em; + margin: 4px 6px; + word-wrap: break-word; +} + +#chat .one-chat b { + margin-right: 3px; +} + +#chat .one-chat b.me { + color: #123a5c; +} + +#chat .one-chat b.him { + color: #801e1e; +} + +#chat .one-chat input { + background-color: white; + bottom: 0; + height: 25px; + width: 100%; + border: none; +} + +#chat .one-chat input.submit { + right: 0; + width: 35px; +} + +/* END CHAT STYLE */ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/mucadmin.css b/sources/extend/addon/matrix/jappixmini/jappix/css/mucadmin.css new file mode 100644 index 00000000..3fe1c754 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/mucadmin.css @@ -0,0 +1,91 @@ +/* + +Jappix - An open social platform +This is the mucadmin CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 11/05/11 + +*/ + +#mucadmin .content { + padding: 10px 0 10px 0; +} + +#mucadmin .content p { + margin: 5px 10px 5px 10px; + text-align: justify; +} + +#mucadmin .mucadmin-head-jid { + text-decoration: underline; + font-size: 0.9em; + float: right; + margin: 1px 4px 1px 1px; +} + +#mucadmin .mucadmin-forms { + height: 310px; + width: 620px; + margin: -5px 0 0 10px; + padding: 6px 0 0 0; + overflow: auto; +} + +#mucadmin .mucadmin-forms label { + width: 260px; +} + +#mucadmin .mucadmin-topic label, +#mucadmin .mucadmin-aut label, +#mucadmin .mucadmin-others label { + font-size: 0.9em; +} + +#mucadmin .mucadmin-forms textarea { + height: 60px; + width: 300px; + margin: 5px 12px 10px 0; +} + +#mucadmin .results { + height: auto; + width: auto; + overflow: visible; + margin: 5px; +} + +#mucadmin .aut-group { + float: left; + padding-bottom: 4px; +} + +#mucadmin .one-aut { + clear: both; + margin: 0 10px 5px 0; +} + +#mucadmin .aut-add { + clear: both; + float: left; + margin-bottom: 5px; + font-size: 0.9em; +} + +#mucadmin .aut-remove { + float: left; +} + +#mucadmin .aut-remove:hover, +#mucadmin .aut-remove:focus { + font-weight: bold; + text-decoration: none; +} + +#mucadmin .mucadmin-others a { + float: left; + font-size: 0.9em; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/myinfos.css b/sources/extend/addon/matrix/jappixmini/jappix/css/myinfos.css new file mode 100644 index 00000000..83262268 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/myinfos.css @@ -0,0 +1,330 @@ +/* + +Jappix - An open social platform +This is the my-infos CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 31/08/11 + +*/ + +#my-infos { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + color: #919191; + margin-top: 8px; + padding: 15px 6px 6px 6px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 0 6px #5c5c5c; + -moz-box-shadow: 0 0 6px #5c5c5c; + -webkit-box-shadow: 0 0 6px #5c5c5c; +} + +#my-infos .content { + background: #e8f1f3; + background: -moz-linear-gradient(top, #e4edef, #e8f1f3); + background: -webkit-gradient(linear, left top, left bottom, from(#e4edef), to(#e8f1f3)); + color: #919191; + max-height: 140px; + padding: 1px 0; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#my-infos .element { + height: 24px; + margin: 6px 0; + position: relative; +} + +#my-infos .element .icon { + background-color: white; + border-color: #636363; + border-width: 1px; + border-style: solid; + margin-left: 6px; + height: 22px; + width: 25px; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#my-infos .element div.bubble a { + width: 100%; + height: 20px; +} + +#my-infos .element .icon:hover, +#my-infos .element div.bubble a:hover { + background-color: #f4f4f4; +} + +#my-infos .element .icon:active, +#my-infos .element div.bubble a:active { + background-color: #ededed; +} + +#my-infos .f-presence div.bubble a[data-value=available] { + background-position: 4px -167px; +} + +#my-infos .f-presence div.bubble a[data-value=away] { + background-position: 4px -183px; +} + +#my-infos .f-presence div.bubble a[data-value=xa] { + background-position: 4px -199px; +} + +#my-infos .f-mood div.bubble a[data-value=crazy] { + background-position: 4px -296px; +} + +#my-infos .f-mood div.bubble a[data-value=excited] { + background-position: 4px -314px; +} + +#my-infos .f-mood div.bubble a[data-value=playful] { + background-position: 4px -332px; +} + +#my-infos .f-mood div.bubble a[data-value=happy] { + background-position: 4px -350px; +} + +#my-infos .f-mood div.bubble a[data-value=shocked] { + background-position: 4px -368px; +} + +#my-infos .f-mood div.bubble a[data-value=hot] { + background-position: 4px -386px; +} + +#my-infos .f-mood div.bubble a[data-value=sad] { + background-position: 4px -404px; +} + +#my-infos .f-mood div.bubble a[data-value=amorous] { + background-position: 4px -422px; +} + +#my-infos .f-mood div.bubble a[data-value=confident] { + background-position: 4px -440px; +} + +#my-infos .f-mood a[data-value] span { + background-position: 0 -352px; +} + +#my-infos .f-mood a[data-value=crazy] span, +.mood-one { + background-position: 0 -298px; +} + +#my-infos .f-mood a[data-value=excited] span, +.mood-two { + background-position: 0 -316px; +} + +#my-infos .f-mood a[data-value=playful] span, +.mood-three { + background-position: 0 -334px; +} + +#my-infos .f-mood a[data-value=happy] span, +.mood-four { + background-position: 0 -352px; +} + +#my-infos .f-mood a[data-value=shocked] span, +.mood-five { + background-position: 0 -370px; +} + +#my-infos .f-mood a[data-value=hot] span, +.mood-six { + background-position: 0 -388px; +} + +#my-infos .f-mood a[data-value=sad] span, +.mood-seven { + background-position: 0 -406px; +} + +#my-infos .f-mood a[data-value=amorous] span, +.mood-eight { + background-position: 0 -424px; +} + +#my-infos .f-mood a[data-value=confident] span, +.mood-nine { + background-position: 0 -442px; +} + +#my-infos .f-activity div.bubble a[data-value=doing_chores] { + background-position: 4px -458px; +} + +#my-infos .f-activity div.bubble a[data-value=drinking] { + background-position: 4px -476px; +} + +#my-infos .f-activity div.bubble a[data-value=eating] { + background-position: 4px -494px; +} + +#my-infos .f-activity div.bubble a[data-value=exercising] { + background-position: 4px -512px; +} + +#my-infos .f-activity div.bubble a[data-value=grooming] { + background-position: 4px -548px; +} + +#my-infos .f-activity div.bubble a[data-value=having_appointment] { + background-position: 4px -566px; +} + +#my-infos .f-activity div.bubble a[data-value=inactive] { + background-position: 4px -530px; +} + +#my-infos .f-activity div.bubble a[data-value=relaxing] { + background-position: 4px -620px; +} + +#my-infos .f-activity div.bubble a[data-value=talking] { + background-position: 4px -602px; +} + +#my-infos .f-activity div.bubble a[data-value=traveling] { + background-position: 4px -584px; +} + +#my-infos .f-activity div.bubble a[data-value=working] { + background-position: 4px -638px; +} + +#my-infos .f-activity a[data-value] span { + background-position: 0 -514px; +} + +#my-infos .f-activity a[data-value=doing_chores] span, +.activity-doing_chores { + background-position: 0 -460px; +} + +#my-infos .f-activity a[data-value=drinking] span, +.activity-drinking { + background-position: 0 -478px; +} + +#my-infos .f-activity a[data-value=eating] span, +.activity-eating { + background-position: 0 -496px; +} + +#my-infos .f-activity a[data-value=exercising] span, +.activity-exercising { + background-position: 0 -514px; +} + +#my-infos .f-activity a[data-value=grooming] span, +.activity-grooming { + background-position: 0 -550px; +} + +#my-infos .f-activity a[data-value=having_appointment] span, +.activity-having_appointment { + background-position: 0 -568px; +} + +#my-infos .f-activity a[data-value=inactive] span, +.activity-inactive { + background-position: 0 -532px; +} + +#my-infos .f-activity a[data-value=relaxing] span, +.activity-relaxing { + background-position: 0 -622px; +} + +#my-infos .f-activity a[data-value=talking] span, +.activity-talking { + background-position: 0 -604px; +} + +#my-infos .f-activity a[data-value=traveling] span, +.activity-traveling { + background-position: 0 -586px; +} + +#my-infos .f-activity a[data-value=working] span, +.activity-working { + background-position: 0 -640px; +} + +#my-infos .element .icon.picker { + border-width: 1px 0 1px 1px; + border-top-right-radius: 0; + border-bottom-right-radius: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-bottomright: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-bottom-right-radius: 0; +} + +#my-infos .element .icon.disabled { + background-color: #f3f3f3; + border-color: #989898; + cursor: default; +} + +#my-infos .element div.bubble { + background-color: white; + border-color: #636363; + border-width: 1px 1px 0 1px; + border-style: solid; + width: 25px; + padding: 1px 0; + position: absolute; + bottom: 21px; + left: 6px; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + -moz-border-radius-topleft: 2px; + -moz-border-radius-topright: 2px; + -webkit-border-top-left-radius: 2px; + -webkit-border-top-right-radius: 2px; +} + +#my-infos .element a { + float: left; +} + +#my-infos .element .icon span { + height: 16px; + width: 16px; + margin: 3px 4px; + display: block; +} + +#my-infos .element input { + height: 18px; + width: 190px; + font-size: 0.85em; + padding-left: 4px; + border-top-left-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-topleft: 0; + -moz-border-radius-bottomleft: 0; + -webkit-border-top-left-radius: 0; + -webkit-border-top-bottom-radius: 0; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/options.css b/sources/extend/addon/matrix/jappixmini/jappix/css/options.css new file mode 100644 index 00000000..6dc4ecdb --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/options.css @@ -0,0 +1,97 @@ +/* + +Jappix - An open social platform +This is the options CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 26/04/11 + +*/ + +#options label { + width: 190px; + font-size: 0.94em; +} + +#options .forms { + width: 610px; + height: 328px; + margin: 15px 15px 15px 15px; + float: left; +} + +#options .forms select { + margin-top: -3px; + min-width: 120px; + float: left; +} + +#options .forms a.linked { + font-size: 0.9em; + float: left; +} + +#options fieldset.privacy { + display: none; +} + +#options .sub-ask-delete, #options .sub-ask-pass, #options .sub-ask-pass-success { + display: none; +} + +#options .sub-ask { + display: none; + width: 592px; + padding: 8px; + float: left; + border: 1px #879da2 dotted; + background: #cbdde1; +} + +#options .sub-ask-top { + font-size: 0.9em; + margin-top: -3px; +} + +#options .sub-ask-title { + margin-bottom: 4px; + float: left; +} + +#options .sub-ask-close { + float: right; +} + +#options .sub-ask-close:hover { + cursor: pointer; +} + +#options .sub-ask-content { + clear: both; + height: 25px; + font-size: 0.9em; + border-top: 1px #416972 solid; + padding: 12px 0; +} + +#options .sub-ask-content label { + width: 125px; +} + +#options .sub-ask-content input { + width: 125px; +} + +#options .sub-ask-bottom { + clear: both; + font-size: 0.9em; + float: right; + text-decoration: underline; +} + +#options .sub-ask-bottom:hover { + cursor: pointer; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/others.css b/sources/extend/addon/matrix/jappixmini/jappix/css/others.css new file mode 100644 index 00000000..f3e2461f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/others.css @@ -0,0 +1,118 @@ +/* + +Jappix - An open social platform +This is the others CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 31/08/11 + +*/ + +#audio { + display: none; +} + +#top-content { + position: absolute; + right: 5px; + left: 5px; + top: 0; + min-width: 860px; + z-index: 50; +} + +#main-content { + position: absolute; + top: 34px; + left: 5px; + right: 5px; + bottom: 5px; + min-width: 850px; + min-height: 450px; +} + +#left-content { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 248px; +} + +#right-content { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 260px; + z-index: 10; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 0 6px #5c5c5c; + -moz-box-shadow: 0 0 6px #5c5c5c; + -webkit-box-shadow: 0 0 6px #5c5c5c; +} + +#general-wait { + background: url(../img/others/blank.gif) repeat; + z-index: 10000; + position: fixed; + top: 0; + bottom: 0; + left: 0; + right: 0; +} + +.general-wait-content { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.9); + background-position: 8px 8px; + padding: 8px; + position: absolute; + right: 5px; + bottom: 5px; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + box-shadow: 0 0 2px #000; + -moz-box-shadow: 0 0 2px #000; + -webkit-box-shadow: 0 0 2px #000; +} + +.inbox-hidable, +.options-hidable, +.pep-hidable, +.pubsub-hidable, +.archives-hidable, +.commands-hidable, +.privacy-hidable, +.xmpplinks-hidable { + display: none; +} + +#reconnect .pane { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.85); + color: white; + padding: 25px; + z-index: 10000; + text-shadow: 0 1px 1px black; + position: absolute; + left: 0; + right: 0; + top: 0; + box-shadow: 0 0 35px #232323; + -moz-box-shadow: 0 0 35px #232323; + -webkit-box-shadow: 0 0 35px #232323; +} + +#reconnect .pane a { + margin-top: -4px; + float: right; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/pageengine.css b/sources/extend/addon/matrix/jappixmini/jappix/css/pageengine.css new file mode 100644 index 00000000..75038b6c --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/pageengine.css @@ -0,0 +1,601 @@ +/* + +Jappix - An open social platform +This is the page-engine CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 31/08/11 + +*/ + +#page-engine { + background-color: #f4f4f4; + position: absolute; + top: 40px; + bottom: 6px; + right: 6px; + left: 6px; + z-index: 8; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +#page-engine .top { + background: #e8f1f3; + background: -moz-linear-gradient(top, #e8f1f3, #dee8ea); + background: -webkit-gradient(linear, left top, left bottom, from(#e8f1f3), to(#dee8ea)); + border-bottom: 1px solid #d0d0d0; + color: black; + position: absolute; + top: 0; + left: 0; + right: 0; + padding: 6px; + height: 80px; + border-top-right-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-top-left-radius: 3px; +} + +#page-engine .top .avatar-container { + text-align: center; + margin: 2px 0 0 10px; + height: 76px; + width: 76px; + float: left; +} + +#page-engine .top .avatar { + max-height: 76px; + max-width: 76px; +} + +#page-engine .top .name { + text-align: right; + padding: 7px; +} + +#page-engine p.bc-name { + font-size: 2.3em; + margin-bottom: 5px; +} + +#page-engine p.bc-infos { + font-size: 0.85em; + height: 16px; + overflow: hidden; + position: absolute; + left: 115px; + right: 12px; +} + +#page-engine .page-engine-chan[data-type=groupchat] p.bc-infos { + left: 12px; +} + +#page-engine p.bc-infos span.show { + padding-left: 18px; +} + +#page-engine p.bc-infos a { + text-decoration: underline; +} + +#page-engine div.bc-pep { + float: right; +} + +#page-engine div.bc-pep a { + height: 16px; + width: 16px; + margin-left: 4px; + float: left; +} + +#page-engine div.bc-pep a:hover { + cursor: default; +} + +#page-engine div.bc-pep a[href]:hover { + cursor: pointer; +} + +#page-engine .content, +#page-engine .list { + font-size: 0.9em; + position: absolute; + top: 93px; + right: 0; + bottom: 29px; + overflow: auto; + box-shadow: inset 0 3px 10px #e8e8e8; + -moz-box-shadow: inset 0 3px 10px #e8e8e8; + -webkit-box-shadow: inset 0 3px 10px #e8e8e8; +} + +#page-engine .content { + left: 0; + padding: 12px 14px 0; +} + +#page-engine .content a { + text-decoration: underline; +} + +#page-engine .page-engine-chan { + display: none; +} + +#page-engine .chat .content, +#page-engine .chat .list { + bottom: 93px; +} + +#page-engine .chat .content { + padding-bottom: 24px; +} + +#page-engine .groupchat-content { + padding-bottom: 16px !important; + right: 191px !important; +} + +#page-engine .list { + border-left: 1px solid #c8c8c8; + padding: 8px 0 0; + width: 190px; + right: 0; +} + +#page-engine .list .role { + display: none; + margin-bottom: 10px; +} + +#page-engine .list .title { + font-weight: bold; + color: #383838; + margin-left: 8px; +} + +#page-engine .list .user { + background: #eff2f2; + background: -moz-linear-gradient(top, #eff2f2, #ecefef); + background: -webkit-gradient(linear, left top, left bottom, from(#eff2f2), to(#ecefef)); + border-color: #c8c8c8; + border-width: 1px 0; + border-style: solid; + color: #383838; + margin-bottom: 3px; + height: 32px; + overflow: hidden; +} + +#page-engine .list .user:hover { + background: #e9ecec; + cursor: pointer; +} + +#page-engine .list .user:active { + background: #e3e7e7; +} + +#page-engine .list .user.myself { + background-color: #eff2f2; + cursor: default; +} + +#page-engine .list .user .name { + float: left; + height: 18px; + overflow: hidden; + margin: 7px 0 7px 3px; + padding-left: 18px; +} + +#page-engine .list .user .avatar-container { + text-align: center; + float: right; + height: 32px; + width: 32px; +} + +#page-engine .list .user .avatar { + max-height: 32px; + max-width: 32px; +} + +#page-engine .one-group, +#archives .one-group { + border-bottom: 1px dotted #d0d0d0; + padding-bottom: 8px; + margin-bottom: 10px; +} + +#page-engine .one-line, +#archives .one-line, +#page-engine .one-group b.name, +#archives .one-group b.name { + padding-left: 50px; + word-wrap: break-word; +} + +#page-engine .one-group b.name, +#archives .one-group b.name { + display: block; + margin-bottom: 4px; +} + +#page-engine .one-group b.name.me, +#archives .one-group b.name.me { + color: #123a5c; +} + +#page-engine .one-group b.name.him, +#archives .one-group b.name.him { + color: #801e1e; +} + +#page-engine .one-group span.date, +#archives .one-group span.date { + float: right; + font-size: 0.9em; +} + +#page-engine .one-group .avatar-container, +#archives .one-group .avatar-container { + text-align: center; + margin: 4px 0 0 6px; + height: 30px; + width: 30px; + float: left; +} + +#page-engine .one-group .avatar, +#archives .one-group .avatar { + max-height: 30px; + max-width: 30px; +} + +#page-engine b.name.talk-images { + background-position: 50px -99px; + padding-left: 68px; +} + +#page-engine .user-message, +#archives .user-message { + margin-bottom: 3px; +} + +#page-engine .system-message { + color: #053805 !important; + margin-bottom: 3px !important; + padding-left: 0 !important; +} + +#page-engine .system-message a { + color: #053805 !important; +} + +#page-engine .system-message p.help b { + margin-bottom: 5px; + text-decoration: underline; + display: block; +} + +#page-engine .system-message p.help em { + width: 240px; + text-decoration: underline; + margin-left: 5px; + float: left; +} + +#page-engine .my-nick { + font-weight: bold; +} + +#page-engine .old-message { + font-size: 11px !important; + margin-bottom: 1px !important; +} + +#page-engine .chatstate { + background-color: rgb(234,234,234); + background-color: rgba(234,234,234,0.8); + color: #2c2c2c; + padding: 3px 10px 2px 8px; + position: absolute; + bottom: 93px; + left: 0; + font-size: 0.75em; + border-top-right-radius: 3px; + -moz-border-radius-topright: 3px; + -webkit-border-top-right-radius: 3px; +} + +#page-engine .text { + height: 93px; + position: absolute; + bottom: 0; + left: 0; + right: 0; +} + +#page-engine .footer { + background: #e8f1f3; + background: -moz-linear-gradient(top, #dee8ea, #e8f1f3); + background: -webkit-gradient(linear, left top, left bottom, from(#dee8ea), to(#e8f1f3)); + border-color: #d0d0d0; + border-width: 1px 0 0; + border-style: solid; + color: black; + position: absolute; + left: 0; + right: 0; + padding: 6px; + height: 16px; +} + +#page-engine .chat .footer { + border-width: 1px 0; + position: static; +} + +#page-engine .chat-tools-content { + height: 16px; + width: 16px; + margin-right: 8px; + float: left; +} + +#page-engine .tools-tooltip { + display: block; + height: 16px; + width: 16px; + overflow: hidden; + float: left; +} + +#page-engine .text .chat-tools-smileys { + margin-left: 4px; +} + +#page-engine .text .chat-tools-file { + display: none; +} + +#page-engine .text .chat-tools-file.mini .bubble-file { + z-index: 39; +} + +#page-engine .text .chat-tools-file.mini .tooltip-subitem { + width: 22px; + height: 20px; +} + +#page-engine .text .chat-tools-file.mini .wait { + margin: -2px 0 0 -1px; +} + +#page-engine .text .tools-smileys { + background-position: 0 -388px; +} + +#page-engine .text .tools-style { + background-position: 0 -700px; +} + +#page-engine .text .tools-file { + background-position: 0 -1956px; +} + +#page-engine .text .tools-save { + background-position: 0 -719px; +} + +#page-engine .text .tools-clear { + background-position: 0 -739px; +} + +#page-engine .text .tools-infos, +#channel .top div.shortcuts a.profile { + background-position: 0 -758px; +} + +#page-engine .text .tools-add, +#page-engine .text .tools-archives, +#page-engine .text .tools-mucadmin { + display: none; +} + +#page-engine .text .tools-mucadmin { + background-position: 0 -777px; +} + +#page-engine .bubble-style label.bold { + font-weight: bold; +} + +#page-engine .bubble-style label.italic { + font-style: italic; +} + +#page-engine .bubble-style label.underline { + text-decoration: underline; +} + +#page-engine .bubble-style a.color { + height: 18px; + width: 18px; + border-color: white; + border-width: 1px; + border-style: solid; + margin: 6px 5px 0 0; + float: left; + opacity: 0.6; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 5px black; + -moz-box-shadow: 0 0 5px black; + -webkit-box-shadow: 0 0 5px black; +} + +#page-engine .bubble-style a.color:hover, +#page-engine .bubble-style a.color:focus { + opacity: 0.7; +} + +#page-engine .bubble-style a.color.selected { + opacity: 1; + border-color: #ffb20d; +} + +#page-engine .bubble-file .tooltip-subitem { + width: 240px; +} + +#page-engine .bubble-file input[type=file] { + width: 220px; +} + +#page-engine .bubble-file input[type=submit], +#page-engine .bubble-file input[type=reset] { + margin: 4px 4px 0 0; +} + +#page-engine .text .compose, +#page-engine .muc-ask { + position: absolute; + left: 0; +} + +#page-engine .text .compose { + top: 29px; + right: 12px; + bottom: 12px; +} + +#page-engine .muc-ask { + right: 0; + bottom: 0; +} + +#page-engine .text textarea { + border: 1px solid #c8c8c8; + padding: 5px; + height: 100%; + width: 100%; + font-size: 1.1em; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-top-right-radius: 0; + border-top-left-radius: 0; + -moz-border-radius-topright: 0; + -moz-border-radius-topleft: 0; + -webkit-border-top-right-radius: 0; + -webkit-border-top-left-radius: 0; +} + +#page-engine .muc-ask { + background-color: #e8f1f3; + height: 64px; + font-size: 0.9em; + right: 0; + z-index: 2; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-bottomright: 3px; + -webkit-border-bottom-left-radius: 3px; + -webkit-border-bottom-right-radius: 3px; +} + +#page-engine .muc-ask label { + color: #224249; + margin: 23px 10px 0 16px; + font-weight: bold; +} + +#page-engine .muc-ask input { + width: 200px; + margin: 19px 10px 0 10px; + padding: 3px; +} + +#page-engine .tooltip { + position: absolute; + bottom: 84px; + margin-left: -13px; + z-index: 40; + font-size: 0.8em; + color: white; +} + +#page-engine .tooltip a { + color: white; + text-decoration: underline; +} + +#page-engine .tooltip-subitem { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.8); + padding: 10px; + width: 200px; + height: 110px; + text-shadow: 0 1px 1px black; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +#page-engine .tooltip-subarrow { + background-position: 0 -251px; + opacity: 0.8; + height: 10px; + width: 18px; + margin-left: 12px; +} + +#page-engine .tooltip .tooltip-top { + margin-bottom: 8px; + font-weight: bold; +} + +#page-engine .tooltip label { + margin-bottom: 4px; + float: left; + clear: both; +} + +#page-engine .tooltip label input[type=checkbox] { + margin: 0 6px 0 0; + float: left; +} + +#page-engine .tooltip label.select { + margin-top: 5px; +} + +#page-engine .tooltip input, +#page-engine .tooltip select { + float: left; +} + +#page-engine .tooltip select { + width: 100px; +} + +#page-engine .tooltip .tooltip-actionlog:hover, +#page-engine .tooltip .tooltip-actionlog:focus { + cursor: pointer; + text-decoration: underline; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/pageswitch.css b/sources/extend/addon/matrix/jappixmini/jappix/css/pageswitch.css new file mode 100644 index 00000000..59830049 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/pageswitch.css @@ -0,0 +1,209 @@ +/* + +Jappix - An open social platform +This is the page-switch CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 22/05/11 + +*/ + +#page-switch { + position: absolute; + top: 15px; + left: 10px; + right: 10px; + z-index: 9; +} + +#page-switch .chans { + position: absolute; + left: 0; + right: 40px; + top: 0; + height: 25px; + overflow: hidden; +} + +#page-switch .more { + position: absolute; + right: 0; + top: 0; +} + +#page-switch .more-button { + background-position: 6px -1372px; + background-color: #d9e7ea; + width: 7px; + height: 17px; + padding: 1px 6px; + font-size: 0.9em; + text-decoration: none; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#page-switch .more-content { + background-color: #d9e7ea; + width: 200px; + max-height: 400px; + overflow: auto; + position: absolute; + margin: -2px 0 0 -181px; + padding: 4px 0; + font-size: 0.95em; + border-top-left-radius: 3px; + border-bottom-left-radius: 3px; + border-bottom-right-radius: 3px; + -moz-border-radius-topleft: 3px; + -moz-border-radius-bottomleft: 3px; + -moz-border-radius-bottomright: 3px; + -webkit-border-top-left-radius: 3px; + -webkit-border-bottom-left-radius: 3px; + -webkit-border-bottom-right-radius: 3px; +} + +#page-switch .switcher { + background-color: #d9e7ea; + color: #17353b; + height: 15px; + padding: 5px 10px 5px 5px; + margin: 0 2px; + font-size: 0.85em; + float: left; + border-top-right-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-top-left-radius: 3px; +} + +#page-switch .more-content .switcher { + background-color: #d9e7ea; + float: none; + margin: 0; + font-size: 0.9em; + border-radius: 0; + -moz-border-radius: 0; + -webkit-border-radius: 0; +} + +#page-switch .more-content .switcher .exit { + display: block; +} + +#page-switch .more-button:hover, +#page-switch .more-button:focus, +#page-switch .switcher:hover, +#page-switch .switcher:focus, +#page-switch .more-content .switcher:hover, +#page-switch .more-content .switcher:focus { + background-color: #cedee1; + cursor: pointer; +} + +#page-switch .more-button:active, +#page-switch .switcher:active, +#page-switch .more-content .switcher:active { + background-color: #c3d3d7; +} + +#page-switch .switcher.activechan { + background-color: #e8f1f3; +} + +#page-switch .more-content .switcher.activechan { + background-color: #d1e0e3; +} + +#page-switch .icon { + height: 16px; + width: 16px; + float: left; +} + +#page-switch .name { + float: left; + margin-left: 4px; + max-height: 16px; + max-width: 140px; + overflow: hidden; +} + +#page-switch .exit { + display: none; + background-color: #bdd9dc; + border: 1px solid #80aab0; + color: #355e64; + height: 14px; + width: 13px; + margin-left: 10px; + font-size: 0.85em; + text-align: center; + text-decoration: none; + float: right; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +#page-switch .exit:hover, +#page-switch .exit:focus { + background-color: #aac7cb; +} + +#page-switch .exit:active { + background-color: #9bbdc1; +} + +#page-switch .activechan .exit { + display: block; + float: right; +} + +#page-switch .chan-newmessage { + background-color: #f6edc3 !important; +} + +#page-switch .chan-newmessage:hover, +#page-switch .chan-newmessage:focus { + background-color: #f1eac0 !important; +} + +#page-switch .chan-newmessage:active { + background-color: #ede4b8 !important; +} + +#page-switch .composing, +#page-engine .list .user.composing { + color: #217021 !important; +} + +#page-switch .paused, +#page-switch .chan-unread .name, +#page-engine .list .user.paused { + color: #2431ac !important; +} + +#page-switch .active, +#page-engine .list .user.active { + color: #353535 !important; +} + +#page-switch .inactive, +#page-engine .list .user.inactive { + color: #585858 !important; +} + +#page-switch .gone { + color: #851313 !important; +} + +#page-switch .channel .icon { + background-position: 0 -55px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/popup.css b/sources/extend/addon/matrix/jappixmini/jappix/css/popup.css new file mode 100644 index 00000000..e5b3eb92 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/popup.css @@ -0,0 +1,612 @@ +/* + +Jappix - An open social platform +This is the popup CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 02/05/11 + +*/ + +.lock { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.6); + left: 0; + right: 0; + top: 0; + bottom: 0; + position: fixed; + z-index: 9999; +} + +.popup { + background-color: rgb(20,20,20); + background-color: rgba(20,20,20,0.95); + margin-top: -250px; + margin-left: -330px; + width: 640px; + height: 500px; + padding: 0 10px; + position: absolute; + z-index: 10000; + left: 50%; + top: 50%; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + box-shadow: 0 0 35px #232323; + -moz-box-shadow: 0 0 35px #232323; + -webkit-box-shadow: 0 0 35px #232323; +} + +.popup.large { + margin-left: -460px; + width: 920px; +} + +.popup .top { + width: 600px; + height: 45px; + font-size: 1.2em; + padding-top: 9px; + color: white; + margin: 14px 0 0 40px; + text-transform: uppercase; + text-decoration: none; + font-weight: bold; + text-shadow: 0 2px 2px black; +} + +.popup .tab { + width: 620px; + height: 25px; + margin: -5px 10px 0 10px; + position: relative; + z-index: 1; +} + +.popup .tab a { + background-color: #d9e7ea; + color: #204249; + width: 180px; + height: 17px; + padding: 4px 4px 4px 16px; + margin-left: 5px; + font-size: 0.94em; + overflow: hidden; + float: left; + border-top-right-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-top-left-radius: 3px; +} + +.popup .tab a:hover, +.popup .tab a:focus { + background-color: #cedee1; + text-decoration: none; +} + +.popup .tab a:active { + background-color: #c3d3d7; + text-decoration: none; +} + +.popup .tab a.tab-active { + background-color: #e4eef9 !important; +} + +.popup .one-lap { + display: none; +} + +.popup .one-lap.lap-active { + display: block; +} + +.popup .content { + background: #e4eef9; + background: -moz-linear-gradient(top, #e4eef9, #D0E5FA); + background: -webkit-gradient(linear, left top, left bottom, from(#e4eef9), to(#D0E5FA)); + height: 358px; + width: 640px; + position: absolute; + left: 10px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 20px black; + -moz-box-shadow: 0 0 20px black; + -webkit-box-shadow: 0 0 20px black; +} + +.popup .content, +.popup .content a { + color: #112a2f; +} + +.popup.large div.comments { + background-color: #f4f4f4; + width: 272px; + margin: 0; + position: absolute; + right: 10px; + top: 63px; + bottom: 10px; + overflow-x: hidden; + overflow-y: auto; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +.popup.large div.comments div.comments-content { + font-size: 0.8em; +} + +.popup.large div.comments input { + width: 185px; + min-width: 0; +} + +.popup.large div.comments .one-comment { + padding-bottom: 4px; +} + +.popup.large div.comments .one-comment a { + text-decoration: underline; +} + +.popup.large div.comments div.comments-content { + border-top-right-radius: 3px; + border-top-left-radius: 3px; + -moz-border-radius-topright: 3px; + -moz-border-radius-topleft: 3px; + -webkit-border-top-right-radius: 3px; + -webkit-border-top-left-radius: 3px; +} + +.popup .head { + background: #f1f6fd; + border: 1px #9dc4fc solid; + width: 606px; + height: 24px; + margin: 0 10px 10px 10px; + padding: 6px; +} + +.popup .head-text { + float: left; + font-size: 0.9em; + margin: 3px; +} + +.popup .head-actions { + float: right; + margin-top: 2px; +} + +.popup .head-actions a { + font-size: 0.9em; + margin: 0 4px; +} + +.popup .actions a { + color: #30575f; + font-size: 0.9em; + margin-left: 5px; +} + +.popup .head .head-input { + float: right; + width: 200px; + padding: 2px; +} + +.popup .head .head-select { + float: right; + height: 24px; +} + +.popup .forms { + width: 390px; + height: 328px; + margin: 15px; + float: left; +} + +.popup fieldset { + border: 1px #547177 solid; + margin: 0 0 15px 0; + padding: 8px 2px 3px 2px; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; +} + +.popup legend { + font-size: 0.9em; + margin: 0 0 0 15px; + padding: 0 2px; + text-transform: uppercase; +} + +.popup label { + color: #1b1b1b; + width: 150px; + margin: 0 0 10px 12px; + clear: both; + float: left; +} + +.popup input, +.popup select { + margin: 0 10px 10px 0; + float: left; +} + +.popup input[type=text] { + min-width: 174px; +} + +.popup select { + min-height: 20px; +} + +.popup .results { + height: 310px; + width: 620px; + margin: -5px 0 0 10px; + padding: 6px 0 0 0; + overflow: auto; +} + +.popup .results .no-results { + margin: 6px 0; + font-size: 0.85em; + font-weight: bold; +} + +.popup .results label { + width: 180px; + margin: 6px 4px 4px 4px; +} + +.popup .results input, +.popup .results textarea, +.popup .results select { + margin: 4px; +} + +.popup .results input, +.popup .results select { + min-width: 180px; +} + +.popup .results input[type=checkbox], +.popup .results input[type=radio] { + margin-top: 7px; +} + +.popup .results textarea { + width: 380px; +} + +.popup .results .avatar-container { + float: left; + width: 60px; + height: 60px; + margin: 5px 12px 5px 9px; + text-align: center; + background-repeat: no-repeat; +} + +.popup .results img.avatar { + max-width: 60px; + max-height: 60px; +} + +.popup .results .one-icon { + height: 16px; + width: 16px; + margin: 10px 3px 0 8px; + float: left; +} + +.popup .results .one-icon.account, +.popup .results .one-icon.auth { + background-position: 0 -777px; +} + +.popup .results .one-icon.automation, +.popup .results .one-icon.client { + background-position: 0 -1500px; +} + +.popup .results .one-icon.collaboration { + background-position: 0 -1520px; +} + +.popup .results .one-icon.proxy, +.popup .results .one-icon.server, +.popup .results .one-icon.others { + background-position: 0 -1540px; +} + +.popup .results .one-icon.component, +.popup .results .one-icon.gateway { + background-position: 0 -1560px; +} + +.popup .results .one-icon.conference { + background-position: 0 -1082px; +} + +.popup .results .one-icon.directory { + background-position: 0 -876px; +} + +.popup .results .one-icon.headline, +.popup .results .one-icon.hierarchy { + background-position: 0 -1580px; +} + +.popup .results .one-icon.pubsub, +.popup .results .one-icon.store { + background-position: 0 -1600px; +} + +.popup .results .one-icon.loading { + background-position: 0 -1620px; +} + +.popup .results .one-icon.down { + background-position: 0 -1640px; +} + +.popup .results .one-host { + font-weight: bold; + width: 170px; +} + +.popup .results .one-type { + width: 210px; +} + +.popup .results .one-type, +.popup .results .one-host { + float: left; + overflow: hidden; + margin: 9px 8px; +} + +.popup .results .one-jid, +.popup .results .one-ctry, +.popup .results .one-fn { + margin: 4px; + width: 400px; +} + +.popup .results .one-fn { + font-weight: bold; +} + +.popup .results .one-jid { + margin-top: 8px; + font-size: 0.9em; +} + +.popup .results .one-name { + float: left; + margin: 4px; +} + +.popup a.one-button { + display: none; + background-color: #f1f6fd; + border: 1px solid #b9cbcf; + margin-top: 1px; + padding: 4px 8px; + text-decoration: none; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +.popup a.one-button:hover, +.popup a.one-button:focus { + border: 1px solid #95b1b7; +} + +.popup a.one-button:active { + border: 1px solid #77989f; +} + +.popup .results .oneresult:hover a.one-button { + display: block; +} + +.popup .results a.one-button, +#inbox .one-message a.one-button { + float: right; + padding: 3px 6px; + margin-right: 4px; +} + +.popup .results a.one-vjud { + position: absolute; + right: 4px; +} + +.popup .results a.one-add { + top: 8px; +} + +.popup .results a.one-chat { + top: 42px; +} + +.popup .results .one-next { + float: right; + margin: 4px 8px 4px 4px; + font-weight: bold; +} + +.popup .results .one-actions { + width: 148px; + margin: 4px; + float: left; +} + +.popup .results .one-actions a { + width: 16px; + height: 16px; + padding: 2px 2px 4px 5px !important; + margin-top: 2px; +} + +.popup .results .one-actions a.browse { + background-position: 3px -1396px; +} + +.popup .results .one-actions a.command { + background-position: 3px -1415px; +} + +.popup .results .one-actions a.subscribe { + background-position: 4px -1435px; +} + +.popup .results .one-actions a.join { + background-position: 3px -1455px; +} + +.popup .results .one-actions a.search { + background-position: 4px -1475px; +} + +.popup .results a.submit, +.popup .results a.cancel, +.popup .results a.back { + margin-right: 8px; + float: right; +} + +.popup .onetitle { + font-size: 0.9em; + padding: 4px; + font-weight: bold; +} + +.popup .oneinstructions { + font-size: 0.9em; + padding: 4px; + margin: 8px 0; +} + +.popup .oneresult { + font-size: 0.9em; + padding: 3px 0 4px 4px; + border-bottom: 1px #9dc4fc solid; + overflow: hidden; + position: relative; +} + +.popup .oneresult:hover { + background: #e9f1fd; +} + +.popup .oneresult[onclick]:hover { + cursor: pointer; +} + +.popup .oneresult[onclick]:active { + background: #f1f6fd; +} + +.popup .infos { + background-color: rgb(255,239,104); + background-color: rgba(255,239,104,0.8); + border: 1px #decb2f solid; + color: #3f3f3f; + padding: 8px; + margin: 10px; + font-size: 0.8em; +} + +.popup .infos p { + margin-top: 10px; +} + +.popup .infos p.infos-title { + font-weight: bold; +} + +.popup .bottom { + width: 640px; + height: 40px; + position: absolute; + bottom: 8px; +} + +.popup .wait { + display: none; + margin: 8px 0 0 3px; + float: left; +} + +a.finish { + border: 1px solid white; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); + color: white; + padding: 4px 8px; + margin-right: 7px; + font-size: 0.95em; + text-align: center; + text-decoration: none; + text-shadow: 0 1px 1px black; + border-radius: 3px; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + box-shadow: 0 0 5px black; + -moz-box-shadow: 0 0 5px black; + -webkit-box-shadow: 0 0 5px black; +} + +a.finish:hover, +a.finish:focus { + cursor: pointer; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.2); + box-shadow: 0 0 15px black; + -moz-box-shadow: 0 0 15px black; + -webkit-box-shadow: 0 0 15px black; +} + +a.finish:active { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.3); +} + +a.finish.disabled { + opacity: 0.2; +} + +a.finish.disabled:hover, +a.finish.disabled:focus, +a.finish.disabled:active { + cursor: default; + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); +} + +.popup a.finish { + margin-top: 6px; + float: right; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/privacy.css b/sources/extend/addon/matrix/jappixmini/jappix/css/privacy.css new file mode 100644 index 00000000..521be322 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/privacy.css @@ -0,0 +1,197 @@ +/* + +Jappix - An open social platform +This is the privacy CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/02/11 + +*/ + +#privacy .content { + padding: 10px 0 10px 0; +} + +#privacy .privacy-head div.list-left, +#privacy .privacy-head div.list-center, +#privacy .privacy-head div.list-right, +#privacy .privacy-first { + float: left; +} + +#privacy .privacy-head div.list-left { + margin-left: 5px; +} + +#privacy .privacy-head div.list-center { + border-right: 1px dotted #1b393f; + height: 24px; + width: 1px; + margin-right: 15px; + padding-left: 18px; +} + +#privacy .privacy-head span, +#privacy .privacy-head a, +#privacy .privacy-item span, +#privacy .privacy-item a { + float: left; +} + +#privacy .privacy-head span { + font-size: 0.9em; + font-weight: bold; + margin: 3px 10px 0 0; +} + +#privacy .privacy-head input, +#privacy .privacy-head select { + width: 180px; +} + +#privacy .privacy-head input { + margin-top: 1px; +} + +#privacy .privacy-head select, +#privacy .privacy-item select { + margin-top: -2px; +} + +#privacy .privacy-head span.left-space { + margin-left: 16px; +} + +#privacy .privacy-head a, +#privacy .privacy-item a { + width: 20px; + height: 20px; + padding: 0; + display: block; +} + +#privacy .privacy-item a.item-add { + background-position: 2px -1178px; +} + +#privacy .privacy-head a.list-remove, +#privacy .privacy-item a.item-remove { + background-position: 2px -1197px; +} + +#privacy .privacy-item a.item-save { + background-position: 3px -126px; + width: auto; + height: 19px; + padding: 1px 7px 0 21px; +} + +#privacy .privacy-item, +#privacy form, +#privacy .privacy-active { + clear: both; +} + +#privacy .privacy-item { + margin: 17px 12px; + font-size: 0.9em; +} + +#privacy .privacy-item span { + font-weight: bold; +} + +#privacy .privacy-item select { + width: 300px; + margin: -4px 30px 0 10px; +} + +#privacy .privacy-item a { + margin: -2px 6px 0 0; +} + +#privacy .privacy-first, +#privacy .privacy-second, +#privacy .privacy-third { + height: 195px; + font-size: 0.9em; + margin: 10px 0 0 10px; + float: left; +} + +#privacy .privacy-first, +#privacy .privacy-second { + border-right: 1px dotted #1b393f; + padding-right: 14px; +} + +#privacy .privacy-first { + width: 125px; +} + +#privacy .privacy-first label { + margin: 50px 0 0 15px; +} + +#privacy .privacy-first label input { + margin-top: 2px; +} + +#privacy .privacy-second { + width: 205px; +} + +#privacy .privacy-second label { + margin: 2px 0 0 12px; +} + +#privacy .privacy-second input[type=radio], +#privacy .privacy-third input[type=checkbox] { + margin-top: 2px; + margin-bottom: 2px; +} + +#privacy .privacy-second input[type=text], +#privacy .privacy-second select { + width: 170px; + margin: 2px 0 11px 12px; + float: none; +} + +#privacy .privacy-third label { + width: auto; + margin-top: 11px; +} + +#privacy .privacy-third { + width: 240px; +} + +#privacy .privacy-active { + margin: 34px 16px 0 16px; + font-size: 0.9em; +} + +#privacy .privacy-active-elements { + float: right; +} + +#privacy .privacy-active input[type=text] { + width: 30px; + margin: 0 0 0 8px; + float: none; +} + +#privacy .privacy-active input[type=checkbox] { + margin: 2px 8px 0 0; + float: left; +} + +#privacy .privacy-active label { + width: auto; + margin: 0 15px 0 0; + clear: none; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/rosterx.css b/sources/extend/addon/matrix/jappixmini/jappix/css/rosterx.css new file mode 100644 index 00000000..4f159ac8 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/rosterx.css @@ -0,0 +1,53 @@ +/* + +Jappix - An open social platform +This is the Roster Item Exchange tool CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 05/02/11 + +*/ + +#rosterx .content { + padding: 10px 0 10px 0; +} + +#rosterx .rosterx-head a { + font-size: 0.9em; + margin: 3px 4px; + float: left; +} + +#rosterx .oneresult:hover { + cursor: pointer; +} + +#rosterx .oneresult span { + margin: 2px 5px 0 5px; + overflow: hidden; + float: left; +} + +#rosterx .oneresult span.name { + width: 230px; + font-weight: bold; +} + +#rosterx .oneresult span.xid { + width: 270px; + font-size: 0.9em; +} + +#rosterx .oneresult span.action { + width: 16px; + height: 16px; + margin-top: 4px; + float: right; +} + +#rosterx .oneresult span.action.modify { + background-position: 0 -1244px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/search.css b/sources/extend/addon/matrix/jappixmini/jappix/css/search.css new file mode 100644 index 00000000..505b17d9 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/search.css @@ -0,0 +1,60 @@ +/* + +Jappix - An open social platform +This is the search tool CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 23/01/11 + +*/ + +.search { + position: relative; +} + +.search input.suggested { + border-bottom: 1px solid white; + border-bottom-right-radius: 0; + border-bottom-left-radius: 0; + -moz-border-radius-bottomright: 0; + -moz-border-radius-bottomleft: 0; + -webkit-border-bottom-right-radius: 0; + -webkit-border-bottom-left-radius: 0; +} + +.search ul { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.9); + border-color: #e1a014; + border-style: solid; + border-width: 0 1px 1px 1px; + position: absolute; + z-index: 1; + padding: 3px 0; + list-style: none; + overflow: auto; + border-bottom-right-radius: 3px; + border-bottom-left-radius: 3px; + -moz-border-radius-bottomright: 3px; + -moz-border-radius-bottomleft: 3px; + -webkit-border-bottom-right-radius: 3px; + -webkit-border-bottom-left-radius: 3px; +} + +.search ul li { + padding: 2px 6px; + color: #3d3d3d; + text-shadow: none; +} + +.search ul li:hover { + cursor: pointer; +} + +.search ul li.hovered { + background-color: rgb(225,160,20); + background-color: rgba(225,160,20,0.3); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/smileys.css b/sources/extend/addon/matrix/jappixmini/jappix/css/smileys.css new file mode 100644 index 00000000..faad478b --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/smileys.css @@ -0,0 +1,196 @@ +/* + +Jappix - An open social platform +This is the smileys CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/02/11 + +*/ + +.emoticon { + width: 16px; + height: 16px; +} + +a.emoticon { + margin: 2px; + float: left; +} + +a.emoticon:hover, +a.emoticon:focus { + opacity: 0.8; +} + +a.emoticon:active { + opacity: 0.7; +} + +img.emoticon { + border: 0 none; + vertical-align: bottom; +} + +.emoticon-biggrin { + background-position: 0 0; +} + +.emoticon-devil { + background-position: -16px 0; +} + +.emoticon-coolglasses { + background-position: -32px 0; +} + +.emoticon-tongue { + background-position: -48px 0; +} + +.emoticon-smile { + background-position: -64px 0; +} + +.emoticon-wink { + background-position: -80px 0; +} + +.emoticon-blush { + background-position: -96px 0; +} + +.emoticon-stare { + background-position: -112px 0; +} + +.emoticon-frowning { + background-position: -128px 0; +} + +.emoticon-oh { + background-position: -144px 0; +} + +.emoticon-unhappy { + background-position: -160px 0; +} + +.emoticon-cry { + background-position: -176px 0; +} + +.emoticon-angry { + background-position: -192px 0; +} + +.emoticon-puke { + background-position: -208px 0; +} + +.emoticon-hugright { + background-position: -224px 0; +} + +.emoticon-hugleft { + background-position: -240px 0; +} + +.emoticon-lion { + background-position: -256px 0; +} + +.emoticon-pussy { + background-position: -272px 0; +} + +.emoticon-bat { + background-position: -288px 0; +} + +.emoticon-kiss { + background-position: -304px 0; +} + +.emoticon-heart { + background-position: -320px 0; +} + +.emoticon-brheart { + background-position: -336px 0; +} + +.emoticon-flower { + background-position: -352px 0; +} + +.emoticon-brflower { + background-position: -368px 0; +} + +.emoticon-thumbup { + background-position: -384px 0; +} + +.emoticon-thumbdown { + background-position: -400px 0; +} + +.emoticon-lamp { + background-position: -416px 0; +} + +.emoticon-coffee { + background-position: -432px 0; +} + +.emoticon-drink { + background-position: -448px 0; +} + +.emoticon-beer { + background-position: -464px 0; +} + +.emoticon-boy { + background-position: -480px 0; +} + +.emoticon-girl { + background-position: -496px 0; +} + +.emoticon-phone { + background-position: -512px 0; +} + +.emoticon-photo { + background-position: -528px 0; +} + +.emoticon-music { + background-position: -544px 0; +} + +.emoticon-cuffs { + background-position: -560px 0; +} + +.emoticon-mail { + background-position: -576px 0; +} + +.emoticon-rainbow { + background-position: -592px 0; +} + +.emoticon-star { + background-position: -608px 0; +} + +.emoticon-moon { + background-position: -624px 0; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/stats-svg.css b/sources/extend/addon/matrix/jappixmini/jappix/css/stats-svg.css new file mode 100644 index 00000000..f512a939 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/stats-svg.css @@ -0,0 +1,71 @@ +/* + +Jappix - An open social platform +This is the SVG stats CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Erwan Briand, Vanaryon +Last revision: 20/11/10 + +*/ + +svg { + background-color: #e8f1f3; +} + +.refline { + stroke: #596171; + stroke-width: 2px; +} + +.refleft { + fill: #000000; + font-family: "Inconsolata", "DejaVu Serif sans", Verdana, sans-serif; + font-size: 8px; +} + +.reftext { + fill: #586070; + font-family: "Inconsolata", "DejaVu Serif sans", Verdana, sans-serif; + font-size: 10px; +} + +.bubbletextblue, +.bubbletextred { + fill: none; + font-family: "Inconsolata", "DejaVu Serif sans", Verdana, sans-serif; + font-size: 8px; + text-anchor: end; +} + +.bluebar { + fill: "#6C84C0"; + fill-opacity: "0.6"; +} + +.gbar:hover .bluebar { + fill: #2A3F73; +} + +.gbar:hover .redbar { + fill: #C70705; +} + +.gbar:hover #bubble { + fill: white; + stroke: grey; +} + +.gbar:hover .bubbletextblue { + fill: #2A3F73; +} + +.gbar:hover .bubbletextred { + fill: #C70705; +} + +.gbar:hover .reftext { + fill: #000000; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/tools.css b/sources/extend/addon/matrix/jappixmini/jappix/css/tools.css new file mode 100644 index 00000000..8b689f54 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/tools.css @@ -0,0 +1,346 @@ +/* + +Jappix - An open social platform +This is the tools CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 27/08/11 + +*/ + +#top-content .tools { + background-color: rgb(232,241,243); + background-color: rgba(232,241,243,0.6); + padding: 3px 8px 5px 8px; + min-width: 10px; + height: 17px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; +} + +#top-content .tools a { + color: black; + padding: 0 3px; + margin: 0 1.5px; +} + +#top-content .tools a:hover, +#top-content .tools a:focus { + cursor: pointer; + text-decoration: underline; +} + +#top-content .tools-logo { + background-position: 9px 2px; + width: 74px; + float: left; +} + +#top-content .tools-all { + float: right; + text-align: right; + margin-left: 8px; + font-size: 0.9em; + color: black; +} + +#top-content .notifications { + background-position: 7px -1264px; +} + +#top-content .music { + background-position: 6px -1286px; +} + +#top-content .notifications:hover, +#top-content .music:hover { + cursor: pointer; +} + +#top-content .music:hover, +#top-content .notifications:hover, +#top-content .music:focus, +#top-content .notifications:focus { + background-color: rgb(232,241,243); + background-color: rgba(232,241,243,0.7); +} + +#top-content .music:active, +#top-content .notifications:active { + background-color: rgb(232,241,243); + background-color: rgba(232,241,243,0.8); +} + +#top-content .actived, +#top-content .actived:hover, +#top-content .actived:focus, +#top-content .actived:active { + background-color: rgb(232,241,243) !important; + background-color: rgba(232,241,243,0.9) !important; +} + +#top-content .notify { + background-color: #c60505; + color: white; + font-size: 0.7em; + font-weight: bold; + margin-left: -10px; + padding: 1px 4px; + position: absolute; + bottom: -2px; + border-radius: 10px; + -moz-border-radius: 10px; + -webkit-border-radius: 10px; +} + +#top-content .tools-content { + display: none; + position: absolute; + top: 25px; + margin-left: -8px; +} + +.tools-content-subarrow { + background-position: 0 -241px; + opacity: 0.8; + height: 10px; + width: 18px; + margin-left: 12px; +} + +.tools-content-subitem { + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.8); + padding: 14px 6px 6px 6px; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; +} + +.notifications-content { + width: 240px; +} + +.notifications-content .tools-content-subitem { + max-height: 250px; + color: white; + text-shadow: 0 1px 1px black; + text-align: left; + overflow-x: none; + overflow-y: auto; +} + +.notifications-content .empty { + color: white; + font-size: 0.9em; + text-decoration: underline; + margin: -8px 4px 2px 0; + display: none; + float: right; +} + +.notifications-content .nothing { + font-size: 0.9em; + margin: 5px; +} + +.notifications-content .one-notification { + padding: 6px 4px; + font-size: 0.85em; + clear: both; + border-radius: 2px; + -moz-border-radius: 2px; + -webkit-border-radius: 2px; +} + +.notifications-content .one-notification:hover, +.notifications-content .one-notification:focus { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.1); +} + +.notifications-content .one-notification:active { + background-color: rgb(255,255,255); + background-color: rgba(255,255,255,0.2); +} + +.notifications-content .avatar-container { + float: left; + width: 40px; + height: 40px; + margin: 0 8px 8px 0; + text-align: center; + background-repeat: no-repeat; +} + +.notifications-content .avatar { + max-width: 40px; + max-height: 40px; +} + +.notifications-content .notification-text, +.notifications-content .notification-actions { + margin-left: 48px; + overflow: hidden; +} + +.notifications-content .notification-actions { + margin-top: 3px; +} + +.notifications-content .notification-actions a { + color: white; + font-weight: bold; + font-size: 0.9em; + text-decoration: underline; + margin-right: 8px; +} + +.notifications-content .one-notification .notification-actions span.talk-images { + background-position: 0 -1828px; + width: 16px; + height: 16px; + margin: -1px 6px 0 0; + float: left; +} + +.notifications-content .one-notification[data-type=subscribe] .notification-actions span.talk-images { + background-position: 0 -1796px; +} + +.notifications-content .one-notification[data-type=invite_room] .notification-actions span.talk-images { + background-position: 0 -1812px; +} + +.notifications-content .one-notification[data-type=send] .notification-actions span.talk-images, +.notifications-content .one-notification[data-type=send_accept] .notification-actions span.talk-images, +.notifications-content .one-notification[data-type=send_reject] .notification-actions span.talk-images, +.notifications-content .one-notification[data-type=send_fail] .notification-actions span.talk-images { + background-position: 0 -1956px; +} + +.notifications-content .one-notification[data-type=rosterx] .notification-actions span.talk-images { + background-position: 0 -1844px; +} + +.notifications-content .one-notification[data-type=comment] .notification-actions span.talk-images { + background-position: 0 -1860px; +} + +.notifications-content .one-notification[data-type=like] .notification-actions span.talk-images { + background-position: 0 -1876px; +} + +.notifications-content .one-notification[data-type=quote] .notification-actions span.talk-images { + background-position: 0 -1892px; +} + +.notifications-content .one-notification[data-type=wall] .notification-actions span.talk-images { + background-position: 0 -1908px; +} + +.notifications-content .one-notification[data-type=photo] .notification-actions span.talk-images { + background-position: 0 -1924px; +} + +.notifications-content .one-notification[data-type=video] .notification-actions span.talk-images { + background-position: 0 -1940px; +} + +.music-content { + width: 220px; +} + +.music-content .tools-content-subitem { + height: 247px; +} + +.music-content .player { + background: #b5d5db; + background: -moz-linear-gradient(top, #b5d5db, #adced4); + background: -webkit-gradient(linear, left top, left bottom, from(#b5d5db), to(#adced4)); + height: 20px; + padding: 2px 5px; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + -moz-border-radius-topright: 4px; + -moz-border-radius-topleft: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-top-left-radius: 4px; +} + +.music-content .player a { + margin: 2px; + height: 16px; + width: 16px; + float: left; +} + +.music-content .player a:hover, +.music-content .player a:focus { + opacity: 0.8; +} + +.music-content .player a:active { + opacity: 0.6; +} + +.music-content .stop { + display: none; + background-position: 0 -270px; +} + +.music-content .list { + background-color: #e8f1f3; + height: 188px; + padding: 5px; + text-align: left; + overflow-y: auto; + overflow-x: hidden; +} + +.music-content p.no-results { + display: none; + color: black; + font-size: 0.9em; +} + +.music-content div.special { + padding-bottom: 2px; + margin-bottom: 6px; + border-bottom: 1px solid #c3d4d7; +} + +.music-content .song { + display: block; + margin: 3px 0; + font-size: 0.8em; +} + +.music-content .playing { + font-weight: bold; +} + +.music-content .search { + background-color: #e8f1f3; + height: 25px; + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-border-bottom-right-radius: 4px; +} + +.music-content .search input { + margin: 2px; + width: 198px; + height: 15px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/userinfos.css b/sources/extend/addon/matrix/jappixmini/jappix/css/userinfos.css new file mode 100644 index 00000000..59bab655 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/userinfos.css @@ -0,0 +1,100 @@ +/* + +Jappix - An open social platform +This is the user-infos CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 27/03/11 + +*/ + +#userinfos .content { + overflow: auto; +} + +#userinfos .one-lap a { + text-decoration: underline; +} + +#userinfos .main-infos { + margin: 20px 20px 8px 20px; + height: 120px; + background: white; + position: relative; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} + +#userinfos .avatar-container { + float: left; + text-align: center; + margin: 20px 35px; + width: 80px; + height: 80px; +} + +#userinfos .avatar { + max-width: 80px; + max-height: 80px; +} + +#userinfos h1, +#userinfos h2, +#userinfos h3 { + width: 410px; + overflow: hidden; +} + +#userinfos h1 { + font-size: 2em; + padding-top: 12px; + margin-bottom: 4px; +} + +#userinfos h2 { + color: #447079; + font-size: 1.1em; + margin-bottom: 10px; +} + +#userinfos h3 { + color: #6e8388; + font-size: 0.8em; +} + +#userinfos .main-infos div.shortcuts { + position: absolute; + top: 10px; + right: 12px; +} + +#userinfos .block-infos { + margin: 7px 20px; + float: left; +} + +#userinfos .one-line { + margin: 4px 0; + font-size: 0.9em; + float: left; +} + +#userinfos .one-line b { + width: 120px; + float: left; +} + +#userinfos .one-line span.reset-info { + float: left; + width: 460px; +} + +#userinfos textarea { + margin: 30px 0 0 30px; + width: 572px; + height: 292px; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/vcard.css b/sources/extend/addon/matrix/jappixmini/jappix/css/vcard.css new file mode 100644 index 00000000..59dfc486 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/vcard.css @@ -0,0 +1,106 @@ +/* + +Jappix - An open social platform +This is the vCard CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 16/01/12 + +*/ + +#vcard label { + font-size: 0.94em; + margin-top: 2px; +} + +#vcard #vcard-avatar input[type=file] { + margin-left: 15px; +} + +#vcard .avatar-container { + float: left; + text-align: center; + margin: 20px 0 35px 35px; + max-width: 96px; + max-height: 96px; +} + +#vcard .avatar { + max-width: 96px; + max-height: 96px; +} + +#vcard .avatar-delete { + background-position: 3px -1195px; + margin: 12px 25px 0 025px; + padding-left: 20px; + font-size: 0.9em; + float: right; +} + +#vcard .no-avatar { + width: 300px; + color: #7c2222; + padding: 10px; + margin: 15px 0 20px 40px; + background: #f8cece; + border: 1px #ba6d6d solid; + font-size: 0.8em; +} + +#vcard .forms textarea { + height: 111px; + width: 358px; + margin: 5px 12px 10px 12px; +} + +#vcard .forms .avatar-info { + border-width: 1px; + border-style: solid; + display: none; + width: 370px; + height: 15px; + font-size: 0.85em; + padding: 10px; +} + +#vcard .forms .avatar-wait { + background-color: #9bcbed; + color: #0a3858; + border-color: #306780; +} + +#vcard .forms .avatar-ok { + background-color: #c4ed9b; + color: #325213; + border-color: #578030; +} + +#vcard .forms .avatar-error { + background-color: #e79595; + color: #6a0b0b; + border-color: #7c1010; +} + +#vcard .infos { + width: 179px; + height: 328px; + margin: 15px 15px 15px 0; + padding: 0 8px; + float: right; +} + +#vcard .infos a { + text-decoration: underline; +} + +#vcard .send { + float: right; +} + +#vcard .send:hover { + cursor: pointer; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/css/welcome.css b/sources/extend/addon/matrix/jappixmini/jappix/css/welcome.css new file mode 100644 index 00000000..71b31ef2 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/css/welcome.css @@ -0,0 +1,170 @@ +/* + +Jappix - An open social platform +This is the welcome tool CSS stylesheet for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 26/04/11 + +*/ + +#welcome .infos { + margin: 15px; +} + +#welcome .infos p { + margin-top: 6px; +} + +#welcome .infos p.infos-title { + margin-top: 0; +} + +#welcome a.box { + background-color: #e4eef9; + border: 1px solid #ccdbde; + margin: 12px 11px 4px 15px; + padding: 10px; + width: 270px; + text-decoration: none; + float: left; + border-radius: 4px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; +} + +#welcome a.box.share { + width: 350px; + margin: 4px 130px; + padding: 4px 10px; + clear: both; +} + +#welcome a.box.share.first { + margin-top: 0; +} + +#welcome a.box.share:hover span.go { + display: block; +} + +#welcome a.box:hover, +#welcome a.box:focus { + border: 1px solid #93c5fa; +} + +#welcome a.box:active { + border: 1px solid #419afa; +} + +#welcome a.box.enabled { + background-color: #f1f6fd; + border: 1px solid #9dc4fc; +} + +#welcome a.box span { + margin: 3px 0; + display: block; +} + +#welcome a.box span.logo { + height: 35px; + width: 35px; + margin-right: 15px; + float: left; +} + +#welcome a.box span.logo.facebook { + background-position: 0 0; +} + +#welcome a.box span.logo.twitter { + background-position: -35px 0; +} + +#welcome a.box span.logo.buzz { + background-position: -70px 0; +} + +#welcome a.box span.logo.identica { + background-position: -105px 0; +} + +#welcome a.box span.option, +#welcome a.box span.name { + font-size: 0.9em; + font-weight: bold; +} + +#welcome a.box span.description { + font-size: 0.7em; + margin-top: 7px; +} + +#welcome a.box.share span.description { + margin-top: 4px; +} + +#welcome a.box span.image { + height: 16px; + width: 16px; + margin: -30px 12px 0 0; + float: right; +} + +#welcome a.box span.image.sound { + background-position: 0 -900px; +} + +#welcome a.box span.image.geolocation { + background-position: 0 -658px; +} + +#welcome a.box span.image.xmpp { + background-position: 0 -990px; +} + +#welcome a.box span.image.archives, +#page-engine .text .tools-archives { + background-position: 0 -1025px; +} + +#welcome a.box span.image.offline { + background-position: 0 -80px; +} + +#welcome a.box span.tick, +#welcome a.box span.go { + height: 16px; + width: 16px; + display: none; + float: right; +} + +#welcome a.box span.tick { + background-position: 0 -1661px; + margin: -52px -15px 0 0; +} + +#welcome a.box span.go { + background-position: 0 -1120px; + margin: -28px 5px 0 0; +} + +#welcome a.box.enabled span.tick { + display: block; +} + +#welcome div.results { + margin: -7px 15px; + padding: 0; + height: 272px; + overflow: auto; +} + +#welcome .bottom .finish.save { + display: none; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/others/blank.gif b/sources/extend/addon/matrix/jappixmini/jappix/img/others/blank.gif new file mode 100644 index 00000000..35d42e80 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/others/blank.gif differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/others/default-avatar.png b/sources/extend/addon/matrix/jappixmini/jappix/img/others/default-avatar.png new file mode 100644 index 00000000..7cda4c64 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/others/default-avatar.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/others/lock.png b/sources/extend/addon/matrix/jappixmini/jappix/img/others/lock.png new file mode 100644 index 00000000..cba6c0d3 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/others/lock.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.gif b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.gif new file mode 100644 index 00000000..cbf55da5 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.gif differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.png new file mode 100644 index 00000000..3d89e5db Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/animate.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/background.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/background.png new file mode 100644 index 00000000..4ae286d8 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/background.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/browsers.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/browsers.png new file mode 100644 index 00000000..8fadb7b3 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/browsers.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/buttons.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/buttons.png new file mode 100644 index 00000000..4c32b14d Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/buttons.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/home.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/home.png new file mode 100644 index 00000000..cd3ca4a1 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/home.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/install.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/install.png new file mode 100644 index 00000000..e2f4cd26 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/install.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/logs.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/logs.png new file mode 100644 index 00000000..bae4fb18 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/logs.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/manager.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/manager.png new file mode 100644 index 00000000..d63a3fec Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/manager.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/me.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/me.png new file mode 100644 index 00000000..8a8bc0fb Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/me.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.gif b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.gif new file mode 100644 index 00000000..3f3f9523 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.gif differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.png new file mode 100644 index 00000000..6852274d Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mini.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mobile.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mobile.png new file mode 100644 index 00000000..ba36a24c Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/mobile.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/smileys.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/smileys.png new file mode 100644 index 00000000..1c33243d Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/smileys.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/talk.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/talk.png new file mode 100644 index 00000000..a307e19e Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/talk.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/welcome.png b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/welcome.png new file mode 100644 index 00000000..9044bd9c Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/sprites/welcome.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-big.gif b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-big.gif new file mode 100644 index 00000000..c6573207 Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-big.gif differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-medium.png b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-medium.png new file mode 100644 index 00000000..4b9a780b Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-medium.png differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-small.gif b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-small.gif new file mode 100644 index 00000000..c4b5787e Binary files /dev/null and b/sources/extend/addon/matrix/jappixmini/jappix/img/wait/wait-small.gif differ diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/adhoc.js b/sources/extend/addon/matrix/jappixmini/jappix/js/adhoc.js new file mode 100644 index 00000000..d4e3bf4c --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/adhoc.js @@ -0,0 +1,85 @@ +/* + +Jappix - An open social platform +These are the Ad-Hoc JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 11/07/11 + +*/ + +// Opens the adhoc popup +function openAdHoc() { + // Popup HTML content + var html = + '
' + _e("Commands") + '
' + + + '
' + + '
' + + + '
' + + '
' + + + '
' + + '
' + + + '' + _e("Close") + '' + + '
'; + + // Create the popup + createPopup('adhoc', html); + + // Associate the events + launchAdHoc(); + + return false; +} + +// Quits the adhoc popup +function closeAdHoc() { + // Destroy the popup + destroyPopup('adhoc'); + + return false; +} + +// Retrieves an entity adhoc command +function retrieveAdHoc(xid) { + // Open the popup + openAdHoc(); + + // Add a XID marker + $('#adhoc .adhoc-head').html('' + getBuddyName(xid).htmlEnc() + ' (' + xid.htmlEnc() + ')'); + + // Get the highest entity resource + var highest = getHighestResource(xid); + + if(highest) + xid = highest; + + // Start a new adhoc command + dataForm(xid, 'command', '', '', 'adhoc'); + + return false; +} + +// Starts an adhoc command on the user server +function serverAdHoc(server) { + // Open the popup + openAdHoc(); + + // Add a XID marker + $('#adhoc .adhoc-head').html('' + server.htmlEnc() + ''); + + // Start a new adhoc command + dataForm(server, 'command', '', '', 'adhoc'); +} + +// Plugin launcher +function launchAdHoc() { + // Click event + $('#adhoc .bottom .finish').click(closeAdHoc); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/anonymous.js b/sources/extend/addon/matrix/jappixmini/jappix/js/anonymous.js new file mode 100644 index 00000000..88eaa7dc --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/anonymous.js @@ -0,0 +1,131 @@ +/* + +Jappix - An open social platform +These are the anonymous mode JS script for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, LinkMauve +Last revision: 02/10/11 + +*/ + +// Connected to an anonymous session +function anonymousConnected(con) { + logThis('Jappix (anonymous) is now connected.', 3); + + // Connected marker + CONNECTED = true; + CURRENT_SESSION = true; + RECONNECT_TRY = 0; + RECONNECT_TIMER = 0; + + // Not resumed? + if(!RESUME) { + // Create the app + createTalkPage(); + + // Send our first presence + firstPresence(''); + + // Set last activity stamp + LAST_ACTIVITY = getTimeStamp(); + + // Create the new groupchat + checkChatCreate(generateXID(ANONYMOUS_ROOM, 'groupchat'), 'groupchat'); + + // Remove some nasty elements for the anonymous mode + $('.tools-mucadmin, .tools-add').remove(); + } + + // Resumed + else { + // Send again our presence + presenceSend(); + + // Change the title + updateTitle(); + } + + // Remove the waiting icon + removeGeneralWait(); +} + +// Disconnected from an anonymous session +function anonymousDisconnected() { + logThis('Jappix (anonymous) is now disconnected.', 3); +} + +// Logins to a anonymous account +function anonymousLogin(server) { + try { + // We define the http binding parameters + oArgs = new Object(); + + if(HOST_BOSH_MAIN) + oArgs.httpbase = HOST_BOSH_MAIN; + else + oArgs.httpbase = HOST_BOSH; + + // We create the new http-binding connection + con = new JSJaCHttpBindingConnection(oArgs); + + // And we handle everything that happen + con.registerHandler('message', handleMessage); + con.registerHandler('presence', handlePresence); + con.registerHandler('iq', handleIQ); + con.registerHandler('onconnect', anonymousConnected); + con.registerHandler('onerror', handleError); + con.registerHandler('ondisconnect', anonymousDisconnected); + + // We set the anonymous connection parameters + oArgs = new Object(); + oArgs.domain = server; + oArgs.authtype = 'saslanon'; + oArgs.resource = JAPPIX_RESOURCE + ' Anonymous (' + (new Date()).getTime() + ')'; + oArgs.secure = true; + oArgs.xmllang = XML_LANG; + + // We connect ! + con.connect(oArgs); + + // Change the page title + pageTitle('wait'); + } + + catch(e) { + // Logs errors + logThis('Error while anonymous loggin in: ' + e, 1); + + // Reset Jappix + anonymousDisconnected(); + + // Open an unknown error + openThisError(2); + } + + finally { + return false; + } +} + +// Plugin launcher +function launchAnonymous() { + logThis('Anonymous mode detected, connecting...', 3); + + // We add the login wait div + showGeneralWait(); + + // Get the vars + if(LINK_VARS['r']) + ANONYMOUS_ROOM = LINK_VARS['r']; + if(LINK_VARS['n']) + ANONYMOUS_NICK = LINK_VARS['n']; + + // Fire the login action + anonymousLogin(HOST_ANONYMOUS); +} + +// Launch this plugin! +$(document).ready(launchAnonymous); diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/archives.js b/sources/extend/addon/matrix/jappixmini/jappix/js/archives.js new file mode 100644 index 00000000..387a379f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/archives.js @@ -0,0 +1,418 @@ +/* + +Jappix - An open social platform +These are the archives functions for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 03/03/11 + +*/ + +// Opens the archive tools +function openArchives() { + // Popup HTML content + var html = + '
' + _e("Message archives") + '
' + + + '
' + + '
' + + '' + + + '
' + + '
' + + + '
' + + '' + + '' + _e("Please select a friend to view the chat history.") + '' + + '
' + + + '
' + + '
' + + + '
' + + '
' + + + '' + _e("Close") + '' + + '
'; + + // Create the popup + createPopup('archives', html); + + // Associate the events + launchArchives(); + + // Get all the buddies in our roster + var buddies = getAllBuddies(); + var options = ''; + + for(i in buddies) { + var current = buddies[i]; + + // Add the current buddy + options += ''; + } + + // Can append the buddy HTML code? + if(options) + $('#archives .filter .friend').append(options); + + return false; +} + +// Closes the archive tools +function closeArchives() { + // Destroy the popup + destroyPopup('archives'); + + return false; +} + +// Gets the archives list for a buddy +function getListArchives(xid) { + // Reset the archives viewer + $('#archives .logs').empty(); + + // Show the waiting icon + $('#archives .wait').show(); + + // Apply the ID + var id = genID(); + $('#archives').attr('data-session', id); + + // New IQ + var iq = new JSJaCIQ(); + iq.setType('get'); + iq.setID(id); + + var list = iq.appendNode('list', {'xmlns': NS_URN_ARCHIVE, 'with': xid}); + var set = list.appendChild(iq.buildNode('set', {'xmlns': NS_RSM})); + set.appendChild(iq.buildNode('max', {'xmlns': NS_RSM}, '0')); + + con.send(iq, handleListArchives); + + logThis('Getting archives list for: ' + xid + '...'); +} + +// Handles the archives list for a buddy +function handleListArchives(iq) { + // Hide the waiting icon + $('#archives .wait').hide(); + + // Any error? + if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']')) + return; + + // Get the last archive date + var last = $(iq.getNode()).find('list set changed').text(); + + // Any last archive? + if(last) { + // Read the date + var date = Date.jab2date(last); + + // Change the datepicker value + $('#archives .filter .date').DatePickerSetDate(date, true); + + // Retrieve the archives + checkChangeArchives(); + } + + logThis('Got archives list.', 2); +} + +// Gets the archives for a day +function getDayArchives(xid, date) { + // Reset the archives viewer + $('#archives .logs').empty(); + + // Show the waiting icon + $('#archives .wait').show(); + + // Apply the ID + var id = genID(); + $('#archives').attr('data-session', id); + + // New IQ + var iq = new JSJaCIQ(); + iq.setType('get'); + iq.setID(id); + + iq.appendNode('list', {'xmlns': NS_URN_ARCHIVE, 'with': xid, 'start': date + 'T00:00:00Z', 'end': date + 'T23:59:59Z'}); + + con.send(iq, handleDayArchives); + + logThis('Getting day archives (' + date + ') for: ' + xid + '...'); +} + +// Handles the archives for a day +function handleDayArchives(iq) { + // Hide the waiting icon + $('#archives .wait').hide(); + + // Any error? + if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']')) + return; + + // Get each archive thread + $(iq.getNode()).find('chat').each(function() { + // Current values + var xid = $(this).attr('with'); + var start = $(this).attr('start'); + + if(xid && start) + $('#archives .logs').append(''); + }); + + // Display the day + var date = parseDay($('#archives .filter .date').DatePickerGetDate(true) + 'T00:00:00Z' + getDateTZO()); + + // Try to get the first thread + var pending = '#archives input.archives-pending:first'; + + if(!exists(pending)) + date = printf(_e("Nothing found for: %s"), date); + + else { + retrieveArchives($(pending).attr('data-with'), $(pending).attr('data-start')); + $(pending).remove(); + } + + $('#archives .current .time').text(date); + + logThis('Got day archives.', 2); +} + +// Retrieves a specified archive collection +function retrieveArchives(xid, start) { + // Show the waiting icon + $('#archives .wait').show(); + + // Apply the ID + var id = genID(); + $('#archives').attr('data-session', id); + + // New IQ + var iq = new JSJaCIQ(); + iq.setType('get'); + iq.setID(id); + + var list = iq.appendNode('retrieve', {'xmlns': NS_URN_ARCHIVE, 'with': xid, 'start': start}); + + con.send(iq, handleRetrieveArchives); + + logThis('Retrieving archives (start: ' + start + ') for: ' + xid + '...'); +} + +// Handles a specified archive collection +function handleRetrieveArchives(iq) { + // Hide the waiting icon + $('#archives .wait').hide(); + + // Any error? + if(handleErrorReply(iq) || !exists('#archives[data-session=' + iq.getID() + ']')) + return; + + // Get the node + var chat = $(iq.getNode()).find('chat:first'); + + // Get the buddy XID + var xid = bareXID(chat.attr('with')); + + // Get the start date & stamp + var start_date = Date.jab2date(chat.attr('start')); + var start_stamp = extractStamp(start_date); + + // Parse the result chat + chat.find('to, from').each(function() { + var node = (this).nodeName; + var stamp = start_stamp + parseInt($(this).attr('secs')); + var date = extractTime(new Date(stamp * 1000)); + var body = $(this).find('body').text(); + + // Is it my message? + if((node == 'to') && body) + displayMessage('chat', getXID(), 'archives', getBuddyName(getXID()).htmlEnc(), body, date, start_stamp, 'user-message', true, '', 'me'); + + // Is it a buddy message? + else if((node == 'from') && body) + displayMessage('chat', xid, 'archives', getBuddyName(xid).htmlEnc(), body, date, start_stamp, 'user-message', true, '', 'him'); + }); + + // Not the latest thread? + var pending = '#archives input.archives-pending:first'; + + if(exists(pending)) { + retrieveArchives($(pending).attr('data-with'), $(pending).attr('data-start')); + $(pending).remove(); + } + + // Everything has been retrieved, get the avatars + else { + getAvatar(getXID(), 'cache', 'true', 'forget'); + getAvatar(xid, 'cache', 'true', 'forget'); + } + + logThis('Got archives.', 2); +} + +// Gets the archiving configuration +function getConfigArchives() { + // Lock the archiving options + $('#archiving').attr('checked', false).attr('disabled', true); + + // Get the archiving configuration + var iq = new JSJaCIQ(); + iq.setType('get'); + + iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE}); + + con.send(iq, handleGetConfigArchives); +} + +// Handles the archiving configuration +function handleGetConfigArchives(iq) { + // Reset the options stuffs + waitOptions('archives'); + + // Unlock the archiving options + $('#archiving').removeAttr('disabled'); + + // End if not a result + if(!iq || (iq.getType() != 'result')) + return; + + // Extract the preferences from the IQ + var enabled = $(iq.getNode()).find('pref auto').attr('save'); + + // Define the input enabling/disabling vars + var checked = true; + + if(enabled != 'true') + checked = false; + + // Apply the values + $('#archiving').attr('checked', checked); +} + +// Configures the archiving on the server +function configArchives(enabled) { + // Configure the auto element + var iq = new JSJaCIQ(); + iq.setType('set'); + + iq.appendNode('auto', {'xmlns': NS_URN_ARCHIVE, 'save': enabled}); + + con.send(iq, handleConfigArchives); + + // Configure the default element + var iq = new JSJaCIQ(); + iq.setType('set'); + + var pref = iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE}); + pref.appendChild(iq.appendNode('default', {'xmlns': NS_URN_ARCHIVE, 'otr': 'concede', 'save': 'body'})); + + con.send(iq); + + // Configure the method element + var iq = new JSJaCIQ(); + iq.setType('set'); + + var mType = new Array('auto', 'local', 'manual'); + var mUse = new Array('prefer', 'concede', 'concede'); + + var pref = iq.appendNode('pref', {'xmlns': NS_URN_ARCHIVE}); + + for(i in mType) + pref.appendChild(iq.appendNode('method', {'xmlns': NS_URN_ARCHIVE, 'type': mType[i], 'use': mUse[i]})); + + con.send(iq); + + // Logger + logThis('Configuring archives...', 3); +} + +// Handles the archives configuration +function handleConfigArchives(iq) { + if(!iq || (iq.getType() != 'result')) + logThis('Archives not configured.', 2); + else + logThis('Archives configured.', 3); +} + +// Checks if the datepicker has changed +function checkChangeArchives() { + var xid = $('#archives .filter .friend').val(); + var date = $('#archives .filter .date').DatePickerGetDate(true); + + // No XID? + if(!xid || !xid.length) + return; + + // Too many value? + if(xid.length > 1) { + $('#archives .filter .friend').val(xid[0]); + + return; + } + + // Get the first XID + xid = xid[0]; + + // Get the archives + getDayArchives(xid, date); +} + +// Update the archives with the selected XID +function updateArchives() { + // Read the values + var xid = $('#archives .filter .friend').val(); + var date = $('#archives .filter .date').DatePickerGetDate(true); + + // No XID? + if(!xid || !xid.length) + return; + + // Too many value? + if(xid.length > 1) { + $('#archives .filter .friend').val(xid[0]); + + return; + } + + // Get the first XID + xid = xid[0]; + + // Apply the current marker + $('#archives .current .name').text(getBuddyName(xid)); + $('#archives .current .time').text(parseDay(date + 'T00:00:00Z' + getDateTZO())); + + // Get the archives + getListArchives(xid, date); +} + +// Plugin launcher +function launchArchives() { + // Current date + var current_date = explodeThis('T', getXMPPTime(), 0); + + // Datepicker + $('#archives .filter .date').DatePicker({ + flat: true, + date: current_date, + current: current_date, + calendars: 1, + starts: 1, + onChange: checkChangeArchives + }); + + // Click events + $('#archives .bottom .finish').click(function() { + return closeArchives(); + }); + + // Change event + $('#archives .filter .friend').change(updateArchives); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/audio.js b/sources/extend/addon/matrix/jappixmini/jappix/js/audio.js new file mode 100644 index 00000000..f83583a9 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/audio.js @@ -0,0 +1,46 @@ +/* + +Jappix - An open social platform +These are the audio JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 10/08/11 + +*/ + +// Plays the given sound ID +function soundPlay(num) { + try { + // Not supported! + if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9)) + return false; + + // If the sounds are enabled + if(getDB('options', 'sounds') == '1') { + // If the audio elements aren't yet in the DOM + if(!exists('#audio')) { + $('body').append( + '
' + + '
' + ); + } + + // We play the target sound + var playThis = document.getElementById('audio').getElementsByTagName('audio')[num]; + playThis.load(); + playThis.play(); + } + } + + catch(e) {} + + finally { + return false; + } +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/autocompletion.js b/sources/extend/addon/matrix/jappixmini/jappix/js/autocompletion.js new file mode 100644 index 00000000..52d3c47e --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/autocompletion.js @@ -0,0 +1,99 @@ +/* + +Jappix - An open social platform +These are the autocompletion tools JS script for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 12/11/10 + +*/ + +// Sort an array with insensitivity to the case +function caseInsensitiveSort(a, b) { + // Put the two strings into lower case + a = a.toLowerCase(); + b = b.toLowerCase(); + + // Process the sort + if(a > b) + return 1; + if(a < b) + return -1; +} + +// Creates an array with the autocompletion results +function processAutocompletion(query, id) { + // Replace forbidden characters in regex + query = escapeRegex(query); + + // Create an empty array + var results = new Array(); + + // Search in the roster + $('#' + id + ' .user').each(function() { + var nick = $(this).find('.name').text(); + var regex = new RegExp('(^)' + query, 'gi'); + + if(nick.match(regex)) + results.push(nick); + }); + + // Sort the array + results = results.sort(caseInsensitiveSort); + + // Return the results array + return results; +} + +// Resets the autocompletion tools +function resetAutocompletion(hash) { + $('#' + hash + ' .message-area').removeAttr('data-autocompletion-pointer').removeAttr('data-autocompletion-query'); +} + +// Autocompletes the chat input nick +function createAutocompletion(hash) { + // Initialize + var vSelector = $('#' + hash + ' .message-area'); + var value = vSelector.val(); + if(!value) + resetAutocompletion(hash); + var query = vSelector.attr('data-autocompletion-query'); + + // The autocompletion has not been yet launched + if(query == undefined) { + query = value; + vSelector.attr('data-autocompletion-query', query); + } + + // Get the pointer + var pointer = vSelector.attr('data-autocompletion-pointer'); + var i = 0; + + if(pointer) + i = parseInt(pointer); + + // We get the nickname + var nick = processAutocompletion(query, hash)[i]; + + // Shit, this is my nick! + if((nick != undefined) && (nick.toLowerCase() == getMUCNick(hash).toLowerCase())) { + // Increment + i++; + + // Get the next nick + nick = processAutocompletion(query, hash)[i]; + } + + // We quote the nick + if(nick != undefined) { + // Increment + i++; + quoteMyNick(hash, nick); + + // Put a pointer + vSelector.attr('data-autocompletion-pointer', i); + } +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/avatar.js b/sources/extend/addon/matrix/jappixmini/jappix/js/avatar.js new file mode 100644 index 00000000..4234ffc7 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/avatar.js @@ -0,0 +1,205 @@ +/* + +Jappix - An open social platform +These are the avatar JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 01/03/11 + +*/ + +// Requests the avatar of a given user +var AVATAR_PENDING = []; + +function getAvatar(xid, mode, enabled, photo) { + /* REF: http://xmpp.org/extensions/xep-0153.html */ + + // No need to get the avatar, another process is yet running + if(existArrayValue(AVATAR_PENDING, xid)) + return false; + + // Initialize: XML data is in one SQL entry, because some browser are sloooow with SQL requests + var xml = XMLFromString(getPersistent('avatar', xid)); + var forced = false; + + // Retrieving forced? + if($(xml).find('forced').text() == 'true') + forced = true; + + // No avatar in presence + if(!photo && !forced && (enabled == 'true')) { + // Pending marker + AVATAR_PENDING.push(xid); + + // Reset the avatar + resetAvatar(xid, hex_md5(xid)); + + logThis('No avatar for: ' + xid, 2); + } + + // Try to catch the avatar + else { + // Define some stuffs + var type = $(xml).find('type').text(); + var binval = $(xml).find('binval').text(); + var checksum = $(xml).find('checksum').text(); + var updated = false; + + // Process the checksum of the avatar + if((checksum == photo) || (photo == 'forget') || forced) + updated = true; + + // If the avatar is yet stored and a new retrieving is not needed + if((mode == 'cache') && type && binval && checksum && updated) { + // Pending marker + AVATAR_PENDING.push(xid); + + // Display the cache avatar + displayAvatar(xid, hex_md5(xid), type, binval); + + logThis('Read avatar from cache: ' + xid, 3); + } + + // Else if the request has not yet been fired, we get it + else if((!updated || (mode == 'cache' && !updated) || (mode == 'force') || (photo = 'forget')) && (enabled != 'false')) { + // Pending marker + AVATAR_PENDING.push(xid); + + // Get the latest avatar + var iq = new JSJaCIQ(); + iq.setType('get'); + iq.setTo(xid); + + iq.appendNode('vCard', {'xmlns': NS_VCARD}); + + con.send(iq, handleAvatar); + + logThis('Get avatar from server: ' + xid, 3); + } + } + + return true; +} + +// Handles the avatar +function handleAvatar(iq) { + // Extract the XML values + var handleXML = iq.getNode(); + var handleFrom = fullXID(getStanzaFrom(iq)); + + // Is this me? Remove the resource! + if(bareXID(handleFrom) == getXID()) + handleFrom = bareXID(handleFrom); + + // Get some other values + var hash = hex_md5(handleFrom); + var find = $(handleXML).find('vCard'); + var aChecksum = 'none'; + var oChecksum = null; + + // Read our own checksum + if(handleFrom == getXID()) { + oChecksum = getDB('checksum', 1); + + // Avoid the "null" value + if(!oChecksum) + oChecksum = ''; + } + + // vCard not empty? + if(find.size()) { + // We get our profile details + if(handleFrom == getXID()) { + // Get the names + var names = generateBuddyName(iq); + + // Write the values to the database + setDB('profile', 'name', names[0]); + setDB('profile', 'nick', names[1]); + } + + // We get the avatar + var aType = find.find('TYPE:first').text(); + var aBinval = find.find('BINVAL:first').text(); + + // No binval? + if(!aBinval) { + aType = 'none'; + aBinval = 'none'; + } + + // Enough data + else { + // No type? + if(!aType) + aType = 'image/png'; + + // Process the checksum + else + aChecksum = hex_sha1(Base64.decode(aBinval)); + } + + // We display the user avatar + displayAvatar(handleFrom, hash, aType, aBinval); + + // Store the avatar + setPersistent('avatar', handleFrom, '' + aType + '' + aBinval + '' + aChecksum + 'false'); + + logThis('Avatar retrieved from server: ' + handleFrom, 3); + } + + // vCard is empty + else + resetAvatar(handleFrom); + + // We got a new checksum for us? + if(((oChecksum != null) && (oChecksum != aChecksum)) || !FIRST_PRESENCE_SENT) { + // Define a proper checksum + var pChecksum = aChecksum; + + if(pChecksum == 'none') + pChecksum = ''; + + // Update our temp. checksum + setDB('checksum', 1, pChecksum); + + // Send the stanza + if(FIRST_PRESENCE_SENT) + presenceSend(pChecksum); + else + getStorage(NS_OPTIONS); + } +} + +// Reset the avatar of an user +function resetAvatar(xid, hash) { + // Store the empty avatar + setPersistent('avatar', xid, 'nonenonenonefalse'); + + // Display the empty avatar + displayAvatar(xid, hash, 'none', 'none'); +} + +// Displays the avatar of an user +function displayAvatar(xid, hash, type, binval) { + // Initialize the vars + var container = hash + ' .avatar-container'; + var code = ''; + + // Replace with the new avatar (in the roster and in the chat) + $('.' + container).html(code); + + // We can remove the pending marker + removeArrayValue(AVATAR_PENDING, xid); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/base64.js b/sources/extend/addon/matrix/jappixmini/jappix/js/base64.js new file mode 100644 index 00000000..1cf2dc74 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/base64.js @@ -0,0 +1,80 @@ +// This code was written by Tyler Akins and has been placed in the +// public domain. It would be nice if you left this header intact. +// Base64 code from Tyler Akins -- http://rumkin.com + +var Base64 = (function () { + var keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + + var obj = { + /** + * Encodes a string in base64 + * @param {String} input The string to encode in base64. + */ + encode: function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + do { + chr1 = input.charCodeAt(i++); + chr2 = input.charCodeAt(i++); + chr3 = input.charCodeAt(i++); + + enc1 = chr1 >> 2; + enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); + enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); + enc4 = chr3 & 63; + + if (isNaN(chr2)) { + enc3 = enc4 = 64; + } else if (isNaN(chr3)) { + enc4 = 64; + } + + output = output + keyStr.charAt(enc1) + keyStr.charAt(enc2) + + keyStr.charAt(enc3) + keyStr.charAt(enc4); + } while (i < input.length); + + return output; + }, + + /** + * Decodes a base64 string. + * @param {String} input The string to decode. + */ + decode: function (input) { + var output = ""; + var chr1, chr2, chr3; + var enc1, enc2, enc3, enc4; + var i = 0; + + // remove all characters that are not A-Z, a-z, 0-9, +, /, or = + input = input.replace(/[^A-Za-z0-9\+\/\=]/g, ""); + + do { + enc1 = keyStr.indexOf(input.charAt(i++)); + enc2 = keyStr.indexOf(input.charAt(i++)); + enc3 = keyStr.indexOf(input.charAt(i++)); + enc4 = keyStr.indexOf(input.charAt(i++)); + + chr1 = (enc1 << 2) | (enc2 >> 4); + chr2 = ((enc2 & 15) << 4) | (enc3 >> 2); + chr3 = ((enc3 & 3) << 6) | enc4; + + output = output + String.fromCharCode(chr1); + + if (enc3 != 64) { + output = output + String.fromCharCode(chr2); + } + if (enc4 != 64) { + output = output + String.fromCharCode(chr3); + } + } while (i < input.length); + + return output; + } + }; + + return obj; +})(); diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/board.js b/sources/extend/addon/matrix/jappixmini/jappix/js/board.js new file mode 100644 index 00000000..1d26acee --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/board.js @@ -0,0 +1,141 @@ +/* + +Jappix - An open social platform +These are the notification board JS script for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 12/03/11 + +*/ + +// Creates a board panel +function createBoard(type, id) { + // Text var + var text = ''; + + // Info + if(type == 'info') { + switch(id) { + // Password change + case 1: + text = _e("Your password has been changed, now you can connect to your account with your new login data."); + + break; + + // Account deletion + case 2: + text = _e("Your XMPP account has been removed, bye!"); + + break; + + // Account logout + case 3: + text = _e("You have been logged out of your XMPP account, have a nice day!"); + + break; + + // Groupchat join + case 4: + text = _e("The room you joined seems not to exist. You should create it!"); + + break; + + // Groupchat removal + case 5: + text = _e("The groupchat has been removed, now someone else will be able to recreate it."); + + break; + + // Non-existant groupchat user + case 6: + text = _e("The user that you want to reach is not present in the room."); + + break; + } + } + + // Error + else { + switch(id) { + // Custom error + case 1: + text = '' + _e("Error") + ' » '; + + break; + + // Network error + case 2: + text = _e("Jappix has been interrupted by a network issue, a bug or bad login (check that you entered the right credentials), sorry for the inconvenience."); + + break; + + // List retrieving error + case 3: + text = _e("The element list on this server could not be obtained!"); + + break; + + // Attaching error + case 4: + text = printf(_e("An error occured while uploading your file: maybe it is too big (%s maximum) or forbidden!"), JAPPIX_MAX_UPLOAD); + + break; + } + } + + // No text? + if(!text) + return false; + + // Append the content + $('#board').append('
' + text + '
'); + + // Events (click and auto-hide) + $('#board .one-board.' + type + '[data-id=' + id + ']') + + .click(function() { + closeThisBoard(this); + }) + + .oneTime('5s', function() { + closeThisBoard(this); + }) + + .slideDown(); + + return true; +} + +// Destroys the existing board notifications +function destroyBoard() { + $('#board').empty(); +} + +// Executes a given action on the notification board +function actionBoard(id, type) { + // In a first, we destroy other boards + destroyBoard(); + + // Then we display the board + createBoard(type, id); +} + +// Opens a given error ID +function openThisError(id) { + actionBoard(id, 'error'); +} + +// Opens a given info ID +function openThisInfo(id) { + actionBoard(id, 'info'); +} + +// Closes a given board +function closeThisBoard(board) { + $(board).slideUp('normal', function() { + $(this).remove(); + }); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/browser-detect.js b/sources/extend/addon/matrix/jappixmini/jappix/js/browser-detect.js new file mode 100644 index 00000000..39edaf2b --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/browser-detect.js @@ -0,0 +1,124 @@ +/* BROWSER DETECT + * http://www.quirksmode.org/js/detect.html + */ + +var BrowserDetect = { + init: function () { + this.browser = this.searchString(this.dataBrowser) || "An unknown browser"; + this.version = this.searchVersion(navigator.userAgent) + || this.searchVersion(navigator.appVersion) + || "an unknown version"; + this.OS = this.searchString(this.dataOS) || "an unknown OS"; + }, + + searchString: function (data) { + for (var i=0;i ' + _e("no subject defined for this room.") + '

'; + specialCode = '

' + _e("Moderators") + '

' + _e("Participants") + '

' + _e("Visitors") + '

' + _e("Others") + '

'; + specialLink = ''; + specialStyle = ''; + + // Is this a gateway? + if(xid.match(/%/)) + specialDisabled = ''; + else + specialDisabled = ' disabled=""'; + } + + // Chat (or other things?!) special code + else { + specialAttributes = ' data-type="chat"'; + specialAvatar = '
'; + specialName = '

'; + specialCode = '
'; + specialLink = ''; + specialStyle = ' style="display: none;"'; + specialDisabled = ''; + } + + // Not a groupchat private chat, we can use the buddy add icon + if((type == 'chat') || (type == 'groupchat')) { + var addTitle; + + if(type == 'chat') + addTitle = _e("Add this contact to your friends"); + else + addTitle = _e("Add this groupchat to your favorites"); + + specialLink += ''; + } + + // IE DOM parsing bug fix + var specialStylePicker = '
' + + '' + + '
'; + + if((BrowserDetect.browser == 'Explorer') && (BrowserDetect.version < 9)) + specialStylePicker = ''; + + // Append the chat HTML code + $('#page-engine').append( + '
' + + '
' + + specialAvatar + + + '
' + + '

' + nick.htmlEnc() + '

' + + specialName + + '
' + + '
' + + + specialCode + + + '
' + + '' + + + '
' + + '' + + '
' + + '
' + + '
' + ); + + // Click event: chat cleaner + $(path + 'tools-clear').click(function() { + cleanChat(id); + }); + + // Click event: user-infos + $(path + 'tools-infos').click(function() { + openUserInfos(xid); + }); +} + +// Generates the chat switch elements +function generateSwitch(type, id, xid, nick) { + // Path to the element + var chat_switch = '#page-switch .'; + + // Special code + var specialClass = ' unavailable'; + var show_close = true; + + // Groupchat + if(type == 'groupchat') { + specialClass = ' groupchat-default'; + + if(isAnonymous() && (xid == generateXID(ANONYMOUS_ROOM, 'groupchat'))) + show_close = false; + } + + // Generate the HTML code + var html = '
' + + '
' + + + '
' + nick.htmlEnc() + '
'; + + // Show the close button if not MUC and not anonymous + if(show_close) + html += '
x
'; + + // Close the HTML + html += '
'; + + // Append the HTML code + $(chat_switch + 'chans, ' + chat_switch + 'more-content').append(html); +} + +// Cleans given the chat lines +function cleanChat(chat) { + $('#page-engine #' + chat + ' .content .one-group').remove(); + + $(document).oneTime(10, function() { + $('#page-engine #' + chat + ' .text .message-area').focus(); + }); +} + +// Creates a new chat +function chatCreate(hash, xid, nick, type) { + logThis('New chat: ' + xid, 3); + + // Create the chat content + generateChat(type, hash, xid, nick); + + // Create the chat switcher + generateSwitch(type, hash, xid, nick); + + // If the user is not in our buddy-list + if(type == 'chat') { + // Add button + if(!exists('#buddy-list .buddy[data-xid=' + escape(xid) + ']')) + $('#' + hash + ' .tools-add').click(function() { + // Hide the icon (to tell the user all is okay) + $(this).hide(); + + // Send the subscribe request + addThisContact(xid, nick); + }).show(); + + // Archives button + else if(enabledArchives() || enabledArchives('auto') || enabledArchives('manual') || enabledArchives('manage')) + $('#' + hash + ' .tools-archives').click(function() { + // Open the archives popup + openArchives(); + + // Get the archives for this user + $('#archives .filter .friend').val(xid); + updateArchives(); + }).show(); + } + + // We catch the user's informations (like this avatar, vcard, and so on...) + getUserInfos(hash, xid, nick, type); + + // The icons-hover functions + tooltipIcons(xid, hash); + + // The event handlers + var inputDetect = $('#page-engine #' + hash + ' .message-area'); + + inputDetect.focus(function() { + chanCleanNotify(hash); + }) + + inputDetect.keypress(function(e) { + // Enter key + if(e.keyCode == 13) { + // Add a new line + if(e.shiftKey) + inputDetect.val(inputDetect.val() + '\n'); + + // Send the message + else { + // Send the message + sendMessage(hash, 'chat'); + + // Reset the composing database entry + setDB('chatstate', xid, 'off'); + } + + return false; + } + }); + + // Chatstate events + eventsChatState(inputDetect, xid, hash); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/chatstate.js b/sources/extend/addon/matrix/jappixmini/jappix/js/chatstate.js new file mode 100644 index 00000000..de7e7966 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/chatstate.js @@ -0,0 +1,174 @@ +/* + +Jappix - An open social platform +These are the chatstate JS script for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 25/08/11 + +*/ + +// Sends a given chatstate to a given entity +function chatStateSend(state, xid, hash) { + var user_type = $('#' + hash).attr('data-type'); + + // If the friend client supports chatstates and is online + if((user_type == 'groupchat') || ((user_type == 'chat') && $('#' + hash + ' .message-area').attr('data-chatstates') && !exists('#page-switch .' + hash + ' .unavailable'))) { + // Already sent? + if(getDB('currentchatstate', xid) == state) + return; + + // Write the state + setDB('currentchatstate', xid, state); + + // New message stanza + var aMsg = new JSJaCMessage(); + aMsg.setTo(xid); + aMsg.setType(user_type); + + // Append the chatstate node + aMsg.appendNode(state, {'xmlns': NS_CHATSTATES}); + + // Send this! + con.send(aMsg); + } +} + +// Displays a given chatstate in a given chat +function displayChatState(state, hash, type) { + // Groupchat? + if(type == 'groupchat') { + resetChatState(hash, type); + + // "gone" state not allowed + if(state != 'gone') + $('#page-engine .page-engine-chan .user.' + hash).addClass(state); + } + + // Chat + else { + // We change the buddy name color in the page-switch + resetChatState(hash, type); + $('#page-switch .' + hash + ' .name').addClass(state); + + // We generate the chatstate text + var text = ''; + + switch(state) { + // Active + case 'active': + text = _e("Your friend is paying attention to the conversation."); + + break; + + // Composing + case 'composing': + text = _e("Your friend is writing a message..."); + + break; + + // Paused + case 'paused': + text = _e("Your friend stopped writing a message."); + + break; + + // Inactive + case 'inactive': + text = _e("Your friend is doing something else."); + + break; + + // Gone + case 'gone': + text = _e("Your friend closed the chat."); + + break; + } + + // We reset the previous state + $('#' + hash + ' .chatstate').remove(); + + // We create the chatstate + $('#' + hash + ' .content').after('
' + text + '
'); + } +} + +// Resets the chatstate switcher marker +function resetChatState(hash, type) { + // Define the selector + var selector; + + if(type == 'groupchat') + selector = $('#page-engine .page-engine-chan .user.' + hash); + else + selector = $('#page-switch .' + hash + ' .name'); + + // Reset! + selector.removeClass('active') + selector.removeClass('composing') + selector.removeClass('paused') + selector.removeClass('inactive') + selector.removeClass('gone'); +} + +// Adds the chatstate events +function eventsChatState(target, xid, hash) { + target.keyup(function(e) { + if(e.keyCode != 13) { + // Composing a message + if($(this).val() && (getDB('chatstate', xid) != 'on')) { + // We change the state detect input + setDB('chatstate', xid, 'on'); + + // We send the friend a "composing" chatstate + chatStateSend('composing', xid, hash); + } + + // Stopped composing a message + else if(!$(this).val() && (getDB('chatstate', xid) == 'on')) { + // We change the state detect input + setDB('chatstate', xid, 'off'); + + // We send the friend an "active" chatstate + chatStateSend('active', xid, hash); + } + } + }); + + target.change(function() { + // Reset the composing database entry + setDB('chatstate', xid, 'off'); + }); + + target.focus(function() { + // Not needed + if(target.is(':disabled')) + return; + + // Nothing in the input, user is active + if(!$(this).val()) + chatStateSend('active', xid, hash); + + // Something was written, user started writing again + else + chatStateSend('composing', xid, hash); + }); + + target.blur(function() { + // Not needed + if(target.is(':disabled')) + return; + + // Nothing in the input, user is inactive + if(!$(this).val()) + chatStateSend('inactive', xid, hash); + + // Something was written, user paused + else + chatStateSend('paused', xid, hash); + }); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/common.js b/sources/extend/addon/matrix/jappixmini/jappix/js/common.js new file mode 100644 index 00000000..ab10d6e7 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/common.js @@ -0,0 +1,311 @@ +/* + +Jappix - An open social platform +These are the common JS script for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, olivierm +Last revision: 24/06/11 + +*/ + +// Checks if an element exists in the DOM +function exists(selector) { + if(jQuery(selector).size() > 0) + return true; + else + return false; +} + +// Checks if Jappix is connected +function isConnected() { + if((typeof con != 'undefined') && con && con.connected()) + return true; + + return false; +} + +// Checks if Jappix has focus +function isFocused() { + try { + if(document.hasFocus()) + return true; + + return false; + } + + catch(e) { + return true; + } +} + +// Generates the good XID +function generateXID(xid, type) { + // XID needs to be transformed + if(xid && (xid.indexOf('@') == -1)) { + // Groupchat + if(type == 'groupchat') + return xid + '@' + HOST_MUC; + + // One-to-one chat + if(xid.indexOf('.') == -1) + return xid + '@' + HOST_MAIN; + + // It might be a gateway? + return xid; + } + + // Nothing special (yet bare XID) + return xid; +} + +// Gets the asked translated string +function _e(string) { + return string; +} + +// Replaces '%s' to a given value for a translated string +function printf(string, value) { + return string.replace('%s', value); +} + +// Properly explodes a string with a given character +function explodeThis(toEx, toStr, i) { + // Get the index of our char to explode + var index = toStr.indexOf(toEx); + + // We split if necessary the string + if(index != -1) { + if(i == 0) + toStr = toStr.substr(0, index); + else + toStr = toStr.substr(index + 1); + } + + // We return the value + return toStr; +} + +// Cuts the resource of a XID +function cutResource(aXID) { + return explodeThis('/', aXID, 0); +} + +// Gets the resource of a XID +function thisResource(aXID) { + // Any resource? + if(aXID.indexOf('/') != -1) + return explodeThis('/', aXID, 1); + + // No resource + return ''; +} + +// Does stringprep on a string +function stringPrep(string) { + // Replacement arrays + var invalid = new Array('Å ', 'Å¡', 'Ä', 'Ä‘', 'Ž', 'ž', 'ÄŒ', 'Ä', 'Ć', 'ć', 'À', 'Ã', 'Â', 'Ã', 'Ä', 'Ã…', 'Æ', 'Ç', 'È', 'É', 'Ê', 'Ë', 'ÃŒ', 'Ã', 'ÃŽ', 'Ã', 'Ñ', 'Ã’', 'Ó', 'Ô', 'Õ', 'Ö', 'Ø', 'Ù', 'Ú', 'Û', 'Ãœ', 'Ã', 'Þ', 'ß', 'à', 'á', 'â', 'ã', 'ä', 'Ã¥', 'æ', 'ç', 'è', 'é', 'ê', 'ë', 'ì', 'í', 'î', 'ï', 'ð', 'ñ', 'ò', 'ó', 'ô', 'õ', 'ö', 'ø', 'ù', 'ú', 'û', 'ý', 'þ', 'ÿ', 'Å”', 'Å•'); + + var valid = new Array('S', 's', 'Dj', 'dj', 'Z', 'z', 'C', 'c', 'C', 'c', 'A', 'A', 'A', 'A', 'A', 'A', 'A', 'C', 'E', 'E', 'E', 'E', 'I', 'I', 'I', 'I', 'N', 'O', 'O', 'O', 'O', 'O', 'O', 'U', 'U', 'U', 'U', 'Y', 'B', 'Ss', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'c', 'e', 'e', 'e', 'e', 'i', 'i', 'i', 'i', 'o', 'n', 'o', 'o', 'o', 'o', 'o', 'o', 'u', 'u', 'u', 'y', 'b', 'y', 'R', 'r'); + + // Compute a new string + for(i in invalid) + string = string.replace(invalid[i], valid[i]); + + return string; +} + +// Encodes quotes in a string +function encodeQuotes(str) { + return (str + '').replace(/"/g, '"'); +} + +// Gets the bare XID from a XID +function bareXID(xid) { + // Cut the resource + xid = cutResource(xid); + + // Launch the stringprep + xid = stringPrep(xid); + + // Set the XID to lower case + xid = xid.toLowerCase(); + + return xid; +} + +// Gets the full XID from a XID +function fullXID(xid) { + // Normalizes the XID + var full = bareXID(xid); + var resource = thisResource(xid); + + // Any resource? + if(resource) + full += '/' + resource; + + return full; +} + +// Gets the nick from a XID +function getXIDNick(aXID) { + return explodeThis('@', aXID, 0); +} + +// Gets the host from a XID +function getXIDHost(aXID) { + return explodeThis('@', aXID, 1); +} + +// Checks if we are in developer mode +function isDeveloper() { + if(DEVELOPER == 'on') + return true; + + return false; +} + +// Checks if anonymous mode is allowed +function allowedAnonymous() { + if(ANONYMOUS == 'on') + return true; + + return false; +} + +// Checks if host is locked +function lockHost() { + if(LOCK_HOST == 'on') + return true; + + return false; +} + +// Gets the full XID of the user +function getXID() { + // Return the XID of the user + if(con.username && con.domain) + return con.username + '@' + con.domain; + + return ''; +} + +// Generates the colors for a given user XID +function generateColor(xid) { + var colors = new Array( + 'ac0000', + 'a66200', + '007703', + '00705f', + '00236b', + '4e005c' + ); + + var number = 0; + + for(var i = 0; i < xid.length; i++) + number += xid.charCodeAt(i); + + var color = '#' + colors[number % (colors.length)]; + + return color; +} + +// Checks if the XID is a gateway +function isGateway(xid) { + if(xid.indexOf('@') != -1) + return false; + + return true; +} + +// Gets the from attribute of a stanza (overrides some servers like Prosody missing from attributes) +function getStanzaFrom(stanza) { + var from = stanza.getFrom(); + + // No from, we assume this is our XID + if(!from) + from = getXID(); + + return from; +} + +// Logs a given data in the console +function logThis(data, level) { + // Console not available + if(!isDeveloper() || (typeof(console) == 'undefined')) + return false; + + // Switch the log level + switch(level) { + // Debug + case 0: + console.debug(data); + + break; + + // Error + case 1: + console.error(data); + + break; + + // Warning + case 2: + console.warn(data); + + break; + + // Information + case 3: + console.info(data); + + break; + + // Default log level + default: + console.log(data); + + break; + } + + return true; +} + +// Gets the current Jappix app. location +function getJappixLocation() { + var url = window.location.href; + + // If the URL has variables, remove them + if(url.indexOf('?') != -1) + url = url.split('?')[0]; + if(url.indexOf('#') != -1) + url = url.split('#')[0]; + + // No "/" at the end + if(!url.match(/(.+)\/$/)) + url += '/'; + + return url; +} + +// Removes spaces at the beginning & the end of a string +function trim(str) { + return str.replace(/^\s+/g,'').replace(/\s+$/g,''); +} + +// Adds a zero to a date when needed +function padZero(i) { + // Negative number (without first 0) + if(i > -10 && i < 0) + return '-0' + (i * -1); + + // Positive number (without first 0) + if(i < 10 && i >= 0) + return '0' + i; + + // All is okay + return i; +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/connection.js b/sources/extend/addon/matrix/jappixmini/jappix/js/connection.js new file mode 100644 index 00000000..85a718c5 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/connection.js @@ -0,0 +1,526 @@ +/* + +Jappix - An open social platform +These are the connection JS script for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 29/08/11 + +*/ + +// Does the user login +var CURRENT_SESSION = false; + +function doLogin(lNick, lServer, lPass, lResource, lPriority, lRemember) { + try { + // We remove the not completed class to avoid problems + $('#home .loginer input').removeClass('please-complete'); + + // We add the login wait div + showGeneralWait(); + + // We define the http binding parameters + oArgs = new Object(); + + if(HOST_BOSH_MAIN) + oArgs.httpbase = HOST_BOSH_MAIN; + else + oArgs.httpbase = HOST_BOSH; + + // We create the new http-binding connection + con = new JSJaCHttpBindingConnection(oArgs); + + // And we handle everything that happen + setupCon(con); + + // Generate a resource + var random_resource = getDB('session', 'resource'); + + if(!random_resource) + random_resource = lResource + ' (' + (new Date()).getTime() + ')'; + + // We retrieve what the user typed in the login inputs + oArgs = new Object(); + oArgs.domain = trim(lServer); + oArgs.username = trim(lNick); + oArgs.resource = random_resource; + oArgs.pass = lPass; + oArgs.secure = true; + oArgs.xmllang = XML_LANG; + + // Store the resource (for reconnection) + setDB('session', 'resource', random_resource); + + // Generate a session XML to be stored + session_xml = 'true' + lServer.htmlEnc() + '' + lNick.htmlEnc() + '' + lResource.htmlEnc() + '' + lPass.htmlEnc() + '' + lPriority.htmlEnc() + ''; + + // Save the session parameters (for reconnect if network issue) + CURRENT_SESSION = session_xml; + + // Remember me? + if(lRemember) + setDB('remember', 'session', 1); + + // We store the infos of the user into the data-base + setDB('priority', 1, lPriority); + + // We connect ! + con.connect(oArgs); + + // Change the page title + pageTitle('wait'); + + logThis('Jappix is connecting...', 3); + } + + catch(e) { + // Logs errors + logThis('Error while logging in: ' + e, 1); + + // Reset Jappix + destroyTalkPage(); + + // Open an unknown error + openThisError(2); + } + + finally { + return false; + } +} + +// Handles the user registration +function handleRegistered() { + logThis('A new account has been registered.', 3); + + // We remove the waiting image + removeGeneralWait(); + + // Reset the title + pageTitle('home'); + + // We show the success information + $('#home .registerer .success').fadeIn('fast'); + + // We quit the session + logout(); +} + +// Does the user registration +function doRegister(username, domain, pass) { + logThis('Trying to register an account...', 3); + + try { + // We define the http binding parameters + oArgs = new Object(); + + if(HOST_BOSH_MAIN) + oArgs.httpbase = HOST_BOSH_MAIN; + else + oArgs.httpbase = HOST_BOSH; + + // We create the new http-binding connection + con = new JSJaCHttpBindingConnection(oArgs); + + // We setup the connection ! + con.registerHandler('onconnect', handleRegistered); + con.registerHandler('onerror', handleError); + + // We retrieve what the user typed in the register inputs + oArgs = new Object(); + oArgs.domain = trim(domain); + oArgs.username = trim(username); + oArgs.resource = JAPPIX_RESOURCE + ' Register (' + (new Date()).getTime() + ')'; + oArgs.pass = pass; + oArgs.register = true; + oArgs.secure = true; + oArgs.xmllang = XML_LANG; + + con.connect(oArgs); + + // We change the registered information text + $('#home .homediv.registerer').append( + '
' + + _e("You have been registered, here is your XMPP address:") + ' ' + con.username.htmlEnc() + '@' + con.domain.htmlEnc() + ' - ' + _e("Login") + '' + + '
' + ); + + // Login link + $('#home .homediv.registerer .success a').click(function() { + return doLogin(con.username, con.domain, con.pass, con.resource, '10', false); + }); + + // Show the waiting image + showGeneralWait(); + + // Change the page title + pageTitle('wait'); + } + + catch(e) { + // Logs errors + logThis(e, 1); + } + + finally { + return false; + } +} + +// Does the user anonymous login +function doAnonymous() { + logThis('Trying to login anonymously...', 3); + + var aPath = '#home .anonymouser '; + var room = $(aPath + '.room').val(); + var nick = $(aPath + '.nick').val(); + + // If the form is correctly completed + if(room && nick) { + // We remove the not completed class to avoid problems + $('#home .anonymouser input').removeClass('please-complete'); + + // Redirect the user to the anonymous room + window.location.href = JAPPIX_LOCATION + '?r=' + room + '&n=' + nick; + } + + // We check if the form is entirely completed + else { + $(aPath + 'input[type=text]').each(function() { + var select = $(this); + + if(!select.val()) + $(document).oneTime(10, function() { + select.addClass('please-complete').focus(); + }); + else + select.removeClass('please-complete'); + }); + } + + return false; +} + +// Handles the user connected event +var CONNECTED = false; + +function handleConnected() { + logThis('Jappix is now connected.', 3); + + // Connection markers + CONNECTED = true; + RECONNECT_TRY = 0; + RECONNECT_TIMER = 0; + + // We hide the home page + $('#home').hide(); + + // Not resumed? + if(!RESUME) { + // Remember the session? + if(getDB('remember', 'session')) + setPersistent('session', 1, CURRENT_SESSION); + + // We show the chatting app. + createTalkPage(); + + // We reset the homepage + switchHome('default'); + + // We get all the other things + getEverything(); + + // Set last activity stamp + LAST_ACTIVITY = getTimeStamp(); + } + + // Resumed + else { + // Send our presence + presenceSend(); + + // Change the title + updateTitle(); + } + + // Remove the waiting item + removeGeneralWait(); +} + +// Handles the user disconnected event +function handleDisconnected() { + logThis('Jappix is now disconnected.', 3); + + // Normal disconnection + if(!CURRENT_SESSION && !CONNECTED) + destroyTalkPage(); +} + +// Setups the normal connection +function setupCon(con) { + // We setup all the necessary handlers for the connection + con.registerHandler('message', handleMessage); + con.registerHandler('presence', handlePresence); + con.registerHandler('iq', handleIQ); + con.registerHandler('onconnect', handleConnected); + con.registerHandler('onerror', handleError); + con.registerHandler('ondisconnect', handleDisconnected); +} + +// Logouts from the server +function logout() { + // We are not connected + if(!isConnected()) + return false; + + // Disconnect from the XMPP server + con.disconnect(); + + logThis('Jappix is disconnecting...', 3); +} + +// Terminates a session +function terminate() { + if(!isConnected()) + return; + + // Clear temporary session storage + resetConMarkers(); + + // Show the waiting item (useful if BOSH is sloooow) + showGeneralWait(); + + // Change the page title + pageTitle('wait'); + + // Disconnect from the XMPP server + logout(); +} + +// Quitss a session +function quit() { + if(!isConnected()) + return; + + // We show the waiting image + showGeneralWait(); + + // Change the page title + pageTitle('wait'); + + // We disconnect from the XMPP server + logout(); +} + +// Creates the reconnect pane +var RECONNECT_TRY = 0; +var RECONNECT_TIMER = 0; + +function createReconnect(mode) { + logThis('This is not a normal disconnection, show the reconnect pane...', 1); + + // Reconnect pane not yet displayed? + if(!exists('#reconnect')) { + // Blur the focused input/textarea/select + $('input, select, textarea').blur(); + + // Create the HTML code + var html = '
' + + '
' + + _e("Due to a network issue, you were disconnected. What do you want to do now?"); + + // Can we cancel reconnection? + if(mode == 'normal') + html += '' + _e("Cancel") + ''; + + html += '' + _e("Reconnect") + '' + + '
'; + + // Append the code + $('body').append(html); + + // Click events + if(mode == 'normal') + $('#reconnect a.finish.cancel').click(function() { + return cancelReconnect(); + }); + + $('#reconnect a.finish.reconnect').click(function() { + return acceptReconnect(mode); + }); + + // Try to reconnect automatically after a while + if(RECONNECT_TRY < 5) + RECONNECT_TIMER = 5 + (5 * RECONNECT_TRY); + else + RECONNECT_TIMER = 120; + + // Change the try number + RECONNECT_TRY++; + + // Fire the event! + $('#reconnect a.finish.reconnect').everyTime('1s', function() { + // We can reconnect! + if(RECONNECT_TIMER == 0) + return acceptReconnect(mode); + + // Button text + if(RECONNECT_TIMER <= 10) + $(this).text(_e("Reconnect") + ' (' + RECONNECT_TIMER + ')'); + + // Remove 1 second + RECONNECT_TIMER--; + }); + + // Page title + updateTitle(); + } +} + +// Reconnects the user if he was disconnected (network issue) +var RESUME = false; + +function acceptReconnect(mode) { + logThis('Trying to reconnect the user...', 3); + + // Resume marker + RESUME = true; + + // Show waiting item + showGeneralWait(); + + // Reset some various stuffs + var groupchats = '#page-engine .page-engine-chan[data-type=groupchat]'; + $(groupchats + ' .list .role').hide(); + $(groupchats + ' .one-group, ' + groupchats + ' .list .user').remove(); + $(groupchats).attr('data-initial', 'false'); + + // Stop the timer + $('#reconnect a.finish.reconnect').stopTime(); + + // Remove the reconnect pane + $('#reconnect').remove(); + + // Try to login again + if(mode == 'normal') + loginFromSession(XMLFromString(CURRENT_SESSION)); + else if(mode == 'anonymous') + anonymousLogin(HOST_ANONYMOUS); + + return false; +} + +// Cancel the reconnection of user account (network issue) +function cancelReconnect() { + logThis('User has canceled automatic reconnection...', 3); + + // Stop the timer + $('#reconnect a.finish.reconnect').stopTime(); + + // Remove the reconnect pane + $('#reconnect').remove(); + + // Destroy the talk page + destroyTalkPage(); + + // Renitialize the previous session parameters + resetConMarkers(); + + return false; +} + +// Clears session reminder database +function clearLastSession() { + // Clear temporary storage + resetConMarkers(); + + // Clear persistent storage + if($(XMLFromString(getPersistent('session', 1))).find('stored').text() == 'true') + removePersistent('session', 1); +} + +// Resets the connection markers +function resetConMarkers() { + CURRENT_SESSION = false; + CONNECTED = false; + RESUME = false; + RECONNECT_TRY = 0; + RECONNECT_TIMER = 0; +} + +// Logins from a saved session +function loginFromSession(data) { + // Select the data + var session = $(data); + + // Fire the login event + doLogin( + session.find('username').text(), + session.find('domain').text(), + session.find('password').text(), + session.find('resource').text(), + session.find('priority').text(), + false + ); +} + +// Quits a session normally +function normalQuit() { + // Reset our database + clearLastSession(); + + // We quit the current session + quit(); + + // We show an info + openThisInfo(3); + + return false; +} + +// Gets all the users stuffs +function getEverything() { + getFeatures(); + getRoster(); + listPrivacy(); + getStorage(NS_ROSTERNOTES); +} + +// Plugin launcher +function launchConnection() { + // Logouts when Jappix is closed + $(window).bind('beforeunload', terminate); + + // Nothing to do when anonymous! + if(isAnonymous()) + return; + + // Try to resume a stored session, if not anonymous + var session = XMLFromString(getPersistent('session', 1)); + + if($(session).find('stored').text() == 'true') { + // Hide the homepage + $('#home').hide(); + + // Show the waiting icon + showGeneralWait(); + + // Login! + loginFromSession(session); + + logThis('Saved session found, resuming it...', 3); + } + + // Not connected, maybe a XMPP link is submitted? + else if((parent.location.hash != '#OK') && LINK_VARS['x']) { + switchHome('loginer'); + + logThis('A XMPP link is set, switch to login page.', 3); + } +} + +// Launch this plugin! +$(document).ready(launchConnection); diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/constants.js b/sources/extend/addon/matrix/jappixmini/jappix/js/constants.js new file mode 100644 index 00000000..bc59bd75 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/constants.js @@ -0,0 +1,211 @@ +/* + +Jappix - An open social platform +These are the constants JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Stefan Strigler, Vanaryon +Last revision: 26/08/11 + +*/ + +// XMPP XMLNS attributes +var NS_PROTOCOL = 'http://jabber.org/protocol/'; +var NS_FEATURES = 'http://jabber.org/features/'; +var NS_CLIENT = 'jabber:client'; +var NS_IQ = 'jabber:iq:'; +var NS_X = 'jabber:x:'; +var NS_IETF = 'urn:ietf:params:xml:ns:xmpp-'; +var NS_XMPP = 'urn:xmpp:'; + +var NS_STORAGE = 'storage:'; +var NS_BOOKMARKS = NS_STORAGE + 'bookmarks'; +var NS_ROSTERNOTES = NS_STORAGE + 'rosternotes'; + +var NS_JAPPIX = 'jappix:'; +var NS_INBOX = NS_JAPPIX + 'inbox'; +var NS_OPTIONS = NS_JAPPIX + 'options'; + +var NS_DISCO_ITEMS = NS_PROTOCOL + 'disco#items'; +var NS_DISCO_INFO = NS_PROTOCOL + 'disco#info'; +var NS_VCARD = 'vcard-temp'; +var NS_VCARD_P = NS_VCARD + ':x:update'; +var NS_AUTH = NS_IQ + 'auth'; +var NS_AUTH_ERROR = NS_IQ + 'auth:error'; +var NS_REGISTER = NS_IQ + 'register'; +var NS_SEARCH = NS_IQ + 'search'; +var NS_ROSTER = NS_IQ + 'roster'; +var NS_PRIVACY = NS_IQ + 'privacy'; +var NS_PRIVATE = NS_IQ + 'private'; +var NS_VERSION = NS_IQ + 'version'; +var NS_TIME = NS_IQ + 'time'; +var NS_LAST = NS_IQ + 'last'; +var NS_IQDATA = NS_IQ + 'data'; +var NS_XDATA = NS_X + 'data'; +var NS_IQOOB = NS_IQ + 'oob'; +var NS_XOOB = NS_X + 'oob'; +var NS_DELAY = NS_X + 'delay'; +var NS_EXPIRE = NS_X + 'expire'; +var NS_EVENT = NS_X + 'event'; +var NS_XCONFERENCE = NS_X + 'conference'; +var NS_STATS = NS_PROTOCOL + 'stats'; +var NS_MUC = NS_PROTOCOL + 'muc'; +var NS_MUC_USER = NS_MUC + '#user'; +var NS_MUC_ADMIN = NS_MUC + '#admin'; +var NS_MUC_OWNER = NS_MUC + '#owner'; +var NS_MUC_CONFIG = NS_MUC + '#roomconfig'; +var NS_PUBSUB = NS_PROTOCOL + 'pubsub'; +var NS_PUBSUB_EVENT = NS_PUBSUB + '#event'; +var NS_PUBSUB_OWNER = NS_PUBSUB + '#owner'; +var NS_PUBSUB_NMI = NS_PUBSUB + '#node-meta-info'; +var NS_PUBSUB_NC = NS_PUBSUB + '#node_config'; +var NS_PUBSUB_RI = NS_PUBSUB + '#retrieve-items'; +var NS_COMMANDS = NS_PROTOCOL + 'commands'; +var NS_BOSH = NS_PROTOCOL + 'httpbind'; +var NS_STREAM = 'http://etherx.jabber.org/streams'; +var NS_URN_TIME = NS_XMPP + 'time'; +var NS_URN_PING = NS_XMPP + 'ping'; +var NS_URN_ADATA = NS_XMPP + 'avatar:data'; +var NS_URN_AMETA = NS_XMPP + 'avatar:metadata'; +var NS_URN_MBLOG = NS_XMPP + 'microblog:0'; +var NS_URN_INBOX = NS_XMPP + 'inbox'; +var NS_URN_ARCHIVE = NS_XMPP + 'archive'; +var NS_URN_AR_PREF = NS_URN_ARCHIVE + ':pref'; +var NS_URN_AR_AUTO = NS_URN_ARCHIVE + ':auto'; +var NS_URN_AR_MANUAL = NS_URN_ARCHIVE + ':manual'; +var NS_URN_AR_MANAGE = NS_URN_ARCHIVE + ':manage'; +var NS_URN_DELAY = NS_XMPP + 'delay'; +var NS_URN_RECEIPTS = NS_XMPP + 'receipts'; +var NS_RSM = NS_PROTOCOL + 'rsm'; +var NS_IPV6 = 'ipv6'; +var NS_XHTML = 'http://www.w3.org/1999/xhtml'; +var NS_XHTML_IM = NS_PROTOCOL + 'xhtml-im'; +var NS_CHATSTATES = NS_PROTOCOL + 'chatstates'; +var NS_HTTP_AUTH = NS_PROTOCOL + 'http-auth'; +var NS_ROSTERX = NS_PROTOCOL + 'rosterx'; +var NS_MOOD = NS_PROTOCOL + 'mood'; +var NS_ACTIVITY = NS_PROTOCOL + 'activity'; +var NS_TUNE = NS_PROTOCOL + 'tune'; +var NS_GEOLOC = NS_PROTOCOL + 'geoloc'; +var NS_NICK = NS_PROTOCOL + 'nick'; +var NS_NOTIFY = '+notify'; +var NS_CAPS = NS_PROTOCOL + 'caps'; +var NS_ATOM = 'http://www.w3.org/2005/Atom'; + +var NS_STANZAS = NS_IETF + 'stanzas'; +var NS_STREAMS = NS_IETF + 'streams'; + +var NS_TLS = NS_IETF + 'tls'; +var NS_SASL = NS_IETF + 'sasl'; +var NS_SESSION = NS_IETF + 'session'; +var NS_BIND = NS_IETF + 'bind'; + +var NS_FEATURE_IQAUTH = NS_FEATURES + 'iq-auth'; +var NS_FEATURE_IQREGISTER = NS_FEATURES + 'iq-register'; +var NS_FEATURE_COMPRESS = NS_FEATURES + 'compress'; + +var NS_COMPRESS = NS_PROTOCOL + 'compress'; + +// Available locales +var LOCALES_AVAILABLE_ID = new Array(); +var LOCALES_AVAILABLE_NAMES = new Array(); + +// XML lang +var XML_LANG = null; + +// Jappix parameters +var JAPPIX_STATIC = null; +var JAPPIX_VERSION = null; +var JAPPIX_MAX_FILE_SIZE = null; +var JAPPIX_MAX_UPLOAD = null; + +// Jappix main configuration +var SERVICE_NAME = null; +var SERVICE_DESC = null; +var JAPPIX_RESOURCE = null; +var LOCK_HOST = null; +var ANONYMOUS = null; +var REGISTRATION = null; +var BOSH_PROXY = null; +var MANAGER_LINK = null; +var GROUPCHATS_JOIN = null; +var ENCRYPTION = null; +var HTTPS_STORAGE = null; +var HTTPS_FORCE = null; +var COMPRESSION = null; +var MULTI_FILES = null; +var DEVELOPER = null; + +// Jappix hosts configuration +var HOST_MAIN = null; +var HOST_MUC = null; +var HOST_PUBSUB = null; +var HOST_VJUD = null; +var HOST_ANONYMOUS = null; +var HOST_BOSH = null; +var HOST_BOSH_MAIN = null; +var HOST_BOSH_MINI = null; +var HOST_STATIC = null; +var HOST_UPLOAD = null; + +// Anonymous mode +var ANONYMOUS_ROOM = null; +var ANONYMOUS_NICK = null; + +// Node parameters +var JAPPIX_LOCATION = getJappixLocation(); + +// XMPP error stanzas +function STANZA_ERROR(code, type, cond) { + if (window == this) + return new STANZA_ERROR(code, type, cond); + + this.code = code; + this.type = type; + this.cond = cond; +} + +var ERR_BAD_REQUEST = + STANZA_ERROR('400', 'modify', 'bad-request'); +var ERR_CONFLICT = + STANZA_ERROR('409', 'cancel', 'conflict'); +var ERR_FEATURE_NOT_IMPLEMENTED = + STANZA_ERROR('501', 'cancel', 'feature-not-implemented'); +var ERR_FORBIDDEN = + STANZA_ERROR('403', 'auth', 'forbidden'); +var ERR_GONE = + STANZA_ERROR('302', 'modify', 'gone'); +var ERR_INTERNAL_SERVER_ERROR = + STANZA_ERROR('500', 'wait', 'internal-server-error'); +var ERR_ITEM_NOT_FOUND = + STANZA_ERROR('404', 'cancel', 'item-not-found'); +var ERR_JID_MALFORMED = + STANZA_ERROR('400', 'modify', 'jid-malformed'); +var ERR_NOT_ACCEPTABLE = + STANZA_ERROR('406', 'modify', 'not-acceptable'); +var ERR_NOT_ALLOWED = + STANZA_ERROR('405', 'cancel', 'not-allowed'); +var ERR_NOT_AUTHORIZED = + STANZA_ERROR('401', 'auth', 'not-authorized'); +var ERR_PAYMENT_REQUIRED = + STANZA_ERROR('402', 'auth', 'payment-required'); +var ERR_RECIPIENT_UNAVAILABLE = + STANZA_ERROR('404', 'wait', 'recipient-unavailable'); +var ERR_REDIRECT = + STANZA_ERROR('302', 'modify', 'redirect'); +var ERR_REGISTRATION_REQUIRED = + STANZA_ERROR('407', 'auth', 'registration-required'); +var ERR_REMOTE_SERVER_NOT_FOUND = + STANZA_ERROR('404', 'cancel', 'remote-server-not-found'); +var ERR_REMOTE_SERVER_TIMEOUT = + STANZA_ERROR('504', 'wait', 'remote-server-timeout'); +var ERR_RESOURCE_CONSTRAINT = + STANZA_ERROR('500', 'wait', 'resource-constraint'); +var ERR_SERVICE_UNAVAILABLE = + STANZA_ERROR('503', 'cancel', 'service-unavailable'); +var ERR_SUBSCRIPTION_REQUIRED = + STANZA_ERROR('407', 'auth', 'subscription-required'); +var ERR_UNEXPECTED_REQUEST = + STANZA_ERROR('400', 'wait', 'unexpected-request'); diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/dataform.js b/sources/extend/addon/matrix/jappixmini/jappix/js/dataform.js new file mode 100644 index 00000000..7fbea89d --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/dataform.js @@ -0,0 +1,921 @@ +/* + +Jappix - An open social platform +These are the dataform JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 28/08/11 + +*/ + +// Gets the defined dataform elements +function dataForm(host, type, node, action, target) { + // Clean the current session + cleanDataForm(target); + + // We tell the user that a search has been launched + $('#' + target + ' .wait').show(); + + // If we have enough data + if(host && type) { + // Generate a session ID + var sessionID = Math.round(100000.5 + (((900000.49999) - (100000.5)) * Math.random())); + var id = target + '-' + sessionID + '-' + genID(); + $('.' + target + '-results').attr('data-session', target + '-' + sessionID); + + // We request the service item + var iq = new JSJaCIQ(); + iq.setID(id); + iq.setTo(host); + iq.setType('get'); + + // MUC admin query + if(type == 'muc') { + iq.setQuery(NS_MUC_OWNER); + con.send(iq, handleDataFormMuc); + } + + // Browse query + else if(type == 'browse') { + var iqQuery = iq.setQuery(NS_DISCO_ITEMS); + + if(node) + iqQuery.setAttribute('node', node); + + con.send(iq, handleDataFormBrowse); + } + + // Command + else if(type == 'command') { + var items; + + if(node) + items = iq.appendNode('command', {'node': node, 'xmlns': NS_COMMANDS}); + + else { + items = iq.setQuery(NS_DISCO_ITEMS); + items.setAttribute('node', NS_COMMANDS); + } + + if(action && node) { + iq.setType('set'); + items.setAttribute('action', action); + } + + con.send(iq, handleDataFormCommand); + } + + // Search query + else if(type == 'search') { + iq.setQuery(NS_SEARCH); + con.send(iq, handleDataFormSearch); + } + + // Subscribe query + else if(type == 'subscribe') { + iq.setQuery(NS_REGISTER); + con.send(iq, handleDataFormSubscribe); + } + + // Join + else if(type == 'join') { + if(target == 'discovery') + closeDiscovery(); + + checkChatCreate(host, 'groupchat'); + } + } + + return false; +} + +// Sends a given dataform +function sendDataForm(type, action, x_type, id, xid, node, sessionid, target) { + // Path + var pathID = '#' + target + ' .results[data-session=' + id + ']'; + + // New IQ + var iq = new JSJaCIQ(); + iq.setTo(xid); + iq.setType('set'); + + // Set the correct query + var query; + + if(type == 'subscribe') + iqQuery = iq.setQuery(NS_REGISTER); + else if(type == 'search') + iqQuery = iq.setQuery(NS_SEARCH); + else if(type == 'command') + iqQuery = iq.appendNode('command', {'xmlns': NS_COMMANDS, 'node': node, 'sessionid': sessionid, 'action': action}); + else if(type == 'x') + iqQuery = iq.setQuery(NS_MUC_OWNER); + + // Build the XML document + if(action != 'cancel') { + // No X node + if(exists('input.register-special') && (type == 'subscribe')) { + $('input.register-special').each(function() { + var iName = $(this).attr('name'); + var iValue = $(this).val(); + + iqQuery.appendChild(iq.buildNode(iName, {'xmlns': NS_REGISTER}, iValue)); + }); + } + + // Can create the X node + else { + var iqX = iqQuery.appendChild(iq.buildNode('x', {'xmlns': NS_XDATA, 'type': x_type})); + + // Each input + $(pathID + ' .oneresult input, ' + pathID + ' .oneresult textarea, ' + pathID + ' .oneresult select').each(function() { + // Get the current input value + var iVar = $(this).attr('name'); + var iType = $(this).attr('data-type'); + var iValue = $(this).val(); + + // Build a new field node + var field = iqX.appendChild(iq.buildNode('field', {'var': iVar, 'type': iType, 'xmlns': NS_XDATA})); + + // Boolean input? + if(iType == 'boolean') { + if($(this).filter(':checked').size()) + iValue = '1'; + else + iValue = '0'; + } + + // JID-multi input? + if(iType == 'jid-multi') { + // Values array + var xid_arr = [iValue]; + var xid_check = []; + + // Try to split it + if(iValue.indexOf(',') != -1) + xid_arr = iValue.split(','); + + // Append each value to the XML document + for(i in xid_arr) { + // Get the current value + xid_current = trim(xid_arr[i]); + + // No current value? + if(!xid_current) + continue; + + // Add the current value + if(!existArrayValue(xid_check, xid_current)) { + xid_check.push(xid_current); + field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, xid_current)); + } + } + } + + // List-multi selector? + else if(iType == 'list-multi') { + // Any value? + if(iValue && iValue.length) { + for(i in iValue) + field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, iValue[i])); + } + } + + // Other inputs? + else + field.appendChild(iq.buildNode('value', {'xmlns': NS_XDATA}, iValue)); + }); + } + } + + // Clean the current session + cleanDataForm(target); + + // Show the waiting item + $('#' + target + ' .wait').show(); + + // Change the ID of the current discovered item + var iqID = target + '-' + genID(); + $('#' + target + ' .' + target + '-results').attr('data-session', iqID); + iq.setID(iqID); + + // Send the IQ + if(type == 'subscribe') + con.send(iq, handleDataFormSubscribe); + else if(type == 'search') + con.send(iq, handleDataFormSearch); + else if(type == 'command') + con.send(iq, handleDataFormCommand); + else + con.send(iq); + + return false; +} + +// Displays the good dataform buttons +function buttonsDataForm(type, action, id, xid, node, sessionid, target, pathID) { + // No need to use buttons? + if(type == 'muc') + return; + + // Override the "undefined" output + if(!id) + id = ''; + if(!xid) + xid = ''; + if(!node) + node = ''; + if(!sessionid) + sessionid = ''; + + // We generate the buttons code + var buttonsCode = '
'; + + if(action == 'submit') { + if((target == 'adhoc') && (type == 'command')) { + buttonsCode += '' + _e("Submit") + ''; + + // When keyup on one text input + $(pathID + ' input').keyup(function(e) { + if(e.keyCode == 13) { + sendDataForm(type, 'execute', 'submit', id, xid, node, sessionid, target); + + return false; + } + }); + } + + else { + buttonsCode += '' + _e("Submit") + ''; + + // When keyup on one text input + $(pathID + ' input').keyup(function(e) { + if(e.keyCode == 13) { + sendDataForm(type, 'submit', 'submit', id, xid, node, sessionid, target); + + return false; + } + }); + } + } + + if((action == 'submit') && (type != 'subscribe') && (type != 'search')) + buttonsCode += '' + _e("Cancel") + ''; + + if(((action == 'back') || (type == 'subscribe') || (type == 'search')) && (target == 'discovery')) + buttonsCode += '' + _e("Close") + ''; + + if((action == 'back') && ((target == 'welcome') || (target == 'directory'))) + buttonsCode += '' + _e("Previous") + ''; + + if((action == 'back') && (target == 'adhoc')) + buttonsCode += '' + _e("Previous") + ''; + + buttonsCode += '
'; + + // We display the buttons code + $(pathID).append(buttonsCode); + + // If no submit link, lock the form + if(!exists(pathID + ' a.submit')) + $(pathID + ' input, ' + pathID + ' textarea').attr('readonly', true); +} + +// Handles the MUC dataform +function handleDataFormMuc(iq) { + handleErrorReply(iq); + handleDataFormContent(iq, 'muc'); +} + +// Handles the browse dataform +function handleDataFormBrowse(iq) { + handleErrorReply(iq); + handleDataFormContent(iq, 'browse'); +} + +// Handles the command dataform +function handleDataFormCommand(iq) { + handleErrorReply(iq); + handleDataFormContent(iq, 'command'); +} + +// Handles the subscribe dataform +function handleDataFormSubscribe(iq) { + handleErrorReply(iq); + handleDataFormContent(iq, 'subscribe'); +} + +// Handles the search dataform +function handleDataFormSearch(iq) { + handleErrorReply(iq); + handleDataFormContent(iq, 'search'); +} + +// Handles the dataform content +function handleDataFormContent(iq, type) { + // Get the ID + var sID = iq.getID(); + + // Get the target + var splitted = sID.split('-'); + var target = splitted[0]; + var sessionID = target + '-' + splitted[1]; + var from = fullXID(getStanzaFrom(iq)); + var pathID = '#' + target + ' .results[data-session=' + sessionID + ']'; + + // If an error occured + if(!iq || (iq.getType() != 'result')) + noResultDataForm(pathID); + + // If we got something okay + else { + var handleXML = iq.getNode(); + + if(type == 'browse') { + if($(handleXML).find('item').attr('jid')) { + // Get the query node + var queryNode = $(handleXML).find('query').attr('node'); + + $(handleXML).find('item').each(function() { + // We parse the received xml + var itemHost = $(this).attr('jid'); + var itemNode = $(this).attr('node'); + var itemName = $(this).attr('name'); + var itemHash = hex_md5(itemHost); + + // Node + if(itemNode) + $(pathID).append( + '
' + + '
' + itemNode.htmlEnc() + '
' + + '
' + ); + + // Item + else if(queryNode && itemName) + $(pathID).append( + '
' + + '
' + itemName.htmlEnc() + '
' + + '
' + ); + + // Item with children + else { + // We display the waiting element + $(pathID + ' .disco-wait .disco-category-title').after( + '
' + + '
' + + '
' + itemHost + '
' + + '
' + _e("Requesting this service...") + '
' + + '
' + ); + + // We display the category + $('#' + target + ' .disco-wait').show(); + + // We ask the server what's the service type + getDataFormType(itemHost, itemNode, sessionID); + } + }); + } + + // Else, there are no items for this query + else + noResultDataForm(pathID); + } + + else if((type == 'muc') || (type == 'search') || (type == 'subscribe') || ((type == 'command') && $(handleXML).find('command').attr('xmlns'))) { + // Get some values + var xCommand = $(handleXML).find('command'); + var bNode = xCommand.attr('node'); + var bSession = xCommand.attr('sessionid'); + var bStatus = xCommand.attr('status'); + var xRegister = $(handleXML).find('query[xmlns=' + NS_REGISTER + ']').text(); + var xElement = $(handleXML).find('x'); + + // Search done + if((xElement.attr('type') == 'result') && (type == 'search')) { + var bPath = pathID; + + // Display the result + $(handleXML).find('item').each(function() { + var bXID = $(this).find('field[var=jid] value:first').text(); + var bName = $(this).find('field[var=fn] value:first').text(); + var bCountry = $(this).find('field[var=ctry] value:first').text(); + var dName = bName; + + // Override "undefined" value + if(!bXID) + bXID = ''; + if(!bName) + bName = _e("Unknown name"); + if(!bCountry) + bCountry = _e("Unknown country"); + + // User hash + var bHash = hex_md5(bXID); + + // HTML code + var bHTML = '
' + + '
' + + '' + + '
' + + '
' + bName + '
' + + '
' + bCountry + '
' + + '
' + bXID + '
' + + '
'; + + // The buddy is not in our buddy list? + if(!exists('#buddy-list .buddy[data-xid=' + escape(bXID) + ']')) + bHTML += '' + _e("Add") + ''; + + // Chat button, if not in welcome/directory mode + if(target == 'discovery') + bHTML += '' + _e("Chat") + ''; + + // Close the HTML element + bHTML += '
'; + + $(bPath).append(bHTML); + + // Click events + $(bPath + ' .' + bHash + ' a').click(function() { + // Buddy add + if($(this).is('.one-add')) { + $(this).hide(); + + addThisContact(bXID, dName); + } + + // Buddy chat + if($(this).is('.one-chat')) { + if(target == 'discovery') + closeDiscovery(); + + checkChatCreate(bXID , 'chat', '', '', dName); + } + + return false; + }); + + // Get the user's avatar + if(bXID) + getAvatar(bXID, 'cache', 'true', 'forget'); + }); + + // No result? + if(!$(handleXML).find('item').size()) + noResultDataForm(pathID); + + // Previous button + buttonsDataForm(type, 'back', sessionID, from, bNode, bSession, target, pathID); + } + + // Command to complete + else if(xElement.attr('xmlns') || ((type == 'subscribe') && xRegister)) { + // We display the elements + fillDataForm(handleXML, sessionID); + + // We display the buttons + if(bStatus != 'completed') + buttonsDataForm(type, 'submit', sessionID, from, bNode, bSession, target, pathID); + else + buttonsDataForm(type, 'back', sessionID, from, bNode, bSession, target, pathID); + } + + // Command completed or subscription done + else if(((bStatus == 'completed') && (type == 'command')) || (!xRegister && (type == 'subscribe'))) { + // Display the good text + var cNote = $(xCommand).find('note'); + + // Any note? + if(cNote.size()) { + cNote.each(function() { + $(pathID).append( + '
' + $(this).text().htmlEnc() + '
' + ); + }); + } + + // Default text + else + $(pathID).append('
' + _e("Your form has been sent.") + '
'); + + // Display the back button + buttonsDataForm(type, 'back', sessionID, from, '', '', target, pathID); + + // Add the gateway to our roster if subscribed + if(type == 'subscribe') + addThisContact(from); + } + + // Command canceled + else if((bStatus == 'canceled') && (type == 'command')) { + if(target == 'discovery') + startDiscovery(); + else if(target == 'adhoc') + dataForm(from, 'command', '', '', 'adhoc'); + } + + // No items for this query + else + noResultDataForm(pathID); + } + + else if(type == 'command') { + if($(handleXML).find('item').attr('jid')) { + // We display the elements + $(handleXML).find('item').each(function() { + // We parse the received xml + var itemHost = $(this).attr('jid'); + var itemNode = $(this).attr('node'); + var itemName = $(this).attr('name'); + var itemHash = hex_md5(itemHost); + + // We display the waiting element + $(pathID).prepend( + '
' + + '
' + itemName + '
' + + '
»
' + + '
' + ); + }); + } + + // Else, there are no items for this query + else + noResultDataForm(pathID); + } + } + + // Focus on the first input + $(document).oneTime(10, function() { + $(pathID + ' input:visible:first').focus(); + }); + + // Hide the wait icon + $('#' + target + ' .wait').hide(); +} + +// Fills the dataform elements +function fillDataForm(xml, id) { + /* REF: http://xmpp.org/extensions/xep-0004.html */ + + // Initialize new vars + var target = id.split('-')[0]; + var pathID = '#' + target + ' .results[data-session=' + id + ']'; + var selector, is_dataform; + + // Is it a dataform? + if($(xml).find('x[xmlns=' + NS_XDATA + ']').size()) + is_dataform = true; + else + is_dataform = false; + + // Determines the good selector to use + if(is_dataform) + selector = $(xml).find('x[xmlns=' + NS_XDATA + ']'); + else + selector = $(xml); + + // Form title + selector.find('title').each(function() { + $(pathID).append( + '
' + $(this).text().htmlEnc() + '
' + ); + }); + + // Form instructions + selector.find('instructions').each(function() { + $(pathID).append( + '
' + $(this).text().htmlEnc() + '
' + ); + }); + + // Register? + if(!is_dataform) { + // Items to detect + var reg_names = [_e("Nickname"), _e("Name"), _e("Password"), _e("E-mail")]; + var reg_ids = ['username', 'name', 'password', 'email']; + + // Append these inputs + for(a in reg_names) { + selector.find(reg_ids[a]).each(function() { + $(pathID).append( + '
' + + '' + + '' + + '
' + ); + }); + } + + return false; + } + + // Dataform? + selector.find('field').each(function() { + // We parse the received xml + var type = $(this).attr('type'); + var label = $(this).attr('label'); + var field = $(this).attr('var'); + var value = $(this).find('value:first').text(); + var required = ''; + + // No value? + if(!field) + return; + + // Required input? + if($(this).find('required').size()) + required = ' required=""'; + + // Compatibility fix + if(!label) + label = field; + + if(!type) + type = ''; + + // Generate some values + var input; + var hideThis = ''; + + // Fixed field + if(type == 'fixed') + $(pathID).append('
' + value.htmlEnc() + '
'); + + else { + // Hidden field + if(type == 'hidden') { + hideThis = ' style="display: none;"'; + input = ''; + } + + // Boolean field + else if(type == 'boolean') { + var checked; + + if(value == '1') + checked = 'checked'; + else + checked = ''; + + input = ''; + } + + // List-single/list-multi field + else if((type == 'list-single') || (type == 'list-multi')) { + var multiple = ''; + + // Multiple options? + if(type == 'list-multi') + multiple = ' multiple=""'; + + // Append the select field + input = ''; + } + + // Text-multi field + else if(type == 'text-multi') + input = ''; + + // JID-multi field + else if(type == 'jid-multi') { + // Put the XID into an array + var xid_arr = []; + + $(this).find('value').each(function() { + var cValue = $(this).text(); + + if(!existArrayValue(xid_arr, cValue)) + xid_arr.push(cValue); + }); + + // Sort the array + xid_arr.sort(); + + // Create the input + var xid_value = ''; + + if(xid_arr.length) { + for(i in xid_arr) { + // Any pre-value + if(xid_value) + xid_value += ', '; + + // Add the current XID + xid_value += xid_arr[i]; + } + } + + input = ''; + } + + // Other stuffs that are similar + else { + // Text-single field + var iType = 'text'; + + // Text-private field + if(type == 'text-private') + iType = 'password'; + + // JID-single field + else if(type == 'jid-single') + iType = 'email'; + + input = ''; + } + + // Append the HTML markup for this field + $(pathID).append( + '
' + + '' + + input + + '
' + ); + } + }); + + return false; +} + +// Gets the dataform type +function getDataFormType(host, node, id) { + var iq = new JSJaCIQ(); + iq.setID(id + '-' + genID()); + iq.setTo(host); + iq.setType('get'); + + var iqQuery = iq.setQuery(NS_DISCO_INFO); + + if(node) + iqQuery.setAttribute('node', node); + + con.send(iq, handleThisBrowse); +} + +// Handles the browse stanza +function handleThisBrowse(iq) { + /* REF: http://xmpp.org/registrar/disco-categories.html */ + + var id = iq.getID(); + var splitted = id.split('-'); + var target = splitted[0]; + var sessionID = target + '-' + splitted[1]; + var from = fullXID(getStanzaFrom(iq)); + var hash = hex_md5(from); + var handleXML = iq.getQuery(); + var pathID = '#' + target + ' .results[data-session=' + sessionID + ']'; + + // We first remove the waiting element + $(pathID + ' .disco-wait .' + hash).remove(); + + if($(handleXML).find('identity').attr('type')) { + var category = $(handleXML).find('identity').attr('category'); + var type = $(handleXML).find('identity').attr('type'); + var named = $(handleXML).find('identity').attr('name'); + + if(named) + gName = named; + else + gName = ''; + + var one, two, three, four, five; + + // Get the features that this entity supports + var findFeature = $(handleXML).find('feature'); + + for(i in findFeature) { + var current = findFeature.eq(i).attr('var'); + + switch(current) { + case NS_SEARCH: + one = 1; + break; + + case NS_MUC: + two = 1; + break; + + case NS_REGISTER: + three = 1; + break; + + case NS_COMMANDS: + four = 1; + break; + + case NS_DISCO_ITEMS: + five = 1; + break; + + default: + break; + } + } + + var buttons = Array(one, two, three, four, five); + + // We define the toolbox links depending on the supported features + var tools = ''; + var aTools = Array('search', 'join', 'subscribe', 'command', 'browse'); + var bTools = Array(_e("Search"), _e("Join"), _e("Subscribe"), _e("Command"), _e("Browse")); + + for(i in buttons) { + if(buttons[i]) + tools += ''; + } + + // As defined in the ref, we detect the type of each category to put an icon + switch(category) { + case 'account': + case 'auth': + case 'automation': + case 'client': + case 'collaboration': + case 'component': + case 'conference': + case 'directory': + case 'gateway': + case 'headline': + case 'hierarchy': + case 'proxy': + case 'pubsub': + case 'server': + case 'store': + break; + + default: + category = 'others'; + } + + // We display the item we found + $(pathID + ' .disco-' + category + ' .disco-category-title').after( + '
' + + '
' + + '
' + from + '
' + + '
' + gName + '
' + + '
' + tools + '
' + + '
' + ); + + // We display the category + $(pathID + ' .disco-' + category).show(); + } + + else { + $(pathID + ' .disco-others .disco-category-title').after( + '
' + + '
' + + '
' + from + '
' + + '
' + _e("Service offline or broken") + '
' + + '
' + ); + + // We display the category + $(pathID + ' .disco-others').show(); + } + + // We hide the waiting stuffs if there's no remaining loading items + if(!$(pathID + ' .disco-wait .' + target + '-oneresult').size()) + $(pathID + ' .disco-wait, #' + target + ' .wait').hide(); +} + +// Cleans the current data-form popup +function cleanDataForm(target) { + if(target == 'discovery') + cleanDiscovery(); + else + $('#' + target + ' div.results').empty(); +} + +// Displays the no result indicator +function noResultDataForm(path) { + $(path).prepend('

' + _e("Sorry, but the entity didn't return any result!") + '

'); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/datastore.js b/sources/extend/addon/matrix/jappixmini/jappix/js/datastore.js new file mode 100644 index 00000000..b818b301 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/datastore.js @@ -0,0 +1,209 @@ +/* + +Jappix - An open social platform +These are the temporary/persistent data store functions + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 23/06/11 + +*/ + +// Temporary: returns whether it is available or not +function hasDB() { + if(window.sessionStorage) + return true; + + return false; +} + +// Temporary: used to read a database entry +function getDB(type, id) { + try { + return sessionStorage.getItem(type + '_' + id); + } + + catch(e) { + logThis('Error while getting a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return null; + } +} + +// Temporary: used to update a database entry +function setDB(type, id, value) { + try { + sessionStorage.setItem(type + '_' + id, value); + + return true; + } + + catch(e) { + logThis('Error while writing a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return false; + } +} + +// Temporary: used to remove a database entry +function removeDB(type, id) { + try { + sessionStorage.removeItem(type + '_' + id); + + return true; + } + + catch(e) { + logThis('Error while removing a temporary database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return false; + } +} + +// Temporary: used to check a database entry exists +function existDB(type, id) { + var read = getDB(type, id); + + if(read != null) + return true; + + return false; +} + +// Temporary: used to clear all the database +function resetDB() { + try { + sessionStorage.clear(); + + logThis('Temporary database cleared.', 3); + + return true; + } + + catch(e) { + logThis('Error while clearing temporary database: ' + e, 1); + + return false; + } +} + +// Persistent: returns whether it is available or not +function hasPersistent() { + if(window.localStorage) + return true; + + return false; +} + +// Persistent: used to read a database entry +function getPersistent(type, id) { + try { + return localStorage.getItem(type + '_' + id); + } + + catch(e) { + logThis('Error while getting a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return null; + } +} + +// Persistent: used to update a database entry +function setPersistent(type, id, value) { + try { + localStorage.setItem(type + '_' + id, value); + + return true; + } + + // Database might be full + catch(e) { + logThis('Retrying: could not write a persistent database entry (' + type + ' -> ' + id + '): ' + e, 2); + + // Flush it! + flushPersistent(); + + // Set the item again + try { + localStorage.setItem(type + '_' + id, value); + + return true; + } + + // New error! + catch(e) { + logThis('Aborted: error while writing a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return false; + } + } +} + +// Persistent: used to remove a database entry +function removePersistent(type, id) { + try { + localStorage.removeItem(type + '_' + id); + + return true; + } + + catch(e) { + logThis('Error while removing a persistent database entry (' + type + ' -> ' + id + '): ' + e, 1); + + return false; + } +} + +// Persistent: used to check a database entry exists +function existPersistent(type, id) { + var read = getPersistent(type, id); + + if(read != null) + return true; + + return false; +} + +// Persistent: used to clear all the database +function resetPersistent() { + try { + localStorage.clear(); + + logThis('Persistent database cleared.', 3); + + return true; + } + + catch(e) { + logThis('Error while clearing persistent database: ' + e, 1); + + return false; + } +} + +// Persistent: used to flush the database +function flushPersistent() { + try { + // Get the stored session entry + var session = getPersistent('session', 1); + + // Clear the persistent database + localStorage.clear(); + + // Restaure the stored session entry + if(session) + setPersistent('session', 1, session); + + logThis('Persistent database flushed.', 3); + + return true; + } + + catch(e) { + logThis('Error while flushing persistent database: ' + e, 1); + + return false; + } +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/date.js b/sources/extend/addon/matrix/jappixmini/jappix/js/date.js new file mode 100644 index 00000000..adbe01c8 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/date.js @@ -0,0 +1,214 @@ +/* + +Jappix - An open social platform +These are the date related JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 17/08/11 + +*/ + +// Gets a stamp from a date +function extractStamp(date) { + return Math.round(date.getTime() / 1000); +} + +// Gets the time from a date +function extractTime(date) { + return date.toLocaleTimeString(); +} + +// Gets the actual date stamp +function getTimeStamp() { + return extractStamp(new Date()); +} + +// Gets the last user activity in seconds +var LAST_ACTIVITY = 0; + +function getLastActivity() { + // Last activity not yet initialized? + if(LAST_ACTIVITY == 0) + return 0; + + return getTimeStamp() - LAST_ACTIVITY; +} + +// Gets the last user available presence in seconds +var PRESENCE_LAST_ACTIVITY = 0; + +function getPresenceLast() { + // Last presence stamp not yet initialized? + if(PRESENCE_LAST_ACTIVITY == 0) + return 0; + + return getTimeStamp() - PRESENCE_LAST_ACTIVITY; +} + +// Generates the time for XMPP +function getXMPPTime(location) { + /* FROM : http://trac.jwchat.org/jsjac/browser/branches/jsjac_1.0/jsextras.js?rev=221 */ + + // Initialize + var jInit = new Date(); + var year, month, day, hours, minutes, seconds; + + // Gets the UTC date + if(location == 'utc') { + year = jInit.getUTCFullYear(); + month = jInit.getUTCMonth(); + day = jInit.getUTCDate(); + hours = jInit.getUTCHours(); + minutes = jInit.getUTCMinutes(); + seconds = jInit.getUTCSeconds(); + } + + // Gets the local date + else { + year = jInit.getFullYear(); + month = jInit.getMonth(); + day = jInit.getDate(); + hours = jInit.getHours(); + minutes = jInit.getMinutes(); + seconds = jInit.getSeconds(); + } + + // Generates the date string + var jDate = year + '-'; + jDate += padZero(month + 1) + '-'; + jDate += padZero(day) + 'T'; + jDate += padZero(hours) + ':'; + jDate += padZero(minutes) + ':'; + jDate += padZero(seconds) + 'Z'; + + // Returns the date string + return jDate; +} + +// Generates then human time +function getCompleteTime() { + var init = new Date(); + var time = padZero(init.getHours()) + ':'; + time += padZero(init.getMinutes()) + ':'; + time += padZero(init.getSeconds()); + + return time; +} + +// Gets the TZO of a date +function getDateTZO() { + // Get the date + var date = new Date(); + var offset = date.getTimezoneOffset(); + + // Default vars + var sign = ''; + var hours = 0; + var minutes = 0; + + // Process a neutral offset + if(offset < 0) { + offset = offset * -1; + sign = '+'; + } + + // Get the values + var n_date = new Date(offset * 60 * 1000); + hours = n_date.getHours() - 1; + minutes = n_date.getMinutes(); + + // Process the TZO + tzo = sign + padZero(hours) + ':' + padZero(minutes); + + // Return the processed value + return tzo; +} + +// Parses a XMPP date (yyyy-mm-dd, hh-mm-ss) into an human-readable one +function parseDate(to_parse) { + var date = Date.jab2date(to_parse); + var parsed = date.toLocaleDateString() + ' (' + date.toLocaleTimeString() + ')'; + + return parsed; +} + +// Parses a XMPP date (yyyy-mm-dd) into an human-readable one +function parseDay(to_parse) { + var date = Date.jab2date(to_parse); + var parsed = date.toLocaleDateString(); + + return parsed; +} + +// Parses a XMPP date (hh-mm-ss) into an human-readable one +function parseTime(to_parse) { + var date = Date.jab2date(to_parse); + var parsed = date.toLocaleTimeString(); + + return parsed; +} + +// Parses a XMPP date stamp into a relative one +function relativeDate(to_parse) { + // Get the current date + var current_date = Date.jab2date(getXMPPTime('utc')); + var current_day = current_date.getDate(); + var current_stamp = current_date.getTime(); + + // Parse the given date + var old_date = Date.jab2date(to_parse); + var old_day = old_date.getDate(); + var old_stamp = old_date.getTime(); + var old_time = old_date.toLocaleTimeString(); + + // Get the day number between the two dates + var days = Math.round((current_stamp - old_stamp) / 86400000); + + // Invalid date? + if(isNaN(old_stamp) || isNaN(days)) + return getCompleteTime(); + + // Is it today? + if(current_day == old_day) + return old_time; + + // It is yesterday? + if(days <= 1) + return _e("Yesterday") + ' - ' + old_time; + + // Is it less than a week ago? + if(days <= 7) + return printf(_e("%s days ago"), days) + ' - ' + old_time; + + // Another longer period + return old_date.toLocaleDateString() + ' - ' + old_time; +} + +// Reads a message delay +function readMessageDelay(node) { + try { + // Initialize + var delay, d_delay; + + // Read the delay + d_delay = jQuery(node).find('delay[xmlns=' + NS_URN_DELAY + ']:first').attr('stamp'); + + // New delay (valid XEP) + if(d_delay) + delay = d_delay; + + // Old delay (obsolete XEP!) + else { + // Try to read the old-school delay + var x_delay = jQuery(node).find('x[xmlns=' + NS_DELAY + ']:first').attr('stamp'); + + if(x_delay) + delay = x_delay.replace(/^(\w{4})(\w{2})(\w{2})T(\w{2}):(\w{2}):(\w{2})Z?(\S+)?/, '$1-$2-$3T$4:$5:$6Z$7'); + } + + return delay; + } catch(e) {} +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/directory.js b/sources/extend/addon/matrix/jappixmini/jappix/js/directory.js new file mode 100644 index 00000000..ebe1a570 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/directory.js @@ -0,0 +1,87 @@ +/* + +Jappix - An open social platform +These are the directory JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 03/03/11 + +*/ + +// Opens the directory popup +function openDirectory() { + // Popup HTML content + var html = + '
' + _e("User directory") + '
' + + + '
' + + '
' + + '
' + _e("Server to query") + '
' + + + '' + + '
' + + + '
' + + '
' + + + '
' + + '
' + + + '' + _e("Close") + '' + + '
'; + + // Create the popup + createPopup('directory', html); + + // Associate the events + launchDirectory(); + + // Start a search! + startDirectory(); + + return false; +} + +// Quits the directory popup +function closeDirectory() { + // Destroy the popup + destroyPopup('directory'); + + return false; +} + +// Launches a directory search +function startDirectory() { + // Get the server to query + var server = $('#directory .directory-server-input').val(); + + // Launch the search! + dataForm($('#directory .directory-server-input').val(), 'search', '', '', 'directory'); + + logThis('Directory search launched: ' + server); + + return false; +} + +// Plugin launcher +function launchDirectory() { + // Click event + $('#directory .bottom .finish').click(closeDirectory); + + // Keyboard event + $('#directory .directory-server-input').keyup(function(e) { + if(e.keyCode == 13) { + // No value? + if(!$(this).val()) + $(this).val(HOST_VJUD); + + // Start the directory search + startDirectory(); + + return false; + } + }); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/discovery.js b/sources/extend/addon/matrix/jappixmini/jappix/js/discovery.js new file mode 100644 index 00000000..867037b2 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/discovery.js @@ -0,0 +1,169 @@ +/* + +Jappix - An open social platform +These are the discovery JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 03/03/11 + +*/ + +// Opens the discovery popup +function openDiscovery() { + // Popup HTML content + var html = + '
' + _e("Service discovery") + '
' + + + '
' + + '
' + + '
' + _e("Server to query") + '
' + + + '' + + '
' + + + '
' + + '' + + + '
' + + '

' + _e("Authentications") + '

' + + '
' + + + '
' + + '

' + _e("Automation") + '

' + + '
' + + + '
' + + '

' + _e("Clients") + '

' + + '
' + + + '
' + + '

' + _e("Collaboration") + '

' + + '
' + + + '
' + + '

' + _e("Components") + '

' + + '
' + + + '
' + + '

' + _e("Rooms") + '

' + + '
' + + + '
' + + '

' + _e("Directories") + '

' + + '
' + + + '
' + + '

' + _e("Gateways") + '

' + + '
' + + + '
' + + '

' + _e("News") + '

' + + '
' + + + '
' + + '

' + _e("Hierarchy") + '

' + + '
' + + + '
' + + '

' + _e("Proxies") + '

' + + '
' + + + '
' + + '

' + _e("Publication/Subscription") + '

' + + '
' + + + '
' + + '

' + _e("Server") + '

' + + '
' + + + '
' + + '

' + _e("Storage") + '

' + + '
' + + + '
' + + '

' + _e("Others") + '

' + + '
' + + + '
' + + '

' + _e("Loading") + '

' + + '
' + + '
' + + '
' + + + '
' + + '
' + + + '' + _e("Close") + '' + + '
'; + + // Create the popup + createPopup('discovery', html); + + // Associate the events + launchDiscovery(); + + // We request a disco to the default server + startDiscovery(); + + return false; +} + +// Quits the discovery popup +function closeDiscovery() { + // Destroy the popup + destroyPopup('discovery'); + + return false; +} + +// Launches a discovery +function startDiscovery() { + /* REF: http://xmpp.org/extensions/xep-0030.html */ + + // We get the server to query + var discoServer = $('#discovery .disco-server-input').val(); + + // We launch the items query + dataForm(discoServer, 'browse', '', '', 'discovery'); + + logThis('Service discovery launched: ' + discoServer); + + return false; +} + +// Cleans the discovery results +function cleanDiscovery() { + // We remove the results + $('#discovery .discovery-oneresult, #discovery .oneinstructions, #discovery .onetitle, #discovery .no-results').remove(); + + // We clean the user info + $('#discovery .disco-server-info').text(''); + + // We hide the wait icon, the no result alert and the results + $('#discovery .wait, #discovery .disco-category').hide(); +} + +// Plugin launcher +function launchDiscovery() { + // Click event + $('#discovery .bottom .finish').click(closeDiscovery); + + // Keyboard event + $('#discovery .disco-server-input').keyup(function(e) { + if(e.keyCode == 13) { + // No value? + if(!$(this).val()) + $(this).val(HOST_MAIN); + + // Start the discovery + startDiscovery(); + + return false; + } + }); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/error.js b/sources/extend/addon/matrix/jappixmini/jappix/js/error.js new file mode 100644 index 00000000..c16ca2a5 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/error.js @@ -0,0 +1,139 @@ +/* + +Jappix - An open social platform +These are the error functions for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 02/04/11 + +*/ + +// Shows the given error output +function showError(condition, reason, type) { + // Enough data to output the error + if(condition || reason) { + // Initialize the error text + var eText = ''; + + // Any error condition + if(condition) + eText += condition; + + // Any error type + if(type && eText) + eText += ' (' + type + ')'; + + // Any error reason + if(reason) { + if(eText) + eText += ' - '; + + eText += reason; + } + + // We reveal the error + openThisError(1); + + // Create the error text + $('#board .one-board.error[data-id=1] span').text(eText); + } + + // Not enough data to output the error: output a generic board + else + openThisError(2); +} + +// Handles the error from a packet and return true if any error +function handleError(packet) { + /* REF: http://xmpp.org/extensions/xep-0086.html */ + + // Initialize + var type, code, reason, condition; + var node = $(packet); + + // First level error (connection error) + if(node.is('error')) { + // Get the value + code = node.attr('code'); + + // Specific error reason + switch(code) { + case '401': + reason = _e("Authorization failed"); + break; + + case '409': + reason = _e("Registration failed, please choose a different username"); + break; + + case '503': + reason = _e("Service unavailable"); + break; + + case '500': + reason = _e("Internal server error, try later"); + break; + + default: + reason = node.find('text').text(); + break; + } + + // Remove the general wait item (security) + removeGeneralWait(); + + // Show reconnect pane + if(CURRENT_SESSION && CONNECTED) { + // Anonymous? + if(isAnonymous()) + createReconnect('anonymous'); + else + createReconnect('normal'); + } + + // Show the homepage (security) + else if(!CURRENT_SESSION || !CONNECTED) { + $('#home').show(); + pageTitle('home'); + } + + // Still connected? (security) + if(isConnected()) + con.disconnect(); + + logThis('First level error received.', 1); + } + + // Second level error (another error) + else if(node.find('error').size()) { + type = node.find('error').attr('type'); + reason = node.find('error text').text(); + condition = packet.getElementsByTagName('error').item(0).childNodes.item(0).nodeName.replace(/-/g, ' '); + + logThis('Second level error received.', 1); + } + + // No error + else + return false; + + // Show the error board + showError(condition, reason, type); + + // Return there's an error + return true; +} + +// Handles the error reply of a packet +function handleErrorReply(packet) { + return handleError(packet.getNode()); +} + +// Handles the error reply for a message +function handleMessageError(packet) { + if(!handleErrorReply(packet)) + handleMessage(packet); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/favorites.js b/sources/extend/addon/matrix/jappixmini/jappix/js/favorites.js new file mode 100644 index 00000000..69a042e8 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/favorites.js @@ -0,0 +1,537 @@ +/* + +Jappix - An open social platform +These are the favorites JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 23/06/11 + +*/ + +// Opens the favorites popup +function openFavorites() { + // Popup HTML content + var html = + '
' + _e("Manage favorite rooms") + '
' + + + '
' + + '
' + + '
' + + '
' + + + _e("Change favorites") + + '
' + + + '' + + '
' + + + '
' + + '
' + + '
' + + '
' + _e("Select a favorite") + '
' + + + '' + + '
' + + + '
' + + '
' + + '' + + + '' + + '
' + + + '
' + + '' + + + '' + + '
' + + + '
' + + '' + + + '' + + '
' + + + '
' + + '' + + + '' + + '
' + + + '
' + + '' + + + '' + + '
' + + + '
' + + '' + + + '' + + '
' + + + '' + + '
' + + '
' + + + '' + + '
' + + '
' + + + '
' + + '
' + + + '' + _e("Close") + '' + + '
'; + + // Create the popup + createPopup('favorites', html); + + // Load the favorites + loadFavorites(); + + // Associate the events + launchFavorites(); +} + +// Resets the favorites elements +function resetFavorites() { + var path = '#favorites '; + + $(path + '.wait, ' + path + '.fedit-terminate').hide(); + $(path + '.fedit-add').show(); + $(path + '.fsearch-oneresult').remove(); + $(path + 'input').val(''); + $(path + '.please-complete').removeClass('please-complete'); + $(path + '.fedit-nick').val(getNick()); + $(path + '.fsearch-head-server, ' + path + '.fedit-server').val(HOST_MUC); + $(path + '.fedit-autojoin').attr('checked', false); +} + +// Quits the favorites popup +function quitFavorites() { + // Destroy the popup + destroyPopup('favorites'); + + return false; +} + +// Adds a room to the favorites +function addThisFavorite(roomXID, roomName) { + // Button path + var button = '#favorites .fsearch-results div[data-xid=' + escape(roomXID) + '] a.one-button'; + + // Add a remove button instead of the add one + $(button + '.add').replaceWith('' + _e("Remove") + ''); + + // Click event + $(button + '.remove').click(function() { + return removeThisFavorite(roomXID, roomName); + }); + + // Hide the add button in the (opened?) groupchat + $('#' + hex_md5(roomXID) + ' .tools-add').hide(); + + // Add the database entry + displayFavorites(roomXID, explodeThis(' (', roomName, 0), getNick(), '0', ''); + + // Publish the favorites + favoritePublish(); + + return false; +} + +// Removes a room from the favorites +function removeThisFavorite(roomXID, roomName) { + // Button path + var button = '#favorites .fsearch-results div[data-xid=' + escape(roomXID) + '] a.one-button'; + + // Add a remove button instead of the add one + $(button + '.remove').replaceWith('' + _e("Add") + ''); + + // Click event + $(button + '.add').click(function() { + return addThisFavorite(roomXID, roomName); + }); + + // Show the add button in the (opened?) groupchat + $('#' + hex_md5(roomXID) + ' .tools-add').show(); + + // Remove the favorite + removeFavorite(roomXID, true); + + // Publish the favorites + favoritePublish(); + + return false; +} + +// Edits a favorite +function editFavorite() { + // Path to favorites + var favorites = '#favorites .'; + + // Reset the favorites + resetFavorites(); + + // Show the edit/remove button, hide the others + $(favorites + 'fedit-terminate').hide(); + $(favorites + 'fedit-edit').show(); + $(favorites + 'fedit-remove').show(); + + // We retrieve the values + var xid = $(favorites + 'fedit-head-select').val(); + var data = XMLFromString(getDB('favorites', xid)); + + // If this is not the default room + if(xid != 'none') { + // We apply the values + $(favorites + 'fedit-title').val($(data).find('name').text()); + $(favorites + 'fedit-nick').val($(data).find('nick').text()); + $(favorites + 'fedit-chan').val(getXIDNick(xid)); + $(favorites + 'fedit-server').val(getXIDHost(xid)); + $(favorites + 'fedit-password').val($(data).find('password').text()); + + if($(data).find('autojoin').text() == '1') + $(favorites + 'fedit-autojoin').attr('checked', true); + } + + else + resetFavorites(); +} + +// Adds a favorite +function addFavorite() { + // Path to favorites + var favorites = '#favorites .'; + + // We reset the inputs + $(favorites + 'fedit-title, ' + favorites + 'fedit-nick, ' + favorites + 'fedit-chan, ' + favorites + 'fedit-server, ' + favorites + 'fedit-password').val(''); + + // Show the add button, hide the others + $(favorites + 'fedit-terminate').hide(); + $(favorites + 'fedit-add').show(); +} + +// Terminate a favorite editing +function terminateThisFavorite(type) { + // Path to favorites + var favorites = '#favorites '; + + // We get the values of the current edited groupchat + var old_xid = $(favorites + '.fedit-head-select').val(); + + var title = $(favorites + '.fedit-title').val(); + var nick = $(favorites + '.fedit-nick').val(); + var room = $(favorites + '.fedit-chan').val(); + var server = $(favorites + '.fedit-server').val(); + var xid = room + '@' + server; + var password = $(favorites + '.fedit-password').val(); + var autojoin = '0'; + + if($(favorites + '.fedit-autojoin').filter(':checked').size()) + autojoin = '1'; + + // We check the missing values and send this if okay + if((type == 'add') || (type == 'edit')) { + if(title && nick && room && server) { + // Remove the edited room + if(type == 'edit') + removeFavorite(old_xid, true); + + // Display the favorites + displayFavorites(xid, title, nick, autojoin, password); + + // Reset the inputs + resetFavorites(); + } + + else { + $(favorites + 'input[required]').each(function() { + var select = $(this); + + if(!select.val()) + $(document).oneTime(10, function() { + select.addClass('please-complete').focus(); + }); + else + select.removeClass('please-complete'); + }); + } + } + + // Must remove a favorite? + else if(type == 'remove') { + removeFavorite(old_xid, true); + + // Reset the inputs + resetFavorites(); + } + + // Publish the new favorites + favoritePublish(); + + logThis('Action on this bookmark: ' + room + '@' + server + ' / ' + type, 3); + + return false; +} + +// Removes a favorite +function removeFavorite(xid, database) { + // We remove the target favorite everywhere needed + $('.buddy-conf-groupchat-select option[value=' + xid + ']').remove(); + $('.fedit-head-select option[value=' + xid + ']').remove(); + + // Must remove it from database? + if(database) + removeDB('favorites', xid); +} + +// Sends a favorite to the XMPP server +function favoritePublish() { + var iq = new JSJaCIQ(); + iq.setType('set'); + + var query = iq.setQuery(NS_PRIVATE); + var storage = query.appendChild(iq.buildNode('storage', {'xmlns': NS_BOOKMARKS})); + + // We generate the XML + for(var i = 0; i < sessionStorage.length; i++) { + // Get the pointer values + var current = sessionStorage.key(i); + + // If the pointer is on a stored favorite + if(explodeThis('_', current, 0) == 'favorites') { + var data = XMLFromString(sessionStorage.getItem(current)); + var xid = $(data).find('xid').text(); + var rName = $(data).find('name').text(); + var nick = $(data).find('nick').text(); + var password = $(data).find('password').text(); + var autojoin = $(data).find('autojoin').text(); + + // We create the node for this groupchat + var item = storage.appendChild(iq.buildNode('conference', {'name': rName, 'jid': xid, 'autojoin': autojoin, xmlns: NS_BOOKMARKS})); + item.appendChild(iq.buildNode('nick', {xmlns: NS_BOOKMARKS}, nick)); + + if(password) + item.appendChild(iq.buildNode('password', {xmlns: NS_BOOKMARKS}, password)); + + logThis('Bookmark sent: ' + xid, 3); + } + } + + con.send(iq); +} + +// Gets a list of the MUC items on a given server +function getGCList() { + var path = '#favorites .'; + var gcServer = $('.fsearch-head-server').val(); + + // We reset some things + $(path + 'fsearch-oneresult').remove(); + $(path + 'fsearch-noresults').hide(); + $(path + 'wait').show(); + + var iq = new JSJaCIQ(); + iq.setType('get'); + iq.setTo(gcServer); + + iq.setQuery(NS_DISCO_ITEMS); + + con.send(iq, handleGCList); +} + +// Handles the MUC items list +function handleGCList(iq) { + var path = '#favorites .'; + var from = fullXID(getStanzaFrom(iq)); + + if (!iq || (iq.getType() != 'result')) { + openThisError(3); + + $(path + 'wait').hide(); + + logThis('Error while retrieving the rooms: ' + from, 1); + } + + else { + var handleXML = iq.getQuery(); + + if($(handleXML).find('item').size()) { + // Initialize the HTML code + var html = ''; + + $(handleXML).find('item').each(function() { + var roomXID = $(this).attr('jid'); + var roomName = $(this).attr('name'); + + if(roomXID && roomName) { + // Escaped values + var escaped_xid = encodeOnclick(roomXID); + var escaped_name = encodeOnclick(roomName); + + // Initialize the room HTML + html += '
' + + '
' + roomName.htmlEnc() + '
' + + '' + _e("Join") + ''; + + // This room is yet a favorite + if(existDB('favorites', roomXID)) + html += '' + _e("Remove") + ''; + else + html += '' + _e("Add") + ''; + + // Close the room HTML + html += '
'; + } + }); + + // Append this code to the popup + $(path + 'fsearch-results').append(html); + } + + else + $(path + 'fsearch-noresults').show(); + + logThis('Rooms retrieved: ' + from, 3); + } + + $(path + 'wait').hide(); +} + +// Joins a groupchat from favorites +function joinFavorite(room) { + quitFavorites(); + checkChatCreate(room, 'groupchat', '', '', getXIDNick(room)); + + return false; +} + +// Displays a given favorite +function displayFavorites(xid, name, nick, autojoin, password) { + // Generate the HTML code + var html = ''; + + // Remove the existing favorite + removeFavorite(xid, false); + + // We complete the select forms + $('#buddy-list .gc-join-first-option, #favorites .fedit-head-select-first-option').after(html); + + // We store the informations + var value = '' + xid.htmlEnc() + '' + name.htmlEnc() + '' + nick.htmlEnc() + '' + autojoin.htmlEnc() + '' + password.htmlEnc() + ''; + setDB('favorites', xid, value); +} + +// Loads the favorites for the popup +function loadFavorites() { + // Initialize the HTML code + var html = ''; + + // Read the database + for(var i = 0; i < sessionStorage.length; i++) { + // Get the pointer values + var current = sessionStorage.key(i); + + // If the pointer is on a stored favorite + if(explodeThis('_', current, 0) == 'favorites') { + var data = XMLFromString(sessionStorage.getItem(current)); + + // Add the current favorite to the HTML code + html += ''; + } + } + + // Generate specific HTML code + var favorites_bubble = '' + html; + var favorites_popup = '' + html; + + // Append the HTML code + $('#buddy-list .buddy-conf-groupchat-select').html(favorites_bubble); + $('#favorites .fedit-head-select').html(favorites_popup); +} + +// Plugin launcher +function launchFavorites() { + var path = '#favorites .'; + + // Keyboard events + $(path + 'fsearch-head-server').keyup(function(e) { + if(e.keyCode == 13) { + // No value? + if(!$(this).val()) + $(this).val(HOST_MUC); + + // Get the list + getGCList(); + } + }); + + $(path + 'fedit-line input').keyup(function(e) { + if(e.keyCode == 13) { + // Edit a favorite + if($(path + 'fedit-edit').is(':visible')) + terminateThisFavorite('edit'); + + // Add a favorite + else + terminateThisFavorite('add'); + } + }); + + // Change events + $('.fedit-head-select').change(editFavorite); + + // Click events + $(path + 'room-switcher').click(function() { + $(path + 'favorites-content').hide(); + resetFavorites(); + }); + + $(path + 'room-list').click(function() { + $(path + 'favorites-edit').show(); + }); + + $(path + 'room-search').click(function() { + $(path + 'favorites-search').show(); + getGCList(); + }); + + $(path + 'fedit-add').click(function() { + return terminateThisFavorite('add'); + }); + + $(path + 'fedit-edit').click(function() { + return terminateThisFavorite('edit'); + }); + + $(path + 'fedit-remove').click(function() { + return terminateThisFavorite('remove'); + }); + + $(path + 'bottom .finish').click(function() { + return quitFavorites(); + }); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/features.js b/sources/extend/addon/matrix/jappixmini/jappix/js/features.js new file mode 100644 index 00000000..4944be0a --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/features.js @@ -0,0 +1,213 @@ +/* + +Jappix - An open social platform +This is the server features JS script for Jappix + +------------------------------------------------- + +License: AGPL +Author: Vanaryon +Last revision: 01/06/11 + +*/ + +// Gets the features of a server +function getFeatures() { + /* REF: http://xmpp.org/extensions/xep-0030.html */ + + // Get the main values + var to = getServer(); + var caps = con.server_caps; + var xml = null; + + // Try to get the stored data + if(caps) + xml = XMLFromString(getPersistent('caps', caps)); + + // Any stored data? + if(xml) { + handleFeatures(xml); + + logThis('Read server CAPS from cache.'); + } + + // Not stored (or no CAPS)! + else { + var iq = new JSJaCIQ(); + + iq.setTo(to); + iq.setType('get'); + iq.setQuery(NS_DISCO_INFO); + + con.send(iq, handleDiscoInfos); + + logThis('Read server CAPS from network.'); + } +} + +// Handles the features of a server +function handleFeatures(xml) { + // Selector + var selector = $(xml); + + // Markers + var pep = false; + var pubsub = false; + var archive = false; + var archive_auto = false; + var archive_manual = false; + var archive_manage = false; + var archive_pref = false; + var commands = false; + + // Scan the features + if(selector.find('identity[category=pubsub][type=pep]').size()) + pep = true; + if(selector.find('feature[var=' + NS_PUBSUB + ']').size()) + pubsub = true; + if(selector.find('feature[var=' + NS_URN_ARCHIVE + ']').size()) + archive = true; + if(selector.find('feature[var=' + NS_URN_AR_AUTO + ']').size()) + archive_auto = true; + if(selector.find('feature[var=' + NS_URN_AR_MANUAL + ']').size()) + archive_manual = true; + if(selector.find('feature[var=' + NS_URN_AR_MANAGE + ']').size()) + archive_manage = true; + if(selector.find('feature[var=' + NS_URN_AR_PREF + ']').size()) + archive_pref = true; + if(selector.find('feature[var=' + NS_COMMANDS + ']').size()) + commands = true; + + // Enable the pep elements if available + if(pep) { + // Update our database + enableFeature('pep'); + + // Get the microblog + getInitMicroblog(); + + // Get the notifications + getNotifications(); + + // Geolocate the user + geolocate(); + + // Enable microblogging send tools + waitMicroblog('sync'); + $('.postit.attach').css('display', 'block'); + + logThis('XMPP server supports PEP.', 3); + } + + // Disable microblogging send tools (no PEP!) + else { + waitMicroblog('unsync'); + + logThis('XMPP server does not support PEP.', 2); + } + + // Enable the pubsub features if available + if(pubsub) + enableFeature(NS_PUBSUB); + + // Enable the archiving features if available + if(archive) + enableFeature(NS_URN_ARCHIVE); + + // Enable the archiving sub-features if available + if(archive_pref) + enableFeature(NS_URN_AR_PREF); + if(archive_auto) + enableFeature(NS_URN_AR_AUTO); + if(archive_manual) + enableFeature(NS_URN_AR_MANUAL); + if(archive_manage) + enableFeature(NS_URN_AR_MANAGE); + + // Enable the commands features if available + if(commands) + enableFeature(NS_COMMANDS); + + // Hide the private life fieldset if nothing to show + if(!pep && !archive_pref) + $('#options fieldset.privacy').hide(); + + // Apply the features + applyFeatures('talk'); + + // Process the buddy-list height + if(pep) + adaptRoster(); + + return false; +} + +// The function to apply the features to an element +function applyFeatures(id) { + // Path to the elements + var path = '#' + id + ' .'; + + // PEP features + if(enabledPEP()) + $(path + 'pep-hidable').show(); + + // PubSub features + if(enabledPubSub()) + $(path + 'pubsub-hidable').show(); + + // Archives features + if(enabledArchives() || enabledArchives('auto') || enabledArchives('manual') || enabledArchives('manage')) { + $(path + 'archives-hidable:not(.pref)').show(); + + // Sub-feature: archives preferences + if(enabledArchives('pref')) + $(path + 'archives-hidable.pref').show(); + } + + // Commands features + if(enabledCommands()) + $(path + 'commands-hidable').show(); + + // XMPP links (browser feature) + if(navigator.registerProtocolHandler) + $(path + 'xmpplinks-hidable').show(); +} + +// Enables a feature +function enableFeature(feature) { + setDB('feature', feature, 'true'); +} + +// Checks if a feature is enabled +function enabledFeature(feature) { + if(getDB('feature', feature) == 'true') + return true; + else + return false; +} + +// Returns the XMPP server PEP support +function enabledPEP() { + return enabledFeature('pep'); +} + +// Returns the XMPP server PubSub support +function enabledPubSub() { + return enabledFeature(NS_PUBSUB); +} + +// Returns the XMPP server archives support +function enabledArchives(sub) { + var xmlns = NS_URN_ARCHIVE; + + // Any sub element sent? + if(sub) + xmlns += ':' + sub; + + return enabledFeature(xmlns); +} + +// Returns the XMPP server commands support +function enabledCommands() { + return enabledFeature(NS_COMMANDS); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/filter.js b/sources/extend/addon/matrix/jappixmini/jappix/js/filter.js new file mode 100644 index 00000000..48e5238f --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/filter.js @@ -0,0 +1,189 @@ +/* + +Jappix - An open social platform +These are the filtering JS script for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, Maranda +Last revision: 04/08/11 + +*/ + +// Generates a given emoticon HTML code +function emoteImage(image, text, after) { + return ' ' + encodeQuotes(text) + ' ' + after; +} + +// Filters a given message +function filterThisMessage(neutralMessage, nick, html_encode) { + var filteredMessage = neutralMessage; + + // We encode the HTML special chars + if(html_encode) + filteredMessage = filteredMessage.htmlEnc(); + + // /me command + filteredMessage = filteredMessage.replace(/((^)|((.+)(>)))(\/me )([^<]+)/, nick + ' $7') + + // We replace the smilies text into images + .replace(/(:-?@)($|\s|<)/gi, emoteImage('angry', '$1', '$2')) + .replace(/(:-?\[)($|\s|<)/gi, emoteImage('bat', '$1', '$2')) + .replace(/(\(B\))($|\s|<)/g, emoteImage('beer', '$1', '$2')) + .replace(/((:-?D)|(XD))($|\s|<)/gi, emoteImage('biggrin', '$1', '$4')) + .replace(/(:-?\$)($|\s|<)/gi, emoteImage('blush', '$1', '$2')) + .replace(/(\(Z\))($|\s|<)/g, emoteImage('boy', '$1', '$2')) + .replace(/(\(W\))($|\s|<)/g, emoteImage('brflower', '$1', '$2')) + .replace(/((<\/3)|(\(U\)))($|\s|<)/g, emoteImage('brheart', '$1', '$4')) + .replace(/(\(C\))($|\s|<)/g, emoteImage('coffee', '$1', '$2')) + .replace(/((8-\))|(\(H\)))($|\s|<)/g, emoteImage('coolglasses', '$1', '$4')) + .replace(/(:'-?\()($|\s|<)/gi, emoteImage('cry', '$1', '$2')) + .replace(/(\(%\))($|\s|<)/g, emoteImage('cuffs', '$1', '$2')) + .replace(/(\]:-?>)($|\s|<)/gi, emoteImage('devil', '$1', '$2')) + .replace(/(\(D\))($|\s|<)/g, emoteImage('drink', '$1', '$2')) + .replace(/(@}->--)($|\s|<)/gi, emoteImage('flower', '$1', '$2')) + .replace(/((:-?\/)|(:-?S))($|\s|<)/gi, emoteImage('frowning', '$1', '$4')) + .replace(/(\(X\))($|\s|<)/g, emoteImage('girl', '$1', '$2')) + .replace(/((<3)|(\(L\)))($|\s|<)/g, emoteImage('heart', '$1', '$4')) + .replace(/(\(}\))($|\s|<)/g, emoteImage('hugleft', '$1', '$2')) + .replace(/(\({\))($|\s|<)/g, emoteImage('hugright', '$1', '$2')) + .replace(/(:-?{})($|\s|<)/gi, emoteImage('kiss', '$1', '$2')) + .replace(/(\(I\))($|\s|<)/g, emoteImage('lamp', '$1', '$2')) + .replace(/(:-?3)($|\s|<)/gi, emoteImage('lion', '$1', '$2')) + .replace(/(\(E\))($|\s|<)/g, emoteImage('mail', '$1', '$2')) + .replace(/(\(S\))($|\s|<)/g, emoteImage('moon', '$1', '$2')) + .replace(/(\(8\))($|\s|<)/g, emoteImage('music', '$1', '$2')) + .replace(/((=-?O)|(:-?O))($|\s|<)/gi, emoteImage('oh', '$1', '$4')) + .replace(/(\(T\))($|\s|<)/g, emoteImage('phone', '$1', '$2')) + .replace(/(\(P\))($|\s|<)/g, emoteImage('photo', '$1', '$2')) + .replace(/(:-?!)($|\s|<)/gi, emoteImage('puke', '$1', '$2')) + .replace(/(\(@\))($|\s|<)/g, emoteImage('pussy', '$1', '$2')) + .replace(/(\(R\))($|\s|<)/g, emoteImage('rainbow', '$1', '$2')) + .replace(/(:-?\))($|\s|<)/gi, emoteImage('smile', '$1', '$2')) + .replace(/(\(\*\))($|\s|<)/g, emoteImage('star', '$1', '$2')) + .replace(/(:-?\|)($|\s|<)/gi, emoteImage('stare', '$1', '$2')) + .replace(/(\(N\))($|\s|<)/g, emoteImage('thumbdown', '$1', '$2')) + .replace(/(\(Y\))($|\s|<)/g, emoteImage('thumbup', '$1', '$2')) + .replace(/(:-?P)($|\s|<)/gi, emoteImage('tongue', '$1', '$2')) + .replace(/(:-?\()($|\s|<)/gi, emoteImage('unhappy', '$1', '$2')) + .replace(/(;-?\))($|\s|<)/gi, emoteImage('wink', '$1', '$2')) + + // Text in bold + .replace(/(^|\s|>)((\*)([^<>'"]+)(\*))($|\s|<)/gi, '$1$2$6') + + // Italic text + .replace(/(^|\s|>)((\/)([^<>'"]+)(\/))($|\s|<)/gi, '$1$2$6') + + // Underlined text + .replace(/(^|\s|>)((_)([^<>'"]+)(_))($|\s|<)/gi, '$1$2$6'); + + // Add the links + if(html_encode) + filteredMessage = applyLinks(filteredMessage, 'desktop'); + + // Filter integratebox links + filteredMessage = filterIntegrateBox(filteredMessage); + + return filteredMessage; +} + +// Filters a xHTML message to be displayed in Jappix +function filterThisXHTML(code) { + // Allowed elements array + var elements = new Array( + 'a', + 'abbr', + 'acronym', + 'address', + 'blockquote', + 'body', + 'br', + 'cite', + 'code', + 'dd', + 'dfn', + 'div', + 'dt', + 'em', + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', + 'head', + 'html', + 'img', + 'kbd', + 'li', + 'ol', + 'p', + 'pre', + 'q', + 'samp', + 'span', + 'strong', + 'title', + 'ul', + 'var' + ); + + // Allowed attributes array + var attributes = new Array( + 'accesskey', + 'alt', + 'charset', + 'cite', + 'class', + 'height', + 'href', + 'hreflang', + 'id', + 'longdesc', + 'profile', + 'rel', + 'rev', + 'src', + 'style', + 'tabindex', + 'title', + 'type', + 'uri', + 'version', + 'width', + 'xml:lang', + 'xmlns' + ); + + // Remove forbidden elements + $(code).find('html body *').each(function() { + // This element is not authorized + if(!existArrayValue(elements, (this).nodeName.toLowerCase())) + $(this).remove(); + }); + + // Remove forbidden attributes + $(code).find('html body *').each(function() { + // Put a pointer on this element (jQuery way & normal way) + var cSelector = $(this); + var cElement = (this); + + // Loop the attributes of the current element + $(cElement.attributes).each(function(index) { + // Read the current attribute + var cAttr = cElement.attributes[index]; + var cName = cAttr.name; + var cVal = cAttr.value; + + // This attribute is not authorized, or contains JS code + if(!existArrayValue(attributes, cName.toLowerCase()) || ((cVal.toLowerCase()).match(/(^|"|')javascript:/))) + cSelector.removeAttr(cName); + }); + }); + + // Filter some other elements + $(code).find('a').attr('target', '_blank'); + + return $(code).find('html body').html(); +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/groupchat.js b/sources/extend/addon/matrix/jappixmini/jappix/js/groupchat.js new file mode 100644 index 00000000..c8dd13b1 --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/groupchat.js @@ -0,0 +1,283 @@ +/* + +Jappix - An open social platform +These are the groupchat JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, Maranda, Eric +Last revision: 28/08/11 + +*/ + +// Displays the MUC admin elements +function displayMucAdmin(affiliation, id, xid, statuscode) { + // We must be in the "login" mode + if(isAnonymous()) + return; + + // We check if the user is a room owner or administrator to give him privileges + if(affiliation == 'owner' || affiliation == 'admin') + $('#' + id + ' .tools-mucadmin').show(); + + // We check if the room hasn't been yet created + if(statuscode == 201) + openThisInfo(4); + + // We add the click event + $('#' + id + ' .tools-mucadmin').click(function() { + openMucAdmin(xid, affiliation); + }); +} + +// Initializes a connection with a MUC groupchat +function getMUC(room, nickname, password) { + // Room hash + var hash = hex_md5(room); + + // Reset the elements + $('#' + hash + ' .muc-ask').remove(); + $('#' + hash + ' .compose').show(); + + // No nickname? + if(!nickname) { + // Get some values + if(!isAnonymous()) + nickname = getNick(); + else + nickname = ANONYMOUS_NICK; + + // If the nickname could not be retrieved, ask it + if(!nickname) + generateMUCAsk('nickname', room, hash, nickname, password); + } + + // Got our nickname? + if(nickname) { + // Get our general presence + var show = getDB('presence-show', 1); + var status = getDB('options', 'presence-status'); + + // Set my nick + $('#' + hash).attr('data-nick', escape(nickname)); + + // Send the appropriate presence + sendPresence(room + '/' + nickname, '', show, status, '', true, password, handleMUC); + } + + return false; +} + +// Handles the MUC main elements +function handleMUC(presence) { + // We get the xml content + var xml = presence.getNode(); + var from = fullXID(getStanzaFrom(presence)); + var room = bareXID(from); + var nickname = thisResource(from); + var hash = hex_md5(room); + + // No ID: must fix M-Link bug + if(presence.getID() == null) + presence.setID(1); + + logThis('First MUC presence: ' + from, 3); + + // Catch the errors + if(!handleError(xml)) { + // Define some stuffs + var muc_user = $(xml).find('x[xmlns=' + NS_MUC_USER + ']'); + var affiliation = muc_user.find('item').attr('affiliation'); + var statuscode = parseInt(muc_user.find('status').attr('code')); + + // Handle my presence + handlePresence(presence); + + // Check if I am a room owner + displayMucAdmin(affiliation, hash, room, statuscode); + + // Tell the MUC we can notify the incoming presences + $(document).oneTime('15s', function() { + $('#' + hash).attr('data-initial', 'true'); + }); + + // Enable the chatting input + $(document).oneTime(10, function() { + $('#' + hash + ' .message-area').removeAttr('disabled').focus(); + }); + } + + // A password is required + else if($(xml).find('error[type=auth] not-authorized').size()) + generateMUCAsk('password', room, hash, nickname); + + // There's a nickname conflict + else if($(xml).find('error[type=cancel] conflict').size()) + generateMUCAsk('nickname', room, hash); +} + +// Generates a correct MUC asker +function generateMUCAsk(type, room, hash, nickname, password) { + // Generate the path to the elements + var path_to = '#' + hash + ' .muc-ask'; + + // Define the label text + var label_text; + + switch(type) { + case 'nickname': + label_text = _e("Nickname"); + break; + + case 'password': + label_text = _e("Password"); + break; + } + + // Create the HTML markup + $('#' + hash + ' .compose').hide(); + + $('#' + hash).append( + '
' + + '' + + '' + + '
' + ); + + // When a key is pressed in the input + $(path_to + ' input').keyup(function(e) { + var value_input = $(this).val(); + + // Enter key pressed + if((e.keyCode == 13) && value_input) { + if(type == 'nickname') + nickname = value_input; + else if(type == 'password') + password = value_input; + + return getMUC(room, nickname, password); + } + }); + + // Focus on the input + $(document).oneTime(10, function() { + $(path_to + ' input').focus(); + }); +} + +// Creates a new groupchat +function groupchatCreate(hash, room, chan, nickname, password) { + /* REF: http://xmpp.org/extensions/xep-0045.html */ + + logThis('New groupchat: ' + room, 3); + + // Create the chat content + generateChat('groupchat', hash, room, chan); + + // Create the chat switcher + generateSwitch('groupchat', hash, room, chan); + + // The icons-hover functions + tooltipIcons(room, hash); + + // Click event on the add tool + $('#' + hash + ' .tools-add').click(function() { + // Hide the icon (to tell the user all is okay) + $(this).hide(); + + // Add the groupchat to the user favorites + addThisFavorite(room, chan); + }); + + // Must show the add button? + if(!existDB('favorites', room)) + $('#' + hash + ' .tools-add').show(); + + // The event handlers + var inputDetect = $('#' + hash + ' .message-area'); + + // Focus event + inputDetect.focus(function() { + chanCleanNotify(hash); + }) + + // Blur event + inputDetect.blur(function() { + resetAutocompletion(hash); + }) + + // Lock to the input + inputDetect.keypress(function(e) { + // Enter key + if(e.keyCode == 13) { + // Add a new line + if(e.shiftKey) + inputDetect.val(inputDetect.val() + '\n'); + + // Send the message + else { + sendMessage(hash, 'groupchat'); + + // Reset the composing database entry + setDB('chatstate', room, 'off'); + } + + return false; + } + + // Tabulation key + else if(e.keyCode == 9) { + createAutocompletion(hash); + + return false; + } + + // Reset the autocompleter + else + resetAutocompletion(hash); + }); + + // Chatstate events + eventsChatState(inputDetect, room, hash); + + // Get the current muc informations and content + getMUC(room, nickname, password); +} + +// Joins the defined groupchats +function joinConfGroupchats() { + // Nothing to join? + if(!GROUPCHATS_JOIN) + return; + + // Values array + var muc_arr = [GROUPCHATS_JOIN]; + var new_arr = []; + + // Try to split it + if(GROUPCHATS_JOIN.indexOf(',') != -1) + muc_arr = GROUPCHATS_JOIN.split(','); + + for(i in muc_arr) { + // Get the current value + var muc_current = trim(muc_arr[i]); + + // No current value? + if(!muc_current) + continue; + + // Filter the current value + muc_current = generateXID(muc_current, 'groupchat'); + + // Add the current value + if(!existArrayValue(new_arr, muc_current)) + new_arr.push(muc_current); + } + + // Join the chats + if(new_arr.length) { + for(g in new_arr) + checkChatCreate(new_arr[g], 'groupchat'); + } +} diff --git a/sources/extend/addon/matrix/jappixmini/jappix/js/home.js b/sources/extend/addon/matrix/jappixmini/jappix/js/home.js new file mode 100644 index 00000000..5322501d --- /dev/null +++ b/sources/extend/addon/matrix/jappixmini/jappix/js/home.js @@ -0,0 +1,371 @@ +/* + +Jappix - An open social platform +These are the homepage JS scripts for Jappix + +------------------------------------------------- + +License: AGPL +Authors: Vanaryon, LinkMauve +Last revision: 15/01/12 + +*/ + +// Allows the user to switch the difference home page elements +function switchHome(div) { + // Path to + var home = '#home .'; + var right = home + 'right '; + var current = right + '.homediv.' + div; + + // We switch the div + $(right + '.homediv, ' + right + '.top').hide(); + $(right + '.' + div).show(); + + // We reset the homedivs + $(home + 'homediv:not(.default), ' + home + 'top:not(.default)').remove(); + + // Get the HTML code to display + var disable_form = ''; + var lock_host = ''; + var code = ''; + + // Apply the previous link + switch(div) { + case 'loginer': + case 'anonymouser': + case 'registerer': + if(!exists(right + '.top.sub')) { + // Append the HTML code for previous link + $(right + '.top.default').after('

«

'); + + // Click event on previous link + $(home + 'top.sub a.previous').click(function() { + return switchHome('default'); + }); + } + + break; + } + + // Apply the form + switch(div) { + // Login tool + case 'loginer': + lock_host = disableInput(LOCK_HOST, 'on'); + code = '

' + printf(_e("Login to your existing XMPP account. You can also use the %s to join a groupchat."), '' + _e("anonymous mode") + '') + '

' + + + '
' + + '
' + + '' + _e("Required") + '' + + + '' + + '@' + + '' + + '' + + '' + + '' + + '
' + + + '' + _e("Advanced") + '' + + + '
' + + '' + _e("Advanced") + '' + + + '' + + '' + + '' + + '' + + '
' + + + '' + + '
'; + + break; + + // Anonymous login tool + case 'anonymouser': + disable_form = disableInput(ANONYMOUS, 'off'); + code = '

' + printf(_e("Enter the groupchat you want to join and the nick you want to have. You can also go back to the %s."), '' + _e("login page") + '') + '

' + + + '
' + + '
' + + '' + _e("Required") + '' + + + '' + + '' + + + '' + + '' + + '
' + + + '' + + '
' + + + '
' + + _e("Share this link with your friends:") + ' ' + + '
'; + + break; + + // Register tool + case 'registerer': + disable_form = disableInput(REGISTRATION, 'off'); + + if(!disable_form) + lock_host = disableInput(LOCK_HOST, 'on'); + + code = '

' + _e("Register a new XMPP account to join your friends on your own social cloud. That's simple!") + '

' + + + '
' + + '
' + + '' + _e("Required") + '' + + + '' + + '@' + + '' + + '' + + '' + + '
' + + + '' + + '
'; + + break; + } + + // Form disabled? + if(disable_form) + code += '
' + + _e("This tool has been disabled, you cannot use it!") + + '
'; + + // Create this HTML code + if(code && !exists(current)) { + // Append it! + $(right + '.homediv.default').after('
' + code + '
'); + + // Create the attached events + switch(div) { + // Login tool + case 'loginer': + $(current + ' a.to-anonymous').click(function() { + return switchHome('anonymouser'); + }); + + $(current + ' a.advanced').click(showAdvanced); + + $(current + ' form').submit(loginForm); + + break; + + // Anonymous login tool + case 'anonymouser': + $(current + ' a.to-home').click(function() { + return switchHome('loginer'); + }); + + $(current + ' form').submit(doAnonymous); + + // Keyup event on anonymous join's room input + $(current + ' input.room').keyup(function() { + var value = $(this).val(); + var report = current + ' .report'; + var span = report + ' span'; + + if(!value) { + $(report).hide(); + $(span).text(''); + } + + else { + $(report).show(); + $(span).text(JAPPIX_LOCATION + '?r=' + value); + } + }); + + break; + + // Register tool + case 'registerer': + $(current + ' form').submit(registerForm); + + break; + } + } + + // We focus on the first input + $(document).oneTime(10, function() { + $(right + 'input:visible:first').focus(); + }); + + return false; +} + +// Allows the user to display the advanced login options +function showAdvanced() { + // Hide the link + $('#home a.advanced').hide(); + + // Show the fieldset + $('#home fieldset.advanced').show(); + + return false; +} + +// Reads the login form values +function loginForm() { + // We get the values + var lPath = '#home .loginer '; + var lServer = $(lPath + '.server').val(); + var lNick = $(lPath + '.nick').val(); + var lPass = $(lPath + '.password').val(); + var lResource = $(lPath + '.resource').val(); + var lPriority = $(lPath + '.priority').val(); + var lRemember = $(lPath + '.remember').filter(':checked').size(); + + // Enough values? + if(lServer && lNick && lPass && lResource && lPriority) + doLogin(lNick, lServer, lPass, lResource, lPriority, lRemember); + + // Something is missing? + else { + $(lPath + 'input[type=text], ' + lPath + 'input[type=password]').each(function() { + var select = $(this); + + if(!select.val()) + $(document).oneTime(10, function() { + select.addClass('please-complete').focus(); + }); + else + select.removeClass('please-complete'); + }); + } + + return false; +} + +// Reads the register form values +function registerForm() { + var rPath = '#home .registerer '; + + // Remove the success info + $(rPath + '.success').remove(); + + // Get the values + var username = $(rPath + '.nick').val(); + var domain = $(rPath + '.server').val(); + var pass = $(rPath + '.password').val(); + var spass = $(rPath + '.spassword').val(); + + // Enough values? + if(domain && username && pass && spass && (pass == spass)) { + // We remove the not completed class to avoid problems + $('#home .registerer input').removeClass('please-complete'); + + // Fire the register event! + doRegister(username, domain, pass); + } + + // Something is missing? + else { + $(rPath + 'input[type=text], ' + rPath + 'input[type=password]').each(function() { + var select = $(this); + + if(!select.val() || (select.is('#spassword') && pass && (pass != spass))) + $(document).oneTime(10, function() { + select.addClass('please-complete').focus(); + }); + else + select.removeClass('please-complete'); + }); + } + + return false; +} + +// Plugin launcher +function launchHome() { + // Define the vars + var home = '#home '; + var button = home + 'button'; + var corp = home + '.corporation'; + var locale = home + '.locale'; + + // Removes the
+ + + + + + + \ No newline at end of file diff --git a/sources/library/bootstrap-colorpicker/src/header.html b/sources/library/bootstrap-colorpicker/src/header.html new file mode 100644 index 00000000..7e812205 --- /dev/null +++ b/sources/library/bootstrap-colorpicker/src/header.html @@ -0,0 +1,69 @@ + + + + + + + Colorpicker for Twitter Bootstrap + + + + + + + +
+
+ +
+
+

+ Colorpicker plugin for the Twitter Bootstrap toolkit. Originally written by @eyecon + and maintained in Github by @mjolnic and the community +

It basically adds a color picker to a field or any other element. +

+
    +
  • can be used as a component
  • +
  • alpha picker
  • +
  • multiple formats: hex, rgb, rgba, hsl, hsla
  • +
+
+ +
+
+
+
+ \ No newline at end of file diff --git a/sources/library/bootstrap-colorpicker/src/js/colorpicker-color.js b/sources/library/bootstrap-colorpicker/src/js/colorpicker-color.js new file mode 100644 index 00000000..2e047406 --- /dev/null +++ b/sources/library/bootstrap-colorpicker/src/js/colorpicker-color.js @@ -0,0 +1,508 @@ +// Color object +var Color = function(val) { + this.value = { + h: 0, + s: 0, + b: 0, + a: 1 + }; + this.origFormat = null; // original string format + if (val) { + if (val.toLowerCase !== undefined) { + this.setColor(val); + } else if (val.h !== undefined) { + this.value = val; + } + } +}; + +Color.prototype = { + constructor: Color, + // 140 predefined colors from the HTML Colors spec + colors : { + "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", + "darkgreen": "#006400", + "darkkhaki": "#bdb76b", + "darkmagenta": "#8b008b", + "darkolivegreen": "#556b2f", + "darkorange": "#ff8c00", + "darkorchid": "#9932cc", + "darkred": "#8b0000", + "darksalmon": "#e9967a", + "darkseagreen": "#8fbc8f", + "darkslateblue": "#483d8b", + "darkslategray": "#2f4f4f", + "darkturquoise": "#00ced1", + "darkviolet": "#9400d3", + "deeppink": "#ff1493", + "deepskyblue": "#00bfff", + "dimgray": "#696969", + "dodgerblue": "#1e90ff", + "firebrick": "#b22222", + "floralwhite": "#fffaf0", + "forestgreen": "#228b22", + "fuchsia": "#ff00ff", + "gainsboro": "#dcdcdc", + "ghostwhite": "#f8f8ff", + "gold": "#ffd700", + "goldenrod": "#daa520", + "gray": "#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", + "lightgrey": "#d3d3d3", + "lightgreen": "#90ee90", + "lightpink": "#ffb6c1", + "lightsalmon": "#ffa07a", + "lightseagreen": "#20b2aa", + "lightskyblue": "#87cefa", + "lightslategray": "#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", + "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" + }, + _sanitizeNumber: function(val) { + if (typeof val === 'number') { + return val; + } + if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) { + return 1; + } + if (val.toLowerCase !== undefined) { + return parseFloat(val); + } + return 1; + }, + //parse a string to HSB + setColor: function(strVal) { + strVal = strVal.toLowerCase(); + this.value = this.stringToHSB(strVal) ||  { + h: 0, + s: 0, + b: 0, + a: 1 + }; + }, + stringToHSB: function(strVal) { + strVal = strVal.toLowerCase(); + var that = this, + result = false; + $.each(this.stringParsers, function(i, parser) { + var match = parser.re.exec(strVal), + values = match && parser.parse.apply(that, [match]), + format = parser.format || 'rgba'; + if (values) { + if (format.match(/hsla?/)) { + result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values)); + } else { + result = that.RGBtoHSB.apply(that, values); + } + that.origFormat = format; + return false; + } + return true; + }); + return result; + }, + setHue: function(h) { + this.value.h = 1 - h; + }, + setSaturation: function(s) { + this.value.s = s; + }, + setBrightness: function(b) { + this.value.b = 1 - b; + }, + setAlpha: function(a) { + this.value.a = parseInt((1 - a) * 100, 10) / 100; + }, + toRGB: function(h, s, v, a) { + h = h || this.value.h; + s = s || this.value.s; + v = v || this.value.b; + a = a || this.value.a; + + var r, g, b, i, f, p, q, t; + if (h && s === undefined && v === undefined) { + s = h.s, v = h.v, h = h.h; + } + i = Math.floor(h * 6); + f = h * 6 - i; + p = v * (1 - s); + q = v * (1 - f * s); + t = v * (1 - (1 - f) * s); + switch (i % 6) { + case 0: + r = v, g = t, b = p; + break; + case 1: + r = q, g = v, b = p; + break; + case 2: + r = p, g = v, b = t; + break; + case 3: + r = p, g = q, b = v; + break; + case 4: + r = t, g = p, b = v; + break; + case 5: + r = v, g = p, b = q; + break; + } + return { + r: Math.floor(r * 255), + g: Math.floor(g * 255), + b: Math.floor(b * 255), + a: a + }; + }, + toHex: function(h, s, b, a) { + var rgb = this.toRGB(h, s, b, a); + return '#' + ((1 << 24) | (parseInt(rgb.r) << 16) | (parseInt(rgb.g) << 8) | parseInt(rgb.b)).toString(16).substr(1); + }, + toHSL: function(h, s, b, a) { + h = h || this.value.h; + s = s || this.value.s; + b = b || this.value.b; + a = a || this.value.a; + + var H = h, + L = (2 - s) * b, + S = s * b; + if (L > 0 && L <= 1) { + S /= L; + } else { + S /= 2 - L; + } + L /= 2; + if (S > 1) { + S = 1; + } + return { + h: isNaN(H) ? 0 : H, + s: isNaN(S) ? 0 : S, + l: isNaN(L) ? 0 : L, + a: isNaN(a) ? 0 : a, + }; + }, + toAlias: function(r, g, b, a) { + var rgb = this.toHex(r, g, b, a); + for(var alias in this.colors){ + if(this.colors[alias] == rgb){ + return alias; + } + } + return false; + }, + RGBtoHSB: function(r, g, b, a) { + r /= 255; + g /= 255; + b /= 255; + + var H, S, V, C; + V = Math.max(r, g, b); + C = V - Math.min(r, g, b); + H = (C === 0 ? null : + V === r ? (g - b) / C : + V === g ? (b - r) / C + 2 : + (r - g) / C + 4 + ); + H = ((H + 360) % 6) * 60 / 360; + S = C === 0 ? 0 : C / V; + return { + h: this._sanitizeNumber(H), + s: S, + b: V, + a: this._sanitizeNumber(a) + }; + }, + HueToRGB: function(p, q, h) { + if (h < 0) { + h += 1; + } else if (h > 1) { + h -= 1; + } + if ((h * 6) < 1) { + return p + (q - p) * h * 6; + } else if ((h * 2) < 1) { + return q; + } else if ((h * 3) < 2) { + return p + (q - p) * ((2 / 3) - h) * 6; + } else { + return p; + } + }, + HSLtoRGB: function(h, s, l, a) { + if (s < 0) { + s = 0; + } + var q; + if (l <= 0.5) { + q = l * (1 + s); + } else { + q = l + s - (l * s); + } + + var p = 2 * l - q; + + var tr = h + (1 / 3); + var tg = h; + var tb = h - (1 / 3); + + var r = Math.round(this.HueToRGB(p, q, tr) * 255); + var g = Math.round(this.HueToRGB(p, q, tg) * 255); + var b = Math.round(this.HueToRGB(p, q, tb) * 255); + return [r, g, b, this._sanitizeNumber(a)]; + }, + toString: function(format) { + format = format ||  'rgba'; + switch (format) { + case 'rgb': + { + var rgb = this.toRGB(); + return 'rgb(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ')'; + } + break; + case 'rgba': + { + var rgb = this.toRGB(); + return 'rgba(' + rgb.r + ',' + rgb.g + ',' + rgb.b + ',' + rgb.a + ')'; + } + break; + case 'hsl': + { + var hsl = this.toHSL(); + return 'hsl(' + Math.round(hsl.h * 360) + ',' + Math.round(hsl.s * 100) + '%,' + Math.round(hsl.l * 100) + '%)'; + } + break; + case 'hsla': + { + var hsl = this.toHSL(); + return 'hsla(' + Math.round(hsl.h * 360) + ',' + Math.round(hsl.s * 100) + '%,' + Math.round(hsl.l * 100) + '%,' + hsl.a + ')'; + } + break; + case 'hex': + { + return this.toHex(); + } + break; + case 'alias': + return this.toAlias() || this.toHex(); + default: + { + return false; + } + break; + } + }, + // a set of RE's that can match strings and generate color tuples. + // from John Resig color plugin + // https://github.com/jquery/jquery-color/ + stringParsers: [{ + re: /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/, + format: 'hex', + parse: function(execResult) { + return [ + parseInt(execResult[1], 16), + parseInt(execResult[2], 16), + parseInt(execResult[3], 16), + 1 + ]; + } + }, { + re: /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/, + format: 'hex', + parse: function(execResult) { + return [ + parseInt(execResult[1] + execResult[1], 16), + parseInt(execResult[2] + execResult[2], 16), + parseInt(execResult[3] + execResult[3], 16), + 1 + ]; + } + }, { + re: /rgb\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*?\)/, + format: 'rgb', + parse: function(execResult) { + return [ + execResult[1], + execResult[2], + execResult[3], + 1 + ]; + } + }, { + re: /rgb\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/, + format: 'rgb', + parse: function(execResult) { + return [ + 2.55 * execResult[1], + 2.55 * execResult[2], + 2.55 * execResult[3], + 1 + ]; + } + }, { + re: /rgba\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + format: 'rgba', + parse: function(execResult) { + return [ + execResult[1], + execResult[2], + execResult[3], + execResult[4] + ]; + } + }, { + re: /rgba\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + format: 'rgba', + parse: function(execResult) { + return [ + 2.55 * execResult[1], + 2.55 * execResult[2], + 2.55 * execResult[3], + execResult[4] + ]; + } + }, { + re: /hsl\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*?\)/, + format: 'hsl', + parse: function(execResult) { + return [ + execResult[1] / 360, + execResult[2] / 100, + execResult[3] / 100, + execResult[4] + ]; + } + }, { + re: /hsla\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d+(?:\.\d+)?)\s*)?\)/, + format: 'hsla', + parse: function(execResult) { + return [ + execResult[1] / 360, + execResult[2] / 100, + execResult[3] / 100, + execResult[4] + ]; + } + }, { + //predefined color name + re: /^([a-z]{3,})$/, + format: 'alias', + parse: function(execResult) { + var hexval = this.colorNameToHex(execResult[0]) ||  '#000000'; + var match = this.stringParsers[0].re.exec(hexval), + values = match && this.stringParsers[0].parse.apply(this, [match]); + return values; + } + }], + colorNameToHex: function(name) { + if (typeof this.colors[name.toLowerCase()] !== 'undefined') { + return this.colors[name.toLowerCase()]; + } + return false; + } +}; diff --git a/sources/library/bootstrap-colorpicker/src/js/colorpicker.js b/sources/library/bootstrap-colorpicker/src/js/colorpicker.js new file mode 100644 index 00000000..e68b965d --- /dev/null +++ b/sources/library/bootstrap-colorpicker/src/js/colorpicker.js @@ -0,0 +1,464 @@ +/*! + * Bootstrap Colorpicker + * http://mjolnic.github.io/bootstrap-colorpicker/ + * + * Originally written by (c) 2012 Stefan Petre + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * @todo Update DOCS + */ + +(function( factory ) { + "use strict"; + if(typeof define === 'function' && define.amd) { + define(['jquery'], factory); + } + else if(window.jQuery && !window.jQuery.fn.colorpicker) { + factory(window.jQuery); + } +} +(function($) { + 'use strict'; + + '{{color}}'; + + var defaults = { + horizontal: false, // horizontal mode layout ? + inline: false, //forces to show the colorpicker as an inline element + color: false, //forces a color + format: false, //forces a format + input: 'input', // children input selector + container: false, // container selector + component: '.add-on, .input-group-addon', // children component selector + sliders: { + saturation: { + maxLeft: 100, + maxTop: 100, + callLeft: 'setSaturation', + callTop: 'setBrightness' + }, + hue: { + maxLeft: 0, + maxTop: 100, + callLeft: false, + callTop: 'setHue' + }, + alpha: { + maxLeft: 0, + maxTop: 100, + callLeft: false, + callTop: 'setAlpha' + } + }, + slidersHorz: { + saturation: { + maxLeft: 100, + maxTop: 100, + callLeft: 'setSaturation', + callTop: 'setBrightness' + }, + hue: { + maxLeft: 100, + maxTop: 0, + callLeft: 'setHue', + callTop: false + }, + alpha: { + maxLeft: 100, + maxTop: 0, + callLeft: 'setAlpha', + callTop: false + } + }, + template: ' +
+ + + +
+ +
+
+
+

See it in Action

+

Play around with the demo

+
+
+
+
$('.single-slider').jRange({
+    from: 0,
+    to: 100,
+    step: 1,
+    scale: [0,25,50,75,100],
+    format: '%s',
+    width: 300,
+    showLabels: true
+});
+
+
+ +
+
+
+
+
$('.range-slider').jRange({
+    from: 0,
+    to: 100,
+    step: 1,
+    scale: [0,25,50,75,100],
+    format: '%s',
+    width: 300,
+    showLabels: true,
+    isRange : true
+});
+
+
+ +
+
+ + +
+
+

How to Use

+

Lets see some code

+

To get started you'll have to include jquery.range.js and jquery.range.css files in your html file.

+
<link rel="stylesheet" href="jquery.range.css">
+<script src="jquery.range.js"></script>
+

Later just add an hidden input, where ever you want this slider to be shown.

+
<input type="hidden" class="slider-input" value="23" />
+

After this you'll have to intialize this plugin for that input, as shown in the example above

+ +

Options

+

See configuration options

+

Options can also be set programatically, by passing an options hash to the jRange method. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OptionOverrideTypeDetails
fromMandatoryIntegerLower bound of slider
toMandatoryIntegerUpper bound of slider
stepOptionalInteger + Default : 1 +

amount of increment on each step

+
scaleOptionalArray +

Array containing label which are shown below the slider. By default its [from, to].

+
showLabelsOptionalBoolean +

False, if you'd like to hide label which are shown on top of slider.

+ Default : true +
showScaleOptionalBoolean +

False, if you'd like to hide scale which are shown below the slider.

+ Default : true +
formatOptionalString / Function +

this is used to show label on the pointer

+ Default : "%s" +

String : %s is replaced by its value, e.g., "%s days", "%s goats"

+

+ Function : format(value, pointer) +
+ return : string label for a given value and pointer.
+ pointer could be 'low'/'high' if isRange is true, else undefined +

+
widthOptionalInteger + Default : 300 +
themeOptionalString + Default : "theme-green" +

This is the css class name added to the container. Available themes are "theme-blue", "theme-green". You can also add more themes, just like in jquery.range.less

+
isRangeOptionalBoolean + Default : false +

True if this is a range selector. If its a range the value of hidden input will be set comma-seperated, e.g., "25,75"

+
disableOptionalBoolean + Default : false +

True if this is a disable(read only) range selector. You can also change disable status later by calling.

+ + $('.slider').jRange('disable'); + $('.slider').jRange('enable'); + $('.slider').jRange('toggleDisable'); + +
onstatechangeOptionalFunction +

This function is called whenever the value is changed by user. This same value is also automatically set for the provided Hidden Input.

+

For single slider value is without comma, however for a range selector value is comma-seperated.

+
+ +

+
+
+
+ + + + + + + diff --git a/sources/library/jRange/demo/main.css b/sources/library/jRange/demo/main.css new file mode 100644 index 00000000..1e29a98a --- /dev/null +++ b/sources/library/jRange/demo/main.css @@ -0,0 +1,289 @@ +html, +body { + height: 100%; + width: 100%; +} +body { + font-family: Helvetica Neue, Helvetica, Arial sans-serif; + font-size: 16px; + line-height: 1.6; + color: #434343; +} +a { + text-decoration: none; +} +pre code { + line-height: 1.5; +} +.container { + width: 1130px; + padding: 0 20px; + margin: 0px auto; +} +.text-container { + width: 900px; + position: relative; + margin: 0px auto; +} +.clearfix:after { + content: " "; + /* Older browser do not support empty content */ + visibility: hidden; + display: block; + height: 0; + clear: both; +} +.pane { + position: relative; + width: 100%; + height: 50%; + min-height: 450px; +} +.body { + position: relative; +} +section.header { + background-color: #606c88; + background: -webkit-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); + /* Chrome 10+, Saf5.1+ */ + background: -moz-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); + /* FF3.6+ */ + background: -ms-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); + /* IE10 */ + background: -o-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); + /* Opera 11.10+ */ + background: linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); + /* W3C */ +} +section.header footer { + position: absolute; + width: 100%; + bottom: 0; + padding: 10px 30px; + box-sizing: border-box; +} +.left { + float: left; + text-align: left; +} +.right { + float: right; + text-align: right; +} +div.header { + color: #fff; + width: 600px; + text-align: center; + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + border-radius: 5px; +} +div.header h1, +div.header h2 { + font-family: 'Raleway' sans-serif; + font-weight: 100; + line-height: 1; + margin: 0; +} +div.header h1 { + font-size: 72px; + margin-bottom: 25px; +} +section.demo h2, +section.demo h3 { + font-family: 'Raleway' sans-serif; + font-weight: 300; + line-height: 1; + margin: 0; + text-align: center; +} +section.demo h2 { + font-size: 48px; + margin-top: 1em; +} +section.demo h3 { + font-size: 28px; + margin: 0.8em 0 1em; +} +section.demo .demo-container { + margin: 40px 0 80px; +} +section.demo .demo-section { + margin: 20px 0; + clear: both; +} +section.demo .demo-section .demo-code { + width: 50%; + float: left; +} +section.demo .demo-section .demo-output { + margin-left: 50%; + padding: 50px 0; +} +section.demo .demo-section .slider-container { + margin: 0 auto; +} +section.demo .text-container h2 { + margin-top: 3em; +} +section.demo .form-vertical { + width: 200px; + float: left; +} +section.demo .image-container { + margin-left: 200px; + padding: 1px; + border: 1px solid #eee; +} +section.demo .form-group { + margin-bottom: 20px; +} +section.demo label { + color: #999; + font-size: 13px; + display: block; +} +section.demo input { + width: 150px; + margin-top: 3px; + border: 1px solid #999; + border-width: 0 0 1px 0; + padding: 3px 0 3px; + transition: 0.3s all; +} +section.demo input:focus, +section.demo input:active { + outline: none; + border-color: #2fc7ff; + box-shadow: 0 1px 3px -3px #2fc7ff; + color: #000; +} +section.demo button { + position: relative; + overflow: visible; + display: inline-block; + padding: 0.3em 1em; + border: 1px solid #d4d4d4; + margin: 0; + text-decoration: none; + text-align: center; + text-shadow: 1px 1px 0 #fff; + font-size: 12px; + color: #333; + white-space: nowrap; + cursor: pointer; + outline: none; + background-color: #ececec; + background-image: linear-gradient(#f4f4f4, #ececec); + background-clip: padding-box; + border-radius: 0.2em; + zoom: 1; + transition: background-image 0.3s; +} +section.demo button:hover, +section.demo button:active { + border-color: #3072b3; + border-bottom-color: #2a65a0; + text-decoration: none; + text-shadow: -1px -1px 0 rgba(0, 0, 0, 0.3); + color: #fff; + background-color: #3c8dde; + background-image: linear-gradient(#599bdc, #3072b3); +} +section.demo p { + font-family: 'Raleway' sans-serif; + margin: 1em auto; +} +section.demo .footer { + margin-top: 80px; + text-align: center; +} +section.demo .large-github { + display: inline-block; + border: 1px solid #21b0ff; + font-weight: 400; + font-family: 'Raleway' sans-serif; + text-shadow: none; + background-color: #fff; + background-image: none; + padding: 8px 25px; + color: #21b0ff; + font-size: 18px; + border-radius: 25px; +} +section.demo .large-github:hover, +section.demo .large-github:active { + background-color: #21b0ff; + color: #fff; + background-image: none; + text-shadow: none; +} +.two-coloumn em { + font-weight: normal; + text-decoration: none; + font-style: normal; + display: inline-block; + width: 85px; +} +.plugin-options { + font-size: 14px; + margin-bottom: 40px; + width: 900px; + font-weight: 200; +} +.plugin-options td, +.plugin-options th { + padding: 8px ; + text-align: left; + vertical-align: top; +} +.plugin-options td:first-child, +.plugin-options th:first-child { + font-weight: bold; +} +.plugin-options td:nth-child(2), +.plugin-options td:nth-child(3) { + font-size: 13px; + color: #999; +} +.plugin-options td p { + font-family: Helvetica Neue, Helvetica, Arial, sans-serif; + margin: 4px 0; +} +.plugin-options td p:first-child { + margin-top: 0; +} +.plugin-options th { + background-color: #358ccb; + color: #fff; +} +.plugin-options tr:nth-child(2n + 1) td { + background-color: #f5f5f5; +} +.plugin-options small { + display: block; +} +.plugin-options ul { + list-style: none; + padding: 0; +} +.plugin-options ul ul { + list-style: circle inside; +} +section.footer { + margin-top: 80px; + padding: 30px; + text-align: center; + background-color: #333; + color: #999; + font-weight: 300; + font-size: 13px; +} +section.footer p { + margin: 5px 0; +} +section.footer a { + color: #fff; +} diff --git a/sources/library/jRange/demo/main.less b/sources/library/jRange/demo/main.less new file mode 100644 index 00000000..e9ee232a --- /dev/null +++ b/sources/library/jRange/demo/main.less @@ -0,0 +1,296 @@ +@font-family: 'Raleway' sans-serif; +html, body{ + height: 100%; + width: 100%; +} +body{ + font-family: Helvetica Neue, Helvetica, Arial sans-serif; + font-size: 16px; + line-height: 1.6; + color: #434343; +} +a{ + text-decoration: none; +} +pre code{ + line-height: 1.5; +} +.container{ + width: 1130px; + padding: 0 20px; + margin: 0px auto; +} +.text-container{ + width: 900px; + position: relative; + margin: 0px auto; +} +.clearfix:after { + content: " "; /* Older browser do not support empty content */ + visibility: hidden; + display: block; + height: 0; + clear: both; +} +.pane{ + position: relative; + width: 100%; + height: 50%; + min-height: 450px; +} +.body{ + position: relative; +} +section.header{ + background-color: #606c88; + + background: -webkit-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); /* Chrome 10+, Saf5.1+ */ + background: -moz-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); /* FF3.6+ */ + background: -ms-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); /* IE10 */ + background: -o-linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); /* Opera 11.10+ */ + background: linear-gradient(90deg, #606c88 10%, #3f4c6b 90%); /* W3C */ + + // background-image: radial-gradient(50% 102%, #3cb3db 48%, #2e6c9a 100%); + footer{ + position: absolute; + width: 100%; + bottom: 0; + padding: 10px 30px; + box-sizing: border-box; + } +} +.left{ + float: left; + text-align: left; +} +.right{ + float: right; + text-align: right; +} +div.header{ + color: #fff; + width: 600px; + text-align: center; + position: absolute; + top: 40%; + left: 50%; + transform: translate(-50%, -50%); + // background-color: #333; + border-radius: 5px; + h1, h2{ + font-family: @font-family; + font-weight: 100; + line-height: 1; + margin: 0; + } + h1{ + font-size: 72px; + margin-bottom: 25px; + } +} +section.demo{ + h2, h3{ + font-family: @font-family; + font-weight: 300; + line-height: 1; + margin: 0; + text-align: center; + } + h2{ + font-size: 48px; + margin-top: 1em; + } + h3{ + font-size: 28px; + margin: 0.8em 0 1em; + } + .demo-container{ + margin: 40px 0 80px; + } + .demo-section{ + margin: 20px 0; + clear: both; + .demo-code{ + width: 50%; + float: left; + } + .demo-output{ + margin-left: 50%; + padding: 50px 0; + } + .slider-container{ + margin: 0 auto; + } + } + .text-container{ + h2{ + margin-top: 3em; + } + } + .form-vertical{ + width: 200px; + float: left; + } + .image-container{ + margin-left: 200px; + padding: 1px; + border: 1px solid #eee; + // background-color: #333; + } + .form-group{ + margin-bottom: 20px; + } + label{ + color: #999; + font-size: 13px; + display: block; + } + input{ + width: 150px; + margin-top: 3px; + // border-radius: 2px; + border: 1px solid #999; + border-width: 0 0 1px 0; + padding: 3px 0 3px; + transition: 0.3s all; + // color: #999; + &:focus, &:active{ + outline: none; + border-color: #2fc7ff; + box-shadow: 0 1px 3px -3px #2fc7ff; + color: #000; + } + } + button{ + position: relative; + overflow: visible; + display: inline-block; + padding: 0.3em 1em; + border: 1px solid #d4d4d4; + margin: 0; + text-decoration: none; + text-align: center; + text-shadow: 1px 1px 0 #fff; + font-size: 12px; + color: #333; + white-space: nowrap; + cursor: pointer; + outline: none; + background-color: #ececec; + background-image: linear-gradient(#f4f4f4, #ececec); + background-clip: padding-box; + border-radius: 0.2em; + zoom: 1; + transition: background-image 0.3s; + &:hover, &:active{ + border-color: #3072b3; + border-bottom-color: #2a65a0; + text-decoration: none; + text-shadow: -1px -1px 0 rgba(0,0,0,0.3); + color: #fff; + background-color: #3c8dde; + background-image: linear-gradient(#599bdc, #3072b3); + } + } + p{ + font-family: @font-family; + margin: 1em auto; + } + .footer{ + margin-top: 80px; + text-align: center; + } + .large-github{ + display: inline-block; + border: 1px solid #21b0ff; + font-weight: 400; + font-family: @font-family; + text-shadow: none; + background-color: #fff; + background-image: none; + padding: 8px 25px; + color: #21b0ff; + font-size: 18px; + border-radius: 25px; + &:hover, &:active{ + background-color: #21b0ff; + color: #fff; + background-image: none; + text-shadow: none; + } + } +} +.two-coloumn{ + em{ + font-weight: normal; + text-decoration: none; + font-style: normal; + display: inline-block; + width: 85px; + } +} +.plugin-options{ + font-size: 14px; + margin-bottom: 40px; + width: 900px; + font-weight: 200; + td, th{ + padding: 8px ; + text-align: left; + vertical-align: top; + &:first-child{ + font-weight: bold; + } + } + td{ + &:nth-child(2), &:nth-child(3){ + font-size: 13px; + color: #999; + } + p{ + font-family: Helvetica Neue, Helvetica, Arial, sans-serif; + margin: 4px 0; + &:first-child{ + margin-top: 0; + } + } + } + th{ + background-color: #358ccb; + color: #fff; + } + tr{ + &:nth-child(2n + 1){ + td{ + background-color: #f5f5f5; + } + } + } + small{ + display: block; + // white-space: nowrap; + } + ul{ + list-style: none; + padding: 0; + ul{ + list-style: circle inside; + // padding-left: 25px; + } + } +} +section.footer{ + margin-top: 80px; + padding: 30px; + text-align: center; + background-color: #333; + color: #999; + font-weight: 300; + font-size: 13px; + p{ + margin: 5px 0; + } + a{ + color: #fff; + } +} \ No newline at end of file diff --git a/sources/library/jRange/demo/normalize.css b/sources/library/jRange/demo/normalize.css new file mode 100644 index 00000000..08f89507 --- /dev/null +++ b/sources/library/jRange/demo/normalize.css @@ -0,0 +1,425 @@ +/*! normalize.css v3.0.1 | MIT License | git.io/normalize */ + +/** + * 1. Set default font family to sans-serif. + * 2. Prevent iOS text size adjust after orientation change, without disabling + * user zoom. + */ + +html { + font-family: sans-serif; /* 1 */ + -ms-text-size-adjust: 100%; /* 2 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/** + * Remove default margin. + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Correct `block` display not defined for any HTML5 element in IE 8/9. + * Correct `block` display not defined for `details` or `summary` in IE 10/11 and Firefox. + * Correct `block` display not defined for `main` in IE 11. + */ + +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +main, +nav, +section, +summary { + display: block; +} + +/** + * 1. Correct `inline-block` display not defined in IE 8/9. + * 2. Normalize vertical alignment of `progress` in Chrome, Firefox, and Opera. + */ + +audio, +canvas, +progress, +video { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Prevent modern browsers from displaying `audio` without controls. + * Remove excess height in iOS 5 devices. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Address `[hidden]` styling not present in IE 8/9/10. + * Hide the `template` element in IE 8/9/11, Safari, and Firefox < 22. + */ + +[hidden], +template { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * Remove the gray background color from active links in IE 10. + */ + +a { + background: transparent; +} + +/** + * Improve readability when focused and also mouse hovered in all browsers. + */ + +a:active, +a:hover { + outline: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Address styling not present in IE 8/9/10/11, Safari, and Chrome. + */ + +abbr[title] { + border-bottom: 1px dotted; +} + +/** + * Address style set to `bolder` in Firefox 4+, Safari, and Chrome. + */ + +b, +strong { + font-weight: bold; +} + +/** + * Address styling not present in Safari and Chrome. + */ + +dfn { + font-style: italic; +} + +/** + * Address variable `h1` font-size and margin within `section` and `article` + * contexts in Firefox 4+, Safari, and Chrome. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Address styling not present in IE 8/9. + */ + +mark { + background: #ff0; + color: #000; +} + +/** + * Address inconsistent and variable font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` affecting `line-height` in all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sup { + top: -0.5em; +} + +sub { + bottom: -0.25em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove border when inside `a` element in IE 8/9/10. + */ + +img { + border: 0; +} + +/** + * Correct overflow not hidden in IE 9/10/11. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * Address margin not present in IE 8/9 and Safari. + */ + +figure { + margin: 1em 40px; +} + +/** + * Address differences between Firefox and other browsers. + */ + +hr { + -moz-box-sizing: content-box; + box-sizing: content-box; + height: 0; +} + +/** + * Contain overflow in all browsers. + */ + +pre { + overflow: auto; +} + +/** + * Address odd `em`-unit font size rendering in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; + font-size: 1em; +} + +/* Forms + ========================================================================== */ + +/** + * Known limitation: by default, Chrome and Safari on OS X allow very limited + * styling of `select`, unless a `border` property is set. + */ + +/** + * 1. Correct color not being inherited. + * Known issue: affects color of disabled elements. + * 2. Correct font properties not being inherited. + * 3. Address margins set differently in Firefox 4+, Safari, and Chrome. + */ + +button, +input, +optgroup, +select, +textarea { + color: inherit; /* 1 */ + font: inherit; /* 2 */ + margin: 0; /* 3 */ +} + +/** + * Address `overflow` set to `hidden` in IE 8/9/10/11. + */ + +button { + overflow: visible; +} + +/** + * Address inconsistent `text-transform` inheritance for `button` and `select`. + * All other form control elements do not inherit `text-transform` values. + * Correct `button` style inheritance in Firefox, IE 8/9/10/11, and Opera. + * Correct `select` style inheritance in Firefox. + */ + +button, +select { + text-transform: none; +} + +/** + * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` + * and `video` controls. + * 2. Correct inability to style clickable `input` types in iOS. + * 3. Improve usability and consistency of cursor style between image-type + * `input` and others. + */ + +button, +html input[type="button"], /* 1 */ +input[type="reset"], +input[type="submit"] { + -webkit-appearance: button; /* 2 */ + cursor: pointer; /* 3 */ +} + +/** + * Re-set default cursor for disabled elements. + */ + +button[disabled], +html input[disabled] { + cursor: default; +} + +/** + * Remove inner padding and border in Firefox 4+. + */ + +button::-moz-focus-inner, +input::-moz-focus-inner { + border: 0; + padding: 0; +} + +/** + * Address Firefox 4+ setting `line-height` on `input` using `!important` in + * the UA stylesheet. + */ + +input { + line-height: normal; +} + +/** + * It's recommended that you don't attempt to style these elements. + * Firefox's implementation doesn't respect box-sizing, padding, or width. + * + * 1. Address box sizing set to `content-box` in IE 8/9/10. + * 2. Remove excess padding in IE 8/9/10. + */ + +input[type="checkbox"], +input[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Fix the cursor style for Chrome's increment/decrement buttons. For certain + * `font-size` values of the `input`, it causes the cursor style of the + * decrement button to change from `default` to `text`. + */ + +input[type="number"]::-webkit-inner-spin-button, +input[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Address `appearance` set to `searchfield` in Safari and Chrome. + * 2. Address `box-sizing` set to `border-box` in Safari and Chrome + * (include `-moz` to future-proof). + */ + +input[type="search"] { + -webkit-appearance: textfield; /* 1 */ + -moz-box-sizing: content-box; + -webkit-box-sizing: content-box; /* 2 */ + box-sizing: content-box; +} + +/** + * Remove inner padding and search cancel button in Safari and Chrome on OS X. + * Safari (but not Chrome) clips the cancel button when the search input has + * padding (and `textfield` appearance). + */ + +input[type="search"]::-webkit-search-cancel-button, +input[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Define consistent border, margin, and padding. + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct `color` not being inherited in IE 8/9/10/11. + * 2. Remove padding so people aren't caught out if they zero out fieldsets. + */ + +legend { + border: 0; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Remove default vertical scrollbar in IE 8/9/10/11. + */ + +textarea { + overflow: auto; +} + +/** + * Don't inherit the `font-weight` (applied by a rule above). + * NOTE: the default cannot safely be changed in Chrome and Safari on OS X. + */ + +optgroup { + font-weight: bold; +} + +/* Tables + ========================================================================== */ + +/** + * Remove most spacing between table cells. + */ + +table { + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + padding: 0; +} diff --git a/sources/library/jRange/demo/prism/prism.css b/sources/library/jRange/demo/prism/prism.css new file mode 100644 index 00000000..afc94b35 --- /dev/null +++ b/sources/library/jRange/demo/prism/prism.css @@ -0,0 +1,193 @@ +/* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+css-extras+clike+javascript */ +/** + * prism.js Coy theme for JavaScript, CoffeeScript, CSS and HTML + * Based on https://github.com/tshedor/workshop-wp-theme (Example: http://workshop.kansan.com/category/sessions/basics or http://workshop.timshedor.com/category/sessions/basics); + * @author Tim Shedor + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + position:relative; + padding: 1em; + margin: .5em 0; + -webkit-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf; + -moz-box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf; + box-shadow: -1px 0px 0px 0px #358ccb, 0px 0px 0px 1px #dfdfdf; + border-left: 10px solid #358ccb; + background-color: #fdfdfd; + background-image: -webkit-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-image: -moz-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-image: -ms-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-image: -o-linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-image: linear-gradient(transparent 50%, rgba(69, 142, 209, 0.04) 50%); + background-size: 3em 3em; + background-origin:content-box; + overflow:visible; + max-height:30em; +} + +code[class*="language"] { + max-height:29em; + display:block; + overflow:scroll; +} + +/* Margin bottom to accomodate shadow */ +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background-color:#fdfdfd; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + margin-bottom: 1em; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + position:relative; + padding: .2em; + -webkit-border-radius: 0.3em; + -moz-border-radius: 0.3em; + -ms-border-radius: 0.3em; + -o-border-radius: 0.3em; + border-radius: 0.3em; + color: #c92c2c; + border: 1px solid rgba(0, 0, 0, 0.1); +} + +pre[class*="language-"]:before, +pre[class*="language-"]:after { + content: ''; + z-index: -2; + display:block; + position: absolute; + bottom: 0.75em; + left: 0.18em; + width: 40%; + height: 20%; + -webkit-box-shadow: 0px 13px 8px #979797; + -moz-box-shadow: 0px 13px 8px #979797; + box-shadow: 0px 13px 8px #979797; + -webkit-transform: rotate(-2deg); + -moz-transform: rotate(-2deg); + -ms-transform: rotate(-2deg); + -o-transform: rotate(-2deg); + transform: rotate(-2deg); +} + +:not(pre) > code[class*="language-"]:after, +pre[class*="language-"]:after { + right: 0.75em; + left: auto; + -webkit-transform: rotate(2deg); + -moz-transform: rotate(2deg); + -ms-transform: rotate(2deg); + -o-transform: rotate(2deg); + transform: rotate(2deg); +} + +.token.comment, +.token.block-comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #7D8B99; +} + +.token.punctuation { + color: #5F6364; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.function-name, +.token.constant, +.token.symbol { + color: #c92c2c; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.function, +.token.builtin { + color: #2f9c0a; +} + +.token.operator, +.token.entity, +.token.url, +.token.variable { + color: #a67f59; + background: rgba(255, 255, 255, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword, +.token.class-name { + color: #1990b8; +} + +.token.regex, +.token.important { + color: #e90; +} +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: rgba(255, 255, 255, 0.5); +} + +.token.important { + font-weight: normal; +} + +.token.entity { + cursor: help; +} + +.namespace { + opacity: .7; +} + +@media screen and (max-width:767px){ + pre[class*="language-"]:before, + pre[class*="language-"]:after { + bottom:14px; + -webkit-box-shadow:none; + -moz-box-shadow:none; + box-shadow:none; + } + +} + +/* Plugin styles */ +.token.tab:not(:empty):before, +.token.cr:before, +.token.lf:before { + color: #e0d7d1; +} + diff --git a/sources/library/jRange/demo/prism/prism.js b/sources/library/jRange/demo/prism/prism.js new file mode 100644 index 00000000..dace6676 --- /dev/null +++ b/sources/library/jRange/demo/prism/prism.js @@ -0,0 +1,8 @@ +/* http://prismjs.com/download.html?themes=prism-coy&languages=markup+css+css-extras+clike+javascript */ +var self=typeof window!="undefined"?window:{},Prism=function(){var e=/\blang(?:uage)?-(?!\*)(\w+)\b/i,t=self.Prism={util:{encode:function(e){return e instanceof n?new n(e.type,t.util.encode(e.content)):t.util.type(e)==="Array"?e.map(t.util.encode):e.replace(/&/g,"&").replace(/e.length)break e;if(p instanceof i)continue;a.lastIndex=0;var d=a.exec(p);if(d){l&&(c=d[1].length);var v=d.index-1+c,d=d[0].slice(c),m=d.length,g=v+m,y=p.slice(0,v+1),b=p.slice(g+1),w=[h,1];y&&w.push(y);var E=new i(u,f?t.tokenize(d,f):d);w.push(E);b&&w.push(b);Array.prototype.splice.apply(s,w)}}}return s},hooks:{all:{},add:function(e,n){var r=t.hooks.all;r[e]=r[e]||[];r[e].push(n)},run:function(e,n){var r=t.hooks.all[e];if(!r||!r.length)return;for(var i=0,s;s=r[i++];)s(n)}}},n=t.Token=function(e,t){this.type=e;this.content=t};n.stringify=function(e,r,i){if(typeof e=="string")return e;if(Object.prototype.toString.call(e)=="[object Array]")return e.map(function(t){return n.stringify(t,r,e)}).join("");var s={type:e.type,content:n.stringify(e.content,r,i),tag:"span",classes:["token",e.type],attributes:{},language:r,parent:i};s.type=="comment"&&(s.attributes.spellcheck="true");t.hooks.run("wrap",s);var o="";for(var u in s.attributes)o+=u+'="'+(s.attributes[u]||"")+'"';return"<"+s.tag+' class="'+s.classes.join(" ")+'" '+o+">"+s.content+""};if(!self.document){if(!self.addEventListener)return self.Prism;self.addEventListener("message",function(e){var n=JSON.parse(e.data),r=n.language,i=n.code;self.postMessage(JSON.stringify(t.tokenize(i,t.languages[r])));self.close()},!1);return self.Prism}var r=document.getElementsByTagName("script");r=r[r.length-1];if(r){t.filename=r.src;document.addEventListener&&!r.hasAttribute("data-manual")&&document.addEventListener("DOMContentLoaded",t.highlightAll)}return self.Prism}();typeof module!="undefined"&&module.exports&&(module.exports=Prism);; +Prism.languages.markup={comment://g,prolog:/<\?.+?\?>/,doctype://,cdata://i,tag:{pattern:/<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi,inside:{tag:{pattern:/^<\/?[\w:-]+/i,inside:{punctuation:/^<\/?/,namespace:/^[\w-]+?:/}},"attr-value":{pattern:/=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi,inside:{punctuation:/=|>|"/g}},punctuation:/\/?>/g,"attr-name":{pattern:/[\w:-]+/g,inside:{namespace:/^[\w-]+?:/}}}},entity:/\&#?[\da-z]{1,8};/gi};Prism.hooks.add("wrap",function(e){e.type==="entity"&&(e.attributes.title=e.content.replace(/&/,"&"))});; +Prism.languages.css={comment:/\/\*[\w\W]*?\*\//g,atrule:{pattern:/@[\w-]+?.*?(;|(?=\s*{))/gi,inside:{punctuation:/[;:]/g}},url:/url\((["']?).*?\1\)/gi,selector:/[^\{\}\s][^\{\};]*(?=\s*\{)/g,property:/(\b|\B)[\w-]+(?=\s*:)/ig,string:/("|')(\\?.)*?\1/g,important:/\B!important\b/gi,punctuation:/[\{\};:]/g,"function":/[-a-z0-9]+(?=\()/ig};Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{style:{pattern:/[\w\W]*?<\/style>/ig,inside:{tag:{pattern:/|<\/style>/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.css}}});; +Prism.languages.css.selector={pattern:/[^\{\}\s][^\{\}]*(?=\s*\{)/g,inside:{"pseudo-element":/:(?:after|before|first-letter|first-line|selection)|::[-\w]+/g,"pseudo-class":/:[-\w]+(?:\(.*\))?/g,"class":/\.[-:\.\w]+/g,id:/#[-:\.\w]+/g}};Prism.languages.insertBefore("css","ignore",{hexcode:/#[\da-f]{3,6}/gi,entity:/\\[\da-f]{1,8}/gi,number:/[\d%\.]+/g});; +Prism.languages.clike={comment:{pattern:/(^|[^\\])(\/\*[\w\W]*?\*\/|(^|[^:])\/\/.*?(\r?\n|$))/g,lookbehind:!0},string:/("|')(\\?.)*?\1/g,"class-name":{pattern:/((?:(?:class|interface|extends|implements|trait|instanceof|new)\s+)|(?:catch\s+\())[a-z0-9_\.\\]+/ig,lookbehind:!0,inside:{punctuation:/(\.|\\)/}},keyword:/\b(if|else|while|do|for|return|in|instanceof|function|new|try|throw|catch|finally|null|break|continue)\b/g,"boolean":/\b(true|false)\b/g,"function":{pattern:/[a-z0-9_]+\(/ig,inside:{punctuation:/\(/}},number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?)\b/g,operator:/[-+]{1,2}|!|<=?|>=?|={1,3}|&{1,2}|\|?\||\?|\*|\/|\~|\^|\%/g,ignore:/&(lt|gt|amp);/gi,punctuation:/[{}[\];(),.:]/g};; +Prism.languages.javascript=Prism.languages.extend("clike",{keyword:/\b(break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|finally|for|function|get|if|implements|import|in|instanceof|interface|let|new|null|package|private|protected|public|return|set|static|super|switch|this|throw|true|try|typeof|var|void|while|with|yield)\b/g,number:/\b-?(0x[\dA-Fa-f]+|\d*\.?\d+([Ee]-?\d+)?|NaN|-?Infinity)\b/g});Prism.languages.insertBefore("javascript","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/g,lookbehind:!0}});Prism.languages.markup&&Prism.languages.insertBefore("markup","tag",{script:{pattern:/[\w\W]*?<\/script>/ig,inside:{tag:{pattern:/|<\/script>/ig,inside:Prism.languages.markup.tag.inside},rest:Prism.languages.javascript}}}); +; diff --git a/sources/library/jRange/jquery.range-min.js b/sources/library/jRange/jquery.range-min.js new file mode 100644 index 00000000..589913e5 --- /dev/null +++ b/sources/library/jRange/jquery.range-min.js @@ -0,0 +1 @@ +!function($,t,i,s){"use strict";var o=function(){return this.init.apply(this,arguments)};o.prototype={defaults:{onstatechange:function(){},isRange:!1,showLabels:!0,showScale:!0,step:1,format:"%s",theme:"theme-green",width:300,disable:!1},template:'
123456
456789
',init:function(t,i){this.options=$.extend({},this.defaults,i),this.inputNode=$(t),this.options.value=this.inputNode.val()||(this.options.isRange?this.options.from+","+this.options.from:this.options.from),this.domNode=$(this.template),this.domNode.addClass(this.options.theme),this.inputNode.after(this.domNode),this.domNode.on("change",this.onChange),this.pointers=$(".pointer",this.domNode),this.lowPointer=this.pointers.first(),this.highPointer=this.pointers.last(),this.labels=$(".pointer-label",this.domNode),this.lowLabel=this.labels.first(),this.highLabel=this.labels.last(),this.scale=$(".scale",this.domNode),this.bar=$(".selected-bar",this.domNode),this.clickableBar=this.domNode.find(".clickable-dummy"),this.interval=this.options.to-this.options.from,this.render()},render:function(){return 0!==this.inputNode.width()||this.options.width?(this.domNode.width(this.options.width||this.inputNode.width()),this.inputNode.hide(),this.isSingle()&&(this.lowPointer.hide(),this.lowLabel.hide()),this.options.showLabels||this.labels.hide(),this.attachEvents(),this.options.showScale&&this.renderScale(),void this.setValue(this.options.value)):void console.log("jRange : no width found, returning")},isSingle:function(){return"number"==typeof this.options.value?!0:-1!==this.options.value.indexOf(",")||this.options.isRange?!1:!0},attachEvents:function(){this.clickableBar.click($.proxy(this.barClicked,this)),this.pointers.on("mousedown touchstart",$.proxy(this.onDragStart,this)),this.pointers.bind("dragstart",function(t){t.preventDefault()})},onDragStart:function(t){if(!(this.options.disable||"mousedown"===t.type&&1!==t.which)){t.stopPropagation(),t.preventDefault();var s=$(t.target);this.pointers.removeClass("last-active"),s.addClass("focused last-active"),this[(s.hasClass("low")?"low":"high")+"Label"].addClass("focused"),$(i).on("mousemove.slider touchmove.slider",$.proxy(this.onDrag,this,s)),$(i).on("mouseup.slider touchend.slider touchcancel.slider",$.proxy(this.onDragEnd,this))}},onDrag:function(t,i){i.stopPropagation(),i.preventDefault(),i.originalEvent.touches&&i.originalEvent.touches.length?i=i.originalEvent.touches[0]:i.originalEvent.changedTouches&&i.originalEvent.changedTouches.length&&(i=i.originalEvent.changedTouches[0]);var s=i.clientX-this.domNode.offset().left;this.domNode.trigger("change",[this,t,s])},onDragEnd:function(t){this.pointers.removeClass("focused"),this.labels.removeClass("focused"),$(i).off(".slider")},barClicked:function(t){if(!this.options.disable){var i=t.pageX-this.clickableBar.offset().left;if(this.isSingle())this.setPosition(this.pointers.last(),i,!0,!0);else{var s=Math.abs(parseInt(this.pointers.first().css("left"),10)-i+this.pointers.first().width()/2)'+("|"!=t[o]?""+t[o]+"":"")+"";this.scale.html(s),$("ins",this.scale).each(function(){$(this).css({marginLeft:-$(this).outerWidth()/2})})},getBarWidth:function(){var t=this.options.value.split(",");return t.length>1?parseInt(t[1],10)-parseInt(t[0],10):parseInt(t[0],10)},showPointerValue:function(t,i,o){var e=$(".pointer-label",this.domNode)[t.hasClass("low")?"first":"last"](),n,h=this.positionToValue(i);if($.isFunction(this.options.format)){var a=this.isSingle()?s:t.hasClass("low")?"low":"high";n=this.options.format(h,a)}else n=this.options.format.replace("%s",h);var l=e.html(n).width(),r=i-l/2;r=Math.min(Math.max(r,0),this.options.width-l),e[o?"animate":"css"]({left:r}),this.setInputValue(t,h)},valuesToPrc:function(t){var i=100*(t[0]-this.options.from)/this.interval,s=100*(t[1]-this.options.from)/this.interval;return[i,s]},prcToPx:function(t){return this.domNode.width()*t/100},positionToValue:function(t){var i=t/this.domNode.width()*this.interval;return i+=this.options.from,Math.round(i/this.options.step)*this.options.step},setInputValue:function(t,i){if(this.isSingle())this.options.value=i.toString();else{var s=this.options.value.split(",");this.options.value=t.hasClass("low")?i+","+s[1]:s[0]+","+i}this.inputNode.val()!==this.options.value&&(this.inputNode.val(this.options.value),this.options.onstatechange.call(this,this.options.value))},getValue:function(){return this.options.value},isReadonly:function(){this.domNode.toggleClass("slider-readonly",this.options.disable)},disable:function(){this.options.disable=!0,this.isReadonly()},enable:function(){this.options.disable=!1,this.isReadonly()},toggleDisable:function(){this.options.disable=!this.options.disable,this.isReadonly()}};var e="jRange";$.fn[e]=function(i){var s=arguments,n;return this.each(function(){var h=$(this),a=$.data(this,"plugin_"+e),l="object"==typeof i&&i;a||(h.data("plugin_"+e,a=new o(this,l)),$(t).resize(function(){a.setValue(a.getValue())})),"string"==typeof i&&(n=a[i].apply(a,Array.prototype.slice.call(s,1)))}),n||this}}(jQuery,window,document); \ No newline at end of file diff --git a/sources/library/jRange/jquery.range.css b/sources/library/jRange/jquery.range.css new file mode 100644 index 00000000..62dc15b4 --- /dev/null +++ b/sources/library/jRange/jquery.range.css @@ -0,0 +1,173 @@ +.slider-container { + width: 300px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} +.slider-container .back-bar { + height: 10px; + position: relative; +} +.slider-container .back-bar .selected-bar { + position: absolute; + height: 100%; +} +.slider-container .back-bar .pointer { + position: absolute; + width: 10px; + height: 10px; + background-color: red; + cursor: col-resize; + opacity: 1; + z-index: 2; +} +.slider-container .back-bar .pointer.last-active { + z-index: 3; +} +.slider-container .back-bar .pointer-label { + position: absolute; + top: -17px; + font-size: 8px; + background: white; + white-space: nowrap; + line-height: 1; +} +.slider-container .back-bar .focused { + z-index: 10; +} +.slider-container .clickable-dummy { + cursor: pointer; + position: absolute; + width: 100%; + height: 100%; + z-index: 1; +} +.slider-container .scale { + top: 2px; + position: relative; +} +.slider-container .scale span { + position: absolute; + height: 5px; + border-left: 1px solid #999; + font-size: 0; +} +.slider-container .scale ins { + font-size: 9px; + text-decoration: none; + position: absolute; + left: 0; + top: 5px; + color: #999; + line-height: 1; +} +.slider-container.slider-readonly .clickable-dummy, +.slider-container.slider-readonly .pointer { + cursor: auto; +} +.theme-green .back-bar { + height: 5px; + border-radius: 2px; + background-color: #eeeeee; + background-color: #e7e7e7; + background-image: -moz-linear-gradient(top, #eeeeee, #dddddd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eeeeee), to(#dddddd)); + background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd); + background-image: -o-linear-gradient(top, #eeeeee, #dddddd); + background-image: linear-gradient(to bottom, #eeeeee, #dddddd); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee', endColorstr='#ffdddddd', GradientType=0); +} +.theme-green .back-bar .selected-bar { + border-radius: 2px; + background-color: #a1fad0; + background-image: -moz-linear-gradient(top, #bdfade, #76fabc); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#bdfade), to(#76fabc)); + background-image: -webkit-linear-gradient(top, #bdfade, #76fabc); + background-image: -o-linear-gradient(top, #bdfade, #76fabc); + background-image: linear-gradient(to bottom, #bdfade, #76fabc); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffbdfade', endColorstr='#ff76fabc', GradientType=0); +} +.theme-green .back-bar .pointer { + width: 14px; + height: 14px; + top: -5px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-radius: 10px; + border: 1px solid #AAA; + background-color: #e7e7e7; + background-image: -moz-linear-gradient(top, #eeeeee, #dddddd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eeeeee), to(#dddddd)); + background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd); + background-image: -o-linear-gradient(top, #eeeeee, #dddddd); + background-image: linear-gradient(to bottom, #eeeeee, #dddddd); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee', endColorstr='#ffdddddd', GradientType=0); +} +.theme-green .back-bar .pointer-label { + color: #999; +} +.theme-green .back-bar .focused { + color: #333; +} +.theme-green .scale span { + border-left: 1px solid #e5e5e5; +} +.theme-green .scale ins { + color: #999; +} +.theme-blue .back-bar { + height: 5px; + border-radius: 2px; + background-color: #eeeeee; + background-color: #e7e7e7; + background-image: -moz-linear-gradient(top, #eeeeee, #dddddd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eeeeee), to(#dddddd)); + background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd); + background-image: -o-linear-gradient(top, #eeeeee, #dddddd); + background-image: linear-gradient(to bottom, #eeeeee, #dddddd); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee', endColorstr='#ffdddddd', GradientType=0); +} +.theme-blue .back-bar .selected-bar { + border-radius: 2px; + background-color: #92c1f9; + background-image: -moz-linear-gradient(top, #b1d1f9, #64a8f9); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#b1d1f9), to(#64a8f9)); + background-image: -webkit-linear-gradient(top, #b1d1f9, #64a8f9); + background-image: -o-linear-gradient(top, #b1d1f9, #64a8f9); + background-image: linear-gradient(to bottom, #b1d1f9, #64a8f9); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffb1d1f9', endColorstr='#ff64a8f9', GradientType=0); +} +.theme-blue .back-bar .pointer { + width: 14px; + height: 14px; + top: -5px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-radius: 10px; + border: 1px solid #AAA; + background-color: #e7e7e7; + background-image: -moz-linear-gradient(top, #eeeeee, #dddddd); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#eeeeee), to(#dddddd)); + background-image: -webkit-linear-gradient(top, #eeeeee, #dddddd); + background-image: -o-linear-gradient(top, #eeeeee, #dddddd); + background-image: linear-gradient(to bottom, #eeeeee, #dddddd); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffeeeeee', endColorstr='#ffdddddd', GradientType=0); +} +.theme-blue .back-bar .pointer-label { + color: #999; +} +.theme-blue .back-bar .focused { + color: #333; +} +.theme-blue .scale span { + border-left: 1px solid #e5e5e5; +} +.theme-blue .scale ins { + color: #999; +} diff --git a/sources/library/jRange/jquery.range.js b/sources/library/jRange/jquery.range.js new file mode 100644 index 00000000..860b7451 --- /dev/null +++ b/sources/library/jRange/jquery.range.js @@ -0,0 +1,335 @@ +/*jshint multistr:true, curly: false */ +/*global jQuery:false, define: false */ +/** + * jRange - Awesome range control + * + * Written by + * ---------- + * Nitin Hayaran (nitinhayaran@gmail.com) + * + * Licensed under the MIT (MIT-LICENSE.txt). + * + * @author Nitin Hayaran + * @version 0.1-RELEASE + * + * Dependencies + * ------------ + * jQuery (http://jquery.com) + * + **/ +; +(function($, window, document, undefined) { + 'use strict'; + + var jRange = function() { + return this.init.apply(this, arguments); + }; + jRange.prototype = { + defaults: { + onstatechange: function() {}, + isRange: false, + showLabels: true, + showScale: true, + step: 1, + format: '%s', + theme: 'theme-green', + width: 300, + disable: false + }, + template: '
\ +
\ +
\ +
123456
\ +
456789
\ +
\ +
\ +
\ +
', + init: function(node, options) { + this.options = $.extend({}, this.defaults, options); + this.inputNode = $(node); + this.options.value = this.inputNode.val() || (this.options.isRange ? this.options.from + ',' + this.options.from : this.options.from); + this.domNode = $(this.template); + this.domNode.addClass(this.options.theme); + this.inputNode.after(this.domNode); + this.domNode.on('change', this.onChange); + this.pointers = $('.pointer', this.domNode); + this.lowPointer = this.pointers.first(); + this.highPointer = this.pointers.last(); + this.labels = $('.pointer-label', this.domNode); + this.lowLabel = this.labels.first(); + this.highLabel = this.labels.last(); + this.scale = $('.scale', this.domNode); + this.bar = $('.selected-bar', this.domNode); + this.clickableBar = this.domNode.find('.clickable-dummy'); + this.interval = this.options.to - this.options.from; + this.render(); + }, + render: function() { + // Check if inputNode is visible, and have some width, so that we can set slider width accordingly. + if (this.inputNode.width() === 0 && !this.options.width) { + console.log('jRange : no width found, returning'); + return; + } else { + this.domNode.width(this.options.width || this.inputNode.width()); + this.inputNode.hide(); + } + + if (this.isSingle()) { + this.lowPointer.hide(); + this.lowLabel.hide(); + } + if (!this.options.showLabels) { + this.labels.hide(); + } + this.attachEvents(); + if (this.options.showScale) { + this.renderScale(); + } + this.setValue(this.options.value); + }, + isSingle: function() { + if (typeof(this.options.value) === 'number') { + return true; + } + return (this.options.value.indexOf(',') !== -1 || this.options.isRange) ? + false : true; + }, + attachEvents: function() { + this.clickableBar.click($.proxy(this.barClicked, this)); + this.pointers.on('mousedown touchstart', $.proxy(this.onDragStart, this)); + this.pointers.bind('dragstart', function(event) { + event.preventDefault(); + }); + }, + onDragStart: function(e) { + if ( this.options.disable || (e.type === 'mousedown' && e.which !== 1)) { + return; + } + e.stopPropagation(); + e.preventDefault(); + var pointer = $(e.target); + this.pointers.removeClass('last-active'); + pointer.addClass('focused last-active'); + this[(pointer.hasClass('low') ? 'low' : 'high') + 'Label'].addClass('focused'); + $(document).on('mousemove.slider touchmove.slider', $.proxy(this.onDrag, this, pointer)); + $(document).on('mouseup.slider touchend.slider touchcancel.slider', $.proxy(this.onDragEnd, this)); + }, + onDrag: function(pointer, e) { + e.stopPropagation(); + e.preventDefault(); + + if (e.originalEvent.touches && e.originalEvent.touches.length) { + e = e.originalEvent.touches[0]; + } else if (e.originalEvent.changedTouches && e.originalEvent.changedTouches.length) { + e = e.originalEvent.changedTouches[0]; + } + + var position = e.clientX - this.domNode.offset().left; + this.domNode.trigger('change', [this, pointer, position]); + }, + onDragEnd: function(e) { + this.pointers.removeClass('focused'); + this.labels.removeClass('focused'); + $(document).off('.slider'); + }, + barClicked: function(e) { + if(this.options.disable) return; + var x = e.pageX - this.clickableBar.offset().left; + if (this.isSingle()) + this.setPosition(this.pointers.last(), x, true, true); + else { + var pointer = Math.abs(parseInt(this.pointers.first().css('left'), 10) - x + this.pointers.first().width() / 2) < Math.abs(parseInt(this.pointers.last().css('left'), 10) - x + this.pointers.first().width() / 2) ? + this.pointers.first() : this.pointers.last(); + this.setPosition(pointer, x, true, true); + } + }, + onChange: function(e, self, pointer, position) { + var min, max; + if (self.isSingle()) { + min = 0; + max = self.domNode.width(); + } else { + min = pointer.hasClass('high') ? self.lowPointer.position().left + self.lowPointer.width() / 2 : 0; + max = pointer.hasClass('low') ? self.highPointer.position().left + self.highPointer.width() / 2 : self.domNode.width(); + } + var value = Math.min(Math.max(position, min), max); + self.setPosition(pointer, value, true); + }, + setPosition: function(pointer, position, isPx, animate) { + var leftPos, + lowPos = this.lowPointer.position().left, + highPos = this.highPointer.position().left, + circleWidth = this.highPointer.width() / 2; + if (!isPx) { + position = this.prcToPx(position); + } + if (pointer[0] === this.highPointer[0]) { + highPos = Math.round(position - circleWidth); + } else { + lowPos = Math.round(position - circleWidth); + } + pointer[animate ? 'animate' : 'css']({ + 'left': Math.round(position - circleWidth) + }); + if (this.isSingle()) { + leftPos = 0; + } else { + leftPos = lowPos + circleWidth; + } + this.bar[animate ? 'animate' : 'css']({ + 'width': Math.round(highPos + circleWidth - leftPos), + 'left': leftPos + }); + this.showPointerValue(pointer, position, animate); + this.isReadonly(); + }, + // will be called from outside + setValue: function(value) { + var values = value.toString().split(','); + this.options.value = value; + var prc = this.valuesToPrc(values.length === 2 ? values : [0, values[0]]); + if (this.isSingle()) { + this.setPosition(this.highPointer, prc[1]); + } else { + this.setPosition(this.lowPointer, prc[0]); + this.setPosition(this.highPointer, prc[1]); + } + }, + renderScale: function() { + var s = this.options.scale || [this.options.from, this.options.to]; + var prc = Math.round((100 / (s.length - 1)) * 10) / 10; + var str = ''; + for (var i = 0; i < s.length; i++) { + str += '' + (s[i] != '|' ? '' + s[i] + '' : '') + ''; + } + this.scale.html(str); + + $('ins', this.scale).each(function() { + $(this).css({ + marginLeft: -$(this).outerWidth() / 2 + }); + }); + }, + getBarWidth: function() { + var values = this.options.value.split(','); + if (values.length > 1) { + return parseInt(values[1], 10) - parseInt(values[0], 10); + } else { + return parseInt(values[0], 10); + } + }, + showPointerValue: function(pointer, position, animate) { + var label = $('.pointer-label', this.domNode)[pointer.hasClass('low') ? 'first' : 'last'](); + var text; + var value = this.positionToValue(position); + if ($.isFunction(this.options.format)) { + var type = this.isSingle() ? undefined : (pointer.hasClass('low') ? 'low' : 'high'); + text = this.options.format(value, type); + } else { + text = this.options.format.replace('%s', value); + } + + var width = label.html(text).width(), + left = position - width / 2; + left = Math.min(Math.max(left, 0), this.options.width - width); + label[animate ? 'animate' : 'css']({ + left: left + }); + this.setInputValue(pointer, value); + }, + valuesToPrc: function(values) { + var lowPrc = ((values[0] - this.options.from) * 100 / this.interval), + highPrc = ((values[1] - this.options.from) * 100 / this.interval); + return [lowPrc, highPrc]; + }, + prcToPx: function(prc) { + return (this.domNode.width() * prc) / 100; + }, + positionToValue: function(pos) { + var value = (pos / this.domNode.width()) * this.interval; + value = value + this.options.from; + return Math.round(value / this.options.step) * this.options.step; + }, + setInputValue: function(pointer, v) { + // if(!isChanged) return; + if (this.isSingle()) { + this.options.value = v.toString(); + } else { + var values = this.options.value.split(','); + if (pointer.hasClass('low')) { + this.options.value = v + ',' + values[1]; + } else { + this.options.value = values[0] + ',' + v; + } + } + if (this.inputNode.val() !== this.options.value) { + this.inputNode.val(this.options.value); + this.options.onstatechange.call(this, this.options.value); + } + }, + getValue: function() { + return this.options.value; + }, + isReadonly: function(){ + this.domNode.toggleClass('slider-readonly', this.options.disable); + }, + disable: function(){ + this.options.disable = true; + this.isReadonly(); + }, + enable: function(){ + this.options.disable = false; + this.isReadonly(); + }, + toggleDisable: function(){ + this.options.disable = !this.options.disable; + this.isReadonly(); + } + }; + + /*$.jRange = function (node, options) { + var jNode = $(node); + if(!jNode.data('jrange')){ + jNode.data('jrange', new jRange(node, options)); + } + return jNode.data('jrange'); + }; + + $.fn.jRange = function (options) { + return this.each(function(){ + $.jRange(this, options); + }); + };*/ + + var pluginName = 'jRange'; + // A really lightweight plugin wrapper around the constructor, + // preventing against multiple instantiations + $.fn[pluginName] = function(option) { + var args = arguments, + result; + + this.each(function() { + var $this = $(this), + data = $.data(this, 'plugin_' + pluginName), + options = typeof option === 'object' && option; + if (!data) { + $this.data('plugin_' + pluginName, (data = new jRange(this, options))); + $(window).resize(function() { + data.setValue(data.getValue()); + }); // Update slider position when window is resized to keep it in sync with scale + } + // if first argument is a string, call silimarly named function + // this gives flexibility to call functions of the plugin e.g. + // - $('.dial').plugin('destroy'); + // - $('.dial').plugin('render', $('.new-child')); + if (typeof option === 'string') { + result = data[option].apply(data, Array.prototype.slice.call(args, 1)); + } + }); + + // To enable plugin returns values + return result || this; + }; + +})(jQuery, window, document); diff --git a/sources/library/jRange/jquery.range.less b/sources/library/jRange/jquery.range.less new file mode 100644 index 00000000..4034bdd6 --- /dev/null +++ b/sources/library/jRange/jquery.range.less @@ -0,0 +1,198 @@ +#gradient { + .horizontal(@startColor: #555, @endColor: #333) { + background-color: @endColor; + background-image: -moz-linear-gradient(left, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 100% 0, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(left, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(left, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to right, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .vertical(@startColor: #555, @endColor: #333) { + background-color: mix(@startColor, @endColor, 60%); + background-image: -moz-linear-gradient(top, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), to(@endColor)); // Safari 4+, Chrome 2+ + background-image: -webkit-linear-gradient(top, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(top, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(to bottom, @startColor, @endColor); // Standard, IE10 + background-repeat: repeat-x; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down + } + .directional(@startColor: #555, @endColor: #333, @deg: 45deg) { + background-color: @endColor; + background-repeat: repeat-x; + background-image: -moz-linear-gradient(@deg, @startColor, @endColor); // FF 3.6+ + background-image: -webkit-linear-gradient(@deg, @startColor, @endColor); // Safari 5.1+, Chrome 10+ + background-image: -o-linear-gradient(@deg, @startColor, @endColor); // Opera 11.10 + background-image: linear-gradient(@deg, @startColor, @endColor); // Standard, IE10 + } + .vertical-three-colors(@startColor: #00b3ee, @midColor: #7a43b6, @colorStop: 50%, @endColor: #c3325f) { + background-color: mix(@midColor, @endColor, 80%); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(@startColor), color-stop(@colorStop, @midColor), to(@endColor)); + background-image: -webkit-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: -moz-linear-gradient(top, @startColor, @midColor @colorStop, @endColor); + background-image: -o-linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-image: linear-gradient(@startColor, @midColor @colorStop, @endColor); + background-repeat: no-repeat; + filter: e(%("progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)",argb(@startColor),argb(@endColor))); // IE9 and down, gets no color-stop at all for proper fallback + } + .radial(@innerColor: #555, @outerColor: #333) { + background-color: @outerColor; + background-image: -webkit-gradient(radial, center center, 0, center center, 460, from(@innerColor), to(@outerColor)); + background-image: -webkit-radial-gradient(circle, @innerColor, @outerColor); + background-image: -moz-radial-gradient(circle, @innerColor, @outerColor); + background-image: -o-radial-gradient(circle, @innerColor, @outerColor); + background-repeat: no-repeat; + } + .striped(@color: #555, @angle: 45deg) { + background-color: @color; + background-image: -webkit-gradient(linear, 0 100%, 100% 0, color-stop(.25, rgba(255,255,255,.15)), color-stop(.25, transparent), color-stop(.5, transparent), color-stop(.5, rgba(255,255,255,.15)), color-stop(.75, rgba(255,255,255,.15)), color-stop(.75, transparent), to(transparent)); + background-image: -webkit-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -moz-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: -o-linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + background-image: linear-gradient(@angle, rgba(255,255,255,.15) 25%, transparent 25%, transparent 50%, rgba(255,255,255,.15) 50%, rgba(255,255,255,.15) 75%, transparent 75%, transparent); + } +} + +.slider-container { + width: 300px; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + .back-bar { + height: 10px; + position: relative; + .selected-bar { + position: absolute; + height: 100%; + } + .pointer { + position: absolute; + width: 10px; + height: 10px; + background-color: red; + cursor: col-resize; + opacity: 1; + z-index: 2; + &.last-active{ + z-index: 3; + } + } + .pointer-label { + position: absolute; + top: -17px; + font-size: 8px; + background: white; + white-space: nowrap; + line-height: 1; + } + .focused { + z-index: 10; + } + } + .clickable-dummy { + cursor: pointer; + position: absolute; + width: 100%; + height: 100%; + z-index: 1; + } + .scale { + top: 2px; + position: relative; + span { + position: absolute; + height: 5px; + border-left: 1px solid #999; + font-size: 0; + } + ins { + font-size: 9px; + text-decoration: none; + position: absolute; + left: 0; + top: 5px; + color: #999; + line-height: 1; + } + } + &.slider-readonly{ + .clickable-dummy, .pointer { + cursor: auto; + } + } +} +.theme-green { + .back-bar { + height: 5px; + border-radius: 2px; + background-color: #eeeeee; + #gradient > .vertical(#eeeeee, #dddddd); + .selected-bar { + border-radius: 2px; + #gradient > .vertical(#bdfade, #76fabc); + } + .pointer { + width: 14px; + height: 14px; + top: -5px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-radius: 10px; + border: 1px solid #AAA; + #gradient > .vertical(#eeeeee, #dddddd); + } + .pointer-label { + color: #999; + } + .focused { + color: #333; + } + } + .scale { + span { + border-left: 1px solid #e5e5e5; + } + ins { + color: #999; + } + } +} + +.theme-blue { + .back-bar { + height: 5px; + border-radius: 2px; + background-color: #eeeeee; + #gradient > .vertical(#eeeeee, #dddddd); + .selected-bar { + border-radius: 2px; + #gradient > .vertical(#b1d1f9, #64a8f9); + } + .pointer { + width: 14px; + height: 14px; + top: -5px; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-radius: 10px; + border: 1px solid #AAA; + #gradient > .vertical(#eeeeee, #dddddd); + } + .pointer-label { + color: #999; + } + .focused { + color: #333; + } + } + .scale { + span { + border-left: 1px solid #e5e5e5; + } + ins { + color: #999; + } + } +} diff --git a/sources/library/jgrowl/README b/sources/library/jgrowl/README new file mode 100644 index 00000000..d0f1a62a --- /dev/null +++ b/sources/library/jgrowl/README @@ -0,0 +1,3 @@ +https://github.com/stanlemon/jGrowl + +jGrowl is free and open source, it's distributed under the MIT and GPL licenses diff --git a/sources/library/jgrowl/jquery.jgrowl.css b/sources/library/jgrowl/jquery.jgrowl.css new file mode 100644 index 00000000..ea394841 --- /dev/null +++ b/sources/library/jgrowl/jquery.jgrowl.css @@ -0,0 +1 @@ +.jGrowl{z-index:9999;color:#fff;font-size:12px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;position:fixed}.jGrowl.top-left{left:0;top:0}.jGrowl.top-right{right:0;top:0}.jGrowl.bottom-left{left:0;bottom:0}.jGrowl.bottom-right{right:0;bottom:0}.jGrowl.center{top:0;width:50%;left:25%}.jGrowl.center .jGrowl-closer,.jGrowl.center .jGrowl-notification{margin-left:auto;margin-right:auto}.jGrowl-notification{background-color:#000;opacity:.9;-ms-filter:alpha(90);filter:alpha(90);zoom:1;width:250px;padding:10px;margin:10px;text-align:left;display:none;border-radius:5px;min-height:40px}.jGrowl-notification .ui-state-highlight,.jGrowl-notification .ui-widget-content .ui-state-highlight,.jGrowl-notification .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}.jGrowl-notification .jGrowl-header{font-weight:700;font-size:.85em}.jGrowl-notification .jGrowl-close{background-color:transparent;color:inherit;border:none;z-index:99;float:right;font-weight:700;font-size:1em;cursor:pointer}.jGrowl-closer{background-color:#000;opacity:.9;-ms-filter:alpha(90);filter:alpha(90);zoom:1;width:250px;padding:10px;margin:10px;display:none;border-radius:5px;padding-top:4px;padding-bottom:4px;cursor:pointer;font-size:.9em;font-weight:700;text-align:center}.jGrowl-closer .ui-state-highlight,.jGrowl-closer .ui-widget-content .ui-state-highlight,.jGrowl-closer .ui-widget-header .ui-state-highlight{border:1px solid #000;background:#000;color:#fff}@media print{.jGrowl{display:none}} \ No newline at end of file diff --git a/sources/library/jgrowl/jquery.jgrowl_minimized.js b/sources/library/jgrowl/jquery.jgrowl_minimized.js new file mode 100644 index 00000000..7e8b6fb3 --- /dev/null +++ b/sources/library/jgrowl/jquery.jgrowl_minimized.js @@ -0,0 +1,2 @@ +!function(a){a.jGrowl=function(b,c){0===a("#jGrowl").length&&a('
').addClass(c&&c.position?c.position:a.jGrowl.defaults.position).appendTo(c&&c.appendTo?c.appendTo:a.jGrowl.defaults.appendTo),a("#jGrowl").jGrowl(b,c)},a.fn.jGrowl=function(b,c){if(void 0===c&&a.isPlainObject(b)&&(c=b,b=c.message),a.isFunction(this.each)){var d=arguments;return this.each(function(){void 0===a(this).data("jGrowl.instance")&&(a(this).data("jGrowl.instance",a.extend(new a.fn.jGrowl,{notifications:[],element:null,interval:null})),a(this).data("jGrowl.instance").startup(this)),a.isFunction(a(this).data("jGrowl.instance")[b])?a(this).data("jGrowl.instance")[b].apply(a(this).data("jGrowl.instance"),a.makeArray(d).slice(1)):a(this).data("jGrowl.instance").create(b,c)})}},a.extend(a.fn.jGrowl.prototype,{defaults:{pool:0,header:"",group:"",sticky:!1,position:"top-right",appendTo:"body",glue:"after",theme:"default",themeState:"highlight",corners:"10px",check:250,life:3e3,closeDuration:"normal",openDuration:"normal",easing:"swing",closer:!0,closeTemplate:"×",closerTemplate:"
[ close all ]
",log:function(){},beforeOpen:function(){},afterOpen:function(){},open:function(){},beforeClose:function(){},close:function(){},click:function(){},animateOpen:{opacity:"show"},animateClose:{opacity:"hide"}},notifications:[],element:null,interval:null,create:function(b,c){var d=a.extend({},this.defaults,c);"undefined"!=typeof d.speed&&(d.openDuration=d.speed,d.closeDuration=d.speed),this.notifications.push({message:b,options:d}),d.log.apply(this.element,[this.element,b,d])},render:function(b){var c=this,d=b.message,e=b.options;e.themeState=""===e.themeState?"":"ui-state-"+e.themeState;var f=a("
").addClass("jGrowl-notification alert "+e.themeState+" ui-corner-all"+(void 0!==e.group&&""!==e.group?" "+e.group:"")).append(a(" + +
+
+ + + +
+
+ +
+
+

... or visit Google or close the window without saving!

+
+ + +

Example 6: HTML5 inputs!

+

+ This example shows support for HTML5 input types. It's not a coffee order form, + but you need coffee if you're working with HTML5 :-) +

+ +
+

Doing HTML5? You'll need coffee!

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

... or visit Google or close the window without saving!

+
+
+

Example 7: Mark current state as not dirty!

+

+ This example shows how you can mark the current state as not dirty. Handy for AJAX forms + we're you're managing your own submits. +

+ +
+

Tell us your default coffee

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

... or visit Google or close the window without saving!

+
+
+ +

+ This jQuery plugin is developed by Chris Dance + at PaperCut Software - Are-You-Sure is used in + PaperCut's printing management software and it has been open sourced with help of + Tom, Jack and Matt from PaperCut's dev team. +

+ + + diff --git a/sources/library/jquery.AreYouSure/jquery.are-you-sure.js b/sources/library/jquery.AreYouSure/jquery.are-you-sure.js new file mode 100644 index 00000000..3c41e2fc --- /dev/null +++ b/sources/library/jquery.AreYouSure/jquery.are-you-sure.js @@ -0,0 +1,192 @@ +/*! + * jQuery Plugin: Are-You-Sure (Dirty Form Detection) + * https://github.com/codedance/jquery.AreYouSure/ + * + * Copyright (c) 2012-2014, Chris Dance and PaperCut Software http://www.papercut.com/ + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Author: chris.dance@papercut.com + * Version: 1.9.0 + * Date: 13th August 2014 + */ +(function($) { + + $.fn.areYouSure = function(options) { + + var settings = $.extend( + { + 'message' : 'You have unsaved changes!', + 'dirtyClass' : 'dirty', + 'change' : null, + 'silent' : false, + 'addRemoveFieldsMarksDirty' : false, + 'fieldEvents' : 'change keyup propertychange input', + 'fieldSelector': ":input:not(input[type=submit]):not(input[type=button])" + }, options); + + var getValue = function($field) { + if ($field.hasClass('ays-ignore') + || $field.hasClass('aysIgnore') + || $field.attr('data-ays-ignore') + || $field.attr('name') === undefined) { + return null; + } + + if ($field.is(':disabled')) { + return 'ays-disabled'; + } + + var val; + var type = $field.attr('type'); + if ($field.is('select')) { + type = 'select'; + } + + switch (type) { + case 'checkbox': + case 'radio': + val = $field.is(':checked'); + break; + case 'select': + val = ''; + $field.find('option').each(function(o) { + var $option = $(this); + if ($option.is(':selected')) { + val += $option.val(); + } + }); + break; + default: + val = $field.val(); + } + + return val; + }; + + var storeOrigValue = function($field) { + $field.data('ays-orig', getValue($field)); + }; + + var checkForm = function(evt) { + + var isFieldDirty = function($field) { + var origValue = $field.data('ays-orig'); + if (undefined === origValue) { + return false; + } + return (getValue($field) != origValue); + }; + + var $form = ($(this).is('form')) + ? $(this) + : $(this).parents('form'); + + // Test on the target first as it's the most likely to be dirty + if (isFieldDirty($(evt.target))) { + setDirtyStatus($form, true); + return; + } + + $fields = $form.find(settings.fieldSelector); + + if (settings.addRemoveFieldsMarksDirty) { + // Check if field count has changed + var origCount = $form.data("ays-orig-field-count"); + if (origCount != $fields.length) { + setDirtyStatus($form, true); + return; + } + } + + // Brute force - check each field + var isDirty = false; + $fields.each(function() { + $field = $(this); + if (isFieldDirty($field)) { + isDirty = true; + return false; // break + } + }); + + setDirtyStatus($form, isDirty); + }; + + var initForm = function($form) { + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { storeOrigValue($(this)); }); + $(fields).unbind(settings.fieldEvents, checkForm); + $(fields).bind(settings.fieldEvents, checkForm); + $form.data("ays-orig-field-count", $(fields).length); + setDirtyStatus($form, false); + }; + + var setDirtyStatus = function($form, isDirty) { + var changed = isDirty != $form.hasClass(settings.dirtyClass); + $form.toggleClass(settings.dirtyClass, isDirty); + + // Fire change event if required + if (changed) { + if (settings.change) settings.change.call($form, $form); + + if (isDirty) $form.trigger('dirty.areYouSure', [$form]); + if (!isDirty) $form.trigger('clean.areYouSure', [$form]); + $form.trigger('change.areYouSure', [$form]); + } + }; + + var rescan = function() { + var $form = $(this); + var fields = $form.find(settings.fieldSelector); + $(fields).each(function() { + var $field = $(this); + if (!$field.data('ays-orig')) { + storeOrigValue($field); + $field.bind(settings.fieldEvents, checkForm); + } + }); + // Check for changes while we're here + $form.trigger('checkform.areYouSure'); + }; + + var reinitialize = function() { + initForm($(this)); + } + + if (!settings.silent && !window.aysUnloadSet) { + window.aysUnloadSet = true; + $(window).bind('beforeunload', function() { + $dirtyForms = $("form").filter('.' + settings.dirtyClass); + if ($dirtyForms.length == 0) { + return; + } + // Prevent multiple prompts - seen on Chrome and IE + if (navigator.userAgent.toLowerCase().match(/msie|chrome/)) { + if (window.aysHasPrompted) { + return; + } + window.aysHasPrompted = true; + window.setTimeout(function() {window.aysHasPrompted = false;}, 900); + } + return settings.message; + }); + } + + return this.each(function(elem) { + if (!$(this).is('form')) { + return; + } + var $form = $(this); + + $form.submit(function() { + $form.removeClass(settings.dirtyClass); + }); + $form.bind('reset', function() { setDirtyStatus($form, false); }); + // Add a custom events + $form.bind('rescan.areYouSure', rescan); + $form.bind('reinitialize.areYouSure', reinitialize); + $form.bind('checkform.areYouSure', checkForm); + initForm($form); + }); + }; +})(jQuery); diff --git a/sources/library/jquery.AreYouSure/package.json b/sources/library/jquery.AreYouSure/package.json new file mode 100644 index 00000000..0b4c38dd --- /dev/null +++ b/sources/library/jquery.AreYouSure/package.json @@ -0,0 +1,45 @@ +{ + "name": "jquery.AreYouSure", + "description": "A light-weight jQuery \"dirty forms\" Plugin - it monitors HTML forms and alerts users to unsaved changes if they attempt to close the browser or navigate away from the page. (Are you sure?)", + "homepage": "https://github.com/codedance/jquery.AreYouSure", + "author": "Chris Dance (https://github.com/codedance)", + "contributors": [ + "Tom Clift (https://github.com/tclift)", + "Jon Egerton (http://www.jonegerton.com/)", + "Scadoodles (https://github.com/Scadoodles)", + "Albin Sunnanbo (https://github.com/albinsunnanbo)", + "Marc Sutton (http://www.codev.co.uk)" + ], + "version": "1.9.0", + "license": "MIT/GPLv2", + "keywords": [ "dirty", "form", "onbeforeunload", "save", "check" ], + "main": "jquery.are-you-sure.js", + "engines": { + "node": ">=0.8.0" + }, + "repository": { + "type": "git", + "url": "https://github.com/codedance/jquery.AreYouSure" + }, + "bugs": { + "url": "https://github.com/codedance/jquery.AreYouSure/issues" + }, + "dependencies": { + "jquery": ">=1.4.2" + }, + "devDependencies": { + "bower": "^1.3.1", + "grunt": "^0.4.5", + "grunt-cli": "^0.1.13", + "grunt-karma": "^0.8.3", + "karma-chrome-launcher": "^0.1.4", + "karma-jasmine": "^0.2.2", + "karma-ie-launcher": "^0.1.5", + "karma-firefox-launcher": "^0.1.3", + "karma-safari-launcher": "^0.1.1" + }, + "scripts": { + "postinstall": "node_modules/.bin/bower install", + "test": "node_modules/.bin/grunt test" + } +} diff --git a/sources/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html b/sources/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html new file mode 100644 index 00000000..1b285075 --- /dev/null +++ b/sources/library/jquery.AreYouSure/spec/javascripts/fixtures/input-text.html @@ -0,0 +1,4 @@ +
+ + +
diff --git a/sources/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js b/sources/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js new file mode 100644 index 00000000..5e02f7cb --- /dev/null +++ b/sources/library/jquery.AreYouSure/spec/javascripts/jquery.are-you-sure_spec.js @@ -0,0 +1,28 @@ +'use strict'; + +// Karma adds 'base/' to the default path +jasmine.getFixtures().fixturesPath = 'base/spec/javascripts/fixtures'; + +describe("A form's", function() { + var $form = undefined; + + describe('text input', function() { + var $textInput = undefined; + + beforeEach(function() { + loadFixtures('input-text.html'); + $form = $('form'); + $textInput = $('input[type=text]'); + $form.areYouSure(); + }); + + it('should cause dirtyness after its value changes', function(done) { + expect($form.hasClass('dirty')).toBe(false); + $textInput.val('new').change(); + setTimeout(function() { + expect($form.hasClass('dirty')).toBe(true); + done(); + }, 0); + }); + }); +}); diff --git a/sources/library/jquery.i18n/.gitignore b/sources/library/jquery.i18n/.gitignore new file mode 100644 index 00000000..ded2e0bd --- /dev/null +++ b/sources/library/jquery.i18n/.gitignore @@ -0,0 +1,2 @@ +build/compiler.jar + diff --git a/sources/library/jquery.i18n/LICENSE b/sources/library/jquery.i18n/LICENSE new file mode 100644 index 00000000..978ee2ae --- /dev/null +++ b/sources/library/jquery.i18n/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Dave Perrett, http://recursive-design.com/ + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. \ No newline at end of file diff --git a/sources/library/jquery.i18n/README.markdown b/sources/library/jquery.i18n/README.markdown new file mode 100644 index 00000000..cbd6e419 --- /dev/null +++ b/sources/library/jquery.i18n/README.markdown @@ -0,0 +1,152 @@ + +About +----- + +_jQuery-i18n_ is a jQuery plugin for doing client-side translations in javascript. It is based heavily on [javascript i18n that almost doesn't suck](http://markos.gaivo.net/blog/?p=100) by Marko Samastur, and is licensed under the [MIT license](http://www.opensource.org/licenses/mit-license.php). + +Installation +------------ + +You'll need to download the [jQuery library](http://docs.jquery.com/Downloading_jQuery#Current_Release), and include it before _jquery.i18n.js_ in your HTML source. See the _examples_ folder for examples. + +Usage +----- + +Before you can do any translation you have to initialise the plugin with a 'dictionary' (basically a property list mapping keys to their translations). + +```javascript +var my_dictionary = { + 'some text': 'a translation', + 'some more text': 'another translation' +} +$.i18n.setDictionary(my_dictionary); +``` + +Once you've initialised it with a dictionary, you can translate strings using the $.i18n._() function, for example: + +```javascript +$('div#example').text($.i18n._('some text')); +``` + +or using $('selector')._t() function + +```javascript +$('div#example')._t('some text'); +``` + +Wildcards +--------- + +It's straightforward to pass dynamic data into your translations. First, add _%s_ in the translation for each variable you want to swap in : + +```javascript +var my_dictionary = { + "wildcard example" : "We have been passed two values : %s and %s." +} +$.i18n.setDictionary(my_dictionary); +``` + +Next, pass an array of values in as the second argument when you perform the translation : + +```javascript +$('div#example').text($.i18n._('wildcard example', [100, 200])); +``` + +or + +```javascript +$('div#example')._t('wildcard example', [100, 200]); +``` + +This will output _We have been passed two values : 100 and 200._ + +Because some languages will need to order arguments differently to english, you can also specify the order in which the variables appear : + +```javascript +var my_dictionary = { + "wildcard example" : "We have been passed two values : %2$s and %1$s." +} +$.i18n.setDictionary(my_dictionary); + +$('div#example').text($.i18n._('wildcard example', [100, 200])); +``` + +This will output: _We have been passed two values: 200 and 100._ + +Building From Scratch +--------------------- + +You can build the regular, un-minified version simply by running _ant_: + +```bash +$ ant +Buildfile: build.xml + +jquery.i18n: + [echo] Building ./jquery.i18n.js + [echo] ./jquery.i18n.js built. + +BUILD SUCCESSFUL +Total time: 0 seconds +``` + +Before you can build the minified version yourself, you'll need to download the [Google Closure Compiler](http://closure-compiler.googlecode.com/files/compiler-latest.zip) and put it in a folder called _build_: + +```bash +$ mkdir build +$ cd build +$ wget http://closure-compiler.googlecode.com/files/compiler-latest.zip +$ unzip compiler-latest.zip +``` + +Once you have the compiler, you can build the minified version by running _ant min_: + +```bash +$ ant min +Buildfile: build.xml + +jquery.i18n: + [echo] Building ./jquery.i18n.js + [echo] ./jquery.i18n.js built. + +min: + [echo] Building ./jquery.i18n.min.js + [apply] Applied java to 1 file and 0 directories. + [delete] Deleting: /Users/dave/Documents/Code/jquery/jquery-i18n/tmpmin + [echo] ./jquery.i18n.min.js built. + +BUILD SUCCESSFUL +Total time: 1 second +``` + +Bug Reports +----------- + +If you come across any problems, please [create a ticket](https://github.com/recurser/jquery-i18n/issues) and we'll try to get it fixed as soon as possible. + + +Contributing +------------ + +Once you've made your commits: + +1. [Fork](http://help.github.com/fork-a-repo/) jquery-i18n +2. Create a topic branch - `git checkout -b my_branch` +3. Push to your branch - `git push origin my_branch` +4. Create a [Pull Request](http://help.github.com/pull-requests/) from your branch +5. That's it! + + +Author +------ + +Dave Perrett :: mail@recursive-design.com :: [@recurser](http://twitter.com/recurser) + + +Copyright +--------- + +Copyright (c) 2010 Dave Perrett. See [License](https://github.com/recurser/jquery-i18n/blob/master/LICENSE) for details. + + + diff --git a/sources/library/jquery.i18n/VERSION b/sources/library/jquery.i18n/VERSION new file mode 100644 index 00000000..f76f9131 --- /dev/null +++ b/sources/library/jquery.i18n/VERSION @@ -0,0 +1 @@ +0.9.2 \ No newline at end of file diff --git a/sources/library/jquery.i18n/build.xml b/sources/library/jquery.i18n/build.xml new file mode 100644 index 00000000..99274e75 --- /dev/null +++ b/sources/library/jquery.i18n/build.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jquery.i18n/examples/index.html b/sources/library/jquery.i18n/examples/index.html new file mode 100644 index 00000000..b73a13fc --- /dev/null +++ b/sources/library/jquery.i18n/examples/index.html @@ -0,0 +1,78 @@ + + + + +jQuery i18n Plugin + + + + + + + +

+ Click the button to translate the following text into some random Finnish from the + Wikipedia Finnish Phonology Article +

+ +
Example 1
+
Example 2
+
Example 3
+
Example 4
+
Example 5
+
Example 6
+
Example 7
+
Example 8
+
Example 9
+
Example 10
+
Dynamic Content
+
Ordered Dynamic Content
+ + + + diff --git a/sources/library/jquery.i18n/examples/jquery-1.4.2.js b/sources/library/jquery.i18n/examples/jquery-1.4.2.js new file mode 100644 index 00000000..e414a7ec --- /dev/null +++ b/sources/library/jquery.i18n/examples/jquery-1.4.2.js @@ -0,0 +1,6240 @@ +/*! + * jQuery JavaScript Library v1.4.2 + * http://jquery.com/ + * + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * Includes Sizzle.js + * http://sizzlejs.com/ + * Copyright 2010, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * + * Date: Sat Feb 13 22:33:48 2010 -0500 + */ +(function( window, undefined ) { + +// Define a local copy of jQuery +var jQuery = function( selector, context ) { + // The jQuery object is actually just the init constructor 'enhanced' + return new jQuery.fn.init( selector, context ); + }, + + // Map over jQuery in case of overwrite + _jQuery = window.jQuery, + + // Map over the $ in case of overwrite + _$ = window.$, + + // Use the correct document accordingly with window argument (sandbox) + document = window.document, + + // A central reference to the root jQuery(document) + rootjQuery, + + // A simple way to check for HTML strings or ID strings + // (both of which we optimize for) + quickExpr = /^[^<]*(<[\w\W]+>)[^>]*$|^#([\w-]+)$/, + + // Is it a simple selector + isSimple = /^.[^:#\[\.,]*$/, + + // Check if a string has a non-whitespace character in it + rnotwhite = /\S/, + + // Used for trimming whitespace + rtrim = /^(\s|\u00A0)+|(\s|\u00A0)+$/g, + + // Match a standalone tag + rsingleTag = /^<(\w+)\s*\/?>(?:<\/\1>)?$/, + + // Keep a UserAgent string for use with jQuery.browser + userAgent = navigator.userAgent, + + // For matching the engine and version of the browser + browserMatch, + + // Has the ready events already been bound? + readyBound = false, + + // The functions to execute on DOM ready + readyList = [], + + // The ready event handler + DOMContentLoaded, + + // Save a reference to some core methods + toString = Object.prototype.toString, + hasOwnProperty = Object.prototype.hasOwnProperty, + push = Array.prototype.push, + slice = Array.prototype.slice, + indexOf = Array.prototype.indexOf; + +jQuery.fn = jQuery.prototype = { + init: function( selector, context ) { + var match, elem, ret, doc; + + // Handle $(""), $(null), or $(undefined) + if ( !selector ) { + return this; + } + + // Handle $(DOMElement) + if ( selector.nodeType ) { + this.context = this[0] = selector; + this.length = 1; + return this; + } + + // The body element only exists once, optimize finding it + if ( selector === "body" && !context ) { + this.context = document; + this[0] = document.body; + this.selector = "body"; + this.length = 1; + return this; + } + + // Handle HTML strings + if ( typeof selector === "string" ) { + // Are we dealing with HTML string or an ID? + match = quickExpr.exec( selector ); + + // Verify a match, and that no context was specified for #id + if ( match && (match[1] || !context) ) { + + // HANDLE: $(html) -> $(array) + if ( match[1] ) { + doc = (context ? context.ownerDocument || context : document); + + // If a single string is passed in and it's a single tag + // just do a createElement and skip the rest + ret = rsingleTag.exec( selector ); + + if ( ret ) { + if ( jQuery.isPlainObject( context ) ) { + selector = [ document.createElement( ret[1] ) ]; + jQuery.fn.attr.call( selector, context, true ); + + } else { + selector = [ doc.createElement( ret[1] ) ]; + } + + } else { + ret = buildFragment( [ match[1] ], [ doc ] ); + selector = (ret.cacheable ? ret.fragment.cloneNode(true) : ret.fragment).childNodes; + } + + return jQuery.merge( this, selector ); + + // HANDLE: $("#id") + } else { + elem = document.getElementById( match[2] ); + + if ( elem ) { + // Handle the case where IE and Opera return items + // by name instead of ID + if ( elem.id !== match[2] ) { + return rootjQuery.find( selector ); + } + + // Otherwise, we inject the element directly into the jQuery object + this.length = 1; + this[0] = elem; + } + + this.context = document; + this.selector = selector; + return this; + } + + // HANDLE: $("TAG") + } else if ( !context && /^\w+$/.test( selector ) ) { + this.selector = selector; + this.context = document; + selector = document.getElementsByTagName( selector ); + return jQuery.merge( this, selector ); + + // HANDLE: $(expr, $(...)) + } else if ( !context || context.jquery ) { + return (context || rootjQuery).find( selector ); + + // HANDLE: $(expr, context) + // (which is just equivalent to: $(context).find(expr) + } else { + return jQuery( context ).find( selector ); + } + + // HANDLE: $(function) + // Shortcut for document ready + } else if ( jQuery.isFunction( selector ) ) { + return rootjQuery.ready( selector ); + } + + if (selector.selector !== undefined) { + this.selector = selector.selector; + this.context = selector.context; + } + + return jQuery.makeArray( selector, this ); + }, + + // Start with an empty selector + selector: "", + + // The current version of jQuery being used + jquery: "1.4.2", + + // The default length of a jQuery object is 0 + length: 0, + + // The number of elements contained in the matched element set + size: function() { + return this.length; + }, + + toArray: function() { + return slice.call( this, 0 ); + }, + + // Get the Nth element in the matched element set OR + // Get the whole matched element set as a clean array + get: function( num ) { + return num == null ? + + // Return a 'clean' array + this.toArray() : + + // Return just the object + ( num < 0 ? this.slice(num)[ 0 ] : this[ num ] ); + }, + + // Take an array of elements and push it onto the stack + // (returning the new matched element set) + pushStack: function( elems, name, selector ) { + // Build a new jQuery matched element set + var ret = jQuery(); + + if ( jQuery.isArray( elems ) ) { + push.apply( ret, elems ); + + } else { + jQuery.merge( ret, elems ); + } + + // Add the old object onto the stack (as a reference) + ret.prevObject = this; + + ret.context = this.context; + + if ( name === "find" ) { + ret.selector = this.selector + (this.selector ? " " : "") + selector; + } else if ( name ) { + ret.selector = this.selector + "." + name + "(" + selector + ")"; + } + + // Return the newly-formed element set + return ret; + }, + + // Execute a callback for every element in the matched set. + // (You can seed the arguments with an array of args, but this is + // only used internally.) + each: function( callback, args ) { + return jQuery.each( this, callback, args ); + }, + + ready: function( fn ) { + // Attach the listeners + jQuery.bindReady(); + + // If the DOM is already ready + if ( jQuery.isReady ) { + // Execute the function immediately + fn.call( document, jQuery ); + + // Otherwise, remember the function for later + } else if ( readyList ) { + // Add the function to the wait list + readyList.push( fn ); + } + + return this; + }, + + eq: function( i ) { + return i === -1 ? + this.slice( i ) : + this.slice( i, +i + 1 ); + }, + + first: function() { + return this.eq( 0 ); + }, + + last: function() { + return this.eq( -1 ); + }, + + slice: function() { + return this.pushStack( slice.apply( this, arguments ), + "slice", slice.call(arguments).join(",") ); + }, + + map: function( callback ) { + return this.pushStack( jQuery.map(this, function( elem, i ) { + return callback.call( elem, i, elem ); + })); + }, + + end: function() { + return this.prevObject || jQuery(null); + }, + + // For internal use only. + // Behaves like an Array's method, not like a jQuery method. + push: push, + sort: [].sort, + splice: [].splice +}; + +// Give the init function the jQuery prototype for later instantiation +jQuery.fn.init.prototype = jQuery.fn; + +jQuery.extend = jQuery.fn.extend = function() { + // copy reference to target object + var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options, name, src, copy; + + // Handle a deep copy situation + if ( typeof target === "boolean" ) { + deep = target; + target = arguments[1] || {}; + // skip the boolean and the target + i = 2; + } + + // Handle case when target is a string or something (possible in deep copy) + if ( typeof target !== "object" && !jQuery.isFunction(target) ) { + target = {}; + } + + // extend jQuery itself if only one argument is passed + if ( length === i ) { + target = this; + --i; + } + + for ( ; i < length; i++ ) { + // Only deal with non-null/undefined values + if ( (options = arguments[ i ]) != null ) { + // Extend the base object + for ( name in options ) { + src = target[ name ]; + copy = options[ name ]; + + // Prevent never-ending loop + if ( target === copy ) { + continue; + } + + // Recurse if we're merging object literal values or arrays + if ( deep && copy && ( jQuery.isPlainObject(copy) || jQuery.isArray(copy) ) ) { + var clone = src && ( jQuery.isPlainObject(src) || jQuery.isArray(src) ) ? src + : jQuery.isArray(copy) ? [] : {}; + + // Never move original objects, clone them + target[ name ] = jQuery.extend( deep, clone, copy ); + + // Don't bring in undefined values + } else if ( copy !== undefined ) { + target[ name ] = copy; + } + } + } + } + + // Return the modified object + return target; +}; + +jQuery.extend({ + noConflict: function( deep ) { + window.$ = _$; + + if ( deep ) { + window.jQuery = _jQuery; + } + + return jQuery; + }, + + // Is the DOM ready to be used? Set to true once it occurs. + isReady: false, + + // Handle when the DOM is ready + ready: function() { + // Make sure that the DOM is not already loaded + if ( !jQuery.isReady ) { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( !document.body ) { + return setTimeout( jQuery.ready, 13 ); + } + + // Remember that the DOM is ready + jQuery.isReady = true; + + // If there are functions bound, to execute + if ( readyList ) { + // Execute all of them + var fn, i = 0; + while ( (fn = readyList[ i++ ]) ) { + fn.call( document, jQuery ); + } + + // Reset the list of functions + readyList = null; + } + + // Trigger any bound ready events + if ( jQuery.fn.triggerHandler ) { + jQuery( document ).triggerHandler( "ready" ); + } + } + }, + + bindReady: function() { + if ( readyBound ) { + return; + } + + readyBound = true; + + // Catch cases where $(document).ready() is called after the + // browser event has already occurred. + if ( document.readyState === "complete" ) { + return jQuery.ready(); + } + + // Mozilla, Opera and webkit nightlies currently support this event + if ( document.addEventListener ) { + // Use the handy event callback + document.addEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + + // A fallback to window.onload, that will always work + window.addEventListener( "load", jQuery.ready, false ); + + // If IE event model is used + } else if ( document.attachEvent ) { + // ensure firing before onload, + // maybe late but safe also for iframes + document.attachEvent("onreadystatechange", DOMContentLoaded); + + // A fallback to window.onload, that will always work + window.attachEvent( "onload", jQuery.ready ); + + // If IE and not a frame + // continually check to see if the document is ready + var toplevel = false; + + try { + toplevel = window.frameElement == null; + } catch(e) {} + + if ( document.documentElement.doScroll && toplevel ) { + doScrollCheck(); + } + } + }, + + // See test/unit/core.js for details concerning isFunction. + // Since version 1.3, DOM methods and functions like alert + // aren't supported. They return false on IE (#2968). + isFunction: function( obj ) { + return toString.call(obj) === "[object Function]"; + }, + + isArray: function( obj ) { + return toString.call(obj) === "[object Array]"; + }, + + isPlainObject: function( obj ) { + // Must be an Object. + // Because of IE, we also have to check the presence of the constructor property. + // Make sure that DOM nodes and window objects don't pass through, as well + if ( !obj || toString.call(obj) !== "[object Object]" || obj.nodeType || obj.setInterval ) { + return false; + } + + // Not own constructor property must be Object + if ( obj.constructor + && !hasOwnProperty.call(obj, "constructor") + && !hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf") ) { + return false; + } + + // Own properties are enumerated firstly, so to speed up, + // if last one is own, then all properties are own. + + var key; + for ( key in obj ) {} + + return key === undefined || hasOwnProperty.call( obj, key ); + }, + + isEmptyObject: function( obj ) { + for ( var name in obj ) { + return false; + } + return true; + }, + + error: function( msg ) { + throw msg; + }, + + parseJSON: function( data ) { + if ( typeof data !== "string" || !data ) { + return null; + } + + // Make sure leading/trailing whitespace is removed (IE can't handle it) + data = jQuery.trim( data ); + + // Make sure the incoming data is actual JSON + // Logic borrowed from http://json.org/json2.js + if ( /^[\],:{}\s]*$/.test(data.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, "@") + .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, "]") + .replace(/(?:^|:|,)(?:\s*\[)+/g, "")) ) { + + // Try to use the native JSON parser first + return window.JSON && window.JSON.parse ? + window.JSON.parse( data ) : + (new Function("return " + data))(); + + } else { + jQuery.error( "Invalid JSON: " + data ); + } + }, + + noop: function() {}, + + // Evalulates a script in a global context + globalEval: function( data ) { + if ( data && rnotwhite.test(data) ) { + // Inspired by code by Andrea Giammarchi + // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html + var head = document.getElementsByTagName("head")[0] || document.documentElement, + script = document.createElement("script"); + + script.type = "text/javascript"; + + if ( jQuery.support.scriptEval ) { + script.appendChild( document.createTextNode( data ) ); + } else { + script.text = data; + } + + // Use insertBefore instead of appendChild to circumvent an IE6 bug. + // This arises when a base node is used (#2709). + head.insertBefore( script, head.firstChild ); + head.removeChild( script ); + } + }, + + nodeName: function( elem, name ) { + return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase(); + }, + + // args is for internal usage only + each: function( object, callback, args ) { + var name, i = 0, + length = object.length, + isObj = length === undefined || jQuery.isFunction(object); + + if ( args ) { + if ( isObj ) { + for ( name in object ) { + if ( callback.apply( object[ name ], args ) === false ) { + break; + } + } + } else { + for ( ; i < length; ) { + if ( callback.apply( object[ i++ ], args ) === false ) { + break; + } + } + } + + // A special, fast, case for the most common use of each + } else { + if ( isObj ) { + for ( name in object ) { + if ( callback.call( object[ name ], name, object[ name ] ) === false ) { + break; + } + } + } else { + for ( var value = object[0]; + i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {} + } + } + + return object; + }, + + trim: function( text ) { + return (text || "").replace( rtrim, "" ); + }, + + // results is for internal usage only + makeArray: function( array, results ) { + var ret = results || []; + + if ( array != null ) { + // The window, strings (and functions) also have 'length' + // The extra typeof function check is to prevent crashes + // in Safari 2 (See: #3039) + if ( array.length == null || typeof array === "string" || jQuery.isFunction(array) || (typeof array !== "function" && array.setInterval) ) { + push.call( ret, array ); + } else { + jQuery.merge( ret, array ); + } + } + + return ret; + }, + + inArray: function( elem, array ) { + if ( array.indexOf ) { + return array.indexOf( elem ); + } + + for ( var i = 0, length = array.length; i < length; i++ ) { + if ( array[ i ] === elem ) { + return i; + } + } + + return -1; + }, + + merge: function( first, second ) { + var i = first.length, j = 0; + + if ( typeof second.length === "number" ) { + for ( var l = second.length; j < l; j++ ) { + first[ i++ ] = second[ j ]; + } + + } else { + while ( second[j] !== undefined ) { + first[ i++ ] = second[ j++ ]; + } + } + + first.length = i; + + return first; + }, + + grep: function( elems, callback, inv ) { + var ret = []; + + // Go through the array, only saving the items + // that pass the validator function + for ( var i = 0, length = elems.length; i < length; i++ ) { + if ( !inv !== !callback( elems[ i ], i ) ) { + ret.push( elems[ i ] ); + } + } + + return ret; + }, + + // arg is for internal usage only + map: function( elems, callback, arg ) { + var ret = [], value; + + // Go through the array, translating each of the items to their + // new value (or values). + for ( var i = 0, length = elems.length; i < length; i++ ) { + value = callback( elems[ i ], i, arg ); + + if ( value != null ) { + ret[ ret.length ] = value; + } + } + + return ret.concat.apply( [], ret ); + }, + + // A global GUID counter for objects + guid: 1, + + proxy: function( fn, proxy, thisObject ) { + if ( arguments.length === 2 ) { + if ( typeof proxy === "string" ) { + thisObject = fn; + fn = thisObject[ proxy ]; + proxy = undefined; + + } else if ( proxy && !jQuery.isFunction( proxy ) ) { + thisObject = proxy; + proxy = undefined; + } + } + + if ( !proxy && fn ) { + proxy = function() { + return fn.apply( thisObject || this, arguments ); + }; + } + + // Set the guid of unique handler to the same of original handler, so it can be removed + if ( fn ) { + proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++; + } + + // So proxy can be declared as an argument + return proxy; + }, + + // Use of jQuery.browser is frowned upon. + // More details: http://docs.jquery.com/Utilities/jQuery.browser + uaMatch: function( ua ) { + ua = ua.toLowerCase(); + + var match = /(webkit)[ \/]([\w.]+)/.exec( ua ) || + /(opera)(?:.*version)?[ \/]([\w.]+)/.exec( ua ) || + /(msie) ([\w.]+)/.exec( ua ) || + !/compatible/.test( ua ) && /(mozilla)(?:.*? rv:([\w.]+))?/.exec( ua ) || + []; + + return { browser: match[1] || "", version: match[2] || "0" }; + }, + + browser: {} +}); + +browserMatch = jQuery.uaMatch( userAgent ); +if ( browserMatch.browser ) { + jQuery.browser[ browserMatch.browser ] = true; + jQuery.browser.version = browserMatch.version; +} + +// Deprecated, use jQuery.browser.webkit instead +if ( jQuery.browser.webkit ) { + jQuery.browser.safari = true; +} + +if ( indexOf ) { + jQuery.inArray = function( elem, array ) { + return indexOf.call( array, elem ); + }; +} + +// All jQuery objects should point back to these +rootjQuery = jQuery(document); + +// Cleanup functions for the document ready method +if ( document.addEventListener ) { + DOMContentLoaded = function() { + document.removeEventListener( "DOMContentLoaded", DOMContentLoaded, false ); + jQuery.ready(); + }; + +} else if ( document.attachEvent ) { + DOMContentLoaded = function() { + // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443). + if ( document.readyState === "complete" ) { + document.detachEvent( "onreadystatechange", DOMContentLoaded ); + jQuery.ready(); + } + }; +} + +// The DOM ready check for Internet Explorer +function doScrollCheck() { + if ( jQuery.isReady ) { + return; + } + + try { + // If IE is used, use the trick by Diego Perini + // http://javascript.nwbox.com/IEContentLoaded/ + document.documentElement.doScroll("left"); + } catch( error ) { + setTimeout( doScrollCheck, 1 ); + return; + } + + // and execute any waiting functions + jQuery.ready(); +} + +function evalScript( i, elem ) { + if ( elem.src ) { + jQuery.ajax({ + url: elem.src, + async: false, + dataType: "script" + }); + } else { + jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || "" ); + } + + if ( elem.parentNode ) { + elem.parentNode.removeChild( elem ); + } +} + +// Mutifunctional method to get and set values to a collection +// The value/s can be optionally by executed if its a function +function access( elems, key, value, exec, fn, pass ) { + var length = elems.length; + + // Setting many attributes + if ( typeof key === "object" ) { + for ( var k in key ) { + access( elems, k, key[k], exec, fn, value ); + } + return elems; + } + + // Setting one attribute + if ( value !== undefined ) { + // Optionally, function values get executed if exec is true + exec = !pass && exec && jQuery.isFunction(value); + + for ( var i = 0; i < length; i++ ) { + fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass ); + } + + return elems; + } + + // Getting an attribute + return length ? fn( elems[0], key ) : undefined; +} + +function now() { + return (new Date).getTime(); +} +(function() { + + jQuery.support = {}; + + var root = document.documentElement, + script = document.createElement("script"), + div = document.createElement("div"), + id = "script" + now(); + + div.style.display = "none"; + div.innerHTML = "
a"; + + var all = div.getElementsByTagName("*"), + a = div.getElementsByTagName("a")[0]; + + // Can't get basic test support + if ( !all || !all.length || !a ) { + return; + } + + jQuery.support = { + // IE strips leading whitespace when .innerHTML is used + leadingWhitespace: div.firstChild.nodeType === 3, + + // Make sure that tbody elements aren't automatically inserted + // IE will insert them into empty tables + tbody: !div.getElementsByTagName("tbody").length, + + // Make sure that link elements get serialized correctly by innerHTML + // This requires a wrapper element in IE + htmlSerialize: !!div.getElementsByTagName("link").length, + + // Get the style information from getAttribute + // (IE uses .cssText insted) + style: /red/.test( a.getAttribute("style") ), + + // Make sure that URLs aren't manipulated + // (IE normalizes it by default) + hrefNormalized: a.getAttribute("href") === "/a", + + // Make sure that element opacity exists + // (IE uses filter instead) + // Use a regex to work around a WebKit issue. See #5145 + opacity: /^0.55$/.test( a.style.opacity ), + + // Verify style float existence + // (IE uses styleFloat instead of cssFloat) + cssFloat: !!a.style.cssFloat, + + // Make sure that if no value is specified for a checkbox + // that it defaults to "on". + // (WebKit defaults to "" instead) + checkOn: div.getElementsByTagName("input")[0].value === "on", + + // Make sure that a selected-by-default option has a working selected property. + // (WebKit defaults to false instead of true, IE too, if it's in an optgroup) + optSelected: document.createElement("select").appendChild( document.createElement("option") ).selected, + + parentNode: div.removeChild( div.appendChild( document.createElement("div") ) ).parentNode === null, + + // Will be defined later + deleteExpando: true, + checkClone: false, + scriptEval: false, + noCloneEvent: true, + boxModel: null + }; + + script.type = "text/javascript"; + try { + script.appendChild( document.createTextNode( "window." + id + "=1;" ) ); + } catch(e) {} + + root.insertBefore( script, root.firstChild ); + + // Make sure that the execution of code works by injecting a script + // tag with appendChild/createTextNode + // (IE doesn't support this, fails, and uses .text instead) + if ( window[ id ] ) { + jQuery.support.scriptEval = true; + delete window[ id ]; + } + + // Test to see if it's possible to delete an expando from an element + // Fails in Internet Explorer + try { + delete script.test; + + } catch(e) { + jQuery.support.deleteExpando = false; + } + + root.removeChild( script ); + + if ( div.attachEvent && div.fireEvent ) { + div.attachEvent("onclick", function click() { + // Cloning a node shouldn't copy over any + // bound event handlers (IE does this) + jQuery.support.noCloneEvent = false; + div.detachEvent("onclick", click); + }); + div.cloneNode(true).fireEvent("onclick"); + } + + div = document.createElement("div"); + div.innerHTML = ""; + + var fragment = document.createDocumentFragment(); + fragment.appendChild( div.firstChild ); + + // WebKit doesn't clone checked state correctly in fragments + jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked; + + // Figure out if the W3C box model works as expected + // document.body must exist before we can do this + jQuery(function() { + var div = document.createElement("div"); + div.style.width = div.style.paddingLeft = "1px"; + + document.body.appendChild( div ); + jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2; + document.body.removeChild( div ).style.display = 'none'; + + div = null; + }); + + // Technique from Juriy Zaytsev + // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/ + var eventSupported = function( eventName ) { + var el = document.createElement("div"); + eventName = "on" + eventName; + + var isSupported = (eventName in el); + if ( !isSupported ) { + el.setAttribute(eventName, "return;"); + isSupported = typeof el[eventName] === "function"; + } + el = null; + + return isSupported; + }; + + jQuery.support.submitBubbles = eventSupported("submit"); + jQuery.support.changeBubbles = eventSupported("change"); + + // release memory in IE + root = script = div = all = a = null; +})(); + +jQuery.props = { + "for": "htmlFor", + "class": "className", + readonly: "readOnly", + maxlength: "maxLength", + cellspacing: "cellSpacing", + rowspan: "rowSpan", + colspan: "colSpan", + tabindex: "tabIndex", + usemap: "useMap", + frameborder: "frameBorder" +}; +var expando = "jQuery" + now(), uuid = 0, windowData = {}; + +jQuery.extend({ + cache: {}, + + expando:expando, + + // The following elements throw uncatchable exceptions if you + // attempt to add expando properties to them. + noData: { + "embed": true, + "object": true, + "applet": true + }, + + data: function( elem, name, data ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache; + + if ( !id && typeof name === "string" && data === undefined ) { + return null; + } + + // Compute a unique ID for the element + if ( !id ) { + id = ++uuid; + } + + // Avoid generating a new cache unless none exists and we + // want to manipulate it. + if ( typeof name === "object" ) { + elem[ expando ] = id; + thisCache = cache[ id ] = jQuery.extend(true, {}, name); + + } else if ( !cache[ id ] ) { + elem[ expando ] = id; + cache[ id ] = {}; + } + + thisCache = cache[ id ]; + + // Prevent overriding the named cache with undefined values + if ( data !== undefined ) { + thisCache[ name ] = data; + } + + return typeof name === "string" ? thisCache[ name ] : thisCache; + }, + + removeData: function( elem, name ) { + if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) { + return; + } + + elem = elem == window ? + windowData : + elem; + + var id = elem[ expando ], cache = jQuery.cache, thisCache = cache[ id ]; + + // If we want to remove a specific section of the element's data + if ( name ) { + if ( thisCache ) { + // Remove the section of cache data + delete thisCache[ name ]; + + // If we've removed all the data, remove the element's cache + if ( jQuery.isEmptyObject(thisCache) ) { + jQuery.removeData( elem ); + } + } + + // Otherwise, we want to remove all of the element's data + } else { + if ( jQuery.support.deleteExpando ) { + delete elem[ jQuery.expando ]; + + } else if ( elem.removeAttribute ) { + elem.removeAttribute( jQuery.expando ); + } + + // Completely remove the data cache + delete cache[ id ]; + } + } +}); + +jQuery.fn.extend({ + data: function( key, value ) { + if ( typeof key === "undefined" && this.length ) { + return jQuery.data( this[0] ); + + } else if ( typeof key === "object" ) { + return this.each(function() { + jQuery.data( this, key ); + }); + } + + var parts = key.split("."); + parts[1] = parts[1] ? "." + parts[1] : ""; + + if ( value === undefined ) { + var data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]); + + if ( data === undefined && this.length ) { + data = jQuery.data( this[0], key ); + } + return data === undefined && parts[1] ? + this.data( parts[0] ) : + data; + } else { + return this.trigger("setData" + parts[1] + "!", [parts[0], value]).each(function() { + jQuery.data( this, key, value ); + }); + } + }, + + removeData: function( key ) { + return this.each(function() { + jQuery.removeData( this, key ); + }); + } +}); +jQuery.extend({ + queue: function( elem, type, data ) { + if ( !elem ) { + return; + } + + type = (type || "fx") + "queue"; + var q = jQuery.data( elem, type ); + + // Speed up dequeue by getting out quickly if this is just a lookup + if ( !data ) { + return q || []; + } + + if ( !q || jQuery.isArray(data) ) { + q = jQuery.data( elem, type, jQuery.makeArray(data) ); + + } else { + q.push( data ); + } + + return q; + }, + + dequeue: function( elem, type ) { + type = type || "fx"; + + var queue = jQuery.queue( elem, type ), fn = queue.shift(); + + // If the fx queue is dequeued, always remove the progress sentinel + if ( fn === "inprogress" ) { + fn = queue.shift(); + } + + if ( fn ) { + // Add a progress sentinel to prevent the fx queue from being + // automatically dequeued + if ( type === "fx" ) { + queue.unshift("inprogress"); + } + + fn.call(elem, function() { + jQuery.dequeue(elem, type); + }); + } + } +}); + +jQuery.fn.extend({ + queue: function( type, data ) { + if ( typeof type !== "string" ) { + data = type; + type = "fx"; + } + + if ( data === undefined ) { + return jQuery.queue( this[0], type ); + } + return this.each(function( i, elem ) { + var queue = jQuery.queue( this, type, data ); + + if ( type === "fx" && queue[0] !== "inprogress" ) { + jQuery.dequeue( this, type ); + } + }); + }, + dequeue: function( type ) { + return this.each(function() { + jQuery.dequeue( this, type ); + }); + }, + + // Based off of the plugin by Clint Helfers, with permission. + // http://blindsignals.com/index.php/2009/07/jquery-delay/ + delay: function( time, type ) { + time = jQuery.fx ? jQuery.fx.speeds[time] || time : time; + type = type || "fx"; + + return this.queue( type, function() { + var elem = this; + setTimeout(function() { + jQuery.dequeue( elem, type ); + }, time ); + }); + }, + + clearQueue: function( type ) { + return this.queue( type || "fx", [] ); + } +}); +var rclass = /[\n\t]/g, + rspace = /\s+/, + rreturn = /\r/g, + rspecialurl = /href|src|style/, + rtype = /(button|input)/i, + rfocusable = /(button|input|object|select|textarea)/i, + rclickable = /^(a|area)$/i, + rradiocheck = /radio|checkbox/; + +jQuery.fn.extend({ + attr: function( name, value ) { + return access( this, name, value, true, jQuery.attr ); + }, + + removeAttr: function( name, fn ) { + return this.each(function(){ + jQuery.attr( this, name, "" ); + if ( this.nodeType === 1 ) { + this.removeAttribute( name ); + } + }); + }, + + addClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.addClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( value && typeof value === "string" ) { + var classNames = (value || "").split( rspace ); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 ) { + if ( !elem.className ) { + elem.className = value; + + } else { + var className = " " + elem.className + " ", setClass = elem.className; + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + if ( className.indexOf( " " + classNames[c] + " " ) < 0 ) { + setClass += " " + classNames[c]; + } + } + elem.className = jQuery.trim( setClass ); + } + } + } + } + + return this; + }, + + removeClass: function( value ) { + if ( jQuery.isFunction(value) ) { + return this.each(function(i) { + var self = jQuery(this); + self.removeClass( value.call(this, i, self.attr("class")) ); + }); + } + + if ( (value && typeof value === "string") || value === undefined ) { + var classNames = (value || "").split(rspace); + + for ( var i = 0, l = this.length; i < l; i++ ) { + var elem = this[i]; + + if ( elem.nodeType === 1 && elem.className ) { + if ( value ) { + var className = (" " + elem.className + " ").replace(rclass, " "); + for ( var c = 0, cl = classNames.length; c < cl; c++ ) { + className = className.replace(" " + classNames[c] + " ", " "); + } + elem.className = jQuery.trim( className ); + + } else { + elem.className = ""; + } + } + } + } + + return this; + }, + + toggleClass: function( value, stateVal ) { + var type = typeof value, isBool = typeof stateVal === "boolean"; + + if ( jQuery.isFunction( value ) ) { + return this.each(function(i) { + var self = jQuery(this); + self.toggleClass( value.call(this, i, self.attr("class"), stateVal), stateVal ); + }); + } + + return this.each(function() { + if ( type === "string" ) { + // toggle individual class names + var className, i = 0, self = jQuery(this), + state = stateVal, + classNames = value.split( rspace ); + + while ( (className = classNames[ i++ ]) ) { + // check each className given, space seperated list + state = isBool ? state : !self.hasClass( className ); + self[ state ? "addClass" : "removeClass" ]( className ); + } + + } else if ( type === "undefined" || type === "boolean" ) { + if ( this.className ) { + // store className if set + jQuery.data( this, "__className__", this.className ); + } + + // toggle whole className + this.className = this.className || value === false ? "" : jQuery.data( this, "__className__" ) || ""; + } + }); + }, + + hasClass: function( selector ) { + var className = " " + selector + " "; + for ( var i = 0, l = this.length; i < l; i++ ) { + if ( (" " + this[i].className + " ").replace(rclass, " ").indexOf( className ) > -1 ) { + return true; + } + } + + return false; + }, + + val: function( value ) { + if ( value === undefined ) { + var elem = this[0]; + + if ( elem ) { + if ( jQuery.nodeName( elem, "option" ) ) { + return (elem.attributes.value || {}).specified ? elem.value : elem.text; + } + + // We need to handle select boxes special + if ( jQuery.nodeName( elem, "select" ) ) { + var index = elem.selectedIndex, + values = [], + options = elem.options, + one = elem.type === "select-one"; + + // Nothing was selected + if ( index < 0 ) { + return null; + } + + // Loop through all the selected options + for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) { + var option = options[ i ]; + + if ( option.selected ) { + // Get the specifc value for the option + value = jQuery(option).val(); + + // We don't need an array for one selects + if ( one ) { + return value; + } + + // Multi-Selects return an array + values.push( value ); + } + } + + return values; + } + + // Handle the case where in Webkit "" is returned instead of "on" if a value isn't specified + if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) { + return elem.getAttribute("value") === null ? "on" : elem.value; + } + + + // Everything else, we just grab the value + return (elem.value || "").replace(rreturn, ""); + + } + + return undefined; + } + + var isFunction = jQuery.isFunction(value); + + return this.each(function(i) { + var self = jQuery(this), val = value; + + if ( this.nodeType !== 1 ) { + return; + } + + if ( isFunction ) { + val = value.call(this, i, self.val()); + } + + // Typecast each time if the value is a Function and the appended + // value is therefore different each time. + if ( typeof val === "number" ) { + val += ""; + } + + if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) { + this.checked = jQuery.inArray( self.val(), val ) >= 0; + + } else if ( jQuery.nodeName( this, "select" ) ) { + var values = jQuery.makeArray(val); + + jQuery( "option", this ).each(function() { + this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0; + }); + + if ( !values.length ) { + this.selectedIndex = -1; + } + + } else { + this.value = val; + } + }); + } +}); + +jQuery.extend({ + attrFn: { + val: true, + css: true, + html: true, + text: true, + data: true, + width: true, + height: true, + offset: true + }, + + attr: function( elem, name, value, pass ) { + // don't set attributes on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + if ( pass && name in jQuery.attrFn ) { + return jQuery(elem)[name](value); + } + + var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ), + // Whether we are setting (or getting) + set = value !== undefined; + + // Try to normalize/fix the name + name = notxml && jQuery.props[ name ] || name; + + // Only do all the following if this is a node (faster for style) + if ( elem.nodeType === 1 ) { + // These attributes require special treatment + var special = rspecialurl.test( name ); + + // Safari mis-reports the default selected property of an option + // Accessing the parent's selectedIndex property fixes it + if ( name === "selected" && !jQuery.support.optSelected ) { + var parent = elem.parentNode; + if ( parent ) { + parent.selectedIndex; + + // Make sure that it also works with optgroups, see #5701 + if ( parent.parentNode ) { + parent.parentNode.selectedIndex; + } + } + } + + // If applicable, access the attribute via the DOM 0 way + if ( name in elem && notxml && !special ) { + if ( set ) { + // We can't allow the type property to be changed (since it causes problems in IE) + if ( name === "type" && rtype.test( elem.nodeName ) && elem.parentNode ) { + jQuery.error( "type property can't be changed" ); + } + + elem[ name ] = value; + } + + // browsers index elements by id/name on forms, give priority to attributes. + if ( jQuery.nodeName( elem, "form" ) && elem.getAttributeNode(name) ) { + return elem.getAttributeNode( name ).nodeValue; + } + + // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set + // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/ + if ( name === "tabIndex" ) { + var attributeNode = elem.getAttributeNode( "tabIndex" ); + + return attributeNode && attributeNode.specified ? + attributeNode.value : + rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ? + 0 : + undefined; + } + + return elem[ name ]; + } + + if ( !jQuery.support.style && notxml && name === "style" ) { + if ( set ) { + elem.style.cssText = "" + value; + } + + return elem.style.cssText; + } + + if ( set ) { + // convert the value to a string (all browsers do this but IE) see #1070 + elem.setAttribute( name, "" + value ); + } + + var attr = !jQuery.support.hrefNormalized && notxml && special ? + // Some attributes require a special call on IE + elem.getAttribute( name, 2 ) : + elem.getAttribute( name ); + + // Non-existent attributes return null, we normalize to undefined + return attr === null ? undefined : attr; + } + + // elem is actually elem.style ... set the style + // Using attr for specific style information is now deprecated. Use style instead. + return jQuery.style( elem, name, value ); + } +}); +var rnamespaces = /\.(.*)$/, + fcleanup = function( nm ) { + return nm.replace(/[^\w\s\.\|`]/g, function( ch ) { + return "\\" + ch; + }); + }; + +/* + * A number of helper functions used for managing events. + * Many of the ideas behind this code originated from + * Dean Edwards' addEvent library. + */ +jQuery.event = { + + // Bind an event to an element + // Original by Dean Edwards + add: function( elem, types, handler, data ) { + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + // For whatever reason, IE has trouble passing the window object + // around, causing it to be cloned in the process + if ( elem.setInterval && ( elem !== window && !elem.frameElement ) ) { + elem = window; + } + + var handleObjIn, handleObj; + + if ( handler.handler ) { + handleObjIn = handler; + handler = handleObjIn.handler; + } + + // Make sure that the function being executed has a unique ID + if ( !handler.guid ) { + handler.guid = jQuery.guid++; + } + + // Init the element's event structure + var elemData = jQuery.data( elem ); + + // If no elemData is found then we must be trying to bind to one of the + // banned noData elements + if ( !elemData ) { + return; + } + + var events = elemData.events = elemData.events || {}, + eventHandle = elemData.handle, eventHandle; + + if ( !eventHandle ) { + elemData.handle = eventHandle = function() { + // Handle the second event of a trigger and when + // an event is called after a page has unloaded + return typeof jQuery !== "undefined" && !jQuery.event.triggered ? + jQuery.event.handle.apply( eventHandle.elem, arguments ) : + undefined; + }; + } + + // Add elem as a property of the handle function + // This is to prevent a memory leak with non-native events in IE. + eventHandle.elem = elem; + + // Handle multiple events separated by a space + // jQuery(...).bind("mouseover mouseout", fn); + types = types.split(" "); + + var type, i = 0, namespaces; + + while ( (type = types[ i++ ]) ) { + handleObj = handleObjIn ? + jQuery.extend({}, handleObjIn) : + { handler: handler, data: data }; + + // Namespaced event handlers + if ( type.indexOf(".") > -1 ) { + namespaces = type.split("."); + type = namespaces.shift(); + handleObj.namespace = namespaces.slice(0).sort().join("."); + + } else { + namespaces = []; + handleObj.namespace = ""; + } + + handleObj.type = type; + handleObj.guid = handler.guid; + + // Get the current list of functions bound to this event + var handlers = events[ type ], + special = jQuery.event.special[ type ] || {}; + + // Init the event handler queue + if ( !handlers ) { + handlers = events[ type ] = []; + + // Check for a special event handler + // Only use addEventListener/attachEvent if the special + // events handler returns false + if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) { + // Bind the global event handler to the element + if ( elem.addEventListener ) { + elem.addEventListener( type, eventHandle, false ); + + } else if ( elem.attachEvent ) { + elem.attachEvent( "on" + type, eventHandle ); + } + } + } + + if ( special.add ) { + special.add.call( elem, handleObj ); + + if ( !handleObj.handler.guid ) { + handleObj.handler.guid = handler.guid; + } + } + + // Add the function to the element's handler list + handlers.push( handleObj ); + + // Keep track of which events have been used, for global triggering + jQuery.event.global[ type ] = true; + } + + // Nullify elem to prevent memory leaks in IE + elem = null; + }, + + global: {}, + + // Detach an event or set of events from an element + remove: function( elem, types, handler, pos ) { + // don't do events on text and comment nodes + if ( elem.nodeType === 3 || elem.nodeType === 8 ) { + return; + } + + var ret, type, fn, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType, + elemData = jQuery.data( elem ), + events = elemData && elemData.events; + + if ( !elemData || !events ) { + return; + } + + // types is actually an event object here + if ( types && types.type ) { + handler = types.handler; + types = types.type; + } + + // Unbind all events for the element + if ( !types || typeof types === "string" && types.charAt(0) === "." ) { + types = types || ""; + + for ( type in events ) { + jQuery.event.remove( elem, type + types ); + } + + return; + } + + // Handle multiple events separated by a space + // jQuery(...).unbind("mouseover mouseout", fn); + types = types.split(" "); + + while ( (type = types[ i++ ]) ) { + origType = type; + handleObj = null; + all = type.indexOf(".") < 0; + namespaces = []; + + if ( !all ) { + // Namespaced event handlers + namespaces = type.split("."); + type = namespaces.shift(); + + namespace = new RegExp("(^|\\.)" + + jQuery.map( namespaces.slice(0).sort(), fcleanup ).join("\\.(?:.*\\.)?") + "(\\.|$)") + } + + eventType = events[ type ]; + + if ( !eventType ) { + continue; + } + + if ( !handler ) { + for ( var j = 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( all || namespace.test( handleObj.namespace ) ) { + jQuery.event.remove( elem, origType, handleObj.handler, j ); + eventType.splice( j--, 1 ); + } + } + + continue; + } + + special = jQuery.event.special[ type ] || {}; + + for ( var j = pos || 0; j < eventType.length; j++ ) { + handleObj = eventType[ j ]; + + if ( handler.guid === handleObj.guid ) { + // remove the given handler for the given type + if ( all || namespace.test( handleObj.namespace ) ) { + if ( pos == null ) { + eventType.splice( j--, 1 ); + } + + if ( special.remove ) { + special.remove.call( elem, handleObj ); + } + } + + if ( pos != null ) { + break; + } + } + } + + // remove generic event handler if no more handlers exist + if ( eventType.length === 0 || pos != null && eventType.length === 1 ) { + if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) { + removeEvent( elem, type, elemData.handle ); + } + + ret = null; + delete events[ type ]; + } + } + + // Remove the expando if it's no longer used + if ( jQuery.isEmptyObject( events ) ) { + var handle = elemData.handle; + if ( handle ) { + handle.elem = null; + } + + delete elemData.events; + delete elemData.handle; + + if ( jQuery.isEmptyObject( elemData ) ) { + jQuery.removeData( elem ); + } + } + }, + + // bubbling is internal + trigger: function( event, data, elem /*, bubbling */ ) { + // Event object or event type + var type = event.type || event, + bubbling = arguments[3]; + + if ( !bubbling ) { + event = typeof event === "object" ? + // jQuery.Event object + event[expando] ? event : + // Object literal + jQuery.extend( jQuery.Event(type), event ) : + // Just the event type (string) + jQuery.Event(type); + + if ( type.indexOf("!") >= 0 ) { + event.type = type = type.slice(0, -1); + event.exclusive = true; + } + + // Handle a global trigger + if ( !elem ) { + // Don't bubble custom events when global (to avoid too much overhead) + event.stopPropagation(); + + // Only trigger if we've ever bound an event for it + if ( jQuery.event.global[ type ] ) { + jQuery.each( jQuery.cache, function() { + if ( this.events && this.events[type] ) { + jQuery.event.trigger( event, data, this.handle.elem ); + } + }); + } + } + + // Handle triggering a single element + + // don't do events on text and comment nodes + if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) { + return undefined; + } + + // Clean up in case it is reused + event.result = undefined; + event.target = elem; + + // Clone the incoming data, if any + data = jQuery.makeArray( data ); + data.unshift( event ); + } + + event.currentTarget = elem; + + // Trigger the event, it is assumed that "handle" is a function + var handle = jQuery.data( elem, "handle" ); + if ( handle ) { + handle.apply( elem, data ); + } + + var parent = elem.parentNode || elem.ownerDocument; + + // Trigger an inline bound script + try { + if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) { + if ( elem[ "on" + type ] && elem[ "on" + type ].apply( elem, data ) === false ) { + event.result = false; + } + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( !event.isPropagationStopped() && parent ) { + jQuery.event.trigger( event, data, parent, true ); + + } else if ( !event.isDefaultPrevented() ) { + var target = event.target, old, + isClick = jQuery.nodeName(target, "a") && type === "click", + special = jQuery.event.special[ type ] || {}; + + if ( (!special._default || special._default.call( elem, event ) === false) && + !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) { + + try { + if ( target[ type ] ) { + // Make sure that we don't accidentally re-trigger the onFOO events + old = target[ "on" + type ]; + + if ( old ) { + target[ "on" + type ] = null; + } + + jQuery.event.triggered = true; + target[ type ](); + } + + // prevent IE from throwing an error for some elements with some event types, see #3533 + } catch (e) {} + + if ( old ) { + target[ "on" + type ] = old; + } + + jQuery.event.triggered = false; + } + } + }, + + handle: function( event ) { + var all, handlers, namespaces, namespace, events; + + event = arguments[0] = jQuery.event.fix( event || window.event ); + event.currentTarget = this; + + // Namespaced event handlers + all = event.type.indexOf(".") < 0 && !event.exclusive; + + if ( !all ) { + namespaces = event.type.split("."); + event.type = namespaces.shift(); + namespace = new RegExp("(^|\\.)" + namespaces.slice(0).sort().join("\\.(?:.*\\.)?") + "(\\.|$)"); + } + + var events = jQuery.data(this, "events"), handlers = events[ event.type ]; + + if ( events && handlers ) { + // Clone the handlers to prevent manipulation + handlers = handlers.slice(0); + + for ( var j = 0, l = handlers.length; j < l; j++ ) { + var handleObj = handlers[ j ]; + + // Filter the functions by class + if ( all || namespace.test( handleObj.namespace ) ) { + // Pass in a reference to the handler function itself + // So that we can later remove it + event.handler = handleObj.handler; + event.data = handleObj.data; + event.handleObj = handleObj; + + var ret = handleObj.handler.apply( this, arguments ); + + if ( ret !== undefined ) { + event.result = ret; + if ( ret === false ) { + event.preventDefault(); + event.stopPropagation(); + } + } + + if ( event.isImmediatePropagationStopped() ) { + break; + } + } + } + } + + return event.result; + }, + + props: "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), + + fix: function( event ) { + if ( event[ expando ] ) { + return event; + } + + // store a copy of the original event object + // and "clone" to set read-only properties + var originalEvent = event; + event = jQuery.Event( originalEvent ); + + for ( var i = this.props.length, prop; i; ) { + prop = this.props[ --i ]; + event[ prop ] = originalEvent[ prop ]; + } + + // Fix target property, if necessary + if ( !event.target ) { + event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either + } + + // check if target is a textnode (safari) + if ( event.target.nodeType === 3 ) { + event.target = event.target.parentNode; + } + + // Add relatedTarget, if necessary + if ( !event.relatedTarget && event.fromElement ) { + event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement; + } + + // Calculate pageX/Y if missing and clientX/Y available + if ( event.pageX == null && event.clientX != null ) { + var doc = document.documentElement, body = document.body; + event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0); + event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc && doc.clientTop || body && body.clientTop || 0); + } + + // Add which for key events + if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) ) { + event.which = event.charCode || event.keyCode; + } + + // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs) + if ( !event.metaKey && event.ctrlKey ) { + event.metaKey = event.ctrlKey; + } + + // Add which for click: 1 === left; 2 === middle; 3 === right + // Note: button is not normalized, so don't use it + if ( !event.which && event.button !== undefined ) { + event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) )); + } + + return event; + }, + + // Deprecated, use jQuery.guid instead + guid: 1E8, + + // Deprecated, use jQuery.proxy instead + proxy: jQuery.proxy, + + special: { + ready: { + // Make sure the ready event is setup + setup: jQuery.bindReady, + teardown: jQuery.noop + }, + + live: { + add: function( handleObj ) { + jQuery.event.add( this, handleObj.origType, jQuery.extend({}, handleObj, {handler: liveHandler}) ); + }, + + remove: function( handleObj ) { + var remove = true, + type = handleObj.origType.replace(rnamespaces, ""); + + jQuery.each( jQuery.data(this, "events").live || [], function() { + if ( type === this.origType.replace(rnamespaces, "") ) { + remove = false; + return false; + } + }); + + if ( remove ) { + jQuery.event.remove( this, handleObj.origType, liveHandler ); + } + } + + }, + + beforeunload: { + setup: function( data, namespaces, eventHandle ) { + // We only want to do this special case on windows + if ( this.setInterval ) { + this.onbeforeunload = eventHandle; + } + + return false; + }, + teardown: function( namespaces, eventHandle ) { + if ( this.onbeforeunload === eventHandle ) { + this.onbeforeunload = null; + } + } + } + } +}; + +var removeEvent = document.removeEventListener ? + function( elem, type, handle ) { + elem.removeEventListener( type, handle, false ); + } : + function( elem, type, handle ) { + elem.detachEvent( "on" + type, handle ); + }; + +jQuery.Event = function( src ) { + // Allow instantiation without the 'new' keyword + if ( !this.preventDefault ) { + return new jQuery.Event( src ); + } + + // Event object + if ( src && src.type ) { + this.originalEvent = src; + this.type = src.type; + // Event type + } else { + this.type = src; + } + + // timeStamp is buggy for some events on Firefox(#3843) + // So we won't rely on the native value + this.timeStamp = now(); + + // Mark it as fixed + this[ expando ] = true; +}; + +function returnFalse() { + return false; +} +function returnTrue() { + return true; +} + +// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding +// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html +jQuery.Event.prototype = { + preventDefault: function() { + this.isDefaultPrevented = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + + // if preventDefault exists run it on the original event + if ( e.preventDefault ) { + e.preventDefault(); + } + // otherwise set the returnValue property of the original event to false (IE) + e.returnValue = false; + }, + stopPropagation: function() { + this.isPropagationStopped = returnTrue; + + var e = this.originalEvent; + if ( !e ) { + return; + } + // if stopPropagation exists run it on the original event + if ( e.stopPropagation ) { + e.stopPropagation(); + } + // otherwise set the cancelBubble property of the original event to true (IE) + e.cancelBubble = true; + }, + stopImmediatePropagation: function() { + this.isImmediatePropagationStopped = returnTrue; + this.stopPropagation(); + }, + isDefaultPrevented: returnFalse, + isPropagationStopped: returnFalse, + isImmediatePropagationStopped: returnFalse +}; + +// Checks if an event happened on an element within another element +// Used in jQuery.event.special.mouseenter and mouseleave handlers +var withinElement = function( event ) { + // Check if mouse(over|out) are still within the same parent element + var parent = event.relatedTarget; + + // Firefox sometimes assigns relatedTarget a XUL element + // which we cannot access the parentNode property of + try { + // Traverse up the tree + while ( parent && parent !== this ) { + parent = parent.parentNode; + } + + if ( parent !== this ) { + // set the correct event type + event.type = event.data; + + // handle event if we actually just moused on to a non sub-element + jQuery.event.handle.apply( this, arguments ); + } + + // assuming we've left the element since we most likely mousedover a xul element + } catch(e) { } +}, + +// In case of event delegation, we only need to rename the event.type, +// liveHandler will take care of the rest. +delegate = function( event ) { + event.type = event.data; + jQuery.event.handle.apply( this, arguments ); +}; + +// Create mouseenter and mouseleave events +jQuery.each({ + mouseenter: "mouseover", + mouseleave: "mouseout" +}, function( orig, fix ) { + jQuery.event.special[ orig ] = { + setup: function( data ) { + jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig ); + }, + teardown: function( data ) { + jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement ); + } + }; +}); + +// submit delegation +if ( !jQuery.support.submitBubbles ) { + + jQuery.event.special.submit = { + setup: function( data, namespaces ) { + if ( this.nodeName.toLowerCase() !== "form" ) { + jQuery.event.add(this, "click.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "submit" || type === "image") && jQuery( elem ).closest("form").length ) { + return trigger( "submit", this, arguments ); + } + }); + + jQuery.event.add(this, "keypress.specialSubmit", function( e ) { + var elem = e.target, type = elem.type; + + if ( (type === "text" || type === "password") && jQuery( elem ).closest("form").length && e.keyCode === 13 ) { + return trigger( "submit", this, arguments ); + } + }); + + } else { + return false; + } + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialSubmit" ); + } + }; + +} + +// change delegation, happens here so we have bind. +if ( !jQuery.support.changeBubbles ) { + + var formElems = /textarea|input|select/i, + + changeFilters, + + getVal = function( elem ) { + var type = elem.type, val = elem.value; + + if ( type === "radio" || type === "checkbox" ) { + val = elem.checked; + + } else if ( type === "select-multiple" ) { + val = elem.selectedIndex > -1 ? + jQuery.map( elem.options, function( elem ) { + return elem.selected; + }).join("-") : + ""; + + } else if ( elem.nodeName.toLowerCase() === "select" ) { + val = elem.selectedIndex; + } + + return val; + }, + + testChange = function testChange( e ) { + var elem = e.target, data, val; + + if ( !formElems.test( elem.nodeName ) || elem.readOnly ) { + return; + } + + data = jQuery.data( elem, "_change_data" ); + val = getVal(elem); + + // the current data will be also retrieved by beforeactivate + if ( e.type !== "focusout" || elem.type !== "radio" ) { + jQuery.data( elem, "_change_data", val ); + } + + if ( data === undefined || val === data ) { + return; + } + + if ( data != null || val ) { + e.type = "change"; + return jQuery.event.trigger( e, arguments[1], elem ); + } + }; + + jQuery.event.special.change = { + filters: { + focusout: testChange, + + click: function( e ) { + var elem = e.target, type = elem.type; + + if ( type === "radio" || type === "checkbox" || elem.nodeName.toLowerCase() === "select" ) { + return testChange.call( this, e ); + } + }, + + // Change has to be called before submit + // Keydown will be called before keypress, which is used in submit-event delegation + keydown: function( e ) { + var elem = e.target, type = elem.type; + + if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== "textarea") || + (e.keyCode === 32 && (type === "checkbox" || type === "radio")) || + type === "select-multiple" ) { + return testChange.call( this, e ); + } + }, + + // Beforeactivate happens also before the previous element is blurred + // with this event you can't trigger a change event, but you can store + // information/focus[in] is not needed anymore + beforeactivate: function( e ) { + var elem = e.target; + jQuery.data( elem, "_change_data", getVal(elem) ); + } + }, + + setup: function( data, namespaces ) { + if ( this.type === "file" ) { + return false; + } + + for ( var type in changeFilters ) { + jQuery.event.add( this, type + ".specialChange", changeFilters[type] ); + } + + return formElems.test( this.nodeName ); + }, + + teardown: function( namespaces ) { + jQuery.event.remove( this, ".specialChange" ); + + return formElems.test( this.nodeName ); + } + }; + + changeFilters = jQuery.event.special.change.filters; +} + +function trigger( type, elem, args ) { + args[0].type = type; + return jQuery.event.handle.apply( elem, args ); +} + +// Create "bubbling" focus and blur events +if ( document.addEventListener ) { + jQuery.each({ focus: "focusin", blur: "focusout" }, function( orig, fix ) { + jQuery.event.special[ fix ] = { + setup: function() { + this.addEventListener( orig, handler, true ); + }, + teardown: function() { + this.removeEventListener( orig, handler, true ); + } + }; + + function handler( e ) { + e = jQuery.event.fix( e ); + e.type = fix; + return jQuery.event.handle.call( this, e ); + } + }); +} + +jQuery.each(["bind", "one"], function( i, name ) { + jQuery.fn[ name ] = function( type, data, fn ) { + // Handle object literals + if ( typeof type === "object" ) { + for ( var key in type ) { + this[ name ](key, data, type[key], fn); + } + return this; + } + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + var handler = name === "one" ? jQuery.proxy( fn, function( event ) { + jQuery( this ).unbind( event, handler ); + return fn.apply( this, arguments ); + }) : fn; + + if ( type === "unload" && name !== "one" ) { + this.one( type, data, fn ); + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.add( this[i], type, handler, data ); + } + } + + return this; + }; +}); + +jQuery.fn.extend({ + unbind: function( type, fn ) { + // Handle object literals + if ( typeof type === "object" && !type.preventDefault ) { + for ( var key in type ) { + this.unbind(key, type[key]); + } + + } else { + for ( var i = 0, l = this.length; i < l; i++ ) { + jQuery.event.remove( this[i], type, fn ); + } + } + + return this; + }, + + delegate: function( selector, types, data, fn ) { + return this.live( types, data, fn, selector ); + }, + + undelegate: function( selector, types, fn ) { + if ( arguments.length === 0 ) { + return this.unbind( "live" ); + + } else { + return this.die( types, null, fn, selector ); + } + }, + + trigger: function( type, data ) { + return this.each(function() { + jQuery.event.trigger( type, data, this ); + }); + }, + + triggerHandler: function( type, data ) { + if ( this[0] ) { + var event = jQuery.Event( type ); + event.preventDefault(); + event.stopPropagation(); + jQuery.event.trigger( event, data, this[0] ); + return event.result; + } + }, + + toggle: function( fn ) { + // Save reference to arguments for access in closure + var args = arguments, i = 1; + + // link all the functions, so any of them can unbind this click handler + while ( i < args.length ) { + jQuery.proxy( fn, args[ i++ ] ); + } + + return this.click( jQuery.proxy( fn, function( event ) { + // Figure out which function to execute + var lastToggle = ( jQuery.data( this, "lastToggle" + fn.guid ) || 0 ) % i; + jQuery.data( this, "lastToggle" + fn.guid, lastToggle + 1 ); + + // Make sure that clicks stop + event.preventDefault(); + + // and execute the function + return args[ lastToggle ].apply( this, arguments ) || false; + })); + }, + + hover: function( fnOver, fnOut ) { + return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver ); + } +}); + +var liveMap = { + focus: "focusin", + blur: "focusout", + mouseenter: "mouseover", + mouseleave: "mouseout" +}; + +jQuery.each(["live", "die"], function( i, name ) { + jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) { + var type, i = 0, match, namespaces, preType, + selector = origSelector || this.selector, + context = origSelector ? this : jQuery( this.context ); + + if ( jQuery.isFunction( data ) ) { + fn = data; + data = undefined; + } + + types = (types || "").split(" "); + + while ( (type = types[ i++ ]) != null ) { + match = rnamespaces.exec( type ); + namespaces = ""; + + if ( match ) { + namespaces = match[0]; + type = type.replace( rnamespaces, "" ); + } + + if ( type === "hover" ) { + types.push( "mouseenter" + namespaces, "mouseleave" + namespaces ); + continue; + } + + preType = type; + + if ( type === "focus" || type === "blur" ) { + types.push( liveMap[ type ] + namespaces ); + type = type + namespaces; + + } else { + type = (liveMap[ type ] || type) + namespaces; + } + + if ( name === "live" ) { + // bind live handler + context.each(function(){ + jQuery.event.add( this, liveConvert( type, selector ), + { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } ); + }); + + } else { + // unbind live handler + context.unbind( liveConvert( type, selector ), fn ); + } + } + + return this; + } +}); + +function liveHandler( event ) { + var stop, elems = [], selectors = [], args = arguments, + related, match, handleObj, elem, j, i, l, data, + events = jQuery.data( this, "events" ); + + // Make sure we avoid non-left-click bubbling in Firefox (#3861) + if ( event.liveFired === this || !events || !events.live || event.button && event.type === "click" ) { + return; + } + + event.liveFired = this; + + var live = events.live.slice(0); + + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( handleObj.origType.replace( rnamespaces, "" ) === event.type ) { + selectors.push( handleObj.selector ); + + } else { + live.splice( j--, 1 ); + } + } + + match = jQuery( event.target ).closest( selectors, event.currentTarget ); + + for ( i = 0, l = match.length; i < l; i++ ) { + for ( j = 0; j < live.length; j++ ) { + handleObj = live[j]; + + if ( match[i].selector === handleObj.selector ) { + elem = match[i].elem; + related = null; + + // Those two events require additional checking + if ( handleObj.preType === "mouseenter" || handleObj.preType === "mouseleave" ) { + related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0]; + } + + if ( !related || related !== elem ) { + elems.push({ elem: elem, handleObj: handleObj }); + } + } + } + } + + for ( i = 0, l = elems.length; i < l; i++ ) { + match = elems[i]; + event.currentTarget = match.elem; + event.data = match.handleObj.data; + event.handleObj = match.handleObj; + + if ( match.handleObj.origHandler.apply( match.elem, args ) === false ) { + stop = false; + break; + } + } + + return stop; +} + +function liveConvert( type, selector ) { + return "live." + (type && type !== "*" ? type + "." : "") + selector.replace(/\./g, "`").replace(/ /g, "&"); +} + +jQuery.each( ("blur focus focusin focusout load resize scroll unload click dblclick " + + "mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " + + "change select submit keydown keypress keyup error").split(" "), function( i, name ) { + + // Handle event binding + jQuery.fn[ name ] = function( fn ) { + return fn ? this.bind( name, fn ) : this.trigger( name ); + }; + + if ( jQuery.attrFn ) { + jQuery.attrFn[ name ] = true; + } +}); + +// Prevent memory leaks in IE +// Window isn't included so as not to unbind existing unload events +// More info: +// - http://isaacschlueter.com/2006/10/msie-memory-leaks/ +if ( window.attachEvent && !window.addEventListener ) { + window.attachEvent("onunload", function() { + for ( var id in jQuery.cache ) { + if ( jQuery.cache[ id ].handle ) { + // Try/Catch is to handle iframes being unloaded, see #4280 + try { + jQuery.event.remove( jQuery.cache[ id ].handle.elem ); + } catch(e) {} + } + } + }); +} +/*! + * Sizzle CSS Selector Engine - v1.0 + * Copyright 2009, The Dojo Foundation + * Released under the MIT, BSD, and GPL Licenses. + * More information: http://sizzlejs.com/ + */ +(function(){ + +var chunker = /((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g, + done = 0, + toString = Object.prototype.toString, + hasDuplicate = false, + baseHasDuplicate = true; + +// Here we check if the JavaScript engine is using some sort of +// optimization where it does not always call our comparision +// function. If that is the case, discard the hasDuplicate value. +// Thus far that includes Google Chrome. +[0, 0].sort(function(){ + baseHasDuplicate = false; + return 0; +}); + +var Sizzle = function(selector, context, results, seed) { + results = results || []; + var origContext = context = context || document; + + if ( context.nodeType !== 1 && context.nodeType !== 9 ) { + return []; + } + + if ( !selector || typeof selector !== "string" ) { + return results; + } + + var parts = [], m, set, checkSet, extra, prune = true, contextXML = isXML(context), + soFar = selector; + + // Reset the position of the chunker regexp (start from head) + while ( (chunker.exec(""), m = chunker.exec(soFar)) !== null ) { + soFar = m[3]; + + parts.push( m[1] ); + + if ( m[2] ) { + extra = m[3]; + break; + } + } + + if ( parts.length > 1 && origPOS.exec( selector ) ) { + if ( parts.length === 2 && Expr.relative[ parts[0] ] ) { + set = posProcess( parts[0] + parts[1], context ); + } else { + set = Expr.relative[ parts[0] ] ? + [ context ] : + Sizzle( parts.shift(), context ); + + while ( parts.length ) { + selector = parts.shift(); + + if ( Expr.relative[ selector ] ) { + selector += parts.shift(); + } + + set = posProcess( selector, set ); + } + } + } else { + // Take a shortcut and set the context if the root selector is an ID + // (but not if it'll be faster if the inner selector is an ID) + if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML && + Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) { + var ret = Sizzle.find( parts.shift(), context, contextXML ); + context = ret.expr ? Sizzle.filter( ret.expr, ret.set )[0] : ret.set[0]; + } + + if ( context ) { + var ret = seed ? + { expr: parts.pop(), set: makeArray(seed) } : + Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML ); + set = ret.expr ? Sizzle.filter( ret.expr, ret.set ) : ret.set; + + if ( parts.length > 0 ) { + checkSet = makeArray(set); + } else { + prune = false; + } + + while ( parts.length ) { + var cur = parts.pop(), pop = cur; + + if ( !Expr.relative[ cur ] ) { + cur = ""; + } else { + pop = parts.pop(); + } + + if ( pop == null ) { + pop = context; + } + + Expr.relative[ cur ]( checkSet, pop, contextXML ); + } + } else { + checkSet = parts = []; + } + } + + if ( !checkSet ) { + checkSet = set; + } + + if ( !checkSet ) { + Sizzle.error( cur || selector ); + } + + if ( toString.call(checkSet) === "[object Array]" ) { + if ( !prune ) { + results.push.apply( results, checkSet ); + } else if ( context && context.nodeType === 1 ) { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && contains(context, checkSet[i])) ) { + results.push( set[i] ); + } + } + } else { + for ( var i = 0; checkSet[i] != null; i++ ) { + if ( checkSet[i] && checkSet[i].nodeType === 1 ) { + results.push( set[i] ); + } + } + } + } else { + makeArray( checkSet, results ); + } + + if ( extra ) { + Sizzle( extra, origContext, results, seed ); + Sizzle.uniqueSort( results ); + } + + return results; +}; + +Sizzle.uniqueSort = function(results){ + if ( sortOrder ) { + hasDuplicate = baseHasDuplicate; + results.sort(sortOrder); + + if ( hasDuplicate ) { + for ( var i = 1; i < results.length; i++ ) { + if ( results[i] === results[i-1] ) { + results.splice(i--, 1); + } + } + } + } + + return results; +}; + +Sizzle.matches = function(expr, set){ + return Sizzle(expr, null, null, set); +}; + +Sizzle.find = function(expr, context, isXML){ + var set, match; + + if ( !expr ) { + return []; + } + + for ( var i = 0, l = Expr.order.length; i < l; i++ ) { + var type = Expr.order[i], match; + + if ( (match = Expr.leftMatch[ type ].exec( expr )) ) { + var left = match[1]; + match.splice(1,1); + + if ( left.substr( left.length - 1 ) !== "\\" ) { + match[1] = (match[1] || "").replace(/\\/g, ""); + set = Expr.find[ type ]( match, context, isXML ); + if ( set != null ) { + expr = expr.replace( Expr.match[ type ], "" ); + break; + } + } + } + } + + if ( !set ) { + set = context.getElementsByTagName("*"); + } + + return {set: set, expr: expr}; +}; + +Sizzle.filter = function(expr, set, inplace, not){ + var old = expr, result = [], curLoop = set, match, anyFound, + isXMLFilter = set && set[0] && isXML(set[0]); + + while ( expr && set.length ) { + for ( var type in Expr.filter ) { + if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) { + var filter = Expr.filter[ type ], found, item, left = match[1]; + anyFound = false; + + match.splice(1,1); + + if ( left.substr( left.length - 1 ) === "\\" ) { + continue; + } + + if ( curLoop === result ) { + result = []; + } + + if ( Expr.preFilter[ type ] ) { + match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter ); + + if ( !match ) { + anyFound = found = true; + } else if ( match === true ) { + continue; + } + } + + if ( match ) { + for ( var i = 0; (item = curLoop[i]) != null; i++ ) { + if ( item ) { + found = filter( item, match, i, curLoop ); + var pass = not ^ !!found; + + if ( inplace && found != null ) { + if ( pass ) { + anyFound = true; + } else { + curLoop[i] = false; + } + } else if ( pass ) { + result.push( item ); + anyFound = true; + } + } + } + } + + if ( found !== undefined ) { + if ( !inplace ) { + curLoop = result; + } + + expr = expr.replace( Expr.match[ type ], "" ); + + if ( !anyFound ) { + return []; + } + + break; + } + } + } + + // Improper expression + if ( expr === old ) { + if ( anyFound == null ) { + Sizzle.error( expr ); + } else { + break; + } + } + + old = expr; + } + + return curLoop; +}; + +Sizzle.error = function( msg ) { + throw "Syntax error, unrecognized expression: " + msg; +}; + +var Expr = Sizzle.selectors = { + order: [ "ID", "NAME", "TAG" ], + match: { + ID: /#((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + CLASS: /\.((?:[\w\u00c0-\uFFFF-]|\\.)+)/, + NAME: /\[name=['"]*((?:[\w\u00c0-\uFFFF-]|\\.)+)['"]*\]/, + ATTR: /\[\s*((?:[\w\u00c0-\uFFFF-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/, + TAG: /^((?:[\w\u00c0-\uFFFF\*-]|\\.)+)/, + CHILD: /:(only|nth|last|first)-child(?:\((even|odd|[\dn+-]*)\))?/, + POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^-]|$)/, + PSEUDO: /:((?:[\w\u00c0-\uFFFF-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/ + }, + leftMatch: {}, + attrMap: { + "class": "className", + "for": "htmlFor" + }, + attrHandle: { + href: function(elem){ + return elem.getAttribute("href"); + } + }, + relative: { + "+": function(checkSet, part){ + var isPartStr = typeof part === "string", + isTag = isPartStr && !/\W/.test(part), + isPartStrNotTag = isPartStr && !isTag; + + if ( isTag ) { + part = part.toLowerCase(); + } + + for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) { + if ( (elem = checkSet[i]) ) { + while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {} + + checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ? + elem || false : + elem === part; + } + } + + if ( isPartStrNotTag ) { + Sizzle.filter( part, checkSet, true ); + } + }, + ">": function(checkSet, part){ + var isPartStr = typeof part === "string"; + + if ( isPartStr && !/\W/.test(part) ) { + part = part.toLowerCase(); + + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + var parent = elem.parentNode; + checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false; + } + } + } else { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + checkSet[i] = isPartStr ? + elem.parentNode : + elem.parentNode === part; + } + } + + if ( isPartStr ) { + Sizzle.filter( part, checkSet, true ); + } + } + }, + "": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("parentNode", part, doneName, checkSet, nodeCheck, isXML); + }, + "~": function(checkSet, part, isXML){ + var doneName = done++, checkFn = dirCheck; + + if ( typeof part === "string" && !/\W/.test(part) ) { + var nodeCheck = part = part.toLowerCase(); + checkFn = dirNodeCheck; + } + + checkFn("previousSibling", part, doneName, checkSet, nodeCheck, isXML); + } + }, + find: { + ID: function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? [m] : []; + } + }, + NAME: function(match, context){ + if ( typeof context.getElementsByName !== "undefined" ) { + var ret = [], results = context.getElementsByName(match[1]); + + for ( var i = 0, l = results.length; i < l; i++ ) { + if ( results[i].getAttribute("name") === match[1] ) { + ret.push( results[i] ); + } + } + + return ret.length === 0 ? null : ret; + } + }, + TAG: function(match, context){ + return context.getElementsByTagName(match[1]); + } + }, + preFilter: { + CLASS: function(match, curLoop, inplace, result, not, isXML){ + match = " " + match[1].replace(/\\/g, "") + " "; + + if ( isXML ) { + return match; + } + + for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) { + if ( elem ) { + if ( not ^ (elem.className && (" " + elem.className + " ").replace(/[\t\n]/g, " ").indexOf(match) >= 0) ) { + if ( !inplace ) { + result.push( elem ); + } + } else if ( inplace ) { + curLoop[i] = false; + } + } + } + + return false; + }, + ID: function(match){ + return match[1].replace(/\\/g, ""); + }, + TAG: function(match, curLoop){ + return match[1].toLowerCase(); + }, + CHILD: function(match){ + if ( match[1] === "nth" ) { + // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6' + var test = /(-?)(\d*)n((?:\+|-)?\d*)/.exec( + match[2] === "even" && "2n" || match[2] === "odd" && "2n+1" || + !/\D/.test( match[2] ) && "0n+" + match[2] || match[2]); + + // calculate the numbers (first)n+(last) including if they are negative + match[2] = (test[1] + (test[2] || 1)) - 0; + match[3] = test[3] - 0; + } + + // TODO: Move to normal caching system + match[0] = done++; + + return match; + }, + ATTR: function(match, curLoop, inplace, result, not, isXML){ + var name = match[1].replace(/\\/g, ""); + + if ( !isXML && Expr.attrMap[name] ) { + match[1] = Expr.attrMap[name]; + } + + if ( match[2] === "~=" ) { + match[4] = " " + match[4] + " "; + } + + return match; + }, + PSEUDO: function(match, curLoop, inplace, result, not){ + if ( match[1] === "not" ) { + // If we're dealing with a complex expression, or a simple one + if ( ( chunker.exec(match[3]) || "" ).length > 1 || /^\w/.test(match[3]) ) { + match[3] = Sizzle(match[3], null, null, curLoop); + } else { + var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not); + if ( !inplace ) { + result.push.apply( result, ret ); + } + return false; + } + } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) { + return true; + } + + return match; + }, + POS: function(match){ + match.unshift( true ); + return match; + } + }, + filters: { + enabled: function(elem){ + return elem.disabled === false && elem.type !== "hidden"; + }, + disabled: function(elem){ + return elem.disabled === true; + }, + checked: function(elem){ + return elem.checked === true; + }, + selected: function(elem){ + // Accessing this property makes selected-by-default + // options in Safari work properly + elem.parentNode.selectedIndex; + return elem.selected === true; + }, + parent: function(elem){ + return !!elem.firstChild; + }, + empty: function(elem){ + return !elem.firstChild; + }, + has: function(elem, i, match){ + return !!Sizzle( match[3], elem ).length; + }, + header: function(elem){ + return /h\d/i.test( elem.nodeName ); + }, + text: function(elem){ + return "text" === elem.type; + }, + radio: function(elem){ + return "radio" === elem.type; + }, + checkbox: function(elem){ + return "checkbox" === elem.type; + }, + file: function(elem){ + return "file" === elem.type; + }, + password: function(elem){ + return "password" === elem.type; + }, + submit: function(elem){ + return "submit" === elem.type; + }, + image: function(elem){ + return "image" === elem.type; + }, + reset: function(elem){ + return "reset" === elem.type; + }, + button: function(elem){ + return "button" === elem.type || elem.nodeName.toLowerCase() === "button"; + }, + input: function(elem){ + return /input|select|textarea|button/i.test(elem.nodeName); + } + }, + setFilters: { + first: function(elem, i){ + return i === 0; + }, + last: function(elem, i, match, array){ + return i === array.length - 1; + }, + even: function(elem, i){ + return i % 2 === 0; + }, + odd: function(elem, i){ + return i % 2 === 1; + }, + lt: function(elem, i, match){ + return i < match[3] - 0; + }, + gt: function(elem, i, match){ + return i > match[3] - 0; + }, + nth: function(elem, i, match){ + return match[3] - 0 === i; + }, + eq: function(elem, i, match){ + return match[3] - 0 === i; + } + }, + filter: { + PSEUDO: function(elem, match, i, array){ + var name = match[1], filter = Expr.filters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } else if ( name === "contains" ) { + return (elem.textContent || elem.innerText || getText([ elem ]) || "").indexOf(match[3]) >= 0; + } else if ( name === "not" ) { + var not = match[3]; + + for ( var i = 0, l = not.length; i < l; i++ ) { + if ( not[i] === elem ) { + return false; + } + } + + return true; + } else { + Sizzle.error( "Syntax error, unrecognized expression: " + name ); + } + }, + CHILD: function(elem, match){ + var type = match[1], node = elem; + switch (type) { + case 'only': + case 'first': + while ( (node = node.previousSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + if ( type === "first" ) { + return true; + } + node = elem; + case 'last': + while ( (node = node.nextSibling) ) { + if ( node.nodeType === 1 ) { + return false; + } + } + return true; + case 'nth': + var first = match[2], last = match[3]; + + if ( first === 1 && last === 0 ) { + return true; + } + + var doneName = match[0], + parent = elem.parentNode; + + if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) { + var count = 0; + for ( node = parent.firstChild; node; node = node.nextSibling ) { + if ( node.nodeType === 1 ) { + node.nodeIndex = ++count; + } + } + parent.sizcache = doneName; + } + + var diff = elem.nodeIndex - last; + if ( first === 0 ) { + return diff === 0; + } else { + return ( diff % first === 0 && diff / first >= 0 ); + } + } + }, + ID: function(elem, match){ + return elem.nodeType === 1 && elem.getAttribute("id") === match; + }, + TAG: function(elem, match){ + return (match === "*" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match; + }, + CLASS: function(elem, match){ + return (" " + (elem.className || elem.getAttribute("class")) + " ") + .indexOf( match ) > -1; + }, + ATTR: function(elem, match){ + var name = match[1], + result = Expr.attrHandle[ name ] ? + Expr.attrHandle[ name ]( elem ) : + elem[ name ] != null ? + elem[ name ] : + elem.getAttribute( name ), + value = result + "", + type = match[2], + check = match[4]; + + return result == null ? + type === "!=" : + type === "=" ? + value === check : + type === "*=" ? + value.indexOf(check) >= 0 : + type === "~=" ? + (" " + value + " ").indexOf(check) >= 0 : + !check ? + value && result !== false : + type === "!=" ? + value !== check : + type === "^=" ? + value.indexOf(check) === 0 : + type === "$=" ? + value.substr(value.length - check.length) === check : + type === "|=" ? + value === check || value.substr(0, check.length + 1) === check + "-" : + false; + }, + POS: function(elem, match, i, array){ + var name = match[2], filter = Expr.setFilters[ name ]; + + if ( filter ) { + return filter( elem, i, match, array ); + } + } + } +}; + +var origPOS = Expr.match.POS; + +for ( var type in Expr.match ) { + Expr.match[ type ] = new RegExp( Expr.match[ type ].source + /(?![^\[]*\])(?![^\(]*\))/.source ); + Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\r|\n)*?)/.source + Expr.match[ type ].source.replace(/\\(\d+)/g, function(all, num){ + return "\\" + (num - 0 + 1); + })); +} + +var makeArray = function(array, results) { + array = Array.prototype.slice.call( array, 0 ); + + if ( results ) { + results.push.apply( results, array ); + return results; + } + + return array; +}; + +// Perform a simple check to determine if the browser is capable of +// converting a NodeList to an array using builtin methods. +// Also verifies that the returned array holds DOM nodes +// (which is not the case in the Blackberry browser) +try { + Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType; + +// Provide a fallback method if it does not work +} catch(e){ + makeArray = function(array, results) { + var ret = results || []; + + if ( toString.call(array) === "[object Array]" ) { + Array.prototype.push.apply( ret, array ); + } else { + if ( typeof array.length === "number" ) { + for ( var i = 0, l = array.length; i < l; i++ ) { + ret.push( array[i] ); + } + } else { + for ( var i = 0; array[i]; i++ ) { + ret.push( array[i] ); + } + } + } + + return ret; + }; +} + +var sortOrder; + +if ( document.documentElement.compareDocumentPosition ) { + sortOrder = function( a, b ) { + if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.compareDocumentPosition ? -1 : 1; + } + + var ret = a.compareDocumentPosition(b) & 4 ? -1 : a === b ? 0 : 1; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( "sourceIndex" in document.documentElement ) { + sortOrder = function( a, b ) { + if ( !a.sourceIndex || !b.sourceIndex ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.sourceIndex ? -1 : 1; + } + + var ret = a.sourceIndex - b.sourceIndex; + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} else if ( document.createRange ) { + sortOrder = function( a, b ) { + if ( !a.ownerDocument || !b.ownerDocument ) { + if ( a == b ) { + hasDuplicate = true; + } + return a.ownerDocument ? -1 : 1; + } + + var aRange = a.ownerDocument.createRange(), bRange = b.ownerDocument.createRange(); + aRange.setStart(a, 0); + aRange.setEnd(a, 0); + bRange.setStart(b, 0); + bRange.setEnd(b, 0); + var ret = aRange.compareBoundaryPoints(Range.START_TO_END, bRange); + if ( ret === 0 ) { + hasDuplicate = true; + } + return ret; + }; +} + +// Utility function for retreiving the text value of an array of DOM nodes +function getText( elems ) { + var ret = "", elem; + + for ( var i = 0; elems[i]; i++ ) { + elem = elems[i]; + + // Get the text from text nodes and CDATA nodes + if ( elem.nodeType === 3 || elem.nodeType === 4 ) { + ret += elem.nodeValue; + + // Traverse everything else, except comment nodes + } else if ( elem.nodeType !== 8 ) { + ret += getText( elem.childNodes ); + } + } + + return ret; +} + +// Check to see if the browser returns elements by name when +// querying by getElementById (and provide a workaround) +(function(){ + // We're going to inject a fake input element with a specified name + var form = document.createElement("div"), + id = "script" + (new Date).getTime(); + form.innerHTML = ""; + + // Inject it into the root element, check its status, and remove it quickly + var root = document.documentElement; + root.insertBefore( form, root.firstChild ); + + // The workaround has to do additional checks after a getElementById + // Which slows things down for other browsers (hence the branching) + if ( document.getElementById( id ) ) { + Expr.find.ID = function(match, context, isXML){ + if ( typeof context.getElementById !== "undefined" && !isXML ) { + var m = context.getElementById(match[1]); + return m ? m.id === match[1] || typeof m.getAttributeNode !== "undefined" && m.getAttributeNode("id").nodeValue === match[1] ? [m] : undefined : []; + } + }; + + Expr.filter.ID = function(elem, match){ + var node = typeof elem.getAttributeNode !== "undefined" && elem.getAttributeNode("id"); + return elem.nodeType === 1 && node && node.nodeValue === match; + }; + } + + root.removeChild( form ); + root = form = null; // release memory in IE +})(); + +(function(){ + // Check to see if the browser returns only elements + // when doing getElementsByTagName("*") + + // Create a fake element + var div = document.createElement("div"); + div.appendChild( document.createComment("") ); + + // Make sure no comments are found + if ( div.getElementsByTagName("*").length > 0 ) { + Expr.find.TAG = function(match, context){ + var results = context.getElementsByTagName(match[1]); + + // Filter out possible comments + if ( match[1] === "*" ) { + var tmp = []; + + for ( var i = 0; results[i]; i++ ) { + if ( results[i].nodeType === 1 ) { + tmp.push( results[i] ); + } + } + + results = tmp; + } + + return results; + }; + } + + // Check to see if an attribute returns normalized href attributes + div.innerHTML = ""; + if ( div.firstChild && typeof div.firstChild.getAttribute !== "undefined" && + div.firstChild.getAttribute("href") !== "#" ) { + Expr.attrHandle.href = function(elem){ + return elem.getAttribute("href", 2); + }; + } + + div = null; // release memory in IE +})(); + +if ( document.querySelectorAll ) { + (function(){ + var oldSizzle = Sizzle, div = document.createElement("div"); + div.innerHTML = "

"; + + // Safari can't handle uppercase or unicode characters when + // in quirks mode. + if ( div.querySelectorAll && div.querySelectorAll(".TEST").length === 0 ) { + return; + } + + Sizzle = function(query, context, extra, seed){ + context = context || document; + + // Only use querySelectorAll on non-XML documents + // (ID selectors don't work in non-HTML documents) + if ( !seed && context.nodeType === 9 && !isXML(context) ) { + try { + return makeArray( context.querySelectorAll(query), extra ); + } catch(e){} + } + + return oldSizzle(query, context, extra, seed); + }; + + for ( var prop in oldSizzle ) { + Sizzle[ prop ] = oldSizzle[ prop ]; + } + + div = null; // release memory in IE + })(); +} + +(function(){ + var div = document.createElement("div"); + + div.innerHTML = "
"; + + // Opera can't find a second classname (in 9.6) + // Also, make sure that getElementsByClassName actually exists + if ( !div.getElementsByClassName || div.getElementsByClassName("e").length === 0 ) { + return; + } + + // Safari caches class attributes, doesn't catch changes (in 3.2) + div.lastChild.className = "e"; + + if ( div.getElementsByClassName("e").length === 1 ) { + return; + } + + Expr.order.splice(1, 0, "CLASS"); + Expr.find.CLASS = function(match, context, isXML) { + if ( typeof context.getElementsByClassName !== "undefined" && !isXML ) { + return context.getElementsByClassName(match[1]); + } + }; + + div = null; // release memory in IE +})(); + +function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 && !isXML ){ + elem.sizcache = doneName; + elem.sizset = i; + } + + if ( elem.nodeName.toLowerCase() === cur ) { + match = elem; + break; + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) { + for ( var i = 0, l = checkSet.length; i < l; i++ ) { + var elem = checkSet[i]; + if ( elem ) { + elem = elem[dir]; + var match = false; + + while ( elem ) { + if ( elem.sizcache === doneName ) { + match = checkSet[elem.sizset]; + break; + } + + if ( elem.nodeType === 1 ) { + if ( !isXML ) { + elem.sizcache = doneName; + elem.sizset = i; + } + if ( typeof cur !== "string" ) { + if ( elem === cur ) { + match = true; + break; + } + + } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) { + match = elem; + break; + } + } + + elem = elem[dir]; + } + + checkSet[i] = match; + } + } +} + +var contains = document.compareDocumentPosition ? function(a, b){ + return !!(a.compareDocumentPosition(b) & 16); +} : function(a, b){ + return a !== b && (a.contains ? a.contains(b) : true); +}; + +var isXML = function(elem){ + // documentElement is verified for cases where it doesn't yet exist + // (such as loading iframes in IE - #4833) + var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement; + return documentElement ? documentElement.nodeName !== "HTML" : false; +}; + +var posProcess = function(selector, context){ + var tmpSet = [], later = "", match, + root = context.nodeType ? [context] : context; + + // Position selectors must be done after the filter + // And so must :not(positional) so we move all PSEUDOs to the end + while ( (match = Expr.match.PSEUDO.exec( selector )) ) { + later += match[0]; + selector = selector.replace( Expr.match.PSEUDO, "" ); + } + + selector = Expr.relative[selector] ? selector + "*" : selector; + + for ( var i = 0, l = root.length; i < l; i++ ) { + Sizzle( selector, root[i], tmpSet ); + } + + return Sizzle.filter( later, tmpSet ); +}; + +// EXPOSE +jQuery.find = Sizzle; +jQuery.expr = Sizzle.selectors; +jQuery.expr[":"] = jQuery.expr.filters; +jQuery.unique = Sizzle.uniqueSort; +jQuery.text = getText; +jQuery.isXMLDoc = isXML; +jQuery.contains = contains; + +return; + +window.Sizzle = Sizzle; + +})(); +var runtil = /Until$/, + rparentsprev = /^(?:parents|prevUntil|prevAll)/, + // Note: This RegExp should be improved, or likely pulled from Sizzle + rmultiselector = /,/, + slice = Array.prototype.slice; + +// Implement the identical functionality for filter and not +var winnow = function( elements, qualifier, keep ) { + if ( jQuery.isFunction( qualifier ) ) { + return jQuery.grep(elements, function( elem, i ) { + return !!qualifier.call( elem, i, elem ) === keep; + }); + + } else if ( qualifier.nodeType ) { + return jQuery.grep(elements, function( elem, i ) { + return (elem === qualifier) === keep; + }); + + } else if ( typeof qualifier === "string" ) { + var filtered = jQuery.grep(elements, function( elem ) { + return elem.nodeType === 1; + }); + + if ( isSimple.test( qualifier ) ) { + return jQuery.filter(qualifier, filtered, !keep); + } else { + qualifier = jQuery.filter( qualifier, filtered ); + } + } + + return jQuery.grep(elements, function( elem, i ) { + return (jQuery.inArray( elem, qualifier ) >= 0) === keep; + }); +}; + +jQuery.fn.extend({ + find: function( selector ) { + var ret = this.pushStack( "", "find", selector ), length = 0; + + for ( var i = 0, l = this.length; i < l; i++ ) { + length = ret.length; + jQuery.find( selector, this[i], ret ); + + if ( i > 0 ) { + // Make sure that the results are unique + for ( var n = length; n < ret.length; n++ ) { + for ( var r = 0; r < length; r++ ) { + if ( ret[r] === ret[n] ) { + ret.splice(n--, 1); + break; + } + } + } + } + } + + return ret; + }, + + has: function( target ) { + var targets = jQuery( target ); + return this.filter(function() { + for ( var i = 0, l = targets.length; i < l; i++ ) { + if ( jQuery.contains( this, targets[i] ) ) { + return true; + } + } + }); + }, + + not: function( selector ) { + return this.pushStack( winnow(this, selector, false), "not", selector); + }, + + filter: function( selector ) { + return this.pushStack( winnow(this, selector, true), "filter", selector ); + }, + + is: function( selector ) { + return !!selector && jQuery.filter( selector, this ).length > 0; + }, + + closest: function( selectors, context ) { + if ( jQuery.isArray( selectors ) ) { + var ret = [], cur = this[0], match, matches = {}, selector; + + if ( cur && selectors.length ) { + for ( var i = 0, l = selectors.length; i < l; i++ ) { + selector = selectors[i]; + + if ( !matches[selector] ) { + matches[selector] = jQuery.expr.match.POS.test( selector ) ? + jQuery( selector, context || this.context ) : + selector; + } + } + + while ( cur && cur.ownerDocument && cur !== context ) { + for ( selector in matches ) { + match = matches[selector]; + + if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) { + ret.push({ selector: selector, elem: cur }); + delete matches[selector]; + } + } + cur = cur.parentNode; + } + } + + return ret; + } + + var pos = jQuery.expr.match.POS.test( selectors ) ? + jQuery( selectors, context || this.context ) : null; + + return this.map(function( i, cur ) { + while ( cur && cur.ownerDocument && cur !== context ) { + if ( pos ? pos.index(cur) > -1 : jQuery(cur).is(selectors) ) { + return cur; + } + cur = cur.parentNode; + } + return null; + }); + }, + + // Determine the position of an element within + // the matched set of elements + index: function( elem ) { + if ( !elem || typeof elem === "string" ) { + return jQuery.inArray( this[0], + // If it receives a string, the selector is used + // If it receives nothing, the siblings are used + elem ? jQuery( elem ) : this.parent().children() ); + } + // Locate the position of the desired element + return jQuery.inArray( + // If it receives a jQuery object, the first element is used + elem.jquery ? elem[0] : elem, this ); + }, + + add: function( selector, context ) { + var set = typeof selector === "string" ? + jQuery( selector, context || this.context ) : + jQuery.makeArray( selector ), + all = jQuery.merge( this.get(), set ); + + return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ? + all : + jQuery.unique( all ) ); + }, + + andSelf: function() { + return this.add( this.prevObject ); + } +}); + +// A painfully simple check to see if an element is disconnected +// from a document (should be improved, where feasible). +function isDisconnected( node ) { + return !node || !node.parentNode || node.parentNode.nodeType === 11; +} + +jQuery.each({ + parent: function( elem ) { + var parent = elem.parentNode; + return parent && parent.nodeType !== 11 ? parent : null; + }, + parents: function( elem ) { + return jQuery.dir( elem, "parentNode" ); + }, + parentsUntil: function( elem, i, until ) { + return jQuery.dir( elem, "parentNode", until ); + }, + next: function( elem ) { + return jQuery.nth( elem, 2, "nextSibling" ); + }, + prev: function( elem ) { + return jQuery.nth( elem, 2, "previousSibling" ); + }, + nextAll: function( elem ) { + return jQuery.dir( elem, "nextSibling" ); + }, + prevAll: function( elem ) { + return jQuery.dir( elem, "previousSibling" ); + }, + nextUntil: function( elem, i, until ) { + return jQuery.dir( elem, "nextSibling", until ); + }, + prevUntil: function( elem, i, until ) { + return jQuery.dir( elem, "previousSibling", until ); + }, + siblings: function( elem ) { + return jQuery.sibling( elem.parentNode.firstChild, elem ); + }, + children: function( elem ) { + return jQuery.sibling( elem.firstChild ); + }, + contents: function( elem ) { + return jQuery.nodeName( elem, "iframe" ) ? + elem.contentDocument || elem.contentWindow.document : + jQuery.makeArray( elem.childNodes ); + } +}, function( name, fn ) { + jQuery.fn[ name ] = function( until, selector ) { + var ret = jQuery.map( this, fn, until ); + + if ( !runtil.test( name ) ) { + selector = until; + } + + if ( selector && typeof selector === "string" ) { + ret = jQuery.filter( selector, ret ); + } + + ret = this.length > 1 ? jQuery.unique( ret ) : ret; + + if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) { + ret = ret.reverse(); + } + + return this.pushStack( ret, name, slice.call(arguments).join(",") ); + }; +}); + +jQuery.extend({ + filter: function( expr, elems, not ) { + if ( not ) { + expr = ":not(" + expr + ")"; + } + + return jQuery.find.matches(expr, elems); + }, + + dir: function( elem, dir, until ) { + var matched = [], cur = elem[dir]; + while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) { + if ( cur.nodeType === 1 ) { + matched.push( cur ); + } + cur = cur[dir]; + } + return matched; + }, + + nth: function( cur, result, dir, elem ) { + result = result || 1; + var num = 0; + + for ( ; cur; cur = cur[dir] ) { + if ( cur.nodeType === 1 && ++num === result ) { + break; + } + } + + return cur; + }, + + sibling: function( n, elem ) { + var r = []; + + for ( ; n; n = n.nextSibling ) { + if ( n.nodeType === 1 && n !== elem ) { + r.push( n ); + } + } + + return r; + } +}); +var rinlinejQuery = / jQuery\d+="(?:\d+|null)"/g, + rleadingWhitespace = /^\s+/, + rxhtmlTag = /(<([\w:]+)[^>]*?)\/>/g, + rselfClosing = /^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i, + rtagName = /<([\w:]+)/, + rtbody = /"; + }, + wrapMap = { + option: [ 1, "" ], + legend: [ 1, "
", "
" ], + thead: [ 1, "", "
" ], + tr: [ 2, "", "
" ], + td: [ 3, "", "
" ], + col: [ 2, "", "
" ], + area: [ 1, "", "" ], + _default: [ 0, "", "" ] + }; + +wrapMap.optgroup = wrapMap.option; +wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; +wrapMap.th = wrapMap.td; + +// IE can't serialize and + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jqupload/basic-plus.html b/sources/library/jqupload/basic-plus.html new file mode 100644 index 00000000..dc90bd76 --- /dev/null +++ b/sources/library/jqupload/basic-plus.html @@ -0,0 +1,226 @@ + + + + + + + +jQuery File Upload Demo - Basic Plus version + + + + + + + + + + + +
+

jQuery File Upload Demo

+

Basic Plus version

+ +
+
+

File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery.
+ Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
+ Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

+
+
+ + + + Add files... + + + +
+
+ +
+
+
+ +
+
+
+
+

Demo Notes

+
+
+
    +
  • The maximum file size for uploads in this demo is 5 MB (default file size is unlimited).
  • +
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • +
  • Uploaded files will be deleted automatically after 5 minutes (demo setting).
  • +
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • +
  • Please refer to the project website and documentation for more information.
  • +
  • Built with Twitter's Bootstrap CSS framework and Icons from Glyphicons.
  • +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jqupload/basic.html b/sources/library/jqupload/basic.html new file mode 100644 index 00000000..ea5d0e66 --- /dev/null +++ b/sources/library/jqupload/basic.html @@ -0,0 +1,136 @@ + + + + + + + +jQuery File Upload Demo - Basic version + + + + + + + + + + + +
+

jQuery File Upload Demo

+

Basic version

+ +
+
+

File Upload widget with multiple file selection, drag&drop support and progress bar for jQuery.
+ Supports cross-domain, chunked and resumable file uploads.
+ Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

+
+
+ + + + Select files... + + + +
+
+ +
+
+
+ +
+
+
+
+

Demo Notes

+
+
+
    +
  • The maximum file size for uploads in this demo is 5 MB (default file size is unlimited).
  • +
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • +
  • Uploaded files will be deleted automatically after 5 minutes (demo setting).
  • +
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • +
  • Please refer to the project website and documentation for more information.
  • +
  • Built with Twitter's Bootstrap CSS framework and Icons from Glyphicons.
  • +
+
+
+
+ + + + + + + + + + + + diff --git a/sources/library/jqupload/blueimp-file-upload.jquery.json b/sources/library/jqupload/blueimp-file-upload.jquery.json new file mode 100644 index 00000000..8382fb4b --- /dev/null +++ b/sources/library/jqupload/blueimp-file-upload.jquery.json @@ -0,0 +1,50 @@ +{ + "name": "blueimp-file-upload", + "version": "9.5.2", + "title": "jQuery File Upload", + "author": { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + }, + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/MIT" + } + ], + "dependencies": { + "jquery": ">=1.6" + }, + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "keywords": [ + "jquery", + "file", + "upload", + "widget", + "multiple", + "selection", + "drag", + "drop", + "progress", + "preview", + "cross-domain", + "cross-site", + "chunk", + "resume", + "gae", + "go", + "python", + "php", + "bootstrap" + ], + "homepage": "https://github.com/blueimp/jQuery-File-Upload", + "docs": "https://github.com/blueimp/jQuery-File-Upload/wiki", + "demo": "http://blueimp.github.io/jQuery-File-Upload/", + "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", + "maintainers": [ + { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + } + ] +} diff --git a/sources/library/jqupload/bower.json b/sources/library/jqupload/bower.json new file mode 100644 index 00000000..54ba68f8 --- /dev/null +++ b/sources/library/jqupload/bower.json @@ -0,0 +1,85 @@ +{ + "name": "blueimp-file-upload", + "version": "9.5.2", + "title": "jQuery File Upload", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "keywords": [ + "jquery", + "file", + "upload", + "widget", + "multiple", + "selection", + "drag", + "drop", + "progress", + "preview", + "cross-domain", + "cross-site", + "chunk", + "resume", + "gae", + "go", + "python", + "php", + "bootstrap" + ], + "homepage": "https://github.com/blueimp/jQuery-File-Upload", + "author": { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + }, + "maintainers": [ + { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/blueimp/jQuery-File-Upload.git" + }, + "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/MIT" + } + ], + "dependencies": { + "jquery": ">=1.6", + "blueimp-tmpl": ">=2.5.3", + "blueimp-load-image": ">=1.11.0", + "blueimp-canvas-to-blob": ">=2.1.0" + }, + "main": [ + "css/jquery.fileupload.css", + "css/jquery.fileupload-ui.css", + "css/jquery.fileupload-noscript.css", + "css/jquery.fileupload-ui-noscript.css", + "js/cors/jquery.postmessage-transport.js", + "js/cors/jquery.xdr-transport.js", + "js/vendor/jquery.ui.widget.js", + "js/jquery.fileupload.js", + "js/jquery.fileupload-process.js", + "js/jquery.fileupload-validate.js", + "js/jquery.fileupload-image.js", + "js/jquery.fileupload-audio.js", + "js/jquery.fileupload-video.js", + "js/jquery.fileupload-ui.js", + "js/jquery.fileupload-jquery-ui.js", + "js/jquery.fileupload-angular.js", + "js/jquery.iframe-transport.js" + ], + "ignore": [ + "/*.*", + "/cors", + "css/demo-ie8.css", + "css/demo.css", + "css/style.css", + "js/app.js", + "js/main.js", + "server", + "test" + ] +} diff --git a/sources/library/jqupload/cors/postmessage.html b/sources/library/jqupload/cors/postmessage.html new file mode 100644 index 00000000..3d1448f0 --- /dev/null +++ b/sources/library/jqupload/cors/postmessage.html @@ -0,0 +1,75 @@ + + + + + +jQuery File Upload Plugin postMessage API + + + + + + \ No newline at end of file diff --git a/sources/library/jqupload/cors/result.html b/sources/library/jqupload/cors/result.html new file mode 100644 index 00000000..22513149 --- /dev/null +++ b/sources/library/jqupload/cors/result.html @@ -0,0 +1,24 @@ + + + + + +jQuery Iframe Transport Plugin Redirect Page + + + + + diff --git a/sources/library/jqupload/css/demo-ie8.css b/sources/library/jqupload/css/demo-ie8.css new file mode 100644 index 00000000..262493d0 --- /dev/null +++ b/sources/library/jqupload/css/demo-ie8.css @@ -0,0 +1,21 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Demo CSS Fixes for IE<9 1.0.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.navigation { + list-style: none; + padding: 0; + margin: 1em 0; +} +.navigation li { + display: inline; + margin-right: 10px; +} diff --git a/sources/library/jqupload/css/demo.css b/sources/library/jqupload/css/demo.css new file mode 100644 index 00000000..2b4d4393 --- /dev/null +++ b/sources/library/jqupload/css/demo.css @@ -0,0 +1,67 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Demo CSS 1.1.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +body { + max-width: 750px; + margin: 0 auto; + padding: 1em; + font-family: "Lucida Grande", "Lucida Sans Unicode", Arial, sans-serif; + font-size: 1em; + line-height: 1.4em; + background: #222; + color: #fff; + -webkit-text-size-adjust: 100%; + -ms-text-size-adjust: 100%; +} +a { + color: orange; + text-decoration: none; +} +img { + border: 0; + vertical-align: middle; +} +h1 { + line-height: 1em; +} +blockquote { + padding: 0 0 0 15px; + margin: 0 0 20px; + border-left: 5px solid #eee; +} +table { + width: 100%; + margin: 10px 0; +} + +.fileupload-progress { + margin: 10px 0; +} +.fileupload-progress .progress-extended { + margin-top: 5px; +} +.error { + color: red; +} + +@media (min-width: 481px) { + .navigation { + list-style: none; + padding: 0; + } + .navigation li { + display: inline-block; + } + .navigation li:not(:first-child):before { + content: "| "; + } +} diff --git a/sources/library/jqupload/css/jquery.fileupload-noscript.css b/sources/library/jqupload/css/jquery.fileupload-noscript.css new file mode 100644 index 00000000..64d728fc --- /dev/null +++ b/sources/library/jqupload/css/jquery.fileupload-noscript.css @@ -0,0 +1,22 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Plugin NoScript CSS 1.2.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileinput-button input { + position: static; + opacity: 1; + filter: none; + font-size: inherit; + direction: inherit; +} +.fileinput-button span { + display: none; +} diff --git a/sources/library/jqupload/css/jquery.fileupload-ui-noscript.css b/sources/library/jqupload/css/jquery.fileupload-ui-noscript.css new file mode 100644 index 00000000..87f110cd --- /dev/null +++ b/sources/library/jqupload/css/jquery.fileupload-ui-noscript.css @@ -0,0 +1,17 @@ +@charset "UTF-8"; +/* + * jQuery File Upload UI Plugin NoScript CSS 8.8.5 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2012, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileinput-button i, +.fileupload-buttonbar .delete, +.fileupload-buttonbar .toggle { + display: none; +} diff --git a/sources/library/jqupload/css/jquery.fileupload-ui.css b/sources/library/jqupload/css/jquery.fileupload-ui.css new file mode 100644 index 00000000..76fb376d --- /dev/null +++ b/sources/library/jqupload/css/jquery.fileupload-ui.css @@ -0,0 +1,57 @@ +@charset "UTF-8"; +/* + * jQuery File Upload UI Plugin CSS 9.0.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileupload-buttonbar .btn, +.fileupload-buttonbar .toggle { + margin-bottom: 5px; +} +.progress-animated .progress-bar, +.progress-animated .bar { + background: url("../img/progressbar.gif") !important; + filter: none; +} +.fileupload-process { + float: right; + display: none; +} +.fileupload-processing .fileupload-process, +.files .processing .preview { + display: block; + width: 32px; + height: 32px; + background: url("../img/loading.gif") center no-repeat; + background-size: contain; +} +.files audio, +.files video { + max-width: 300px; +} + +@media (max-width: 767px) { + .fileupload-buttonbar .toggle, + .files .toggle, + .files .btn span { + display: none; + } + .files .name { + width: 80px; + word-wrap: break-word; + } + .files audio, + .files video { + max-width: 80px; + } + .files img, + .files canvas { + max-width: 100%; + } +} diff --git a/sources/library/jqupload/css/jquery.fileupload.css b/sources/library/jqupload/css/jquery.fileupload.css new file mode 100644 index 00000000..fb6044d3 --- /dev/null +++ b/sources/library/jqupload/css/jquery.fileupload.css @@ -0,0 +1,36 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Plugin CSS 1.3.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +.fileinput-button { + position: relative; + overflow: hidden; +} +.fileinput-button input { + position: absolute; + top: 0; + right: 0; + margin: 0; + opacity: 0; + -ms-filter: 'alpha(opacity=0)'; + font-size: 200px; + direction: ltr; + cursor: pointer; +} + +/* Fixes for IE < 8 */ +@media screen\9 { + .fileinput-button input { + filter: alpha(opacity=0); + font-size: 100%; + height: 100%; + } +} diff --git a/sources/library/jqupload/css/style.css b/sources/library/jqupload/css/style.css new file mode 100644 index 00000000..b2c60a6f --- /dev/null +++ b/sources/library/jqupload/css/style.css @@ -0,0 +1,15 @@ +@charset "UTF-8"; +/* + * jQuery File Upload Plugin CSS Example 8.8.2 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +body { + padding-top: 60px; +} diff --git a/sources/library/jqupload/img/loading.gif b/sources/library/jqupload/img/loading.gif new file mode 100644 index 00000000..90f28cbd Binary files /dev/null and b/sources/library/jqupload/img/loading.gif differ diff --git a/sources/library/jqupload/img/progressbar.gif b/sources/library/jqupload/img/progressbar.gif new file mode 100644 index 00000000..fbcce6bc Binary files /dev/null and b/sources/library/jqupload/img/progressbar.gif differ diff --git a/sources/library/jqupload/index.html b/sources/library/jqupload/index.html new file mode 100644 index 00000000..a3a06aa9 --- /dev/null +++ b/sources/library/jqupload/index.html @@ -0,0 +1,255 @@ + + + + + + + +jQuery File Upload Demo + + + + + + + + + + + + + + + + + +
+

jQuery File Upload Demo

+

Basic Plus UI version

+ +
+
+

File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery.
+ Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
+ Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

+
+
+ +
+ + + +
+
+ + + + Add files... + + + + + + + + +
+ +
+ +
+
+
+ +
 
+
+
+ + +
+
+
+
+

Demo Notes

+
+
+
    +
  • The maximum file size for uploads in this demo is 5 MB (default file size is unlimited).
  • +
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • +
  • Uploaded files will be deleted automatically after 5 minutes (demo setting).
  • +
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • +
  • Please refer to the project website and documentation for more information.
  • +
  • Built with Twitter's Bootstrap CSS framework and Icons from Glyphicons.
  • +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jqupload/jquery-ui.html b/sources/library/jqupload/jquery-ui.html new file mode 100644 index 00000000..993a4c81 --- /dev/null +++ b/sources/library/jqupload/jquery-ui.html @@ -0,0 +1,250 @@ + + + + + + + +jQuery File Upload Demo - jQuery UI version + + + + + + + + + + + + + + + + + + + +

jQuery File Upload Demo

+

jQuery UI version

+
+ + +
+ +
+

File Upload widget with multiple file selection, drag&drop support, progress bars, validation and preview images, audio and video for jQuery UI.
+ Supports cross-domain, chunked and resumable file uploads and client-side image resizing.
+ Works with any server-side platform (PHP, Python, Ruby on Rails, Java, Node.js, Go etc.) that supports standard HTML form file uploads.

+
+ +
+ + + +
+
+ + + Add files... + + + + + + + + +
+ + +
+ +
+
+
+

Demo Notes

+
    +
  • The maximum file size for uploads in this demo is 5 MB (default file size is unlimited).
  • +
  • Only image files (JPG, GIF, PNG) are allowed in this demo (by default there is no file type restriction).
  • +
  • Uploaded files will be deleted automatically after 5 minutes (demo setting).
  • +
  • You can drag & drop files from your desktop on this webpage (see Browser support).
  • +
  • Please refer to the project website and documentation for more information.
  • +
  • Built with jQuery UI.
  • +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jqupload/js/app.js b/sources/library/jqupload/js/app.js new file mode 100644 index 00000000..47b4f923 --- /dev/null +++ b/sources/library/jqupload/js/app.js @@ -0,0 +1,101 @@ +/* + * jQuery File Upload Plugin Angular JS Example 1.2.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global window, angular */ + +(function () { + 'use strict'; + + var isOnGitHub = window.location.hostname === 'blueimp.github.io', + url = isOnGitHub ? '//jquery-file-upload.appspot.com/' : 'server/php/'; + + angular.module('demo', [ + 'blueimp.fileupload' + ]) + .config([ + '$httpProvider', 'fileUploadProvider', + function ($httpProvider, fileUploadProvider) { + delete $httpProvider.defaults.headers.common['X-Requested-With']; + fileUploadProvider.defaults.redirect = window.location.href.replace( + /\/[^\/]*$/, + '/cors/result.html?%s' + ); + if (isOnGitHub) { + // Demo settings: + angular.extend(fileUploadProvider.defaults, { + // Enable image resizing, except for Android and Opera, + // which actually support image resizing, but fail to + // send Blob objects via XHR requests: + disableImageResize: /Android(?!.*Chrome)|Opera/ + .test(window.navigator.userAgent), + maxFileSize: 5000000, + acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i + }); + } + } + ]) + + .controller('DemoFileUploadController', [ + '$scope', '$http', '$filter', '$window', + function ($scope, $http) { + $scope.options = { + url: url + }; + if (!isOnGitHub) { + $scope.loadingFiles = true; + $http.get(url) + .then( + function (response) { + $scope.loadingFiles = false; + $scope.queue = response.data.files || []; + }, + function () { + $scope.loadingFiles = false; + } + ); + } + } + ]) + + .controller('FileDestroyController', [ + '$scope', '$http', + function ($scope, $http) { + var file = $scope.file, + state; + if (file.url) { + file.$state = function () { + return state; + }; + file.$destroy = function () { + state = 'pending'; + return $http({ + url: file.deleteUrl, + method: file.deleteType + }).then( + function () { + state = 'resolved'; + $scope.clear(file); + }, + function () { + state = 'rejected'; + } + ); + }; + } else if (!file.$cancel && !file._index) { + file.$cancel = function () { + $scope.clear(file); + }; + } + } + ]); + +}()); diff --git a/sources/library/jqupload/js/cors/jquery.postmessage-transport.js b/sources/library/jqupload/js/cors/jquery.postmessage-transport.js new file mode 100644 index 00000000..2b4851e6 --- /dev/null +++ b/sources/library/jqupload/js/cors/jquery.postmessage-transport.js @@ -0,0 +1,117 @@ +/* + * jQuery postMessage Transport Plugin 1.1.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery'], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + + var counter = 0, + names = [ + 'accepts', + 'cache', + 'contents', + 'contentType', + 'crossDomain', + 'data', + 'dataType', + 'headers', + 'ifModified', + 'mimeType', + 'password', + 'processData', + 'timeout', + 'traditional', + 'type', + 'url', + 'username' + ], + convert = function (p) { + return p; + }; + + $.ajaxSetup({ + converters: { + 'postmessage text': convert, + 'postmessage json': convert, + 'postmessage html': convert + } + }); + + $.ajaxTransport('postmessage', function (options) { + if (options.postMessage && window.postMessage) { + var iframe, + loc = $('').prop('href', options.postMessage)[0], + target = loc.protocol + '//' + loc.host, + xhrUpload = options.xhr().upload; + return { + send: function (_, completeCallback) { + counter += 1; + var message = { + id: 'postmessage-transport-' + counter + }, + eventName = 'message.' + message.id; + iframe = $( + '' + ).bind('load', function () { + $.each(names, function (i, name) { + message[name] = options[name]; + }); + message.dataType = message.dataType.replace('postmessage ', ''); + $(window).bind(eventName, function (e) { + e = e.originalEvent; + var data = e.data, + ev; + if (e.origin === target && data.id === message.id) { + if (data.type === 'progress') { + ev = document.createEvent('Event'); + ev.initEvent(data.type, false, true); + $.extend(ev, data); + xhrUpload.dispatchEvent(ev); + } else { + completeCallback( + data.status, + data.statusText, + {postmessage: data.result}, + data.headers + ); + iframe.remove(); + $(window).unbind(eventName); + } + } + }); + iframe[0].contentWindow.postMessage( + message, + target + ); + }).appendTo(document.body); + }, + abort: function () { + if (iframe) { + iframe.remove(); + } + } + }; + } + }); + +})); diff --git a/sources/library/jqupload/js/cors/jquery.xdr-transport.js b/sources/library/jqupload/js/cors/jquery.xdr-transport.js new file mode 100644 index 00000000..0044cc2d --- /dev/null +++ b/sources/library/jqupload/js/cors/jquery.xdr-transport.js @@ -0,0 +1,86 @@ +/* + * jQuery XDomainRequest Transport Plugin 1.1.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + * + * Based on Julian Aubourg's ajaxHooks xdr.js: + * https://github.com/jaubourg/ajaxHooks/ + */ + +/* global define, window, XDomainRequest */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery'], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + if (window.XDomainRequest && !$.support.cors) { + $.ajaxTransport(function (s) { + if (s.crossDomain && s.async) { + if (s.timeout) { + s.xdrTimeout = s.timeout; + delete s.timeout; + } + var xdr; + return { + send: function (headers, completeCallback) { + var addParamChar = /\?/.test(s.url) ? '&' : '?'; + function callback(status, statusText, responses, responseHeaders) { + xdr.onload = xdr.onerror = xdr.ontimeout = $.noop; + xdr = null; + completeCallback(status, statusText, responses, responseHeaders); + } + xdr = new XDomainRequest(); + // XDomainRequest only supports GET and POST: + if (s.type === 'DELETE') { + s.url = s.url + addParamChar + '_method=DELETE'; + s.type = 'POST'; + } else if (s.type === 'PUT') { + s.url = s.url + addParamChar + '_method=PUT'; + s.type = 'POST'; + } else if (s.type === 'PATCH') { + s.url = s.url + addParamChar + '_method=PATCH'; + s.type = 'POST'; + } + xdr.open(s.type, s.url); + xdr.onload = function () { + callback( + 200, + 'OK', + {text: xdr.responseText}, + 'Content-Type: ' + xdr.contentType + ); + }; + xdr.onerror = function () { + callback(404, 'Not Found'); + }; + if (s.xdrTimeout) { + xdr.ontimeout = function () { + callback(0, 'timeout'); + }; + xdr.timeout = s.xdrTimeout; + } + xdr.send((s.hasContent && s.data) || null); + }, + abort: function () { + if (xdr) { + xdr.onerror = $.noop(); + xdr.abort(); + } + } + }; + } + }); + } +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-angular.js b/sources/library/jqupload/js/jquery.fileupload-angular.js new file mode 100644 index 00000000..666f5142 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-angular.js @@ -0,0 +1,428 @@ +/* + * jQuery File Upload AngularJS Plugin 2.1.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, angular */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'angular', + './jquery.fileupload-image', + './jquery.fileupload-audio', + './jquery.fileupload-video', + './jquery.fileupload-validate' + ], factory); + } else { + factory(); + } +}(function () { + 'use strict'; + + angular.module('blueimp.fileupload', []) + + // The fileUpload service provides configuration options + // for the fileUpload directive and default handlers for + // File Upload events: + .provider('fileUpload', function () { + var scopeEvalAsync = function (expression) { + var scope = angular.element(this) + .fileupload('option', 'scope')(); + // Schedule a new $digest cycle if not already inside of one + // and evaluate the given expression: + scope.$evalAsync(expression); + }, + addFileMethods = function (scope, data) { + var files = data.files, + file = files[0]; + angular.forEach(files, function (file, index) { + file._index = index; + file.$state = function () { + return data.state(); + }; + file.$processing = function () { + return data.processing(); + }; + file.$progress = function () { + return data.progress(); + }; + file.$response = function () { + return data.response(); + }; + }); + file.$submit = function () { + if (!file.error) { + return data.submit(); + } + }; + file.$cancel = function () { + return data.abort(); + }; + }, + $config; + $config = this.defaults = { + handleResponse: function (e, data) { + var files = data.result && data.result.files; + if (files) { + data.scope().replace(data.files, files); + } else if (data.errorThrown || + data.textStatus === 'error') { + data.files[0].error = data.errorThrown || + data.textStatus; + } + }, + add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var scope = data.scope(), + filesCopy = []; + angular.forEach(data.files, function (file) { + filesCopy.push(file); + }); + scope.$apply(function () { + addFileMethods(scope, data); + var method = scope.option('prependFiles') ? + 'unshift' : 'push'; + Array.prototype[method].apply(scope.queue, data.files); + }); + data.process(function () { + return scope.process(data); + }).always(function () { + scope.$apply(function () { + addFileMethods(scope, data); + scope.replace(filesCopy, data.files); + }); + }).then(function () { + if ((scope.option('autoUpload') || + data.autoUpload) && + data.autoUpload !== false) { + data.submit(); + } + }); + }, + progress: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + data.scope().$apply(); + }, + done: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = this; + data.scope().$apply(function () { + data.handleResponse.call(that, e, data); + }); + }, + fail: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = this, + scope = data.scope(); + if (data.errorThrown === 'abort') { + scope.clear(data.files); + return; + } + scope.$apply(function () { + data.handleResponse.call(that, e, data); + }); + }, + stop: scopeEvalAsync, + processstart: scopeEvalAsync, + processstop: scopeEvalAsync, + getNumberOfFiles: function () { + var scope = this.scope(); + return scope.queue.length - scope.processing(); + }, + dataType: 'json', + autoUpload: false + }; + this.$get = [ + function () { + return { + defaults: $config + }; + } + ]; + }) + + // Format byte numbers to readable presentations: + .provider('formatFileSizeFilter', function () { + var $config = { + // Byte units following the IEC format + // http://en.wikipedia.org/wiki/Kilobyte + units: [ + {size: 1000000000, suffix: ' GB'}, + {size: 1000000, suffix: ' MB'}, + {size: 1000, suffix: ' KB'} + ] + }; + this.defaults = $config; + this.$get = function () { + return function (bytes) { + if (!angular.isNumber(bytes)) { + return ''; + } + var unit = true, + i = 0, + prefix, + suffix; + while (unit) { + unit = $config.units[i]; + prefix = unit.prefix || ''; + suffix = unit.suffix || ''; + if (i === $config.units.length - 1 || bytes >= unit.size) { + return prefix + (bytes / unit.size).toFixed(2) + suffix; + } + i += 1; + } + }; + }; + }) + + // The FileUploadController initializes the fileupload widget and + // provides scope methods to control the File Upload functionality: + .controller('FileUploadController', [ + '$scope', '$element', '$attrs', '$window', 'fileUpload', + function ($scope, $element, $attrs, $window, fileUpload) { + var uploadMethods = { + progress: function () { + return $element.fileupload('progress'); + }, + active: function () { + return $element.fileupload('active'); + }, + option: function (option, data) { + return $element.fileupload('option', option, data); + }, + add: function (data) { + return $element.fileupload('add', data); + }, + send: function (data) { + return $element.fileupload('send', data); + }, + process: function (data) { + return $element.fileupload('process', data); + }, + processing: function (data) { + return $element.fileupload('processing', data); + } + }; + $scope.disabled = !$window.jQuery.support.fileInput; + $scope.queue = $scope.queue || []; + $scope.clear = function (files) { + var queue = this.queue, + i = queue.length, + file = files, + length = 1; + if (angular.isArray(files)) { + file = files[0]; + length = files.length; + } + while (i) { + i -= 1; + if (queue[i] === file) { + return queue.splice(i, length); + } + } + }; + $scope.replace = function (oldFiles, newFiles) { + var queue = this.queue, + file = oldFiles[0], + i, + j; + for (i = 0; i < queue.length; i += 1) { + if (queue[i] === file) { + for (j = 0; j < newFiles.length; j += 1) { + queue[i + j] = newFiles[j]; + } + return; + } + } + }; + $scope.applyOnQueue = function (method) { + var list = this.queue.slice(0), + i, + file; + for (i = 0; i < list.length; i += 1) { + file = list[i]; + if (file[method]) { + file[method](); + } + } + }; + $scope.submit = function () { + this.applyOnQueue('$submit'); + }; + $scope.cancel = function () { + this.applyOnQueue('$cancel'); + }; + // Add upload methods to the scope: + angular.extend($scope, uploadMethods); + // The fileupload widget will initialize with + // the options provided via "data-"-parameters, + // as well as those given via options object: + $element.fileupload(angular.extend( + {scope: function () { + return $scope; + }}, + fileUpload.defaults + )).on('fileuploadadd', function (e, data) { + data.scope = $scope.option('scope'); + }).on('fileuploadfail', function (e, data) { + if (data.errorThrown === 'abort') { + return; + } + if (data.dataType && + data.dataType.indexOf('json') === data.dataType.length - 4) { + try { + data.result = angular.fromJson(data.jqXHR.responseText); + } catch (ignore) {} + } + }).on([ + 'fileuploadadd', + 'fileuploadsubmit', + 'fileuploadsend', + 'fileuploaddone', + 'fileuploadfail', + 'fileuploadalways', + 'fileuploadprogress', + 'fileuploadprogressall', + 'fileuploadstart', + 'fileuploadstop', + 'fileuploadchange', + 'fileuploadpaste', + 'fileuploaddrop', + 'fileuploaddragover', + 'fileuploadchunksend', + 'fileuploadchunkdone', + 'fileuploadchunkfail', + 'fileuploadchunkalways', + 'fileuploadprocessstart', + 'fileuploadprocess', + 'fileuploadprocessdone', + 'fileuploadprocessfail', + 'fileuploadprocessalways', + 'fileuploadprocessstop' + ].join(' '), function (e, data) { + if ($scope.$emit(e.type, data).defaultPrevented) { + e.preventDefault(); + } + }).on('remove', function () { + // Remove upload methods from the scope, + // when the widget is removed: + var method; + for (method in uploadMethods) { + if (uploadMethods.hasOwnProperty(method)) { + delete $scope[method]; + } + } + }); + // Observe option changes: + $scope.$watch( + $attrs.fileUpload, + function (newOptions) { + if (newOptions) { + $element.fileupload('option', newOptions); + } + } + ); + } + ]) + + // Provide File Upload progress feedback: + .controller('FileUploadProgressController', [ + '$scope', '$attrs', '$parse', + function ($scope, $attrs, $parse) { + var fn = $parse($attrs.fileUploadProgress), + update = function () { + var progress = fn($scope); + if (!progress || !progress.total) { + return; + } + $scope.num = Math.floor( + progress.loaded / progress.total * 100 + ); + }; + update(); + $scope.$watch( + $attrs.fileUploadProgress + '.loaded', + function (newValue, oldValue) { + if (newValue !== oldValue) { + update(); + } + } + ); + } + ]) + + // Display File Upload previews: + .controller('FileUploadPreviewController', [ + '$scope', '$element', '$attrs', + function ($scope, $element, $attrs) { + $scope.$watch( + $attrs.fileUploadPreview + '.preview', + function (preview) { + $element.empty(); + if (preview) { + $element.append(preview); + } + } + ); + } + ]) + + .directive('fileUpload', function () { + return { + controller: 'FileUploadController', + scope: true + }; + }) + + .directive('fileUploadProgress', function () { + return { + controller: 'FileUploadProgressController', + scope: true + }; + }) + + .directive('fileUploadPreview', function () { + return { + controller: 'FileUploadPreviewController' + }; + }) + + // Enhance the HTML5 download attribute to + // allow drag&drop of files to the desktop: + .directive('download', function () { + return function (scope, elm) { + elm.on('dragstart', function (e) { + try { + e.originalEvent.dataTransfer.setData( + 'DownloadURL', + [ + 'application/octet-stream', + elm.prop('download'), + elm.prop('href') + ].join(':') + ); + } catch (ignore) {} + }); + }; + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-audio.js b/sources/library/jqupload/js/jquery.fileupload-audio.js new file mode 100644 index 00000000..575800e8 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-audio.js @@ -0,0 +1,106 @@ +/* + * jQuery File Upload Audio Preview Plugin 1.0.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadAudio', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + disabled: '@disableAudioPreview' + }, + { + action: 'setAudio', + name: '@audioPreviewName', + disabled: '@disableAudioPreview' + } + ); + + // The File Upload Audio Preview plugin extends the fileupload widget + // with audio preview functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of audio files to load, + // matched against the file type: + loadAudioFileTypes: /^audio\/.*$/ + }, + + _audioElement: document.createElement('audio'), + + processActions: { + + // Loads the audio file given via data.files and data.index + // as audio element if the browser supports playing it. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadAudio: function (data, options) { + if (options.disabled) { + return data; + } + var file = data.files[data.index], + url, + audio; + if (this._audioElement.canPlayType && + this._audioElement.canPlayType(file.type) && + ($.type(options.maxFileSize) !== 'number' || + file.size <= options.maxFileSize) && + (!options.fileTypes || + options.fileTypes.test(file.type))) { + url = loadImage.createObjectURL(file); + if (url) { + audio = this._audioElement.cloneNode(false); + audio.src = url; + audio.controls = true; + data.audio = audio; + return data; + } + } + return data; + }, + + // Sets the audio element as a property of the file object: + setAudio: function (data, options) { + if (data.audio && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.audio; + } + return data; + } + + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-image.js b/sources/library/jqupload/js/jquery.fileupload-image.js new file mode 100644 index 00000000..8fbf7d42 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-image.js @@ -0,0 +1,309 @@ +/* + * jQuery File Upload Image Preview & Resize Plugin 1.7.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, Blob */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + 'load-image-meta', + 'load-image-exif', + 'load-image-ios', + 'canvas-to-blob', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadImageMetaData', + disableImageHead: '@', + disableExif: '@', + disableExifThumbnail: '@', + disableExifSub: '@', + disableExifGps: '@', + disabled: '@disableImageMetaDataLoad' + }, + { + action: 'loadImage', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + noRevoke: '@', + disabled: '@disableImageLoad' + }, + { + action: 'resizeImage', + // Use "image" as prefix for the "@" options: + prefix: 'image', + maxWidth: '@', + maxHeight: '@', + minWidth: '@', + minHeight: '@', + crop: '@', + orientation: '@', + forceResize: '@', + disabled: '@disableImageResize' + }, + { + action: 'saveImage', + quality: '@imageQuality', + type: '@imageType', + disabled: '@disableImageResize' + }, + { + action: 'saveImageMetaData', + disabled: '@disableImageMetaDataSave' + }, + { + action: 'resizeImage', + // Use "preview" as prefix for the "@" options: + prefix: 'preview', + maxWidth: '@', + maxHeight: '@', + minWidth: '@', + minHeight: '@', + crop: '@', + orientation: '@', + thumbnail: '@', + canvas: '@', + disabled: '@disableImagePreview' + }, + { + action: 'setImage', + name: '@imagePreviewName', + disabled: '@disableImagePreview' + }, + { + action: 'deleteImageReferences', + disabled: '@disableImageReferencesDeletion' + } + ); + + // The File Upload Resize plugin extends the fileupload widget + // with image resize functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of images to load: + // matched against the file type: + loadImageFileTypes: /^image\/(gif|jpeg|png)$/, + // The maximum file size of images to load: + loadImageMaxFileSize: 10000000, // 10MB + // The maximum width of resized images: + imageMaxWidth: 1920, + // The maximum height of resized images: + imageMaxHeight: 1080, + // Defines the image orientation (1-8) or takes the orientation + // value from Exif data if set to true: + imageOrientation: false, + // Define if resized images should be cropped or only scaled: + imageCrop: false, + // Disable the resize image functionality by default: + disableImageResize: true, + // The maximum width of the preview images: + previewMaxWidth: 80, + // The maximum height of the preview images: + previewMaxHeight: 80, + // Defines the preview orientation (1-8) or takes the orientation + // value from Exif data if set to true: + previewOrientation: true, + // Create the preview using the Exif data thumbnail: + previewThumbnail: true, + // Define if preview images should be cropped or only scaled: + previewCrop: false, + // Define if preview images should be resized as canvas elements: + previewCanvas: true + }, + + processActions: { + + // Loads the image given via data.files and data.index + // as img element, if the browser supports the File API. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadImage: function (data, options) { + if (options.disabled) { + return data; + } + var that = this, + file = data.files[data.index], + dfd = $.Deferred(); + if (($.type(options.maxFileSize) === 'number' && + file.size > options.maxFileSize) || + (options.fileTypes && + !options.fileTypes.test(file.type)) || + !loadImage( + file, + function (img) { + if (img.src) { + data.img = img; + } + dfd.resolveWith(that, [data]); + }, + options + )) { + return data; + } + return dfd.promise(); + }, + + // Resizes the image given as data.canvas or data.img + // and updates data.canvas or data.img with the resized image. + // Also stores the resized image as preview property. + // Accepts the options maxWidth, maxHeight, minWidth, + // minHeight, canvas and crop: + resizeImage: function (data, options) { + if (options.disabled || !(data.canvas || data.img)) { + return data; + } + options = $.extend({canvas: true}, options); + var that = this, + dfd = $.Deferred(), + img = (options.canvas && data.canvas) || data.img, + resolve = function (newImg) { + if (newImg && (newImg.width !== img.width || + newImg.height !== img.height || + options.forceResize)) { + data[newImg.getContext ? 'canvas' : 'img'] = newImg; + } + data.preview = newImg; + dfd.resolveWith(that, [data]); + }, + thumbnail; + if (data.exif) { + if (options.orientation === true) { + options.orientation = data.exif.get('Orientation'); + } + if (options.thumbnail) { + thumbnail = data.exif.get('Thumbnail'); + if (thumbnail) { + loadImage(thumbnail, resolve, options); + return dfd.promise(); + } + } + } + if (img) { + resolve(loadImage.scale(img, options)); + return dfd.promise(); + } + return data; + }, + + // Saves the processed image given as data.canvas + // inplace at data.index of data.files: + saveImage: function (data, options) { + if (!data.canvas || options.disabled) { + return data; + } + var that = this, + file = data.files[data.index], + dfd = $.Deferred(); + if (data.canvas.toBlob) { + data.canvas.toBlob( + function (blob) { + if (!blob.name) { + if (file.type === blob.type) { + blob.name = file.name; + } else if (file.name) { + blob.name = file.name.replace( + /\..+$/, + '.' + blob.type.substr(6) + ); + } + } + // Don't restore invalid meta data: + if (file.type !== blob.type) { + delete data.imageHead; + } + // Store the created blob at the position + // of the original file in the files list: + data.files[data.index] = blob; + dfd.resolveWith(that, [data]); + }, + options.type || file.type, + options.quality + ); + } else { + return data; + } + return dfd.promise(); + }, + + loadImageMetaData: function (data, options) { + if (options.disabled) { + return data; + } + var that = this, + dfd = $.Deferred(); + loadImage.parseMetaData(data.files[data.index], function (result) { + $.extend(data, result); + dfd.resolveWith(that, [data]); + }, options); + return dfd.promise(); + }, + + saveImageMetaData: function (data, options) { + if (!(data.imageHead && data.canvas && + data.canvas.toBlob && !options.disabled)) { + return data; + } + var file = data.files[data.index], + blob = new Blob([ + data.imageHead, + // Resized images always have a head size of 20 bytes, + // including the JPEG marker and a minimal JFIF header: + this._blobSlice.call(file, 20) + ], {type: file.type}); + blob.name = file.name; + data.files[data.index] = blob; + return data; + }, + + // Sets the resized version of the image as a property of the + // file object, must be called after "saveImage": + setImage: function (data, options) { + if (data.preview && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.preview; + } + return data; + }, + + deleteImageReferences: function (data, options) { + if (!options.disabled) { + delete data.img; + delete data.canvas; + delete data.preview; + delete data.imageHead; + } + return data; + } + + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-jquery-ui.js b/sources/library/jqupload/js/jquery.fileupload-jquery-ui.js new file mode 100755 index 00000000..7b4ffdf0 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-jquery-ui.js @@ -0,0 +1,144 @@ +/* + * jQuery File Upload jQuery UI Plugin 8.7.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery', './jquery.fileupload-ui'], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + progress: function (e, data) { + if (data.context) { + data.context.find('.progress').progressbar( + 'option', + 'value', + parseInt(data.loaded / data.total * 100, 10) + ); + } + }, + progressall: function (e, data) { + var $this = $(this); + $this.find('.fileupload-progress') + .find('.progress').progressbar( + 'option', + 'value', + parseInt(data.loaded / data.total * 100, 10) + ).end() + .find('.progress-extended').each(function () { + $(this).html( + ($this.data('blueimp-fileupload') || + $this.data('fileupload')) + ._renderExtendedProgress(data) + ); + }); + } + }, + + _renderUpload: function (func, files) { + var node = this._super(func, files), + showIconText = $(window).width() > 480; + node.find('.progress').empty().progressbar(); + node.find('.start').button({ + icons: {primary: 'ui-icon-circle-arrow-e'}, + text: showIconText + }); + node.find('.cancel').button({ + icons: {primary: 'ui-icon-cancel'}, + text: showIconText + }); + if (node.hasClass('fade')) { + node.hide(); + } + return node; + }, + + _renderDownload: function (func, files) { + var node = this._super(func, files), + showIconText = $(window).width() > 480; + node.find('.delete').button({ + icons: {primary: 'ui-icon-trash'}, + text: showIconText + }); + if (node.hasClass('fade')) { + node.hide(); + } + return node; + }, + + _transition: function (node) { + var deferred = $.Deferred(); + if (node.hasClass('fade')) { + node.fadeToggle( + this.options.transitionDuration, + this.options.transitionEasing, + function () { + deferred.resolveWith(node); + } + ); + } else { + deferred.resolveWith(node); + } + return deferred; + }, + + _create: function () { + this._super(); + this.element + .find('.fileupload-buttonbar') + .find('.fileinput-button').each(function () { + var input = $(this).find('input:file').detach(); + $(this) + .button({icons: {primary: 'ui-icon-plusthick'}}) + .append(input); + }) + .end().find('.start') + .button({icons: {primary: 'ui-icon-circle-arrow-e'}}) + .end().find('.cancel') + .button({icons: {primary: 'ui-icon-cancel'}}) + .end().find('.delete') + .button({icons: {primary: 'ui-icon-trash'}}) + .end().find('.progress').progressbar(); + }, + + _destroy: function () { + this.element + .find('.fileupload-buttonbar') + .find('.fileinput-button').each(function () { + var input = $(this).find('input:file').detach(); + $(this) + .button('destroy') + .append(input); + }) + .end().find('.start') + .button('destroy') + .end().find('.cancel') + .button('destroy') + .end().find('.delete') + .button('destroy') + .end().find('.progress').progressbar('destroy'); + this._super(); + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-process.js b/sources/library/jqupload/js/jquery.fileupload-process.js new file mode 100644 index 00000000..8a6b929a --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-process.js @@ -0,0 +1,172 @@ +/* + * jQuery File Upload Processing Plugin 1.3.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2012, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + './jquery.fileupload' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery + ); + } +}(function ($) { + 'use strict'; + + var originalAdd = $.blueimp.fileupload.prototype.options.add; + + // The File Upload Processing plugin extends the fileupload widget + // with file processing functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The list of processing actions: + processQueue: [ + /* + { + action: 'log', + type: 'debug' + } + */ + ], + add: function (e, data) { + var $this = $(this); + data.process(function () { + return $this.fileupload('process', data); + }); + originalAdd.call(this, e, data); + } + }, + + processActions: { + /* + log: function (data, options) { + console[options.type]( + 'Processing "' + data.files[data.index].name + '"' + ); + } + */ + }, + + _processFile: function (data, originalData) { + var that = this, + dfd = $.Deferred().resolveWith(that, [data]), + chain = dfd.promise(); + this._trigger('process', null, data); + $.each(data.processQueue, function (i, settings) { + var func = function (data) { + if (originalData.errorThrown) { + return $.Deferred() + .rejectWith(that, [originalData]).promise(); + } + return that.processActions[settings.action].call( + that, + data, + settings + ); + }; + chain = chain.pipe(func, settings.always && func); + }); + chain + .done(function () { + that._trigger('processdone', null, data); + that._trigger('processalways', null, data); + }) + .fail(function () { + that._trigger('processfail', null, data); + that._trigger('processalways', null, data); + }); + return chain; + }, + + // Replaces the settings of each processQueue item that + // are strings starting with an "@", using the remaining + // substring as key for the option map, + // e.g. "@autoUpload" is replaced with options.autoUpload: + _transformProcessQueue: function (options) { + var processQueue = []; + $.each(options.processQueue, function () { + var settings = {}, + action = this.action, + prefix = this.prefix === true ? action : this.prefix; + $.each(this, function (key, value) { + if ($.type(value) === 'string' && + value.charAt(0) === '@') { + settings[key] = options[ + value.slice(1) || (prefix ? prefix + + key.charAt(0).toUpperCase() + key.slice(1) : key) + ]; + } else { + settings[key] = value; + } + + }); + processQueue.push(settings); + }); + options.processQueue = processQueue; + }, + + // Returns the number of files currently in the processsing queue: + processing: function () { + return this._processing; + }, + + // Processes the files given as files property of the data parameter, + // returns a Promise object that allows to bind callbacks: + process: function (data) { + var that = this, + options = $.extend({}, this.options, data); + if (options.processQueue && options.processQueue.length) { + this._transformProcessQueue(options); + if (this._processing === 0) { + this._trigger('processstart'); + } + $.each(data.files, function (index) { + var opts = index ? $.extend({}, options) : options, + func = function () { + if (data.errorThrown) { + return $.Deferred() + .rejectWith(that, [data]).promise(); + } + return that._processFile(opts, data); + }; + opts.index = index; + that._processing += 1; + that._processingQueue = that._processingQueue.pipe(func, func) + .always(function () { + that._processing -= 1; + if (that._processing === 0) { + that._trigger('processstop'); + } + }); + }); + } + return this._processingQueue; + }, + + _create: function () { + this._super(); + this._processing = 0; + this._processingQueue = $.Deferred().resolveWith(this) + .promise(); + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-ui.js b/sources/library/jqupload/js/jquery.fileupload-ui.js new file mode 100644 index 00000000..417edb73 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-ui.js @@ -0,0 +1,701 @@ +/* + * jQuery File Upload User Interface Plugin 9.5.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'tmpl', + './jquery.fileupload-image', + './jquery.fileupload-audio', + './jquery.fileupload-video', + './jquery.fileupload-validate' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.tmpl + ); + } +}(function ($, tmpl) { + 'use strict'; + + $.blueimp.fileupload.prototype._specialOptions.push( + 'filesContainer', + 'uploadTemplateId', + 'downloadTemplateId' + ); + + // The UI version extends the file upload widget + // and adds complete user interface interaction: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // By default, files added to the widget are uploaded as soon + // as the user clicks on the start buttons. To enable automatic + // uploads, set the following option to true: + autoUpload: false, + // The ID of the upload template: + uploadTemplateId: 'template-upload', + // The ID of the download template: + downloadTemplateId: 'template-download', + // The container for the list of files. If undefined, it is set to + // an element with class "files" inside of the widget element: + filesContainer: undefined, + // By default, files are appended to the files container. + // Set the following option to true, to prepend files instead: + prependFiles: false, + // The expected data type of the upload response, sets the dataType + // option of the $.ajax upload requests: + dataType: 'json', + + // Function returning the current number of files, + // used by the maxNumberOfFiles validation: + getNumberOfFiles: function () { + return this.filesContainer.children() + .not('.processing').length; + }, + + // Callback to retrieve the list of files from the server response: + getFilesFromResponse: function (data) { + if (data.result && $.isArray(data.result.files)) { + return data.result.files; + } + return []; + }, + + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop or add API call). + // See the basic file upload widget for more information: + add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var $this = $(this), + that = $this.data('blueimp-fileupload') || + $this.data('fileupload'), + options = that.options; + data.context = that._renderUpload(data.files) + .data('data', data) + .addClass('processing'); + options.filesContainer[ + options.prependFiles ? 'prepend' : 'append' + ](data.context); + that._forceReflow(data.context); + $.when( + that._transition(data.context), + data.process(function () { + return $this.fileupload('process', data); + }) + ).always(function () { + data.context.each(function (index) { + $(this).find('.size').text( + that._formatFileSize(data.files[index].size) + ); + }).removeClass('processing'); + that._renderPreviews(data); + }).done(function () { + data.context.find('.start').prop('disabled', false); + if ((that._trigger('added', e, data) !== false) && + (options.autoUpload || data.autoUpload) && + data.autoUpload !== false) { + data.submit(); + } + }).fail(function () { + if (data.files.error) { + data.context.each(function (index) { + var error = data.files[index].error; + if (error) { + $(this).find('.error').text(error); + } + }); + } + }); + }, + // Callback for the start of each file upload request: + send: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'); + if (data.context && data.dataType && + data.dataType.substr(0, 6) === 'iframe') { + // Iframe Transport does not support progress events. + // In lack of an indeterminate progress bar, we set + // the progress to 100%, showing the full animated bar: + data.context + .find('.progress').addClass( + !$.support.transition && 'progress-animated' + ) + .attr('aria-valuenow', 100) + .children().first().css( + 'width', + '100%' + ); + } + return that._trigger('sent', e, data); + }, + // Callback for successful uploads: + done: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'), + getFilesFromResponse = data.getFilesFromResponse || + that.options.getFilesFromResponse, + files = getFilesFromResponse(data), + template, + deferred; + if (data.context) { + data.context.each(function (index) { + var file = files[index] || + {error: 'Empty file upload result'}; + deferred = that._addFinishedDeferreds(); + that._transition($(this)).done( + function () { + var node = $(this); + template = that._renderDownload([file]) + .replaceAll(node); + that._forceReflow(template); + that._transition(template).done( + function () { + data.context = $(this); + that._trigger('completed', e, data); + that._trigger('finished', e, data); + deferred.resolve(); + } + ); + } + ); + }); + } else { + template = that._renderDownload(files)[ + that.options.prependFiles ? 'prependTo' : 'appendTo' + ](that.options.filesContainer); + that._forceReflow(template); + deferred = that._addFinishedDeferreds(); + that._transition(template).done( + function () { + data.context = $(this); + that._trigger('completed', e, data); + that._trigger('finished', e, data); + deferred.resolve(); + } + ); + } + }, + // Callback for failed (abort or error) uploads: + fail: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'), + template, + deferred; + if (data.context) { + data.context.each(function (index) { + if (data.errorThrown !== 'abort') { + var file = data.files[index]; + file.error = file.error || data.errorThrown || + true; + deferred = that._addFinishedDeferreds(); + that._transition($(this)).done( + function () { + var node = $(this); + template = that._renderDownload([file]) + .replaceAll(node); + that._forceReflow(template); + that._transition(template).done( + function () { + data.context = $(this); + that._trigger('failed', e, data); + that._trigger('finished', e, data); + deferred.resolve(); + } + ); + } + ); + } else { + deferred = that._addFinishedDeferreds(); + that._transition($(this)).done( + function () { + $(this).remove(); + that._trigger('failed', e, data); + that._trigger('finished', e, data); + deferred.resolve(); + } + ); + } + }); + } else if (data.errorThrown !== 'abort') { + data.context = that._renderUpload(data.files)[ + that.options.prependFiles ? 'prependTo' : 'appendTo' + ](that.options.filesContainer) + .data('data', data); + that._forceReflow(data.context); + deferred = that._addFinishedDeferreds(); + that._transition(data.context).done( + function () { + data.context = $(this); + that._trigger('failed', e, data); + that._trigger('finished', e, data); + deferred.resolve(); + } + ); + } else { + that._trigger('failed', e, data); + that._trigger('finished', e, data); + that._addFinishedDeferreds().resolve(); + } + }, + // Callback for upload progress events: + progress: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var progress = Math.floor(data.loaded / data.total * 100); + if (data.context) { + data.context.each(function () { + $(this).find('.progress') + .attr('aria-valuenow', progress) + .children().first().css( + 'width', + progress + '%' + ); + }); + } + }, + // Callback for global upload progress events: + progressall: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var $this = $(this), + progress = Math.floor(data.loaded / data.total * 100), + globalProgressNode = $this.find('.fileupload-progress'), + extendedProgressNode = globalProgressNode + .find('.progress-extended'); + if (extendedProgressNode.length) { + extendedProgressNode.html( + ($this.data('blueimp-fileupload') || $this.data('fileupload')) + ._renderExtendedProgress(data) + ); + } + globalProgressNode + .find('.progress') + .attr('aria-valuenow', progress) + .children().first().css( + 'width', + progress + '%' + ); + }, + // Callback for uploads start, equivalent to the global ajaxStart event: + start: function (e) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'); + that._resetFinishedDeferreds(); + that._transition($(this).find('.fileupload-progress')).done( + function () { + that._trigger('started', e); + } + ); + }, + // Callback for uploads stop, equivalent to the global ajaxStop event: + stop: function (e) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'), + deferred = that._addFinishedDeferreds(); + $.when.apply($, that._getFinishedDeferreds()) + .done(function () { + that._trigger('stopped', e); + }); + that._transition($(this).find('.fileupload-progress')).done( + function () { + $(this).find('.progress') + .attr('aria-valuenow', '0') + .children().first().css('width', '0%'); + $(this).find('.progress-extended').html(' '); + deferred.resolve(); + } + ); + }, + processstart: function (e) { + if (e.isDefaultPrevented()) { + return false; + } + $(this).addClass('fileupload-processing'); + }, + processstop: function (e) { + if (e.isDefaultPrevented()) { + return false; + } + $(this).removeClass('fileupload-processing'); + }, + // Callback for file deletion: + destroy: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + var that = $(this).data('blueimp-fileupload') || + $(this).data('fileupload'), + removeNode = function () { + that._transition(data.context).done( + function () { + $(this).remove(); + that._trigger('destroyed', e, data); + } + ); + }; + if (data.url) { + data.dataType = data.dataType || that.options.dataType; + $.ajax(data).done(removeNode).fail(function () { + that._trigger('destroyfailed', e, data); + }); + } else { + removeNode(); + } + } + }, + + _resetFinishedDeferreds: function () { + this._finishedUploads = []; + }, + + _addFinishedDeferreds: function (deferred) { + if (!deferred) { + deferred = $.Deferred(); + } + this._finishedUploads.push(deferred); + return deferred; + }, + + _getFinishedDeferreds: function () { + return this._finishedUploads; + }, + + // Link handler, that allows to download files + // by drag & drop of the links to the desktop: + _enableDragToDesktop: function () { + var link = $(this), + url = link.prop('href'), + name = link.prop('download'), + type = 'application/octet-stream'; + link.bind('dragstart', function (e) { + try { + e.originalEvent.dataTransfer.setData( + 'DownloadURL', + [type, name, url].join(':') + ); + } catch (ignore) {} + }); + }, + + _formatFileSize: function (bytes) { + if (typeof bytes !== 'number') { + return ''; + } + if (bytes >= 1000000000) { + return (bytes / 1000000000).toFixed(2) + ' GB'; + } + if (bytes >= 1000000) { + return (bytes / 1000000).toFixed(2) + ' MB'; + } + return (bytes / 1000).toFixed(2) + ' KB'; + }, + + _formatBitrate: function (bits) { + if (typeof bits !== 'number') { + return ''; + } + if (bits >= 1000000000) { + return (bits / 1000000000).toFixed(2) + ' Gbit/s'; + } + if (bits >= 1000000) { + return (bits / 1000000).toFixed(2) + ' Mbit/s'; + } + if (bits >= 1000) { + return (bits / 1000).toFixed(2) + ' kbit/s'; + } + return bits.toFixed(2) + ' bit/s'; + }, + + _formatTime: function (seconds) { + var date = new Date(seconds * 1000), + days = Math.floor(seconds / 86400); + days = days ? days + 'd ' : ''; + return days + + ('0' + date.getUTCHours()).slice(-2) + ':' + + ('0' + date.getUTCMinutes()).slice(-2) + ':' + + ('0' + date.getUTCSeconds()).slice(-2); + }, + + _formatPercentage: function (floatValue) { + return (floatValue * 100).toFixed(2) + ' %'; + }, + + _renderExtendedProgress: function (data) { + return this._formatBitrate(data.bitrate) + ' | ' + + this._formatTime( + (data.total - data.loaded) * 8 / data.bitrate + ) + ' | ' + + this._formatPercentage( + data.loaded / data.total + ) + ' | ' + + this._formatFileSize(data.loaded) + ' / ' + + this._formatFileSize(data.total); + }, + + _renderTemplate: function (func, files) { + if (!func) { + return $(); + } + var result = func({ + files: files, + formatFileSize: this._formatFileSize, + options: this.options + }); + if (result instanceof $) { + return result; + } + return $(this.options.templatesContainer).html(result).children(); + }, + + _renderPreviews: function (data) { + data.context.find('.preview').each(function (index, elm) { + $(elm).append(data.files[index].preview); + }); + }, + + _renderUpload: function (files) { + return this._renderTemplate( + this.options.uploadTemplate, + files + ); + }, + + _renderDownload: function (files) { + return this._renderTemplate( + this.options.downloadTemplate, + files + ).find('a[download]').each(this._enableDragToDesktop).end(); + }, + + _startHandler: function (e) { + e.preventDefault(); + var button = $(e.currentTarget), + template = button.closest('.template-upload'), + data = template.data('data'); + button.prop('disabled', true); + if (data && data.submit) { + data.submit(); + } + }, + + _cancelHandler: function (e) { + e.preventDefault(); + var template = $(e.currentTarget) + .closest('.template-upload,.template-download'), + data = template.data('data') || {}; + data.context = data.context || template; + if (data.abort) { + data.abort(); + } else { + data.errorThrown = 'abort'; + this._trigger('fail', e, data); + } + }, + + _deleteHandler: function (e) { + e.preventDefault(); + var button = $(e.currentTarget); + this._trigger('destroy', e, $.extend({ + context: button.closest('.template-download'), + type: 'DELETE' + }, button.data())); + }, + + _forceReflow: function (node) { + return $.support.transition && node.length && + node[0].offsetWidth; + }, + + _transition: function (node) { + var dfd = $.Deferred(); + if ($.support.transition && node.hasClass('fade') && node.is(':visible')) { + node.bind( + $.support.transition.end, + function (e) { + // Make sure we don't respond to other transitions events + // in the container element, e.g. from button elements: + if (e.target === node[0]) { + node.unbind($.support.transition.end); + dfd.resolveWith(node); + } + } + ).toggleClass('in'); + } else { + node.toggleClass('in'); + dfd.resolveWith(node); + } + return dfd; + }, + + _initButtonBarEventHandlers: function () { + var fileUploadButtonBar = this.element.find('.fileupload-buttonbar'), + filesList = this.options.filesContainer; + this._on(fileUploadButtonBar.find('.start'), { + click: function (e) { + e.preventDefault(); + filesList.find('.start').click(); + } + }); + this._on(fileUploadButtonBar.find('.cancel'), { + click: function (e) { + e.preventDefault(); + filesList.find('.cancel').click(); + } + }); + this._on(fileUploadButtonBar.find('.delete'), { + click: function (e) { + e.preventDefault(); + filesList.find('.toggle:checked') + .closest('.template-download') + .find('.delete').click(); + fileUploadButtonBar.find('.toggle') + .prop('checked', false); + } + }); + this._on(fileUploadButtonBar.find('.toggle'), { + change: function (e) { + filesList.find('.toggle').prop( + 'checked', + $(e.currentTarget).is(':checked') + ); + } + }); + }, + + _destroyButtonBarEventHandlers: function () { + this._off( + this.element.find('.fileupload-buttonbar') + .find('.start, .cancel, .delete'), + 'click' + ); + this._off( + this.element.find('.fileupload-buttonbar .toggle'), + 'change.' + ); + }, + + _initEventHandlers: function () { + this._super(); + this._on(this.options.filesContainer, { + 'click .start': this._startHandler, + 'click .cancel': this._cancelHandler, + 'click .delete': this._deleteHandler + }); + this._initButtonBarEventHandlers(); + }, + + _destroyEventHandlers: function () { + this._destroyButtonBarEventHandlers(); + this._off(this.options.filesContainer, 'click'); + this._super(); + }, + + _enableFileInputButton: function () { + this.element.find('.fileinput-button input') + .prop('disabled', false) + .parent().removeClass('disabled'); + }, + + _disableFileInputButton: function () { + this.element.find('.fileinput-button input') + .prop('disabled', true) + .parent().addClass('disabled'); + }, + + _initTemplates: function () { + var options = this.options; + options.templatesContainer = this.document[0].createElement( + options.filesContainer.prop('nodeName') + ); + if (tmpl) { + if (options.uploadTemplateId) { + options.uploadTemplate = tmpl(options.uploadTemplateId); + } + if (options.downloadTemplateId) { + options.downloadTemplate = tmpl(options.downloadTemplateId); + } + } + }, + + _initFilesContainer: function () { + var options = this.options; + if (options.filesContainer === undefined) { + options.filesContainer = this.element.find('.files'); + } else if (!(options.filesContainer instanceof $)) { + options.filesContainer = $(options.filesContainer); + } + }, + + _initSpecialOptions: function () { + this._super(); + this._initFilesContainer(); + this._initTemplates(); + }, + + _create: function () { + this._super(); + this._resetFinishedDeferreds(); + if (!$.support.fileInput) { + this._disableFileInputButton(); + } + }, + + enable: function () { + var wasDisabled = false; + if (this.options.disabled) { + wasDisabled = true; + } + this._super(); + if (wasDisabled) { + this.element.find('input, button').prop('disabled', false); + this._enableFileInputButton(); + } + }, + + disable: function () { + if (!this.options.disabled) { + this.element.find('input, button').prop('disabled', true); + this._disableFileInputButton(); + } + this._super(); + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-validate.js b/sources/library/jqupload/js/jquery.fileupload-validate.js new file mode 100644 index 00000000..f93a18fa --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-validate.js @@ -0,0 +1,119 @@ +/* + * jQuery File Upload Validation Plugin 1.1.2 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery + ); + } +}(function ($) { + 'use strict'; + + // Append to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.push( + { + action: 'validate', + // Always trigger this action, + // even if the previous action was rejected: + always: true, + // Options taken from the global options map: + acceptFileTypes: '@', + maxFileSize: '@', + minFileSize: '@', + maxNumberOfFiles: '@', + disabled: '@disableValidation' + } + ); + + // The File Upload Validation plugin extends the fileupload widget + // with file validation functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + /* + // The regular expression for allowed file types, matches + // against either file type or file name: + acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, + // The maximum allowed file size in bytes: + maxFileSize: 10000000, // 10 MB + // The minimum allowed file size in bytes: + minFileSize: undefined, // No minimal file size + // The limit of files to be uploaded: + maxNumberOfFiles: 10, + */ + + // Function returning the current number of files, + // has to be overriden for maxNumberOfFiles validation: + getNumberOfFiles: $.noop, + + // Error and info messages: + messages: { + maxNumberOfFiles: 'Maximum number of files exceeded', + acceptFileTypes: 'File type not allowed', + maxFileSize: 'File is too large', + minFileSize: 'File is too small' + } + }, + + processActions: { + + validate: function (data, options) { + if (options.disabled) { + return data; + } + var dfd = $.Deferred(), + settings = this.options, + file = data.files[data.index], + fileSize; + if (options.minFileSize || options.maxFileSize) { + fileSize = file.size; + } + if ($.type(options.maxNumberOfFiles) === 'number' && + (settings.getNumberOfFiles() || 0) + data.files.length > + options.maxNumberOfFiles) { + file.error = settings.i18n('maxNumberOfFiles'); + } else if (options.acceptFileTypes && + !(options.acceptFileTypes.test(file.type) || + options.acceptFileTypes.test(file.name))) { + file.error = settings.i18n('acceptFileTypes'); + } else if (fileSize > options.maxFileSize) { + file.error = settings.i18n('maxFileSize'); + } else if ($.type(fileSize) === 'number' && + fileSize < options.minFileSize) { + file.error = settings.i18n('minFileSize'); + } else { + delete file.error; + } + if (file.error || data.files.error) { + data.files.error = true; + dfd.rejectWith(this, [data]); + } else { + dfd.resolveWith(this, [data]); + } + return dfd.promise(); + } + + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload-video.js b/sources/library/jqupload/js/jquery.fileupload-video.js new file mode 100644 index 00000000..3764b27a --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload-video.js @@ -0,0 +1,106 @@ +/* + * jQuery File Upload Video Preview Plugin 1.0.3 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'load-image', + './jquery.fileupload-process' + ], factory); + } else { + // Browser globals: + factory( + window.jQuery, + window.loadImage + ); + } +}(function ($, loadImage) { + 'use strict'; + + // Prepend to the default processQueue: + $.blueimp.fileupload.prototype.options.processQueue.unshift( + { + action: 'loadVideo', + // Use the action as prefix for the "@" options: + prefix: true, + fileTypes: '@', + maxFileSize: '@', + disabled: '@disableVideoPreview' + }, + { + action: 'setVideo', + name: '@videoPreviewName', + disabled: '@disableVideoPreview' + } + ); + + // The File Upload Video Preview plugin extends the fileupload widget + // with video preview functionality: + $.widget('blueimp.fileupload', $.blueimp.fileupload, { + + options: { + // The regular expression for the types of video files to load, + // matched against the file type: + loadVideoFileTypes: /^video\/.*$/ + }, + + _videoElement: document.createElement('video'), + + processActions: { + + // Loads the video file given via data.files and data.index + // as video element if the browser supports playing it. + // Accepts the options fileTypes (regular expression) + // and maxFileSize (integer) to limit the files to load: + loadVideo: function (data, options) { + if (options.disabled) { + return data; + } + var file = data.files[data.index], + url, + video; + if (this._videoElement.canPlayType && + this._videoElement.canPlayType(file.type) && + ($.type(options.maxFileSize) !== 'number' || + file.size <= options.maxFileSize) && + (!options.fileTypes || + options.fileTypes.test(file.type))) { + url = loadImage.createObjectURL(file); + if (url) { + video = this._videoElement.cloneNode(false); + video.src = url; + video.controls = true; + data.video = video; + return data; + } + } + return data; + }, + + // Sets the video element as a property of the file object: + setVideo: function (data, options) { + if (data.video && !options.disabled) { + data.files[data.index][options.name || 'preview'] = data.video; + } + return data; + } + + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.fileupload.js b/sources/library/jqupload/js/jquery.fileupload.js new file mode 100644 index 00000000..b52af065 --- /dev/null +++ b/sources/library/jqupload/js/jquery.fileupload.js @@ -0,0 +1,1420 @@ +/* + * jQuery File Upload Plugin 5.40.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global define, window, document, location, Blob, FormData */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define([ + 'jquery', + 'jquery.ui.widget' + ], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + + // Detect file input support, based on + // http://viljamis.com/blog/2012/file-upload-support-on-mobile/ + $.support.fileInput = !(new RegExp( + // Handle devices which give false positives for the feature detection: + '(Android (1\\.[0156]|2\\.[01]))' + + '|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' + + '|(w(eb)?OSBrowser)|(webOS)' + + '|(Kindle/(1\\.0|2\\.[05]|3\\.0))' + ).test(window.navigator.userAgent) || + // Feature detection for all other devices: + $('').prop('disabled')); + + // The FileReader API is not actually used, but works as feature detection, + // as some Safari versions (5?) support XHR file uploads via the FormData API, + // but not non-multipart XHR file uploads. + // window.XMLHttpRequestUpload is not available on IE10, so we check for + // window.ProgressEvent instead to detect XHR2 file upload capability: + $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader); + $.support.xhrFormDataFileUpload = !!window.FormData; + + // Detect support for Blob slicing (required for chunked uploads): + $.support.blobSlice = window.Blob && (Blob.prototype.slice || + Blob.prototype.webkitSlice || Blob.prototype.mozSlice); + + // The fileupload widget listens for change events on file input fields defined + // via fileInput setting and paste or drop events of the given dropZone. + // In addition to the default jQuery Widget methods, the fileupload widget + // exposes the "add" and "send" methods, to add or directly send files using + // the fileupload API. + // By default, files added via file input selection, paste, drag & drop or + // "add" method are uploaded immediately, but it is possible to override + // the "add" callback option to queue file uploads. + $.widget('blueimp.fileupload', { + + options: { + // The drop target element(s), by the default the complete document. + // Set to null to disable drag & drop support: + dropZone: $(document), + // The paste target element(s), by the default the complete document. + // Set to null to disable paste support: + pasteZone: $(document), + // The file input field(s), that are listened to for change events. + // If undefined, it is set to the file input fields inside + // of the widget element on plugin initialization. + // Set to null to disable the change listener. + fileInput: undefined, + // By default, the file input field is replaced with a clone after + // each input field change event. This is required for iframe transport + // queues and allows change events to be fired for the same file + // selection, but can be disabled by setting the following option to false: + replaceFileInput: true, + // The parameter name for the file form data (the request argument name). + // If undefined or empty, the name property of the file input field is + // used, or "files[]" if the file input name property is also empty, + // can be a string or an array of strings: + paramName: undefined, + // By default, each file of a selection is uploaded using an individual + // request for XHR type uploads. Set to false to upload file + // selections in one request each: + singleFileUploads: true, + // To limit the number of files uploaded with one XHR request, + // set the following option to an integer greater than 0: + limitMultiFileUploads: undefined, + // The following option limits the number of files uploaded with one + // XHR request to keep the request size under or equal to the defined + // limit in bytes: + limitMultiFileUploadSize: undefined, + // Multipart file uploads add a number of bytes to each uploaded file, + // therefore the following option adds an overhead for each file used + // in the limitMultiFileUploadSize configuration: + limitMultiFileUploadSizeOverhead: 512, + // Set the following option to true to issue all file upload requests + // in a sequential order: + sequentialUploads: false, + // To limit the number of concurrent uploads, + // set the following option to an integer greater than 0: + limitConcurrentUploads: undefined, + // Set the following option to true to force iframe transport uploads: + forceIframeTransport: false, + // Set the following option to the location of a redirect url on the + // origin server, for cross-domain iframe transport uploads: + redirect: undefined, + // The parameter name for the redirect url, sent as part of the form + // data and set to 'redirect' if this option is empty: + redirectParamName: undefined, + // Set the following option to the location of a postMessage window, + // to enable postMessage transport uploads: + postMessage: undefined, + // By default, XHR file uploads are sent as multipart/form-data. + // The iframe transport is always using multipart/form-data. + // Set to false to enable non-multipart XHR uploads: + multipart: true, + // To upload large files in smaller chunks, set the following option + // to a preferred maximum chunk size. If set to 0, null or undefined, + // or the browser does not support the required Blob API, files will + // be uploaded as a whole. + maxChunkSize: undefined, + // When a non-multipart upload or a chunked multipart upload has been + // aborted, this option can be used to resume the upload by setting + // it to the size of the already uploaded bytes. This option is most + // useful when modifying the options object inside of the "add" or + // "send" callbacks, as the options are cloned for each file upload. + uploadedBytes: undefined, + // By default, failed (abort or error) file uploads are removed from the + // global progress calculation. Set the following option to false to + // prevent recalculating the global progress data: + recalculateProgress: true, + // Interval in milliseconds to calculate and trigger progress events: + progressInterval: 100, + // Interval in milliseconds to calculate progress bitrate: + bitrateInterval: 500, + // By default, uploads are started automatically when adding files: + autoUpload: true, + + // Error and info messages: + messages: { + uploadedBytes: 'Uploaded bytes exceed file size' + }, + + // Translation function, gets the message key to be translated + // and an object with context specific data as arguments: + i18n: function (message, context) { + message = this.messages[message] || message.toString(); + if (context) { + $.each(context, function (key, value) { + message = message.replace('{' + key + '}', value); + }); + } + return message; + }, + + // Additional form data to be sent along with the file uploads can be set + // using this option, which accepts an array of objects with name and + // value properties, a function returning such an array, a FormData + // object (for XHR file uploads), or a simple object. + // The form of the first fileInput is given as parameter to the function: + formData: function (form) { + return form.serializeArray(); + }, + + // The add callback is invoked as soon as files are added to the fileupload + // widget (via file input selection, drag & drop, paste or add API call). + // If the singleFileUploads option is enabled, this callback will be + // called once for each file in the selection for XHR file uploads, else + // once for each file selection. + // + // The upload starts when the submit method is invoked on the data parameter. + // The data object contains a files property holding the added files + // and allows you to override plugin options as well as define ajax settings. + // + // Listeners for this callback can also be bound the following way: + // .bind('fileuploadadd', func); + // + // data.submit() returns a Promise object and allows to attach additional + // handlers using jQuery's Deferred callbacks: + // data.submit().done(func).fail(func).always(func); + add: function (e, data) { + if (e.isDefaultPrevented()) { + return false; + } + if (data.autoUpload || (data.autoUpload !== false && + $(this).fileupload('option', 'autoUpload'))) { + data.process().done(function () { + data.submit(); + }); + } + }, + + // Other callbacks: + + // Callback for the submit event of each file upload: + // submit: function (e, data) {}, // .bind('fileuploadsubmit', func); + + // Callback for the start of each file upload request: + // send: function (e, data) {}, // .bind('fileuploadsend', func); + + // Callback for successful uploads: + // done: function (e, data) {}, // .bind('fileuploaddone', func); + + // Callback for failed (abort or error) uploads: + // fail: function (e, data) {}, // .bind('fileuploadfail', func); + + // Callback for completed (success, abort or error) requests: + // always: function (e, data) {}, // .bind('fileuploadalways', func); + + // Callback for upload progress events: + // progress: function (e, data) {}, // .bind('fileuploadprogress', func); + + // Callback for global upload progress events: + // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func); + + // Callback for uploads start, equivalent to the global ajaxStart event: + // start: function (e) {}, // .bind('fileuploadstart', func); + + // Callback for uploads stop, equivalent to the global ajaxStop event: + // stop: function (e) {}, // .bind('fileuploadstop', func); + + // Callback for change events of the fileInput(s): + // change: function (e, data) {}, // .bind('fileuploadchange', func); + + // Callback for paste events to the pasteZone(s): + // paste: function (e, data) {}, // .bind('fileuploadpaste', func); + + // Callback for drop events of the dropZone(s): + // drop: function (e, data) {}, // .bind('fileuploaddrop', func); + + // Callback for dragover events of the dropZone(s): + // dragover: function (e) {}, // .bind('fileuploaddragover', func); + + // Callback for the start of each chunk upload request: + // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func); + + // Callback for successful chunk uploads: + // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func); + + // Callback for failed (abort or error) chunk uploads: + // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func); + + // Callback for completed (success, abort or error) chunk upload requests: + // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func); + + // The plugin options are used as settings object for the ajax calls. + // The following are jQuery ajax settings required for the file uploads: + processData: false, + contentType: false, + cache: false + }, + + // A list of options that require reinitializing event listeners and/or + // special initialization code: + _specialOptions: [ + 'fileInput', + 'dropZone', + 'pasteZone', + 'multipart', + 'forceIframeTransport' + ], + + _blobSlice: $.support.blobSlice && function () { + var slice = this.slice || this.webkitSlice || this.mozSlice; + return slice.apply(this, arguments); + }, + + _BitrateTimer: function () { + this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime()); + this.loaded = 0; + this.bitrate = 0; + this.getBitrate = function (now, loaded, interval) { + var timeDiff = now - this.timestamp; + if (!this.bitrate || !interval || timeDiff > interval) { + this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8; + this.loaded = loaded; + this.timestamp = now; + } + return this.bitrate; + }; + }, + + _isXHRUpload: function (options) { + return !options.forceIframeTransport && + ((!options.multipart && $.support.xhrFileUpload) || + $.support.xhrFormDataFileUpload); + }, + + _getFormData: function (options) { + var formData; + if ($.type(options.formData) === 'function') { + return options.formData(options.form); + } + if ($.isArray(options.formData)) { + return options.formData; + } + if ($.type(options.formData) === 'object') { + formData = []; + $.each(options.formData, function (name, value) { + formData.push({name: name, value: value}); + }); + return formData; + } + return []; + }, + + _getTotal: function (files) { + var total = 0; + $.each(files, function (index, file) { + total += file.size || 1; + }); + return total; + }, + + _initProgressObject: function (obj) { + var progress = { + loaded: 0, + total: 0, + bitrate: 0 + }; + if (obj._progress) { + $.extend(obj._progress, progress); + } else { + obj._progress = progress; + } + }, + + _initResponseObject: function (obj) { + var prop; + if (obj._response) { + for (prop in obj._response) { + if (obj._response.hasOwnProperty(prop)) { + delete obj._response[prop]; + } + } + } else { + obj._response = {}; + } + }, + + _onProgress: function (e, data) { + if (e.lengthComputable) { + var now = ((Date.now) ? Date.now() : (new Date()).getTime()), + loaded; + if (data._time && data.progressInterval && + (now - data._time < data.progressInterval) && + e.loaded !== e.total) { + return; + } + data._time = now; + loaded = Math.floor( + e.loaded / e.total * (data.chunkSize || data._progress.total) + ) + (data.uploadedBytes || 0); + // Add the difference from the previously loaded state + // to the global loaded counter: + this._progress.loaded += (loaded - data._progress.loaded); + this._progress.bitrate = this._bitrateTimer.getBitrate( + now, + this._progress.loaded, + data.bitrateInterval + ); + data._progress.loaded = data.loaded = loaded; + data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate( + now, + loaded, + data.bitrateInterval + ); + // Trigger a custom progress event with a total data property set + // to the file size(s) of the current upload and a loaded data + // property calculated accordingly: + this._trigger( + 'progress', + $.Event('progress', {delegatedEvent: e}), + data + ); + // Trigger a global progress event for all current file uploads, + // including ajax calls queued for sequential file uploads: + this._trigger( + 'progressall', + $.Event('progressall', {delegatedEvent: e}), + this._progress + ); + } + }, + + _initProgressListener: function (options) { + var that = this, + xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr(); + // Accesss to the native XHR object is required to add event listeners + // for the upload progress event: + if (xhr.upload) { + $(xhr.upload).bind('progress', function (e) { + var oe = e.originalEvent; + // Make sure the progress event properties get copied over: + e.lengthComputable = oe.lengthComputable; + e.loaded = oe.loaded; + e.total = oe.total; + that._onProgress(e, options); + }); + options.xhr = function () { + return xhr; + }; + } + }, + + _isInstanceOf: function (type, obj) { + // Cross-frame instanceof check + return Object.prototype.toString.call(obj) === '[object ' + type + ']'; + }, + + _initXHRData: function (options) { + var that = this, + formData, + file = options.files[0], + // Ignore non-multipart setting if not supported: + multipart = options.multipart || !$.support.xhrFileUpload, + paramName = $.type(options.paramName) === 'array' ? + options.paramName[0] : options.paramName; + options.headers = $.extend({}, options.headers); + if (options.contentRange) { + options.headers['Content-Range'] = options.contentRange; + } + if (!multipart || options.blob || !this._isInstanceOf('File', file)) { + options.headers['Content-Disposition'] = 'attachment; filename="' + + encodeURI(file.name) + '"'; + } + if (!multipart) { + options.contentType = file.type || 'application/octet-stream'; + options.data = options.blob || file; + } else if ($.support.xhrFormDataFileUpload) { + if (options.postMessage) { + // window.postMessage does not allow sending FormData + // objects, so we just add the File/Blob objects to + // the formData array and let the postMessage window + // create the FormData object out of this array: + formData = this._getFormData(options); + if (options.blob) { + formData.push({ + name: paramName, + value: options.blob + }); + } else { + $.each(options.files, function (index, file) { + formData.push({ + name: ($.type(options.paramName) === 'array' && + options.paramName[index]) || paramName, + value: file + }); + }); + } + } else { + if (that._isInstanceOf('FormData', options.formData)) { + formData = options.formData; + } else { + formData = new FormData(); + $.each(this._getFormData(options), function (index, field) { + formData.append(field.name, field.value); + }); + } + if (options.blob) { + formData.append(paramName, options.blob, file.name); + } else { + $.each(options.files, function (index, file) { + // This check allows the tests to run with + // dummy objects: + if (that._isInstanceOf('File', file) || + that._isInstanceOf('Blob', file)) { + formData.append( + ($.type(options.paramName) === 'array' && + options.paramName[index]) || paramName, + file, + file.uploadName || file.name + ); + } + }); + } + } + options.data = formData; + } + // Blob reference is not needed anymore, free memory: + options.blob = null; + }, + + _initIframeSettings: function (options) { + var targetHost = $('').prop('href', options.url).prop('host'); + // Setting the dataType to iframe enables the iframe transport: + options.dataType = 'iframe ' + (options.dataType || ''); + // The iframe transport accepts a serialized array as form data: + options.formData = this._getFormData(options); + // Add redirect url to form data on cross-domain uploads: + if (options.redirect && targetHost && targetHost !== location.host) { + options.formData.push({ + name: options.redirectParamName || 'redirect', + value: options.redirect + }); + } + }, + + _initDataSettings: function (options) { + if (this._isXHRUpload(options)) { + if (!this._chunkedUpload(options, true)) { + if (!options.data) { + this._initXHRData(options); + } + this._initProgressListener(options); + } + if (options.postMessage) { + // Setting the dataType to postmessage enables the + // postMessage transport: + options.dataType = 'postmessage ' + (options.dataType || ''); + } + } else { + this._initIframeSettings(options); + } + }, + + _getParamName: function (options) { + var fileInput = $(options.fileInput), + paramName = options.paramName; + if (!paramName) { + paramName = []; + fileInput.each(function () { + var input = $(this), + name = input.prop('name') || 'files[]', + i = (input.prop('files') || [1]).length; + while (i) { + paramName.push(name); + i -= 1; + } + }); + if (!paramName.length) { + paramName = [fileInput.prop('name') || 'files[]']; + } + } else if (!$.isArray(paramName)) { + paramName = [paramName]; + } + return paramName; + }, + + _initFormSettings: function (options) { + // Retrieve missing options from the input field and the + // associated form, if available: + if (!options.form || !options.form.length) { + options.form = $(options.fileInput.prop('form')); + // If the given file input doesn't have an associated form, + // use the default widget file input's form: + if (!options.form.length) { + options.form = $(this.options.fileInput.prop('form')); + } + } + options.paramName = this._getParamName(options); + if (!options.url) { + options.url = options.form.prop('action') || location.href; + } + // The HTTP request method must be "POST" or "PUT": + options.type = (options.type || + ($.type(options.form.prop('method')) === 'string' && + options.form.prop('method')) || '' + ).toUpperCase(); + if (options.type !== 'POST' && options.type !== 'PUT' && + options.type !== 'PATCH') { + options.type = 'POST'; + } + if (!options.formAcceptCharset) { + options.formAcceptCharset = options.form.attr('accept-charset'); + } + }, + + _getAJAXSettings: function (data) { + var options = $.extend({}, this.options, data); + this._initFormSettings(options); + this._initDataSettings(options); + return options; + }, + + // jQuery 1.6 doesn't provide .state(), + // while jQuery 1.8+ removed .isRejected() and .isResolved(): + _getDeferredState: function (deferred) { + if (deferred.state) { + return deferred.state(); + } + if (deferred.isResolved()) { + return 'resolved'; + } + if (deferred.isRejected()) { + return 'rejected'; + } + return 'pending'; + }, + + // Maps jqXHR callbacks to the equivalent + // methods of the given Promise object: + _enhancePromise: function (promise) { + promise.success = promise.done; + promise.error = promise.fail; + promise.complete = promise.always; + return promise; + }, + + // Creates and returns a Promise object enhanced with + // the jqXHR methods abort, success, error and complete: + _getXHRPromise: function (resolveOrReject, context, args) { + var dfd = $.Deferred(), + promise = dfd.promise(); + context = context || this.options.context || promise; + if (resolveOrReject === true) { + dfd.resolveWith(context, args); + } else if (resolveOrReject === false) { + dfd.rejectWith(context, args); + } + promise.abort = dfd.promise; + return this._enhancePromise(promise); + }, + + // Adds convenience methods to the data callback argument: + _addConvenienceMethods: function (e, data) { + var that = this, + getPromise = function (args) { + return $.Deferred().resolveWith(that, args).promise(); + }; + data.process = function (resolveFunc, rejectFunc) { + if (resolveFunc || rejectFunc) { + data._processQueue = this._processQueue = + (this._processQueue || getPromise([this])).pipe( + function () { + if (data.errorThrown) { + return $.Deferred() + .rejectWith(that, [data]).promise(); + } + return getPromise(arguments); + } + ).pipe(resolveFunc, rejectFunc); + } + return this._processQueue || getPromise([this]); + }; + data.submit = function () { + if (this.state() !== 'pending') { + data.jqXHR = this.jqXHR = + (that._trigger( + 'submit', + $.Event('submit', {delegatedEvent: e}), + this + ) !== false) && that._onSend(e, this); + } + return this.jqXHR || that._getXHRPromise(); + }; + data.abort = function () { + if (this.jqXHR) { + return this.jqXHR.abort(); + } + this.errorThrown = 'abort'; + that._trigger('fail', null, this); + return that._getXHRPromise(false); + }; + data.state = function () { + if (this.jqXHR) { + return that._getDeferredState(this.jqXHR); + } + if (this._processQueue) { + return that._getDeferredState(this._processQueue); + } + }; + data.processing = function () { + return !this.jqXHR && this._processQueue && that + ._getDeferredState(this._processQueue) === 'pending'; + }; + data.progress = function () { + return this._progress; + }; + data.response = function () { + return this._response; + }; + }, + + // Parses the Range header from the server response + // and returns the uploaded bytes: + _getUploadedBytes: function (jqXHR) { + var range = jqXHR.getResponseHeader('Range'), + parts = range && range.split('-'), + upperBytesPos = parts && parts.length > 1 && + parseInt(parts[1], 10); + return upperBytesPos && upperBytesPos + 1; + }, + + // Uploads a file in multiple, sequential requests + // by splitting the file up in multiple blob chunks. + // If the second parameter is true, only tests if the file + // should be uploaded in chunks, but does not invoke any + // upload requests: + _chunkedUpload: function (options, testOnly) { + options.uploadedBytes = options.uploadedBytes || 0; + var that = this, + file = options.files[0], + fs = file.size, + ub = options.uploadedBytes, + mcs = options.maxChunkSize || fs, + slice = this._blobSlice, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + upload; + if (!(this._isXHRUpload(options) && slice && (ub || mcs < fs)) || + options.data) { + return false; + } + if (testOnly) { + return true; + } + if (ub >= fs) { + file.error = options.i18n('uploadedBytes'); + return this._getXHRPromise( + false, + options.context, + [null, 'error', file.error] + ); + } + // The chunk upload method: + upload = function () { + // Clone the options object for each chunk upload: + var o = $.extend({}, options), + currentLoaded = o._progress.loaded; + o.blob = slice.call( + file, + ub, + ub + mcs, + file.type + ); + // Store the current chunk size, as the blob itself + // will be dereferenced after data processing: + o.chunkSize = o.blob.size; + // Expose the chunk bytes position range: + o.contentRange = 'bytes ' + ub + '-' + + (ub + o.chunkSize - 1) + '/' + fs; + // Process the upload data (the blob and potential form data): + that._initXHRData(o); + // Add progress listeners for this chunk upload: + that._initProgressListener(o); + jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) || + that._getXHRPromise(false, o.context)) + .done(function (result, textStatus, jqXHR) { + ub = that._getUploadedBytes(jqXHR) || + (ub + o.chunkSize); + // Create a progress event if no final progress event + // with loaded equaling total has been triggered + // for this chunk: + if (currentLoaded + o.chunkSize - o._progress.loaded) { + that._onProgress($.Event('progress', { + lengthComputable: true, + loaded: ub - o.uploadedBytes, + total: ub - o.uploadedBytes + }), o); + } + options.uploadedBytes = o.uploadedBytes = ub; + o.result = result; + o.textStatus = textStatus; + o.jqXHR = jqXHR; + that._trigger('chunkdone', null, o); + that._trigger('chunkalways', null, o); + if (ub < fs) { + // File upload not yet complete, + // continue with the next chunk: + upload(); + } else { + dfd.resolveWith( + o.context, + [result, textStatus, jqXHR] + ); + } + }) + .fail(function (jqXHR, textStatus, errorThrown) { + o.jqXHR = jqXHR; + o.textStatus = textStatus; + o.errorThrown = errorThrown; + that._trigger('chunkfail', null, o); + that._trigger('chunkalways', null, o); + dfd.rejectWith( + o.context, + [jqXHR, textStatus, errorThrown] + ); + }); + }; + this._enhancePromise(promise); + promise.abort = function () { + return jqXHR.abort(); + }; + upload(); + return promise; + }, + + _beforeSend: function (e, data) { + if (this._active === 0) { + // the start callback is triggered when an upload starts + // and no other uploads are currently running, + // equivalent to the global ajaxStart event: + this._trigger('start'); + // Set timer for global bitrate progress calculation: + this._bitrateTimer = new this._BitrateTimer(); + // Reset the global progress values: + this._progress.loaded = this._progress.total = 0; + this._progress.bitrate = 0; + } + // Make sure the container objects for the .response() and + // .progress() methods on the data object are available + // and reset to their initial state: + this._initResponseObject(data); + this._initProgressObject(data); + data._progress.loaded = data.loaded = data.uploadedBytes || 0; + data._progress.total = data.total = this._getTotal(data.files) || 1; + data._progress.bitrate = data.bitrate = 0; + this._active += 1; + // Initialize the global progress values: + this._progress.loaded += data.loaded; + this._progress.total += data.total; + }, + + _onDone: function (result, textStatus, jqXHR, options) { + var total = options._progress.total, + response = options._response; + if (options._progress.loaded < total) { + // Create a progress event if no final progress event + // with loaded equaling total has been triggered: + this._onProgress($.Event('progress', { + lengthComputable: true, + loaded: total, + total: total + }), options); + } + response.result = options.result = result; + response.textStatus = options.textStatus = textStatus; + response.jqXHR = options.jqXHR = jqXHR; + this._trigger('done', null, options); + }, + + _onFail: function (jqXHR, textStatus, errorThrown, options) { + var response = options._response; + if (options.recalculateProgress) { + // Remove the failed (error or abort) file upload from + // the global progress calculation: + this._progress.loaded -= options._progress.loaded; + this._progress.total -= options._progress.total; + } + response.jqXHR = options.jqXHR = jqXHR; + response.textStatus = options.textStatus = textStatus; + response.errorThrown = options.errorThrown = errorThrown; + this._trigger('fail', null, options); + }, + + _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) { + // jqXHRorResult, textStatus and jqXHRorError are added to the + // options object via done and fail callbacks + this._trigger('always', null, options); + }, + + _onSend: function (e, data) { + if (!data.submit) { + this._addConvenienceMethods(e, data); + } + var that = this, + jqXHR, + aborted, + slot, + pipe, + options = that._getAJAXSettings(data), + send = function () { + that._sending += 1; + // Set timer for bitrate progress calculation: + options._bitrateTimer = new that._BitrateTimer(); + jqXHR = jqXHR || ( + ((aborted || that._trigger( + 'send', + $.Event('send', {delegatedEvent: e}), + options + ) === false) && + that._getXHRPromise(false, options.context, aborted)) || + that._chunkedUpload(options) || $.ajax(options) + ).done(function (result, textStatus, jqXHR) { + that._onDone(result, textStatus, jqXHR, options); + }).fail(function (jqXHR, textStatus, errorThrown) { + that._onFail(jqXHR, textStatus, errorThrown, options); + }).always(function (jqXHRorResult, textStatus, jqXHRorError) { + that._onAlways( + jqXHRorResult, + textStatus, + jqXHRorError, + options + ); + that._sending -= 1; + that._active -= 1; + if (options.limitConcurrentUploads && + options.limitConcurrentUploads > that._sending) { + // Start the next queued upload, + // that has not been aborted: + var nextSlot = that._slots.shift(); + while (nextSlot) { + if (that._getDeferredState(nextSlot) === 'pending') { + nextSlot.resolve(); + break; + } + nextSlot = that._slots.shift(); + } + } + if (that._active === 0) { + // The stop callback is triggered when all uploads have + // been completed, equivalent to the global ajaxStop event: + that._trigger('stop'); + } + }); + return jqXHR; + }; + this._beforeSend(e, options); + if (this.options.sequentialUploads || + (this.options.limitConcurrentUploads && + this.options.limitConcurrentUploads <= this._sending)) { + if (this.options.limitConcurrentUploads > 1) { + slot = $.Deferred(); + this._slots.push(slot); + pipe = slot.pipe(send); + } else { + this._sequence = this._sequence.pipe(send, send); + pipe = this._sequence; + } + // Return the piped Promise object, enhanced with an abort method, + // which is delegated to the jqXHR object of the current upload, + // and jqXHR callbacks mapped to the equivalent Promise methods: + pipe.abort = function () { + aborted = [undefined, 'abort', 'abort']; + if (!jqXHR) { + if (slot) { + slot.rejectWith(options.context, aborted); + } + return send(); + } + return jqXHR.abort(); + }; + return this._enhancePromise(pipe); + } + return send(); + }, + + _onAdd: function (e, data) { + var that = this, + result = true, + options = $.extend({}, this.options, data), + files = data.files, + filesLength = files.length, + limit = options.limitMultiFileUploads, + limitSize = options.limitMultiFileUploadSize, + overhead = options.limitMultiFileUploadSizeOverhead, + batchSize = 0, + paramName = this._getParamName(options), + paramNameSet, + paramNameSlice, + fileSet, + i, + j = 0; + if (limitSize && (!filesLength || files[0].size === undefined)) { + limitSize = undefined; + } + if (!(options.singleFileUploads || limit || limitSize) || + !this._isXHRUpload(options)) { + fileSet = [files]; + paramNameSet = [paramName]; + } else if (!(options.singleFileUploads || limitSize) && limit) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i += limit) { + fileSet.push(files.slice(i, i + limit)); + paramNameSlice = paramName.slice(i, i + limit); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + } + } else if (!options.singleFileUploads && limitSize) { + fileSet = []; + paramNameSet = []; + for (i = 0; i < filesLength; i = i + 1) { + batchSize += files[i].size + overhead; + if (i + 1 === filesLength || + ((batchSize + files[i + 1].size + overhead) > limitSize) || + (limit && i + 1 - j >= limit)) { + fileSet.push(files.slice(j, i + 1)); + paramNameSlice = paramName.slice(j, i + 1); + if (!paramNameSlice.length) { + paramNameSlice = paramName; + } + paramNameSet.push(paramNameSlice); + j = i + 1; + batchSize = 0; + } + } + } else { + paramNameSet = paramName; + } + data.originalFiles = files; + $.each(fileSet || files, function (index, element) { + var newData = $.extend({}, data); + newData.files = fileSet ? element : [element]; + newData.paramName = paramNameSet[index]; + that._initResponseObject(newData); + that._initProgressObject(newData); + that._addConvenienceMethods(e, newData); + result = that._trigger( + 'add', + $.Event('add', {delegatedEvent: e}), + newData + ); + return result; + }); + return result; + }, + + _replaceFileInput: function (input) { + var inputClone = input.clone(true); + $('
').append(inputClone)[0].reset(); + // Detaching allows to insert the fileInput on another form + // without loosing the file input value: + input.after(inputClone).detach(); + // Avoid memory leaks with the detached file input: + $.cleanData(input.unbind('remove')); + // Replace the original file input element in the fileInput + // elements set with the clone, which has been copied including + // event handlers: + this.options.fileInput = this.options.fileInput.map(function (i, el) { + if (el === input[0]) { + return inputClone[0]; + } + return el; + }); + // If the widget has been initialized on the file input itself, + // override this.element with the file input clone: + if (input[0] === this.element[0]) { + this.element = inputClone; + } + }, + + _handleFileTreeEntry: function (entry, path) { + var that = this, + dfd = $.Deferred(), + errorHandler = function (e) { + if (e && !e.entry) { + e.entry = entry; + } + // Since $.when returns immediately if one + // Deferred is rejected, we use resolve instead. + // This allows valid files and invalid items + // to be returned together in one set: + dfd.resolve([e]); + }, + dirReader; + path = path || ''; + if (entry.isFile) { + if (entry._file) { + // Workaround for Chrome bug #149735 + entry._file.relativePath = path; + dfd.resolve(entry._file); + } else { + entry.file(function (file) { + file.relativePath = path; + dfd.resolve(file); + }, errorHandler); + } + } else if (entry.isDirectory) { + dirReader = entry.createReader(); + dirReader.readEntries(function (entries) { + that._handleFileTreeEntries( + entries, + path + entry.name + '/' + ).done(function (files) { + dfd.resolve(files); + }).fail(errorHandler); + }, errorHandler); + } else { + // Return an empy list for file system items + // other than files or directories: + dfd.resolve([]); + } + return dfd.promise(); + }, + + _handleFileTreeEntries: function (entries, path) { + var that = this; + return $.when.apply( + $, + $.map(entries, function (entry) { + return that._handleFileTreeEntry(entry, path); + }) + ).pipe(function () { + return Array.prototype.concat.apply( + [], + arguments + ); + }); + }, + + _getDroppedFiles: function (dataTransfer) { + dataTransfer = dataTransfer || {}; + var items = dataTransfer.items; + if (items && items.length && (items[0].webkitGetAsEntry || + items[0].getAsEntry)) { + return this._handleFileTreeEntries( + $.map(items, function (item) { + var entry; + if (item.webkitGetAsEntry) { + entry = item.webkitGetAsEntry(); + if (entry) { + // Workaround for Chrome bug #149735: + entry._file = item.getAsFile(); + } + return entry; + } + return item.getAsEntry(); + }) + ); + } + return $.Deferred().resolve( + $.makeArray(dataTransfer.files) + ).promise(); + }, + + _getSingleFileInputFiles: function (fileInput) { + fileInput = $(fileInput); + var entries = fileInput.prop('webkitEntries') || + fileInput.prop('entries'), + files, + value; + if (entries && entries.length) { + return this._handleFileTreeEntries(entries); + } + files = $.makeArray(fileInput.prop('files')); + if (!files.length) { + value = fileInput.prop('value'); + if (!value) { + return $.Deferred().resolve([]).promise(); + } + // If the files property is not available, the browser does not + // support the File API and we add a pseudo File object with + // the input value as name with path information removed: + files = [{name: value.replace(/^.*\\/, '')}]; + } else if (files[0].name === undefined && files[0].fileName) { + // File normalization for Safari 4 and Firefox 3: + $.each(files, function (index, file) { + file.name = file.fileName; + file.size = file.fileSize; + }); + } + return $.Deferred().resolve(files).promise(); + }, + + _getFileInputFiles: function (fileInput) { + if (!(fileInput instanceof $) || fileInput.length === 1) { + return this._getSingleFileInputFiles(fileInput); + } + return $.when.apply( + $, + $.map(fileInput, this._getSingleFileInputFiles) + ).pipe(function () { + return Array.prototype.concat.apply( + [], + arguments + ); + }); + }, + + _onChange: function (e) { + var that = this, + data = { + fileInput: $(e.target), + form: $(e.target.form) + }; + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + if (that.options.replaceFileInput) { + that._replaceFileInput(data.fileInput); + } + if (that._trigger( + 'change', + $.Event('change', {delegatedEvent: e}), + data + ) !== false) { + that._onAdd(e, data); + } + }); + }, + + _onPaste: function (e) { + var items = e.originalEvent && e.originalEvent.clipboardData && + e.originalEvent.clipboardData.items, + data = {files: []}; + if (items && items.length) { + $.each(items, function (index, item) { + var file = item.getAsFile && item.getAsFile(); + if (file) { + data.files.push(file); + } + }); + if (this._trigger( + 'paste', + $.Event('paste', {delegatedEvent: e}), + data + ) !== false) { + this._onAdd(e, data); + } + } + }, + + _onDrop: function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var that = this, + dataTransfer = e.dataTransfer, + data = {}; + if (dataTransfer && dataTransfer.files && dataTransfer.files.length) { + e.preventDefault(); + this._getDroppedFiles(dataTransfer).always(function (files) { + data.files = files; + if (that._trigger( + 'drop', + $.Event('drop', {delegatedEvent: e}), + data + ) !== false) { + that._onAdd(e, data); + } + }); + } + }, + + _onDragOver: function (e) { + e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer; + var dataTransfer = e.dataTransfer; + if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 && + this._trigger( + 'dragover', + $.Event('dragover', {delegatedEvent: e}) + ) !== false) { + e.preventDefault(); + dataTransfer.dropEffect = 'copy'; + } + }, + + _initEventHandlers: function () { + if (this._isXHRUpload(this.options)) { + this._on(this.options.dropZone, { + dragover: this._onDragOver, + drop: this._onDrop + }); + this._on(this.options.pasteZone, { + paste: this._onPaste + }); + } + if ($.support.fileInput) { + this._on(this.options.fileInput, { + change: this._onChange + }); + } + }, + + _destroyEventHandlers: function () { + this._off(this.options.dropZone, 'dragover drop'); + this._off(this.options.pasteZone, 'paste'); + this._off(this.options.fileInput, 'change'); + }, + + _setOption: function (key, value) { + var reinit = $.inArray(key, this._specialOptions) !== -1; + if (reinit) { + this._destroyEventHandlers(); + } + this._super(key, value); + if (reinit) { + this._initSpecialOptions(); + this._initEventHandlers(); + } + }, + + _initSpecialOptions: function () { + var options = this.options; + if (options.fileInput === undefined) { + options.fileInput = this.element.is('input[type="file"]') ? + this.element : this.element.find('input[type="file"]'); + } else if (!(options.fileInput instanceof $)) { + options.fileInput = $(options.fileInput); + } + if (!(options.dropZone instanceof $)) { + options.dropZone = $(options.dropZone); + } + if (!(options.pasteZone instanceof $)) { + options.pasteZone = $(options.pasteZone); + } + }, + + _getRegExp: function (str) { + var parts = str.split('/'), + modifiers = parts.pop(); + parts.shift(); + return new RegExp(parts.join('/'), modifiers); + }, + + _isRegExpOption: function (key, value) { + return key !== 'url' && $.type(value) === 'string' && + /^\/.*\/[igm]{0,3}$/.test(value); + }, + + _initDataAttributes: function () { + var that = this, + options = this.options; + // Initialize options set via HTML5 data-attributes: + $.each( + $(this.element[0].cloneNode(false)).data(), + function (key, value) { + if (that._isRegExpOption(key, value)) { + value = that._getRegExp(value); + } + options[key] = value; + } + ); + }, + + _create: function () { + this._initDataAttributes(); + this._initSpecialOptions(); + this._slots = []; + this._sequence = this._getXHRPromise(true); + this._sending = this._active = 0; + this._initProgressObject(this); + this._initEventHandlers(); + }, + + // This method is exposed to the widget API and allows to query + // the number of active uploads: + active: function () { + return this._active; + }, + + // This method is exposed to the widget API and allows to query + // the widget upload progress. + // It returns an object with loaded, total and bitrate properties + // for the running uploads: + progress: function () { + return this._progress; + }, + + // This method is exposed to the widget API and allows adding files + // using the fileupload API. The data parameter accepts an object which + // must have a files property and can contain additional options: + // .fileupload('add', {files: filesList}); + add: function (data) { + var that = this; + if (!data || this.options.disabled) { + return; + } + if (data.fileInput && !data.files) { + this._getFileInputFiles(data.fileInput).always(function (files) { + data.files = files; + that._onAdd(null, data); + }); + } else { + data.files = $.makeArray(data.files); + this._onAdd(null, data); + } + }, + + // This method is exposed to the widget API and allows sending files + // using the fileupload API. The data parameter accepts an object which + // must have a files or fileInput property and can contain additional options: + // .fileupload('send', {files: filesList}); + // The method returns a Promise object for the file upload call. + send: function (data) { + if (data && !this.options.disabled) { + if (data.fileInput && !data.files) { + var that = this, + dfd = $.Deferred(), + promise = dfd.promise(), + jqXHR, + aborted; + promise.abort = function () { + aborted = true; + if (jqXHR) { + return jqXHR.abort(); + } + dfd.reject(null, 'abort', 'abort'); + return promise; + }; + this._getFileInputFiles(data.fileInput).always( + function (files) { + if (aborted) { + return; + } + if (!files.length) { + dfd.reject(); + return; + } + data.files = files; + jqXHR = that._onSend(null, data).then( + function (result, textStatus, jqXHR) { + dfd.resolve(result, textStatus, jqXHR); + }, + function (jqXHR, textStatus, errorThrown) { + dfd.reject(jqXHR, textStatus, errorThrown); + } + ); + } + ); + return this._enhancePromise(promise); + } + data.files = $.makeArray(data.files); + if (data.files.length) { + return this._onSend(null, data); + } + } + return this._getXHRPromise(false, data && data.context); + } + + }); + +})); diff --git a/sources/library/jqupload/js/jquery.iframe-transport.js b/sources/library/jqupload/js/jquery.iframe-transport.js new file mode 100644 index 00000000..8d64b591 --- /dev/null +++ b/sources/library/jqupload/js/jquery.iframe-transport.js @@ -0,0 +1,214 @@ +/* + * jQuery Iframe Transport Plugin 1.8.2 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global define, window, document */ + +(function (factory) { + 'use strict'; + if (typeof define === 'function' && define.amd) { + // Register as an anonymous AMD module: + define(['jquery'], factory); + } else { + // Browser globals: + factory(window.jQuery); + } +}(function ($) { + 'use strict'; + + // Helper variable to create unique names for the transport iframes: + var counter = 0; + + // The iframe transport accepts four additional options: + // options.fileInput: a jQuery collection of file input fields + // options.paramName: the parameter name for the file form data, + // overrides the name property of the file input field(s), + // can be a string or an array of strings. + // options.formData: an array of objects with name and value properties, + // equivalent to the return data of .serializeArray(), e.g.: + // [{name: 'a', value: 1}, {name: 'b', value: 2}] + // options.initialIframeSrc: the URL of the initial iframe src, + // by default set to "javascript:false;" + $.ajaxTransport('iframe', function (options) { + if (options.async) { + // javascript:false as initial iframe src + // prevents warning popups on HTTPS in IE6: + /*jshint scripturl: true */ + var initialIframeSrc = options.initialIframeSrc || 'javascript:false;', + /*jshint scripturl: false */ + form, + iframe, + addParamChar; + return { + send: function (_, completeCallback) { + form = $('
'); + form.attr('accept-charset', options.formAcceptCharset); + addParamChar = /\?/.test(options.url) ? '&' : '?'; + // XDomainRequest only supports GET and POST: + if (options.type === 'DELETE') { + options.url = options.url + addParamChar + '_method=DELETE'; + options.type = 'POST'; + } else if (options.type === 'PUT') { + options.url = options.url + addParamChar + '_method=PUT'; + options.type = 'POST'; + } else if (options.type === 'PATCH') { + options.url = options.url + addParamChar + '_method=PATCH'; + options.type = 'POST'; + } + // IE versions below IE8 cannot set the name property of + // elements that have already been added to the DOM, + // so we set the name along with the iframe HTML markup: + counter += 1; + iframe = $( + '' + ).bind('load', function () { + var fileInputClones, + paramNames = $.isArray(options.paramName) ? + options.paramName : [options.paramName]; + iframe + .unbind('load') + .bind('load', function () { + var response; + // Wrap in a try/catch block to catch exceptions thrown + // when trying to access cross-domain iframe contents: + try { + response = iframe.contents(); + // Google Chrome and Firefox do not throw an + // exception when calling iframe.contents() on + // cross-domain requests, so we unify the response: + if (!response.length || !response[0].firstChild) { + throw new Error(); + } + } catch (e) { + response = undefined; + } + // The complete callback returns the + // iframe content document as response object: + completeCallback( + 200, + 'success', + {'iframe': response} + ); + // Fix for IE endless progress bar activity bug + // (happens on form submits to iframe targets): + $('') + .appendTo(form); + window.setTimeout(function () { + // Removing the form in a setTimeout call + // allows Chrome's developer tools to display + // the response result + form.remove(); + }, 0); + }); + form + .prop('target', iframe.prop('name')) + .prop('action', options.url) + .prop('method', options.type); + if (options.formData) { + $.each(options.formData, function (index, field) { + $('') + .prop('name', field.name) + .val(field.value) + .appendTo(form); + }); + } + if (options.fileInput && options.fileInput.length && + options.type === 'POST') { + fileInputClones = options.fileInput.clone(); + // Insert a clone for each file input field: + options.fileInput.after(function (index) { + return fileInputClones[index]; + }); + if (options.paramName) { + options.fileInput.each(function (index) { + $(this).prop( + 'name', + paramNames[index] || options.paramName + ); + }); + } + // Appending the file input fields to the hidden form + // removes them from their original location: + form + .append(options.fileInput) + .prop('enctype', 'multipart/form-data') + // enctype must be set as encoding for IE: + .prop('encoding', 'multipart/form-data'); + // Remove the HTML5 form attribute from the input(s): + options.fileInput.removeAttr('form'); + } + form.submit(); + // Insert the file input fields at their original location + // by replacing the clones with the originals: + if (fileInputClones && fileInputClones.length) { + options.fileInput.each(function (index, input) { + var clone = $(fileInputClones[index]); + // Restore the original name and form properties: + $(input) + .prop('name', clone.prop('name')) + .attr('form', clone.attr('form')); + clone.replaceWith(input); + }); + } + }); + form.append(iframe).appendTo(document.body); + }, + abort: function () { + if (iframe) { + // javascript:false as iframe src aborts the request + // and prevents warning popups on HTTPS in IE6. + // concat is used to avoid the "Script URL" JSLint error: + iframe + .unbind('load') + .prop('src', initialIframeSrc); + } + if (form) { + form.remove(); + } + } + }; + } + }); + + // The iframe transport returns the iframe content document as response. + // The following adds converters from iframe to text, json, html, xml + // and script. + // Please note that the Content-Type for JSON responses has to be text/plain + // or text/html, if the browser doesn't include application/json in the + // Accept header, else IE will show a download dialog. + // The Content-Type for XML responses on the other hand has to be always + // application/xml or text/xml, so IE properly parses the XML response. + // See also + // https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation + $.ajaxSetup({ + converters: { + 'iframe text': function (iframe) { + return iframe && $(iframe[0].body).text(); + }, + 'iframe json': function (iframe) { + return iframe && $.parseJSON($(iframe[0].body).text()); + }, + 'iframe html': function (iframe) { + return iframe && $(iframe[0].body).html(); + }, + 'iframe xml': function (iframe) { + var xmlDoc = iframe && iframe[0]; + return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc : + $.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) || + $(xmlDoc.body).html()); + }, + 'iframe script': function (iframe) { + return iframe && $.globalEval($(iframe[0].body).text()); + } + } + }); + +})); diff --git a/sources/library/jqupload/js/main.js b/sources/library/jqupload/js/main.js new file mode 100644 index 00000000..8f57967a --- /dev/null +++ b/sources/library/jqupload/js/main.js @@ -0,0 +1,75 @@ +/* + * jQuery File Upload Plugin JS Example 8.9.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global $, window */ + +$(function () { + 'use strict'; + + // Initialize the jQuery File Upload widget: + $('#fileupload').fileupload({ + // Uncomment the following to send cross-domain cookies: + //xhrFields: {withCredentials: true}, + url: 'server/php/' + }); + + // Enable iframe cross-domain access via redirect option: + $('#fileupload').fileupload( + 'option', + 'redirect', + window.location.href.replace( + /\/[^\/]*$/, + '/cors/result.html?%s' + ) + ); + + if (window.location.hostname === 'blueimp.github.io') { + // Demo settings: + $('#fileupload').fileupload('option', { + url: '//jquery-file-upload.appspot.com/', + // Enable image resizing, except for Android and Opera, + // which actually support image resizing, but fail to + // send Blob objects via XHR requests: + disableImageResize: /Android(?!.*Chrome)|Opera/ + .test(window.navigator.userAgent), + maxFileSize: 5000000, + acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i + }); + // Upload server status check for browsers with CORS support: + if ($.support.cors) { + $.ajax({ + url: '//jquery-file-upload.appspot.com/', + type: 'HEAD' + }).fail(function () { + $('
') + .text('Upload server currently unavailable - ' + + new Date()) + .appendTo('#fileupload'); + }); + } + } else { + // Load existing files: + $('#fileupload').addClass('fileupload-processing'); + $.ajax({ + // Uncomment the following to send cross-domain cookies: + //xhrFields: {withCredentials: true}, + url: $('#fileupload').fileupload('option', 'url'), + dataType: 'json', + context: $('#fileupload')[0] + }).always(function () { + $(this).removeClass('fileupload-processing'); + }).done(function (result) { + $(this).fileupload('option', 'done') + .call(this, $.Event('done'), {result: result}); + }); + } + +}); diff --git a/sources/library/jqupload/js/vendor/jquery.ui.widget.js b/sources/library/jqupload/js/vendor/jquery.ui.widget.js new file mode 100644 index 00000000..2d370893 --- /dev/null +++ b/sources/library/jqupload/js/vendor/jquery.ui.widget.js @@ -0,0 +1,530 @@ +/* + * jQuery UI Widget 1.10.3+amd + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2013 jQuery Foundation and other contributors + * Released under the MIT license. + * http://jquery.org/license + * + * http://api.jqueryui.com/jQuery.widget/ + */ + +(function (factory) { + if (typeof define === "function" && define.amd) { + // Register as an anonymous AMD module: + define(["jquery"], factory); + } else { + // Browser globals: + factory(jQuery); + } +}(function( $, undefined ) { + +var uuid = 0, + slice = Array.prototype.slice, + _cleanData = $.cleanData; +$.cleanData = function( elems ) { + for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) { + try { + $( elem ).triggerHandler( "remove" ); + // http://bugs.jquery.com/ticket/8235 + } catch( e ) {} + } + _cleanData( elems ); +}; + +$.widget = function( name, base, prototype ) { + var fullName, existingConstructor, constructor, basePrototype, + // proxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + proxiedPrototype = {}, + namespace = name.split( "." )[ 0 ]; + + name = name.split( "." )[ 1 ]; + fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + // create selector for plugin + $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + // allow instantiation without "new" keyword + if ( !this._createWidget ) { + return new constructor( options, element ); + } + + // allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + // extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + // copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + // track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + }); + + basePrototype = new base(); + // we need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( !$.isFunction( value ) ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = (function() { + var _super = function() { + return base.prototype[ prop ].apply( this, arguments ); + }, + _superApply = function( args ) { + return base.prototype[ prop ].apply( this, args ); + }; + return function() { + var __super = this._super, + __superApply = this._superApply, + returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + })(); + }); + constructor.prototype = $.widget.extend( basePrototype, { + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? basePrototype.widgetEventPrefix : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + }); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, child._proto ); + }); + // remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); +}; + +$.widget.extend = function( target ) { + var input = slice.call( arguments, 1 ), + inputIndex = 0, + inputLength = input.length, + key, + value; + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) { + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string", + args = slice.call( arguments, 1 ), + returnValue = this; + + // allow multiple hashes to be passed on init + options = !isMethodCall && args.length ? + $.widget.extend.apply( null, [ options ].concat(args) ) : + options; + + if ( isMethodCall ) { + this.each(function() { + var methodValue, + instance = $.data( this, fullName ); + if ( !instance ) { + return $.error( "cannot call methods on " + name + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + if ( !$.isFunction( instance[options] ) || options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + " widget instance" ); + } + methodValue = instance[ options ].apply( instance, args ); + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + }); + } else { + this.each(function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} )._init(); + } else { + $.data( this, fullName, new object( options, this ) ); + } + }); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
", + options: { + disabled: false, + + // callbacks + create: null + }, + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = uuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + }); + this.document = $( element.style ? + // element within the document + element.ownerDocument : + // element is window or document + element.document || element ); + this.window = $( this.document[0].defaultView || this.document[0].parentWindow ); + } + + this._create(); + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + _getCreateOptions: $.noop, + _getCreateEventData: $.noop, + _create: $.noop, + _init: $.noop, + + destroy: function() { + this._destroy(); + // we can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .unbind( this.eventNamespace ) + // 1.9 BC for #7810 + // TODO remove dual storage + .removeData( this.widgetName ) + .removeData( this.widgetFullName ) + // support: jquery <1.6.3 + // http://bugs.jquery.com/ticket/9413 + .removeData( $.camelCase( this.widgetFullName ) ); + this.widget() + .unbind( this.eventNamespace ) + .removeAttr( "aria-disabled" ) + .removeClass( + this.widgetFullName + "-disabled " + + "ui-state-disabled" ); + + // clean up events and states + this.bindings.unbind( this.eventNamespace ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + }, + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key, + parts, + curOption, + i; + + if ( arguments.length === 0 ) { + // don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + // handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( value === undefined ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( value === undefined ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + _setOption: function( key, value ) { + this.options[ key ] = value; + + if ( key === "disabled" ) { + this.widget() + .toggleClass( this.widgetFullName + "-disabled ui-state-disabled", !!value ) + .attr( "aria-disabled", value ); + this.hoverable.removeClass( "ui-state-hover" ); + this.focusable.removeClass( "ui-state-focus" ); + } + + return this; + }, + + enable: function() { + return this._setOption( "disabled", false ); + }, + disable: function() { + return this._setOption( "disabled", true ); + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement, + instance = this; + + // no suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // no element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + // accept selectors, DOM elements + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + // allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^(\w+)\s*(.*)$/ ), + eventName = match[1] + instance.eventNamespace, + selector = match[2]; + if ( selector ) { + delegateElement.delegate( selector, eventName, handlerProxy ); + } else { + element.bind( eventName, handlerProxy ); + } + }); + }, + + _off: function( element, eventName ) { + eventName = (eventName || "").split( " " ).join( this.eventNamespace + " " ) + this.eventNamespace; + element.unbind( eventName ).undelegate( eventName ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + $( event.currentTarget ).addClass( "ui-state-hover" ); + }, + mouseleave: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-hover" ); + } + }); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + $( event.currentTarget ).addClass( "ui-state-focus" ); + }, + focusout: function( event ) { + $( event.currentTarget ).removeClass( "ui-state-focus" ); + } + }); + }, + + _trigger: function( type, event, data ) { + var prop, orig, + callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + // the original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( $.isFunction( callback ) && + callback.apply( this.element[0], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + var hasOptions, + effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + if ( options.delay ) { + element.delay( options.delay ); + } + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue(function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + }); + } + }; +}); + +})); diff --git a/sources/library/jqupload/package.json b/sources/library/jqupload/package.json new file mode 100644 index 00000000..85852c35 --- /dev/null +++ b/sources/library/jqupload/package.json @@ -0,0 +1,54 @@ +{ + "name": "blueimp-file-upload", + "version": "9.5.2", + "title": "jQuery File Upload", + "description": "File Upload widget with multiple file selection, drag&drop support, progress bar, validation and preview images, audio and video for jQuery. Supports cross-domain, chunked and resumable file uploads. Works with any server-side platform (Google App Engine, PHP, Python, Ruby on Rails, Java, etc.) that supports standard HTML form file uploads.", + "keywords": [ + "jquery", + "file", + "upload", + "widget", + "multiple", + "selection", + "drag", + "drop", + "progress", + "preview", + "cross-domain", + "cross-site", + "chunk", + "resume", + "gae", + "go", + "python", + "php", + "bootstrap" + ], + "homepage": "https://github.com/blueimp/jQuery-File-Upload", + "author": { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + }, + "maintainers": [ + { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/blueimp/jQuery-File-Upload.git" + }, + "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/MIT" + } + ], + "devDependencies": { + "grunt": "~0.4.2", + "grunt-bump-build-git": "~1.1.1", + "grunt-contrib-jshint": "~0.8.0" + } +} diff --git a/sources/library/jqupload/server/gae-go/app.yaml b/sources/library/jqupload/server/gae-go/app.yaml new file mode 100644 index 00000000..2d09daa5 --- /dev/null +++ b/sources/library/jqupload/server/gae-go/app.yaml @@ -0,0 +1,12 @@ +application: jquery-file-upload +version: 2 +runtime: go +api_version: go1 + +handlers: +- url: /(favicon\.ico|robots\.txt) + static_files: static/\1 + upload: static/(.*) + expiration: '1d' +- url: /.* + script: _go_app diff --git a/sources/library/jqupload/server/gae-go/app/main.go b/sources/library/jqupload/server/gae-go/app/main.go new file mode 100644 index 00000000..f995f73a --- /dev/null +++ b/sources/library/jqupload/server/gae-go/app/main.go @@ -0,0 +1,296 @@ +/* + * jQuery File Upload Plugin GAE Go Example 3.1.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2011, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +package app + +import ( + "appengine" + "appengine/blobstore" + "appengine/image" + "appengine/taskqueue" + "bytes" + "encoding/json" + "fmt" + "io" + "log" + "mime/multipart" + "net/http" + "net/url" + "regexp" + "strings" + "time" +) + +const ( + WEBSITE = "http://blueimp.github.io/jQuery-File-Upload/" + MIN_FILE_SIZE = 1 // bytes + MAX_FILE_SIZE = 5000000 // bytes + IMAGE_TYPES = "image/(gif|p?jpeg|(x-)?png)" + ACCEPT_FILE_TYPES = IMAGE_TYPES + EXPIRATION_TIME = 300 // seconds + THUMBNAIL_PARAM = "=s80" +) + +var ( + imageTypes = regexp.MustCompile(IMAGE_TYPES) + acceptFileTypes = regexp.MustCompile(ACCEPT_FILE_TYPES) +) + +type FileInfo struct { + Key appengine.BlobKey `json:"-"` + Url string `json:"url,omitempty"` + ThumbnailUrl string `json:"thumbnailUrl,omitempty"` + Name string `json:"name"` + Type string `json:"type"` + Size int64 `json:"size"` + Error string `json:"error,omitempty"` + DeleteUrl string `json:"deleteUrl,omitempty"` + DeleteType string `json:"deleteType,omitempty"` +} + +func (fi *FileInfo) ValidateType() (valid bool) { + if acceptFileTypes.MatchString(fi.Type) { + return true + } + fi.Error = "Filetype not allowed" + return false +} + +func (fi *FileInfo) ValidateSize() (valid bool) { + if fi.Size < MIN_FILE_SIZE { + fi.Error = "File is too small" + } else if fi.Size > MAX_FILE_SIZE { + fi.Error = "File is too big" + } else { + return true + } + return false +} + +func (fi *FileInfo) CreateUrls(r *http.Request, c appengine.Context) { + u := &url.URL{ + Scheme: r.URL.Scheme, + Host: appengine.DefaultVersionHostname(c), + Path: "/", + } + uString := u.String() + fi.Url = uString + escape(string(fi.Key)) + "/" + + escape(string(fi.Name)) + fi.DeleteUrl = fi.Url + "?delete=true" + fi.DeleteType = "DELETE" + if imageTypes.MatchString(fi.Type) { + servingUrl, err := image.ServingURL( + c, + fi.Key, + &image.ServingURLOptions{ + Secure: strings.HasSuffix(u.Scheme, "s"), + Size: 0, + Crop: false, + }, + ) + check(err) + fi.ThumbnailUrl = servingUrl.String() + THUMBNAIL_PARAM + } +} + +func check(err error) { + if err != nil { + panic(err) + } +} + +func escape(s string) string { + return strings.Replace(url.QueryEscape(s), "+", "%20", -1) +} + +func delayedDelete(c appengine.Context, fi *FileInfo) { + if key := string(fi.Key); key != "" { + task := &taskqueue.Task{ + Path: "/" + escape(key) + "/-", + Method: "DELETE", + Delay: time.Duration(EXPIRATION_TIME) * time.Second, + } + taskqueue.Add(c, task, "") + } +} + +func handleUpload(r *http.Request, p *multipart.Part) (fi *FileInfo) { + fi = &FileInfo{ + Name: p.FileName(), + Type: p.Header.Get("Content-Type"), + } + if !fi.ValidateType() { + return + } + defer func() { + if rec := recover(); rec != nil { + log.Println(rec) + fi.Error = rec.(error).Error() + } + }() + lr := &io.LimitedReader{R: p, N: MAX_FILE_SIZE + 1} + context := appengine.NewContext(r) + w, err := blobstore.Create(context, fi.Type) + defer func() { + w.Close() + fi.Size = MAX_FILE_SIZE + 1 - lr.N + fi.Key, err = w.Key() + check(err) + if !fi.ValidateSize() { + err := blobstore.Delete(context, fi.Key) + check(err) + return + } + delayedDelete(context, fi) + fi.CreateUrls(r, context) + }() + check(err) + _, err = io.Copy(w, lr) + return +} + +func getFormValue(p *multipart.Part) string { + var b bytes.Buffer + io.CopyN(&b, p, int64(1<<20)) // Copy max: 1 MiB + return b.String() +} + +func handleUploads(r *http.Request) (fileInfos []*FileInfo) { + fileInfos = make([]*FileInfo, 0) + mr, err := r.MultipartReader() + check(err) + r.Form, err = url.ParseQuery(r.URL.RawQuery) + check(err) + part, err := mr.NextPart() + for err == nil { + if name := part.FormName(); name != "" { + if part.FileName() != "" { + fileInfos = append(fileInfos, handleUpload(r, part)) + } else { + r.Form[name] = append(r.Form[name], getFormValue(part)) + } + } + part, err = mr.NextPart() + } + return +} + +func get(w http.ResponseWriter, r *http.Request) { + if r.URL.Path == "/" { + http.Redirect(w, r, WEBSITE, http.StatusFound) + return + } + parts := strings.Split(r.URL.Path, "/") + if len(parts) == 3 { + if key := parts[1]; key != "" { + blobKey := appengine.BlobKey(key) + bi, err := blobstore.Stat(appengine.NewContext(r), blobKey) + if err == nil { + w.Header().Add("X-Content-Type-Options", "nosniff") + if !imageTypes.MatchString(bi.ContentType) { + w.Header().Add("Content-Type", "application/octet-stream") + w.Header().Add( + "Content-Disposition", + fmt.Sprintf("attachment; filename=\"%s\"", parts[2]), + ) + } + w.Header().Add( + "Cache-Control", + fmt.Sprintf("public,max-age=%d", EXPIRATION_TIME), + ) + blobstore.Send(w, blobKey) + return + } + } + } + http.Error(w, "404 Not Found", http.StatusNotFound) +} + +func post(w http.ResponseWriter, r *http.Request) { + result := make(map[string][]*FileInfo, 1) + result["files"] = handleUploads(r) + b, err := json.Marshal(result) + check(err) + if redirect := r.FormValue("redirect"); redirect != "" { + if strings.Contains(redirect, "%s") { + redirect = fmt.Sprintf( + redirect, + escape(string(b)), + ) + } + http.Redirect(w, r, redirect, http.StatusFound) + return + } + w.Header().Set("Cache-Control", "no-cache") + jsonType := "application/json" + if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { + w.Header().Set("Content-Type", jsonType) + } + fmt.Fprintln(w, string(b)) +} + +func delete(w http.ResponseWriter, r *http.Request) { + parts := strings.Split(r.URL.Path, "/") + if len(parts) != 3 { + return + } + result := make(map[string]bool, 1) + if key := parts[1]; key != "" { + c := appengine.NewContext(r) + blobKey := appengine.BlobKey(key) + err := blobstore.Delete(c, blobKey) + check(err) + err = image.DeleteServingURL(c, blobKey) + check(err) + result[key] = true + } + jsonType := "application/json" + if strings.Index(r.Header.Get("Accept"), jsonType) != -1 { + w.Header().Set("Content-Type", jsonType) + } + b, err := json.Marshal(result) + check(err) + fmt.Fprintln(w, string(b)) +} + +func handle(w http.ResponseWriter, r *http.Request) { + params, err := url.ParseQuery(r.URL.RawQuery) + check(err) + w.Header().Add("Access-Control-Allow-Origin", "*") + w.Header().Add( + "Access-Control-Allow-Methods", + "OPTIONS, HEAD, GET, POST, PUT, DELETE", + ) + w.Header().Add( + "Access-Control-Allow-Headers", + "Content-Type, Content-Range, Content-Disposition", + ) + switch r.Method { + case "OPTIONS": + case "HEAD": + case "GET": + get(w, r) + case "POST": + if len(params["_method"]) > 0 && params["_method"][0] == "DELETE" { + delete(w, r) + } else { + post(w, r) + } + case "DELETE": + delete(w, r) + default: + http.Error(w, "501 Not Implemented", http.StatusNotImplemented) + } +} + +func init() { + http.HandleFunc("/", handle) +} diff --git a/sources/library/jqupload/server/gae-go/static/robots.txt b/sources/library/jqupload/server/gae-go/static/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/sources/library/jqupload/server/gae-go/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/sources/library/jqupload/server/gae-python/app.yaml b/sources/library/jqupload/server/gae-python/app.yaml new file mode 100644 index 00000000..5fe123f5 --- /dev/null +++ b/sources/library/jqupload/server/gae-python/app.yaml @@ -0,0 +1,16 @@ +application: jquery-file-upload +version: 1 +runtime: python27 +api_version: 1 +threadsafe: true + +builtins: +- deferred: on + +handlers: +- url: /(favicon\.ico|robots\.txt) + static_files: static/\1 + upload: static/(.*) + expiration: '1d' +- url: /.* + script: main.app diff --git a/sources/library/jqupload/server/gae-python/main.py b/sources/library/jqupload/server/gae-python/main.py new file mode 100644 index 00000000..37aa44e3 --- /dev/null +++ b/sources/library/jqupload/server/gae-python/main.py @@ -0,0 +1,170 @@ +# -*- coding: utf-8 -*- +# +# jQuery File Upload Plugin GAE Python Example 2.1.1 +# https://github.com/blueimp/jQuery-File-Upload +# +# Copyright 2011, Sebastian Tschan +# https://blueimp.net +# +# Licensed under the MIT license: +# http://www.opensource.org/licenses/MIT +# + +from __future__ import with_statement +from google.appengine.api import files, images +from google.appengine.ext import blobstore, deferred +from google.appengine.ext.webapp import blobstore_handlers +import json +import re +import urllib +import webapp2 + +WEBSITE = 'http://blueimp.github.io/jQuery-File-Upload/' +MIN_FILE_SIZE = 1 # bytes +MAX_FILE_SIZE = 5000000 # bytes +IMAGE_TYPES = re.compile('image/(gif|p?jpeg|(x-)?png)') +ACCEPT_FILE_TYPES = IMAGE_TYPES +THUMBNAIL_MODIFICATOR = '=s80' # max width / height +EXPIRATION_TIME = 300 # seconds + + +def cleanup(blob_keys): + blobstore.delete(blob_keys) + + +class UploadHandler(webapp2.RequestHandler): + + def initialize(self, request, response): + super(UploadHandler, self).initialize(request, response) + self.response.headers['Access-Control-Allow-Origin'] = '*' + self.response.headers[ + 'Access-Control-Allow-Methods' + ] = 'OPTIONS, HEAD, GET, POST, PUT, DELETE' + self.response.headers[ + 'Access-Control-Allow-Headers' + ] = 'Content-Type, Content-Range, Content-Disposition' + + def validate(self, file): + if file['size'] < MIN_FILE_SIZE: + file['error'] = 'File is too small' + elif file['size'] > MAX_FILE_SIZE: + file['error'] = 'File is too big' + elif not ACCEPT_FILE_TYPES.match(file['type']): + file['error'] = 'Filetype not allowed' + else: + return True + return False + + def get_file_size(self, file): + file.seek(0, 2) # Seek to the end of the file + size = file.tell() # Get the position of EOF + file.seek(0) # Reset the file position to the beginning + return size + + def write_blob(self, data, info): + blob = files.blobstore.create( + mime_type=info['type'], + _blobinfo_uploaded_filename=info['name'] + ) + with files.open(blob, 'a') as f: + f.write(data) + files.finalize(blob) + return files.blobstore.get_blob_key(blob) + + def handle_upload(self): + results = [] + blob_keys = [] + for name, fieldStorage in self.request.POST.items(): + if type(fieldStorage) is unicode: + continue + result = {} + result['name'] = re.sub( + r'^.*\\', + '', + fieldStorage.filename + ) + result['type'] = fieldStorage.type + result['size'] = self.get_file_size(fieldStorage.file) + if self.validate(result): + blob_key = str( + self.write_blob(fieldStorage.value, result) + ) + blob_keys.append(blob_key) + result['deleteType'] = 'DELETE' + result['deleteUrl'] = self.request.host_url +\ + '/?key=' + urllib.quote(blob_key, '') + if (IMAGE_TYPES.match(result['type'])): + try: + result['url'] = images.get_serving_url( + blob_key, + secure_url=self.request.host_url.startswith( + 'https' + ) + ) + result['thumbnailUrl'] = result['url'] +\ + THUMBNAIL_MODIFICATOR + except: # Could not get an image serving url + pass + if not 'url' in result: + result['url'] = self.request.host_url +\ + '/' + blob_key + '/' + urllib.quote( + result['name'].encode('utf-8'), '') + results.append(result) + deferred.defer( + cleanup, + blob_keys, + _countdown=EXPIRATION_TIME + ) + return results + + def options(self): + pass + + def head(self): + pass + + def get(self): + self.redirect(WEBSITE) + + def post(self): + if (self.request.get('_method') == 'DELETE'): + return self.delete() + result = {'files': self.handle_upload()} + s = json.dumps(result, separators=(',', ':')) + redirect = self.request.get('redirect') + if redirect: + return self.redirect(str( + redirect.replace('%s', urllib.quote(s, ''), 1) + )) + if 'application/json' in self.request.headers.get('Accept'): + self.response.headers['Content-Type'] = 'application/json' + self.response.write(s) + + def delete(self): + key = self.request.get('key') or '' + blobstore.delete(key) + s = json.dumps({key: True}, separators=(',', ':')) + if 'application/json' in self.request.headers.get('Accept'): + self.response.headers['Content-Type'] = 'application/json' + self.response.write(s) + + +class DownloadHandler(blobstore_handlers.BlobstoreDownloadHandler): + def get(self, key, filename): + if not blobstore.get(key): + self.error(404) + else: + # Prevent browsers from MIME-sniffing the content-type: + self.response.headers['X-Content-Type-Options'] = 'nosniff' + # Cache for the expiration time: + self.response.headers['Cache-Control'] = 'public,max-age=%d' % EXPIRATION_TIME + # Send the file forcing a download dialog: + self.send_blob(key, save_as=filename, content_type='application/octet-stream') + +app = webapp2.WSGIApplication( + [ + ('/', UploadHandler), + ('/([^/]+)/([^/]+)', DownloadHandler) + ], + debug=True +) diff --git a/sources/library/jqupload/server/gae-python/static/robots.txt b/sources/library/jqupload/server/gae-python/static/robots.txt new file mode 100644 index 00000000..eb053628 --- /dev/null +++ b/sources/library/jqupload/server/gae-python/static/robots.txt @@ -0,0 +1,2 @@ +User-agent: * +Disallow: diff --git a/sources/library/jqupload/server/node/.gitignore b/sources/library/jqupload/server/node/.gitignore new file mode 100644 index 00000000..9daa8247 --- /dev/null +++ b/sources/library/jqupload/server/node/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +node_modules diff --git a/sources/library/jqupload/server/node/package.json b/sources/library/jqupload/server/node/package.json new file mode 100644 index 00000000..dd38c50c --- /dev/null +++ b/sources/library/jqupload/server/node/package.json @@ -0,0 +1,41 @@ +{ + "name": "blueimp-file-upload-node", + "version": "2.1.0", + "title": "jQuery File Upload Node.js example", + "description": "Node.js implementation example of a file upload handler for jQuery File Upload.", + "keywords": [ + "file", + "upload", + "cross-domain", + "cross-site", + "node" + ], + "homepage": "https://github.com/blueimp/jQuery-File-Upload", + "author": { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + }, + "maintainers": [ + { + "name": "Sebastian Tschan", + "url": "https://blueimp.net" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/blueimp/jQuery-File-Upload.git" + }, + "bugs": "https://github.com/blueimp/jQuery-File-Upload/issues", + "licenses": [ + { + "type": "MIT", + "url": "http://www.opensource.org/licenses/MIT" + } + ], + "dependencies": { + "formidable": ">=1.0.11", + "node-static": ">=0.6.5", + "imagemagick": ">=0.1.3" + }, + "main": "server.js" +} diff --git a/sources/library/jqupload/server/node/public/files/.gitignore b/sources/library/jqupload/server/node/public/files/.gitignore new file mode 100644 index 00000000..d6b7ef32 --- /dev/null +++ b/sources/library/jqupload/server/node/public/files/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/sources/library/jqupload/server/node/server.js b/sources/library/jqupload/server/node/server.js new file mode 100755 index 00000000..5eb07a6e --- /dev/null +++ b/sources/library/jqupload/server/node/server.js @@ -0,0 +1,292 @@ +#!/usr/bin/env node +/* + * jQuery File Upload Plugin Node.js Example 2.1.1 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2012, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* jshint nomen:false */ +/* global require, __dirname, unescape, console */ + +(function (port) { + 'use strict'; + var path = require('path'), + fs = require('fs'), + // Since Node 0.8, .existsSync() moved from path to fs: + _existsSync = fs.existsSync || path.existsSync, + formidable = require('formidable'), + nodeStatic = require('node-static'), + imageMagick = require('imagemagick'), + options = { + tmpDir: __dirname + '/tmp', + publicDir: __dirname + '/public', + uploadDir: __dirname + '/public/files', + uploadUrl: '/files/', + maxPostSize: 11000000000, // 11 GB + minFileSize: 1, + maxFileSize: 10000000000, // 10 GB + acceptFileTypes: /.+/i, + // Files not matched by this regular expression force a download dialog, + // to prevent executing any scripts in the context of the service domain: + inlineFileTypes: /\.(gif|jpe?g|png)$/i, + imageTypes: /\.(gif|jpe?g|png)$/i, + imageVersions: { + 'thumbnail': { + width: 80, + height: 80 + } + }, + accessControl: { + allowOrigin: '*', + allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE', + allowHeaders: 'Content-Type, Content-Range, Content-Disposition' + }, + /* Uncomment and edit this section to provide the service via HTTPS: + ssl: { + key: fs.readFileSync('/Applications/XAMPP/etc/ssl.key/server.key'), + cert: fs.readFileSync('/Applications/XAMPP/etc/ssl.crt/server.crt') + }, + */ + nodeStatic: { + cache: 3600 // seconds to cache served files + } + }, + utf8encode = function (str) { + return unescape(encodeURIComponent(str)); + }, + fileServer = new nodeStatic.Server(options.publicDir, options.nodeStatic), + nameCountRegexp = /(?:(?: \(([\d]+)\))?(\.[^.]+))?$/, + nameCountFunc = function (s, index, ext) { + return ' (' + ((parseInt(index, 10) || 0) + 1) + ')' + (ext || ''); + }, + FileInfo = function (file) { + this.name = file.name; + this.size = file.size; + this.type = file.type; + this.deleteType = 'DELETE'; + }, + UploadHandler = function (req, res, callback) { + this.req = req; + this.res = res; + this.callback = callback; + }, + serve = function (req, res) { + res.setHeader( + 'Access-Control-Allow-Origin', + options.accessControl.allowOrigin + ); + res.setHeader( + 'Access-Control-Allow-Methods', + options.accessControl.allowMethods + ); + res.setHeader( + 'Access-Control-Allow-Headers', + options.accessControl.allowHeaders + ); + var handleResult = function (result, redirect) { + if (redirect) { + res.writeHead(302, { + 'Location': redirect.replace( + /%s/, + encodeURIComponent(JSON.stringify(result)) + ) + }); + res.end(); + } else { + res.writeHead(200, { + 'Content-Type': req.headers.accept + .indexOf('application/json') !== -1 ? + 'application/json' : 'text/plain' + }); + res.end(JSON.stringify(result)); + } + }, + setNoCacheHeaders = function () { + res.setHeader('Pragma', 'no-cache'); + res.setHeader('Cache-Control', 'no-store, no-cache, must-revalidate'); + res.setHeader('Content-Disposition', 'inline; filename="files.json"'); + }, + handler = new UploadHandler(req, res, handleResult); + switch (req.method) { + case 'OPTIONS': + res.end(); + break; + case 'HEAD': + case 'GET': + if (req.url === '/') { + setNoCacheHeaders(); + if (req.method === 'GET') { + handler.get(); + } else { + res.end(); + } + } else { + fileServer.serve(req, res); + } + break; + case 'POST': + setNoCacheHeaders(); + handler.post(); + break; + case 'DELETE': + handler.destroy(); + break; + default: + res.statusCode = 405; + res.end(); + } + }; + fileServer.respond = function (pathname, status, _headers, files, stat, req, res, finish) { + // Prevent browsers from MIME-sniffing the content-type: + _headers['X-Content-Type-Options'] = 'nosniff'; + if (!options.inlineFileTypes.test(files[0])) { + // Force a download dialog for unsafe file extensions: + _headers['Content-Type'] = 'application/octet-stream'; + _headers['Content-Disposition'] = 'attachment; filename="' + + utf8encode(path.basename(files[0])) + '"'; + } + nodeStatic.Server.prototype.respond + .call(this, pathname, status, _headers, files, stat, req, res, finish); + }; + FileInfo.prototype.validate = function () { + if (options.minFileSize && options.minFileSize > this.size) { + this.error = 'File is too small'; + } else if (options.maxFileSize && options.maxFileSize < this.size) { + this.error = 'File is too big'; + } else if (!options.acceptFileTypes.test(this.name)) { + this.error = 'Filetype not allowed'; + } + return !this.error; + }; + FileInfo.prototype.safeName = function () { + // Prevent directory traversal and creating hidden system files: + this.name = path.basename(this.name).replace(/^\.+/, ''); + // Prevent overwriting existing files: + while (_existsSync(options.uploadDir + '/' + this.name)) { + this.name = this.name.replace(nameCountRegexp, nameCountFunc); + } + }; + FileInfo.prototype.initUrls = function (req) { + if (!this.error) { + var that = this, + baseUrl = (options.ssl ? 'https:' : 'http:') + + '//' + req.headers.host + options.uploadUrl; + this.url = this.deleteUrl = baseUrl + encodeURIComponent(this.name); + Object.keys(options.imageVersions).forEach(function (version) { + if (_existsSync( + options.uploadDir + '/' + version + '/' + that.name + )) { + that[version + 'Url'] = baseUrl + version + '/' + + encodeURIComponent(that.name); + } + }); + } + }; + UploadHandler.prototype.get = function () { + var handler = this, + files = []; + fs.readdir(options.uploadDir, function (err, list) { + list.forEach(function (name) { + var stats = fs.statSync(options.uploadDir + '/' + name), + fileInfo; + if (stats.isFile() && name[0] !== '.') { + fileInfo = new FileInfo({ + name: name, + size: stats.size + }); + fileInfo.initUrls(handler.req); + files.push(fileInfo); + } + }); + handler.callback({files: files}); + }); + }; + UploadHandler.prototype.post = function () { + var handler = this, + form = new formidable.IncomingForm(), + tmpFiles = [], + files = [], + map = {}, + counter = 1, + redirect, + finish = function () { + counter -= 1; + if (!counter) { + files.forEach(function (fileInfo) { + fileInfo.initUrls(handler.req); + }); + handler.callback({files: files}, redirect); + } + }; + form.uploadDir = options.tmpDir; + form.on('fileBegin', function (name, file) { + tmpFiles.push(file.path); + var fileInfo = new FileInfo(file, handler.req, true); + fileInfo.safeName(); + map[path.basename(file.path)] = fileInfo; + files.push(fileInfo); + }).on('field', function (name, value) { + if (name === 'redirect') { + redirect = value; + } + }).on('file', function (name, file) { + var fileInfo = map[path.basename(file.path)]; + fileInfo.size = file.size; + if (!fileInfo.validate()) { + fs.unlink(file.path); + return; + } + fs.renameSync(file.path, options.uploadDir + '/' + fileInfo.name); + if (options.imageTypes.test(fileInfo.name)) { + Object.keys(options.imageVersions).forEach(function (version) { + counter += 1; + var opts = options.imageVersions[version]; + imageMagick.resize({ + width: opts.width, + height: opts.height, + srcPath: options.uploadDir + '/' + fileInfo.name, + dstPath: options.uploadDir + '/' + version + '/' + + fileInfo.name + }, finish); + }); + } + }).on('aborted', function () { + tmpFiles.forEach(function (file) { + fs.unlink(file); + }); + }).on('error', function (e) { + console.log(e); + }).on('progress', function (bytesReceived) { + if (bytesReceived > options.maxPostSize) { + handler.req.connection.destroy(); + } + }).on('end', finish).parse(handler.req); + }; + UploadHandler.prototype.destroy = function () { + var handler = this, + fileName; + if (handler.req.url.slice(0, options.uploadUrl.length) === options.uploadUrl) { + fileName = path.basename(decodeURIComponent(handler.req.url)); + if (fileName[0] !== '.') { + fs.unlink(options.uploadDir + '/' + fileName, function (ex) { + Object.keys(options.imageVersions).forEach(function (version) { + fs.unlink(options.uploadDir + '/' + version + '/' + fileName); + }); + handler.callback({success: !ex}); + }); + return; + } + } + handler.callback({success: false}); + }; + if (options.ssl) { + require('https').createServer(options.ssl, serve).listen(port); + } else { + require('http').createServer(serve).listen(port); + } +}(8888)); diff --git a/sources/library/jqupload/server/node/tmp/.gitignore b/sources/library/jqupload/server/node/tmp/.gitignore new file mode 100644 index 00000000..e69de29b diff --git a/sources/library/jqupload/server/php/UploadHandler.php b/sources/library/jqupload/server/php/UploadHandler.php new file mode 100644 index 00000000..66545b12 --- /dev/null +++ b/sources/library/jqupload/server/php/UploadHandler.php @@ -0,0 +1,1329 @@ + 'The uploaded file exceeds the upload_max_filesize directive in php.ini', + 2 => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form', + 3 => 'The uploaded file was only partially uploaded', + 4 => 'No file was uploaded', + 6 => 'Missing a temporary folder', + 7 => 'Failed to write file to disk', + 8 => 'A PHP extension stopped the file upload', + 'post_max_size' => 'The uploaded file exceeds the post_max_size directive in php.ini', + 'max_file_size' => 'File is too big', + 'min_file_size' => 'File is too small', + 'accept_file_types' => 'Filetype not allowed', + 'max_number_of_files' => 'Maximum number of files exceeded', + 'max_width' => 'Image exceeds maximum width', + 'min_width' => 'Image requires a minimum width', + 'max_height' => 'Image exceeds maximum height', + 'min_height' => 'Image requires a minimum height', + 'abort' => 'File upload aborted', + 'image_resize' => 'Failed to resize image' + ); + + protected $image_objects = array(); + + function __construct($options = null, $initialize = true, $error_messages = null) { + $this->options = array( + 'script_url' => $this->get_full_url().'/', + 'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/files/', + 'upload_url' => $this->get_full_url().'/files/', + 'user_dirs' => false, + 'mkdir_mode' => 0755, + 'param_name' => 'files', + // Set the following option to 'POST', if your server does not support + // DELETE requests. This is a parameter sent to the client: + 'delete_type' => 'DELETE', + 'access_control_allow_origin' => '*', + 'access_control_allow_credentials' => false, + 'access_control_allow_methods' => array( + 'OPTIONS', + 'HEAD', + 'GET', + 'POST', + 'PUT', + 'PATCH', + 'DELETE' + ), + 'access_control_allow_headers' => array( + 'Content-Type', + 'Content-Range', + 'Content-Disposition' + ), + // Enable to provide file downloads via GET requests to the PHP script: + // 1. Set to 1 to download files via readfile method through PHP + // 2. Set to 2 to send a X-Sendfile header for lighttpd/Apache + // 3. Set to 3 to send a X-Accel-Redirect header for nginx + // If set to 2 or 3, adjust the upload_url option to the base path of + // the redirect parameter, e.g. '/files/'. + 'download_via_php' => false, + // Read files in chunks to avoid memory limits when download_via_php + // is enabled, set to 0 to disable chunked reading of files: + 'readfile_chunk_size' => 10 * 1024 * 1024, // 10 MiB + // Defines which files can be displayed inline when downloaded: + 'inline_file_types' => '/\.(gif|jpe?g|png)$/i', + // Defines which files (based on their names) are accepted for upload: + 'accept_file_types' => '/.+$/i', + // The php.ini settings upload_max_filesize and post_max_size + // take precedence over the following max_file_size setting: + 'max_file_size' => null, + 'min_file_size' => 1, + // The maximum number of files for the upload directory: + 'max_number_of_files' => null, + // Defines which files are handled as image files: + 'image_file_types' => '/\.(gif|jpe?g|png)$/i', + // Image resolution restrictions: + 'max_width' => null, + 'max_height' => null, + 'min_width' => 1, + 'min_height' => 1, + // Set the following option to false to enable resumable uploads: + 'discard_aborted_uploads' => true, + // Set to 0 to use the GD library to scale and orient images, + // set to 1 to use imagick (if installed, falls back to GD), + // set to 2 to use the ImageMagick convert binary directly: + 'image_library' => 1, + // Uncomment the following to define an array of resource limits + // for imagick: + /* + 'imagick_resource_limits' => array( + imagick::RESOURCETYPE_MAP => 32, + imagick::RESOURCETYPE_MEMORY => 32 + ), + */ + // Command or path for to the ImageMagick convert binary: + 'convert_bin' => 'convert', + // Uncomment the following to add parameters in front of each + // ImageMagick convert call (the limit constraints seem only + // to have an effect if put in front): + /* + 'convert_params' => '-limit memory 32MiB -limit map 32MiB', + */ + // Command or path for to the ImageMagick identify binary: + 'identify_bin' => 'identify', + 'image_versions' => array( + // The empty image version key defines options for the original image: + '' => array( + // Automatically rotate images based on EXIF meta data: + 'auto_orient' => true + ), + // Uncomment the following to create medium sized images: + /* + 'medium' => array( + 'max_width' => 800, + 'max_height' => 600 + ), + */ + 'thumbnail' => array( + // Uncomment the following to use a defined directory for the thumbnails + // instead of a subdirectory based on the version identifier. + // Make sure that this directory doesn't allow execution of files if you + // don't pose any restrictions on the type of uploaded files, e.g. by + // copying the .htaccess file from the files directory for Apache: + //'upload_dir' => dirname($this->get_server_var('SCRIPT_FILENAME')).'/thumb/', + //'upload_url' => $this->get_full_url().'/thumb/', + // Uncomment the following to force the max + // dimensions and e.g. create square thumbnails: + //'crop' => true, + 'max_width' => 80, + 'max_height' => 80 + ) + ) + ); + if ($options) { + $this->options = $options + $this->options; + } + if ($error_messages) { + $this->error_messages = $error_messages + $this->error_messages; + } + if ($initialize) { + $this->initialize(); + } + } + + protected function initialize() { + switch ($this->get_server_var('REQUEST_METHOD')) { + case 'OPTIONS': + case 'HEAD': + $this->head(); + break; + case 'GET': + $this->get(); + break; + case 'PATCH': + case 'PUT': + case 'POST': + $this->post(); + break; + case 'DELETE': + $this->delete(); + break; + default: + $this->header('HTTP/1.1 405 Method Not Allowed'); + } + } + + protected function get_full_url() { + $https = !empty($_SERVER['HTTPS']) && strcasecmp($_SERVER['HTTPS'], 'on') === 0; + return + ($https ? 'https://' : 'http://'). + (!empty($_SERVER['REMOTE_USER']) ? $_SERVER['REMOTE_USER'].'@' : ''). + (isset($_SERVER['HTTP_HOST']) ? $_SERVER['HTTP_HOST'] : ($_SERVER['SERVER_NAME']. + ($https && $_SERVER['SERVER_PORT'] === 443 || + $_SERVER['SERVER_PORT'] === 80 ? '' : ':'.$_SERVER['SERVER_PORT']))). + substr($_SERVER['SCRIPT_NAME'],0, strrpos($_SERVER['SCRIPT_NAME'], '/')); + } + + protected function get_user_id() { + @session_start(); + return session_id(); + } + + protected function get_user_path() { + if ($this->options['user_dirs']) { + return $this->get_user_id().'/'; + } + return ''; + } + + protected function get_upload_path($file_name = null, $version = null) { + $file_name = $file_name ? $file_name : ''; + if (empty($version)) { + $version_path = ''; + } else { + $version_dir = @$this->options['image_versions'][$version]['upload_dir']; + if ($version_dir) { + return $version_dir.$this->get_user_path().$file_name; + } + $version_path = $version.'/'; + } + return $this->options['upload_dir'].$this->get_user_path() + .$version_path.$file_name; + } + + protected function get_query_separator($url) { + return strpos($url, '?') === false ? '?' : '&'; + } + + protected function get_download_url($file_name, $version = null, $direct = false) { + if (!$direct && $this->options['download_via_php']) { + $url = $this->options['script_url'] + .$this->get_query_separator($this->options['script_url']) + .$this->get_singular_param_name() + .'='.rawurlencode($file_name); + if ($version) { + $url .= '&version='.rawurlencode($version); + } + return $url.'&download=1'; + } + if (empty($version)) { + $version_path = ''; + } else { + $version_url = @$this->options['image_versions'][$version]['upload_url']; + if ($version_url) { + return $version_url.$this->get_user_path().rawurlencode($file_name); + } + $version_path = rawurlencode($version).'/'; + } + return $this->options['upload_url'].$this->get_user_path() + .$version_path.rawurlencode($file_name); + } + + protected function set_additional_file_properties($file) { + $file->deleteUrl = $this->options['script_url'] + .$this->get_query_separator($this->options['script_url']) + .$this->get_singular_param_name() + .'='.rawurlencode($file->name); + $file->deleteType = $this->options['delete_type']; + if ($file->deleteType !== 'DELETE') { + $file->deleteUrl .= '&_method=DELETE'; + } + if ($this->options['access_control_allow_credentials']) { + $file->deleteWithCredentials = true; + } + } + + // Fix for overflowing signed 32 bit integers, + // works for sizes up to 2^32-1 bytes (4 GiB - 1): + protected function fix_integer_overflow($size) { + if ($size < 0) { + $size += 2.0 * (PHP_INT_MAX + 1); + } + return $size; + } + + protected function get_file_size($file_path, $clear_stat_cache = false) { + if ($clear_stat_cache) { + if (version_compare(PHP_VERSION, '5.3.0') >= 0) { + clearstatcache(true, $file_path); + } else { + clearstatcache(); + } + } + return $this->fix_integer_overflow(filesize($file_path)); + } + + protected function is_valid_file_object($file_name) { + $file_path = $this->get_upload_path($file_name); + if (is_file($file_path) && $file_name[0] !== '.') { + return true; + } + return false; + } + + protected function get_file_object($file_name) { + if ($this->is_valid_file_object($file_name)) { + $file = new stdClass(); + $file->name = $file_name; + $file->size = $this->get_file_size( + $this->get_upload_path($file_name) + ); + $file->url = $this->get_download_url($file->name); + foreach($this->options['image_versions'] as $version => $options) { + if (!empty($version)) { + if (is_file($this->get_upload_path($file_name, $version))) { + $file->{$version.'Url'} = $this->get_download_url( + $file->name, + $version + ); + } + } + } + $this->set_additional_file_properties($file); + return $file; + } + return null; + } + + protected function get_file_objects($iteration_method = 'get_file_object') { + $upload_dir = $this->get_upload_path(); + if (!is_dir($upload_dir)) { + return array(); + } + return array_values(array_filter(array_map( + array($this, $iteration_method), + scandir($upload_dir) + ))); + } + + protected function count_file_objects() { + return count($this->get_file_objects('is_valid_file_object')); + } + + protected function get_error_message($error) { + return array_key_exists($error, $this->error_messages) ? + $this->error_messages[$error] : $error; + } + + function get_config_bytes($val) { + $val = trim($val); + $last = strtolower($val[strlen($val)-1]); + switch($last) { + case 'g': + $val *= 1024; + case 'm': + $val *= 1024; + case 'k': + $val *= 1024; + } + return $this->fix_integer_overflow($val); + } + + protected function validate($uploaded_file, $file, $error, $index) { + if ($error) { + $file->error = $this->get_error_message($error); + return false; + } + $content_length = $this->fix_integer_overflow(intval( + $this->get_server_var('CONTENT_LENGTH') + )); + $post_max_size = $this->get_config_bytes(ini_get('post_max_size')); + if ($post_max_size && ($content_length > $post_max_size)) { + $file->error = $this->get_error_message('post_max_size'); + return false; + } + if (!preg_match($this->options['accept_file_types'], $file->name)) { + $file->error = $this->get_error_message('accept_file_types'); + return false; + } + if ($uploaded_file && is_uploaded_file($uploaded_file)) { + $file_size = $this->get_file_size($uploaded_file); + } else { + $file_size = $content_length; + } + if ($this->options['max_file_size'] && ( + $file_size > $this->options['max_file_size'] || + $file->size > $this->options['max_file_size']) + ) { + $file->error = $this->get_error_message('max_file_size'); + return false; + } + if ($this->options['min_file_size'] && + $file_size < $this->options['min_file_size']) { + $file->error = $this->get_error_message('min_file_size'); + return false; + } + if (is_int($this->options['max_number_of_files']) && ( + $this->count_file_objects() >= $this->options['max_number_of_files']) + ) { + $file->error = $this->get_error_message('max_number_of_files'); + return false; + } + $max_width = @$this->options['max_width']; + $max_height = @$this->options['max_height']; + $min_width = @$this->options['min_width']; + $min_height = @$this->options['min_height']; + if (($max_width || $max_height || $min_width || $min_height)) { + list($img_width, $img_height) = $this->get_image_size($uploaded_file); + } + if (!empty($img_width)) { + if ($max_width && $img_width > $max_width) { + $file->error = $this->get_error_message('max_width'); + return false; + } + if ($max_height && $img_height > $max_height) { + $file->error = $this->get_error_message('max_height'); + return false; + } + if ($min_width && $img_width < $min_width) { + $file->error = $this->get_error_message('min_width'); + return false; + } + if ($min_height && $img_height < $min_height) { + $file->error = $this->get_error_message('min_height'); + return false; + } + } + return true; + } + + protected function upcount_name_callback($matches) { + $index = isset($matches[1]) ? intval($matches[1]) + 1 : 1; + $ext = isset($matches[2]) ? $matches[2] : ''; + return ' ('.$index.')'.$ext; + } + + protected function upcount_name($name) { + return preg_replace_callback( + '/(?:(?: \(([\d]+)\))?(\.[^.]+))?$/', + array($this, 'upcount_name_callback'), + $name, + 1 + ); + } + + protected function get_unique_filename($file_path, $name, $size, $type, $error, + $index, $content_range) { + while(is_dir($this->get_upload_path($name))) { + $name = $this->upcount_name($name); + } + // Keep an existing filename if this is part of a chunked upload: + $uploaded_bytes = $this->fix_integer_overflow(intval($content_range[1])); + while(is_file($this->get_upload_path($name))) { + if ($uploaded_bytes === $this->get_file_size( + $this->get_upload_path($name))) { + break; + } + $name = $this->upcount_name($name); + } + return $name; + } + + protected function trim_file_name($file_path, $name, $size, $type, $error, + $index, $content_range) { + // Remove path information and dots around the filename, to prevent uploading + // into different directories or replacing hidden system files. + // Also remove control characters and spaces (\x00..\x20) around the filename: + $name = trim(basename(stripslashes($name)), ".\x00..\x20"); + // Use a timestamp for empty filenames: + if (!$name) { + $name = str_replace('.', '-', microtime(true)); + } + // Add missing file extension for known image types: + if (strpos($name, '.') === false && + preg_match('/^image\/(gif|jpe?g|png)/', $type, $matches)) { + $name .= '.'.$matches[1]; + } + if (function_exists('exif_imagetype')) { + switch(@exif_imagetype($file_path)){ + case IMAGETYPE_JPEG: + $extensions = array('jpg', 'jpeg'); + break; + case IMAGETYPE_PNG: + $extensions = array('png'); + break; + case IMAGETYPE_GIF: + $extensions = array('gif'); + break; + } + // Adjust incorrect image file extensions: + if (!empty($extensions)) { + $parts = explode('.', $name); + $extIndex = count($parts) - 1; + $ext = strtolower(@$parts[$extIndex]); + if (!in_array($ext, $extensions)) { + $parts[$extIndex] = $extensions[0]; + $name = implode('.', $parts); + } + } + } + return $name; + } + + protected function get_file_name($file_path, $name, $size, $type, $error, + $index, $content_range) { + return $this->get_unique_filename( + $file_path, + $this->trim_file_name($file_path, $name, $size, $type, $error, + $index, $content_range), + $size, + $type, + $error, + $index, + $content_range + ); + } + + protected function handle_form_data($file, $index) { + // Handle form data, e.g. $_REQUEST['description'][$index] + } + + protected function get_scaled_image_file_paths($file_name, $version) { + $file_path = $this->get_upload_path($file_name); + if (!empty($version)) { + $version_dir = $this->get_upload_path(null, $version); + if (!is_dir($version_dir)) { + mkdir($version_dir, $this->options['mkdir_mode'], true); + } + $new_file_path = $version_dir.'/'.$file_name; + } else { + $new_file_path = $file_path; + } + return array($file_path, $new_file_path); + } + + protected function gd_get_image_object($file_path, $func, $no_cache = false) { + if (empty($this->image_objects[$file_path]) || $no_cache) { + $this->gd_destroy_image_object($file_path); + $this->image_objects[$file_path] = $func($file_path); + } + return $this->image_objects[$file_path]; + } + + protected function gd_set_image_object($file_path, $image) { + $this->gd_destroy_image_object($file_path); + $this->image_objects[$file_path] = $image; + } + + protected function gd_destroy_image_object($file_path) { + $image = @$this->image_objects[$file_path]; + return $image && imagedestroy($image); + } + + protected function gd_imageflip($image, $mode) { + if (function_exists('imageflip')) { + return imageflip($image, $mode); + } + $new_width = $src_width = imagesx($image); + $new_height = $src_height = imagesy($image); + $new_img = imagecreatetruecolor($new_width, $new_height); + $src_x = 0; + $src_y = 0; + switch ($mode) { + case '1': // flip on the horizontal axis + $src_y = $new_height - 1; + $src_height = -$new_height; + break; + case '2': // flip on the vertical axis + $src_x = $new_width - 1; + $src_width = -$new_width; + break; + case '3': // flip on both axes + $src_y = $new_height - 1; + $src_height = -$new_height; + $src_x = $new_width - 1; + $src_width = -$new_width; + break; + default: + return $image; + } + imagecopyresampled( + $new_img, + $image, + 0, + 0, + $src_x, + $src_y, + $new_width, + $new_height, + $src_width, + $src_height + ); + return $new_img; + } + + protected function gd_orient_image($file_path, $src_img) { + if (!function_exists('exif_read_data')) { + return false; + } + $exif = @exif_read_data($file_path); + if ($exif === false) { + return false; + } + $orientation = intval(@$exif['Orientation']); + if ($orientation < 2 || $orientation > 8) { + return false; + } + switch ($orientation) { + case 2: + $new_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 + ); + break; + case 3: + $new_img = imagerotate($src_img, 180, 0); + break; + case 4: + $new_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 + ); + break; + case 5: + $tmp_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_HORIZONTAL') ? IMG_FLIP_HORIZONTAL : 1 + ); + $new_img = imagerotate($tmp_img, 270, 0); + imagedestroy($tmp_img); + break; + case 6: + $new_img = imagerotate($src_img, 270, 0); + break; + case 7: + $tmp_img = $this->gd_imageflip( + $src_img, + defined('IMG_FLIP_VERTICAL') ? IMG_FLIP_VERTICAL : 2 + ); + $new_img = imagerotate($tmp_img, 270, 0); + imagedestroy($tmp_img); + break; + case 8: + $new_img = imagerotate($src_img, 90, 0); + break; + default: + return false; + } + $this->gd_set_image_object($file_path, $new_img); + return true; + } + + protected function gd_create_scaled_image($file_name, $version, $options) { + if (!function_exists('imagecreatetruecolor')) { + error_log('Function not found: imagecreatetruecolor'); + return false; + } + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $type = strtolower(substr(strrchr($file_name, '.'), 1)); + switch ($type) { + case 'jpg': + case 'jpeg': + $src_func = 'imagecreatefromjpeg'; + $write_func = 'imagejpeg'; + $image_quality = isset($options['jpeg_quality']) ? + $options['jpeg_quality'] : 75; + break; + case 'gif': + $src_func = 'imagecreatefromgif'; + $write_func = 'imagegif'; + $image_quality = null; + break; + case 'png': + $src_func = 'imagecreatefrompng'; + $write_func = 'imagepng'; + $image_quality = isset($options['png_quality']) ? + $options['png_quality'] : 9; + break; + default: + return false; + } + $src_img = $this->gd_get_image_object( + $file_path, + $src_func, + !empty($options['no_cache']) + ); + $image_oriented = false; + if (!empty($options['auto_orient']) && $this->gd_orient_image( + $file_path, + $src_img + )) { + $image_oriented = true; + $src_img = $this->gd_get_image_object( + $file_path, + $src_func + ); + } + $max_width = $img_width = imagesx($src_img); + $max_height = $img_height = imagesy($src_img); + if (!empty($options['max_width'])) { + $max_width = $options['max_width']; + } + if (!empty($options['max_height'])) { + $max_height = $options['max_height']; + } + $scale = min( + $max_width / $img_width, + $max_height / $img_height + ); + if ($scale >= 1) { + if ($image_oriented) { + return $write_func($src_img, $new_file_path, $image_quality); + } + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + if (empty($options['crop'])) { + $new_width = $img_width * $scale; + $new_height = $img_height * $scale; + $dst_x = 0; + $dst_y = 0; + $new_img = imagecreatetruecolor($new_width, $new_height); + } else { + if (($img_width / $img_height) >= ($max_width / $max_height)) { + $new_width = $img_width / ($img_height / $max_height); + $new_height = $max_height; + } else { + $new_width = $max_width; + $new_height = $img_height / ($img_width / $max_width); + } + $dst_x = 0 - ($new_width - $max_width) / 2; + $dst_y = 0 - ($new_height - $max_height) / 2; + $new_img = imagecreatetruecolor($max_width, $max_height); + } + // Handle transparency in GIF and PNG images: + switch ($type) { + case 'gif': + case 'png': + imagecolortransparent($new_img, imagecolorallocate($new_img, 0, 0, 0)); + case 'png': + imagealphablending($new_img, false); + imagesavealpha($new_img, true); + break; + } + $success = imagecopyresampled( + $new_img, + $src_img, + $dst_x, + $dst_y, + 0, + 0, + $new_width, + $new_height, + $img_width, + $img_height + ) && $write_func($new_img, $new_file_path, $image_quality); + $this->gd_set_image_object($file_path, $new_img); + return $success; + } + + protected function imagick_get_image_object($file_path, $no_cache = false) { + if (empty($this->image_objects[$file_path]) || $no_cache) { + $this->imagick_destroy_image_object($file_path); + $image = new Imagick(); + if (!empty($this->options['imagick_resource_limits'])) { + foreach ($this->options['imagick_resource_limits'] as $type => $limit) { + $image->setResourceLimit($type, $limit); + } + } + $image->readImage($file_path); + $this->image_objects[$file_path] = $image; + } + return $this->image_objects[$file_path]; + } + + protected function imagick_set_image_object($file_path, $image) { + $this->imagick_destroy_image_object($file_path); + $this->image_objects[$file_path] = $image; + } + + protected function imagick_destroy_image_object($file_path) { + $image = @$this->image_objects[$file_path]; + return $image && $image->destroy(); + } + + protected function imagick_orient_image($image) { + $orientation = $image->getImageOrientation(); + $background = new ImagickPixel('none'); + switch ($orientation) { + case imagick::ORIENTATION_TOPRIGHT: // 2 + $image->flopImage(); // horizontal flop around y-axis + break; + case imagick::ORIENTATION_BOTTOMRIGHT: // 3 + $image->rotateImage($background, 180); + break; + case imagick::ORIENTATION_BOTTOMLEFT: // 4 + $image->flipImage(); // vertical flip around x-axis + break; + case imagick::ORIENTATION_LEFTTOP: // 5 + $image->flopImage(); // horizontal flop around y-axis + $image->rotateImage($background, 270); + break; + case imagick::ORIENTATION_RIGHTTOP: // 6 + $image->rotateImage($background, 90); + break; + case imagick::ORIENTATION_RIGHTBOTTOM: // 7 + $image->flipImage(); // vertical flip around x-axis + $image->rotateImage($background, 270); + break; + case imagick::ORIENTATION_LEFTBOTTOM: // 8 + $image->rotateImage($background, 270); + break; + default: + return false; + } + $image->setImageOrientation(imagick::ORIENTATION_TOPLEFT); // 1 + return true; + } + + protected function imagick_create_scaled_image($file_name, $version, $options) { + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $image = $this->imagick_get_image_object( + $file_path, + !empty($options['no_cache']) + ); + if ($image->getImageFormat() === 'GIF') { + // Handle animated GIFs: + $images = $image->coalesceImages(); + foreach ($images as $frame) { + $image = $frame; + $this->imagick_set_image_object($file_name, $image); + break; + } + } + $image_oriented = false; + if (!empty($options['auto_orient'])) { + $image_oriented = $this->imagick_orient_image($image); + } + $new_width = $max_width = $img_width = $image->getImageWidth(); + $new_height = $max_height = $img_height = $image->getImageHeight(); + if (!empty($options['max_width'])) { + $new_width = $max_width = $options['max_width']; + } + if (!empty($options['max_height'])) { + $new_height = $max_height = $options['max_height']; + } + if (!($image_oriented || $max_width < $img_width || $max_height < $img_height)) { + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + $crop = !empty($options['crop']); + if ($crop) { + $x = 0; + $y = 0; + if (($img_width / $img_height) >= ($max_width / $max_height)) { + $new_width = 0; // Enables proportional scaling based on max_height + $x = ($img_width / ($img_height / $max_height) - $max_width) / 2; + } else { + $new_height = 0; // Enables proportional scaling based on max_width + $y = ($img_height / ($img_width / $max_width) - $max_height) / 2; + } + } + $success = $image->resizeImage( + $new_width, + $new_height, + isset($options['filter']) ? $options['filter'] : imagick::FILTER_LANCZOS, + isset($options['blur']) ? $options['blur'] : 1, + $new_width && $new_height // fit image into constraints if not to be cropped + ); + if ($success && $crop) { + $success = $image->cropImage( + $max_width, + $max_height, + $x, + $y + ); + if ($success) { + $success = $image->setImagePage($max_width, $max_height, 0, 0); + } + } + $type = strtolower(substr(strrchr($file_name, '.'), 1)); + switch ($type) { + case 'jpg': + case 'jpeg': + if (!empty($options['jpeg_quality'])) { + $image->setImageCompression(Imagick::COMPRESSION_JPEG); + $image->setImageCompressionQuality($options['jpeg_quality']); + } + break; + } + if (!empty($options['strip'])) { + $image->stripImage(); + } + return $success && $image->writeImage($new_file_path); + } + + protected function imagemagick_create_scaled_image($file_name, $version, $options) { + list($file_path, $new_file_path) = + $this->get_scaled_image_file_paths($file_name, $version); + $resize = @$options['max_width'] + .(empty($options['max_height']) ? '' : 'x'.$options['max_height']); + if (!$resize && empty($options['auto_orient'])) { + if ($file_path !== $new_file_path) { + return copy($file_path, $new_file_path); + } + return true; + } + $cmd = $this->options['convert_bin']; + if (!empty($this->options['convert_params'])) { + $cmd .= ' '.$this->options['convert_params']; + } + $cmd .= ' '.escapeshellarg($file_path); + if (!empty($options['auto_orient'])) { + $cmd .= ' -auto-orient'; + } + if ($resize) { + // Handle animated GIFs: + $cmd .= ' -coalesce'; + if (empty($options['crop'])) { + $cmd .= ' -resize '.escapeshellarg($resize.'>'); + } else { + $cmd .= ' -resize '.escapeshellarg($resize.'^'); + $cmd .= ' -gravity center'; + $cmd .= ' -crop '.escapeshellarg($resize.'+0+0'); + } + // Make sure the page dimensions are correct (fixes offsets of animated GIFs): + $cmd .= ' +repage'; + } + if (!empty($options['convert_params'])) { + $cmd .= ' '.$options['convert_params']; + } + $cmd .= ' '.escapeshellarg($new_file_path); + exec($cmd, $output, $error); + if ($error) { + error_log(implode('\n', $output)); + return false; + } + return true; + } + + protected function get_image_size($file_path) { + if ($this->options['image_library']) { + if (extension_loaded('imagick')) { + $image = new Imagick(); + try { + if (@$image->pingImage($file_path)) { + $dimensions = array($image->getImageWidth(), $image->getImageHeight()); + $image->destroy(); + return $dimensions; + } + return false; + } catch (Exception $e) { + error_log($e->getMessage()); + } + } + if ($this->options['image_library'] === 2) { + $cmd = $this->options['identify_bin']; + $cmd .= ' -ping '.escapeshellarg($file_path); + exec($cmd, $output, $error); + if (!$error && !empty($output)) { + // image.jpg JPEG 1920x1080 1920x1080+0+0 8-bit sRGB 465KB 0.000u 0:00.000 + $infos = preg_split('/\s+/', $output[0]); + $dimensions = preg_split('/x/', $infos[2]); + return $dimensions; + } + return false; + } + } + if (!function_exists('getimagesize')) { + error_log('Function not found: getimagesize'); + return false; + } + return @getimagesize($file_path); + } + + protected function create_scaled_image($file_name, $version, $options) { + if ($this->options['image_library'] === 2) { + return $this->imagemagick_create_scaled_image($file_name, $version, $options); + } + if ($this->options['image_library'] && extension_loaded('imagick')) { + return $this->imagick_create_scaled_image($file_name, $version, $options); + } + return $this->gd_create_scaled_image($file_name, $version, $options); + } + + protected function destroy_image_object($file_path) { + if ($this->options['image_library'] && extension_loaded('imagick')) { + return $this->imagick_destroy_image_object($file_path); + } + } + + protected function is_valid_image_file($file_path) { + if (!preg_match($this->options['image_file_types'], $file_path)) { + return false; + } + if (function_exists('exif_imagetype')) { + return @exif_imagetype($file_path); + } + $image_info = $this->get_image_size($file_path); + return $image_info && $image_info[0] && $image_info[1]; + } + + protected function handle_image_file($file_path, $file) { + $failed_versions = array(); + foreach($this->options['image_versions'] as $version => $options) { + if ($this->create_scaled_image($file->name, $version, $options)) { + if (!empty($version)) { + $file->{$version.'Url'} = $this->get_download_url( + $file->name, + $version + ); + } else { + $file->size = $this->get_file_size($file_path, true); + } + } else { + $failed_versions[] = $version ? $version : 'original'; + } + } + if (count($failed_versions)) { + $file->error = $this->get_error_message('image_resize') + .' ('.implode($failed_versions,', ').')'; + } + // Free memory: + $this->destroy_image_object($file_path); + } + + protected function handle_file_upload($uploaded_file, $name, $size, $type, $error, + $index = null, $content_range = null) { + $file = new stdClass(); + $file->name = $this->get_file_name($uploaded_file, $name, $size, $type, $error, + $index, $content_range); + $file->size = $this->fix_integer_overflow(intval($size)); + $file->type = $type; + if ($this->validate($uploaded_file, $file, $error, $index)) { + $this->handle_form_data($file, $index); + $upload_dir = $this->get_upload_path(); + if (!is_dir($upload_dir)) { + mkdir($upload_dir, $this->options['mkdir_mode'], true); + } + $file_path = $this->get_upload_path($file->name); + $append_file = $content_range && is_file($file_path) && + $file->size > $this->get_file_size($file_path); + if ($uploaded_file && is_uploaded_file($uploaded_file)) { + // multipart/formdata uploads (POST method uploads) + if ($append_file) { + file_put_contents( + $file_path, + fopen($uploaded_file, 'r'), + FILE_APPEND + ); + } else { + move_uploaded_file($uploaded_file, $file_path); + } + } else { + // Non-multipart uploads (PUT method support) + file_put_contents( + $file_path, + fopen('php://input', 'r'), + $append_file ? FILE_APPEND : 0 + ); + } + $file_size = $this->get_file_size($file_path, $append_file); + if ($file_size === $file->size) { + $file->url = $this->get_download_url($file->name); + if ($this->is_valid_image_file($file_path)) { + $this->handle_image_file($file_path, $file); + } + } else { + $file->size = $file_size; + if (!$content_range && $this->options['discard_aborted_uploads']) { + unlink($file_path); + $file->error = $this->get_error_message('abort'); + } + } + $this->set_additional_file_properties($file); + } + return $file; + } + + protected function readfile($file_path) { + $file_size = $this->get_file_size($file_path); + $chunk_size = $this->options['readfile_chunk_size']; + if ($chunk_size && $file_size > $chunk_size) { + $handle = fopen($file_path, 'rb'); + while (!feof($handle)) { + echo fread($handle, $chunk_size); + ob_flush(); + flush(); + } + fclose($handle); + return $file_size; + } + return readfile($file_path); + } + + protected function body($str) { + echo $str; + } + + protected function header($str) { + header($str); + } + + protected function get_server_var($id) { + return isset($_SERVER[$id]) ? $_SERVER[$id] : ''; + } + + protected function generate_response($content, $print_response = true) { + if ($print_response) { + $json = json_encode($content); + $redirect = isset($_REQUEST['redirect']) ? + stripslashes($_REQUEST['redirect']) : null; + if ($redirect) { + $this->header('Location: '.sprintf($redirect, rawurlencode($json))); + return; + } + $this->head(); + if ($this->get_server_var('HTTP_CONTENT_RANGE')) { + $files = isset($content[$this->options['param_name']]) ? + $content[$this->options['param_name']] : null; + if ($files && is_array($files) && is_object($files[0]) && $files[0]->size) { + $this->header('Range: 0-'.( + $this->fix_integer_overflow(intval($files[0]->size)) - 1 + )); + } + } + $this->body($json); + } + return $content; + } + + protected function get_version_param() { + return isset($_GET['version']) ? basename(stripslashes($_GET['version'])) : null; + } + + protected function get_singular_param_name() { + return substr($this->options['param_name'], 0, -1); + } + + protected function get_file_name_param() { + $name = $this->get_singular_param_name(); + return isset($_GET[$name]) ? basename(stripslashes($_GET[$name])) : null; + } + + protected function get_file_names_params() { + $params = isset($_GET[$this->options['param_name']]) ? + $_GET[$this->options['param_name']] : array(); + foreach ($params as $key => $value) { + $params[$key] = basename(stripslashes($value)); + } + return $params; + } + + protected function get_file_type($file_path) { + switch (strtolower(pathinfo($file_path, PATHINFO_EXTENSION))) { + case 'jpeg': + case 'jpg': + return 'image/jpeg'; + case 'png': + return 'image/png'; + case 'gif': + return 'image/gif'; + default: + return ''; + } + } + + protected function download() { + switch ($this->options['download_via_php']) { + case 1: + $redirect_header = null; + break; + case 2: + $redirect_header = 'X-Sendfile'; + break; + case 3: + $redirect_header = 'X-Accel-Redirect'; + break; + default: + return $this->header('HTTP/1.1 403 Forbidden'); + } + $file_name = $this->get_file_name_param(); + if (!$this->is_valid_file_object($file_name)) { + return $this->header('HTTP/1.1 404 Not Found'); + } + if ($redirect_header) { + return $this->header( + $redirect_header.': '.$this->get_download_url( + $file_name, + $this->get_version_param(), + true + ) + ); + } + $file_path = $this->get_upload_path($file_name, $this->get_version_param()); + // Prevent browsers from MIME-sniffing the content-type: + $this->header('X-Content-Type-Options: nosniff'); + if (!preg_match($this->options['inline_file_types'], $file_name)) { + $this->header('Content-Type: application/octet-stream'); + $this->header('Content-Disposition: attachment; filename="'.$file_name.'"'); + } else { + $this->header('Content-Type: '.$this->get_file_type($file_path)); + $this->header('Content-Disposition: inline; filename="'.$file_name.'"'); + } + $this->header('Content-Length: '.$this->get_file_size($file_path)); + $this->header('Last-Modified: '.gmdate('D, d M Y H:i:s T', filemtime($file_path))); + $this->readfile($file_path); + } + + protected function send_content_type_header() { + $this->header('Vary: Accept'); + if (strpos($this->get_server_var('HTTP_ACCEPT'), 'application/json') !== false) { + $this->header('Content-type: application/json'); + } else { + $this->header('Content-type: text/plain'); + } + } + + protected function send_access_control_headers() { + $this->header('Access-Control-Allow-Origin: '.$this->options['access_control_allow_origin']); + $this->header('Access-Control-Allow-Credentials: ' + .($this->options['access_control_allow_credentials'] ? 'true' : 'false')); + $this->header('Access-Control-Allow-Methods: ' + .implode(', ', $this->options['access_control_allow_methods'])); + $this->header('Access-Control-Allow-Headers: ' + .implode(', ', $this->options['access_control_allow_headers'])); + } + + public function head() { + $this->header('Pragma: no-cache'); + $this->header('Cache-Control: no-store, no-cache, must-revalidate'); + $this->header('Content-Disposition: inline; filename="files.json"'); + // Prevent Internet Explorer from MIME-sniffing the content-type: + $this->header('X-Content-Type-Options: nosniff'); + if ($this->options['access_control_allow_origin']) { + $this->send_access_control_headers(); + } + $this->send_content_type_header(); + } + + public function get($print_response = true) { + if ($print_response && isset($_GET['download'])) { + return $this->download(); + } + $file_name = $this->get_file_name_param(); + if ($file_name) { + $response = array( + $this->get_singular_param_name() => $this->get_file_object($file_name) + ); + } else { + $response = array( + $this->options['param_name'] => $this->get_file_objects() + ); + } + return $this->generate_response($response, $print_response); + } + + public function post($print_response = true) { + if (isset($_REQUEST['_method']) && $_REQUEST['_method'] === 'DELETE') { + return $this->delete($print_response); + } + $upload = isset($_FILES[$this->options['param_name']]) ? + $_FILES[$this->options['param_name']] : null; + // Parse the Content-Disposition header, if available: + $file_name = $this->get_server_var('HTTP_CONTENT_DISPOSITION') ? + rawurldecode(preg_replace( + '/(^[^"]+")|("$)/', + '', + $this->get_server_var('HTTP_CONTENT_DISPOSITION') + )) : null; + // Parse the Content-Range header, which has the following form: + // Content-Range: bytes 0-524287/2000000 + $content_range = $this->get_server_var('HTTP_CONTENT_RANGE') ? + preg_split('/[^0-9]+/', $this->get_server_var('HTTP_CONTENT_RANGE')) : null; + $size = $content_range ? $content_range[3] : null; + $files = array(); + if ($upload && is_array($upload['tmp_name'])) { + // param_name is an array identifier like "files[]", + // $_FILES is a multi-dimensional array: + foreach ($upload['tmp_name'] as $index => $value) { + $files[] = $this->handle_file_upload( + $upload['tmp_name'][$index], + $file_name ? $file_name : $upload['name'][$index], + $size ? $size : $upload['size'][$index], + $upload['type'][$index], + $upload['error'][$index], + $index, + $content_range + ); + } + } else { + // param_name is a single object identifier like "file", + // $_FILES is a one-dimensional array: + $files[] = $this->handle_file_upload( + isset($upload['tmp_name']) ? $upload['tmp_name'] : null, + $file_name ? $file_name : (isset($upload['name']) ? + $upload['name'] : null), + $size ? $size : (isset($upload['size']) ? + $upload['size'] : $this->get_server_var('CONTENT_LENGTH')), + isset($upload['type']) ? + $upload['type'] : $this->get_server_var('CONTENT_TYPE'), + isset($upload['error']) ? $upload['error'] : null, + null, + $content_range + ); + } + return $this->generate_response( + array($this->options['param_name'] => $files), + $print_response + ); + } + + public function delete($print_response = true) { + $file_names = $this->get_file_names_params(); + if (empty($file_names)) { + $file_names = array($this->get_file_name_param()); + } + $response = array(); + foreach($file_names as $file_name) { + $file_path = $this->get_upload_path($file_name); + $success = is_file($file_path) && $file_name[0] !== '.' && unlink($file_path); + if ($success) { + foreach($this->options['image_versions'] as $version => $options) { + if (!empty($version)) { + $file = $this->get_upload_path($file_name, $version); + if (is_file($file)) { + unlink($file); + } + } + } + } + $response[$file_name] = $success; + } + return $this->generate_response($response, $print_response); + } + +} diff --git a/sources/library/jqupload/server/php/files/.gitignore b/sources/library/jqupload/server/php/files/.gitignore new file mode 100644 index 00000000..e24a60fa --- /dev/null +++ b/sources/library/jqupload/server/php/files/.gitignore @@ -0,0 +1,3 @@ +* +!.gitignore +!.htaccess diff --git a/sources/library/jqupload/server/php/files/.htaccess b/sources/library/jqupload/server/php/files/.htaccess new file mode 100644 index 00000000..56689f0b --- /dev/null +++ b/sources/library/jqupload/server/php/files/.htaccess @@ -0,0 +1,18 @@ +# The following directives force the content-type application/octet-stream +# and force browsers to display a download dialog for non-image files. +# This prevents the execution of script files in the context of the website: +ForceType application/octet-stream +Header set Content-Disposition attachment + + ForceType none + Header unset Content-Disposition + + +# The following directive prevents browsers from MIME-sniffing the content-type. +# This is an important complement to the ForceType directive above: +Header set X-Content-Type-Options nosniff + +# Uncomment the following lines to prevent unauthorized download of files: +#AuthName "Authorization required" +#AuthType Basic +#require valid-user diff --git a/sources/library/jqupload/server/php/index.php b/sources/library/jqupload/server/php/index.php new file mode 100644 index 00000000..be29bf47 --- /dev/null +++ b/sources/library/jqupload/server/php/index.php @@ -0,0 +1,19 @@ + + + + + + + +jQuery File Upload Plugin Test + + + + +

jQuery File Upload Plugin Test

+

+
+

+
    +
    + +
    + +
    +
    + + + + Add files... + + + + + + + + +
    + +
    + +
    +
    +
    + +
     
    +
    +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sources/library/jqupload/test/test.js b/sources/library/jqupload/test/test.js new file mode 100644 index 00000000..72d08d99 --- /dev/null +++ b/sources/library/jqupload/test/test.js @@ -0,0 +1,1288 @@ +/* + * jQuery File Upload Plugin Test 9.4.0 + * https://github.com/blueimp/jQuery-File-Upload + * + * Copyright 2010, Sebastian Tschan + * https://blueimp.net + * + * Licensed under the MIT license: + * http://www.opensource.org/licenses/MIT + */ + +/* global $, QUnit, window, document, expect, module, test, asyncTest, start, ok, strictEqual, notStrictEqual */ + +$(function () { + // jshint nomen:false + 'use strict'; + + QUnit.done = function () { + // Delete all uploaded files: + var url = $('#fileupload').prop('action'); + $.getJSON(url, function (result) { + $.each(result.files, function (index, file) { + $.ajax({ + url: url + '?file=' + encodeURIComponent(file.name), + type: 'DELETE' + }); + }); + }); + }; + + var lifecycle = { + setup: function () { + // Set the .fileupload method to the basic widget method: + $.widget('blueimp.fileupload', window.testBasicWidget, {}); + }, + teardown: function () { + // Remove all remaining event listeners: + $(document).unbind(); + } + }, + lifecycleUI = { + setup: function () { + // Set the .fileupload method to the UI widget method: + $.widget('blueimp.fileupload', window.testUIWidget, {}); + }, + teardown: function () { + // Remove all remaining event listeners: + $(document).unbind(); + } + }; + + module('Initialization', lifecycle); + + test('Widget initialization', function () { + var fu = $('#fileupload').fileupload(); + ok(fu.data('blueimp-fileupload') || fu.data('fileupload')); + }); + + test('Data attribute options', function () { + $('#fileupload').attr('data-url', 'http://example.org'); + $('#fileupload').fileupload(); + strictEqual( + $('#fileupload').fileupload('option', 'url'), + 'http://example.org' + ); + }); + + test('File input initialization', function () { + var fu = $('#fileupload').fileupload(); + ok( + fu.fileupload('option', 'fileInput').length, + 'File input field inside of the widget' + ); + ok( + fu.fileupload('option', 'fileInput').length, + 'Widget element as file input field' + ); + }); + + test('Drop zone initialization', function () { + ok($('#fileupload').fileupload() + .fileupload('option', 'dropZone').length); + }); + + test('Paste zone initialization', function () { + ok($('#fileupload').fileupload() + .fileupload('option', 'pasteZone').length); + }); + + test('Event listeners initialization', function () { + expect( + $.support.xhrFormDataFileUpload ? 4 : 1 + ); + var eo = { + originalEvent: { + dataTransfer: {files: [{}], types: ['Files']}, + clipboardData: {items: [{}]} + } + }, + fu = $('#fileupload').fileupload({ + dragover: function () { + ok(true, 'Triggers dragover callback'); + return false; + }, + drop: function () { + ok(true, 'Triggers drop callback'); + return false; + }, + paste: function () { + ok(true, 'Triggers paste callback'); + return false; + }, + change: function () { + ok(true, 'Triggers change callback'); + return false; + } + }), + fileInput = fu.fileupload('option', 'fileInput'), + dropZone = fu.fileupload('option', 'dropZone'), + pasteZone = fu.fileupload('option', 'pasteZone'); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + }); + + module('API', lifecycle); + + test('destroy', function () { + expect(4); + var eo = { + originalEvent: { + dataTransfer: {files: [{}], types: ['Files']}, + clipboardData: {items: [{}]} + } + }, + options = { + dragover: function () { + ok(true, 'Triggers dragover callback'); + return false; + }, + drop: function () { + ok(true, 'Triggers drop callback'); + return false; + }, + paste: function () { + ok(true, 'Triggers paste callback'); + return false; + }, + change: function () { + ok(true, 'Triggers change callback'); + return false; + } + }, + fu = $('#fileupload').fileupload(options), + fileInput = fu.fileupload('option', 'fileInput'), + dropZone = fu.fileupload('option', 'dropZone'), + pasteZone = fu.fileupload('option', 'pasteZone'); + dropZone.bind('dragover', options.dragover); + dropZone.bind('drop', options.drop); + pasteZone.bind('paste', options.paste); + fileInput.bind('change', options.change); + fu.fileupload('destroy'); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + }); + + test('disable/enable', function () { + expect( + $.support.xhrFormDataFileUpload ? 4 : 1 + ); + var eo = { + originalEvent: { + dataTransfer: {files: [{}], types: ['Files']}, + clipboardData: {items: [{}]} + } + }, + fu = $('#fileupload').fileupload({ + dragover: function () { + ok(true, 'Triggers dragover callback'); + return false; + }, + drop: function () { + ok(true, 'Triggers drop callback'); + return false; + }, + paste: function () { + ok(true, 'Triggers paste callback'); + return false; + }, + change: function () { + ok(true, 'Triggers change callback'); + return false; + } + }), + fileInput = fu.fileupload('option', 'fileInput'), + dropZone = fu.fileupload('option', 'dropZone'), + pasteZone = fu.fileupload('option', 'pasteZone'); + fu.fileupload('disable'); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + fu.fileupload('enable'); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + }); + + test('option', function () { + expect( + $.support.xhrFormDataFileUpload ? 10 : 7 + ); + var eo = { + originalEvent: { + dataTransfer: {files: [{}], types: ['Files']}, + clipboardData: {items: [{}]} + } + }, + fu = $('#fileupload').fileupload({ + dragover: function () { + ok(true, 'Triggers dragover callback'); + return false; + }, + drop: function () { + ok(true, 'Triggers drop callback'); + return false; + }, + paste: function () { + ok(true, 'Triggers paste callback'); + return false; + }, + change: function () { + ok(true, 'Triggers change callback'); + return false; + } + }), + fileInput = fu.fileupload('option', 'fileInput'), + dropZone = fu.fileupload('option', 'dropZone'), + pasteZone = fu.fileupload('option', 'pasteZone'); + fu.fileupload('option', 'fileInput', null); + fu.fileupload('option', 'dropZone', null); + fu.fileupload('option', 'pasteZone', null); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + fu.fileupload('option', 'dropZone', 'body'); + strictEqual( + fu.fileupload('option', 'dropZone')[0], + document.body, + 'Allow a query string as parameter for the dropZone option' + ); + fu.fileupload('option', 'dropZone', document); + strictEqual( + fu.fileupload('option', 'dropZone')[0], + document, + 'Allow a document element as parameter for the dropZone option' + ); + fu.fileupload('option', 'pasteZone', 'body'); + strictEqual( + fu.fileupload('option', 'pasteZone')[0], + document.body, + 'Allow a query string as parameter for the pasteZone option' + ); + fu.fileupload('option', 'pasteZone', document); + strictEqual( + fu.fileupload('option', 'pasteZone')[0], + document, + 'Allow a document element as parameter for the pasteZone option' + ); + fu.fileupload('option', 'fileInput', ':file'); + strictEqual( + fu.fileupload('option', 'fileInput')[0], + $(':file')[0], + 'Allow a query string as parameter for the fileInput option' + ); + fu.fileupload('option', 'fileInput', $(':file')[0]); + strictEqual( + fu.fileupload('option', 'fileInput')[0], + $(':file')[0], + 'Allow a document element as parameter for the fileInput option' + ); + fu.fileupload('option', 'fileInput', fileInput); + fu.fileupload('option', 'dropZone', dropZone); + fu.fileupload('option', 'pasteZone', pasteZone); + fileInput.trigger($.Event('change', eo)); + dropZone.trigger($.Event('dragover', eo)); + dropZone.trigger($.Event('drop', eo)); + pasteZone.trigger($.Event('paste', eo)); + }); + + asyncTest('add', function () { + expect(2); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + add: function (e, data) { + strictEqual( + data.files[0].name, + param.files[0].name, + 'Triggers add callback' + ); + } + }).fileupload('add', param).fileupload( + 'option', + 'add', + function (e, data) { + data.submit().complete(function () { + ok(true, 'data.submit() Returns a jqXHR object'); + start(); + }); + } + ).fileupload('add', param); + }); + + asyncTest('send', function () { + expect(3); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + send: function (e, data) { + strictEqual( + data.files[0].name, + 'test', + 'Triggers send callback' + ); + } + }).fileupload('send', param).fail(function () { + ok(true, 'Allows to abort the request'); + }).complete(function () { + ok(true, 'Returns a jqXHR object'); + start(); + }).abort(); + }); + + module('Callbacks', lifecycle); + + asyncTest('add', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + add: function () { + ok(true, 'Triggers add callback'); + start(); + } + }).fileupload('add', param); + }); + + asyncTest('submit', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + submit: function () { + ok(true, 'Triggers submit callback'); + start(); + return false; + } + }).fileupload('add', param); + }); + + asyncTest('send', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + send: function () { + ok(true, 'Triggers send callback'); + start(); + return false; + } + }).fileupload('send', param); + }); + + asyncTest('done', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + done: function () { + ok(true, 'Triggers done callback'); + start(); + } + }).fileupload('send', param); + }); + + asyncTest('fail', function () { + expect(1); + var param = {files: [{name: 'test'}]}, + fu = $('#fileupload').fileupload({ + url: '404', + fail: function () { + ok(true, 'Triggers fail callback'); + start(); + } + }); + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + fu.fileupload('send', param); + }); + + asyncTest('always', function () { + expect(2); + var param = {files: [{name: 'test'}]}, + counter = 0, + fu = $('#fileupload').fileupload({ + always: function () { + ok(true, 'Triggers always callback'); + if (counter === 1) { + start(); + } else { + counter += 1; + } + } + }); + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + fu.fileupload('add', param).fileupload( + 'option', + 'url', + '404' + ).fileupload('add', param); + }); + + asyncTest('progress', function () { + expect(1); + var param = {files: [{name: 'test'}]}, + counter = 0; + $('#fileupload').fileupload({ + forceIframeTransport: true, + progress: function () { + ok(true, 'Triggers progress callback'); + if (counter === 0) { + start(); + } else { + counter += 1; + } + } + }).fileupload('send', param); + }); + + asyncTest('progressall', function () { + expect(1); + var param = {files: [{name: 'test'}]}, + counter = 0; + $('#fileupload').fileupload({ + forceIframeTransport: true, + progressall: function () { + ok(true, 'Triggers progressall callback'); + if (counter === 0) { + start(); + } else { + counter += 1; + } + } + }).fileupload('send', param); + }); + + asyncTest('start', function () { + expect(1); + var param = {files: [{name: '1'}, {name: '2'}]}, + active = 0; + $('#fileupload').fileupload({ + send: function () { + active += 1; + }, + start: function () { + ok(!active, 'Triggers start callback before uploads'); + start(); + } + }).fileupload('send', param); + }); + + asyncTest('stop', function () { + expect(1); + var param = {files: [{name: '1'}, {name: '2'}]}, + active = 0; + $('#fileupload').fileupload({ + send: function () { + active += 1; + }, + always: function () { + active -= 1; + }, + stop: function () { + ok(!active, 'Triggers stop callback after uploads'); + start(); + } + }).fileupload('send', param); + }); + + test('change', function () { + var fu = $('#fileupload').fileupload(), + fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'), + fileInput = fu.fileupload('option', 'fileInput'); + expect(2); + fu.fileupload({ + change: function (e, data) { + ok(true, 'Triggers change callback'); + strictEqual( + data.files.length, + 0, + 'Returns empty files list' + ); + }, + add: $.noop + }); + fuo._onChange({ + data: {fileupload: fuo}, + target: fileInput[0] + }); + }); + + test('paste', function () { + var fu = $('#fileupload').fileupload(), + fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'); + expect(1); + fu.fileupload({ + paste: function () { + ok(true, 'Triggers paste callback'); + }, + add: $.noop + }); + fuo._onPaste({ + data: {fileupload: fuo}, + originalEvent: { + dataTransfer: {files: [{}]}, + clipboardData: {items: [{}]} + }, + preventDefault: $.noop + }); + }); + + test('drop', function () { + var fu = $('#fileupload').fileupload(), + fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'); + expect(1); + fu.fileupload({ + drop: function () { + ok(true, 'Triggers drop callback'); + }, + add: $.noop + }); + fuo._onDrop({ + data: {fileupload: fuo}, + originalEvent: { + dataTransfer: {files: [{}]}, + clipboardData: {items: [{}]} + }, + preventDefault: $.noop + }); + }); + + test('dragover', function () { + var fu = $('#fileupload').fileupload(), + fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'); + expect(1); + fu.fileupload({ + dragover: function () { + ok(true, 'Triggers dragover callback'); + }, + add: $.noop + }); + fuo._onDragOver({ + data: {fileupload: fuo}, + originalEvent: {dataTransfer: {types: ['Files']}}, + preventDefault: $.noop + }); + }); + + module('Options', lifecycle); + + test('paramName', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + paramName: null, + send: function (e, data) { + strictEqual( + data.paramName[0], + data.fileInput.prop('name'), + 'Takes paramName from file input field if not set' + ); + return false; + } + }).fileupload('send', param); + }); + + test('url', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + url: null, + send: function (e, data) { + strictEqual( + data.url, + $(data.fileInput.prop('form')).prop('action'), + 'Takes url from form action if not set' + ); + return false; + } + }).fileupload('send', param); + }); + + test('type', function () { + expect(2); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + type: null, + send: function (e, data) { + strictEqual( + data.type, + 'POST', + 'Request type is "POST" if not set to "PUT"' + ); + return false; + } + }).fileupload('send', param); + $('#fileupload').fileupload({ + type: 'PUT', + send: function (e, data) { + strictEqual( + data.type, + 'PUT', + 'Request type is "PUT" if set to "PUT"' + ); + return false; + } + }).fileupload('send', param); + }); + + test('replaceFileInput', function () { + var fu = $('#fileupload').fileupload(), + fuo = fu.data('blueimp-fileupload') || fu.data('fileupload'), + fileInput = fu.fileupload('option', 'fileInput'), + fileInputElement = fileInput[0]; + expect(2); + fu.fileupload({ + replaceFileInput: false, + change: function () { + strictEqual( + fu.fileupload('option', 'fileInput')[0], + fileInputElement, + 'Keeps file input with replaceFileInput: false' + ); + }, + add: $.noop + }); + fuo._onChange({ + data: {fileupload: fuo}, + target: fileInput[0] + }); + fu.fileupload({ + replaceFileInput: true, + change: function () { + notStrictEqual( + fu.fileupload('option', 'fileInput')[0], + fileInputElement, + 'Replaces file input with replaceFileInput: true' + ); + }, + add: $.noop + }); + fuo._onChange({ + data: {fileupload: fuo}, + target: fileInput[0] + }); + }); + + asyncTest('forceIframeTransport', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + forceIframeTransport: true, + done: function (e, data) { + strictEqual( + data.dataType.substr(0, 6), + 'iframe', + 'Iframe Transport is used' + ); + start(); + } + }).fileupload('send', param); + }); + + test('singleFileUploads', function () { + expect(3); + var fu = $('#fileupload').fileupload(), + param = {files: [{name: '1'}, {name: '2'}]}, + index = 1; + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + $('#fileupload').fileupload({ + singleFileUploads: true, + add: function () { + ok(true, 'Triggers callback number ' + index.toString()); + index += 1; + } + }).fileupload('add', param).fileupload( + 'option', + 'singleFileUploads', + false + ).fileupload('add', param); + }); + + test('limitMultiFileUploads', function () { + expect(3); + var fu = $('#fileupload').fileupload(), + param = {files: [ + {name: '1'}, + {name: '2'}, + {name: '3'}, + {name: '4'}, + {name: '5'} + ]}, + index = 1; + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + $('#fileupload').fileupload({ + singleFileUploads: false, + limitMultiFileUploads: 2, + add: function () { + ok(true, 'Triggers callback number ' + index.toString()); + index += 1; + } + }).fileupload('add', param); + }); + + test('limitMultiFileUploadSize', function () { + expect(7); + var fu = $('#fileupload').fileupload(), + param = {files: [ + {name: '1-1', size: 100000}, + {name: '1-2', size: 40000}, + {name: '2-1', size: 100000}, + {name: '3-1', size: 50000}, + {name: '3-2', size: 40000}, + {name: '4-1', size: 45000} // New request due to limitMultiFileUploads + ]}, + param2 = {files: [ + {name: '5-1'}, + {name: '5-2'}, + {name: '6-1'}, + {name: '6-2'}, + {name: '7-1'} + ]}, + index = 1; + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + $('#fileupload').fileupload({ + singleFileUploads: false, + limitMultiFileUploads: 2, + limitMultiFileUploadSize: 150000, + limitMultiFileUploadSizeOverhead: 5000, + add: function () { + ok(true, 'Triggers callback number ' + index.toString()); + index += 1; + } + }).fileupload('add', param).fileupload('add', param2); + }); + + asyncTest('sequentialUploads', function () { + expect(6); + var param = {files: [ + {name: '1'}, + {name: '2'}, + {name: '3'}, + {name: '4'}, + {name: '5'}, + {name: '6'} + ]}, + addIndex = 0, + sendIndex = 0, + loadIndex = 0, + fu = $('#fileupload').fileupload({ + sequentialUploads: true, + add: function (e, data) { + addIndex += 1; + if (addIndex === 4) { + data.submit().abort(); + } else { + data.submit(); + } + }, + send: function () { + sendIndex += 1; + }, + done: function () { + loadIndex += 1; + strictEqual(sendIndex, loadIndex, 'upload in order'); + }, + fail: function (e, data) { + strictEqual(data.errorThrown, 'abort', 'upload aborted'); + }, + stop: function () { + start(); + } + }); + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + fu.fileupload('add', param); + }); + + asyncTest('limitConcurrentUploads', function () { + expect(12); + var param = {files: [ + {name: '1'}, + {name: '2'}, + {name: '3'}, + {name: '4'}, + {name: '5'}, + {name: '6'}, + {name: '7'}, + {name: '8'}, + {name: '9'}, + {name: '10'}, + {name: '11'}, + {name: '12'} + ]}, + addIndex = 0, + sendIndex = 0, + loadIndex = 0, + fu = $('#fileupload').fileupload({ + limitConcurrentUploads: 3, + add: function (e, data) { + addIndex += 1; + if (addIndex === 4) { + data.submit().abort(); + } else { + data.submit(); + } + }, + send: function () { + sendIndex += 1; + }, + done: function () { + loadIndex += 1; + ok(sendIndex - loadIndex < 3); + }, + fail: function (e, data) { + strictEqual(data.errorThrown, 'abort', 'upload aborted'); + }, + stop: function () { + start(); + } + }); + (fu.data('blueimp-fileupload') || fu.data('fileupload')) + ._isXHRUpload = function () { + return true; + }; + fu.fileupload('add', param); + }); + + if ($.support.xhrFileUpload) { + asyncTest('multipart', function () { + expect(2); + var param = {files: [{ + name: 'test.png', + size: 123, + type: 'image/png' + }]}, + fu = $('#fileupload').fileupload({ + multipart: false, + always: function (e, data) { + strictEqual( + data.contentType, + param.files[0].type, + 'non-multipart upload sets file type as contentType' + ); + strictEqual( + data.headers['Content-Disposition'], + 'attachment; filename="' + param.files[0].name + '"', + 'non-multipart upload sets Content-Disposition header' + ); + start(); + } + }); + fu.fileupload('send', param); + }); + } + + module('UI Initialization', lifecycleUI); + + test('Widget initialization', function () { + var fu = $('#fileupload').fileupload(); + ok(fu.data('blueimp-fileupload') || fu.data('fileupload')); + ok( + $('#fileupload').fileupload('option', 'uploadTemplate').length, + 'Initialized upload template' + ); + ok( + $('#fileupload').fileupload('option', 'downloadTemplate').length, + 'Initialized download template' + ); + }); + + test('Buttonbar event listeners', function () { + var buttonbar = $('#fileupload .fileupload-buttonbar'), + files = [{name: 'test'}]; + expect(4); + $('#fileupload').fileupload({ + send: function () { + ok(true, 'Started file upload via global start button'); + }, + fail: function (e, data) { + ok(true, 'Canceled file upload via global cancel button'); + data.context.remove(); + }, + destroy: function () { + ok(true, 'Delete action called via global delete button'); + } + }); + $('#fileupload').fileupload('add', {files: files}); + buttonbar.find('.cancel').click(); + $('#fileupload').fileupload('add', {files: files}); + buttonbar.find('.start').click(); + buttonbar.find('.cancel').click(); + files[0].deleteUrl = 'http://example.org/banana.jpg'; + ($('#fileupload').data('blueimp-fileupload') || + $('#fileupload').data('fileupload')) + ._renderDownload(files) + .appendTo($('#fileupload .files')).show() + .find('.toggle').click(); + buttonbar.find('.delete').click(); + }); + + module('UI API', lifecycleUI); + + test('destroy', function () { + var buttonbar = $('#fileupload .fileupload-buttonbar'), + files = [{name: 'test'}]; + expect(1); + $('#fileupload').fileupload({ + send: function () { + ok(true, 'This test should not run'); + return false; + } + }) + .fileupload('add', {files: files}) + .fileupload('destroy'); + buttonbar.find('.start').click(function () { + ok(true, 'Clicked global start button'); + return false; + }).click(); + }); + + test('disable/enable', function () { + var buttonbar = $('#fileupload .fileupload-buttonbar'); + $('#fileupload').fileupload(); + $('#fileupload').fileupload('disable'); + strictEqual( + buttonbar.find('input[type=file], button').not(':disabled').length, + 0, + 'Disables the buttonbar buttons' + ); + $('#fileupload').fileupload('enable'); + strictEqual( + buttonbar.find('input[type=file], button').not(':disabled').length, + 4, + 'Enables the buttonbar buttons' + ); + }); + + module('UI Callbacks', lifecycleUI); + + test('destroy', function () { + expect(3); + $('#fileupload').fileupload({ + destroy: function (e, data) { + ok(true, 'Triggers destroy callback'); + strictEqual( + data.url, + 'test', + 'Passes over deletion url parameter' + ); + strictEqual( + data.type, + 'DELETE', + 'Passes over deletion request type parameter' + ); + } + }); + ($('#fileupload').data('blueimp-fileupload') || + $('#fileupload').data('fileupload')) + ._renderDownload([{ + name: 'test', + deleteUrl: 'test', + deleteType: 'DELETE' + }]) + .appendTo($('#fileupload .files')) + .show() + .find('.toggle').click(); + $('#fileupload .fileupload-buttonbar .delete').click(); + }); + + asyncTest('added', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + added: function (e, data) { + start(); + strictEqual( + data.files[0].name, + param.files[0].name, + 'Triggers added callback' + ); + }, + send: function () { + return false; + } + }).fileupload('add', param); + }); + + asyncTest('started', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + started: function () { + start(); + ok('Triggers started callback'); + return false; + }, + sent: function () { + return false; + } + }).fileupload('send', param); + }); + + asyncTest('sent', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + sent: function (e, data) { + start(); + strictEqual( + data.files[0].name, + param.files[0].name, + 'Triggers sent callback' + ); + return false; + } + }).fileupload('send', param); + }); + + asyncTest('completed', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + completed: function () { + start(); + ok('Triggers completed callback'); + return false; + } + }).fileupload('send', param); + }); + + asyncTest('failed', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + failed: function () { + start(); + ok('Triggers failed callback'); + return false; + } + }).fileupload('send', param).abort(); + }); + + asyncTest('stopped', function () { + expect(1); + var param = {files: [{name: 'test'}]}; + $('#fileupload').fileupload({ + stopped: function () { + start(); + ok('Triggers stopped callback'); + return false; + } + }).fileupload('send', param); + }); + + asyncTest('destroyed', function () { + expect(1); + $('#fileupload').fileupload({ + dataType: 'html', + destroyed: function () { + start(); + ok(true, 'Triggers destroyed callback'); + } + }); + ($('#fileupload').data('blueimp-fileupload') || + $('#fileupload').data('fileupload')) + ._renderDownload([{ + name: 'test', + deleteUrl: '.', + deleteType: 'GET' + }]) + .appendTo($('#fileupload .files')) + .show() + .find('.toggle').click(); + $('#fileupload .fileupload-buttonbar .delete').click(); + }); + + module('UI Options', lifecycleUI); + + test('autoUpload', function () { + expect(1); + $('#fileupload') + .fileupload({ + autoUpload: true, + send: function () { + ok(true, 'Started file upload automatically'); + return false; + } + }) + .fileupload('add', {files: [{name: 'test'}]}) + .fileupload('option', 'autoUpload', false) + .fileupload('add', {files: [{name: 'test'}]}); + }); + + test('maxNumberOfFiles', function () { + expect(3); + var addIndex = 0, + sendIndex = 0; + $('#fileupload') + .fileupload({ + autoUpload: true, + maxNumberOfFiles: 3, + singleFileUploads: false, + send: function () { + strictEqual( + sendIndex += 1, + addIndex + ); + }, + progress: $.noop, + progressall: $.noop, + done: $.noop, + stop: $.noop + }) + .fileupload('add', {files: [{name: (addIndex += 1)}]}) + .fileupload('add', {files: [{name: (addIndex += 1)}]}) + .fileupload('add', {files: [{name: (addIndex += 1)}]}) + .fileupload('add', {files: [{name: 'test'}]}); + }); + + test('maxFileSize', function () { + expect(2); + var addIndex = 0, + sendIndex = 0; + $('#fileupload') + .fileupload({ + autoUpload: true, + maxFileSize: 1000, + send: function () { + strictEqual( + sendIndex += 1, + addIndex + ); + return false; + } + }) + .fileupload('add', {files: [{ + name: (addIndex += 1) + }]}) + .fileupload('add', {files: [{ + name: (addIndex += 1), + size: 999 + }]}) + .fileupload('add', {files: [{ + name: 'test', + size: 1001 + }]}) + .fileupload({ + send: function (e, data) { + ok( + !$.blueimp.fileupload.prototype.options + .send.call(this, e, data) + ); + return false; + } + }); + }); + + test('minFileSize', function () { + expect(2); + var addIndex = 0, + sendIndex = 0; + $('#fileupload') + .fileupload({ + autoUpload: true, + minFileSize: 1000, + send: function () { + strictEqual( + sendIndex += 1, + addIndex + ); + return false; + } + }) + .fileupload('add', {files: [{ + name: (addIndex += 1) + }]}) + .fileupload('add', {files: [{ + name: (addIndex += 1), + size: 1001 + }]}) + .fileupload('add', {files: [{ + name: 'test', + size: 999 + }]}) + .fileupload({ + send: function (e, data) { + ok( + !$.blueimp.fileupload.prototype.options + .send.call(this, e, data) + ); + return false; + } + }); + }); + + test('acceptFileTypes', function () { + expect(2); + var addIndex = 0, + sendIndex = 0; + $('#fileupload') + .fileupload({ + autoUpload: true, + acceptFileTypes: /(\.|\/)(gif|jpe?g|png)$/i, + disableImageMetaDataLoad: true, + send: function () { + strictEqual( + sendIndex += 1, + addIndex + ); + return false; + } + }) + .fileupload('add', {files: [{ + name: (addIndex += 1) + '.jpg' + }]}) + .fileupload('add', {files: [{ + name: (addIndex += 1), + type: 'image/jpeg' + }]}) + .fileupload('add', {files: [{ + name: 'test.txt', + type: 'text/plain' + }]}) + .fileupload({ + send: function (e, data) { + ok( + !$.blueimp.fileupload.prototype.options + .send.call(this, e, data) + ); + return false; + } + }); + }); + + test('acceptFileTypes as HTML5 data attribute', function () { + expect(2); + var regExp = /(\.|\/)(gif|jpe?g|png)$/i; + $('#fileupload') + .attr('data-accept-file-types', regExp.toString()) + .fileupload(); + strictEqual( + $.type($('#fileupload').fileupload('option', 'acceptFileTypes')), + $.type(regExp) + ); + strictEqual( + $('#fileupload').fileupload('option', 'acceptFileTypes').toString(), + regExp.toString() + ); + }); + +}); diff --git a/sources/library/justifiedGallery/jquery.justifiedGallery.js b/sources/library/justifiedGallery/jquery.justifiedGallery.js new file mode 100644 index 00000000..7c63149a --- /dev/null +++ b/sources/library/justifiedGallery/jquery.justifiedGallery.js @@ -0,0 +1,1097 @@ +/*! + * Justified Gallery - v3.6.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2015 Miro Mannino + * Licensed under the MIT license. + */ +(function($) { + + /** + * Justified Gallery controller constructor + * + * @param $gallery the gallery to build + * @param settings the settings (the defaults are in $.fn.justifiedGallery.defaults) + * @constructor + */ + var JustifiedGallery = function ($gallery, settings) { + + this.settings = settings; + this.checkSettings(); + + this.imgAnalyzerTimeout = null; + this.entries = null; + this.buildingRow = { + entriesBuff : [], + width : 0, + aspectRatio : 0 + }; + this.lastAnalyzedIndex = -1; + this.yield = { + every : 2, // do a flush every n flushes (must be greater than 1) + flushed : 0 // flushed rows without a yield + }; + this.border = settings.border >= 0 ? settings.border : settings.margins; + this.maxRowHeight = this.retrieveMaxRowHeight(); + this.suffixRanges = this.retrieveSuffixRanges(); + this.offY = this.border; + this.spinner = { + phase : 0, + timeSlot : 150, + $el : $('
    '), + intervalId : null + }; + this.checkWidthIntervalId = null; + this.galleryWidth = $gallery.width(); + this.$gallery = $gallery; + + }; + + /** @returns {String} the best suffix given the width and the height */ + JustifiedGallery.prototype.getSuffix = function (width, height) { + var longestSide, i; + longestSide = (width > height) ? width : height; + for (i = 0; i < this.suffixRanges.length; i++) { + if (longestSide <= this.suffixRanges[i]) { + return this.settings.sizeRangeSuffixes[this.suffixRanges[i]]; + } + } + return this.settings.sizeRangeSuffixes[this.suffixRanges[i - 1]]; + }; + + /** + * Remove the suffix from the string + * + * @returns {string} a new string without the suffix + */ + JustifiedGallery.prototype.removeSuffix = function (str, suffix) { + return str.substring(0, str.length - suffix.length); + }; + + /** + * @returns {boolean} a boolean to say if the suffix is contained in the str or not + */ + JustifiedGallery.prototype.endsWith = function (str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + }; + + /** + * Get the used suffix of a particular url + * + * @param str + * @returns {String} return the used suffix + */ + JustifiedGallery.prototype.getUsedSuffix = function (str) { + for (var si in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(si)) { + if (this.settings.sizeRangeSuffixes[si].length === 0) continue; + if (this.endsWith(str, this.settings.sizeRangeSuffixes[si])) return this.settings.sizeRangeSuffixes[si]; + } + } + return ''; + }; + + /** + * Given an image src, with the width and the height, returns the new image src with the + * best suffix to show the best quality thumbnail. + * + * @returns {String} the suffix to use + */ + JustifiedGallery.prototype.newSrc = function (imageSrc, imgWidth, imgHeight) { + var matchRes = imageSrc.match(this.settings.extension); + var ext = (matchRes != null) ? matchRes[0] : ''; + var newImageSrc = imageSrc.replace(this.settings.extension, ''); + newImageSrc = this.removeSuffix(newImageSrc, this.getUsedSuffix(newImageSrc)); + newImageSrc += this.getSuffix(imgWidth, imgHeight) + ext; + return newImageSrc; + }; + + /** + * Shows the images that is in the given entry + * + * @param $entry the entry + * @param callback the callback that is called when the show animation is finished + */ + JustifiedGallery.prototype.showImg = function ($entry, callback) { + if (this.settings.cssAnimation) { + $entry.addClass('entry-visible'); + if (callback) callback(); + } else { + $entry.stop().fadeTo(this.settings.imagesAnimationDuration, 1.0, callback); + } + }; + + /** + * Extract the image src form the image, looking from the 'safe-src', and if it can't be found, from the + * 'src' attribute. It saves in the image data the 'jg.originalSrc' field, with the extracted src. + * + * @param $image the image to analyze + * @returns {String} the extracted src + */ + JustifiedGallery.prototype.extractImgSrcFromImage = function ($image) { + var imageSrc = (typeof $image.data('safe-src') !== 'undefined') ? $image.data('safe-src') : $image.attr('src'); + $image.data('jg.originalSrc', imageSrc); + return imageSrc; + }; + + /** @returns {jQuery} the image in the given entry */ + JustifiedGallery.prototype.imgFromEntry = function ($entry) { + var $img = $entry.find('> img'); + if ($img.length === 0) $img = $entry.find('> a > img'); + return $img.length === 0 ? null : $img; + }; + + /** @returns {jQuery} the caption in the given entry */ + JustifiedGallery.prototype.captionFromEntry = function ($entry) { + var $caption = $entry.find('> .caption'); + return $caption.length === 0 ? null : $caption; + }; + + /** + * Display the entry + * + * @param {jQuery} $entry the entry to display + * @param {int} x the x position where the entry must be positioned + * @param y the y position where the entry must be positioned + * @param imgWidth the image width + * @param imgHeight the image height + * @param rowHeight the row height of the row that owns the entry + */ + JustifiedGallery.prototype.displayEntry = function ($entry, x, y, imgWidth, imgHeight, rowHeight) { + $entry.width(imgWidth); + $entry.height(rowHeight); + $entry.css('top', y); + $entry.css('left', x); + + var $image = this.imgFromEntry($entry); + if ($image !== null) { + $image.css('width', imgWidth); + $image.css('height', imgHeight); + $image.css('margin-left', - imgWidth / 2); + $image.css('margin-top', - imgHeight / 2); + + // Image reloading for an high quality of thumbnails + var imageSrc = $image.attr('src'); + var newImageSrc = this.newSrc(imageSrc, imgWidth, imgHeight); + + $image.one('error', function () { + $image.attr('src', $image.data('jg.originalSrc')); //revert to the original thumbnail, we got it. + }); + + var loadNewImage = function () { + if (imageSrc !== newImageSrc) { //load the new image after the fadeIn + $image.attr('src', newImageSrc); + } + }; + + if ($entry.data('jg.loaded') === 'skipped') { + this.onImageEvent(imageSrc, $.proxy(function() { + this.showImg($entry, loadNewImage); + $entry.data('jg.loaded', true); + }, this)); + } else { + this.showImg($entry, loadNewImage); + } + + } else { + this.showImg($entry); + } + + this.displayEntryCaption($entry); + }; + + /** + * Display the entry caption. If the caption element doesn't exists, it creates the caption using the 'alt' + * or the 'title' attributes. + * + * @param {jQuery} $entry the entry to process + */ + JustifiedGallery.prototype.displayEntryCaption = function ($entry) { + var $image = this.imgFromEntry($entry); + if ($image !== null && this.settings.captions) { + var $imgCaption = this.captionFromEntry($entry); + + // Create it if it doesn't exists + if ($imgCaption == null) { + var caption = $image.attr('alt'); + if (typeof caption === 'undefined') caption = $entry.attr('title'); + if (typeof caption !== 'undefined') { // Create only we found something + $imgCaption = $('
    ' + caption + '
    '); + $entry.append($imgCaption); + $entry.data('jg.createdCaption', true); + } + } + + // Create events (we check again the $imgCaption because it can be still inexistent) + if ($imgCaption !== null) { + if (!this.settings.cssAnimation) $imgCaption.stop().fadeTo(0, this.settings.captionSettings.nonVisibleOpacity); + this.addCaptionEventsHandlers($entry); + } + } else { + this.removeCaptionEventsHandlers($entry); + } + }; + + /** + * The callback for the event 'mouseenter'. It assumes that the event currentTarget is an entry. + * It shows the caption using jQuery (or using CSS if it is configured so) + * + * @param {Event} eventObject the event object + */ + JustifiedGallery.prototype.onEntryMouseEnterForCaption = function (eventObject) { + var $caption = this.captionFromEntry($(eventObject.currentTarget)); + if (this.settings.cssAnimation) { + $caption.addClass('caption-visible').removeClass('caption-hidden'); + } else { + $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, + this.settings.captionSettings.visibleOpacity); + } + }; + + /** + * The callback for the event 'mouseleave'. It assumes that the event currentTarget is an entry. + * It hides the caption using jQuery (or using CSS if it is configured so) + * + * @param {Event} eventObject the event object + */ + JustifiedGallery.prototype.onEntryMouseLeaveForCaption = function (eventObject) { + var $caption = this.captionFromEntry($(eventObject.currentTarget)); + if (this.settings.cssAnimation) { + $caption.removeClass('caption-visible').removeClass('caption-hidden'); + } else { + $caption.stop().fadeTo(this.settings.captionSettings.animationDuration, + this.settings.captionSettings.nonVisibleOpacity); + } + }; + + /** + * Add the handlers of the entry for the caption + * + * @param $entry the entry to modify + */ + JustifiedGallery.prototype.addCaptionEventsHandlers = function ($entry) { + var captionMouseEvents = $entry.data('jg.captionMouseEvents'); + if (typeof captionMouseEvents === 'undefined') { + captionMouseEvents = { + mouseenter: $.proxy(this.onEntryMouseEnterForCaption, this), + mouseleave: $.proxy(this.onEntryMouseLeaveForCaption, this) + }; + $entry.on('mouseenter', undefined, undefined, captionMouseEvents.mouseenter); + $entry.on('mouseleave', undefined, undefined, captionMouseEvents.mouseleave); + $entry.data('jg.captionMouseEvents', captionMouseEvents); + } + }; + + /** + * Remove the handlers of the entry for the caption + * + * @param $entry the entry to modify + */ + JustifiedGallery.prototype.removeCaptionEventsHandlers = function ($entry) { + var captionMouseEvents = $entry.data('jg.captionMouseEvents'); + if (typeof captionMouseEvents !== 'undefined') { + $entry.off('mouseenter', undefined, captionMouseEvents.mouseenter); + $entry.off('mouseleave', undefined, captionMouseEvents.mouseleave); + $entry.removeData('jg.captionMouseEvents'); + } + }; + + /** + * Justify the building row, preparing it to + * + * @param isLastRow + * @returns {*} + */ + JustifiedGallery.prototype.prepareBuildingRow = function (isLastRow) { + var i, $entry, imgAspectRatio, newImgW, newImgH, justify = true; + var minHeight = 0; + var availableWidth = this.galleryWidth - 2 * this.border - ( + (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); + var rowHeight = availableWidth / this.buildingRow.aspectRatio; + var justifiable = this.buildingRow.width / availableWidth > this.settings.justifyThreshold; + + //Skip the last row if we can't justify it and the lastRow == 'hide' + if (isLastRow && this.settings.lastRow === 'hide' && !justifiable) { + for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + if (this.settings.cssAnimation) + $entry.removeClass('entry-visible'); + else + $entry.stop().fadeTo(0, 0); + } + return -1; + } + + // With lastRow = nojustify, justify if is justificable (the images will not become too big) + if (isLastRow && !justifiable && this.settings.lastRow === 'nojustify') justify = false; + + for (i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); + + if (justify) { + newImgW = (i === this.buildingRow.entriesBuff.length - 1) ? availableWidth : rowHeight * imgAspectRatio; + newImgH = rowHeight; + + /* With fixedHeight the newImgH must be greater than rowHeight. + In some cases here this is not satisfied (due to the justification). + But we comment it, because is better to have a shorter but justified row instead + to have a cropped image at the end. */ + /*if (this.settings.fixedHeight && newImgH < this.settings.rowHeight) { + newImgW = this.settings.rowHeight * imgAspectRatio; + newImgH = this.settings.rowHeight; + }*/ + + } else { + newImgW = this.settings.rowHeight * imgAspectRatio; + newImgH = this.settings.rowHeight; + } + + availableWidth -= Math.round(newImgW); + $entry.data('jg.jwidth', Math.round(newImgW)); + $entry.data('jg.jheight', Math.ceil(newImgH)); + if (i === 0 || minHeight > newImgH) minHeight = newImgH; + } + + if (this.settings.fixedHeight && minHeight > this.settings.rowHeight) + minHeight = this.settings.rowHeight; + + return {minHeight: minHeight, justify: justify}; + }; + + /** + * Clear the building row data to be used for a new row + */ + JustifiedGallery.prototype.clearBuildingRow = function () { + this.buildingRow.entriesBuff = []; + this.buildingRow.aspectRatio = 0; + this.buildingRow.width = 0; + }; + + /** + * Flush a row: justify it, modify the gallery height accordingly to the row height + * + * @param isLastRow + */ + JustifiedGallery.prototype.flushRow = function (isLastRow) { + var settings = this.settings; + var $entry, minHeight, buildingRowRes, offX = this.border; + + buildingRowRes = this.prepareBuildingRow(isLastRow); + minHeight = buildingRowRes.minHeight; + if (isLastRow && settings.lastRow === 'hide' && minHeight === -1) { + this.clearBuildingRow(); + return; + } + + if (this.maxRowHeight.percentage) { + if (this.maxRowHeight.value * settings.rowHeight < minHeight) minHeight = this.maxRowHeight.value * settings.rowHeight; + } else { + if (this.maxRowHeight.value > 0 && this.maxRowHeight.value < minHeight) minHeight = this.maxRowHeight.value; + } + + for (var i = 0; i < this.buildingRow.entriesBuff.length; i++) { + $entry = this.buildingRow.entriesBuff[i]; + this.displayEntry($entry, offX, this.offY, $entry.data('jg.jwidth'), $entry.data('jg.jheight'), minHeight); + offX += $entry.data('jg.jwidth') + settings.margins; + } + + //Gallery Height + this.$gallery.height(this.offY + minHeight + this.border + (this.isSpinnerActive() ? this.getSpinnerHeight() : 0)); + + if (!isLastRow || (minHeight <= this.settings.rowHeight && buildingRowRes.justify)) { + //Ready for a new row + this.offY += minHeight + this.settings.margins; + this.clearBuildingRow(); + this.$gallery.trigger('jg.rowflush'); + } + }; + + /** + * Checks the width of the gallery container, to know if a new justification is needed + */ + JustifiedGallery.prototype.checkWidth = function () { + this.checkWidthIntervalId = setInterval($.proxy(function () { + var galleryWidth = parseInt(this.$gallery.width(), 10); + if (this.galleryWidth !== galleryWidth) { + this.galleryWidth = galleryWidth; + this.rewind(); + + // Restart to analyze + this.startImgAnalyzer(true); + } + }, this), this.settings.refreshTime); + }; + + /** + * @returns {boolean} a boolean saying if the spinner is active or not + */ + JustifiedGallery.prototype.isSpinnerActive = function () { + return this.spinner.intervalId != null; + }; + + /** + * @returns {int} the spinner height + */ + JustifiedGallery.prototype.getSpinnerHeight = function () { + return this.spinner.$el.innerHeight(); + }; + + /** + * Stops the spinner animation and modify the gallery height to exclude the spinner + */ + JustifiedGallery.prototype.stopLoadingSpinnerAnimation = function () { + clearInterval(this.spinner.intervalId); + this.spinner.intervalId = null; + this.$gallery.height(this.$gallery.height() - this.getSpinnerHeight()); + this.spinner.$el.detach(); + }; + + /** + * Starts the spinner animation + */ + JustifiedGallery.prototype.startLoadingSpinnerAnimation = function () { + var spinnerContext = this.spinner; + var $spinnerPoints = spinnerContext.$el.find('span'); + clearInterval(spinnerContext.intervalId); + this.$gallery.append(spinnerContext.$el); + this.$gallery.height(this.offY + this.getSpinnerHeight()); + spinnerContext.intervalId = setInterval(function () { + if (spinnerContext.phase < $spinnerPoints.length) { + $spinnerPoints.eq(spinnerContext.phase).fadeTo(spinnerContext.timeSlot, 1); + } else { + $spinnerPoints.eq(spinnerContext.phase - $spinnerPoints.length).fadeTo(spinnerContext.timeSlot, 0); + } + spinnerContext.phase = (spinnerContext.phase + 1) % ($spinnerPoints.length * 2); + }, spinnerContext.timeSlot); + }; + + /** + * Rewind the image analysis to start from the first entry. + */ + JustifiedGallery.prototype.rewind = function () { + this.lastAnalyzedIndex = -1; + this.offY = this.border; + this.clearBuildingRow(); + }; + + /** + * Hide the image of the buildingRow to prevent strange effects when the row will be + * re-justified again + */ + JustifiedGallery.prototype.hideBuildingRowImages = function () { + for (var i = 0; i < this.buildingRow.entriesBuff.length; i++) { + if (this.settings.cssAnimation) { + this.buildingRow.entriesBuff[i].removeClass('entry-visible'); + } else { + this.buildingRow.entriesBuff[i].stop().fadeTo(0, 0); + } + } + }; + + /** + * Update the entries searching it from the justified gallery HTML element + * + * @param norewind if norewind only the new entries will be changed (i.e. randomized, sorted or filtered) + * @returns {boolean} true if some entries has been founded + */ + JustifiedGallery.prototype.updateEntries = function (norewind) { + this.entries = this.$gallery.find(this.settings.selector).toArray(); + if (this.entries.length === 0) return false; + + // Filter + if (this.settings.filter) { + this.modifyEntries(this.filterArray, norewind); + } else { + this.modifyEntries(this.resetFilters, norewind); + } + + // Sort or randomize + if ($.isFunction(this.settings.sort)) { + this.modifyEntries(this.sortArray, norewind); + } else if (this.settings.randomize) { + this.modifyEntries(this.shuffleArray, norewind); + } + + return true; + }; + + /** + * Apply the entries order to the DOM, iterating the entries and appending the images + * + * @param entries the entries that has been modified and that must be re-ordered in the DOM + */ + JustifiedGallery.prototype.insertToGallery = function (entries) { + var that = this; + $.each(entries, function () { + $(this).appendTo(that.$gallery); + }); + }; + + /** + * Shuffle the array using the Fisher-Yates shuffle algorithm + * + * @param a the array to shuffle + * @return the shuffled array + */ + JustifiedGallery.prototype.shuffleArray = function (a) { + var i, j, temp; + for (i = a.length - 1; i > 0; i--) { + j = Math.floor(Math.random() * (i + 1)); + temp = a[i]; + a[i] = a[j]; + a[j] = temp; + } + this.insertToGallery(a); + return a; + }; + + /** + * Sort the array using settings.comparator as comparator + * + * @param a the array to sort (it is sorted) + * @return the sorted array + */ + JustifiedGallery.prototype.sortArray = function (a) { + a.sort(this.settings.sort); + this.insertToGallery(a); + return a; + }; + + /** + * Reset the filters removing the 'jg-filtered' class from all the entries + * + * @param a the array to reset + */ + JustifiedGallery.prototype.resetFilters = function (a) { + for (var i = 0; i < a.length; i++) $(a[i]).removeClass('jg-filtered'); + return a; + }; + + /** + * Filter the entries considering theirs classes (if a string has been passed) or using a function for filtering. + * + * @param a the array to filter + * @return the filtered array + */ + JustifiedGallery.prototype.filterArray = function (a) { + var settings = this.settings; + if ($.type(settings.filter) === 'string') { + // Filter only keeping the entries passed in the string + return a.filter(function (el) { + var $el = $(el); + if ($el.is(settings.filter)) { + $el.removeClass('jg-filtered'); + return true; + } else { + $el.addClass('jg-filtered'); + return false; + } + }); + } else if ($.isFunction(settings.filter)) { + // Filter using the passed function + return a.filter(settings.filter); + } + }; + + /** + * Modify the entries. With norewind only the new inserted images will be modified (the ones after lastAnalyzedIndex) + * + * @param functionToApply the function to call to modify the entries (e.g. sorting, randomization, filtering) + * @param norewind specify if the norewind has been called or not + */ + JustifiedGallery.prototype.modifyEntries = function (functionToApply, norewind) { + var lastEntries = norewind ? + this.entries.splice(this.lastAnalyzedIndex + 1, this.entries.length - this.lastAnalyzedIndex - 1) + : this.entries; + lastEntries = functionToApply.call(this, lastEntries); + this.entries = norewind ? this.entries.concat(lastEntries) : lastEntries; + }; + + /** + * Destroy the Justified Gallery instance. + * + * It clears all the css properties added in the style attributes. We doesn't backup the original + * values for those css attributes, because it costs (performance) and because in general one + * shouldn't use the style attribute for an uniform set of images (where we suppose the use of + * classes). Creating a backup is also difficult because JG could be called multiple times and + * with different style attributes. + */ + JustifiedGallery.prototype.destroy = function () { + clearInterval(this.checkWidthIntervalId); + + $.each(this.entries, $.proxy(function(_, entry) { + var $entry = $(entry); + + // Reset entry style + $entry.css('width', ''); + $entry.css('height', ''); + $entry.css('top', ''); + $entry.css('left', ''); + $entry.data('jg.loaded', undefined); + $entry.removeClass('jg-entry'); + + // Reset image style + var $img = this.imgFromEntry($entry); + $img.css('width', ''); + $img.css('height', ''); + $img.css('margin-left', ''); + $img.css('margin-top', ''); + $img.attr('src', $img.data('jg.originalSrc')); + $img.data('jg.originalSrc', undefined); + + // Remove caption + this.removeCaptionEventsHandlers($entry); + var $caption = this.captionFromEntry($entry); + if ($entry.data('jg.createdCaption')) { + // remove also the caption element (if created by jg) + $entry.data('jg.createdCaption', undefined); + if ($caption != null) $caption.remove(); + } else { + if ($caption != null) $caption.fadeTo(0, 1); + } + + }, this)); + + this.$gallery.css('height', ''); + this.$gallery.removeClass('justified-gallery'); + this.$gallery.data('jg.controller', undefined); + }; + + /** + * Analyze the images and builds the rows. It returns if it found an image that is not loaded. + * + * @param isForResize if the image analyzer is called for resizing or not, to call a different callback at the end + */ + JustifiedGallery.prototype.analyzeImages = function (isForResize) { + for (var i = this.lastAnalyzedIndex + 1; i < this.entries.length; i++) { + var $entry = $(this.entries[i]); + if ($entry.data('jg.loaded') === true || $entry.data('jg.loaded') === 'skipped') { + var availableWidth = this.galleryWidth - 2 * this.border - ( + (this.buildingRow.entriesBuff.length - 1) * this.settings.margins); + var imgAspectRatio = $entry.data('jg.width') / $entry.data('jg.height'); + if (availableWidth / (this.buildingRow.aspectRatio + imgAspectRatio) < this.settings.rowHeight) { + this.flushRow(false); + if(++this.yield.flushed >= this.yield.every) { + this.startImgAnalyzer(isForResize); + return; + } + } + + this.buildingRow.entriesBuff.push($entry); + this.buildingRow.aspectRatio += imgAspectRatio; + this.buildingRow.width += imgAspectRatio * this.settings.rowHeight; + this.lastAnalyzedIndex = i; + + } else if ($entry.data('jg.loaded') !== 'error') { + return; + } + } + + // Last row flush (the row is not full) + if (this.buildingRow.entriesBuff.length > 0) this.flushRow(true); + + if (this.isSpinnerActive()) { + this.stopLoadingSpinnerAnimation(); + } + + /* Stop, if there is, the timeout to start the analyzeImages. + This is because an image can be set loaded, and the timeout can be set, + but this image can be analyzed yet. + */ + this.stopImgAnalyzerStarter(); + + //On complete callback + this.$gallery.trigger(isForResize ? 'jg.resize' : 'jg.complete'); + }; + + /** + * Stops any ImgAnalyzer starter (that has an assigned timeout) + */ + JustifiedGallery.prototype.stopImgAnalyzerStarter = function () { + this.yield.flushed = 0; + if (this.imgAnalyzerTimeout !== null) clearTimeout(this.imgAnalyzerTimeout); + }; + + /** + * Starts the image analyzer. It is not immediately called to let the browser to update the view + * + * @param isForResize specifies if the image analyzer must be called for resizing or not + */ + JustifiedGallery.prototype.startImgAnalyzer = function (isForResize) { + var that = this; + this.stopImgAnalyzerStarter(); + this.imgAnalyzerTimeout = setTimeout(function () { + that.analyzeImages(isForResize); + }, 0.001); // we can't start it immediately due to a IE different behaviour + }; + + /** + * Checks if the image is loaded or not using another image object. We cannot use the 'complete' image property, + * because some browsers, with a 404 set complete = true. + * + * @param imageSrc the image src to load + * @param onLoad callback that is called when the image has been loaded + * @param onError callback that is called in case of an error + */ + JustifiedGallery.prototype.onImageEvent = function (imageSrc, onLoad, onError) { + if (!onLoad && !onError) return; + + var memImage = new Image(); + var $memImage = $(memImage); + if (onLoad) { + $memImage.one('load', function () { + $memImage.off('load error'); + onLoad(memImage); + }); + } + if (onError) { + $memImage.one('error', function() { + $memImage.off('load error'); + onError(memImage); + }); + } + memImage.src = imageSrc; + }; + + /** + * Init of Justified Gallery controlled + * It analyzes all the entries starting theirs loading and calling the image analyzer (that works with loaded images) + */ + JustifiedGallery.prototype.init = function () { + var imagesToLoad = false, skippedImages = false, that = this; + $.each(this.entries, function (index, entry) { + var $entry = $(entry); + var $image = that.imgFromEntry($entry); + + $entry.addClass('jg-entry'); + + if ($entry.data('jg.loaded') !== true && $entry.data('jg.loaded') !== 'skipped') { + + // Link Rel global overwrite + if (that.settings.rel !== null) $entry.attr('rel', that.settings.rel); + + // Link Target global overwrite + if (that.settings.target !== null) $entry.attr('target', that.settings.target); + + if ($image !== null) { + + // Image src + var imageSrc = that.extractImgSrcFromImage($image); + $image.attr('src', imageSrc); + + /* If we have the height and the width, we don't wait that the image is loaded, but we start directly + * with the justification */ + if (that.settings.waitThumbnailsLoad === false) { + var width = parseInt($image.attr('width'), 10); + var height = parseInt($image.attr('height'), 10); + if (!isNaN(width) && !isNaN(height)) { + $entry.data('jg.width', width); + $entry.data('jg.height', height); + $entry.data('jg.loaded', 'skipped'); + skippedImages = true; + that.startImgAnalyzer(false); + return true; // continue + } + } + + $entry.data('jg.loaded', false); + imagesToLoad = true; + + // Spinner start + if (!that.isSpinnerActive()) { + that.startLoadingSpinnerAnimation(); + } + + that.onImageEvent(imageSrc, function (loadImg) { // image loaded + $entry.data('jg.width', loadImg.width); + $entry.data('jg.height', loadImg.height); + $entry.data('jg.loaded', true); + that.startImgAnalyzer(false); + }, function () { // image load error + $entry.data('jg.loaded', 'error'); + that.startImgAnalyzer(false); + }); + + } else { + $entry.data('jg.loaded', true); + $entry.data('jg.width', $entry.width() | $entry.css('width') | 1); + $entry.data('jg.height', $entry.height() | $entry.css('height') | 1); + } + + } + + }); + + if (!imagesToLoad && !skippedImages) this.startImgAnalyzer(false); + this.checkWidth(); + }; + + /** + * Checks that it is a valid number. If a string is passed it is converted to a number + * + * @param settingContainer the object that contains the setting (to allow the conversion) + * @param settingName the setting name + */ + JustifiedGallery.prototype.checkOrConvertNumber = function (settingContainer, settingName) { + if ($.type(settingContainer[settingName]) === 'string') { + settingContainer[settingName] = parseFloat(settingContainer[settingName]); + } + + if ($.type(settingContainer[settingName]) === 'number') { + if (isNaN(settingContainer[settingName])) throw 'invalid number for ' + settingName; + } else { + throw settingName + ' must be a number'; + } + }; + + /** + * Checks the sizeRangeSuffixes and, if necessary, converts + * its keys from string (e.g. old settings with 'lt100') to int. + */ + JustifiedGallery.prototype.checkSizeRangesSuffixes = function () { + if ($.type(this.settings.sizeRangeSuffixes) !== 'object') { + throw 'sizeRangeSuffixes must be defined and must be an object'; + } + + var suffixRanges = []; + for (var rangeIdx in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(rangeIdx); + } + + var newSizeRngSuffixes = {0: ''}; + for (var i = 0; i < suffixRanges.length; i++) { + if ($.type(suffixRanges[i]) === 'string') { + try { + var numIdx = parseInt(suffixRanges[i].replace(/^[a-z]+/, ''), 10); + newSizeRngSuffixes[numIdx] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; + } catch (e) { + throw 'sizeRangeSuffixes keys must contains correct numbers (' + e + ')'; + } + } else { + newSizeRngSuffixes[suffixRanges[i]] = this.settings.sizeRangeSuffixes[suffixRanges[i]]; + } + } + + this.settings.sizeRangeSuffixes = newSizeRngSuffixes; + }; + + /** + * check and convert the maxRowHeight setting + */ + JustifiedGallery.prototype.retrieveMaxRowHeight = function () { + var newMaxRowHeight = { }; + + if ($.type(this.settings.maxRowHeight) === 'string') { + if (this.settings.maxRowHeight.match(/^[0-9]+%$/)) { + newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight.match(/^([0-9])+%$/)[1]) / 100; + newMaxRowHeight.percentage = false; + } else { + newMaxRowHeight.value = parseFloat(this.settings.maxRowHeight); + newMaxRowHeight.percentage = true; + } + } else if ($.type(this.settings.maxRowHeight) === 'number') { + newMaxRowHeight.value = this.settings.maxRowHeight; + newMaxRowHeight.percentage = false; + } else { + throw 'maxRowHeight must be a number or a percentage'; + } + + // check if the converted value is not a number + if (isNaN(newMaxRowHeight.value)) throw 'invalid number for maxRowHeight'; + + // check values + if (newMaxRowHeight.percentage) { + if (newMaxRowHeight.value < 100) newMaxRowHeight.value = 100; + } else { + if (newMaxRowHeight.value > 0 && newMaxRowHeight.value < this.settings.rowHeight) { + newMaxRowHeight.value = this.settings.rowHeight; + } + } + + return newMaxRowHeight; + + }; + + /** + * Checks the settings + */ + JustifiedGallery.prototype.checkSettings = function () { + this.checkSizeRangesSuffixes(); + + this.checkOrConvertNumber(this.settings, 'rowHeight'); + this.checkOrConvertNumber(this.settings, 'margins'); + this.checkOrConvertNumber(this.settings, 'border'); + + if (this.settings.lastRow !== 'nojustify' && + this.settings.lastRow !== 'justify' && + this.settings.lastRow !== 'hide') { + throw 'lastRow must be "nojustify", "justify" or "hide"'; + } + + this.checkOrConvertNumber(this.settings, 'justifyThreshold'); + if (this.settings.justifyThreshold < 0 || this.settings.justifyThreshold > 1) { + throw 'justifyThreshold must be in the interval [0,1]'; + } + if ($.type(this.settings.cssAnimation) !== 'boolean') { + throw 'cssAnimation must be a boolean'; + } + + if ($.type(this.settings.captions) !== 'boolean') throw 'captions must be a boolean'; + this.checkOrConvertNumber(this.settings.captionSettings, 'animationDuration'); + + this.checkOrConvertNumber(this.settings.captionSettings, 'visibleOpacity'); + if (this.settings.captionSettings.visibleOpacity < 0 || + this.settings.captionSettings.visibleOpacity > 1) { + throw 'captionSettings.visibleOpacity must be in the interval [0, 1]'; + } + + this.checkOrConvertNumber(this.settings.captionSettings, 'nonVisibleOpacity'); + if (this.settings.captionSettings.nonVisibleOpacity < 0 || + this.settings.captionSettings.nonVisibleOpacity > 1) { + throw 'captionSettings.nonVisibleOpacity must be in the interval [0, 1]'; + } + + if ($.type(this.settings.fixedHeight) !== 'boolean') throw 'fixedHeight must be a boolean'; + this.checkOrConvertNumber(this.settings, 'imagesAnimationDuration'); + this.checkOrConvertNumber(this.settings, 'refreshTime'); + if ($.type(this.settings.randomize) !== 'boolean') throw 'randomize must be a boolean'; + if ($.type(this.settings.selector) !== 'string') throw 'selector must be a string'; + + if (this.settings.sort !== false && !$.isFunction(this.settings.sort)) { + throw 'sort must be false or a comparison function'; + } + + if (this.settings.filter !== false && !$.isFunction(this.settings.sort) && + $.type(this.settings.filter) !== 'string') { + throw 'filter must be false, a string or a filter function'; + } + }; + + /** + * It brings all the indexes from the sizeRangeSuffixes and it orders them. They are then sorted and returned. + * @returns {Array} sorted suffix ranges + */ + JustifiedGallery.prototype.retrieveSuffixRanges = function () { + var suffixRanges = []; + for (var rangeIdx in this.settings.sizeRangeSuffixes) { + if (this.settings.sizeRangeSuffixes.hasOwnProperty(rangeIdx)) suffixRanges.push(parseInt(rangeIdx, 10)); + } + suffixRanges.sort(function (a, b) { return a > b ? 1 : a < b ? -1 : 0; }); + return suffixRanges; + }; + + /** + * Update the existing settings only changing some of them + * + * @param newSettings the new settings (or a subgroup of them) + */ + JustifiedGallery.prototype.updateSettings = function (newSettings) { + // In this case Justified Gallery has been called again changing only some options + this.settings = $.extend({}, this.settings, newSettings); + this.checkSettings(); + + // As reported in the settings: negative value = same as margins, 0 = disabled + this.border = this.settings.border >= 0 ? this.settings.border : this.settings.margins; + + this.maxRowHeight = this.retrieveMaxRowHeight(); + this.suffixRanges = this.retrieveSuffixRanges(); + }; + + /** + * Justified Gallery plugin for jQuery + * + * Events + * - jg.complete : called when all the gallery has been created + * - jg.resize : called when the gallery has been resized + * - jg.rowflush : when a new row appears + * + * @param arg the action (or the settings) passed when the plugin is called + * @returns {*} the object itself + */ + $.fn.justifiedGallery = function (arg) { + return this.each(function (index, gallery) { + + var $gallery = $(gallery); + $gallery.addClass('justified-gallery'); + + var controller = $gallery.data('jg.controller'); + if (typeof controller === 'undefined') { + // Create controller and assign it to the object data + if (typeof arg !== 'undefined' && arg !== null && $.type(arg) !== 'object') { + throw 'The argument must be an object'; + } + controller = new JustifiedGallery($gallery, $.extend({}, $.fn.justifiedGallery.defaults, arg)); + $gallery.data('jg.controller', controller); + } else if (arg === 'norewind') { + // In this case we don't rewind: we analyze only the latest images (e.g. to complete the last unfinished row + controller.hideBuildingRowImages(); + } else if (arg === 'destroy') { + controller.destroy(); + return; + } else { + // In this case Justified Gallery has been called again changing only some options + controller.updateSettings(arg); + controller.rewind(); + } + + // Update the entries list + if (!controller.updateEntries(arg === 'norewind')) return; + + // Init justified gallery + controller.init(); + + }); + }; + + // Default options + $.fn.justifiedGallery.defaults = { + sizeRangeSuffixes: { }, /* e.g. Flickr configuration + { + 100: '_t', // used when longest is less than 100px + 240: '_m', // used when longest is between 101px and 240px + 320: '_n', // ... + 500: '', + 640: '_z', + 1024: '_b' // used as else case because it is the last + } + */ + rowHeight: 120, + maxRowHeight: '200%', // negative value = no limits, number to express the value in pixels, + // '[0-9]+%' to express in percentage (e.g. 200% means that the row height + // can't exceed 2 * rowHeight) + margins: 1, + border: -1, // negative value = same as margins, 0 = disabled, any other value to set the border + + lastRow: 'nojustify', // or can be 'justify' or 'hide' + justifyThreshold: 0.75, /* if row width / available space > 0.75 it will be always justified + * (i.e. lastRow setting is not considered) */ + fixedHeight: false, + waitThumbnailsLoad: true, + captions: true, + cssAnimation: false, + imagesAnimationDuration: 500, // ignored with css animations + captionSettings: { // ignored with css animations + animationDuration: 500, + visibleOpacity: 0.7, + nonVisibleOpacity: 0.0 + }, + rel: null, // rewrite the rel of each analyzed links + target: null, // rewrite the target of all links + extension: /\.[^.\\/]+$/, // regexp to capture the extension of an image + refreshTime: 100, // time interval (in ms) to check if the page changes its width + randomize: false, + sort: false, /* + - false: to do not sort + - function: to sort them using the function as comparator (see Array.prototype.sort()) + */ + filter: false, /* + - false: for a disabled filter + - a string: an entry is kept if entry.is(filter string) returns true + see jQuery's .is() function for further information + - a function: invoked with arguments (entry, index, array). Return true to keep the entry, false otherwise. + see Array.prototype.filter for further information. + */ + selector: '> a, > div:not(.spinner)' // The selector that is used to know what are the entries of the gallery + }; + +}(jQuery)); diff --git a/sources/library/justifiedGallery/jquery.justifiedGallery.min.js b/sources/library/justifiedGallery/jquery.justifiedGallery.min.js new file mode 100644 index 00000000..74f33320 --- /dev/null +++ b/sources/library/justifiedGallery/jquery.justifiedGallery.min.js @@ -0,0 +1,7 @@ +/*! + * Justified Gallery - v3.6.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2015 Miro Mannino + * Licensed under the MIT license. + */ +!function(a){var b=function(b,c){this.settings=c,this.checkSettings(),this.imgAnalyzerTimeout=null,this.entries=null,this.buildingRow={entriesBuff:[],width:0,aspectRatio:0},this.lastAnalyzedIndex=-1,this.yield={every:2,flushed:0},this.border=c.border>=0?c.border:c.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges(),this.offY=this.border,this.spinner={phase:0,timeSlot:150,$el:a('
    '),intervalId:null},this.checkWidthIntervalId=null,this.galleryWidth=b.width(),this.$gallery=b};b.prototype.getSuffix=function(a,b){var c,d;for(c=a>b?a:b,d=0;d img");return 0===b.length&&(b=a.find("> a > img")),0===b.length?null:b},b.prototype.captionFromEntry=function(a){var b=a.find("> .caption");return 0===b.length?null:b},b.prototype.displayEntry=function(b,c,d,e,f,g){b.width(e),b.height(g),b.css("top",d),b.css("left",c);var h=this.imgFromEntry(b);if(null!==h){h.css("width",e),h.css("height",f),h.css("margin-left",-e/2),h.css("margin-top",-f/2);var i=h.attr("src"),j=this.newSrc(i,e,f);h.one("error",function(){h.attr("src",h.data("jg.originalSrc"))});var k=function(){i!==j&&h.attr("src",j)};"skipped"===b.data("jg.loaded")?this.onImageEvent(i,a.proxy(function(){this.showImg(b,k),b.data("jg.loaded",!0)},this)):this.showImg(b,k)}else this.showImg(b);this.displayEntryCaption(b)},b.prototype.displayEntryCaption=function(b){var c=this.imgFromEntry(b);if(null!==c&&this.settings.captions){var d=this.captionFromEntry(b);if(null==d){var e=c.attr("alt");"undefined"==typeof e&&(e=b.attr("title")),"undefined"!=typeof e&&(d=a('
    '+e+"
    "),b.append(d),b.data("jg.createdCaption",!0))}null!==d&&(this.settings.cssAnimation||d.stop().fadeTo(0,this.settings.captionSettings.nonVisibleOpacity),this.addCaptionEventsHandlers(b))}else this.removeCaptionEventsHandlers(b)},b.prototype.onEntryMouseEnterForCaption=function(b){var c=this.captionFromEntry(a(b.currentTarget));this.settings.cssAnimation?c.addClass("caption-visible").removeClass("caption-hidden"):c.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.visibleOpacity)},b.prototype.onEntryMouseLeaveForCaption=function(b){var c=this.captionFromEntry(a(b.currentTarget));this.settings.cssAnimation?c.removeClass("caption-visible").removeClass("caption-hidden"):c.stop().fadeTo(this.settings.captionSettings.animationDuration,this.settings.captionSettings.nonVisibleOpacity)},b.prototype.addCaptionEventsHandlers=function(b){var c=b.data("jg.captionMouseEvents");"undefined"==typeof c&&(c={mouseenter:a.proxy(this.onEntryMouseEnterForCaption,this),mouseleave:a.proxy(this.onEntryMouseLeaveForCaption,this)},b.on("mouseenter",void 0,void 0,c.mouseenter),b.on("mouseleave",void 0,void 0,c.mouseleave),b.data("jg.captionMouseEvents",c))},b.prototype.removeCaptionEventsHandlers=function(a){var b=a.data("jg.captionMouseEvents");"undefined"!=typeof b&&(a.off("mouseenter",void 0,b.mouseenter),a.off("mouseleave",void 0,b.mouseleave),a.removeData("jg.captionMouseEvents"))},b.prototype.prepareBuildingRow=function(a){var b,c,d,e,f,g=!0,h=0,i=this.galleryWidth-2*this.border-(this.buildingRow.entriesBuff.length-1)*this.settings.margins,j=i/this.buildingRow.aspectRatio,k=this.buildingRow.width/i>this.settings.justifyThreshold;if(a&&"hide"===this.settings.lastRow&&!k){for(b=0;bf)&&(h=f);return this.settings.fixedHeight&&h>this.settings.rowHeight&&(h=this.settings.rowHeight),{minHeight:h,justify:g}},b.prototype.clearBuildingRow=function(){this.buildingRow.entriesBuff=[],this.buildingRow.aspectRatio=0,this.buildingRow.width=0},b.prototype.flushRow=function(a){var b,c,d,e=this.settings,f=this.border;if(d=this.prepareBuildingRow(a),c=d.minHeight,a&&"hide"===e.lastRow&&-1===c)return void this.clearBuildingRow();this.maxRowHeight.percentage?this.maxRowHeight.value*e.rowHeight0&&this.maxRowHeight.value0;b--)c=Math.floor(Math.random()*(b+1)),d=a[b],a[b]=a[c],a[c]=d;return this.insertToGallery(a),a},b.prototype.sortArray=function(a){return a.sort(this.settings.sort),this.insertToGallery(a),a},b.prototype.resetFilters=function(b){for(var c=0;c=this.yield.every))return void this.startImgAnalyzer(b);this.buildingRow.entriesBuff.push(d),this.buildingRow.aspectRatio+=f,this.buildingRow.width+=f*this.settings.rowHeight,this.lastAnalyzedIndex=c}else if("error"!==d.data("jg.loaded"))return}this.buildingRow.entriesBuff.length>0&&this.flushRow(!0),this.isSpinnerActive()&&this.stopLoadingSpinnerAnimation(),this.stopImgAnalyzerStarter(),this.$gallery.trigger(b?"jg.resize":"jg.complete")},b.prototype.stopImgAnalyzerStarter=function(){this.yield.flushed=0,null!==this.imgAnalyzerTimeout&&clearTimeout(this.imgAnalyzerTimeout)},b.prototype.startImgAnalyzer=function(a){var b=this;this.stopImgAnalyzerStarter(),this.imgAnalyzerTimeout=setTimeout(function(){b.analyzeImages(a)},.001)},b.prototype.onImageEvent=function(b,c,d){if(c||d){var e=new Image,f=a(e);c&&f.one("load",function(){f.off("load error"),c(e)}),d&&f.one("error",function(){f.off("load error"),d(e)}),e.src=b}},b.prototype.init=function(){var b=!1,c=!1,d=this;a.each(this.entries,function(e,f){var g=a(f),h=d.imgFromEntry(g);if(g.addClass("jg-entry"),g.data("jg.loaded")!==!0&&"skipped"!==g.data("jg.loaded"))if(null!==d.settings.rel&&g.attr("rel",d.settings.rel),null!==d.settings.target&&g.attr("target",d.settings.target),null!==h){var i=d.extractImgSrcFromImage(h);if(h.attr("src",i),d.settings.waitThumbnailsLoad===!1){var j=parseInt(h.attr("width"),10),k=parseInt(h.attr("height"),10);if(!isNaN(j)&&!isNaN(k))return g.data("jg.width",j),g.data("jg.height",k),g.data("jg.loaded","skipped"),c=!0,d.startImgAnalyzer(!1),!0}g.data("jg.loaded",!1),b=!0,d.isSpinnerActive()||d.startLoadingSpinnerAnimation(),d.onImageEvent(i,function(a){g.data("jg.width",a.width),g.data("jg.height",a.height),g.data("jg.loaded",!0),d.startImgAnalyzer(!1)},function(){g.data("jg.loaded","error"),d.startImgAnalyzer(!1)})}else g.data("jg.loaded",!0),g.data("jg.width",g.width()|g.css("width")|1),g.data("jg.height",g.height()|g.css("height")|1)}),b||c||this.startImgAnalyzer(!1),this.checkWidth()},b.prototype.checkOrConvertNumber=function(b,c){if("string"===a.type(b[c])&&(b[c]=parseFloat(b[c])),"number"!==a.type(b[c]))throw c+" must be a number";if(isNaN(b[c]))throw"invalid number for "+c},b.prototype.checkSizeRangesSuffixes=function(){if("object"!==a.type(this.settings.sizeRangeSuffixes))throw"sizeRangeSuffixes must be defined and must be an object";var b=[];for(var c in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(c)&&b.push(c);for(var d={0:""},e=0;e0&&b.value1)throw"justifyThreshold must be in the interval [0,1]";if("boolean"!==a.type(this.settings.cssAnimation))throw"cssAnimation must be a boolean";if("boolean"!==a.type(this.settings.captions))throw"captions must be a boolean";if(this.checkOrConvertNumber(this.settings.captionSettings,"animationDuration"),this.checkOrConvertNumber(this.settings.captionSettings,"visibleOpacity"),this.settings.captionSettings.visibleOpacity<0||this.settings.captionSettings.visibleOpacity>1)throw"captionSettings.visibleOpacity must be in the interval [0, 1]";if(this.checkOrConvertNumber(this.settings.captionSettings,"nonVisibleOpacity"),this.settings.captionSettings.nonVisibleOpacity<0||this.settings.captionSettings.nonVisibleOpacity>1)throw"captionSettings.nonVisibleOpacity must be in the interval [0, 1]";if("boolean"!==a.type(this.settings.fixedHeight))throw"fixedHeight must be a boolean";if(this.checkOrConvertNumber(this.settings,"imagesAnimationDuration"),this.checkOrConvertNumber(this.settings,"refreshTime"),"boolean"!==a.type(this.settings.randomize))throw"randomize must be a boolean";if("string"!==a.type(this.settings.selector))throw"selector must be a string";if(this.settings.sort!==!1&&!a.isFunction(this.settings.sort))throw"sort must be false or a comparison function";if(this.settings.filter!==!1&&!a.isFunction(this.settings.sort)&&"string"!==a.type(this.settings.filter))throw"filter must be false, a string or a filter function"},b.prototype.retrieveSuffixRanges=function(){var a=[];for(var b in this.settings.sizeRangeSuffixes)this.settings.sizeRangeSuffixes.hasOwnProperty(b)&&a.push(parseInt(b,10));return a.sort(function(a,b){return a>b?1:b>a?-1:0}),a},b.prototype.updateSettings=function(b){this.settings=a.extend({},this.settings,b),this.checkSettings(),this.border=this.settings.border>=0?this.settings.border:this.settings.margins,this.maxRowHeight=this.retrieveMaxRowHeight(),this.suffixRanges=this.retrieveSuffixRanges()},a.fn.justifiedGallery=function(c){return this.each(function(d,e){var f=a(e);f.addClass("justified-gallery");var g=f.data("jg.controller");if("undefined"==typeof g){if("undefined"!=typeof c&&null!==c&&"object"!==a.type(c))throw"The argument must be an object";g=new b(f,a.extend({},a.fn.justifiedGallery.defaults,c)),f.data("jg.controller",g)}else if("norewind"===c)g.hideBuildingRowImages();else{if("destroy"===c)return void g.destroy();g.updateSettings(c),g.rewind()}g.updateEntries("norewind"===c)&&g.init()})},a.fn.justifiedGallery.defaults={sizeRangeSuffixes:{},rowHeight:120,maxRowHeight:"200%",margins:1,border:-1,lastRow:"nojustify",justifyThreshold:.75,fixedHeight:!1,waitThumbnailsLoad:!0,captions:!0,cssAnimation:!1,imagesAnimationDuration:500,captionSettings:{animationDuration:500,visibleOpacity:.7,nonVisibleOpacity:0},rel:null,target:null,extension:/\.[^.\\/]+$/,refreshTime:100,randomize:!1,sort:!1,filter:!1,selector:"> a, > div:not(.spinner)"}}(jQuery); \ No newline at end of file diff --git a/sources/library/justifiedGallery/justifiedGallery.css b/sources/library/justifiedGallery/justifiedGallery.css new file mode 100644 index 00000000..0d45475c --- /dev/null +++ b/sources/library/justifiedGallery/justifiedGallery.css @@ -0,0 +1,155 @@ +/*! + * Justified Gallery - v3.6.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2015 Miro Mannino + * Licensed under the MIT license. + */ +@-webkit-keyframes justified-gallery-show-caption-animation { + from { + opacity: 0; + } + to { + opacity: 0.7; + } +} +@-moz-keyframes justified-gallery-show-caption-animation { + from { + opacity: 0; + } + to { + opacity: 0.7; + } +} +@-o-keyframes justified-gallery-show-caption-animation { + from { + opacity: 0; + } + to { + opacity: 0.7; + } +} +@keyframes justified-gallery-show-caption-animation { + from { + opacity: 0; + } + to { + opacity: 0.7; + } +} +@-webkit-keyframes justified-gallery-show-entry-animation { + from { + opacity: 0; + } + to { + opacity: 1.0; + } +} +@-moz-keyframes justified-gallery-show-entry-animation { + from { + opacity: 0; + } + to { + opacity: 1.0; + } +} +@-o-keyframes justified-gallery-show-entry-animation { + from { + opacity: 0; + } + to { + opacity: 1.0; + } +} +@keyframes justified-gallery-show-entry-animation { + from { + opacity: 0; + } + to { + opacity: 1.0; + } +} +.justified-gallery { + width: 100%; + position: relative; + overflow: hidden; +} +.justified-gallery > a, +.justified-gallery > div { + position: absolute; + display: inline-block; + overflow: hidden; + opacity: 0; + filter: alpha(opacity=0); + /* IE8 or Earlier */ +} +.justified-gallery > a > img, +.justified-gallery > div > img, +.justified-gallery > a > a > img, +.justified-gallery > div > a > img { + position: absolute; + top: 50%; + left: 50%; + margin: 0; + padding: 0; + border: none; +} +.justified-gallery > a > .caption, +.justified-gallery > div > .caption { + display: none; + position: absolute; + bottom: 0; + padding: 5px; + background-color: #000000; + left: 0; + right: 0; + margin: 0; + color: white; + font-size: 12px; + font-weight: 300; + font-family: sans-serif; +} +.justified-gallery > a > .caption.caption-visible, +.justified-gallery > div > .caption.caption-visible { + display: initial; + opacity: 0.7; + filter: "alpha(opacity=70)"; + /* IE8 or Earlier */ + -webkit-animation: justified-gallery-show-caption-animation 500ms 0 ease; + -moz-animation: justified-gallery-show-caption-animation 500ms 0 ease; + -ms-animation: justified-gallery-show-caption-animation 500ms 0 ease; +} +.justified-gallery > .entry-visible { + opacity: 1.0; + filter: alpha(opacity=100); + /* IE8 or Earlier */ + -webkit-animation: justified-gallery-show-entry-animation 500ms 0 ease; + -moz-animation: justified-gallery-show-entry-animation 500ms 0 ease; + -ms-animation: justified-gallery-show-entry-animation 500ms 0 ease; +} +.justified-gallery > .jg-filtered { + display: none; +} +.justified-gallery > .spinner { + position: absolute; + bottom: 0; + margin-left: -24px; + padding: 10px 0 10px 0; + left: 50%; + opacity: initial; + filter: initial; + overflow: initial; +} +.justified-gallery > .spinner > span { + display: inline-block; + opacity: 0; + filter: alpha(opacity=0); + /* IE8 or Earlier */ + width: 8px; + height: 8px; + margin: 0 4px 0 4px; + background-color: #000; + border-top-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px; +} diff --git a/sources/library/justifiedGallery/justifiedGallery.min.css b/sources/library/justifiedGallery/justifiedGallery.min.css new file mode 100644 index 00000000..d7b1c672 --- /dev/null +++ b/sources/library/justifiedGallery/justifiedGallery.min.css @@ -0,0 +1,7 @@ +/*! + * Justified Gallery - v3.6.0 + * http://miromannino.github.io/Justified-Gallery/ + * Copyright (c) 2015 Miro Mannino + * Licensed under the MIT license. + */ +@-webkit-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-moz-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-o-keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@keyframes justified-gallery-show-caption-animation{from{opacity:0}to{opacity:.7}}@-webkit-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@-moz-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@-o-keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}@keyframes justified-gallery-show-entry-animation{from{opacity:0}to{opacity:1}}.justified-gallery{width:100%;position:relative;overflow:hidden}.justified-gallery>a,.justified-gallery>div{position:absolute;display:inline-block;overflow:hidden;opacity:0;filter:alpha(opacity=0)}.justified-gallery>a>img,.justified-gallery>div>img,.justified-gallery>a>a>img,.justified-gallery>div>a>img{position:absolute;top:50%;left:50%;margin:0;padding:0;border:0}.justified-gallery>a>.caption,.justified-gallery>div>.caption{display:none;position:absolute;bottom:0;padding:5px;background-color:#000;left:0;right:0;margin:0;color:#fff;font-size:12px;font-weight:300;font-family:sans-serif}.justified-gallery>a>.caption.caption-visible,.justified-gallery>div>.caption.caption-visible{display:initial;opacity:.7;filter:"alpha(opacity=70)";-webkit-animation:justified-gallery-show-caption-animation 500ms 0 ease;-moz-animation:justified-gallery-show-caption-animation 500ms 0 ease;-ms-animation:justified-gallery-show-caption-animation 500ms 0 ease}.justified-gallery>.entry-visible{opacity:1;filter:alpha(opacity=100);-webkit-animation:justified-gallery-show-entry-animation 500ms 0 ease;-moz-animation:justified-gallery-show-entry-animation 500ms 0 ease;-ms-animation:justified-gallery-show-entry-animation 500ms 0 ease}.justified-gallery>.jg-filtered{display:none}.justified-gallery>.spinner{position:absolute;bottom:0;margin-left:-24px;padding:10px 0;left:50%;opacity:initial;filter:initial;overflow:initial}.justified-gallery>.spinner>span{display:inline-block;opacity:0;filter:alpha(opacity=0);width:8px;height:8px;margin:0 4px;background-color:#000;border-top-left-radius:6px;border-top-right-radius:6px;border-bottom-right-radius:6px;border-bottom-left-radius:6px} \ No newline at end of file diff --git a/sources/library/langdet/Text/LanguageDetect.php b/sources/library/langdet/Text/LanguageDetect.php new file mode 100644 index 00000000..7cebbe60 --- /dev/null +++ b/sources/library/langdet/Text/LanguageDetect.php @@ -0,0 +1,1708 @@ + + * @copyright 2005-2006 Nicholas Pisarro + * @license http://www.debian.org/misc/bsd.license BSD + * @version SVN: $Id: LanguageDetect.php 322353 2012-01-16 08:41:43Z cweiske $ + * @link http://pear.php.net/package/Text_LanguageDetect/ + * @link http://langdetect.blogspot.com/ + */ + +require_once 'Text/LanguageDetect/Exception.php'; +require_once 'Text/LanguageDetect/Parser.php'; +require_once 'Text/LanguageDetect/ISO639.php'; + +/** + * Language detection class + * + * Requires the langauge model database (lang.dat) that should have + * accompanied this class definition in order to be instantiated. + * + * Example usage: + * + * + * require_once 'Text/LanguageDetect.php'; + * + * $l = new Text_LanguageDetect; + * + * $stdin = fopen('php://stdin', 'r'); + * + * echo "Supported languages:\n"; + * + * try { + * $langs = $l->getLanguages(); + * } catch (Text_LanguageDetect_Exception $e) { + * die($e->getMessage()); + * } + * + * sort($langs); + * echo join(', ', $langs); + * + * while ($line = fgets($stdin)) { + * print_r($l->detect($line, 4)); + * } + * + * + * @category Text + * @package Text_LanguageDetect + * @author Nicholas Pisarro + * @copyright 2005 Nicholas Pisarro + * @license http://www.debian.org/misc/bsd.license BSD + * @version Release: @package_version@ + * @link http://pear.php.net/package/Text_LanguageDetect/ + * @todo allow users to generate their own language models + */ +class Text_LanguageDetect +{ + /** + * The filename that stores the trigram data for the detector + * + * If this value starts with a slash (/) or a dot (.) the value of + * $this->_data_dir will be ignored + * + * @var string + * @access private + */ + var $_db_filename = 'lang.dat'; + + /** + * The filename that stores the unicode block definitions + * + * If this value starts with a slash (/) or a dot (.) the value of + * $this->_data_dir will be ignored + * + * @var string + * @access private + */ + var $_unicode_db_filename = 'unicode_blocks.dat'; + + /** + * The data directory + * + * Should be set by PEAR installer + * + * @var string + * @access private + */ + var $_data_dir = '@data_dir@'; + + /** + * The trigram data for comparison + * + * Will be loaded on start from $this->_db_filename + * + * @var array + * @access private + */ + var $_lang_db = array(); + + /** + * stores the map of the trigram data to unicode characters + * + * @access private + * @var array + */ + var $_unicode_map; + + /** + * The size of the trigram data arrays + * + * @var int + * @access private + */ + var $_threshold = 300; + + /** + * the maximum possible score. + * + * needed for score normalization. Different depending on the + * perl compatibility setting + * + * @access private + * @var int + * @see setPerlCompatible() + */ + var $_max_score = 0; + + /** + * Whether or not to simulate perl's Language::Guess exactly + * + * @access private + * @var bool + * @see setPerlCompatible() + */ + var $_perl_compatible = false; + + /** + * Whether to use the unicode block detection to speed up processing + * + * @access private + * @var bool + */ + var $_use_unicode_narrowing = true; + + /** + * stores the result of the clustering operation + * + * @access private + * @var array + * @see clusterLanguages() + */ + var $_clusters; + + /** + * Which type of "language names" are accepted and returned: + * + * 0 - language name ("english") + * 2 - 2-letter ISO 639-1 code ("en") + * 3 - 3-letter ISO 639-2 code ("eng") + */ + var $_name_mode = 0; + + /** + * Constructor + * + * Will attempt to load the language database. If it fails, you will get + * an exception. + */ + function __construct() + { + $data = $this->_readdb($this->_db_filename); + $this->_checkTrigram($data['trigram']); + $this->_lang_db = $data['trigram']; + + if (isset($data['trigram-unicodemap'])) { + $this->_unicode_map = $data['trigram-unicodemap']; + } + + // Not yet implemented: + if (isset($data['trigram-clusters'])) { + $this->_clusters = $data['trigram-clusters']; + } + } + + /** + * Returns the path to the location of the database + * + * @param string $fname File name to load + * + * @return string expected path to the language model database + * @access private + */ + function _get_data_loc($fname) + { + if ($fname{0} == '/' || $fname{0} == '.') { + // if filename starts with a slash, assume it's an absolute pathname + // and skip whatever is in $this->_data_dir + return $fname; + + } elseif ($this->_data_dir != '@' . 'data_dir' . '@') { + // if the data dir was set by the PEAR installer, use that + return $this->_data_dir . '/Text_LanguageDetect/' . $fname; + + } else { + // assume this was just unpacked somewhere + // try the local working directory if otherwise + return __DIR__ . '/../data/' . $fname; + } + } + + /** + * Loads the language trigram database from filename + * + * Trigram datbase should be a serialize()'d array + * + * @param string $fname the filename where the data is stored + * + * @return array the language model data + * @throws Text_LanguageDetect_Exception + * @access private + */ + function _readdb($fname) + { + // finds the correct data dir + $fname = $this->_get_data_loc($fname); + + // input check + if (!file_exists($fname)) { + throw new Text_LanguageDetect_Exception( + 'Language database does not exist: ' . $fname, + Text_LanguageDetect_Exception::DB_NOT_FOUND + ); + } elseif (!is_readable($fname)) { + throw new Text_LanguageDetect_Exception( + 'Language database is not readable: ' . $fname, + Text_LanguageDetect_Exception::DB_NOT_READABLE + ); + } + + return unserialize(file_get_contents($fname)); + } + + + /** + * Checks if this object is ready to detect languages + * + * @param array $trigram Trigram data from database + * + * @return void + * @access private + */ + function _checkTrigram($trigram) + { + if (!is_array($trigram)) { + if (ini_get('magic_quotes_runtime')) { + throw new Text_LanguageDetect_Exception( + 'Error loading database. Try turning magic_quotes_runtime off.', + Text_LanguageDetect_Exception::MAGIC_QUOTES + ); + } + throw new Text_LanguageDetect_Exception( + 'Language database is not an array.', + Text_LanguageDetect_Exception::DB_NOT_ARRAY + ); + } elseif (empty($trigram)) { + throw new Text_LanguageDetect_Exception( + 'Language database has no elements.', + Text_LanguageDetect_Exception::DB_EMPTY + ); + } + } + + /** + * Omits languages + * + * Pass this function the name of or an array of names of + * languages that you don't want considered + * + * If you're only expecting a limited set of languages, this can greatly + * speed up processing + * + * @param mixed $omit_list language name or array of names to omit + * @param bool $include_only if true will include (rather than + * exclude) only those in the list + * + * @return int number of languages successfully deleted + * @throws Text_LanguageDetect_Exception + */ + public function omitLanguages($omit_list, $include_only = false) + { + $deleted = 0; + + $omit_list = $this->_convertFromNameMode($omit_list); + + if (!$include_only) { + // deleting the given languages + if (!is_array($omit_list)) { + $omit_list = strtolower($omit_list); // case desensitize + if (isset($this->_lang_db[$omit_list])) { + unset($this->_lang_db[$omit_list]); + $deleted++; + } + } else { + foreach ($omit_list as $omit_lang) { + if (isset($this->_lang_db[$omit_lang])) { + unset($this->_lang_db[$omit_lang]); + $deleted++; + } + } + } + + } else { + // deleting all except the given languages + if (!is_array($omit_list)) { + $omit_list = array($omit_list); + } + + // case desensitize + foreach ($omit_list as $key => $omit_lang) { + $omit_list[$key] = strtolower($omit_lang); + } + + foreach (array_keys($this->_lang_db) as $lang) { + if (!in_array($lang, $omit_list)) { + unset($this->_lang_db[$lang]); + $deleted++; + } + } + } + + // reset the cluster cache if the number of languages changes + // this will then have to be recalculated + if (isset($this->_clusters) && $deleted > 0) { + $this->_clusters = null; + } + + return $deleted; + } + + + /** + * Returns the number of languages that this object can detect + * + * @access public + * @return int the number of languages + * @throws Text_LanguageDetect_Exception + */ + function getLanguageCount() + { + return count($this->_lang_db); + } + + /** + * Checks if the language with the given name exists in the database + * + * @param mixed $lang Language name or array of language names + * + * @return bool true if language model exists + */ + public function languageExists($lang) + { + $lang = $this->_convertFromNameMode($lang); + + if (is_string($lang)) { + return isset($this->_lang_db[strtolower($lang)]); + + } elseif (is_array($lang)) { + foreach ($lang as $test_lang) { + if (!isset($this->_lang_db[strtolower($test_lang)])) { + return false; + } + } + return true; + + } else { + throw new Text_LanguageDetect_Exception( + 'Unsupported parameter type passed to languageExists()', + Text_LanguageDetect_Exception::PARAM_TYPE + ); + } + } + + /** + * Returns the list of detectable languages + * + * @access public + * @return array the names of the languages known to this object<<<<<<< + * @throws Text_LanguageDetect_Exception + */ + function getLanguages() + { + return $this->_convertToNameMode( + array_keys($this->_lang_db) + ); + } + + /** + * Make this object behave like Language::Guess + * + * @param bool $setting false to turn off perl compatibility + * + * @return void + */ + public function setPerlCompatible($setting = true) + { + if (is_bool($setting)) { // input check + $this->_perl_compatible = $setting; + + if ($setting == true) { + $this->_max_score = $this->_threshold; + } else { + $this->_max_score = 0; + } + } + + } + + /** + * Sets the way how language names are accepted and returned. + * + * @param integer $name_mode One of the following modes: + * 0 - language name ("english") + * 2 - 2-letter ISO 639-1 code ("en") + * 3 - 3-letter ISO 639-2 code ("eng") + * + * @return void + */ + function setNameMode($name_mode) + { + $this->_name_mode = $name_mode; + } + + /** + * Whether to use unicode block ranges in detection + * + * Should speed up most detections if turned on (detault is on). In some + * circumstances it may be slower, such as for large text samples (> 10K) + * in languages that use latin scripts. In other cases it should speed up + * detection noticeably. + * + * @param bool $setting false to turn off + * + * @return void + */ + public function useUnicodeBlocks($setting = true) + { + if (is_bool($setting)) { + $this->_use_unicode_narrowing = $setting; + } + } + + /** + * Converts a piece of text into trigrams + * + * @param string $text text to convert + * + * @return array array of trigram frequencies + * @access private + * @deprecated Superceded by the Text_LanguageDetect_Parser class + */ + function _trigram($text) + { + $s = new Text_LanguageDetect_Parser($text); + $s->prepareTrigram(); + $s->prepareUnicode(false); + $s->setPadStart(!$this->_perl_compatible); + $s->analyze(); + return $s->getTrigramFreqs(); + } + + /** + * Converts a set of trigrams from frequencies to ranks + * + * Thresholds (cuts off) the list at $this->_threshold + * + * @param array $arr array of trigram + * + * @return array ranks of trigrams + * @access protected + */ + function _arr_rank($arr) + { + + // sorts alphabetically first as a standard way of breaking rank ties + $this->_bub_sort($arr); + + // below might also work, but seemed to introduce errors in testing + //ksort($arr); + //asort($arr); + + $rank = array(); + + $i = 0; + foreach ($arr as $key => $value) { + $rank[$key] = $i++; + + // cut off at a standard threshold + if ($i >= $this->_threshold) { + break; + } + } + + return $rank; + } + + /** + * Sorts an array by value breaking ties alphabetically + * + * @param array &$arr the array to sort + * + * @return void + * @access private + */ + function _bub_sort(&$arr) + { + // should do the same as this perl statement: + // sort { $trigrams{$b} == $trigrams{$a} + // ? $a cmp $b : $trigrams{$b} <=> $trigrams{$a} } + + // needs to sort by both key and value at once + // using the key to break ties for the value + + // converts array into an array of arrays of each key and value + // may be a better way of doing this + $combined = array(); + + foreach ($arr as $key => $value) { + $combined[] = array($key, $value); + } + + usort($combined, array($this, '_sort_func')); + + $replacement = array(); + foreach ($combined as $key => $value) { + list($new_key, $new_value) = $value; + $replacement[$new_key] = $new_value; + } + + $arr = $replacement; + } + + /** + * Sort function used by bubble sort + * + * Callback function for usort(). + * + * @param array $a first param passed by usort() + * @param array $b second param passed by usort() + * + * @return int 1 if $a is greater, -1 if not + * @see _bub_sort() + * @access private + */ + function _sort_func($a, $b) + { + // each is actually a key/value pair, so that it can compare using both + list($a_key, $a_value) = $a; + list($b_key, $b_value) = $b; + + if ($a_value == $b_value) { + // if the values are the same, break ties using the key + return strcmp($a_key, $b_key); + + } else { + // if not, just sort normally + if ($a_value > $b_value) { + return -1; + } else { + return 1; + } + } + + // 0 should not be possible because keys must be unique + } + + /** + * Calculates a linear rank-order distance statistic between two sets of + * ranked trigrams + * + * Sums the differences in rank for each trigram. If the trigram does not + * appear in both, consider it a difference of $this->_threshold. + * + * This distance measure was proposed by Cavnar & Trenkle (1994). Despite + * its simplicity it has been shown to be highly accurate for language + * identification tasks. + * + * @param array $arr1 the reference set of trigram ranks + * @param array $arr2 the target set of trigram ranks + * + * @return int the sum of the differences between the ranks of + * the two trigram sets + * @access private + */ + function _distance($arr1, $arr2) + { + $sumdist = 0; + + foreach ($arr2 as $key => $value) { + if (isset($arr1[$key])) { + $distance = abs($value - $arr1[$key]); + } else { + // $this->_threshold sets the maximum possible distance value + // for any one pair of trigrams + $distance = $this->_threshold; + } + $sumdist += $distance; + } + + return $sumdist; + + // todo: there are other distance statistics to try, e.g. relative + // entropy, but they're probably more costly to compute + } + + /** + * Normalizes the score returned by _distance() + * + * Different if perl compatible or not + * + * @param int $score the score from _distance() + * @param int $base_count the number of trigrams being considered + * + * @return float the normalized score + * @see _distance() + * @access private + */ + function _normalize_score($score, $base_count = null) + { + if ($base_count === null) { + $base_count = $this->_threshold; + } + + if (!$this->_perl_compatible) { + return 1 - ($score / $base_count / $this->_threshold); + } else { + return floor($score / $base_count); + } + } + + + /** + * Detects the closeness of a sample of text to the known languages + * + * Calculates the statistical difference between the text and + * the trigrams for each language, normalizes the score then + * returns results for all languages in sorted order + * + * If perl compatible, the score is 300-0, 0 being most similar. + * Otherwise, it's 0-1 with 1 being most similar. + * + * The $sample text should be at least a few sentences in length; + * should be ascii-7 or utf8 encoded, if another and the mbstring extension + * is present it will try to detect and convert. However, experience has + * shown that mb_detect_encoding() *does not work very well* with at least + * some types of encoding. + * + * @param string $sample a sample of text to compare. + * @param int $limit if specified, return an array of the most likely + * $limit languages and their scores. + * + * @return mixed sorted array of language scores, blank array if no + * useable text was found + * @see _distance() + * @throws Text_LanguageDetect_Exception + */ + public function detect($sample, $limit = 0) + { + // input check + if (!Text_LanguageDetect_Parser::validateString($sample)) { + return array(); + } + + // check char encoding + // (only if mbstring extension is compiled and PHP > 4.0.6) + if (function_exists('mb_detect_encoding') + && function_exists('mb_convert_encoding') + ) { + // mb_detect_encoding isn't very reliable, to say the least + // detection should still work with a sufficient sample + // of ascii characters + $encoding = mb_detect_encoding($sample); + + // mb_detect_encoding() will return FALSE if detection fails + // don't attempt conversion if that's the case + if ($encoding != 'ASCII' && $encoding != 'UTF-8' + && $encoding !== false + ) { + // verify the encoding exists in mb_list_encodings + if (in_array($encoding, mb_list_encodings())) { + $sample = mb_convert_encoding($sample, 'UTF-8', $encoding); + } + } + } + + $sample_obj = new Text_LanguageDetect_Parser($sample); + $sample_obj->prepareTrigram(); + if ($this->_use_unicode_narrowing) { + $sample_obj->prepareUnicode(); + } + $sample_obj->setPadStart(!$this->_perl_compatible); + $sample_obj->analyze(); + + $trigram_freqs =& $sample_obj->getTrigramRanks(); + $trigram_count = count($trigram_freqs); + + if ($trigram_count == 0) { + return array(); + } + + $scores = array(); + + // use unicode block detection to narrow down the possibilities + if ($this->_use_unicode_narrowing) { + $blocks =& $sample_obj->getUnicodeBlocks(); + + if (is_array($blocks)) { + $present_blocks = array_keys($blocks); + } else { + throw new Text_LanguageDetect_Exception( + 'Error during block detection', + Text_LanguageDetect_Exception::BLOCK_DETECTION + ); + } + + $possible_langs = array(); + + foreach ($present_blocks as $blockname) { + if (isset($this->_unicode_map[$blockname])) { + + $possible_langs = array_merge( + $possible_langs, + array_keys($this->_unicode_map[$blockname]) + ); + + // todo: faster way to do this? + } + } + + // could also try an intersect operation rather than a union + // in other words, choose languages whose trigrams contain + // ALL of the unicode blocks found in this sample + // would improve speed but would be completely thrown off by an + // unexpected character, like an umlaut appearing in english text + + $possible_langs = array_intersect( + array_keys($this->_lang_db), + array_unique($possible_langs) + ); + + // needs to intersect it with the keys of _lang_db in case + // languages have been omitted + + } else { + // or just try 'em all + $possible_langs = array_keys($this->_lang_db); + } + + + foreach ($possible_langs as $lang) { + $scores[$lang] = $this->_normalize_score( + $this->_distance($this->_lang_db[$lang], $trigram_freqs), + $trigram_count + ); + } + + unset($sample_obj); + + if ($this->_perl_compatible) { + asort($scores); + } else { + arsort($scores); + } + + // todo: drop languages with a score of $this->_max_score? + + // limit the number of returned scores + if ($limit && is_numeric($limit)) { + $limited_scores = array(); + + $i = 0; + foreach ($scores as $key => $value) { + if ($i++ >= $limit) { + break; + } + + $limited_scores[$key] = $value; + } + + return $this->_convertToNameMode($limited_scores, true); + } else { + return $this->_convertToNameMode($scores, true); + } + } + + /** + * Returns only the most similar language to the text sample + * + * Calls $this->detect() and returns only the top result + * + * @param string $sample text to detect the language of + * + * @return string the name of the most likely language + * or null if no language is similar + * @see detect() + * @throws Text_LanguageDetect_Exception + */ + public function detectSimple($sample) + { + $scores = $this->detect($sample, 1); + + // if top language has the maximum possible score, + // then the top score will have been picked at random + if (!is_array($scores) || empty($scores) + || current($scores) == $this->_max_score + ) { + return null; + } else { + return key($scores); + } + } + + /** + * Returns an array containing the most similar language and a confidence + * rating + * + * Confidence is a simple measure calculated from the similarity score + * minus the similarity score from the next most similar language + * divided by the highest possible score. Languages that have closely + * related cousins (e.g. Norwegian and Danish) should generally have lower + * confidence scores. + * + * The similarity score answers the question "How likely is the text the + * returned language regardless of the other languages considered?" The + * confidence score is one way of answering the question "how likely is the + * text the detected language relative to the rest of the language model + * set?" + * + * To see how similar languages are a priori, see languageSimilarity() + * + * @param string $sample text for which language will be detected + * + * @return array most similar language, score and confidence rating + * or null if no language is similar + * @see detect() + * @throws Text_LanguageDetect_Exception + */ + public function detectConfidence($sample) + { + $scores = $this->detect($sample, 2); + + // if most similar language has the max score, it + // will have been picked at random + if (!is_array($scores) || empty($scores) + || current($scores) == $this->_max_score + ) { + return null; + } + + $arr['language'] = key($scores); + $arr['similarity'] = current($scores); + if (next($scores) !== false) { // if false then no next element + // the goal is to return a higher value if the distance between + // the similarity of the first score and the second score is high + + if ($this->_perl_compatible) { + $arr['confidence'] = (current($scores) - $arr['similarity']) + / $this->_max_score; + + } else { + $arr['confidence'] = $arr['similarity'] - current($scores); + + } + + } else { + $arr['confidence'] = null; + } + + return $arr; + } + + /** + * Returns the distribution of unicode blocks in a given utf8 string + * + * For the block name of a single char, use unicodeBlockName() + * + * @param string $str input string. Must be ascii or utf8 + * @param bool $skip_symbols if true, skip ascii digits, symbols and + * non-printing characters. Includes spaces, + * newlines and common punctutation characters. + * + * @return array + * @throws Text_LanguageDetect_Exception + */ + public function detectUnicodeBlocks($str, $skip_symbols) + { + $skip_symbols = (bool)$skip_symbols; + $str = (string)$str; + + $sample_obj = new Text_LanguageDetect_Parser($str); + $sample_obj->prepareUnicode(); + $sample_obj->prepareTrigram(false); + $sample_obj->setUnicodeSkipSymbols($skip_symbols); + $sample_obj->analyze(); + $blocks = $sample_obj->getUnicodeBlocks(); + unset($sample_obj); + return $blocks; + } + + /** + * Returns the block name for a given unicode value + * + * If passed a string, will assume it is being passed a UTF8-formatted + * character and will automatically convert. Otherwise it will assume it + * is being passed a numeric unicode value. + * + * Make sure input is of the correct type! + * + * @param mixed $unicode unicode value or utf8 char + * + * @return mixed the block name string or false if not found + * @throws Text_LanguageDetect_Exception + */ + public function unicodeBlockName($unicode) + { + if (is_string($unicode)) { + // assume it is being passed a utf8 char, so convert it + if (self::utf8strlen($unicode) > 1) { + throw new Text_LanguageDetect_Exception( + 'Pass a single char only to this method', + Text_LanguageDetect_Exception::PARAM_TYPE + ); + } + $unicode = $this->_utf8char2unicode($unicode); + + } elseif (!is_int($unicode)) { + throw new Text_LanguageDetect_Exception( + 'Input must be of type string or int.', + Text_LanguageDetect_Exception::PARAM_TYPE + ); + } + + $blocks = $this->_read_unicode_block_db(); + + $result = $this->_unicode_block_name($unicode, $blocks); + + if ($result == -1) { + return false; + } else { + return $result[2]; + } + } + + /** + * Searches the unicode block database + * + * Returns the block name for a given unicode value. unicodeBlockName() is + * the public interface for this function, which does input checks which + * this function omits for speed. + * + * @param int $unicode the unicode value + * @param array $blocks the block database + * @param int $block_count the number of defined blocks in the database + * + * @return mixed Block name, -1 if it failed + * @see unicodeBlockName() + * @access protected + */ + function _unicode_block_name($unicode, $blocks, $block_count = -1) + { + // for a reference, see + // http://www.unicode.org/Public/UNIDATA/Blocks.txt + + // assume that ascii characters are the most common + // so try it first for efficiency + if ($unicode <= $blocks[0][1]) { + return $blocks[0]; + } + + // the optional $block_count param is for efficiency + // so we this function doesn't have to run count() every time + if ($block_count != -1) { + $high = $block_count - 1; + } else { + $high = count($blocks) - 1; + } + + $low = 1; // start with 1 because ascii was 0 + + // your average binary search algorithm + while ($low <= $high) { + $mid = floor(($low + $high) / 2); + + if ($unicode < $blocks[$mid][0]) { + // if it's lower than the lower bound + $high = $mid - 1; + + } elseif ($unicode > $blocks[$mid][1]) { + // if it's higher than the upper bound + $low = $mid + 1; + + } else { + // found it + return $blocks[$mid]; + } + } + + // failed to find the block + return -1; + + // todo: differentiate when it's out of range or when it falls + // into an unassigned range? + } + + /** + * Brings up the unicode block database + * + * @return array the database of unicode block definitions + * @throws Text_LanguageDetect_Exception + * @access protected + */ + function _read_unicode_block_db() + { + // since the unicode definitions are always going to be the same, + // might as well share the memory for the db with all other instances + // of this class + static $data; + + if (!isset($data)) { + $data = $this->_readdb($this->_unicode_db_filename); + } + + return $data; + } + + /** + * Calculate the similarities between the language models + * + * Use this function to see how similar languages are to each other. + * + * If passed 2 language names, will return just those languages compared. + * If passed 1 language name, will return that language compared to + * all others. + * If passed none, will return an array of every language model compared + * to every other one. + * + * @param string $lang1 the name of the first language to be compared + * @param string $lang2 the name of the second language to be compared + * + * @return array scores of every language compared + * or the score of just the provided languages + * or null if one of the supplied languages does not exist + * @throws Text_LanguageDetect_Exception + */ + public function languageSimilarity($lang1 = null, $lang2 = null) + { + $lang1 = $this->_convertFromNameMode($lang1); + $lang2 = $this->_convertFromNameMode($lang2); + if ($lang1 != null) { + $lang1 = strtolower($lang1); + + // check if language model exists + if (!isset($this->_lang_db[$lang1])) { + return null; + } + + if ($lang2 != null) { + if (!isset($this->_lang_db[$lang2])) { + // check if language model exists + return null; + } + + $lang2 = strtolower($lang2); + + // compare just these two languages + return $this->_normalize_score( + $this->_distance( + $this->_lang_db[$lang1], + $this->_lang_db[$lang2] + ) + ); + + } else { + // compare just $lang1 to all languages + $return_arr = array(); + foreach ($this->_lang_db as $key => $value) { + if ($key != $lang1) { + // don't compare a language to itself + $return_arr[$key] = $this->_normalize_score( + $this->_distance($this->_lang_db[$lang1], $value) + ); + } + } + asort($return_arr); + + return $return_arr; + } + + + } else { + // compare all languages to each other + $return_arr = array(); + foreach (array_keys($this->_lang_db) as $lang1) { + foreach (array_keys($this->_lang_db) as $lang2) { + // skip comparing languages to themselves + if ($lang1 != $lang2) { + + if (isset($return_arr[$lang2][$lang1])) { + // don't re-calculate what's already been done + $return_arr[$lang1][$lang2] + = $return_arr[$lang2][$lang1]; + + } else { + // calculate + $return_arr[$lang1][$lang2] + = $this->_normalize_score( + $this->_distance( + $this->_lang_db[$lang1], + $this->_lang_db[$lang2] + ) + ); + + } + } + } + } + return $return_arr; + } + } + + /** + * Cluster known languages according to languageSimilarity() + * + * WARNING: this method is EXPERIMENTAL. It is not recommended for common + * use, and it may disappear or its functionality may change in future + * releases without notice. + * + * Uses a nearest neighbor technique to generate the maximum possible + * number of dendograms from the similarity data. + * + * @access public + * @return array language cluster data + * @throws Text_LanguageDetect_Exception + * @see languageSimilarity() + * @deprecated this function will eventually be removed and placed into + * the model generation class + */ + function clusterLanguages() + { + // todo: set the maximum number of clusters + // return cached result, if any + if (isset($this->_clusters)) { + return $this->_clusters; + } + + $langs = array_keys($this->_lang_db); + + $arr = $this->languageSimilarity(); + + sort($langs); + + foreach ($langs as $lang) { + if (!isset($this->_lang_db[$lang])) { + throw new Text_LanguageDetect_Exception( + "missing $lang!", + Text_LanguageDetect_Exception::UNKNOWN_LANGUAGE + ); + } + } + + // http://www.psychstat.missouristate.edu/multibook/mlt04m.html + foreach ($langs as $old_key => $lang1) { + $langs[$lang1] = $lang1; + unset($langs[$old_key]); + } + + $result_data = $really_map = array(); + + $i = 0; + while (count($langs) > 2 && $i++ < 200) { + $highest_score = -1; + $highest_key1 = ''; + $highest_key2 = ''; + foreach ($langs as $lang1) { + foreach ($langs as $lang2) { + if ($lang1 != $lang2 + && $arr[$lang1][$lang2] > $highest_score + ) { + $highest_score = $arr[$lang1][$lang2]; + $highest_key1 = $lang1; + $highest_key2 = $lang2; + } + } + } + + if (!$highest_key1) { + // should not ever happen + throw new Text_LanguageDetect_Exception( + "no highest key? (step: $i)", + Text_LanguageDetect_Exception::NO_HIGHEST_KEY + ); + } + + if ($highest_score == 0) { + // languages are perfectly dissimilar + break; + } + + // $highest_key1 and $highest_key2 are most similar + $sum1 = array_sum($arr[$highest_key1]); + $sum2 = array_sum($arr[$highest_key2]); + + // use the score for the one that is most similar to the rest of + // the field as the score for the group + // todo: could try averaging or "centroid" method instead + // seems like that might make more sense + // actually nearest neighbor may be better for binary searching + + + // for "Complete Linkage"/"furthest neighbor" + // sign should be < + // for "Single Linkage"/"nearest neighbor" method + // should should be > + // results seem to be pretty much the same with either method + + // figure out which to delete and which to replace + if ($sum1 > $sum2) { + $replaceme = $highest_key1; + $deleteme = $highest_key2; + } else { + $replaceme = $highest_key2; + $deleteme = $highest_key1; + } + + $newkey = $replaceme . ':' . $deleteme; + + // $replaceme is most similar to remaining languages + // replace $replaceme with '$newkey', deleting $deleteme + + // keep a record of which fork is really which language + $really_lang = $replaceme; + while (isset($really_map[$really_lang])) { + $really_lang = $really_map[$really_lang]; + } + $really_map[$newkey] = $really_lang; + + + // replace the best fitting key, delete the other + foreach ($arr as $key1 => $arr2) { + foreach ($arr2 as $key2 => $value2) { + if ($key2 == $replaceme) { + $arr[$key1][$newkey] = $arr[$key1][$key2]; + unset($arr[$key1][$key2]); + // replacing $arr[$key1][$key2] with $arr[$key1][$newkey] + } + + if ($key1 == $replaceme) { + $arr[$newkey][$key2] = $arr[$key1][$key2]; + unset($arr[$key1][$key2]); + // replacing $arr[$key1][$key2] with $arr[$newkey][$key2] + } + + if ($key1 == $deleteme || $key2 == $deleteme) { + // deleting $arr[$key1][$key2] + unset($arr[$key1][$key2]); + } + } + } + + + unset($langs[$highest_key1]); + unset($langs[$highest_key2]); + $langs[$newkey] = $newkey; + + + // some of these may be overkill + $result_data[$newkey] = array( + 'newkey' => $newkey, + 'count' => $i, + 'diff' => abs($sum1 - $sum2), + 'score' => $highest_score, + 'bestfit' => $replaceme, + 'otherfit' => $deleteme, + 'really' => $really_lang, + ); + } + + $return_val = array( + 'open_forks' => $langs, + // the top level of clusters + // clusters that are mutually exclusive + // or specified by a specific maximum + + 'fork_data' => $result_data, + // data for each split + + 'name_map' => $really_map, + // which cluster is really which language + // using the nearest neighbor technique, the cluster + // inherits all of the properties of its most-similar member + // this keeps track + ); + + + // saves the result in the object + $this->_clusters = $return_val; + + return $return_val; + } + + + /** + * Perform an intelligent detection based on clusterLanguages() + * + * WARNING: this method is EXPERIMENTAL. It is not recommended for common + * use, and it may disappear or its functionality may change in future + * releases without notice. + * + * This compares the sample text to top the top level of clusters. If the + * sample is similar to the cluster it will drop down and compare it to the + * languages in the cluster, and so on until it hits a leaf node. + * + * this should find the language in considerably fewer compares + * (the equivalent of a binary search), however clusterLanguages() is costly + * and the loss of accuracy from this technique is significant. + * + * This method may need to be 'fuzzier' in order to become more accurate. + * + * This function could be more useful if the universe of possible languages + * was very large, however in such cases some method of Bayesian inference + * might be more helpful. + * + * @param string $str input string + * + * @return array language scores (only those compared) + * @throws Text_LanguageDetect_Exception + * @see clusterLanguages() + */ + public function clusteredSearch($str) + { + // input check + if (!Text_LanguageDetect_Parser::validateString($str)) { + return array(); + } + + // clusterLanguages() will return a cached result if possible + // so it's safe to call it every time + $result = $this->clusterLanguages(); + + $dendogram_start = $result['open_forks']; + $dendogram_data = $result['fork_data']; + $dendogram_alias = $result['name_map']; + + $sample_obj = new Text_LanguageDetect_Parser($str); + $sample_obj->prepareTrigram(); + $sample_obj->setPadStart(!$this->_perl_compatible); + $sample_obj->analyze(); + $sample_result = $sample_obj->getTrigramRanks(); + $sample_count = count($sample_result); + + // input check + if ($sample_count == 0) { + return array(); + } + + $i = 0; // counts the number of steps + + foreach ($dendogram_start as $lang) { + if (isset($dendogram_alias[$lang])) { + $lang_key = $dendogram_alias[$lang]; + } else { + $lang_key = $lang; + } + + $scores[$lang] = $this->_normalize_score( + $this->_distance($this->_lang_db[$lang_key], $sample_result), + $sample_count + ); + + $i++; + } + + if ($this->_perl_compatible) { + asort($scores); + } else { + arsort($scores); + } + + $top_score = current($scores); + $top_key = key($scores); + + // of starting forks, $top_key is the most similar to the sample + + $cur_key = $top_key; + while (isset($dendogram_data[$cur_key])) { + $lang1 = $dendogram_data[$cur_key]['bestfit']; + $lang2 = $dendogram_data[$cur_key]['otherfit']; + foreach (array($lang1, $lang2) as $lang) { + if (isset($dendogram_alias[$lang])) { + $lang_key = $dendogram_alias[$lang]; + } else { + $lang_key = $lang; + } + + $scores[$lang] = $this->_normalize_score( + $this->_distance($this->_lang_db[$lang_key], $sample_result), + $sample_count + ); + + //todo: does not need to do same comparison again + } + + $i++; + + if ($scores[$lang1] > $scores[$lang2]) { + $cur_key = $lang1; + $loser_key = $lang2; + } else { + $cur_key = $lang2; + $loser_key = $lang1; + } + + $diff = $scores[$cur_key] - $scores[$loser_key]; + + // $cur_key ({$dendogram_alias[$cur_key]}) wins + // over $loser_key ({$dendogram_alias[$loser_key]}) + // with a difference of $diff + } + + // found result in $i compares + + // rather than sorting the result, preserve it so that you can see + // which paths the algorithm decided to take along the tree + + // but sometimes the last item is only the second highest + if (($this->_perl_compatible && (end($scores) > prev($scores))) + || (!$this->_perl_compatible && (end($scores) < prev($scores))) + ) { + $real_last_score = current($scores); + $real_last_key = key($scores); + + // swaps the 2nd-to-last item for the last item + unset($scores[$real_last_key]); + $scores[$real_last_key] = $real_last_score; + } + + + if (!$this->_perl_compatible) { + $scores = array_reverse($scores, true); + // second param requires php > 4.0.3 + } + + return $scores; + } + + /** + * ut8-safe strlen() + * + * Returns the numbers of characters (not bytes) in a utf8 string + * + * @param string $str string to get the length of + * + * @return int number of chars + */ + public static function utf8strlen($str) + { + // utf8_decode() will convert unknown chars to '?', which is actually + // ideal for counting. + + return strlen(utf8_decode($str)); + + // idea stolen from dokuwiki + } + + /** + * Returns the unicode value of a utf8 char + * + * @param string $char a utf8 (possibly multi-byte) char + * + * @return int unicode value + * @access protected + * @link http://en.wikipedia.org/wiki/UTF-8 + */ + function _utf8char2unicode($char) + { + // strlen() here will actually get the binary length of a single char + switch (strlen($char)) { + case 1: + // normal ASCII-7 byte + // 0xxxxxxx --> 0xxxxxxx + return ord($char{0}); + + case 2: + // 2 byte unicode + // 110zzzzx 10xxxxxx --> 00000zzz zxxxxxxx + $z = (ord($char{0}) & 0x000001F) << 6; + $x = (ord($char{1}) & 0x0000003F); + return ($z | $x); + + case 3: + // 3 byte unicode + // 1110zzzz 10zxxxxx 10xxxxxx --> zzzzzxxx xxxxxxxx + $z = (ord($char{0}) & 0x0000000F) << 12; + $x1 = (ord($char{1}) & 0x0000003F) << 6; + $x2 = (ord($char{2}) & 0x0000003F); + return ($z | $x1 | $x2); + + case 4: + // 4 byte unicode + // 11110zzz 10zzxxxx 10xxxxxx 10xxxxxx --> + // 000zzzzz xxxxxxxx xxxxxxxx + $z1 = (ord($char{0}) & 0x00000007) << 18; + $z2 = (ord($char{1}) & 0x0000003F) << 12; + $x1 = (ord($char{2}) & 0x0000003F) << 6; + $x2 = (ord($char{3}) & 0x0000003F); + return ($z1 | $z2 | $x1 | $x2); + } + } + + /** + * utf8-safe fast character iterator + * + * Will get the next character starting from $counter, which will then be + * incremented. If a multi-byte char the bytes will be concatenated and + * $counter will be incremeted by the number of bytes in the char. + * + * @param string $str the string being iterated over + * @param int &$counter the iterator, will increment by reference + * @param bool $special_convert whether to do special conversions + * + * @return char the next (possibly multi-byte) char from $counter + * @access private + */ + static function _next_char($str, &$counter, $special_convert = false) + { + $char = $str{$counter++}; + $ord = ord($char); + + // for a description of the utf8 system see + // http://www.phpclasses.org/browse/file/5131.html + + // normal ascii one byte char + if ($ord <= 127) { + // special conversions needed for this package + // (that only apply to regular ascii characters) + // lower case, and convert all non-alphanumeric characters + // other than "'" to space + if ($special_convert && $char != ' ' && $char != "'") { + if ($ord >= 65 && $ord <= 90) { // A-Z + $char = chr($ord + 32); // lower case + } elseif ($ord < 97 || $ord > 122) { // NOT a-z + $char = ' '; // convert to space + } + } + + return $char; + + } elseif ($ord >> 5 == 6) { // two-byte char + // multi-byte chars + $nextchar = $str{$counter++}; // get next byte + + // lower-casing of non-ascii characters is still incomplete + + if ($special_convert) { + // lower case latin accented characters + if ($ord == 195) { + $nextord = ord($nextchar); + $nextord_adj = $nextord + 64; + // for a reference, see + // http://www.ramsch.org/martin/uni/fmi-hp/iso8859-1.html + + // À - Þ but not × + if ($nextord_adj >= 192 + && $nextord_adj <= 222 + && $nextord_adj != 215 + ) { + $nextchar = chr($nextord + 32); + } + + } elseif ($ord == 208) { + // lower case cyrillic alphabet + $nextord = ord($nextchar); + // if A - Pe + if ($nextord >= 144 && $nextord <= 159) { + // lower case + $nextchar = chr($nextord + 32); + + } elseif ($nextord >= 160 && $nextord <= 175) { + // if Er - Ya + // lower case + $char = chr(209); // == $ord++ + $nextchar = chr($nextord - 32); + } + } + } + + // tag on next byte + return $char . $nextchar; + } elseif ($ord >> 4 == 14) { // three-byte char + + // tag on next 2 bytes + return $char . $str{$counter++} . $str{$counter++}; + + } elseif ($ord >> 3 == 30) { // four-byte char + + // tag on next 3 bytes + return $char . $str{$counter++} . $str{$counter++} . $str{$counter++}; + + } else { + // error? + } + } + + /** + * Converts an $language input parameter from the configured mode + * to the language name that is used internally. + * + * Works for strings and arrays. + * + * @param string|array $lang A language description ("english"/"en"/"eng") + * @param boolean $convertKey If $lang is an array, setting $key + * converts the keys to the language name. + * + * @return string|array Language name + */ + function _convertFromNameMode($lang, $convertKey = false) + { + if ($this->_name_mode == 0) { + return $lang; + } + + if ($this->_name_mode == 2) { + $method = 'code2ToName'; + } else { + $method = 'code3ToName'; + } + + if (is_string($lang)) { + return (string)Text_LanguageDetect_ISO639::$method($lang); + } + + $newlang = array(); + foreach ($lang as $key => $val) { + if ($convertKey) { + $newkey = (string)Text_LanguageDetect_ISO639::$method($key); + $newlang[$newkey] = $val; + } else { + $newlang[$key] = (string)Text_LanguageDetect_ISO639::$method($val); + } + } + return $newlang; + } + + /** + * Converts an $language output parameter from the language name that is + * used internally to the configured mode. + * + * Works for strings and arrays. + * + * @param string|array $lang A language description ("english"/"en"/"eng") + * @param boolean $convertKey If $lang is an array, setting $key + * converts the keys to the language name. + * + * @return string|array Language name + */ + function _convertToNameMode($lang, $convertKey = false) + { + if ($this->_name_mode == 0) { + return $lang; + } + + if ($this->_name_mode == 2) { + $method = 'nameToCode2'; + } else { + $method = 'nameToCode3'; + } + + if (is_string($lang)) { + return Text_LanguageDetect_ISO639::$method($lang); + } + + $newlang = array(); + foreach ($lang as $key => $val) { + if ($convertKey) { + $newkey = Text_LanguageDetect_ISO639::$method($key); + $newlang[$newkey] = $val; + } else { + $newlang[$key] = Text_LanguageDetect_ISO639::$method($val); + } + } + return $newlang; + } +} + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +?> diff --git a/sources/library/langdet/Text/LanguageDetect/Exception.php b/sources/library/langdet/Text/LanguageDetect/Exception.php new file mode 100644 index 00000000..196d994f --- /dev/null +++ b/sources/library/langdet/Text/LanguageDetect/Exception.php @@ -0,0 +1,57 @@ + + * @copyright 2011 Christian Weiske + * @license http://www.debian.org/misc/bsd.license BSD + * @version SVN: $Id$ + * @link http://pear.php.net/package/Text_LanguageDetect/ + */ + +/** + * Provides a mapping between the languages from lang.dat and the + * ISO 639-1 and ISO-639-2 codes. + * + * Note that this class contains only languages that exist in lang.dat. + * + * @category Text + * @package Text_LanguageDetect + * @author Christian Weiske + * @copyright 2011 Christian Weiske + * @license http://www.debian.org/misc/bsd.license BSD + * @link http://www.loc.gov/standards/iso639-2/php/code_list.php + */ +class Text_LanguageDetect_ISO639 +{ + /** + * Maps all language names from the language database to the + * ISO 639-1 2-letter language code. + * + * NULL indicates that there is no 2-letter code. + * + * @var array + */ + public static $nameToCode2 = array( + 'albanian' => 'sq', + 'arabic' => 'ar', + 'azeri' => 'az', + 'bengali' => 'bn', + 'bulgarian' => 'bg', + 'cebuano' => null, + 'croatian' => 'hr', + 'czech' => 'cs', + 'danish' => 'da', + 'dutch' => 'nl', + 'english' => 'en', + 'estonian' => 'et', + 'farsi' => 'fa', + 'finnish' => 'fi', + 'french' => 'fr', + 'german' => 'de', + 'hausa' => 'ha', + 'hawaiian' => null, + 'hindi' => 'hi', + 'hungarian' => 'hu', + 'icelandic' => 'is', + 'indonesian' => 'id', + 'italian' => 'it', + 'kazakh' => 'kk', + 'kyrgyz' => 'ky', + 'latin' => 'la', + 'latvian' => 'lv', + 'lithuanian' => 'lt', + 'macedonian' => 'mk', + 'mongolian' => 'mn', + 'nepali' => 'ne', + 'norwegian' => 'no', + 'pashto' => 'ps', + 'pidgin' => null, + 'polish' => 'pl', + 'portuguese' => 'pt', + 'romanian' => 'ro', + 'russian' => 'ru', + 'serbian' => 'sr', + 'slovak' => 'sk', + 'slovene' => 'sl', + 'somali' => 'so', + 'spanish' => 'es', + 'swahili' => 'sw', + 'swedish' => 'sv', + 'tagalog' => 'tl', + 'turkish' => 'tr', + 'ukrainian' => 'uk', + 'urdu' => 'ur', + 'uzbek' => 'uz', + 'vietnamese' => 'vi', + 'welsh' => 'cy', + ); + + /** + * Maps all language names from the language database to the + * ISO 639-2 3-letter language code. + * + * @var array + */ + public static $nameToCode3 = array( + 'albanian' => 'sqi', + 'arabic' => 'ara', + 'azeri' => 'aze', + 'bengali' => 'ben', + 'bulgarian' => 'bul', + 'cebuano' => 'ceb', + 'croatian' => 'hrv', + 'czech' => 'ces', + 'danish' => 'dan', + 'dutch' => 'nld', + 'english' => 'eng', + 'estonian' => 'est', + 'farsi' => 'fas', + 'finnish' => 'fin', + 'french' => 'fra', + 'german' => 'deu', + 'hausa' => 'hau', + 'hawaiian' => 'haw', + 'hindi' => 'hin', + 'hungarian' => 'hun', + 'icelandic' => 'isl', + 'indonesian' => 'ind', + 'italian' => 'ita', + 'kazakh' => 'kaz', + 'kyrgyz' => 'kir', + 'latin' => 'lat', + 'latvian' => 'lav', + 'lithuanian' => 'lit', + 'macedonian' => 'mkd', + 'mongolian' => 'mon', + 'nepali' => 'nep', + 'norwegian' => 'nor', + 'pashto' => 'pus', + 'pidgin' => 'crp', + 'polish' => 'pol', + 'portuguese' => 'por', + 'romanian' => 'ron', + 'russian' => 'rus', + 'serbian' => 'srp', + 'slovak' => 'slk', + 'slovene' => 'slv', + 'somali' => 'som', + 'spanish' => 'spa', + 'swahili' => 'swa', + 'swedish' => 'swe', + 'tagalog' => 'tgl', + 'turkish' => 'tur', + 'ukrainian' => 'ukr', + 'urdu' => 'urd', + 'uzbek' => 'uzb', + 'vietnamese' => 'vie', + 'welsh' => 'cym', + ); + + /** + * Maps ISO 639-1 2-letter language codes to the language names + * in the language database + * + * Not all languages have a 2 letter code, so some are missing + * + * @var array + */ + public static $code2ToName = array( + 'ar' => 'arabic', + 'az' => 'azeri', + 'bg' => 'bulgarian', + 'bn' => 'bengali', + 'cs' => 'czech', + 'cy' => 'welsh', + 'da' => 'danish', + 'de' => 'german', + 'en' => 'english', + 'es' => 'spanish', + 'et' => 'estonian', + 'fa' => 'farsi', + 'fi' => 'finnish', + 'fr' => 'french', + 'ha' => 'hausa', + 'hi' => 'hindi', + 'hr' => 'croatian', + 'hu' => 'hungarian', + 'id' => 'indonesian', + 'is' => 'icelandic', + 'it' => 'italian', + 'kk' => 'kazakh', + 'ky' => 'kyrgyz', + 'la' => 'latin', + 'lt' => 'lithuanian', + 'lv' => 'latvian', + 'mk' => 'macedonian', + 'mn' => 'mongolian', + 'ne' => 'nepali', + 'nl' => 'dutch', + 'no' => 'norwegian', + 'pl' => 'polish', + 'ps' => 'pashto', + 'pt' => 'portuguese', + 'ro' => 'romanian', + 'ru' => 'russian', + 'sk' => 'slovak', + 'sl' => 'slovene', + 'so' => 'somali', + 'sq' => 'albanian', + 'sr' => 'serbian', + 'sv' => 'swedish', + 'sw' => 'swahili', + 'tl' => 'tagalog', + 'tr' => 'turkish', + 'uk' => 'ukrainian', + 'ur' => 'urdu', + 'uz' => 'uzbek', + 'vi' => 'vietnamese', + ); + + /** + * Maps ISO 639-2 3-letter language codes to the language names + * in the language database. + * + * @var array + */ + public static $code3ToName = array( + 'ara' => 'arabic', + 'aze' => 'azeri', + 'ben' => 'bengali', + 'bul' => 'bulgarian', + 'ceb' => 'cebuano', + 'ces' => 'czech', + 'crp' => 'pidgin', + 'cym' => 'welsh', + 'dan' => 'danish', + 'deu' => 'german', + 'eng' => 'english', + 'est' => 'estonian', + 'fas' => 'farsi', + 'fin' => 'finnish', + 'fra' => 'french', + 'hau' => 'hausa', + 'haw' => 'hawaiian', + 'hin' => 'hindi', + 'hrv' => 'croatian', + 'hun' => 'hungarian', + 'ind' => 'indonesian', + 'isl' => 'icelandic', + 'ita' => 'italian', + 'kaz' => 'kazakh', + 'kir' => 'kyrgyz', + 'lat' => 'latin', + 'lav' => 'latvian', + 'lit' => 'lithuanian', + 'mkd' => 'macedonian', + 'mon' => 'mongolian', + 'nep' => 'nepali', + 'nld' => 'dutch', + 'nor' => 'norwegian', + 'pol' => 'polish', + 'por' => 'portuguese', + 'pus' => 'pashto', + 'rom' => 'romanian', + 'rus' => 'russian', + 'slk' => 'slovak', + 'slv' => 'slovene', + 'som' => 'somali', + 'spa' => 'spanish', + 'sqi' => 'albanian', + 'srp' => 'serbian', + 'swa' => 'swahili', + 'swe' => 'swedish', + 'tgl' => 'tagalog', + 'tur' => 'turkish', + 'ukr' => 'ukrainian', + 'urd' => 'urdu', + 'uzb' => 'uzbek', + 'vie' => 'vietnamese', + ); + + /** + * Returns the 2-letter ISO 639-1 code for the given language name. + * + * @param string $lang English language name like "swedish" + * + * @return string Two-letter language code (e.g. "sv") or NULL if not found + */ + public static function nameToCode2($lang) + { + $lang = strtolower($lang); + if (!isset(self::$nameToCode2[$lang])) { + return null; + } + return self::$nameToCode2[$lang]; + } + + /** + * Returns the 3-letter ISO 639-2 code for the given language name. + * + * @param string $lang English language name like "swedish" + * + * @return string Three-letter language code (e.g. "swe") or NULL if not found + */ + public static function nameToCode3($lang) + { + $lang = strtolower($lang); + if (!isset(self::$nameToCode3[$lang])) { + return null; + } + return self::$nameToCode3[$lang]; + } + + /** + * Returns the language name for the given 2-letter ISO 639-1 code. + * + * @param string $code Two-letter language code (e.g. "sv") + * + * @return string English language name like "swedish" + */ + public static function code2ToName($code) + { + $lang = strtolower($code); + if (!isset(self::$code2ToName[$code])) { + return null; + } + return self::$code2ToName[$code]; + } + + /** + * Returns the language name for the given 3-letter ISO 639-2 code. + * + * @param string $code Three-letter language code (e.g. "swe") + * + * @return string English language name like "swedish" + */ + public static function code3ToName($code) + { + $lang = strtolower($code); + if (!isset(self::$code3ToName[$code])) { + return null; + } + return self::$code3ToName[$code]; + } +} + +?> \ No newline at end of file diff --git a/sources/library/langdet/Text/LanguageDetect/Parser.php b/sources/library/langdet/Text/LanguageDetect/Parser.php new file mode 100644 index 00000000..1c20c265 --- /dev/null +++ b/sources/library/langdet/Text/LanguageDetect/Parser.php @@ -0,0 +1,349 @@ +_string = $string; + } + + /** + * Returns true if a string is suitable for parsing + * + * @param string $str input string to test + * @return bool true if acceptable, false if not + */ + public static function validateString($str) { + if (!empty($str) && strlen($str) > 3 && preg_match('/\S/', $str)) { + return true; + } else { + return false; + } + } + + /** + * turn on/off trigram counting + * + * @access public + * @param bool $bool true for on, false for off + */ + function prepareTrigram($bool = true) + { + $this->_compile_trigram = $bool; + } + + /** + * turn on/off unicode block counting + * + * @access public + * @param bool $bool true for on, false for off + */ + function prepareUnicode($bool = true) + { + $this->_compile_unicode = $bool; + } + + /** + * turn on/off padding the beginning of the sample string + * + * @access public + * @param bool $bool true for on, false for off + */ + function setPadStart($bool = true) + { + $this->_trigram_pad_start = $bool; + } + + /** + * Should the unicode block counter skip non-alphabetical ascii chars? + * + * @access public + * @param bool $bool true for on, false for off + */ + function setUnicodeSkipSymbols($bool = true) + { + $this->_unicode_skip_symbols = $bool; + } + + /** + * Returns the trigram ranks for the text sample + * + * @access public + * @return array trigram ranks in the text sample + */ + function &getTrigramRanks() + { + return $this->_trigram_ranks; + } + + /** + * Return the trigram freqency table + * + * only used in testing to make sure the parser is working + * + * @access public + * @return array trigram freqencies in the text sample + */ + function &getTrigramFreqs() + { + return $this->_trigram; + } + + /** + * returns the array of unicode blocks + * + * @access public + * @return array unicode blocks in the text sample + */ + function &getUnicodeBlocks() + { + return $this->_unicode_blocks; + } + + /** + * Executes the parsing operation + * + * Be sure to call the set*() functions to set options and the + * prepare*() functions first to tell it what kind of data to compute + * + * Afterwards the get*() functions can be used to access the compiled + * information. + * + * @access public + */ + function analyze() + { + $len = strlen($this->_string); + $byte_counter = 0; + + + // unicode startup + if ($this->_compile_unicode) { + $blocks = $this->_read_unicode_block_db(); + $block_count = count($blocks); + + $skipped_count = 0; + $unicode_chars = array(); + } + + // trigram startup + if ($this->_compile_trigram) { + // initialize them as blank so the parser will skip the first two + // (since it skips trigrams with more than 2 contiguous spaces) + $a = ' '; + $b = ' '; + + // kludge + // if it finds a valid trigram to start and the start pad option is + // off, then set a variable that will be used to reduce this + // trigram after parsing has finished + if (!$this->_trigram_pad_start) { + $a = $this->_next_char($this->_string, $byte_counter, true); + + if ($a != ' ') { + $b = $this->_next_char($this->_string, $byte_counter, true); + $dropone = " $a$b"; + } + + $byte_counter = 0; + $a = ' '; + $b = ' '; + } + } + + while ($byte_counter < $len) { + $char = $this->_next_char($this->_string, $byte_counter, true); + + + // language trigram detection + if ($this->_compile_trigram) { + if (!($b == ' ' && ($a == ' ' || $char == ' '))) { + if (!isset($this->_trigram[$a . $b . $char])) { + $this->_trigram[$a . $b . $char] = 1; + } else { + $this->_trigram[$a . $b . $char]++; + } + } + + $a = $b; + $b = $char; + } + + // unicode block detection + if ($this->_compile_unicode) { + if ($this->_unicode_skip_symbols + && strlen($char) == 1 + && ($char < 'A' || $char > 'z' + || ($char > 'Z' && $char < 'a')) + && $char != "'") { // does not skip the apostrophe + // since it's included in the language + // models + + $skipped_count++; + continue; + } + + // build an array of all the characters + if (isset($unicode_chars[$char])) { + $unicode_chars[$char]++; + } else { + $unicode_chars[$char] = 1; + } + } + + // todo: add byte detection here + } + + // unicode cleanup + if ($this->_compile_unicode) { + foreach ($unicode_chars as $utf8_char => $count) { + $search_result = $this->_unicode_block_name( + $this->_utf8char2unicode($utf8_char), $blocks, $block_count); + + if ($search_result != -1) { + $block_name = $search_result[2]; + } else { + $block_name = '[Malformatted]'; + } + + if (isset($this->_unicode_blocks[$block_name])) { + $this->_unicode_blocks[$block_name] += $count; + } else { + $this->_unicode_blocks[$block_name] = $count; + } + } + } + + + // trigram cleanup + if ($this->_compile_trigram) { + // pad the end + if ($b != ' ') { + if (!isset($this->_trigram["$a$b "])) { + $this->_trigram["$a$b "] = 1; + } else { + $this->_trigram["$a$b "]++; + } + } + + // perl compatibility; Language::Guess does not pad the beginning + // kludge + if (isset($dropone)) { + if ($this->_trigram[$dropone] == 1) { + unset($this->_trigram[$dropone]); + } else { + $this->_trigram[$dropone]--; + } + } + + if (!empty($this->_trigram)) { + $this->_trigram_ranks = $this->_arr_rank($this->_trigram); + } else { + $this->_trigram_ranks = array(); + } + } + } +} + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +?> diff --git a/sources/library/langdet/data/lang.dat b/sources/library/langdet/data/lang.dat new file mode 100644 index 00000000..c2a44f56 --- /dev/null +++ b/sources/library/langdet/data/lang.dat @@ -0,0 +1 @@ +a:2:{s:7:"trigram";a:52:{s:8:"albanian";a:300:{s:4:"të ";s:1:"0";s:4:" të";s:1:"1";s:4:"në ";s:1:"2";s:4:"për";s:1:"3";s:4:" pë";s:1:"4";s:3:" e ";s:1:"5";s:3:"sht";s:1:"6";s:4:" në";s:1:"7";s:3:" sh";s:1:"8";s:3:"se ";s:1:"9";s:3:"et ";s:2:"10";s:4:"ë s";s:2:"11";s:4:"ë t";s:2:"12";s:3:" se";s:2:"13";s:3:"he ";s:2:"14";s:4:"jë ";s:2:"15";s:4:"ër ";s:2:"16";s:3:"dhe";s:2:"17";s:3:" pa";s:2:"18";s:4:"ë n";s:2:"19";s:4:"ë p";s:2:"20";s:4:" që";s:2:"21";s:3:" dh";s:2:"22";s:4:"një";s:2:"23";s:4:"ë m";s:2:"24";s:3:" nj";s:2:"25";s:4:"ësh";s:2:"26";s:3:"in ";s:2:"27";s:3:" me";s:2:"28";s:4:"që ";s:2:"29";s:3:" po";s:2:"30";s:3:"e n";s:2:"31";s:3:"e t";s:2:"32";s:3:"ish";s:2:"33";s:4:"më ";s:2:"34";s:4:"së ";s:2:"35";s:3:"me ";s:2:"36";s:4:"htë";s:2:"37";s:3:" ka";s:2:"38";s:3:" si";s:2:"39";s:3:"e k";s:2:"40";s:3:"e p";s:2:"41";s:3:" i ";s:2:"42";s:4:"anë";s:2:"43";s:3:"ar ";s:2:"44";s:3:" nu";s:2:"45";s:3:"und";s:2:"46";s:3:"ve ";s:2:"47";s:4:" ës";s:2:"48";s:3:"e s";s:2:"49";s:4:" më";s:2:"50";s:3:"nuk";s:2:"51";s:3:"par";s:2:"52";s:3:"uar";s:2:"53";s:3:"uk ";s:2:"54";s:3:"jo ";s:2:"55";s:4:"rë ";s:2:"56";s:3:"ta ";s:2:"57";s:4:"ë f";s:2:"58";s:3:"en ";s:2:"59";s:3:"it ";s:2:"60";s:3:"min";s:2:"61";s:3:"het";s:2:"62";s:3:"n e";s:2:"63";s:3:"ri ";s:2:"64";s:3:"shq";s:2:"65";s:4:"ë d";s:2:"66";s:3:" do";s:2:"67";s:3:" nd";s:2:"68";s:3:"sh ";s:2:"69";s:4:"ën ";s:2:"70";s:4:"atë";s:2:"71";s:3:"hqi";s:2:"72";s:3:"ist";s:2:"73";s:4:"ë q";s:2:"74";s:3:" gj";s:2:"75";s:3:" ng";s:2:"76";s:3:" th";s:2:"77";s:3:"a n";s:2:"78";s:3:"do ";s:2:"79";s:3:"end";s:2:"80";s:3:"imi";s:2:"81";s:3:"ndi";s:2:"82";s:3:"r t";s:2:"83";s:3:"rat";s:2:"84";s:4:"ë b";s:2:"85";s:4:"ëri";s:2:"86";s:3:" mu";s:2:"87";s:3:"art";s:2:"88";s:3:"ash";s:2:"89";s:3:"qip";s:2:"90";s:3:" ko";s:2:"91";s:3:"e m";s:2:"92";s:3:"edh";s:2:"93";s:3:"eri";s:2:"94";s:3:"je ";s:2:"95";s:3:"ka ";s:2:"96";s:3:"nga";s:2:"97";s:3:"si ";s:2:"98";s:3:"te ";s:2:"99";s:4:"ë k";s:3:"100";s:4:"ësi";s:3:"101";s:3:" ma";s:3:"102";s:3:" ti";s:3:"103";s:3:"eve";s:3:"104";s:3:"hje";s:3:"105";s:3:"ira";s:3:"106";s:3:"mun";s:3:"107";s:3:"on ";s:3:"108";s:3:"po ";s:3:"109";s:3:"re ";s:3:"110";s:3:" pr";s:3:"111";s:3:"im ";s:3:"112";s:3:"lit";s:3:"113";s:3:"o t";s:3:"114";s:3:"ur ";s:3:"115";s:4:"ë e";s:3:"116";s:4:"ë v";s:3:"117";s:4:"ët ";s:3:"118";s:3:" ku";s:3:"119";s:4:" së";s:3:"120";s:3:"e d";s:3:"121";s:3:"es ";s:3:"122";s:3:"ga ";s:3:"123";s:3:"iti";s:3:"124";s:3:"jet";s:3:"125";s:4:"ndë";s:3:"126";s:3:"oli";s:3:"127";s:3:"shi";s:3:"128";s:3:"tje";s:3:"129";s:4:" bë";s:3:"130";s:3:" z ";s:3:"131";s:3:"gje";s:3:"132";s:3:"kan";s:3:"133";s:3:"shk";s:3:"134";s:4:"ënd";s:3:"135";s:4:"ës ";s:3:"136";s:3:" de";s:3:"137";s:3:" kj";s:3:"138";s:3:" ru";s:3:"139";s:3:" vi";s:3:"140";s:3:"ara";s:3:"141";s:3:"gov";s:3:"142";s:3:"kjo";s:3:"143";s:3:"or ";s:3:"144";s:3:"r p";s:3:"145";s:3:"rto";s:3:"146";s:3:"rug";s:3:"147";s:3:"tet";s:3:"148";s:3:"ugo";s:3:"149";s:3:"ali";s:3:"150";s:3:"arr";s:3:"151";s:3:"at ";s:3:"152";s:3:"d t";s:3:"153";s:3:"ht ";s:3:"154";s:3:"i p";s:3:"155";s:4:"ipë";s:3:"156";s:3:"izi";s:3:"157";s:4:"jnë";s:3:"158";s:3:"n n";s:3:"159";s:3:"ohe";s:3:"160";s:3:"shu";s:3:"161";s:4:"shë";s:3:"162";s:3:"t e";s:3:"163";s:3:"tik";s:3:"164";s:3:"a e";s:3:"165";s:4:"arë";s:3:"166";s:4:"etë";s:3:"167";s:3:"hum";s:3:"168";s:3:"nd ";s:3:"169";s:3:"ndr";s:3:"170";s:3:"osh";s:3:"171";s:3:"ova";s:3:"172";s:3:"rim";s:3:"173";s:3:"tos";s:3:"174";s:3:"va ";s:3:"175";s:3:" fa";s:3:"176";s:3:" fi";s:3:"177";s:3:"a s";s:3:"178";s:3:"hen";s:3:"179";s:3:"i n";s:3:"180";s:3:"mar";s:3:"181";s:3:"ndo";s:3:"182";s:3:"por";s:3:"183";s:3:"ris";s:3:"184";s:3:"sa ";s:3:"185";s:3:"sis";s:3:"186";s:4:"tës";s:3:"187";s:4:"umë";s:3:"188";s:3:"viz";s:3:"189";s:3:"zit";s:3:"190";s:3:" di";s:3:"191";s:3:" mb";s:3:"192";s:3:"aj ";s:3:"193";s:3:"ana";s:3:"194";s:3:"ata";s:3:"195";s:4:"dër";s:3:"196";s:3:"e a";s:3:"197";s:3:"esh";s:3:"198";s:3:"ime";s:3:"199";s:3:"jes";s:3:"200";s:3:"lar";s:3:"201";s:3:"n s";s:3:"202";s:3:"nte";s:3:"203";s:3:"pol";s:3:"204";s:3:"r n";s:3:"205";s:3:"ran";s:3:"206";s:3:"res";s:3:"207";s:4:"rrë";s:3:"208";s:3:"tar";s:3:"209";s:4:"ë a";s:3:"210";s:4:"ë i";s:3:"211";s:3:" at";s:3:"212";s:3:" jo";s:3:"213";s:4:" kë";s:3:"214";s:3:" re";s:3:"215";s:3:"a k";s:3:"216";s:3:"ai ";s:3:"217";s:3:"akt";s:3:"218";s:4:"hë ";s:3:"219";s:4:"hën";s:3:"220";s:3:"i i";s:3:"221";s:3:"i m";s:3:"222";s:3:"ia ";s:3:"223";s:3:"men";s:3:"224";s:3:"nis";s:3:"225";s:3:"shm";s:3:"226";s:3:"str";s:3:"227";s:3:"t k";s:3:"228";s:3:"t n";s:3:"229";s:3:"t s";s:3:"230";s:4:"ë g";s:3:"231";s:4:"ërk";s:3:"232";s:4:"ëve";s:3:"233";s:3:" ai";s:3:"234";s:3:" ci";s:3:"235";s:3:" ed";s:3:"236";s:3:" ja";s:3:"237";s:3:" kr";s:3:"238";s:3:" qe";s:3:"239";s:3:" ta";s:3:"240";s:3:" ve";s:3:"241";s:3:"a p";s:3:"242";s:3:"cil";s:3:"243";s:3:"el ";s:3:"244";s:4:"erë";s:3:"245";s:3:"gji";s:3:"246";s:3:"hte";s:3:"247";s:3:"i t";s:3:"248";s:3:"jen";s:3:"249";s:3:"jit";s:3:"250";s:3:"k d";s:3:"251";s:4:"mën";s:3:"252";s:3:"n t";s:3:"253";s:3:"nyr";s:3:"254";s:3:"ori";s:3:"255";s:3:"pas";s:3:"256";s:3:"ra ";s:3:"257";s:3:"rie";s:3:"258";s:4:"rës";s:3:"259";s:3:"tor";s:3:"260";s:3:"uaj";s:3:"261";s:3:"yre";s:3:"262";s:4:"ëm ";s:3:"263";s:4:"ëny";s:3:"264";s:3:" ar";s:3:"265";s:3:" du";s:3:"266";s:3:" ga";s:3:"267";s:3:" je";s:3:"268";s:4:"dës";s:3:"269";s:3:"e e";s:3:"270";s:3:"e z";s:3:"271";s:3:"ha ";s:3:"272";s:3:"hme";s:3:"273";s:3:"ika";s:3:"274";s:3:"ini";s:3:"275";s:3:"ite";s:3:"276";s:3:"ith";s:3:"277";s:3:"koh";s:3:"278";s:3:"kra";s:3:"279";s:3:"ku ";s:3:"280";s:3:"lim";s:3:"281";s:3:"lis";s:3:"282";s:4:"qën";s:3:"283";s:4:"rën";s:3:"284";s:3:"s s";s:3:"285";s:3:"t d";s:3:"286";s:3:"t t";s:3:"287";s:3:"tir";s:3:"288";s:4:"tën";s:3:"289";s:3:"ver";s:3:"290";s:4:"ë j";s:3:"291";s:3:" ba";s:3:"292";s:3:" in";s:3:"293";s:3:" tr";s:3:"294";s:3:" zg";s:3:"295";s:3:"a a";s:3:"296";s:3:"a m";s:3:"297";s:3:"a t";s:3:"298";s:3:"abr";s:3:"299";}s:6:"arabic";a:300:{s:5:" ال";s:1:"0";s:6:"الع";s:1:"1";s:6:"لعر";s:1:"2";s:6:"عرا";s:1:"3";s:6:"راق";s:1:"4";s:5:" ÙÙŠ";s:1:"5";s:5:"ÙÙŠ ";s:1:"6";s:5:"ين ";s:1:"7";s:5:"ية ";s:1:"8";s:5:"Ù† ا";s:1:"9";s:6:"الم";s:2:"10";s:5:"ات ";s:2:"11";s:5:"من ";s:2:"12";s:5:"ÙŠ ا";s:2:"13";s:5:" من";s:2:"14";s:6:"الأ";s:2:"15";s:5:"Ø© ا";s:2:"16";s:5:"اق ";s:2:"17";s:5:" وا";s:2:"18";s:5:"اء ";s:2:"19";s:6:"الإ";s:2:"20";s:5:" أن";s:2:"21";s:6:"وال";s:2:"22";s:5:"ما ";s:2:"23";s:5:" عل";s:2:"24";s:5:"لى ";s:2:"25";s:5:"ت ا";s:2:"26";s:5:"ون ";s:2:"27";s:5:"هم ";s:2:"28";s:6:"اقي";s:2:"29";s:5:"ام ";s:2:"30";s:5:"Ù„ ا";s:2:"31";s:5:"أن ";s:2:"32";s:5:"Ù… ا";s:2:"33";s:6:"الت";s:2:"34";s:5:"لا ";s:2:"35";s:6:"الا";s:2:"36";s:5:"ان ";s:2:"37";s:5:"ها ";s:2:"38";s:5:"ال ";s:2:"39";s:5:"Ø© Ùˆ";s:2:"40";s:5:"ا ا";s:2:"41";s:6:"رها";s:2:"42";s:6:"لام";s:2:"43";s:6:"يين";s:2:"44";s:5:" ول";s:2:"45";s:6:"لأم";s:2:"46";s:5:"نا ";s:2:"47";s:6:"على";s:2:"48";s:5:"Ù† ÙŠ";s:2:"49";s:6:"الب";s:2:"50";s:5:"اد ";s:2:"51";s:6:"الق";s:2:"52";s:5:"د ا";s:2:"53";s:5:"ذا ";s:2:"54";s:5:"Ù‡ ا";s:2:"55";s:5:" با";s:2:"56";s:6:"الد";s:2:"57";s:5:"ب ا";s:2:"58";s:6:"مري";s:2:"59";s:5:"لم ";s:2:"60";s:5:" إن";s:2:"61";s:5:" لل";s:2:"62";s:6:"سلا";s:2:"63";s:6:"أمر";s:2:"64";s:6:"ريك";s:2:"65";s:5:"مة ";s:2:"66";s:5:"Ù‰ ا";s:2:"67";s:5:"ا ÙŠ";s:2:"68";s:5:" عن";s:2:"69";s:5:" هذ";s:2:"70";s:5:"Ø¡ ا";s:2:"71";s:5:"ر ا";s:2:"72";s:6:"كان";s:2:"73";s:6:"قتل";s:2:"74";s:6:"إسل";s:2:"75";s:6:"الح";s:2:"76";s:5:"وا ";s:2:"77";s:5:" إل";s:2:"78";s:5:"ا Ø£";s:2:"79";s:6:"بال";s:2:"80";s:5:"Ù† Ù…";s:2:"81";s:6:"الس";s:2:"82";s:5:"رة ";s:2:"83";s:6:"لإس";s:2:"84";s:5:"Ù† Ùˆ";s:2:"85";s:6:"هاب";s:2:"86";s:5:"ÙŠ Ùˆ";s:2:"87";s:5:"ير ";s:2:"88";s:5:" كا";s:2:"89";s:5:"لة ";s:2:"90";s:6:"يات";s:2:"91";s:5:" لا";s:2:"92";s:6:"انت";s:2:"93";s:5:"Ù† Ø£";s:2:"94";s:6:"يكي";s:2:"95";s:6:"الر";s:2:"96";s:6:"الو";s:2:"97";s:5:"Ø© Ù";s:2:"98";s:5:"دة ";s:2:"99";s:6:"الج";s:3:"100";s:5:"قي ";s:3:"101";s:5:"وي ";s:3:"102";s:6:"الذ";s:3:"103";s:6:"الش";s:3:"104";s:6:"امي";s:3:"105";s:6:"اني";s:3:"106";s:5:"ذه ";s:3:"107";s:5:"عن ";s:3:"108";s:6:"لما";s:3:"109";s:6:"هذه";s:3:"110";s:5:"ول ";s:3:"111";s:5:"ا٠";s:3:"112";s:6:"اوي";s:3:"113";s:6:"بري";s:3:"114";s:5:"Ø© Ù„";s:3:"115";s:5:" أم";s:3:"116";s:5:" لم";s:3:"117";s:5:" ما";s:3:"118";s:5:"يد ";s:3:"119";s:5:" أي";s:3:"120";s:6:"إره";s:3:"121";s:5:"ع ا";s:3:"122";s:6:"عمل";s:3:"123";s:6:"ولا";s:3:"124";s:6:"إلى";s:3:"125";s:6:"ابي";s:3:"126";s:5:"Ù† Ù";s:3:"127";s:6:"ختط";s:3:"128";s:5:"لك ";s:3:"129";s:5:"نه ";s:3:"130";s:5:"ني ";s:3:"131";s:5:"إن ";s:3:"132";s:6:"دين";s:3:"133";s:5:"٠ا";s:3:"134";s:6:"لذي";s:3:"135";s:5:"ÙŠ Ø£";s:3:"136";s:5:"ÙŠ ب";s:3:"137";s:5:" وأ";s:3:"138";s:5:"ا ع";s:3:"139";s:6:"الخ";s:3:"140";s:5:"تل ";s:3:"141";s:5:"تي ";s:3:"142";s:5:"قد ";s:3:"143";s:6:"لدي";s:3:"144";s:5:" كل";s:3:"145";s:5:" مع";s:3:"146";s:5:"اب ";s:3:"147";s:6:"اخت";s:3:"148";s:5:"ار ";s:3:"149";s:6:"الن";s:3:"150";s:6:"علا";s:3:"151";s:5:"Ù… Ùˆ";s:3:"152";s:5:"مع ";s:3:"153";s:5:"س ا";s:3:"154";s:5:"كل ";s:3:"155";s:6:"لاء";s:3:"156";s:5:"Ù† ب";s:3:"157";s:5:"Ù† ت";s:3:"158";s:5:"ÙŠ Ù…";s:3:"159";s:6:"عرب";s:3:"160";s:5:"Ù… ب";s:3:"161";s:5:" وق";s:3:"162";s:5:" يق";s:3:"163";s:5:"ا Ù„";s:3:"164";s:5:"ا Ù…";s:3:"165";s:6:"الÙ";s:3:"166";s:6:"تطا";s:3:"167";s:6:"داد";s:3:"168";s:6:"لمس";s:3:"169";s:5:"له ";s:3:"170";s:6:"هذا";s:3:"171";s:5:" مح";s:3:"172";s:6:"ؤلا";s:3:"173";s:5:"بي ";s:3:"174";s:5:"Ø© Ù…";s:3:"175";s:5:"Ù† Ù„";s:3:"176";s:6:"هؤل";s:3:"177";s:5:"كن ";s:3:"178";s:6:"لإر";s:3:"179";s:6:"لتي";s:3:"180";s:5:" أو";s:3:"181";s:5:" ان";s:3:"182";s:5:" عم";s:3:"183";s:5:"ا Ù";s:3:"184";s:5:"Ø© Ø£";s:3:"185";s:6:"طاÙ";s:3:"186";s:5:"عب ";s:3:"187";s:5:"Ù„ Ù…";s:3:"188";s:5:"Ù† ع";s:3:"189";s:5:"ور ";s:3:"190";s:5:"يا ";s:3:"191";s:5:" يس";s:3:"192";s:5:"ا ت";s:3:"193";s:5:"Ø© ب";s:3:"194";s:6:"راء";s:3:"195";s:6:"عال";s:3:"196";s:6:"قوا";s:3:"197";s:6:"قية";s:3:"198";s:6:"لعا";s:3:"199";s:5:"Ù… ÙŠ";s:3:"200";s:5:"مي ";s:3:"201";s:6:"مية";s:3:"202";s:6:"نية";s:3:"203";s:5:"أي ";s:3:"204";s:6:"ابا";s:3:"205";s:6:"بغد";s:3:"206";s:5:"بل ";s:3:"207";s:5:"رب ";s:3:"208";s:6:"عما";s:3:"209";s:6:"غدا";s:3:"210";s:6:"مال";s:3:"211";s:6:"ملي";s:3:"212";s:5:"يس ";s:3:"213";s:5:" بأ";s:3:"214";s:5:" بع";s:3:"215";s:5:" بغ";s:3:"216";s:5:" وم";s:3:"217";s:6:"بات";s:3:"218";s:6:"بية";s:3:"219";s:6:"ذلك";s:3:"220";s:5:"عة ";s:3:"221";s:6:"قاو";s:3:"222";s:6:"قيي";s:3:"223";s:5:"كي ";s:3:"224";s:5:"Ù… Ù…";s:3:"225";s:5:"ÙŠ ع";s:3:"226";s:5:" عر";s:3:"227";s:5:" قا";s:3:"228";s:5:"ا Ùˆ";s:3:"229";s:5:"رى ";s:3:"230";s:5:"Ù‚ ا";s:3:"231";s:6:"وات";s:3:"232";s:5:"وم ";s:3:"233";s:5:" هؤ";s:3:"234";s:5:"ا ب";s:3:"235";s:6:"دام";s:3:"236";s:5:"دي ";s:3:"237";s:6:"رات";s:3:"238";s:6:"شعب";s:3:"239";s:6:"لان";s:3:"240";s:6:"لشع";s:3:"241";s:6:"لقو";s:3:"242";s:6:"ليا";s:3:"243";s:5:"Ù† Ù‡";s:3:"244";s:5:"ÙŠ ت";s:3:"245";s:5:"ÙŠ ÙŠ";s:3:"246";s:5:" وه";s:3:"247";s:5:" يح";s:3:"248";s:6:"جرا";s:3:"249";s:6:"جما";s:3:"250";s:6:"حمد";s:3:"251";s:5:"دم ";s:3:"252";s:5:"كم ";s:3:"253";s:6:"لاو";s:3:"254";s:6:"لره";s:3:"255";s:6:"ماع";s:3:"256";s:5:"Ù† Ù‚";s:3:"257";s:5:"نة ";s:3:"258";s:5:"هي ";s:3:"259";s:5:" بل";s:3:"260";s:5:" به";s:3:"261";s:5:" له";s:3:"262";s:5:" وي";s:3:"263";s:5:"ا Ùƒ";s:3:"264";s:6:"اذا";s:3:"265";s:5:"اع ";s:3:"266";s:5:"ت Ù…";s:3:"267";s:6:"تخا";s:3:"268";s:6:"خاب";s:3:"269";s:5:"ر Ù…";s:3:"270";s:6:"لمت";s:3:"271";s:6:"مسل";s:3:"272";s:5:"Ù‰ Ø£";s:3:"273";s:6:"يست";s:3:"274";s:6:"يطا";s:3:"275";s:5:" لأ";s:3:"276";s:5:" لي";s:3:"277";s:6:"أمن";s:3:"278";s:6:"است";s:3:"279";s:6:"بعض";s:3:"280";s:5:"Ø© ت";s:3:"281";s:5:"ري ";s:3:"282";s:6:"صدا";s:3:"283";s:5:"Ù‚ Ùˆ";s:3:"284";s:6:"قول";s:3:"285";s:5:"مد ";s:3:"286";s:6:"نتخ";s:3:"287";s:6:"Ù†Ùس";s:3:"288";s:6:"نها";s:3:"289";s:6:"هنا";s:3:"290";s:6:"أعم";s:3:"291";s:6:"أنه";s:3:"292";s:6:"ائن";s:3:"293";s:6:"الآ";s:3:"294";s:6:"الك";s:3:"295";s:5:"حة ";s:3:"296";s:5:"د Ù…";s:3:"297";s:5:"ر ع";s:3:"298";s:6:"ربي";s:3:"299";}s:5:"azeri";a:300:{s:4:"lÉ™r";s:1:"0";s:3:"in ";s:1:"1";s:4:"ın ";s:1:"2";s:3:"lar";s:1:"3";s:3:"da ";s:1:"4";s:3:"an ";s:1:"5";s:3:"ir ";s:1:"6";s:4:"dÉ™ ";s:1:"7";s:3:"ki ";s:1:"8";s:3:" bi";s:1:"9";s:4:"É™n ";s:2:"10";s:4:"É™ri";s:2:"11";s:4:"arı";s:2:"12";s:4:"É™r ";s:2:"13";s:3:"dir";s:2:"14";s:3:"nda";s:2:"15";s:3:" ki";s:2:"16";s:3:"rin";s:2:"17";s:4:"nın";s:2:"18";s:4:"É™si";s:2:"19";s:3:"ini";s:2:"20";s:3:" ed";s:2:"21";s:3:" qa";s:2:"22";s:4:" tÉ™";s:2:"23";s:3:" ba";s:2:"24";s:3:" ol";s:2:"25";s:4:"ası";s:2:"26";s:4:"ilÉ™";s:2:"27";s:4:"rın";s:2:"28";s:3:" ya";s:2:"29";s:4:"anı";s:2:"30";s:4:" vÉ™";s:2:"31";s:4:"ndÉ™";s:2:"32";s:3:"ni ";s:2:"33";s:3:"ara";s:2:"34";s:5:"ını";s:2:"35";s:4:"ınd";s:2:"36";s:3:" bu";s:2:"37";s:3:"si ";s:2:"38";s:3:"ib ";s:2:"39";s:3:"aq ";s:2:"40";s:4:"dÉ™n";s:2:"41";s:3:"iya";s:2:"42";s:4:"nÉ™ ";s:2:"43";s:4:"rÉ™ ";s:2:"44";s:3:"n b";s:2:"45";s:4:"sın";s:2:"46";s:4:"vÉ™ ";s:2:"47";s:3:"iri";s:2:"48";s:4:"lÉ™ ";s:2:"49";s:3:"nin";s:2:"50";s:4:"É™li";s:2:"51";s:3:" de";s:2:"52";s:4:" mü";s:2:"53";s:3:"bir";s:2:"54";s:3:"n s";s:2:"55";s:3:"ri ";s:2:"56";s:4:"É™k ";s:2:"57";s:3:" az";s:2:"58";s:4:" sÉ™";s:2:"59";s:3:"ar ";s:2:"60";s:3:"bil";s:2:"61";s:4:"zÉ™r";s:2:"62";s:3:"bu ";s:2:"63";s:3:"dan";s:2:"64";s:3:"edi";s:2:"65";s:3:"ind";s:2:"66";s:3:"man";s:2:"67";s:3:"un ";s:2:"68";s:5:"É™rÉ™";s:2:"69";s:3:" ha";s:2:"70";s:3:"lan";s:2:"71";s:4:"yyÉ™";s:2:"72";s:3:"iyy";s:2:"73";s:3:" il";s:2:"74";s:3:" ne";s:2:"75";s:3:"r k";s:2:"76";s:4:"É™ b";s:2:"77";s:3:" is";s:2:"78";s:3:"na ";s:2:"79";s:3:"nun";s:2:"80";s:4:"ır ";s:2:"81";s:3:" da";s:2:"82";s:4:" hÉ™";s:2:"83";s:3:"a b";s:2:"84";s:4:"inÉ™";s:2:"85";s:3:"sin";s:2:"86";s:3:"yan";s:2:"87";s:4:"É™rb";s:2:"88";s:4:" dÉ™";s:2:"89";s:4:" mÉ™";s:2:"90";s:4:" qÉ™";s:2:"91";s:4:"dır";s:2:"92";s:3:"li ";s:2:"93";s:3:"ola";s:2:"94";s:3:"rba";s:2:"95";s:4:"azÉ™";s:2:"96";s:3:"can";s:2:"97";s:4:"lı ";s:2:"98";s:3:"nla";s:2:"99";s:3:" et";s:3:"100";s:4:" gö";s:3:"101";s:4:"alı";s:3:"102";s:3:"ayc";s:3:"103";s:3:"bay";s:3:"104";s:3:"eft";s:3:"105";s:3:"ist";s:3:"106";s:3:"n i";s:3:"107";s:3:"nef";s:3:"108";s:4:"tlÉ™";s:3:"109";s:3:"yca";s:3:"110";s:4:"yÉ™t";s:3:"111";s:5:"É™cÉ™";s:3:"112";s:3:" la";s:3:"113";s:3:"ild";s:3:"114";s:4:"nı ";s:3:"115";s:3:"tin";s:3:"116";s:3:"ldi";s:3:"117";s:3:"lik";s:3:"118";s:3:"n h";s:3:"119";s:3:"n m";s:3:"120";s:3:"oyu";s:3:"121";s:3:"raq";s:3:"122";s:3:"ya ";s:3:"123";s:4:"É™ti";s:3:"124";s:3:" ar";s:3:"125";s:3:"ada";s:3:"126";s:4:"edÉ™";s:3:"127";s:3:"mas";s:3:"128";s:4:"sı ";s:3:"129";s:4:"ına";s:3:"130";s:4:"É™ d";s:3:"131";s:5:"É™lÉ™";s:3:"132";s:4:"ayı";s:3:"133";s:3:"iyi";s:3:"134";s:3:"lma";s:3:"135";s:4:"mÉ™k";s:3:"136";s:3:"n d";s:3:"137";s:3:"ti ";s:3:"138";s:3:"yin";s:3:"139";s:3:"yun";s:3:"140";s:4:"É™t ";s:3:"141";s:4:"azı";s:3:"142";s:3:"ft ";s:3:"143";s:3:"i t";s:3:"144";s:3:"lli";s:3:"145";s:3:"n a";s:3:"146";s:3:"ra ";s:3:"147";s:4:" cÉ™";s:3:"148";s:4:" gÉ™";s:3:"149";s:3:" ko";s:3:"150";s:4:" nÉ™";s:3:"151";s:3:" oy";s:3:"152";s:3:"a d";s:3:"153";s:3:"ana";s:3:"154";s:4:"cÉ™k";s:3:"155";s:3:"eyi";s:3:"156";s:3:"ilm";s:3:"157";s:3:"irl";s:3:"158";s:3:"lay";s:3:"159";s:3:"liy";s:3:"160";s:3:"lub";s:3:"161";s:4:"n É™";s:3:"162";s:3:"ril";s:3:"163";s:4:"rlÉ™";s:3:"164";s:3:"unu";s:3:"165";s:3:"ver";s:3:"166";s:4:"ün ";s:3:"167";s:4:"É™ o";s:3:"168";s:4:"É™ni";s:3:"169";s:3:" he";s:3:"170";s:3:" ma";s:3:"171";s:3:" on";s:3:"172";s:3:" pa";s:3:"173";s:3:"ala";s:3:"174";s:3:"dey";s:3:"175";s:3:"i m";s:3:"176";s:3:"ima";s:3:"177";s:4:"lmÉ™";s:3:"178";s:4:"mÉ™t";s:3:"179";s:3:"par";s:3:"180";s:4:"yÉ™ ";s:3:"181";s:4:"É™tl";s:3:"182";s:3:" al";s:3:"183";s:3:" mi";s:3:"184";s:3:" sa";s:3:"185";s:4:" É™l";s:3:"186";s:4:"adı";s:3:"187";s:4:"akı";s:3:"188";s:3:"and";s:3:"189";s:3:"ard";s:3:"190";s:3:"art";s:3:"191";s:3:"ayi";s:3:"192";s:3:"i a";s:3:"193";s:3:"i q";s:3:"194";s:3:"i y";s:3:"195";s:3:"ili";s:3:"196";s:3:"ill";s:3:"197";s:4:"isÉ™";s:3:"198";s:3:"n o";s:3:"199";s:3:"n q";s:3:"200";s:3:"olu";s:3:"201";s:3:"rla";s:3:"202";s:4:"stÉ™";s:3:"203";s:4:"sÉ™ ";s:3:"204";s:3:"tan";s:3:"205";s:3:"tel";s:3:"206";s:3:"yar";s:3:"207";s:5:"É™dÉ™";s:3:"208";s:3:" me";s:3:"209";s:4:" rÉ™";s:3:"210";s:3:" ve";s:3:"211";s:3:" ye";s:3:"212";s:3:"a k";s:3:"213";s:3:"at ";s:3:"214";s:4:"baÅŸ";s:3:"215";s:3:"diy";s:3:"216";s:3:"ent";s:3:"217";s:3:"eti";s:3:"218";s:4:"hÉ™s";s:3:"219";s:3:"i i";s:3:"220";s:3:"ik ";s:3:"221";s:3:"la ";s:3:"222";s:4:"miÅŸ";s:3:"223";s:3:"n n";s:3:"224";s:3:"nu ";s:3:"225";s:3:"qar";s:3:"226";s:3:"ran";s:3:"227";s:4:"tÉ™r";s:3:"228";s:3:"xan";s:3:"229";s:4:"É™ a";s:3:"230";s:4:"É™ g";s:3:"231";s:4:"É™ t";s:3:"232";s:4:" dü";s:3:"233";s:3:"ama";s:3:"234";s:3:"b k";s:3:"235";s:3:"dil";s:3:"236";s:3:"era";s:3:"237";s:3:"etm";s:3:"238";s:3:"i b";s:3:"239";s:3:"kil";s:3:"240";s:3:"mil";s:3:"241";s:3:"n r";s:3:"242";s:3:"qla";s:3:"243";s:3:"r s";s:3:"244";s:3:"ras";s:3:"245";s:3:"siy";s:3:"246";s:3:"son";s:3:"247";s:3:"tim";s:3:"248";s:3:"yer";s:3:"249";s:4:"É™ k";s:3:"250";s:4:" gü";s:3:"251";s:3:" so";s:3:"252";s:4:" sö";s:3:"253";s:3:" te";s:3:"254";s:3:" xa";s:3:"255";s:3:"ai ";s:3:"256";s:3:"bar";s:3:"257";s:3:"cti";s:3:"258";s:3:"di ";s:3:"259";s:3:"eri";s:3:"260";s:4:"gör";s:3:"261";s:4:"gün";s:3:"262";s:4:"gÉ™l";s:3:"263";s:4:"hbÉ™";s:3:"264";s:4:"ihÉ™";s:3:"265";s:3:"iki";s:3:"266";s:3:"isi";s:3:"267";s:3:"lin";s:3:"268";s:3:"mai";s:3:"269";s:3:"maq";s:3:"270";s:3:"n k";s:3:"271";s:3:"n t";s:3:"272";s:3:"n v";s:3:"273";s:3:"onu";s:3:"274";s:3:"qan";s:3:"275";s:4:"qÉ™z";s:3:"276";s:4:"tÉ™ ";s:3:"277";s:3:"xal";s:3:"278";s:3:"yib";s:3:"279";s:3:"yih";s:3:"280";s:3:"zet";s:3:"281";s:4:"zır";s:3:"282";s:4:"ıb ";s:3:"283";s:4:"É™ m";s:3:"284";s:4:"É™ze";s:3:"285";s:3:" br";s:3:"286";s:3:" in";s:3:"287";s:4:" i̇";s:3:"288";s:3:" pr";s:3:"289";s:3:" ta";s:3:"290";s:3:" to";s:3:"291";s:5:" üç";s:3:"292";s:3:"a o";s:3:"293";s:3:"ali";s:3:"294";s:3:"ani";s:3:"295";s:3:"anl";s:3:"296";s:3:"aql";s:3:"297";s:3:"azi";s:3:"298";s:3:"bri";s:3:"299";}s:7:"bengali";a:300:{s:7:"ার ";s:1:"0";s:7:"য় ";s:1:"1";s:9:"েয়";s:1:"2";s:9:"য়া";s:1:"3";s:7:" কর";s:1:"4";s:7:"েত ";s:1:"5";s:7:" কা";s:1:"6";s:7:" পা";s:1:"7";s:7:" তা";s:1:"8";s:7:"না ";s:1:"9";s:9:"ায়";s:2:"10";s:7:"ের ";s:2:"11";s:9:"য়ে";s:2:"12";s:7:" বা";s:2:"13";s:7:"েব ";s:2:"14";s:7:" যা";s:2:"15";s:7:" হে";s:2:"16";s:7:" সা";s:2:"17";s:7:"ান ";s:2:"18";s:7:"েছ ";s:2:"19";s:7:" িন";s:2:"20";s:7:"েল ";s:2:"21";s:7:" িদ";s:2:"22";s:7:" না";s:2:"23";s:7:" িব";s:2:"24";s:7:"েক ";s:2:"25";s:7:"লা ";s:2:"26";s:7:"তা ";s:2:"27";s:7:" বઘ";s:2:"28";s:7:" িক";s:2:"29";s:9:"করে";s:2:"30";s:7:" পચ";s:2:"31";s:9:"াের";s:2:"32";s:9:"িনে";s:2:"33";s:7:"রা ";s:2:"34";s:7:" োব";s:2:"35";s:7:"কা ";s:2:"36";s:7:" কে";s:2:"37";s:7:" টা";s:2:"38";s:7:"র ক";s:2:"39";s:9:"েলা";s:2:"40";s:7:" োক";s:2:"41";s:7:" মা";s:2:"42";s:7:" োদ";s:2:"43";s:7:" োম";s:2:"44";s:7:"দর ";s:2:"45";s:7:"়া ";s:2:"46";s:9:"িদে";s:2:"47";s:9:"াকা";s:2:"48";s:9:"়েছ";s:2:"49";s:9:"েদর";s:2:"50";s:7:" আে";s:2:"51";s:5:" ও ";s:2:"52";s:7:"াল ";s:2:"53";s:7:"িট ";s:2:"54";s:7:" মà§";s:2:"55";s:9:"কের";s:2:"56";s:9:"হয়";s:2:"57";s:9:"করা";s:2:"58";s:7:"পর ";s:2:"59";s:9:"পাে";s:2:"60";s:7:" à¦à¦•";s:2:"61";s:7:" পদ";s:2:"62";s:9:"টাক";s:2:"63";s:7:"ড় ";s:2:"64";s:9:"কান";s:2:"65";s:7:"টা ";s:2:"66";s:9:"দગা";s:2:"67";s:9:"পদગ";s:2:"68";s:9:"াড়";s:2:"69";s:9:"োকা";s:2:"70";s:9:"ওয়";s:2:"71";s:9:"কাপ";s:2:"72";s:9:"হেয";s:2:"73";s:9:"েনর";s:2:"74";s:7:" হয";s:2:"75";s:9:"দেয";s:2:"76";s:7:"নর ";s:2:"77";s:9:"ানা";s:2:"78";s:9:"ােল";s:2:"79";s:7:" আর";s:2:"80";s:5:" ় ";s:2:"81";s:9:"বઘব";s:2:"82";s:9:"িয়";s:2:"83";s:7:" দা";s:2:"84";s:7:" সম";s:2:"85";s:9:"কার";s:2:"86";s:9:"হার";s:2:"87";s:7:"াই ";s:2:"88";s:9:"ড়া";s:2:"89";s:9:"িবি";s:2:"90";s:7:" রা";s:2:"91";s:7:" লা";s:2:"92";s:9:"নার";s:2:"93";s:9:"বহা";s:2:"94";s:7:"বা ";s:2:"95";s:9:"যায";s:2:"96";s:7:"েন ";s:2:"97";s:9:"ઘবহ";s:2:"98";s:7:" ভা";s:2:"99";s:7:" সে";s:3:"100";s:7:" োয";s:3:"101";s:7:"রর ";s:3:"102";s:9:"়ার";s:3:"103";s:9:"়াল";s:3:"104";s:7:"ગা ";s:3:"105";s:9:"থেক";s:3:"106";s:9:"ভাে";s:3:"107";s:7:"়ে ";s:3:"108";s:9:"েরর";s:3:"109";s:7:" ধর";s:3:"110";s:7:" হা";s:3:"111";s:7:"নઘ ";s:3:"112";s:9:"রেন";s:3:"113";s:9:"ােব";s:3:"114";s:9:"িড়";s:3:"115";s:7:"ির ";s:3:"116";s:7:" োথ";s:3:"117";s:9:"তার";s:3:"118";s:9:"বিভ";s:3:"119";s:9:"রেত";s:3:"120";s:9:"সাে";s:3:"121";s:9:"াকে";s:3:"122";s:9:"ােত";s:3:"123";s:9:"িভਭ";s:3:"124";s:7:"ে ব";s:3:"125";s:9:"োথে";s:3:"126";s:7:" োপ";s:3:"127";s:7:" োস";s:3:"128";s:9:"বার";s:3:"129";s:7:"ভਭ ";s:3:"130";s:7:"রন ";s:3:"131";s:7:"াম ";s:3:"132";s:7:" à¦à¦–";s:3:"133";s:7:"আর ";s:3:"134";s:9:"কাে";s:3:"135";s:7:"দন ";s:3:"136";s:9:"সাজ";s:3:"137";s:9:"ােক";s:3:"138";s:9:"ােন";s:3:"139";s:9:"েনা";s:3:"140";s:7:" ঘে";s:3:"141";s:7:" তে";s:3:"142";s:7:" রে";s:3:"143";s:9:"তেব";s:3:"144";s:7:"বন ";s:3:"145";s:9:"বઘা";s:3:"146";s:9:"েড়";s:3:"147";s:9:"েবন";s:3:"148";s:7:" খà§";s:3:"149";s:7:" চা";s:3:"150";s:7:" সà§";s:3:"151";s:7:"কে ";s:3:"152";s:9:"ধরে";s:3:"153";s:7:"র ো";s:3:"154";s:7:"় ি";s:3:"155";s:7:"া ি";s:3:"156";s:9:"ােথ";s:3:"157";s:9:"াਠা";s:3:"158";s:7:"িদ ";s:3:"159";s:7:"িন ";s:3:"160";s:7:" অন";s:3:"161";s:7:" আপ";s:3:"162";s:7:" আম";s:3:"163";s:7:" থা";s:3:"164";s:7:" বચ";s:3:"165";s:7:" োফ";s:3:"166";s:7:" ৌত";s:3:"167";s:9:"ঘের";s:3:"168";s:7:"তে ";s:3:"169";s:9:"ময়";s:3:"170";s:9:"যাਠ";s:3:"171";s:7:"র স";s:3:"172";s:9:"রাখ";s:3:"173";s:7:"া ব";s:3:"174";s:7:"া ো";s:3:"175";s:9:"ালা";s:3:"176";s:7:"িক ";s:3:"177";s:7:"িশ ";s:3:"178";s:7:"েখ ";s:3:"179";s:7:" à¦à¦°";s:3:"180";s:7:" চઓ";s:3:"181";s:7:" িড";s:3:"182";s:7:"খন ";s:3:"183";s:9:"ড়ে";s:3:"184";s:7:"র ব";s:3:"185";s:7:"়র ";s:3:"186";s:9:"াইে";s:3:"187";s:9:"ােদ";s:3:"188";s:9:"িদন";s:3:"189";s:9:"েরন";s:3:"190";s:7:" তੴ";s:3:"191";s:9:"ছাড";s:3:"192";s:9:"জনઘ";s:3:"193";s:9:"তাই";s:3:"194";s:7:"মা ";s:3:"195";s:9:"মাে";s:3:"196";s:9:"লার";s:3:"197";s:7:"াজ ";s:3:"198";s:9:"াতা";s:3:"199";s:9:"ামা";s:3:"200";s:9:"ਊেল";s:3:"201";s:9:"ગার";s:3:"202";s:7:" সব";s:3:"203";s:9:"আপন";s:3:"204";s:9:"à¦à¦•à¦Ÿ";s:3:"205";s:9:"কাি";s:3:"206";s:9:"জাই";s:3:"207";s:7:"টর ";s:3:"208";s:9:"ডজা";s:3:"209";s:9:"দেখ";s:3:"210";s:9:"পনা";s:3:"211";s:7:"রও ";s:3:"212";s:7:"লে ";s:3:"213";s:9:"হেব";s:3:"214";s:9:"াজা";s:3:"215";s:9:"ািট";s:3:"216";s:9:"িডজ";s:3:"217";s:7:"েথ ";s:3:"218";s:7:" à¦à¦¬";s:3:"219";s:7:" জন";s:3:"220";s:7:" জা";s:3:"221";s:9:"আমা";s:3:"222";s:9:"গেল";s:3:"223";s:9:"জান";s:3:"224";s:9:"নেত";s:3:"225";s:9:"বিশ";s:3:"226";s:9:"মà§à§‡";s:3:"227";s:9:"মেয";s:3:"228";s:7:"র প";s:3:"229";s:7:"সে ";s:3:"230";s:9:"হেল";s:3:"231";s:7:"় ো";s:3:"232";s:7:"া হ";s:3:"233";s:9:"াওয";s:3:"234";s:9:"োমক";s:3:"235";s:9:"ઘাি";s:3:"236";s:7:" অে";s:3:"237";s:5:" ট ";s:3:"238";s:7:" োগ";s:3:"239";s:7:" োন";s:3:"240";s:7:"জর ";s:3:"241";s:9:"তির";s:3:"242";s:9:"দাম";s:3:"243";s:9:"পড়";s:3:"244";s:9:"পার";s:3:"245";s:9:"বাঘ";s:3:"246";s:9:"মকা";s:3:"247";s:9:"মাম";s:3:"248";s:9:"য়র";s:3:"249";s:9:"যাে";s:3:"250";s:7:"র ম";s:3:"251";s:7:"রে ";s:3:"252";s:7:"লর ";s:3:"253";s:7:"া ক";s:3:"254";s:7:"াগ ";s:3:"255";s:9:"াবা";s:3:"256";s:9:"ারা";s:3:"257";s:9:"ািন";s:3:"258";s:7:"ে গ";s:3:"259";s:7:"েগ ";s:3:"260";s:9:"েলর";s:3:"261";s:9:"োদখ";s:3:"262";s:9:"োবি";s:3:"263";s:7:"ઓল ";s:3:"264";s:7:" দে";s:3:"265";s:7:" পà§";s:3:"266";s:7:" বে";s:3:"267";s:9:"অেন";s:3:"268";s:9:"à¦à¦–ন";s:3:"269";s:9:"কছà§";s:3:"270";s:9:"কাল";s:3:"271";s:9:"গেয";s:3:"272";s:7:"ছন ";s:3:"273";s:7:"ত প";s:3:"274";s:9:"নেয";s:3:"275";s:9:"পাি";s:3:"276";s:7:"মন ";s:3:"277";s:7:"র আ";s:3:"278";s:9:"রার";s:3:"279";s:7:"াও ";s:3:"280";s:7:"াপ ";s:3:"281";s:9:"িকছ";s:3:"282";s:9:"িগে";s:3:"283";s:9:"েছন";s:3:"284";s:9:"েজর";s:3:"285";s:9:"োমা";s:3:"286";s:9:"োমে";s:3:"287";s:9:"ৌতি";s:3:"288";s:9:"ઘাে";s:3:"289";s:3:" ' ";s:3:"290";s:7:" à¦à¦›";s:3:"291";s:7:" ছা";s:3:"292";s:7:" বল";s:3:"293";s:7:" যি";s:3:"294";s:7:" শি";s:3:"295";s:7:" িম";s:3:"296";s:7:" োল";s:3:"297";s:9:"à¦à¦›à¦¾";s:3:"298";s:7:"খা ";s:3:"299";}s:9:"bulgarian";a:300:{s:5:"на ";s:1:"0";s:5:" на";s:1:"1";s:5:"то ";s:1:"2";s:5:" пр";s:1:"3";s:5:" за";s:1:"4";s:5:"та ";s:1:"5";s:5:" по";s:1:"6";s:6:"ите";s:1:"7";s:5:"те ";s:1:"8";s:5:"а п";s:1:"9";s:5:"а Ñ";s:2:"10";s:5:" от";s:2:"11";s:5:"за ";s:2:"12";s:6:"ата";s:2:"13";s:5:"Ð¸Ñ ";s:2:"14";s:4:" в ";s:2:"15";s:5:"е н";s:2:"16";s:5:" да";s:2:"17";s:5:"а н";s:2:"18";s:5:" Ñе";s:2:"19";s:5:" ко";s:2:"20";s:5:"да ";s:2:"21";s:5:"от ";s:2:"22";s:6:"ани";s:2:"23";s:6:"пре";s:2:"24";s:5:"не ";s:2:"25";s:6:"ени";s:2:"26";s:5:"о н";s:2:"27";s:5:"ни ";s:2:"28";s:5:"Ñе ";s:2:"29";s:4:" и ";s:2:"30";s:5:"но ";s:2:"31";s:6:"ане";s:2:"32";s:6:"ето";s:2:"33";s:5:"а в";s:2:"34";s:5:"ва ";s:2:"35";s:6:"ван";s:2:"36";s:5:"е п";s:2:"37";s:5:"а о";s:2:"38";s:6:"ото";s:2:"39";s:6:"ран";s:2:"40";s:5:"ат ";s:2:"41";s:6:"ред";s:2:"42";s:5:" не";s:2:"43";s:5:"а д";s:2:"44";s:5:"и п";s:2:"45";s:5:" до";s:2:"46";s:6:"про";s:2:"47";s:5:" ÑÑŠ";s:2:"48";s:5:"ли ";s:2:"49";s:6:"при";s:2:"50";s:6:"ниÑ";s:2:"51";s:6:"Ñки";s:2:"52";s:6:"тел";s:2:"53";s:5:"а и";s:2:"54";s:5:"по ";s:2:"55";s:5:"ри ";s:2:"56";s:4:" е ";s:2:"57";s:5:" ка";s:2:"58";s:6:"ира";s:2:"59";s:6:"кат";s:2:"60";s:6:"ние";s:2:"61";s:6:"нит";s:2:"62";s:5:"е з";s:2:"63";s:5:"и Ñ";s:2:"64";s:5:"о Ñ";s:2:"65";s:6:"оÑÑ‚";s:2:"66";s:5:"че ";s:2:"67";s:5:" ра";s:2:"68";s:6:"иÑÑ‚";s:2:"69";s:5:"о п";s:2:"70";s:5:" из";s:2:"71";s:5:" Ñа";s:2:"72";s:5:"е д";s:2:"73";s:6:"ини";s:2:"74";s:5:"ки ";s:2:"75";s:6:"мин";s:2:"76";s:5:" ми";s:2:"77";s:5:"а б";s:2:"78";s:6:"ава";s:2:"79";s:5:"е в";s:2:"80";s:5:"ие ";s:2:"81";s:6:"пол";s:2:"82";s:6:"Ñтв";s:2:"83";s:5:"Ñ‚ н";s:2:"84";s:5:" въ";s:2:"85";s:5:" ÑÑ‚";s:2:"86";s:5:" то";s:2:"87";s:6:"аза";s:2:"88";s:5:"е о";s:2:"89";s:5:"ов ";s:2:"90";s:5:"ÑÑ‚ ";s:2:"91";s:5:"ÑŠÑ‚ ";s:2:"92";s:5:"и н";s:2:"93";s:6:"иÑÑ‚";s:2:"94";s:6:"нат";s:2:"95";s:5:"ра ";s:2:"96";s:5:" бъ";s:2:"97";s:5:" че";s:2:"98";s:6:"алн";s:2:"99";s:5:"е Ñ";s:3:"100";s:5:"ен ";s:3:"101";s:6:"еÑÑ‚";s:3:"102";s:5:"и д";s:3:"103";s:6:"лен";s:3:"104";s:6:"ниÑ";s:3:"105";s:5:"о о";s:3:"106";s:6:"ови";s:3:"107";s:5:" об";s:3:"108";s:5:" Ñл";s:3:"109";s:5:"а Ñ€";s:3:"110";s:6:"ато";s:3:"111";s:6:"кон";s:3:"112";s:6:"ноÑ";s:3:"113";s:6:"ров";s:3:"114";s:5:"ще ";s:3:"115";s:5:" ре";s:3:"116";s:4:" Ñ ";s:3:"117";s:5:" Ñп";s:3:"118";s:6:"ват";s:3:"119";s:6:"еше";s:3:"120";s:5:"и в";s:3:"121";s:6:"иет";s:3:"122";s:5:"о в";s:3:"123";s:6:"ове";s:3:"124";s:6:"Ñта";s:3:"125";s:5:"а к";s:3:"126";s:5:"а Ñ‚";s:3:"127";s:6:"дат";s:3:"128";s:6:"ент";s:3:"129";s:5:"ка ";s:3:"130";s:6:"лед";s:3:"131";s:6:"нет";s:3:"132";s:6:"ори";s:3:"133";s:6:"ÑÑ‚Ñ€";s:3:"134";s:6:"ÑÑ‚ÑŠ";s:3:"135";s:5:"ти ";s:3:"136";s:6:"Ñ‚ÑŠÑ€";s:3:"137";s:5:" те";s:3:"138";s:5:"а з";s:3:"139";s:5:"а м";s:3:"140";s:5:"ад ";s:3:"141";s:6:"ана";s:3:"142";s:6:"ено";s:3:"143";s:5:"и о";s:3:"144";s:6:"ина";s:3:"145";s:6:"ити";s:3:"146";s:5:"ма ";s:3:"147";s:6:"Ñка";s:3:"148";s:6:"Ñле";s:3:"149";s:6:"тво";s:3:"150";s:6:"тер";s:3:"151";s:6:"циÑ";s:3:"152";s:5:"ÑÑ‚ ";s:3:"153";s:5:" бе";s:3:"154";s:5:" де";s:3:"155";s:5:" па";s:3:"156";s:6:"ате";s:3:"157";s:6:"вен";s:3:"158";s:5:"ви ";s:3:"159";s:6:"вит";s:3:"160";s:5:"и з";s:3:"161";s:5:"и и";s:3:"162";s:6:"нар";s:3:"163";s:6:"нов";s:3:"164";s:6:"ова";s:3:"165";s:6:"пов";s:3:"166";s:6:"рез";s:3:"167";s:6:"рит";s:3:"168";s:5:"Ñа ";s:3:"169";s:6:"Ñта";s:3:"170";s:5:" го";s:3:"171";s:5:" ще";s:3:"172";s:6:"али";s:3:"173";s:5:"в п";s:3:"174";s:6:"гра";s:3:"175";s:5:"е и";s:3:"176";s:6:"еди";s:3:"177";s:6:"ели";s:3:"178";s:6:"или";s:3:"179";s:6:"каз";s:3:"180";s:6:"кит";s:3:"181";s:6:"лно";s:3:"182";s:6:"мен";s:3:"183";s:6:"оли";s:3:"184";s:6:"раз";s:3:"185";s:5:" ве";s:3:"186";s:5:" гр";s:3:"187";s:5:" им";s:3:"188";s:5:" ме";s:3:"189";s:5:" пъ";s:3:"190";s:6:"ави";s:3:"191";s:6:"ако";s:3:"192";s:6:"ача";s:3:"193";s:6:"вин";s:3:"194";s:5:"во ";s:3:"195";s:6:"гов";s:3:"196";s:6:"дан";s:3:"197";s:5:"ди ";s:3:"198";s:5:"до ";s:3:"199";s:5:"ед ";s:3:"200";s:6:"ери";s:3:"201";s:6:"еро";s:3:"202";s:6:"жда";s:3:"203";s:6:"ито";s:3:"204";s:6:"ков";s:3:"205";s:6:"кол";s:3:"206";s:6:"лни";s:3:"207";s:6:"мер";s:3:"208";s:6:"нач";s:3:"209";s:5:"о з";s:3:"210";s:6:"ола";s:3:"211";s:5:"он ";s:3:"212";s:6:"она";s:3:"213";s:6:"пра";s:3:"214";s:6:"рав";s:3:"215";s:6:"рем";s:3:"216";s:6:"ÑиÑ";s:3:"217";s:6:"Ñти";s:3:"218";s:5:"Ñ‚ п";s:3:"219";s:6:"тан";s:3:"220";s:5:"ха ";s:3:"221";s:5:"ше ";s:3:"222";s:6:"шен";s:3:"223";s:6:"ълг";s:3:"224";s:5:" ба";s:3:"225";s:5:" Ñи";s:3:"226";s:6:"аро";s:3:"227";s:6:"бъл";s:3:"228";s:5:"в Ñ€";s:3:"229";s:6:"гар";s:3:"230";s:5:"е е";s:3:"231";s:6:"елн";s:3:"232";s:6:"еме";s:3:"233";s:6:"ико";s:3:"234";s:6:"има";s:3:"235";s:5:"ко ";s:3:"236";s:6:"кои";s:3:"237";s:5:"ла ";s:3:"238";s:6:"лга";s:3:"239";s:5:"о д";s:3:"240";s:6:"ози";s:3:"241";s:6:"оит";s:3:"242";s:6:"под";s:3:"243";s:6:"реÑ";s:3:"244";s:6:"рие";s:3:"245";s:6:"Ñто";s:3:"246";s:5:"Ñ‚ к";s:3:"247";s:5:"Ñ‚ м";s:3:"248";s:5:"Ñ‚ Ñ";s:3:"249";s:6:"уÑÑ‚";s:3:"250";s:5:" би";s:3:"251";s:5:" дв";s:3:"252";s:5:" дъ";s:3:"253";s:5:" ма";s:3:"254";s:5:" мо";s:3:"255";s:5:" ни";s:3:"256";s:5:" оÑ";s:3:"257";s:6:"ала";s:3:"258";s:6:"анÑ";s:3:"259";s:6:"ара";s:3:"260";s:6:"ати";s:3:"261";s:6:"аци";s:3:"262";s:6:"беш";s:3:"263";s:6:"вър";s:3:"264";s:5:"е Ñ€";s:3:"265";s:6:"едв";s:3:"266";s:6:"ема";s:3:"267";s:6:"жав";s:3:"268";s:5:"и к";s:3:"269";s:6:"иал";s:3:"270";s:6:"ица";s:3:"271";s:6:"иче";s:3:"272";s:6:"киÑ";s:3:"273";s:6:"лит";s:3:"274";s:5:"о б";s:3:"275";s:6:"ово";s:3:"276";s:6:"оди";s:3:"277";s:6:"ока";s:3:"278";s:6:"поÑ";s:3:"279";s:6:"род";s:3:"280";s:6:"Ñед";s:3:"281";s:6:"Ñлу";s:3:"282";s:5:"Ñ‚ и";s:3:"283";s:6:"тов";s:3:"284";s:6:"ува";s:3:"285";s:6:"циа";s:3:"286";s:6:"чеÑ";s:3:"287";s:5:"Ñ Ð·";s:3:"288";s:5:" во";s:3:"289";s:5:" ил";s:3:"290";s:5:" Ñк";s:3:"291";s:5:" Ñ‚Ñ€";s:3:"292";s:5:" це";s:3:"293";s:6:"ами";s:3:"294";s:6:"ари";s:3:"295";s:6:"бат";s:3:"296";s:5:"би ";s:3:"297";s:6:"бра";s:3:"298";s:6:"бъд";s:3:"299";}s:7:"cebuano";a:300:{s:3:"ng ";s:1:"0";s:3:"sa ";s:1:"1";s:3:" sa";s:1:"2";s:3:"ang";s:1:"3";s:3:"ga ";s:1:"4";s:3:"nga";s:1:"5";s:3:" ka";s:1:"6";s:3:" ng";s:1:"7";s:3:"an ";s:1:"8";s:3:" an";s:1:"9";s:3:" na";s:2:"10";s:3:" ma";s:2:"11";s:3:" ni";s:2:"12";s:3:"a s";s:2:"13";s:3:"a n";s:2:"14";s:3:"on ";s:2:"15";s:3:" pa";s:2:"16";s:3:" si";s:2:"17";s:3:"a k";s:2:"18";s:3:"a m";s:2:"19";s:3:" ba";s:2:"20";s:3:"ong";s:2:"21";s:3:"a i";s:2:"22";s:3:"ila";s:2:"23";s:3:" mg";s:2:"24";s:3:"mga";s:2:"25";s:3:"a p";s:2:"26";s:3:"iya";s:2:"27";s:3:"a a";s:2:"28";s:3:"ay ";s:2:"29";s:3:"ka ";s:2:"30";s:3:"ala";s:2:"31";s:3:"ing";s:2:"32";s:3:"g m";s:2:"33";s:3:"n s";s:2:"34";s:3:"g n";s:2:"35";s:3:"lan";s:2:"36";s:3:" gi";s:2:"37";s:3:"na ";s:2:"38";s:3:"ni ";s:2:"39";s:3:"o s";s:2:"40";s:3:"g p";s:2:"41";s:3:"n n";s:2:"42";s:3:" da";s:2:"43";s:3:"ag ";s:2:"44";s:3:"pag";s:2:"45";s:3:"g s";s:2:"46";s:3:"yan";s:2:"47";s:3:"ayo";s:2:"48";s:3:"o n";s:2:"49";s:3:"si ";s:2:"50";s:3:" mo";s:2:"51";s:3:"a b";s:2:"52";s:3:"g a";s:2:"53";s:3:"ail";s:2:"54";s:3:"g b";s:2:"55";s:3:"han";s:2:"56";s:3:"a d";s:2:"57";s:3:"asu";s:2:"58";s:3:"nag";s:2:"59";s:3:"ya ";s:2:"60";s:3:"man";s:2:"61";s:3:"ne ";s:2:"62";s:3:"pan";s:2:"63";s:3:"kon";s:2:"64";s:3:" il";s:2:"65";s:3:" la";s:2:"66";s:3:"aka";s:2:"67";s:3:"ako";s:2:"68";s:3:"ana";s:2:"69";s:3:"bas";s:2:"70";s:3:"ko ";s:2:"71";s:3:"od ";s:2:"72";s:3:"yo ";s:2:"73";s:3:" di";s:2:"74";s:3:" ko";s:2:"75";s:3:" ug";s:2:"76";s:3:"a u";s:2:"77";s:3:"g k";s:2:"78";s:3:"kan";s:2:"79";s:3:"la ";s:2:"80";s:3:"len";s:2:"81";s:3:"sur";s:2:"82";s:3:"ug ";s:2:"83";s:3:" ai";s:2:"84";s:3:"apa";s:2:"85";s:3:"aw ";s:2:"86";s:3:"d s";s:2:"87";s:3:"g d";s:2:"88";s:3:"g g";s:2:"89";s:3:"ile";s:2:"90";s:3:"nin";s:2:"91";s:3:" iy";s:2:"92";s:3:" su";s:2:"93";s:3:"ene";s:2:"94";s:3:"og ";s:2:"95";s:3:"ot ";s:2:"96";s:3:"aba";s:2:"97";s:3:"aha";s:2:"98";s:3:"as ";s:2:"99";s:3:"imo";s:3:"100";s:3:" ki";s:3:"101";s:3:"a t";s:3:"102";s:3:"aga";s:3:"103";s:3:"ban";s:3:"104";s:3:"ero";s:3:"105";s:3:"nan";s:3:"106";s:3:"o k";s:3:"107";s:3:"ran";s:3:"108";s:3:"ron";s:3:"109";s:3:"sil";s:3:"110";s:3:"una";s:3:"111";s:3:"usa";s:3:"112";s:3:" us";s:3:"113";s:3:"a g";s:3:"114";s:3:"ahi";s:3:"115";s:3:"ani";s:3:"116";s:3:"er ";s:3:"117";s:3:"ha ";s:3:"118";s:3:"i a";s:3:"119";s:3:"rer";s:3:"120";s:3:"yon";s:3:"121";s:3:" pu";s:3:"122";s:3:"ini";s:3:"123";s:3:"nak";s:3:"124";s:3:"ro ";s:3:"125";s:3:"to ";s:3:"126";s:3:"ure";s:3:"127";s:3:" ed";s:3:"128";s:3:" og";s:3:"129";s:3:" wa";s:3:"130";s:3:"ili";s:3:"131";s:3:"mo ";s:3:"132";s:3:"n a";s:3:"133";s:3:"nd ";s:3:"134";s:3:"o a";s:3:"135";s:3:" ad";s:3:"136";s:3:" du";s:3:"137";s:3:" pr";s:3:"138";s:3:"aro";s:3:"139";s:3:"i s";s:3:"140";s:3:"ma ";s:3:"141";s:3:"n m";s:3:"142";s:3:"ulo";s:3:"143";s:3:"und";s:3:"144";s:3:" ta";s:3:"145";s:3:"ara";s:3:"146";s:3:"asa";s:3:"147";s:3:"ato";s:3:"148";s:3:"awa";s:3:"149";s:3:"dmu";s:3:"150";s:3:"e n";s:3:"151";s:3:"edm";s:3:"152";s:3:"ina";s:3:"153";s:3:"mak";s:3:"154";s:3:"mun";s:3:"155";s:3:"niy";s:3:"156";s:3:"san";s:3:"157";s:3:"wa ";s:3:"158";s:3:" tu";s:3:"159";s:3:" un";s:3:"160";s:3:"a l";s:3:"161";s:3:"bay";s:3:"162";s:3:"iga";s:3:"163";s:3:"ika";s:3:"164";s:3:"ita";s:3:"165";s:3:"kin";s:3:"166";s:3:"lis";s:3:"167";s:3:"may";s:3:"168";s:3:"os ";s:3:"169";s:3:" ar";s:3:"170";s:3:"ad ";s:3:"171";s:3:"ali";s:3:"172";s:3:"ama";s:3:"173";s:3:"ers";s:3:"174";s:3:"ipa";s:3:"175";s:3:"isa";s:3:"176";s:3:"mao";s:3:"177";s:3:"nim";s:3:"178";s:3:"t s";s:3:"179";s:3:"tin";s:3:"180";s:3:" ak";s:3:"181";s:3:" ap";s:3:"182";s:3:" hi";s:3:"183";s:3:"abo";s:3:"184";s:3:"agp";s:3:"185";s:3:"ano";s:3:"186";s:3:"ata";s:3:"187";s:3:"g i";s:3:"188";s:3:"gan";s:3:"189";s:3:"gka";s:3:"190";s:3:"gpa";s:3:"191";s:3:"i m";s:3:"192";s:3:"iha";s:3:"193";s:3:"k s";s:3:"194";s:3:"law";s:3:"195";s:3:"or ";s:3:"196";s:3:"rs ";s:3:"197";s:3:"siy";s:3:"198";s:3:"tag";s:3:"199";s:3:" al";s:3:"200";s:3:" at";s:3:"201";s:3:" ha";s:3:"202";s:3:" hu";s:3:"203";s:3:" im";s:3:"204";s:3:"a h";s:3:"205";s:3:"bu ";s:3:"206";s:3:"e s";s:3:"207";s:3:"gma";s:3:"208";s:3:"kas";s:3:"209";s:3:"lag";s:3:"210";s:3:"mon";s:3:"211";s:3:"nah";s:3:"212";s:3:"ngo";s:3:"213";s:3:"r s";s:3:"214";s:3:"ra ";s:3:"215";s:3:"sab";s:3:"216";s:3:"sam";s:3:"217";s:3:"sul";s:3:"218";s:3:"uba";s:3:"219";s:3:"uha";s:3:"220";s:3:" lo";s:3:"221";s:3:" re";s:3:"222";s:3:"ada";s:3:"223";s:3:"aki";s:3:"224";s:3:"aya";s:3:"225";s:3:"bah";s:3:"226";s:3:"ce ";s:3:"227";s:3:"d n";s:3:"228";s:3:"lab";s:3:"229";s:3:"pa ";s:3:"230";s:3:"pak";s:3:"231";s:3:"s n";s:3:"232";s:3:"s s";s:3:"233";s:3:"tan";s:3:"234";s:3:"taw";s:3:"235";s:3:"te ";s:3:"236";s:3:"uma";s:3:"237";s:3:"ura";s:3:"238";s:3:" in";s:3:"239";s:3:" lu";s:3:"240";s:3:"a c";s:3:"241";s:3:"abi";s:3:"242";s:3:"at ";s:3:"243";s:3:"awo";s:3:"244";s:3:"bat";s:3:"245";s:3:"dal";s:3:"246";s:3:"dla";s:3:"247";s:3:"ele";s:3:"248";s:3:"g t";s:3:"249";s:3:"g u";s:3:"250";s:3:"gay";s:3:"251";s:3:"go ";s:3:"252";s:3:"hab";s:3:"253";s:3:"hin";s:3:"254";s:3:"i e";s:3:"255";s:3:"i n";s:3:"256";s:3:"kab";s:3:"257";s:3:"kap";s:3:"258";s:3:"lay";s:3:"259";s:3:"lin";s:3:"260";s:3:"nil";s:3:"261";s:3:"pam";s:3:"262";s:3:"pas";s:3:"263";s:3:"pro";s:3:"264";s:3:"pul";s:3:"265";s:3:"ta ";s:3:"266";s:3:"ton";s:3:"267";s:3:"uga";s:3:"268";s:3:"ugm";s:3:"269";s:3:"unt";s:3:"270";s:3:" co";s:3:"271";s:3:" gu";s:3:"272";s:3:" mi";s:3:"273";s:3:" pi";s:3:"274";s:3:" ti";s:3:"275";s:3:"a o";s:3:"276";s:3:"abu";s:3:"277";s:3:"adl";s:3:"278";s:3:"ado";s:3:"279";s:3:"agh";s:3:"280";s:3:"agk";s:3:"281";s:3:"ao ";s:3:"282";s:3:"art";s:3:"283";s:3:"bal";s:3:"284";s:3:"cit";s:3:"285";s:3:"di ";s:3:"286";s:3:"dto";s:3:"287";s:3:"dun";s:3:"288";s:3:"ent";s:3:"289";s:3:"g e";s:3:"290";s:3:"gon";s:3:"291";s:3:"gug";s:3:"292";s:3:"ia ";s:3:"293";s:3:"iba";s:3:"294";s:3:"ice";s:3:"295";s:3:"in ";s:3:"296";s:3:"inu";s:3:"297";s:3:"it ";s:3:"298";s:3:"kaa";s:3:"299";}s:8:"croatian";a:300:{s:3:"je ";s:1:"0";s:3:" na";s:1:"1";s:3:" pr";s:1:"2";s:3:" po";s:1:"3";s:3:"na ";s:1:"4";s:3:" je";s:1:"5";s:3:" za";s:1:"6";s:3:"ije";s:1:"7";s:3:"ne ";s:1:"8";s:3:" i ";s:1:"9";s:3:"ti ";s:2:"10";s:3:"da ";s:2:"11";s:3:" ko";s:2:"12";s:3:" ne";s:2:"13";s:3:"li ";s:2:"14";s:3:" bi";s:2:"15";s:3:" da";s:2:"16";s:3:" u ";s:2:"17";s:3:"ma ";s:2:"18";s:3:"mo ";s:2:"19";s:3:"a n";s:2:"20";s:3:"ih ";s:2:"21";s:3:"za ";s:2:"22";s:3:"a s";s:2:"23";s:3:"ko ";s:2:"24";s:3:"i s";s:2:"25";s:3:"a p";s:2:"26";s:3:"koj";s:2:"27";s:3:"pro";s:2:"28";s:3:"ju ";s:2:"29";s:3:"se ";s:2:"30";s:3:" go";s:2:"31";s:3:"ost";s:2:"32";s:3:"to ";s:2:"33";s:3:"va ";s:2:"34";s:3:" do";s:2:"35";s:3:" to";s:2:"36";s:3:"e n";s:2:"37";s:3:"i p";s:2:"38";s:3:" od";s:2:"39";s:3:" ra";s:2:"40";s:3:"no ";s:2:"41";s:3:"ako";s:2:"42";s:3:"ka ";s:2:"43";s:3:"ni ";s:2:"44";s:3:" ka";s:2:"45";s:3:" se";s:2:"46";s:3:" mo";s:2:"47";s:3:" st";s:2:"48";s:3:"i n";s:2:"49";s:3:"ima";s:2:"50";s:3:"ja ";s:2:"51";s:3:"pri";s:2:"52";s:3:"vat";s:2:"53";s:3:"sta";s:2:"54";s:3:" su";s:2:"55";s:3:"ati";s:2:"56";s:3:"e p";s:2:"57";s:3:"ta ";s:2:"58";s:3:"tsk";s:2:"59";s:3:"e i";s:2:"60";s:3:"nij";s:2:"61";s:3:" tr";s:2:"62";s:3:"cij";s:2:"63";s:3:"jen";s:2:"64";s:3:"nos";s:2:"65";s:3:"o s";s:2:"66";s:3:" iz";s:2:"67";s:3:"om ";s:2:"68";s:3:"tro";s:2:"69";s:3:"ili";s:2:"70";s:3:"iti";s:2:"71";s:3:"pos";s:2:"72";s:3:" al";s:2:"73";s:3:"a i";s:2:"74";s:3:"a o";s:2:"75";s:3:"e s";s:2:"76";s:3:"ija";s:2:"77";s:3:"ini";s:2:"78";s:3:"pre";s:2:"79";s:3:"str";s:2:"80";s:3:"la ";s:2:"81";s:3:"og ";s:2:"82";s:3:"ovo";s:2:"83";s:3:" sv";s:2:"84";s:3:"ekt";s:2:"85";s:3:"nje";s:2:"86";s:3:"o p";s:2:"87";s:3:"odi";s:2:"88";s:3:"rva";s:2:"89";s:3:" ni";s:2:"90";s:3:"ali";s:2:"91";s:3:"min";s:2:"92";s:3:"rij";s:2:"93";s:3:"a t";s:2:"94";s:3:"a z";s:2:"95";s:3:"ats";s:2:"96";s:3:"iva";s:2:"97";s:3:"o t";s:2:"98";s:3:"od ";s:2:"99";s:3:"oje";s:3:"100";s:3:"ra ";s:3:"101";s:3:" hr";s:3:"102";s:3:"a m";s:3:"103";s:3:"a u";s:3:"104";s:3:"hrv";s:3:"105";s:3:"im ";s:3:"106";s:3:"ke ";s:3:"107";s:3:"o i";s:3:"108";s:3:"ovi";s:3:"109";s:3:"red";s:3:"110";s:3:"riv";s:3:"111";s:3:"te ";s:3:"112";s:3:"bi ";s:3:"113";s:3:"e o";s:3:"114";s:3:"god";s:3:"115";s:3:"i d";s:3:"116";s:3:"lek";s:3:"117";s:3:"umi";s:3:"118";s:3:"zvo";s:3:"119";s:3:"din";s:3:"120";s:3:"e u";s:3:"121";s:3:"ene";s:3:"122";s:3:"jed";s:3:"123";s:3:"ji ";s:3:"124";s:3:"lje";s:3:"125";s:3:"nog";s:3:"126";s:3:"su ";s:3:"127";s:3:" a ";s:3:"128";s:3:" el";s:3:"129";s:3:" mi";s:3:"130";s:3:" o ";s:3:"131";s:3:"a d";s:3:"132";s:3:"alu";s:3:"133";s:3:"ele";s:3:"134";s:3:"i u";s:3:"135";s:3:"izv";s:3:"136";s:3:"ktr";s:3:"137";s:3:"lum";s:3:"138";s:3:"o d";s:3:"139";s:3:"ori";s:3:"140";s:3:"rad";s:3:"141";s:3:"sto";s:3:"142";s:3:"a k";s:3:"143";s:3:"anj";s:3:"144";s:3:"ava";s:3:"145";s:3:"e k";s:3:"146";s:3:"men";s:3:"147";s:3:"nic";s:3:"148";s:3:"o j";s:3:"149";s:3:"oj ";s:3:"150";s:3:"ove";s:3:"151";s:3:"ski";s:3:"152";s:3:"tvr";s:3:"153";s:3:"una";s:3:"154";s:3:"vor";s:3:"155";s:3:" di";s:3:"156";s:3:" no";s:3:"157";s:3:" s ";s:3:"158";s:3:" ta";s:3:"159";s:3:" tv";s:3:"160";s:3:"i i";s:3:"161";s:3:"i o";s:3:"162";s:3:"kak";s:3:"163";s:4:"roÅ¡";s:3:"164";s:3:"sko";s:3:"165";s:3:"vod";s:3:"166";s:3:" sa";s:3:"167";s:4:" će";s:3:"168";s:3:"a b";s:3:"169";s:3:"adi";s:3:"170";s:3:"amo";s:3:"171";s:3:"eni";s:3:"172";s:3:"gov";s:3:"173";s:3:"iju";s:3:"174";s:3:"ku ";s:3:"175";s:3:"o n";s:3:"176";s:3:"ora";s:3:"177";s:3:"rav";s:3:"178";s:3:"ruj";s:3:"179";s:3:"smo";s:3:"180";s:3:"tav";s:3:"181";s:3:"tru";s:3:"182";s:3:"u p";s:3:"183";s:3:"ve ";s:3:"184";s:3:" in";s:3:"185";s:3:" pl";s:3:"186";s:3:"aci";s:3:"187";s:3:"bit";s:3:"188";s:3:"de ";s:3:"189";s:4:"diÅ¡";s:3:"190";s:3:"ema";s:3:"191";s:3:"i m";s:3:"192";s:3:"ika";s:3:"193";s:4:"iÅ¡t";s:3:"194";s:3:"jer";s:3:"195";s:3:"ki ";s:3:"196";s:3:"mog";s:3:"197";s:3:"nik";s:3:"198";s:3:"nov";s:3:"199";s:3:"nu ";s:3:"200";s:3:"oji";s:3:"201";s:3:"oli";s:3:"202";s:3:"pla";s:3:"203";s:3:"pod";s:3:"204";s:3:"st ";s:3:"205";s:3:"sti";s:3:"206";s:3:"tra";s:3:"207";s:3:"tre";s:3:"208";s:3:"vo ";s:3:"209";s:3:" sm";s:3:"210";s:4:" Å¡t";s:3:"211";s:3:"dan";s:3:"212";s:3:"e z";s:3:"213";s:3:"i t";s:3:"214";s:3:"io ";s:3:"215";s:3:"ist";s:3:"216";s:3:"kon";s:3:"217";s:3:"lo ";s:3:"218";s:3:"stv";s:3:"219";s:3:"u s";s:3:"220";s:3:"uje";s:3:"221";s:3:"ust";s:3:"222";s:4:"će ";s:3:"223";s:4:"ći ";s:3:"224";s:4:"Å¡to";s:3:"225";s:3:" dr";s:3:"226";s:3:" im";s:3:"227";s:3:" li";s:3:"228";s:3:"ada";s:3:"229";s:3:"aft";s:3:"230";s:3:"ani";s:3:"231";s:3:"ao ";s:3:"232";s:3:"ars";s:3:"233";s:3:"ata";s:3:"234";s:3:"e t";s:3:"235";s:3:"emo";s:3:"236";s:3:"i k";s:3:"237";s:3:"ine";s:3:"238";s:3:"jem";s:3:"239";s:3:"kov";s:3:"240";s:3:"lik";s:3:"241";s:3:"lji";s:3:"242";s:3:"mje";s:3:"243";s:3:"naf";s:3:"244";s:3:"ner";s:3:"245";s:3:"nih";s:3:"246";s:3:"nja";s:3:"247";s:3:"ogo";s:3:"248";s:3:"oiz";s:3:"249";s:3:"ome";s:3:"250";s:3:"pot";s:3:"251";s:3:"ran";s:3:"252";s:3:"ri ";s:3:"253";s:3:"roi";s:3:"254";s:3:"rtk";s:3:"255";s:3:"ska";s:3:"256";s:3:"ter";s:3:"257";s:3:"u i";s:3:"258";s:3:"u o";s:3:"259";s:3:"vi ";s:3:"260";s:3:"vrt";s:3:"261";s:3:" me";s:3:"262";s:3:" ug";s:3:"263";s:3:"ak ";s:3:"264";s:3:"ama";s:3:"265";s:4:"drž";s:3:"266";s:3:"e e";s:3:"267";s:3:"e g";s:3:"268";s:3:"e m";s:3:"269";s:3:"em ";s:3:"270";s:3:"eme";s:3:"271";s:3:"enj";s:3:"272";s:3:"ent";s:3:"273";s:3:"er ";s:3:"274";s:3:"ere";s:3:"275";s:3:"erg";s:3:"276";s:3:"eur";s:3:"277";s:3:"go ";s:3:"278";s:3:"i b";s:3:"279";s:3:"i z";s:3:"280";s:3:"jet";s:3:"281";s:3:"ksi";s:3:"282";s:3:"o u";s:3:"283";s:3:"oda";s:3:"284";s:3:"ona";s:3:"285";s:3:"pra";s:3:"286";s:3:"reb";s:3:"287";s:3:"rem";s:3:"288";s:3:"rop";s:3:"289";s:3:"tri";s:3:"290";s:4:"žav";s:3:"291";s:3:" ci";s:3:"292";s:3:" eu";s:3:"293";s:3:" re";s:3:"294";s:3:" te";s:3:"295";s:3:" uv";s:3:"296";s:3:" ve";s:3:"297";s:3:"aju";s:3:"298";s:3:"an ";s:3:"299";}s:5:"czech";a:300:{s:3:" pr";s:1:"0";s:3:" po";s:1:"1";s:4:"ní ";s:1:"2";s:3:"pro";s:1:"3";s:3:" na";s:1:"4";s:3:"na ";s:1:"5";s:4:" pÅ™";s:1:"6";s:3:"ch ";s:1:"7";s:3:" je";s:1:"8";s:3:" ne";s:1:"9";s:4:"že ";s:2:"10";s:4:" že";s:2:"11";s:3:" se";s:2:"12";s:3:" do";s:2:"13";s:3:" ro";s:2:"14";s:3:" st";s:2:"15";s:3:" v ";s:2:"16";s:3:" ve";s:2:"17";s:4:"pÅ™e";s:2:"18";s:3:"se ";s:2:"19";s:3:"ho ";s:2:"20";s:3:"sta";s:2:"21";s:3:" to";s:2:"22";s:3:" vy";s:2:"23";s:3:" za";s:2:"24";s:3:"ou ";s:2:"25";s:3:" a ";s:2:"26";s:3:"to ";s:2:"27";s:3:" by";s:2:"28";s:3:"la ";s:2:"29";s:3:"ce ";s:2:"30";s:3:"e v";s:2:"31";s:3:"ist";s:2:"32";s:3:"le ";s:2:"33";s:3:"pod";s:2:"34";s:4:"í p";s:2:"35";s:3:" vl";s:2:"36";s:3:"e n";s:2:"37";s:3:"e s";s:2:"38";s:3:"je ";s:2:"39";s:4:"ké ";s:2:"40";s:3:"by ";s:2:"41";s:3:"em ";s:2:"42";s:4:"ých";s:2:"43";s:3:" od";s:2:"44";s:3:"ova";s:2:"45";s:4:"Å™ed";s:2:"46";s:3:"dy ";s:2:"47";s:4:"ení";s:2:"48";s:3:"kon";s:2:"49";s:3:"li ";s:2:"50";s:4:"nÄ› ";s:2:"51";s:3:"str";s:2:"52";s:4:" zá";s:2:"53";s:3:"ve ";s:2:"54";s:3:" ka";s:2:"55";s:3:" sv";s:2:"56";s:3:"e p";s:2:"57";s:3:"it ";s:2:"58";s:4:"lád";s:2:"59";s:3:"oho";s:2:"60";s:3:"rov";s:2:"61";s:3:"roz";s:2:"62";s:3:"ter";s:2:"63";s:4:"vlá";s:2:"64";s:4:"ím ";s:2:"65";s:3:" ko";s:2:"66";s:3:"hod";s:2:"67";s:3:"nis";s:2:"68";s:5:"pří";s:2:"69";s:4:"ský";s:2:"70";s:3:" mi";s:2:"71";s:3:" ob";s:2:"72";s:3:" so";s:2:"73";s:3:"a p";s:2:"74";s:3:"ali";s:2:"75";s:3:"bud";s:2:"76";s:3:"edn";s:2:"77";s:3:"ick";s:2:"78";s:3:"kte";s:2:"79";s:3:"ku ";s:2:"80";s:3:"o s";s:2:"81";s:3:"al ";s:2:"82";s:3:"ci ";s:2:"83";s:3:"e t";s:2:"84";s:3:"il ";s:2:"85";s:3:"ny ";s:2:"86";s:4:"né ";s:2:"87";s:3:"odl";s:2:"88";s:4:"ová";s:2:"89";s:3:"rot";s:2:"90";s:3:"sou";s:2:"91";s:5:"ání";s:2:"92";s:3:" bu";s:2:"93";s:3:" mo";s:2:"94";s:3:" o ";s:2:"95";s:3:"ast";s:2:"96";s:3:"byl";s:2:"97";s:3:"de ";s:2:"98";s:3:"ek ";s:2:"99";s:3:"ost";s:3:"100";s:4:" mí";s:3:"101";s:3:" ta";s:3:"102";s:3:"es ";s:3:"103";s:3:"jed";s:3:"104";s:3:"ky ";s:3:"105";s:3:"las";s:3:"106";s:3:"m p";s:3:"107";s:3:"nes";s:3:"108";s:4:"ním";s:3:"109";s:3:"ran";s:3:"110";s:3:"rem";s:3:"111";s:3:"ros";s:3:"112";s:4:"ého";s:3:"113";s:3:" de";s:3:"114";s:3:" kt";s:3:"115";s:3:" ni";s:3:"116";s:3:" si";s:3:"117";s:4:" vý";s:3:"118";s:3:"at ";s:3:"119";s:4:"jí ";s:3:"120";s:4:"ký ";s:3:"121";s:3:"mi ";s:3:"122";s:3:"pre";s:3:"123";s:3:"tak";s:3:"124";s:3:"tan";s:3:"125";s:3:"y v";s:3:"126";s:4:"Å™ek";s:3:"127";s:3:" ch";s:3:"128";s:3:" li";s:3:"129";s:4:" ná";s:3:"130";s:3:" pa";s:3:"131";s:4:" Å™e";s:3:"132";s:3:"da ";s:3:"133";s:3:"dle";s:3:"134";s:3:"dne";s:3:"135";s:3:"i p";s:3:"136";s:3:"i v";s:3:"137";s:3:"ly ";s:3:"138";s:3:"min";s:3:"139";s:3:"o n";s:3:"140";s:3:"o v";s:3:"141";s:3:"pol";s:3:"142";s:3:"tra";s:3:"143";s:3:"val";s:3:"144";s:4:"vní";s:3:"145";s:4:"ích";s:3:"146";s:4:"ý p";s:3:"147";s:4:"Å™ej";s:3:"148";s:3:" ce";s:3:"149";s:3:" kd";s:3:"150";s:3:" le";s:3:"151";s:3:"a s";s:3:"152";s:3:"a z";s:3:"153";s:3:"cen";s:3:"154";s:3:"e k";s:3:"155";s:3:"eds";s:3:"156";s:3:"ekl";s:3:"157";s:3:"emi";s:3:"158";s:3:"kl ";s:3:"159";s:3:"lat";s:3:"160";s:3:"lo ";s:3:"161";s:4:"mié";s:3:"162";s:3:"nov";s:3:"163";s:3:"pra";s:3:"164";s:3:"sku";s:3:"165";s:4:"ské";s:3:"166";s:3:"sti";s:3:"167";s:3:"tav";s:3:"168";s:3:"ti ";s:3:"169";s:3:"ty ";s:3:"170";s:4:"ván";s:3:"171";s:4:"vé ";s:3:"172";s:3:"y n";s:3:"173";s:3:"y s";s:3:"174";s:4:"í s";s:3:"175";s:4:"í v";s:3:"176";s:4:"Ä› p";s:3:"177";s:3:" dn";s:3:"178";s:4:" nÄ›";s:3:"179";s:3:" sp";s:3:"180";s:4:" Äs";s:3:"181";s:3:"a n";s:3:"182";s:3:"a t";s:3:"183";s:3:"ak ";s:3:"184";s:4:"dní";s:3:"185";s:3:"doh";s:3:"186";s:3:"e b";s:3:"187";s:3:"e m";s:3:"188";s:3:"ejn";s:3:"189";s:3:"ena";s:3:"190";s:3:"est";s:3:"191";s:3:"ini";s:3:"192";s:3:"m z";s:3:"193";s:3:"nal";s:3:"194";s:3:"nou";s:3:"195";s:4:"ná ";s:3:"196";s:3:"ovi";s:3:"197";s:4:"ové";s:3:"198";s:4:"ový";s:3:"199";s:3:"rsk";s:3:"200";s:4:"stá";s:3:"201";s:4:"tí ";s:3:"202";s:4:"tÅ™e";s:3:"203";s:4:"tů ";s:3:"204";s:3:"ude";s:3:"205";s:3:"za ";s:3:"206";s:4:"é p";s:3:"207";s:4:"ém ";s:3:"208";s:4:"í d";s:3:"209";s:3:" ir";s:3:"210";s:3:" zv";s:3:"211";s:3:"ale";s:3:"212";s:4:"anÄ›";s:3:"213";s:3:"ave";s:3:"214";s:4:"cké";s:3:"215";s:3:"den";s:3:"216";s:3:"e z";s:3:"217";s:3:"ech";s:3:"218";s:3:"en ";s:3:"219";s:4:"erý";s:3:"220";s:3:"hla";s:3:"221";s:3:"i s";s:3:"222";s:4:"iér";s:3:"223";s:3:"lov";s:3:"224";s:3:"mu ";s:3:"225";s:3:"neb";s:3:"226";s:3:"nic";s:3:"227";s:3:"o b";s:3:"228";s:3:"o m";s:3:"229";s:3:"pad";s:3:"230";s:3:"pot";s:3:"231";s:3:"rav";s:3:"232";s:3:"rop";s:3:"233";s:4:"rý ";s:3:"234";s:3:"sed";s:3:"235";s:3:"si ";s:3:"236";s:3:"t p";s:3:"237";s:3:"tic";s:3:"238";s:3:"tu ";s:3:"239";s:4:"tÄ› ";s:3:"240";s:3:"u p";s:3:"241";s:3:"u v";s:3:"242";s:4:"vá ";s:3:"243";s:5:"výš";s:3:"244";s:4:"zvý";s:3:"245";s:5:"Äní";s:3:"246";s:5:"ří ";s:3:"247";s:4:"ům ";s:3:"248";s:3:" bl";s:3:"249";s:3:" br";s:3:"250";s:3:" ho";s:3:"251";s:3:" ja";s:3:"252";s:3:" re";s:3:"253";s:3:" s ";s:3:"254";s:3:" z ";s:3:"255";s:3:" zd";s:3:"256";s:3:"a v";s:3:"257";s:3:"ani";s:3:"258";s:3:"ato";s:3:"259";s:3:"bla";s:3:"260";s:3:"bri";s:3:"261";s:4:"eÄn";s:3:"262";s:4:"eÅ™e";s:3:"263";s:3:"h v";s:3:"264";s:3:"i n";s:3:"265";s:3:"ie ";s:3:"266";s:3:"ila";s:3:"267";s:3:"irs";s:3:"268";s:3:"ite";s:3:"269";s:3:"kov";s:3:"270";s:3:"nos";s:3:"271";s:3:"o o";s:3:"272";s:3:"o p";s:3:"273";s:3:"oce";s:3:"274";s:3:"ody";s:3:"275";s:3:"ohl";s:3:"276";s:3:"oli";s:3:"277";s:3:"ovo";s:3:"278";s:3:"pla";s:3:"279";s:4:"poÄ";s:3:"280";s:4:"prá";s:3:"281";s:3:"ra ";s:3:"282";s:3:"rit";s:3:"283";s:3:"rod";s:3:"284";s:3:"ry ";s:3:"285";s:3:"sd ";s:3:"286";s:3:"sko";s:3:"287";s:3:"ssd";s:3:"288";s:3:"tel";s:3:"289";s:3:"u s";s:3:"290";s:3:"vat";s:3:"291";s:4:"veÅ™";s:3:"292";s:3:"vit";s:3:"293";s:3:"vla";s:3:"294";s:3:"y p";s:3:"295";s:4:"áln";s:3:"296";s:4:"Äss";s:3:"297";s:4:"Å¡en";s:3:"298";s:3:" al";s:3:"299";}s:6:"danish";a:300:{s:3:"er ";s:1:"0";s:3:"en ";s:1:"1";s:3:" de";s:1:"2";s:3:"et ";s:1:"3";s:3:"der";s:1:"4";s:3:"de ";s:1:"5";s:3:"for";s:1:"6";s:3:" fo";s:1:"7";s:3:" i ";s:1:"8";s:3:"at ";s:1:"9";s:3:" at";s:2:"10";s:3:"re ";s:2:"11";s:3:"det";s:2:"12";s:3:" ha";s:2:"13";s:3:"nde";s:2:"14";s:3:"ere";s:2:"15";s:3:"ing";s:2:"16";s:3:"den";s:2:"17";s:3:" me";s:2:"18";s:3:" og";s:2:"19";s:3:"ger";s:2:"20";s:3:"ter";s:2:"21";s:3:" er";s:2:"22";s:3:" si";s:2:"23";s:3:"and";s:2:"24";s:3:" af";s:2:"25";s:3:"or ";s:2:"26";s:3:" st";s:2:"27";s:3:" ti";s:2:"28";s:3:" en";s:2:"29";s:3:"og ";s:2:"30";s:3:"ar ";s:2:"31";s:3:"il ";s:2:"32";s:3:"r s";s:2:"33";s:3:"ige";s:2:"34";s:3:"til";s:2:"35";s:3:"ke ";s:2:"36";s:3:"r e";s:2:"37";s:3:"af ";s:2:"38";s:3:"kke";s:2:"39";s:3:" ma";s:2:"40";s:4:" pÃ¥";s:2:"41";s:3:"om ";s:2:"42";s:4:"pÃ¥ ";s:2:"43";s:3:"ed ";s:2:"44";s:3:"ge ";s:2:"45";s:3:"end";s:2:"46";s:3:"nge";s:2:"47";s:3:"t s";s:2:"48";s:3:"e s";s:2:"49";s:3:"ler";s:2:"50";s:3:" sk";s:2:"51";s:3:"els";s:2:"52";s:3:"ern";s:2:"53";s:3:"sig";s:2:"54";s:3:"ne ";s:2:"55";s:3:"lig";s:2:"56";s:3:"r d";s:2:"57";s:3:"ska";s:2:"58";s:3:" vi";s:2:"59";s:3:"har";s:2:"60";s:3:" be";s:2:"61";s:3:" se";s:2:"62";s:3:"an ";s:2:"63";s:3:"ikk";s:2:"64";s:3:"lle";s:2:"65";s:3:"gen";s:2:"66";s:3:"n f";s:2:"67";s:3:"ste";s:2:"68";s:3:"t a";s:2:"69";s:3:"t d";s:2:"70";s:3:"rin";s:2:"71";s:3:" ik";s:2:"72";s:3:"es ";s:2:"73";s:3:"ng ";s:2:"74";s:3:"ver";s:2:"75";s:3:"r b";s:2:"76";s:3:"sen";s:2:"77";s:3:"ede";s:2:"78";s:3:"men";s:2:"79";s:3:"r i";s:2:"80";s:3:" he";s:2:"81";s:3:" et";s:2:"82";s:3:"ig ";s:2:"83";s:3:"lan";s:2:"84";s:3:"med";s:2:"85";s:3:"nd ";s:2:"86";s:3:"rne";s:2:"87";s:3:" da";s:2:"88";s:3:" in";s:2:"89";s:3:"e t";s:2:"90";s:3:"mme";s:2:"91";s:3:"und";s:2:"92";s:3:" om";s:2:"93";s:3:"e e";s:2:"94";s:3:"e m";s:2:"95";s:3:"her";s:2:"96";s:3:"le ";s:2:"97";s:3:"r f";s:2:"98";s:3:"t f";s:2:"99";s:4:"sÃ¥ ";s:3:"100";s:3:"te ";s:3:"101";s:3:" so";s:3:"102";s:3:"ele";s:3:"103";s:3:"t e";s:3:"104";s:3:" ko";s:3:"105";s:3:"est";s:3:"106";s:3:"ske";s:3:"107";s:3:" bl";s:3:"108";s:3:"e f";s:3:"109";s:3:"ekt";s:3:"110";s:3:"mar";s:3:"111";s:3:"bru";s:3:"112";s:3:"e a";s:3:"113";s:3:"el ";s:3:"114";s:3:"ers";s:3:"115";s:3:"ret";s:3:"116";s:3:"som";s:3:"117";s:3:"tte";s:3:"118";s:3:"ve ";s:3:"119";s:3:" la";s:3:"120";s:3:" ud";s:3:"121";s:3:" ve";s:3:"122";s:3:"age";s:3:"123";s:3:"e d";s:3:"124";s:3:"e h";s:3:"125";s:3:"lse";s:3:"126";s:3:"man";s:3:"127";s:3:"rug";s:3:"128";s:3:"sel";s:3:"129";s:3:"ser";s:3:"130";s:3:" fi";s:3:"131";s:3:" op";s:3:"132";s:3:" pr";s:3:"133";s:3:"dt ";s:3:"134";s:3:"e i";s:3:"135";s:3:"n m";s:3:"136";s:3:"r m";s:3:"137";s:3:" an";s:3:"138";s:3:" re";s:3:"139";s:3:" sa";s:3:"140";s:3:"ion";s:3:"141";s:3:"ner";s:3:"142";s:3:"res";s:3:"143";s:3:"t i";s:3:"144";s:3:"get";s:3:"145";s:3:"n s";s:3:"146";s:3:"one";s:3:"147";s:3:"orb";s:3:"148";s:3:"t h";s:3:"149";s:3:"vis";s:3:"150";s:4:"Ã¥r ";s:3:"151";s:3:" fr";s:3:"152";s:3:"bil";s:3:"153";s:3:"e k";s:3:"154";s:3:"ens";s:3:"155";s:3:"ind";s:3:"156";s:3:"omm";s:3:"157";s:3:"t m";s:3:"158";s:3:" hv";s:3:"159";s:3:" je";s:3:"160";s:3:"dan";s:3:"161";s:3:"ent";s:3:"162";s:3:"fte";s:3:"163";s:3:"nin";s:3:"164";s:3:" mi";s:3:"165";s:3:"e o";s:3:"166";s:3:"e p";s:3:"167";s:3:"n o";s:3:"168";s:3:"nte";s:3:"169";s:3:" ku";s:3:"170";s:3:"ell";s:3:"171";s:3:"nas";s:3:"172";s:3:"ore";s:3:"173";s:3:"r h";s:3:"174";s:3:"r k";s:3:"175";s:3:"sta";s:3:"176";s:3:"sto";s:3:"177";s:3:"dag";s:3:"178";s:3:"eri";s:3:"179";s:3:"kun";s:3:"180";s:3:"lde";s:3:"181";s:3:"mer";s:3:"182";s:3:"r a";s:3:"183";s:3:"r v";s:3:"184";s:3:"rek";s:3:"185";s:3:"rer";s:3:"186";s:3:"t o";s:3:"187";s:3:"tor";s:3:"188";s:4:"tør";s:3:"189";s:4:" fÃ¥";s:3:"190";s:4:" mÃ¥";s:3:"191";s:3:" to";s:3:"192";s:3:"boe";s:3:"193";s:3:"che";s:3:"194";s:3:"e v";s:3:"195";s:3:"i d";s:3:"196";s:3:"ive";s:3:"197";s:3:"kab";s:3:"198";s:3:"ns ";s:3:"199";s:3:"oel";s:3:"200";s:3:"se ";s:3:"201";s:3:"t v";s:3:"202";s:3:" al";s:3:"203";s:3:" bo";s:3:"204";s:3:" un";s:3:"205";s:3:"ans";s:3:"206";s:3:"dre";s:3:"207";s:3:"ire";s:3:"208";s:4:"køb";s:3:"209";s:3:"ors";s:3:"210";s:3:"ove";s:3:"211";s:3:"ren";s:3:"212";s:3:"t b";s:3:"213";s:4:"ør ";s:3:"214";s:3:" ka";s:3:"215";s:3:"ald";s:3:"216";s:3:"bet";s:3:"217";s:3:"gt ";s:3:"218";s:3:"isk";s:3:"219";s:3:"kal";s:3:"220";s:3:"kom";s:3:"221";s:3:"lev";s:3:"222";s:3:"n d";s:3:"223";s:3:"n i";s:3:"224";s:3:"pri";s:3:"225";s:3:"r p";s:3:"226";s:3:"rbr";s:3:"227";s:4:"søg";s:3:"228";s:3:"tel";s:3:"229";s:4:" sÃ¥";s:3:"230";s:3:" te";s:3:"231";s:3:" va";s:3:"232";s:3:"al ";s:3:"233";s:3:"dir";s:3:"234";s:3:"eje";s:3:"235";s:3:"fis";s:3:"236";s:4:"gsÃ¥";s:3:"237";s:3:"isc";s:3:"238";s:3:"jer";s:3:"239";s:3:"ker";s:3:"240";s:3:"ogs";s:3:"241";s:3:"sch";s:3:"242";s:3:"st ";s:3:"243";s:3:"t k";s:3:"244";s:3:"uge";s:3:"245";s:3:" di";s:3:"246";s:3:"ag ";s:3:"247";s:3:"d a";s:3:"248";s:3:"g i";s:3:"249";s:3:"ill";s:3:"250";s:3:"l a";s:3:"251";s:3:"lsk";s:3:"252";s:3:"n a";s:3:"253";s:3:"on ";s:3:"254";s:3:"sam";s:3:"255";s:3:"str";s:3:"256";s:3:"tet";s:3:"257";s:3:"var";s:3:"258";s:3:" mo";s:3:"259";s:3:"art";s:3:"260";s:3:"ash";s:3:"261";s:3:"att";s:3:"262";s:3:"e b";s:3:"263";s:3:"han";s:3:"264";s:3:"hav";s:3:"265";s:3:"kla";s:3:"266";s:3:"kon";s:3:"267";s:3:"n t";s:3:"268";s:3:"ned";s:3:"269";s:3:"r o";s:3:"270";s:3:"ra ";s:3:"271";s:3:"rre";s:3:"272";s:3:"ves";s:3:"273";s:3:"vil";s:3:"274";s:3:" el";s:3:"275";s:3:" kr";s:3:"276";s:3:" ov";s:3:"277";s:3:"ann";s:3:"278";s:3:"e u";s:3:"279";s:3:"ess";s:3:"280";s:3:"fra";s:3:"281";s:3:"g a";s:3:"282";s:3:"g d";s:3:"283";s:3:"int";s:3:"284";s:3:"ngs";s:3:"285";s:3:"rde";s:3:"286";s:3:"tra";s:3:"287";s:4:" Ã¥r";s:3:"288";s:3:"akt";s:3:"289";s:3:"asi";s:3:"290";s:3:"em ";s:3:"291";s:3:"gel";s:3:"292";s:3:"gym";s:3:"293";s:3:"hol";s:3:"294";s:3:"kan";s:3:"295";s:3:"mna";s:3:"296";s:3:"n h";s:3:"297";s:3:"nsk";s:3:"298";s:3:"old";s:3:"299";}s:5:"dutch";a:300:{s:3:"en ";s:1:"0";s:3:"de ";s:1:"1";s:3:" de";s:1:"2";s:3:"et ";s:1:"3";s:3:"an ";s:1:"4";s:3:" he";s:1:"5";s:3:"er ";s:1:"6";s:3:" va";s:1:"7";s:3:"n d";s:1:"8";s:3:"van";s:1:"9";s:3:"een";s:2:"10";s:3:"het";s:2:"11";s:3:" ge";s:2:"12";s:3:"oor";s:2:"13";s:3:" ee";s:2:"14";s:3:"der";s:2:"15";s:3:" en";s:2:"16";s:3:"ij ";s:2:"17";s:3:"aar";s:2:"18";s:3:"gen";s:2:"19";s:3:"te ";s:2:"20";s:3:"ver";s:2:"21";s:3:" in";s:2:"22";s:3:" me";s:2:"23";s:3:"aan";s:2:"24";s:3:"den";s:2:"25";s:3:" we";s:2:"26";s:3:"at ";s:2:"27";s:3:"in ";s:2:"28";s:3:" da";s:2:"29";s:3:" te";s:2:"30";s:3:"eer";s:2:"31";s:3:"nde";s:2:"32";s:3:"ter";s:2:"33";s:3:"ste";s:2:"34";s:3:"n v";s:2:"35";s:3:" vo";s:2:"36";s:3:" zi";s:2:"37";s:3:"ing";s:2:"38";s:3:"n h";s:2:"39";s:3:"voo";s:2:"40";s:3:"is ";s:2:"41";s:3:" op";s:2:"42";s:3:"tie";s:2:"43";s:3:" aa";s:2:"44";s:3:"ede";s:2:"45";s:3:"erd";s:2:"46";s:3:"ers";s:2:"47";s:3:" be";s:2:"48";s:3:"eme";s:2:"49";s:3:"ten";s:2:"50";s:3:"ken";s:2:"51";s:3:"n e";s:2:"52";s:3:" ni";s:2:"53";s:3:" ve";s:2:"54";s:3:"ent";s:2:"55";s:3:"ijn";s:2:"56";s:3:"jn ";s:2:"57";s:3:"mee";s:2:"58";s:3:"iet";s:2:"59";s:3:"n w";s:2:"60";s:3:"ng ";s:2:"61";s:3:"nie";s:2:"62";s:3:" is";s:2:"63";s:3:"cht";s:2:"64";s:3:"dat";s:2:"65";s:3:"ere";s:2:"66";s:3:"ie ";s:2:"67";s:3:"ijk";s:2:"68";s:3:"n b";s:2:"69";s:3:"rde";s:2:"70";s:3:"ar ";s:2:"71";s:3:"e b";s:2:"72";s:3:"e a";s:2:"73";s:3:"met";s:2:"74";s:3:"t d";s:2:"75";s:3:"el ";s:2:"76";s:3:"ond";s:2:"77";s:3:"t h";s:2:"78";s:3:" al";s:2:"79";s:3:"e w";s:2:"80";s:3:"op ";s:2:"81";s:3:"ren";s:2:"82";s:3:" di";s:2:"83";s:3:" on";s:2:"84";s:3:"al ";s:2:"85";s:3:"and";s:2:"86";s:3:"bij";s:2:"87";s:3:"zij";s:2:"88";s:3:" bi";s:2:"89";s:3:" hi";s:2:"90";s:3:" wi";s:2:"91";s:3:"or ";s:2:"92";s:3:"r d";s:2:"93";s:3:"t v";s:2:"94";s:3:" wa";s:2:"95";s:3:"e h";s:2:"96";s:3:"lle";s:2:"97";s:3:"rt ";s:2:"98";s:3:"ang";s:2:"99";s:3:"hij";s:3:"100";s:3:"men";s:3:"101";s:3:"n a";s:3:"102";s:3:"n z";s:3:"103";s:3:"rs ";s:3:"104";s:3:" om";s:3:"105";s:3:"e o";s:3:"106";s:3:"e v";s:3:"107";s:3:"end";s:3:"108";s:3:"est";s:3:"109";s:3:"n t";s:3:"110";s:3:"par";s:3:"111";s:3:" pa";s:3:"112";s:3:" pr";s:3:"113";s:3:" ze";s:3:"114";s:3:"e g";s:3:"115";s:3:"e p";s:3:"116";s:3:"n p";s:3:"117";s:3:"ord";s:3:"118";s:3:"oud";s:3:"119";s:3:"raa";s:3:"120";s:3:"sch";s:3:"121";s:3:"t e";s:3:"122";s:3:"ege";s:3:"123";s:3:"ich";s:3:"124";s:3:"ien";s:3:"125";s:3:"aat";s:3:"126";s:3:"ek ";s:3:"127";s:3:"len";s:3:"128";s:3:"n m";s:3:"129";s:3:"nge";s:3:"130";s:3:"nt ";s:3:"131";s:3:"ove";s:3:"132";s:3:"rd ";s:3:"133";s:3:"wer";s:3:"134";s:3:" ma";s:3:"135";s:3:" mi";s:3:"136";s:3:"daa";s:3:"137";s:3:"e k";s:3:"138";s:3:"lij";s:3:"139";s:3:"mer";s:3:"140";s:3:"n g";s:3:"141";s:3:"n o";s:3:"142";s:3:"om ";s:3:"143";s:3:"sen";s:3:"144";s:3:"t b";s:3:"145";s:3:"wij";s:3:"146";s:3:" ho";s:3:"147";s:3:"e m";s:3:"148";s:3:"ele";s:3:"149";s:3:"gem";s:3:"150";s:3:"heb";s:3:"151";s:3:"pen";s:3:"152";s:3:"ude";s:3:"153";s:3:" bo";s:3:"154";s:3:" ja";s:3:"155";s:3:"die";s:3:"156";s:3:"e e";s:3:"157";s:3:"eli";s:3:"158";s:3:"erk";s:3:"159";s:3:"le ";s:3:"160";s:3:"pro";s:3:"161";s:3:"rij";s:3:"162";s:3:" er";s:3:"163";s:3:" za";s:3:"164";s:3:"e d";s:3:"165";s:3:"ens";s:3:"166";s:3:"ind";s:3:"167";s:3:"ke ";s:3:"168";s:3:"n k";s:3:"169";s:3:"nd ";s:3:"170";s:3:"nen";s:3:"171";s:3:"nte";s:3:"172";s:3:"r h";s:3:"173";s:3:"s d";s:3:"174";s:3:"s e";s:3:"175";s:3:"t z";s:3:"176";s:3:" b ";s:3:"177";s:3:" co";s:3:"178";s:3:" ik";s:3:"179";s:3:" ko";s:3:"180";s:3:" ov";s:3:"181";s:3:"eke";s:3:"182";s:3:"hou";s:3:"183";s:3:"ik ";s:3:"184";s:3:"iti";s:3:"185";s:3:"lan";s:3:"186";s:3:"ns ";s:3:"187";s:3:"t g";s:3:"188";s:3:"t m";s:3:"189";s:3:" do";s:3:"190";s:3:" le";s:3:"191";s:3:" zo";s:3:"192";s:3:"ams";s:3:"193";s:3:"e z";s:3:"194";s:3:"g v";s:3:"195";s:3:"it ";s:3:"196";s:3:"je ";s:3:"197";s:3:"ls ";s:3:"198";s:3:"maa";s:3:"199";s:3:"n i";s:3:"200";s:3:"nke";s:3:"201";s:3:"rke";s:3:"202";s:3:"uit";s:3:"203";s:3:" ha";s:3:"204";s:3:" ka";s:3:"205";s:3:" mo";s:3:"206";s:3:" re";s:3:"207";s:3:" st";s:3:"208";s:3:" to";s:3:"209";s:3:"age";s:3:"210";s:3:"als";s:3:"211";s:3:"ark";s:3:"212";s:3:"art";s:3:"213";s:3:"ben";s:3:"214";s:3:"e r";s:3:"215";s:3:"e s";s:3:"216";s:3:"ert";s:3:"217";s:3:"eze";s:3:"218";s:3:"ht ";s:3:"219";s:3:"ijd";s:3:"220";s:3:"lem";s:3:"221";s:3:"r v";s:3:"222";s:3:"rte";s:3:"223";s:3:"t p";s:3:"224";s:3:"zeg";s:3:"225";s:3:"zic";s:3:"226";s:3:"aak";s:3:"227";s:3:"aal";s:3:"228";s:3:"ag ";s:3:"229";s:3:"ale";s:3:"230";s:3:"bbe";s:3:"231";s:3:"ch ";s:3:"232";s:3:"e t";s:3:"233";s:3:"ebb";s:3:"234";s:3:"erz";s:3:"235";s:3:"ft ";s:3:"236";s:3:"ge ";s:3:"237";s:3:"led";s:3:"238";s:3:"mst";s:3:"239";s:3:"n n";s:3:"240";s:3:"oek";s:3:"241";s:3:"r i";s:3:"242";s:3:"t o";s:3:"243";s:3:"t w";s:3:"244";s:3:"tel";s:3:"245";s:3:"tte";s:3:"246";s:3:"uur";s:3:"247";s:3:"we ";s:3:"248";s:3:"zit";s:3:"249";s:3:" af";s:3:"250";s:3:" li";s:3:"251";s:3:" ui";s:3:"252";s:3:"ak ";s:3:"253";s:3:"all";s:3:"254";s:3:"aut";s:3:"255";s:3:"doo";s:3:"256";s:3:"e i";s:3:"257";s:3:"ene";s:3:"258";s:3:"erg";s:3:"259";s:3:"ete";s:3:"260";s:3:"ges";s:3:"261";s:3:"hee";s:3:"262";s:3:"jaa";s:3:"263";s:3:"jke";s:3:"264";s:3:"kee";s:3:"265";s:3:"kel";s:3:"266";s:3:"kom";s:3:"267";s:3:"lee";s:3:"268";s:3:"moe";s:3:"269";s:3:"n s";s:3:"270";s:3:"ort";s:3:"271";s:3:"rec";s:3:"272";s:3:"s o";s:3:"273";s:3:"s v";s:3:"274";s:3:"teg";s:3:"275";s:3:"tij";s:3:"276";s:3:"ven";s:3:"277";s:3:"waa";s:3:"278";s:3:"wel";s:3:"279";s:3:" an";s:3:"280";s:3:" au";s:3:"281";s:3:" bu";s:3:"282";s:3:" gr";s:3:"283";s:3:" pl";s:3:"284";s:3:" ti";s:3:"285";s:3:"'' ";s:3:"286";s:3:"ade";s:3:"287";s:3:"dag";s:3:"288";s:3:"e l";s:3:"289";s:3:"ech";s:3:"290";s:3:"eel";s:3:"291";s:3:"eft";s:3:"292";s:3:"ger";s:3:"293";s:3:"gt ";s:3:"294";s:3:"ig ";s:3:"295";s:3:"itt";s:3:"296";s:3:"j d";s:3:"297";s:3:"ppe";s:3:"298";s:3:"rda";s:3:"299";}s:7:"english";a:300:{s:3:" th";s:1:"0";s:3:"the";s:1:"1";s:3:"he ";s:1:"2";s:3:"ed ";s:1:"3";s:3:" to";s:1:"4";s:3:" in";s:1:"5";s:3:"er ";s:1:"6";s:3:"ing";s:1:"7";s:3:"ng ";s:1:"8";s:3:" an";s:1:"9";s:3:"nd ";s:2:"10";s:3:" of";s:2:"11";s:3:"and";s:2:"12";s:3:"to ";s:2:"13";s:3:"of ";s:2:"14";s:3:" co";s:2:"15";s:3:"at ";s:2:"16";s:3:"on ";s:2:"17";s:3:"in ";s:2:"18";s:3:" a ";s:2:"19";s:3:"d t";s:2:"20";s:3:" he";s:2:"21";s:3:"e t";s:2:"22";s:3:"ion";s:2:"23";s:3:"es ";s:2:"24";s:3:" re";s:2:"25";s:3:"re ";s:2:"26";s:3:"hat";s:2:"27";s:3:" sa";s:2:"28";s:3:" st";s:2:"29";s:3:" ha";s:2:"30";s:3:"her";s:2:"31";s:3:"tha";s:2:"32";s:3:"tio";s:2:"33";s:3:"or ";s:2:"34";s:3:" ''";s:2:"35";s:3:"en ";s:2:"36";s:3:" wh";s:2:"37";s:3:"e s";s:2:"38";s:3:"ent";s:2:"39";s:3:"n t";s:2:"40";s:3:"s a";s:2:"41";s:3:"as ";s:2:"42";s:3:"for";s:2:"43";s:3:"is ";s:2:"44";s:3:"t t";s:2:"45";s:3:" be";s:2:"46";s:3:"ld ";s:2:"47";s:3:"e a";s:2:"48";s:3:"rs ";s:2:"49";s:3:" wa";s:2:"50";s:3:"ut ";s:2:"51";s:3:"ve ";s:2:"52";s:3:"ll ";s:2:"53";s:3:"al ";s:2:"54";s:3:" ma";s:2:"55";s:3:"e i";s:2:"56";s:3:" fo";s:2:"57";s:3:"'s ";s:2:"58";s:3:"an ";s:2:"59";s:3:"est";s:2:"60";s:3:" hi";s:2:"61";s:3:" mo";s:2:"62";s:3:" se";s:2:"63";s:3:" pr";s:2:"64";s:3:"s t";s:2:"65";s:3:"ate";s:2:"66";s:3:"st ";s:2:"67";s:3:"ter";s:2:"68";s:3:"ere";s:2:"69";s:3:"ted";s:2:"70";s:3:"nt ";s:2:"71";s:3:"ver";s:2:"72";s:3:"d a";s:2:"73";s:3:" wi";s:2:"74";s:3:"se ";s:2:"75";s:3:"e c";s:2:"76";s:3:"ect";s:2:"77";s:3:"ns ";s:2:"78";s:3:" on";s:2:"79";s:3:"ly ";s:2:"80";s:3:"tol";s:2:"81";s:3:"ey ";s:2:"82";s:3:"r t";s:2:"83";s:3:" ca";s:2:"84";s:3:"ati";s:2:"85";s:3:"ts ";s:2:"86";s:3:"all";s:2:"87";s:3:" no";s:2:"88";s:3:"his";s:2:"89";s:3:"s o";s:2:"90";s:3:"ers";s:2:"91";s:3:"con";s:2:"92";s:3:"e o";s:2:"93";s:3:"ear";s:2:"94";s:3:"f t";s:2:"95";s:3:"e w";s:2:"96";s:3:"was";s:2:"97";s:3:"ons";s:2:"98";s:3:"sta";s:2:"99";s:3:"'' ";s:3:"100";s:3:"sti";s:3:"101";s:3:"n a";s:3:"102";s:3:"sto";s:3:"103";s:3:"t h";s:3:"104";s:3:" we";s:3:"105";s:3:"id ";s:3:"106";s:3:"th ";s:3:"107";s:3:" it";s:3:"108";s:3:"ce ";s:3:"109";s:3:" di";s:3:"110";s:3:"ave";s:3:"111";s:3:"d h";s:3:"112";s:3:"cou";s:3:"113";s:3:"pro";s:3:"114";s:3:"ad ";s:3:"115";s:3:"oll";s:3:"116";s:3:"ry ";s:3:"117";s:3:"d s";s:3:"118";s:3:"e m";s:3:"119";s:3:" so";s:3:"120";s:3:"ill";s:3:"121";s:3:"cti";s:3:"122";s:3:"te ";s:3:"123";s:3:"tor";s:3:"124";s:3:"eve";s:3:"125";s:3:"g t";s:3:"126";s:3:"it ";s:3:"127";s:3:" ch";s:3:"128";s:3:" de";s:3:"129";s:3:"hav";s:3:"130";s:3:"oul";s:3:"131";s:3:"ty ";s:3:"132";s:3:"uld";s:3:"133";s:3:"use";s:3:"134";s:3:" al";s:3:"135";s:3:"are";s:3:"136";s:3:"ch ";s:3:"137";s:3:"me ";s:3:"138";s:3:"out";s:3:"139";s:3:"ove";s:3:"140";s:3:"wit";s:3:"141";s:3:"ys ";s:3:"142";s:3:"chi";s:3:"143";s:3:"t a";s:3:"144";s:3:"ith";s:3:"145";s:3:"oth";s:3:"146";s:3:" ab";s:3:"147";s:3:" te";s:3:"148";s:3:" wo";s:3:"149";s:3:"s s";s:3:"150";s:3:"res";s:3:"151";s:3:"t w";s:3:"152";s:3:"tin";s:3:"153";s:3:"e b";s:3:"154";s:3:"e h";s:3:"155";s:3:"nce";s:3:"156";s:3:"t s";s:3:"157";s:3:"y t";s:3:"158";s:3:"e p";s:3:"159";s:3:"ele";s:3:"160";s:3:"hin";s:3:"161";s:3:"s i";s:3:"162";s:3:"nte";s:3:"163";s:3:" li";s:3:"164";s:3:"le ";s:3:"165";s:3:" do";s:3:"166";s:3:"aid";s:3:"167";s:3:"hey";s:3:"168";s:3:"ne ";s:3:"169";s:3:"s w";s:3:"170";s:3:" as";s:3:"171";s:3:" fr";s:3:"172";s:3:" tr";s:3:"173";s:3:"end";s:3:"174";s:3:"sai";s:3:"175";s:3:" el";s:3:"176";s:3:" ne";s:3:"177";s:3:" su";s:3:"178";s:3:"'t ";s:3:"179";s:3:"ay ";s:3:"180";s:3:"hou";s:3:"181";s:3:"ive";s:3:"182";s:3:"lec";s:3:"183";s:3:"n't";s:3:"184";s:3:" ye";s:3:"185";s:3:"but";s:3:"186";s:3:"d o";s:3:"187";s:3:"o t";s:3:"188";s:3:"y o";s:3:"189";s:3:" ho";s:3:"190";s:3:" me";s:3:"191";s:3:"be ";s:3:"192";s:3:"cal";s:3:"193";s:3:"e e";s:3:"194";s:3:"had";s:3:"195";s:3:"ple";s:3:"196";s:3:" at";s:3:"197";s:3:" bu";s:3:"198";s:3:" la";s:3:"199";s:3:"d b";s:3:"200";s:3:"s h";s:3:"201";s:3:"say";s:3:"202";s:3:"t i";s:3:"203";s:3:" ar";s:3:"204";s:3:"e f";s:3:"205";s:3:"ght";s:3:"206";s:3:"hil";s:3:"207";s:3:"igh";s:3:"208";s:3:"int";s:3:"209";s:3:"not";s:3:"210";s:3:"ren";s:3:"211";s:3:" is";s:3:"212";s:3:" pa";s:3:"213";s:3:" sh";s:3:"214";s:3:"ays";s:3:"215";s:3:"com";s:3:"216";s:3:"n s";s:3:"217";s:3:"r a";s:3:"218";s:3:"rin";s:3:"219";s:3:"y a";s:3:"220";s:3:" un";s:3:"221";s:3:"n c";s:3:"222";s:3:"om ";s:3:"223";s:3:"thi";s:3:"224";s:3:" mi";s:3:"225";s:3:"by ";s:3:"226";s:3:"d i";s:3:"227";s:3:"e d";s:3:"228";s:3:"e n";s:3:"229";s:3:"t o";s:3:"230";s:3:" by";s:3:"231";s:3:"e r";s:3:"232";s:3:"eri";s:3:"233";s:3:"old";s:3:"234";s:3:"ome";s:3:"235";s:3:"whe";s:3:"236";s:3:"yea";s:3:"237";s:3:" gr";s:3:"238";s:3:"ar ";s:3:"239";s:3:"ity";s:3:"240";s:3:"mpl";s:3:"241";s:3:"oun";s:3:"242";s:3:"one";s:3:"243";s:3:"ow ";s:3:"244";s:3:"r s";s:3:"245";s:3:"s f";s:3:"246";s:3:"tat";s:3:"247";s:3:" ba";s:3:"248";s:3:" vo";s:3:"249";s:3:"bou";s:3:"250";s:3:"sam";s:3:"251";s:3:"tim";s:3:"252";s:3:"vot";s:3:"253";s:3:"abo";s:3:"254";s:3:"ant";s:3:"255";s:3:"ds ";s:3:"256";s:3:"ial";s:3:"257";s:3:"ine";s:3:"258";s:3:"man";s:3:"259";s:3:"men";s:3:"260";s:3:" or";s:3:"261";s:3:" po";s:3:"262";s:3:"amp";s:3:"263";s:3:"can";s:3:"264";s:3:"der";s:3:"265";s:3:"e l";s:3:"266";s:3:"les";s:3:"267";s:3:"ny ";s:3:"268";s:3:"ot ";s:3:"269";s:3:"rec";s:3:"270";s:3:"tes";s:3:"271";s:3:"tho";s:3:"272";s:3:"ica";s:3:"273";s:3:"ild";s:3:"274";s:3:"ir ";s:3:"275";s:3:"nde";s:3:"276";s:3:"ose";s:3:"277";s:3:"ous";s:3:"278";s:3:"pre";s:3:"279";s:3:"ste";s:3:"280";s:3:"era";s:3:"281";s:3:"per";s:3:"282";s:3:"r o";s:3:"283";s:3:"red";s:3:"284";s:3:"rie";s:3:"285";s:3:" bo";s:3:"286";s:3:" le";s:3:"287";s:3:"ali";s:3:"288";s:3:"ars";s:3:"289";s:3:"ore";s:3:"290";s:3:"ric";s:3:"291";s:3:"s m";s:3:"292";s:3:"str";s:3:"293";s:3:" fa";s:3:"294";s:3:"ess";s:3:"295";s:3:"ie ";s:3:"296";s:3:"ist";s:3:"297";s:3:"lat";s:3:"298";s:3:"uri";s:3:"299";}s:8:"estonian";a:300:{s:3:"st ";s:1:"0";s:3:" ka";s:1:"1";s:3:"on ";s:1:"2";s:3:"ja ";s:1:"3";s:3:" va";s:1:"4";s:3:" on";s:1:"5";s:3:" ja";s:1:"6";s:3:" ko";s:1:"7";s:3:"se ";s:1:"8";s:3:"ast";s:1:"9";s:3:"le ";s:2:"10";s:3:"es ";s:2:"11";s:3:"as ";s:2:"12";s:3:"is ";s:2:"13";s:3:"ud ";s:2:"14";s:3:" sa";s:2:"15";s:3:"da ";s:2:"16";s:3:"ga ";s:2:"17";s:3:" ta";s:2:"18";s:3:"aja";s:2:"19";s:3:"sta";s:2:"20";s:3:" ku";s:2:"21";s:3:" pe";s:2:"22";s:3:"a k";s:2:"23";s:3:"est";s:2:"24";s:3:"ist";s:2:"25";s:3:"ks ";s:2:"26";s:3:"ta ";s:2:"27";s:3:"al ";s:2:"28";s:3:"ava";s:2:"29";s:3:"id ";s:2:"30";s:3:"saa";s:2:"31";s:3:"mis";s:2:"32";s:3:"te ";s:2:"33";s:3:"val";s:2:"34";s:3:" et";s:2:"35";s:3:"nud";s:2:"36";s:3:" te";s:2:"37";s:3:"inn";s:2:"38";s:3:" se";s:2:"39";s:3:" tu";s:2:"40";s:3:"a v";s:2:"41";s:3:"alu";s:2:"42";s:3:"e k";s:2:"43";s:3:"ise";s:2:"44";s:3:"lu ";s:2:"45";s:3:"ma ";s:2:"46";s:3:"mes";s:2:"47";s:3:" mi";s:2:"48";s:3:"et ";s:2:"49";s:3:"iku";s:2:"50";s:3:"lin";s:2:"51";s:3:"ad ";s:2:"52";s:3:"el ";s:2:"53";s:3:"ime";s:2:"54";s:3:"ne ";s:2:"55";s:3:"nna";s:2:"56";s:3:" ha";s:2:"57";s:3:" in";s:2:"58";s:3:" ke";s:2:"59";s:4:" võ";s:2:"60";s:3:"a s";s:2:"61";s:3:"a t";s:2:"62";s:3:"ab ";s:2:"63";s:3:"e s";s:2:"64";s:3:"esi";s:2:"65";s:3:" la";s:2:"66";s:3:" li";s:2:"67";s:3:"e v";s:2:"68";s:3:"eks";s:2:"69";s:3:"ema";s:2:"70";s:3:"las";s:2:"71";s:3:"les";s:2:"72";s:3:"rju";s:2:"73";s:3:"tle";s:2:"74";s:3:"tsi";s:2:"75";s:3:"tus";s:2:"76";s:3:"upa";s:2:"77";s:3:"use";s:2:"78";s:3:"ust";s:2:"79";s:3:"var";s:2:"80";s:4:" lä";s:2:"81";s:3:"ali";s:2:"82";s:3:"arj";s:2:"83";s:3:"de ";s:2:"84";s:3:"ete";s:2:"85";s:3:"i t";s:2:"86";s:3:"iga";s:2:"87";s:3:"ilm";s:2:"88";s:3:"kui";s:2:"89";s:3:"li ";s:2:"90";s:3:"tul";s:2:"91";s:3:" ei";s:2:"92";s:3:" me";s:2:"93";s:4:" sõ";s:2:"94";s:3:"aal";s:2:"95";s:3:"ata";s:2:"96";s:3:"dus";s:2:"97";s:3:"ei ";s:2:"98";s:3:"nik";s:2:"99";s:3:"pea";s:3:"100";s:3:"s k";s:3:"101";s:3:"s o";s:3:"102";s:3:"sal";s:3:"103";s:4:"sõn";s:3:"104";s:3:"ter";s:3:"105";s:3:"ul ";s:3:"106";s:4:"või";s:3:"107";s:3:" el";s:3:"108";s:3:" ne";s:3:"109";s:3:"a j";s:3:"110";s:3:"ate";s:3:"111";s:3:"end";s:3:"112";s:3:"i k";s:3:"113";s:3:"ita";s:3:"114";s:3:"kar";s:3:"115";s:3:"kor";s:3:"116";s:3:"l o";s:3:"117";s:3:"lt ";s:3:"118";s:3:"maa";s:3:"119";s:3:"oli";s:3:"120";s:3:"sti";s:3:"121";s:3:"vad";s:3:"122";s:5:"ään";s:3:"123";s:3:" ju";s:3:"124";s:4:" jä";s:3:"125";s:4:" kü";s:3:"126";s:3:" ma";s:3:"127";s:3:" po";s:3:"128";s:4:" üt";s:3:"129";s:3:"aas";s:3:"130";s:3:"aks";s:3:"131";s:3:"at ";s:3:"132";s:3:"ed ";s:3:"133";s:3:"eri";s:3:"134";s:3:"hoi";s:3:"135";s:3:"i s";s:3:"136";s:3:"ka ";s:3:"137";s:3:"la ";s:3:"138";s:3:"nni";s:3:"139";s:3:"oid";s:3:"140";s:3:"pai";s:3:"141";s:3:"rit";s:3:"142";s:3:"us ";s:3:"143";s:4:"ütl";s:3:"144";s:3:" aa";s:3:"145";s:3:" lo";s:3:"146";s:3:" to";s:3:"147";s:3:" ve";s:3:"148";s:3:"a e";s:3:"149";s:3:"ada";s:3:"150";s:3:"aid";s:3:"151";s:3:"ami";s:3:"152";s:3:"and";s:3:"153";s:3:"dla";s:3:"154";s:3:"e j";s:3:"155";s:3:"ega";s:3:"156";s:3:"gi ";s:3:"157";s:3:"gu ";s:3:"158";s:3:"i p";s:3:"159";s:3:"idl";s:3:"160";s:3:"ik ";s:3:"161";s:3:"ini";s:3:"162";s:3:"jup";s:3:"163";s:3:"kal";s:3:"164";s:3:"kas";s:3:"165";s:3:"kes";s:3:"166";s:3:"koh";s:3:"167";s:3:"s e";s:3:"168";s:3:"s p";s:3:"169";s:3:"sel";s:3:"170";s:3:"sse";s:3:"171";s:3:"ui ";s:3:"172";s:3:" pi";s:3:"173";s:3:" si";s:3:"174";s:3:"aru";s:3:"175";s:3:"eda";s:3:"176";s:3:"eva";s:3:"177";s:3:"fil";s:3:"178";s:3:"i v";s:3:"179";s:3:"ida";s:3:"180";s:3:"ing";s:3:"181";s:5:"lää";s:3:"182";s:3:"me ";s:3:"183";s:3:"na ";s:3:"184";s:3:"nda";s:3:"185";s:3:"nim";s:3:"186";s:3:"ole";s:3:"187";s:3:"ots";s:3:"188";s:3:"ris";s:3:"189";s:3:"s l";s:3:"190";s:3:"sia";s:3:"191";s:3:"t p";s:3:"192";s:3:" en";s:3:"193";s:3:" mu";s:3:"194";s:3:" ol";s:3:"195";s:4:" põ";s:3:"196";s:3:" su";s:3:"197";s:4:" vä";s:3:"198";s:4:" üh";s:3:"199";s:3:"a l";s:3:"200";s:3:"a p";s:3:"201";s:3:"aga";s:3:"202";s:3:"ale";s:3:"203";s:3:"aps";s:3:"204";s:3:"arv";s:3:"205";s:3:"e a";s:3:"206";s:3:"ela";s:3:"207";s:3:"ika";s:3:"208";s:3:"lle";s:3:"209";s:3:"loo";s:3:"210";s:3:"mal";s:3:"211";s:3:"pet";s:3:"212";s:3:"t k";s:3:"213";s:3:"tee";s:3:"214";s:3:"tis";s:3:"215";s:3:"vat";s:3:"216";s:4:"äne";s:3:"217";s:4:"õnn";s:3:"218";s:3:" es";s:3:"219";s:3:" fi";s:3:"220";s:3:" vi";s:3:"221";s:3:"a i";s:3:"222";s:3:"a o";s:3:"223";s:3:"aab";s:3:"224";s:3:"aap";s:3:"225";s:3:"ala";s:3:"226";s:3:"alt";s:3:"227";s:3:"ama";s:3:"228";s:3:"anu";s:3:"229";s:3:"e p";s:3:"230";s:3:"e t";s:3:"231";s:3:"eal";s:3:"232";s:3:"eli";s:3:"233";s:3:"haa";s:3:"234";s:3:"hin";s:3:"235";s:3:"iva";s:3:"236";s:3:"kon";s:3:"237";s:3:"ku ";s:3:"238";s:3:"lik";s:3:"239";s:3:"lm ";s:3:"240";s:3:"min";s:3:"241";s:3:"n t";s:3:"242";s:3:"odu";s:3:"243";s:3:"oon";s:3:"244";s:3:"psa";s:3:"245";s:3:"ri ";s:3:"246";s:3:"si ";s:3:"247";s:3:"stu";s:3:"248";s:3:"t e";s:3:"249";s:3:"t s";s:3:"250";s:3:"ti ";s:3:"251";s:3:"ule";s:3:"252";s:3:"uur";s:3:"253";s:3:"vas";s:3:"254";s:3:"vee";s:3:"255";s:3:" ki";s:3:"256";s:3:" ni";s:3:"257";s:4:" nä";s:3:"258";s:3:" ra";s:3:"259";s:3:"aig";s:3:"260";s:3:"aka";s:3:"261";s:3:"all";s:3:"262";s:3:"atu";s:3:"263";s:3:"e e";s:3:"264";s:3:"eis";s:3:"265";s:3:"ers";s:3:"266";s:3:"i e";s:3:"267";s:3:"ii ";s:3:"268";s:3:"iis";s:3:"269";s:3:"il ";s:3:"270";s:3:"ima";s:3:"271";s:3:"its";s:3:"272";s:3:"kka";s:3:"273";s:3:"kuh";s:3:"274";s:3:"l k";s:3:"275";s:3:"lat";s:3:"276";s:3:"maj";s:3:"277";s:3:"ndu";s:3:"278";s:3:"ni ";s:3:"279";s:3:"nii";s:3:"280";s:3:"oma";s:3:"281";s:3:"ool";s:3:"282";s:3:"rso";s:3:"283";s:3:"ru ";s:3:"284";s:3:"rva";s:3:"285";s:3:"s t";s:3:"286";s:3:"sek";s:3:"287";s:3:"son";s:3:"288";s:3:"ste";s:3:"289";s:3:"t m";s:3:"290";s:3:"taj";s:3:"291";s:3:"tam";s:3:"292";s:3:"ude";s:3:"293";s:3:"uho";s:3:"294";s:3:"vai";s:3:"295";s:3:" ag";s:3:"296";s:3:" os";s:3:"297";s:3:" pa";s:3:"298";s:3:" re";s:3:"299";}s:5:"farsi";a:300:{s:5:"ان ";s:1:"0";s:5:"ای ";s:1:"1";s:5:"Ù‡ ا";s:1:"2";s:5:" اي";s:1:"3";s:5:" در";s:1:"4";s:5:"به ";s:1:"5";s:5:" بر";s:1:"6";s:5:"در ";s:1:"7";s:6:"ران";s:1:"8";s:5:" به";s:1:"9";s:5:"ÛŒ ا";s:2:"10";s:5:"از ";s:2:"11";s:5:"ين ";s:2:"12";s:5:"Ù…ÛŒ ";s:2:"13";s:5:" از";s:2:"14";s:5:"ده ";s:2:"15";s:5:"ست ";s:2:"16";s:6:"است";s:2:"17";s:5:" اس";s:2:"18";s:5:" Ú©Ù‡";s:2:"19";s:5:"Ú©Ù‡ ";s:2:"20";s:6:"اير";s:2:"21";s:5:"ند ";s:2:"22";s:6:"اين";s:2:"23";s:5:" ها";s:2:"24";s:6:"يرا";s:2:"25";s:5:"ود ";s:2:"26";s:5:" را";s:2:"27";s:6:"های";s:2:"28";s:5:" خو";s:2:"29";s:5:"ته ";s:2:"30";s:5:"را ";s:2:"31";s:6:"رای";s:2:"32";s:5:"رد ";s:2:"33";s:5:"Ù† ب";s:2:"34";s:6:"کرد";s:2:"35";s:4:" Ùˆ ";s:2:"36";s:5:" کر";s:2:"37";s:5:"ات ";s:2:"38";s:6:"برا";s:2:"39";s:5:"د Ú©";s:2:"40";s:6:"مان";s:2:"41";s:5:"ÛŒ د";s:2:"42";s:5:" ان";s:2:"43";s:6:"خوا";s:2:"44";s:6:"شور";s:2:"45";s:5:" با";s:2:"46";s:5:"Ù† ا";s:2:"47";s:5:" سا";s:2:"48";s:6:"تمی";s:2:"49";s:5:"ری ";s:2:"50";s:6:"اتم";s:2:"51";s:5:"ا ا";s:2:"52";s:6:"واه";s:2:"53";s:5:" ات";s:2:"54";s:5:" عر";s:2:"55";s:5:"اق ";s:2:"56";s:5:"ر Ù…";s:2:"57";s:6:"راق";s:2:"58";s:6:"عرا";s:2:"59";s:5:"ÛŒ ب";s:2:"60";s:5:" تا";s:2:"61";s:5:" تو";s:2:"62";s:5:"ار ";s:2:"63";s:5:"ر ا";s:2:"64";s:5:"Ù† Ù…";s:2:"65";s:5:"Ù‡ ب";s:2:"66";s:5:"ور ";s:2:"67";s:5:"يد ";s:2:"68";s:5:"ÛŒ Ú©";s:2:"69";s:5:" ام";s:2:"70";s:5:" دا";s:2:"71";s:5:" Ú©Ù†";s:2:"72";s:6:"اهد";s:2:"73";s:5:"هد ";s:2:"74";s:5:" آن";s:2:"75";s:5:" Ù…ÛŒ";s:2:"76";s:5:" ني";s:2:"77";s:5:" Ú¯Ù";s:2:"78";s:5:"د ا";s:2:"79";s:6:"Ú¯Ùت";s:2:"80";s:5:" Ú©Ø´";s:2:"81";s:5:"ا ب";s:2:"82";s:5:"Ù†ÛŒ ";s:2:"83";s:5:"ها ";s:2:"84";s:6:"کشو";s:2:"85";s:5:" رو";s:2:"86";s:5:"ت Ú©";s:2:"87";s:6:"نيو";s:2:"88";s:5:"Ù‡ Ù…";s:2:"89";s:5:"ÙˆÛŒ ";s:2:"90";s:5:"ÛŒ ت";s:2:"91";s:5:" شو";s:2:"92";s:5:"ال ";s:2:"93";s:6:"دار";s:2:"94";s:5:"مه ";s:2:"95";s:5:"Ù† Ú©";s:2:"96";s:5:"Ù‡ د";s:2:"97";s:5:"يه ";s:2:"98";s:5:" ما";s:2:"99";s:6:"امه";s:3:"100";s:5:"د ب";s:3:"101";s:6:"زار";s:3:"102";s:6:"ورا";s:3:"103";s:6:"گزا";s:3:"104";s:5:" پي";s:3:"105";s:5:"آن ";s:3:"106";s:6:"انت";s:3:"107";s:5:"ت ا";s:3:"108";s:5:"Ùت ";s:3:"109";s:5:"Ù‡ Ù†";s:3:"110";s:5:"ÛŒ Ø®";s:3:"111";s:6:"اما";s:3:"112";s:6:"بات";s:3:"113";s:5:"ما ";s:3:"114";s:6:"ملل";s:3:"115";s:6:"نام";s:3:"116";s:5:"ير ";s:3:"117";s:5:"ÛŒ Ù…";s:3:"118";s:5:"ÛŒ Ù‡";s:3:"119";s:5:" آم";s:3:"120";s:5:" ای";s:3:"121";s:5:" من";s:3:"122";s:6:"انس";s:3:"123";s:6:"اني";s:3:"124";s:5:"ت د";s:3:"125";s:6:"رده";s:3:"126";s:6:"ساز";s:3:"127";s:5:"Ù† د";s:3:"128";s:5:"نه ";s:3:"129";s:6:"ورد";s:3:"130";s:5:" او";s:3:"131";s:5:" بي";s:3:"132";s:5:" سو";s:3:"133";s:5:" شد";s:3:"134";s:6:"اده";s:3:"135";s:6:"اند";s:3:"136";s:5:"با ";s:3:"137";s:5:"ت ب";s:3:"138";s:5:"ر ب";s:3:"139";s:5:"ز ا";s:3:"140";s:6:"زما";s:3:"141";s:6:"سته";s:3:"142";s:5:"Ù† ر";s:3:"143";s:5:"Ù‡ س";s:3:"144";s:6:"وان";s:3:"145";s:5:"وز ";s:3:"146";s:5:"ÛŒ ر";s:3:"147";s:5:"ÛŒ س";s:3:"148";s:5:" هس";s:3:"149";s:6:"ابا";s:3:"150";s:5:"ام ";s:3:"151";s:6:"اور";s:3:"152";s:6:"تخا";s:3:"153";s:6:"خاب";s:3:"154";s:6:"خود";s:3:"155";s:5:"د د";s:3:"156";s:5:"دن ";s:3:"157";s:6:"رها";s:3:"158";s:6:"روز";s:3:"159";s:6:"رگز";s:3:"160";s:6:"نتخ";s:3:"161";s:5:"Ù‡ Ø´";s:3:"162";s:5:"Ù‡ Ù‡";s:3:"163";s:6:"هست";s:3:"164";s:5:"يت ";s:3:"165";s:5:"يم ";s:3:"166";s:5:" دو";s:3:"167";s:5:" دي";s:3:"168";s:5:" مو";s:3:"169";s:5:" نو";s:3:"170";s:5:" هم";s:3:"171";s:5:" کا";s:3:"172";s:5:"اد ";s:3:"173";s:6:"اری";s:3:"174";s:6:"انی";s:3:"175";s:5:"بر ";s:3:"176";s:6:"بود";s:3:"177";s:5:"ت Ù‡";s:3:"178";s:5:"Ø­ Ù‡";s:3:"179";s:6:"حال";s:3:"180";s:5:"رش ";s:3:"181";s:5:"عه ";s:3:"182";s:5:"Ù„ÛŒ ";s:3:"183";s:5:"وم ";s:3:"184";s:6:"ژان";s:3:"185";s:5:" سل";s:3:"186";s:6:"آمر";s:3:"187";s:5:"اح ";s:3:"188";s:6:"توس";s:3:"189";s:6:"داد";s:3:"190";s:6:"دام";s:3:"191";s:5:"ر د";s:3:"192";s:5:"ره ";s:3:"193";s:6:"ريک";s:3:"194";s:5:"زی ";s:3:"195";s:6:"سلا";s:3:"196";s:6:"شود";s:3:"197";s:6:"لاح";s:3:"198";s:6:"مري";s:3:"199";s:6:"نند";s:3:"200";s:5:"Ù‡ ع";s:3:"201";s:6:"يما";s:3:"202";s:6:"يکا";s:3:"203";s:6:"پيم";s:3:"204";s:5:"گر ";s:3:"205";s:5:" Ø¢Ú˜";s:3:"206";s:5:" ال";s:3:"207";s:5:" بو";s:3:"208";s:5:" مق";s:3:"209";s:5:" مل";s:3:"210";s:5:" ÙˆÛŒ";s:3:"211";s:6:"آژا";s:3:"212";s:6:"ازم";s:3:"213";s:6:"ازی";s:3:"214";s:6:"بار";s:3:"215";s:6:"برن";s:3:"216";s:5:"ر Ø¢";s:3:"217";s:5:"ز س";s:3:"218";s:6:"سعه";s:3:"219";s:6:"شته";s:3:"220";s:6:"مات";s:3:"221";s:5:"Ù† Ø¢";s:3:"222";s:5:"Ù† Ù¾";s:3:"223";s:5:"نس ";s:3:"224";s:5:"Ù‡ Ú¯";s:3:"225";s:6:"وسع";s:3:"226";s:6:"يان";s:3:"227";s:6:"يوم";s:3:"228";s:5:"کا ";s:3:"229";s:6:"کام";s:3:"230";s:6:"کند";s:3:"231";s:5:" خا";s:3:"232";s:5:" سر";s:3:"233";s:6:"آور";s:3:"234";s:6:"ارد";s:3:"235";s:6:"اقد";s:3:"236";s:6:"ايم";s:3:"237";s:6:"ايی";s:3:"238";s:6:"برگ";s:3:"239";s:5:"ت ع";s:3:"240";s:5:"تن ";s:3:"241";s:5:"خت ";s:3:"242";s:5:"د Ùˆ";s:3:"243";s:5:"ر Ø®";s:3:"244";s:5:"رک ";s:3:"245";s:6:"زير";s:3:"246";s:6:"Ùته";s:3:"247";s:6:"قدا";s:3:"248";s:5:"Ù„ ت";s:3:"249";s:6:"مين";s:3:"250";s:5:"Ù† Ú¯";s:3:"251";s:5:"Ù‡ Ø¢";s:3:"252";s:5:"Ù‡ Ø®";s:3:"253";s:5:"Ù‡ Ú©";s:3:"254";s:6:"ورک";s:3:"255";s:6:"ويو";s:3:"256";s:6:"يور";s:3:"257";s:6:"يوي";s:3:"258";s:5:"ÙŠÛŒ ";s:3:"259";s:5:"Ú© ت";s:3:"260";s:5:"ÛŒ Ø´";s:3:"261";s:5:" اق";s:3:"262";s:5:" حا";s:3:"263";s:5:" حق";s:3:"264";s:5:" دس";s:3:"265";s:5:" Ø´Ú©";s:3:"266";s:5:" عم";s:3:"267";s:5:" ÙŠÚ©";s:3:"268";s:5:"ا ت";s:3:"269";s:5:"ا د";s:3:"270";s:6:"ارج";s:3:"271";s:6:"بين";s:3:"272";s:5:"ت Ù…";s:3:"273";s:5:"ت Ùˆ";s:3:"274";s:6:"تاي";s:3:"275";s:6:"دست";s:3:"276";s:5:"ر Ø­";s:3:"277";s:5:"ر س";s:3:"278";s:6:"رنا";s:3:"279";s:5:"ز ب";s:3:"280";s:6:"شکا";s:3:"281";s:5:"لل ";s:3:"282";s:5:"Ù… Ú©";s:3:"283";s:5:"مز ";s:3:"284";s:6:"ندا";s:3:"285";s:6:"نوا";s:3:"286";s:5:"Ùˆ ا";s:3:"287";s:6:"وره";s:3:"288";s:5:"ون ";s:3:"289";s:6:"وند";s:3:"290";s:6:"يمز";s:3:"291";s:5:" آو";s:3:"292";s:5:" اع";s:3:"293";s:5:" Ùر";s:3:"294";s:5:" مت";s:3:"295";s:5:" نه";s:3:"296";s:5:" هر";s:3:"297";s:5:" وز";s:3:"298";s:5:" گز";s:3:"299";}s:7:"finnish";a:300:{s:3:"en ";s:1:"0";s:3:"in ";s:1:"1";s:3:"an ";s:1:"2";s:3:"on ";s:1:"3";s:3:"ist";s:1:"4";s:3:"ta ";s:1:"5";s:3:"ja ";s:1:"6";s:3:"n t";s:1:"7";s:3:"sa ";s:1:"8";s:3:"sta";s:1:"9";s:3:"aan";s:2:"10";s:3:"n p";s:2:"11";s:3:" on";s:2:"12";s:3:"ssa";s:2:"13";s:3:"tta";s:2:"14";s:4:"tä ";s:2:"15";s:3:" ka";s:2:"16";s:3:" pa";s:2:"17";s:3:"si ";s:2:"18";s:3:" ja";s:2:"19";s:3:"n k";s:2:"20";s:3:"lla";s:2:"21";s:4:"än ";s:2:"22";s:3:"een";s:2:"23";s:3:"n v";s:2:"24";s:3:"ksi";s:2:"25";s:3:"ett";s:2:"26";s:3:"nen";s:2:"27";s:3:"taa";s:2:"28";s:4:"ttä";s:2:"29";s:3:" va";s:2:"30";s:3:"ill";s:2:"31";s:3:"itt";s:2:"32";s:3:" jo";s:2:"33";s:3:" ko";s:2:"34";s:3:"n s";s:2:"35";s:3:" tu";s:2:"36";s:3:"ia ";s:2:"37";s:3:" su";s:2:"38";s:3:"a p";s:2:"39";s:3:"aa ";s:2:"40";s:3:"la ";s:2:"41";s:3:"lle";s:2:"42";s:3:"n m";s:2:"43";s:3:"le ";s:2:"44";s:3:"tte";s:2:"45";s:3:"na ";s:2:"46";s:3:" ta";s:2:"47";s:3:" ve";s:2:"48";s:3:"at ";s:2:"49";s:3:" vi";s:2:"50";s:3:"utt";s:2:"51";s:3:" sa";s:2:"52";s:3:"ise";s:2:"53";s:3:"sen";s:2:"54";s:3:" ku";s:2:"55";s:4:" nä";s:2:"56";s:4:" pä";s:2:"57";s:3:"ste";s:2:"58";s:3:" ol";s:2:"59";s:3:"a t";s:2:"60";s:3:"ais";s:2:"61";s:3:"maa";s:2:"62";s:3:"ti ";s:2:"63";s:3:"a o";s:2:"64";s:3:"oit";s:2:"65";s:5:"pää";s:2:"66";s:3:" pi";s:2:"67";s:3:"a v";s:2:"68";s:3:"ala";s:2:"69";s:3:"ine";s:2:"70";s:3:"isi";s:2:"71";s:3:"tel";s:2:"72";s:3:"tti";s:2:"73";s:3:" si";s:2:"74";s:3:"a k";s:2:"75";s:3:"all";s:2:"76";s:3:"iin";s:2:"77";s:3:"kin";s:2:"78";s:4:"stä";s:2:"79";s:3:"uom";s:2:"80";s:3:"vii";s:2:"81";s:3:" ma";s:2:"82";s:3:" se";s:2:"83";s:4:"enä";s:2:"84";s:3:" mu";s:2:"85";s:3:"a s";s:2:"86";s:3:"est";s:2:"87";s:3:"iss";s:2:"88";s:4:"llä";s:2:"89";s:3:"lok";s:2:"90";s:4:"lä ";s:2:"91";s:3:"n j";s:2:"92";s:3:"n o";s:2:"93";s:3:"toi";s:2:"94";s:3:"ven";s:2:"95";s:3:"ytt";s:2:"96";s:3:" li";s:2:"97";s:3:"ain";s:2:"98";s:3:"et ";s:2:"99";s:3:"ina";s:3:"100";s:3:"n a";s:3:"101";s:3:"n n";s:3:"102";s:3:"oll";s:3:"103";s:3:"plo";s:3:"104";s:3:"ten";s:3:"105";s:3:"ust";s:3:"106";s:4:"äll";s:3:"107";s:5:"ään";s:3:"108";s:3:" to";s:3:"109";s:3:"den";s:3:"110";s:3:"men";s:3:"111";s:3:"oki";s:3:"112";s:3:"suo";s:3:"113";s:4:"sä ";s:3:"114";s:5:"tää";s:3:"115";s:3:"uks";s:3:"116";s:3:"vat";s:3:"117";s:3:" al";s:3:"118";s:3:" ke";s:3:"119";s:3:" te";s:3:"120";s:3:"a e";s:3:"121";s:3:"lii";s:3:"122";s:3:"tai";s:3:"123";s:3:"tei";s:3:"124";s:4:"äis";s:3:"125";s:5:"ää ";s:3:"126";s:3:" pl";s:3:"127";s:3:"ell";s:3:"128";s:3:"i t";s:3:"129";s:3:"ide";s:3:"130";s:3:"ikk";s:3:"131";s:3:"ki ";s:3:"132";s:3:"nta";s:3:"133";s:3:"ova";s:3:"134";s:3:"yst";s:3:"135";s:3:"yt ";s:3:"136";s:4:"ä p";s:3:"137";s:4:"äyt";s:3:"138";s:3:" ha";s:3:"139";s:3:" pe";s:3:"140";s:4:" tä";s:3:"141";s:3:"a n";s:3:"142";s:3:"aik";s:3:"143";s:3:"i p";s:3:"144";s:3:"i v";s:3:"145";s:3:"nyt";s:3:"146";s:4:"näy";s:3:"147";s:3:"pal";s:3:"148";s:3:"tee";s:3:"149";s:3:"un ";s:3:"150";s:3:" me";s:3:"151";s:3:"a m";s:3:"152";s:3:"ess";s:3:"153";s:3:"kau";s:3:"154";s:3:"pai";s:3:"155";s:3:"stu";s:3:"156";s:3:"ut ";s:3:"157";s:3:"voi";s:3:"158";s:3:" et";s:3:"159";s:3:"a h";s:3:"160";s:3:"eis";s:3:"161";s:3:"hte";s:3:"162";s:3:"i o";s:3:"163";s:3:"iik";s:3:"164";s:3:"ita";s:3:"165";s:3:"jou";s:3:"166";s:3:"mis";s:3:"167";s:3:"nin";s:3:"168";s:3:"nut";s:3:"169";s:3:"sia";s:3:"170";s:4:"ssä";s:3:"171";s:3:"van";s:3:"172";s:3:" ty";s:3:"173";s:3:" yh";s:3:"174";s:3:"aks";s:3:"175";s:3:"ime";s:3:"176";s:3:"loi";s:3:"177";s:3:"me ";s:3:"178";s:3:"n e";s:3:"179";s:3:"n h";s:3:"180";s:3:"n l";s:3:"181";s:3:"oin";s:3:"182";s:3:"ome";s:3:"183";s:3:"ott";s:3:"184";s:3:"ouk";s:3:"185";s:3:"sit";s:3:"186";s:3:"sti";s:3:"187";s:3:"tet";s:3:"188";s:3:"tie";s:3:"189";s:3:"ukk";s:3:"190";s:4:"ä k";s:3:"191";s:3:" ra";s:3:"192";s:3:" ti";s:3:"193";s:3:"aja";s:3:"194";s:3:"asi";s:3:"195";s:3:"ent";s:3:"196";s:3:"iga";s:3:"197";s:3:"iig";s:3:"198";s:3:"ite";s:3:"199";s:3:"jan";s:3:"200";s:3:"kaa";s:3:"201";s:3:"kse";s:3:"202";s:3:"laa";s:3:"203";s:3:"lan";s:3:"204";s:3:"li ";s:3:"205";s:4:"näj";s:3:"206";s:3:"ole";s:3:"207";s:3:"tii";s:3:"208";s:3:"usi";s:3:"209";s:5:"äjä";s:3:"210";s:3:" ov";s:3:"211";s:3:"a a";s:3:"212";s:3:"ant";s:3:"213";s:3:"ava";s:3:"214";s:3:"ei ";s:3:"215";s:3:"eri";s:3:"216";s:3:"kan";s:3:"217";s:3:"kku";s:3:"218";s:3:"lai";s:3:"219";s:3:"lis";s:3:"220";s:4:"läi";s:3:"221";s:3:"mat";s:3:"222";s:3:"ois";s:3:"223";s:3:"pel";s:3:"224";s:3:"sil";s:3:"225";s:3:"sty";s:3:"226";s:3:"taj";s:3:"227";s:3:"tav";s:3:"228";s:3:"ttu";s:3:"229";s:4:"työ";s:3:"230";s:4:"yös";s:3:"231";s:4:"ä o";s:3:"232";s:3:" ai";s:3:"233";s:3:" pu";s:3:"234";s:3:"a j";s:3:"235";s:3:"a l";s:3:"236";s:3:"aal";s:3:"237";s:3:"arv";s:3:"238";s:3:"ass";s:3:"239";s:3:"ien";s:3:"240";s:3:"imi";s:3:"241";s:3:"imm";s:3:"242";s:4:"itä";s:3:"243";s:3:"ka ";s:3:"244";s:3:"kes";s:3:"245";s:3:"kue";s:3:"246";s:3:"lee";s:3:"247";s:3:"lin";s:3:"248";s:3:"llo";s:3:"249";s:3:"one";s:3:"250";s:3:"ri ";s:3:"251";s:3:"t o";s:3:"252";s:3:"t p";s:3:"253";s:3:"tu ";s:3:"254";s:3:"val";s:3:"255";s:3:"vuo";s:3:"256";s:3:" ei";s:3:"257";s:3:" he";s:3:"258";s:3:" hy";s:3:"259";s:3:" my";s:3:"260";s:3:" vo";s:3:"261";s:3:"ali";s:3:"262";s:3:"alo";s:3:"263";s:3:"ano";s:3:"264";s:3:"ast";s:3:"265";s:3:"att";s:3:"266";s:3:"auk";s:3:"267";s:3:"eli";s:3:"268";s:3:"ely";s:3:"269";s:3:"hti";s:3:"270";s:3:"ika";s:3:"271";s:3:"ken";s:3:"272";s:3:"kki";s:3:"273";s:3:"lys";s:3:"274";s:3:"min";s:3:"275";s:4:"myö";s:3:"276";s:3:"oht";s:3:"277";s:3:"oma";s:3:"278";s:3:"tus";s:3:"279";s:3:"umi";s:3:"280";s:3:"yks";s:3:"281";s:4:"ät ";s:3:"282";s:5:"ääl";s:3:"283";s:4:"ös ";s:3:"284";s:3:" ar";s:3:"285";s:3:" eu";s:3:"286";s:3:" hu";s:3:"287";s:3:" na";s:3:"288";s:3:"aat";s:3:"289";s:3:"alk";s:3:"290";s:3:"alu";s:3:"291";s:3:"ans";s:3:"292";s:3:"arj";s:3:"293";s:3:"enn";s:3:"294";s:3:"han";s:3:"295";s:3:"kuu";s:3:"296";s:3:"n y";s:3:"297";s:3:"set";s:3:"298";s:3:"sim";s:3:"299";}s:6:"french";a:300:{s:3:"es ";s:1:"0";s:3:" de";s:1:"1";s:3:"de ";s:1:"2";s:3:" le";s:1:"3";s:3:"ent";s:1:"4";s:3:"le ";s:1:"5";s:3:"nt ";s:1:"6";s:3:"la ";s:1:"7";s:3:"s d";s:1:"8";s:3:" la";s:1:"9";s:3:"ion";s:2:"10";s:3:"on ";s:2:"11";s:3:"re ";s:2:"12";s:3:" pa";s:2:"13";s:3:"e l";s:2:"14";s:3:"e d";s:2:"15";s:3:" l'";s:2:"16";s:3:"e p";s:2:"17";s:3:" co";s:2:"18";s:3:" pr";s:2:"19";s:3:"tio";s:2:"20";s:3:"ns ";s:2:"21";s:3:" en";s:2:"22";s:3:"ne ";s:2:"23";s:3:"que";s:2:"24";s:3:"r l";s:2:"25";s:3:"les";s:2:"26";s:3:"ur ";s:2:"27";s:3:"en ";s:2:"28";s:3:"ati";s:2:"29";s:3:"ue ";s:2:"30";s:3:" po";s:2:"31";s:3:" d'";s:2:"32";s:3:"par";s:2:"33";s:3:" a ";s:2:"34";s:3:"et ";s:2:"35";s:3:"it ";s:2:"36";s:3:" qu";s:2:"37";s:3:"men";s:2:"38";s:3:"ons";s:2:"39";s:3:"te ";s:2:"40";s:3:" et";s:2:"41";s:3:"t d";s:2:"42";s:3:" re";s:2:"43";s:3:"des";s:2:"44";s:3:" un";s:2:"45";s:3:"ie ";s:2:"46";s:3:"s l";s:2:"47";s:3:" su";s:2:"48";s:3:"pou";s:2:"49";s:3:" au";s:2:"50";s:4:" à ";s:2:"51";s:3:"con";s:2:"52";s:3:"er ";s:2:"53";s:3:" no";s:2:"54";s:3:"ait";s:2:"55";s:3:"e c";s:2:"56";s:3:"se ";s:2:"57";s:4:"té ";s:2:"58";s:3:"du ";s:2:"59";s:3:" du";s:2:"60";s:4:" dé";s:2:"61";s:3:"ce ";s:2:"62";s:3:"e e";s:2:"63";s:3:"is ";s:2:"64";s:3:"n d";s:2:"65";s:3:"s a";s:2:"66";s:3:" so";s:2:"67";s:3:"e r";s:2:"68";s:3:"e s";s:2:"69";s:3:"our";s:2:"70";s:3:"res";s:2:"71";s:3:"ssi";s:2:"72";s:3:"eur";s:2:"73";s:3:" se";s:2:"74";s:3:"eme";s:2:"75";s:3:"est";s:2:"76";s:3:"us ";s:2:"77";s:3:"sur";s:2:"78";s:3:"ant";s:2:"79";s:3:"iqu";s:2:"80";s:3:"s p";s:2:"81";s:3:"une";s:2:"82";s:3:"uss";s:2:"83";s:3:"l'a";s:2:"84";s:3:"pro";s:2:"85";s:3:"ter";s:2:"86";s:3:"tre";s:2:"87";s:3:"end";s:2:"88";s:3:"rs ";s:2:"89";s:3:" ce";s:2:"90";s:3:"e a";s:2:"91";s:3:"t p";s:2:"92";s:3:"un ";s:2:"93";s:3:" ma";s:2:"94";s:3:" ru";s:2:"95";s:4:" ré";s:2:"96";s:3:"ous";s:2:"97";s:3:"ris";s:2:"98";s:3:"rus";s:2:"99";s:3:"sse";s:3:"100";s:3:"ans";s:3:"101";s:3:"ar ";s:3:"102";s:3:"com";s:3:"103";s:3:"e m";s:3:"104";s:3:"ire";s:3:"105";s:3:"nce";s:3:"106";s:3:"nte";s:3:"107";s:3:"t l";s:3:"108";s:3:" av";s:3:"109";s:3:" mo";s:3:"110";s:3:" te";s:3:"111";s:3:"il ";s:3:"112";s:3:"me ";s:3:"113";s:3:"ont";s:3:"114";s:3:"ten";s:3:"115";s:3:"a p";s:3:"116";s:3:"dan";s:3:"117";s:3:"pas";s:3:"118";s:3:"qui";s:3:"119";s:3:"s e";s:3:"120";s:3:"s s";s:3:"121";s:3:" in";s:3:"122";s:3:"ist";s:3:"123";s:3:"lle";s:3:"124";s:3:"nou";s:3:"125";s:4:"pré";s:3:"126";s:3:"'un";s:3:"127";s:3:"air";s:3:"128";s:3:"d'a";s:3:"129";s:3:"ir ";s:3:"130";s:3:"n e";s:3:"131";s:3:"rop";s:3:"132";s:3:"ts ";s:3:"133";s:3:" da";s:3:"134";s:3:"a s";s:3:"135";s:3:"as ";s:3:"136";s:3:"au ";s:3:"137";s:3:"den";s:3:"138";s:3:"mai";s:3:"139";s:3:"mis";s:3:"140";s:3:"ori";s:3:"141";s:3:"out";s:3:"142";s:3:"rme";s:3:"143";s:3:"sio";s:3:"144";s:3:"tte";s:3:"145";s:3:"ux ";s:3:"146";s:3:"a d";s:3:"147";s:3:"ien";s:3:"148";s:3:"n a";s:3:"149";s:3:"ntr";s:3:"150";s:3:"omm";s:3:"151";s:3:"ort";s:3:"152";s:3:"ouv";s:3:"153";s:3:"s c";s:3:"154";s:3:"son";s:3:"155";s:3:"tes";s:3:"156";s:3:"ver";s:3:"157";s:4:"ère";s:3:"158";s:3:" il";s:3:"159";s:3:" m ";s:3:"160";s:3:" sa";s:3:"161";s:3:" ve";s:3:"162";s:3:"a r";s:3:"163";s:3:"ais";s:3:"164";s:3:"ava";s:3:"165";s:3:"di ";s:3:"166";s:3:"n p";s:3:"167";s:3:"sti";s:3:"168";s:3:"ven";s:3:"169";s:3:" mi";s:3:"170";s:3:"ain";s:3:"171";s:3:"enc";s:3:"172";s:3:"for";s:3:"173";s:4:"ité";s:3:"174";s:3:"lar";s:3:"175";s:3:"oir";s:3:"176";s:3:"rem";s:3:"177";s:3:"ren";s:3:"178";s:3:"rro";s:3:"179";s:4:"rés";s:3:"180";s:3:"sie";s:3:"181";s:3:"t a";s:3:"182";s:3:"tur";s:3:"183";s:3:" pe";s:3:"184";s:3:" to";s:3:"185";s:3:"d'u";s:3:"186";s:3:"ell";s:3:"187";s:3:"err";s:3:"188";s:3:"ers";s:3:"189";s:3:"ide";s:3:"190";s:3:"ine";s:3:"191";s:3:"iss";s:3:"192";s:3:"mes";s:3:"193";s:3:"por";s:3:"194";s:3:"ran";s:3:"195";s:3:"sit";s:3:"196";s:3:"st ";s:3:"197";s:3:"t r";s:3:"198";s:3:"uti";s:3:"199";s:3:"vai";s:3:"200";s:4:"é l";s:3:"201";s:4:"ési";s:3:"202";s:3:" di";s:3:"203";s:3:" n'";s:3:"204";s:4:" ét";s:3:"205";s:3:"a c";s:3:"206";s:3:"ass";s:3:"207";s:3:"e t";s:3:"208";s:3:"in ";s:3:"209";s:3:"nde";s:3:"210";s:3:"pre";s:3:"211";s:3:"rat";s:3:"212";s:3:"s m";s:3:"213";s:3:"ste";s:3:"214";s:3:"tai";s:3:"215";s:3:"tch";s:3:"216";s:3:"ui ";s:3:"217";s:3:"uro";s:3:"218";s:4:"ès ";s:3:"219";s:3:" es";s:3:"220";s:3:" fo";s:3:"221";s:3:" tr";s:3:"222";s:3:"'ad";s:3:"223";s:3:"app";s:3:"224";s:3:"aux";s:3:"225";s:4:"e à";s:3:"226";s:3:"ett";s:3:"227";s:3:"iti";s:3:"228";s:3:"lit";s:3:"229";s:3:"nal";s:3:"230";s:4:"opé";s:3:"231";s:3:"r d";s:3:"232";s:3:"ra ";s:3:"233";s:3:"rai";s:3:"234";s:3:"ror";s:3:"235";s:3:"s r";s:3:"236";s:3:"tat";s:3:"237";s:4:"uté";s:3:"238";s:4:"à l";s:3:"239";s:3:" af";s:3:"240";s:3:"anc";s:3:"241";s:3:"ara";s:3:"242";s:3:"art";s:3:"243";s:3:"bre";s:3:"244";s:4:"ché";s:3:"245";s:3:"dre";s:3:"246";s:3:"e f";s:3:"247";s:3:"ens";s:3:"248";s:3:"lem";s:3:"249";s:3:"n r";s:3:"250";s:3:"n t";s:3:"251";s:3:"ndr";s:3:"252";s:3:"nne";s:3:"253";s:3:"onn";s:3:"254";s:3:"pos";s:3:"255";s:3:"s t";s:3:"256";s:3:"tiq";s:3:"257";s:3:"ure";s:3:"258";s:3:" tu";s:3:"259";s:3:"ale";s:3:"260";s:3:"and";s:3:"261";s:3:"ave";s:3:"262";s:3:"cla";s:3:"263";s:3:"cou";s:3:"264";s:3:"e n";s:3:"265";s:3:"emb";s:3:"266";s:3:"ins";s:3:"267";s:3:"jou";s:3:"268";s:3:"mme";s:3:"269";s:3:"rie";s:3:"270";s:4:"rès";s:3:"271";s:3:"sem";s:3:"272";s:3:"str";s:3:"273";s:3:"t i";s:3:"274";s:3:"ues";s:3:"275";s:3:"uni";s:3:"276";s:3:"uve";s:3:"277";s:4:"é d";s:3:"278";s:4:"ée ";s:3:"279";s:3:" ch";s:3:"280";s:3:" do";s:3:"281";s:3:" eu";s:3:"282";s:3:" fa";s:3:"283";s:3:" lo";s:3:"284";s:3:" ne";s:3:"285";s:3:" ra";s:3:"286";s:3:"arl";s:3:"287";s:3:"att";s:3:"288";s:3:"ec ";s:3:"289";s:3:"ica";s:3:"290";s:3:"l a";s:3:"291";s:3:"l'o";s:3:"292";s:4:"l'é";s:3:"293";s:3:"mmi";s:3:"294";s:3:"nta";s:3:"295";s:3:"orm";s:3:"296";s:3:"ou ";s:3:"297";s:3:"r u";s:3:"298";s:3:"rle";s:3:"299";}s:6:"german";a:300:{s:3:"en ";s:1:"0";s:3:"er ";s:1:"1";s:3:" de";s:1:"2";s:3:"der";s:1:"3";s:3:"ie ";s:1:"4";s:3:" di";s:1:"5";s:3:"die";s:1:"6";s:3:"sch";s:1:"7";s:3:"ein";s:1:"8";s:3:"che";s:1:"9";s:3:"ich";s:2:"10";s:3:"den";s:2:"11";s:3:"in ";s:2:"12";s:3:"te ";s:2:"13";s:3:"ch ";s:2:"14";s:3:" ei";s:2:"15";s:3:"ung";s:2:"16";s:3:"n d";s:2:"17";s:3:"nd ";s:2:"18";s:3:" be";s:2:"19";s:3:"ver";s:2:"20";s:3:"es ";s:2:"21";s:3:" zu";s:2:"22";s:3:"eit";s:2:"23";s:3:"gen";s:2:"24";s:3:"und";s:2:"25";s:3:" un";s:2:"26";s:3:" au";s:2:"27";s:3:" in";s:2:"28";s:3:"cht";s:2:"29";s:3:"it ";s:2:"30";s:3:"ten";s:2:"31";s:3:" da";s:2:"32";s:3:"ent";s:2:"33";s:3:" ve";s:2:"34";s:3:"and";s:2:"35";s:3:" ge";s:2:"36";s:3:"ine";s:2:"37";s:3:" mi";s:2:"38";s:3:"r d";s:2:"39";s:3:"hen";s:2:"40";s:3:"ng ";s:2:"41";s:3:"nde";s:2:"42";s:3:" vo";s:2:"43";s:3:"e d";s:2:"44";s:3:"ber";s:2:"45";s:3:"men";s:2:"46";s:3:"ei ";s:2:"47";s:3:"mit";s:2:"48";s:3:" st";s:2:"49";s:3:"ter";s:2:"50";s:3:"ren";s:2:"51";s:3:"t d";s:2:"52";s:3:" er";s:2:"53";s:3:"ere";s:2:"54";s:3:"n s";s:2:"55";s:3:"ste";s:2:"56";s:3:" se";s:2:"57";s:3:"e s";s:2:"58";s:3:"ht ";s:2:"59";s:3:"des";s:2:"60";s:3:"ist";s:2:"61";s:3:"ne ";s:2:"62";s:3:"auf";s:2:"63";s:3:"e a";s:2:"64";s:3:"isc";s:2:"65";s:3:"on ";s:2:"66";s:3:"rte";s:2:"67";s:3:" re";s:2:"68";s:3:" we";s:2:"69";s:3:"ges";s:2:"70";s:3:"uch";s:2:"71";s:4:" fü";s:2:"72";s:3:" so";s:2:"73";s:3:"bei";s:2:"74";s:3:"e e";s:2:"75";s:3:"nen";s:2:"76";s:3:"r s";s:2:"77";s:3:"ach";s:2:"78";s:4:"für";s:2:"79";s:3:"ier";s:2:"80";s:3:"par";s:2:"81";s:4:"ür ";s:2:"82";s:3:" ha";s:2:"83";s:3:"as ";s:2:"84";s:3:"ert";s:2:"85";s:3:" an";s:2:"86";s:3:" pa";s:2:"87";s:3:" sa";s:2:"88";s:3:" sp";s:2:"89";s:3:" wi";s:2:"90";s:3:"for";s:2:"91";s:3:"tag";s:2:"92";s:3:"zu ";s:2:"93";s:3:"das";s:2:"94";s:3:"rei";s:2:"95";s:3:"he ";s:2:"96";s:3:"hre";s:2:"97";s:3:"nte";s:2:"98";s:3:"sen";s:2:"99";s:3:"vor";s:3:"100";s:3:" sc";s:3:"101";s:3:"ech";s:3:"102";s:3:"etz";s:3:"103";s:3:"hei";s:3:"104";s:3:"lan";s:3:"105";s:3:"n a";s:3:"106";s:3:"pd ";s:3:"107";s:3:"st ";s:3:"108";s:3:"sta";s:3:"109";s:3:"ese";s:3:"110";s:3:"lic";s:3:"111";s:3:" ab";s:3:"112";s:3:" si";s:3:"113";s:3:"gte";s:3:"114";s:3:" wa";s:3:"115";s:3:"iti";s:3:"116";s:3:"kei";s:3:"117";s:3:"n e";s:3:"118";s:3:"nge";s:3:"119";s:3:"sei";s:3:"120";s:3:"tra";s:3:"121";s:3:"zen";s:3:"122";s:3:" im";s:3:"123";s:3:" la";s:3:"124";s:3:"art";s:3:"125";s:3:"im ";s:3:"126";s:3:"lle";s:3:"127";s:3:"n w";s:3:"128";s:3:"rde";s:3:"129";s:3:"rec";s:3:"130";s:3:"set";s:3:"131";s:3:"str";s:3:"132";s:3:"tei";s:3:"133";s:3:"tte";s:3:"134";s:3:" ni";s:3:"135";s:3:"e p";s:3:"136";s:3:"ehe";s:3:"137";s:3:"ers";s:3:"138";s:3:"g d";s:3:"139";s:3:"nic";s:3:"140";s:3:"von";s:3:"141";s:3:" al";s:3:"142";s:3:" pr";s:3:"143";s:3:"an ";s:3:"144";s:3:"aus";s:3:"145";s:3:"erf";s:3:"146";s:3:"r e";s:3:"147";s:3:"tze";s:3:"148";s:4:"tür";s:3:"149";s:3:"uf ";s:3:"150";s:3:"ag ";s:3:"151";s:3:"als";s:3:"152";s:3:"ar ";s:3:"153";s:3:"chs";s:3:"154";s:3:"end";s:3:"155";s:3:"ge ";s:3:"156";s:3:"ige";s:3:"157";s:3:"ion";s:3:"158";s:3:"ls ";s:3:"159";s:3:"n m";s:3:"160";s:3:"ngs";s:3:"161";s:3:"nis";s:3:"162";s:3:"nt ";s:3:"163";s:3:"ord";s:3:"164";s:3:"s s";s:3:"165";s:3:"sse";s:3:"166";s:4:" tü";s:3:"167";s:3:"ahl";s:3:"168";s:3:"e b";s:3:"169";s:3:"ede";s:3:"170";s:3:"em ";s:3:"171";s:3:"len";s:3:"172";s:3:"n i";s:3:"173";s:3:"orm";s:3:"174";s:3:"pro";s:3:"175";s:3:"rke";s:3:"176";s:3:"run";s:3:"177";s:3:"s d";s:3:"178";s:3:"wah";s:3:"179";s:3:"wer";s:3:"180";s:4:"ürk";s:3:"181";s:3:" me";s:3:"182";s:3:"age";s:3:"183";s:3:"att";s:3:"184";s:3:"ell";s:3:"185";s:3:"est";s:3:"186";s:3:"hat";s:3:"187";s:3:"n b";s:3:"188";s:3:"oll";s:3:"189";s:3:"raf";s:3:"190";s:3:"s a";s:3:"191";s:3:"tsc";s:3:"192";s:3:" es";s:3:"193";s:3:" fo";s:3:"194";s:3:" gr";s:3:"195";s:3:" ja";s:3:"196";s:3:"abe";s:3:"197";s:3:"auc";s:3:"198";s:3:"ben";s:3:"199";s:3:"e n";s:3:"200";s:3:"ege";s:3:"201";s:3:"lie";s:3:"202";s:3:"n u";s:3:"203";s:3:"r v";s:3:"204";s:3:"re ";s:3:"205";s:3:"rit";s:3:"206";s:3:"sag";s:3:"207";s:3:" am";s:3:"208";s:3:"agt";s:3:"209";s:3:"ahr";s:3:"210";s:3:"bra";s:3:"211";s:3:"de ";s:3:"212";s:3:"erd";s:3:"213";s:3:"her";s:3:"214";s:3:"ite";s:3:"215";s:3:"le ";s:3:"216";s:3:"n p";s:3:"217";s:3:"n v";s:3:"218";s:3:"or ";s:3:"219";s:3:"rbe";s:3:"220";s:3:"rt ";s:3:"221";s:3:"sic";s:3:"222";s:3:"wie";s:3:"223";s:4:"übe";s:3:"224";s:3:" is";s:3:"225";s:4:" üb";s:3:"226";s:3:"cha";s:3:"227";s:3:"chi";s:3:"228";s:3:"e f";s:3:"229";s:3:"e m";s:3:"230";s:3:"eri";s:3:"231";s:3:"ied";s:3:"232";s:3:"mme";s:3:"233";s:3:"ner";s:3:"234";s:3:"r a";s:3:"235";s:3:"sti";s:3:"236";s:3:"t a";s:3:"237";s:3:"t s";s:3:"238";s:3:"tis";s:3:"239";s:3:" ko";s:3:"240";s:3:"arb";s:3:"241";s:3:"ds ";s:3:"242";s:3:"gan";s:3:"243";s:3:"n z";s:3:"244";s:3:"r f";s:3:"245";s:3:"r w";s:3:"246";s:3:"ran";s:3:"247";s:3:"se ";s:3:"248";s:3:"t i";s:3:"249";s:3:"wei";s:3:"250";s:3:"wir";s:3:"251";s:3:" br";s:3:"252";s:3:" np";s:3:"253";s:3:"am ";s:3:"254";s:3:"bes";s:3:"255";s:3:"d d";s:3:"256";s:3:"deu";s:3:"257";s:3:"e g";s:3:"258";s:3:"e k";s:3:"259";s:3:"efo";s:3:"260";s:3:"et ";s:3:"261";s:3:"eut";s:3:"262";s:3:"fen";s:3:"263";s:3:"hse";s:3:"264";s:3:"lte";s:3:"265";s:3:"n r";s:3:"266";s:3:"npd";s:3:"267";s:3:"r b";s:3:"268";s:3:"rhe";s:3:"269";s:3:"t w";s:3:"270";s:3:"tz ";s:3:"271";s:3:" fr";s:3:"272";s:3:" ih";s:3:"273";s:3:" ke";s:3:"274";s:3:" ma";s:3:"275";s:3:"ame";s:3:"276";s:3:"ang";s:3:"277";s:3:"d s";s:3:"278";s:3:"eil";s:3:"279";s:3:"el ";s:3:"280";s:3:"era";s:3:"281";s:3:"erh";s:3:"282";s:3:"h d";s:3:"283";s:3:"i d";s:3:"284";s:3:"kan";s:3:"285";s:3:"n f";s:3:"286";s:3:"n l";s:3:"287";s:3:"nts";s:3:"288";s:3:"och";s:3:"289";s:3:"rag";s:3:"290";s:3:"rd ";s:3:"291";s:3:"spd";s:3:"292";s:3:"spr";s:3:"293";s:3:"tio";s:3:"294";s:3:" ar";s:3:"295";s:3:" en";s:3:"296";s:3:" ka";s:3:"297";s:3:"ark";s:3:"298";s:3:"ass";s:3:"299";}s:5:"hausa";a:300:{s:3:" da";s:1:"0";s:3:"da ";s:1:"1";s:3:"in ";s:1:"2";s:3:"an ";s:1:"3";s:3:"ya ";s:1:"4";s:3:" wa";s:1:"5";s:3:" ya";s:1:"6";s:3:"na ";s:1:"7";s:3:"ar ";s:1:"8";s:3:"a d";s:1:"9";s:3:" ma";s:2:"10";s:3:"wa ";s:2:"11";s:3:"a a";s:2:"12";s:3:"a k";s:2:"13";s:3:"a s";s:2:"14";s:3:" ta";s:2:"15";s:3:"wan";s:2:"16";s:3:" a ";s:2:"17";s:3:" ba";s:2:"18";s:3:" ka";s:2:"19";s:3:"ta ";s:2:"20";s:3:"a y";s:2:"21";s:3:"n d";s:2:"22";s:3:" ha";s:2:"23";s:3:" na";s:2:"24";s:3:" su";s:2:"25";s:3:" sa";s:2:"26";s:3:"kin";s:2:"27";s:3:"sa ";s:2:"28";s:3:"ata";s:2:"29";s:3:" ko";s:2:"30";s:3:"a t";s:2:"31";s:3:"su ";s:2:"32";s:3:" ga";s:2:"33";s:3:"ai ";s:2:"34";s:3:" sh";s:2:"35";s:3:"a m";s:2:"36";s:3:"uwa";s:2:"37";s:3:"iya";s:2:"38";s:3:"ma ";s:2:"39";s:3:"a w";s:2:"40";s:3:"asa";s:2:"41";s:3:"yan";s:2:"42";s:3:"ka ";s:2:"43";s:3:"ani";s:2:"44";s:3:"shi";s:2:"45";s:3:"a b";s:2:"46";s:3:"a h";s:2:"47";s:3:"a c";s:2:"48";s:3:"ama";s:2:"49";s:3:"ba ";s:2:"50";s:3:"nan";s:2:"51";s:3:"n a";s:2:"52";s:3:" mu";s:2:"53";s:3:"ana";s:2:"54";s:3:" yi";s:2:"55";s:3:"a g";s:2:"56";s:3:" za";s:2:"57";s:3:"i d";s:2:"58";s:3:" ku";s:2:"59";s:3:"aka";s:2:"60";s:3:"yi ";s:2:"61";s:3:"n k";s:2:"62";s:3:"ann";s:2:"63";s:3:"ke ";s:2:"64";s:3:"tar";s:2:"65";s:3:" ci";s:2:"66";s:3:"iki";s:2:"67";s:3:"n s";s:2:"68";s:3:"ko ";s:2:"69";s:3:" ra";s:2:"70";s:3:"ki ";s:2:"71";s:3:"ne ";s:2:"72";s:3:"a z";s:2:"73";s:3:"mat";s:2:"74";s:3:"hak";s:2:"75";s:3:"nin";s:2:"76";s:3:"e d";s:2:"77";s:3:"nna";s:2:"78";s:3:"uma";s:2:"79";s:3:"nda";s:2:"80";s:3:"a n";s:2:"81";s:3:"ada";s:2:"82";s:3:"cik";s:2:"83";s:3:"ni ";s:2:"84";s:3:"rin";s:2:"85";s:3:"una";s:2:"86";s:3:"ara";s:2:"87";s:3:"kum";s:2:"88";s:3:"akk";s:2:"89";s:3:" ce";s:2:"90";s:3:" du";s:2:"91";s:3:"man";s:2:"92";s:3:"n y";s:2:"93";s:3:"nci";s:2:"94";s:3:"sar";s:2:"95";s:3:"aki";s:2:"96";s:3:"awa";s:2:"97";s:3:"ci ";s:2:"98";s:3:"kan";s:2:"99";s:3:"kar";s:3:"100";s:3:"ari";s:3:"101";s:3:"n m";s:3:"102";s:3:"and";s:3:"103";s:3:"hi ";s:3:"104";s:3:"n t";s:3:"105";s:3:"ga ";s:3:"106";s:3:"owa";s:3:"107";s:3:"ash";s:3:"108";s:3:"kam";s:3:"109";s:3:"dan";s:3:"110";s:3:"ewa";s:3:"111";s:3:"nsa";s:3:"112";s:3:"ali";s:3:"113";s:3:"ami";s:3:"114";s:3:" ab";s:3:"115";s:3:" do";s:3:"116";s:3:"anc";s:3:"117";s:3:"n r";s:3:"118";s:3:"aya";s:3:"119";s:3:"i n";s:3:"120";s:3:"sun";s:3:"121";s:3:"uka";s:3:"122";s:3:" al";s:3:"123";s:3:" ne";s:3:"124";s:3:"a'a";s:3:"125";s:3:"cew";s:3:"126";s:3:"cin";s:3:"127";s:3:"mas";s:3:"128";s:3:"tak";s:3:"129";s:3:"un ";s:3:"130";s:3:"aba";s:3:"131";s:3:"kow";s:3:"132";s:3:"a r";s:3:"133";s:3:"ra ";s:3:"134";s:3:" ja";s:3:"135";s:4:" Æ™a";s:3:"136";s:3:"en ";s:3:"137";s:3:"r d";s:3:"138";s:3:"sam";s:3:"139";s:3:"tsa";s:3:"140";s:3:" ru";s:3:"141";s:3:"ce ";s:3:"142";s:3:"i a";s:3:"143";s:3:"abi";s:3:"144";s:3:"ida";s:3:"145";s:3:"mut";s:3:"146";s:3:"n g";s:3:"147";s:3:"n j";s:3:"148";s:3:"san";s:3:"149";s:4:"a Æ™";s:3:"150";s:3:"har";s:3:"151";s:3:"on ";s:3:"152";s:3:"i m";s:3:"153";s:3:"suk";s:3:"154";s:3:" ak";s:3:"155";s:3:" ji";s:3:"156";s:3:"yar";s:3:"157";s:3:"'ya";s:3:"158";s:3:"kwa";s:3:"159";s:3:"min";s:3:"160";s:3:" 'y";s:3:"161";s:3:"ane";s:3:"162";s:3:"ban";s:3:"163";s:3:"ins";s:3:"164";s:3:"ruw";s:3:"165";s:3:"i k";s:3:"166";s:3:"n h";s:3:"167";s:3:" ad";s:3:"168";s:3:"ake";s:3:"169";s:3:"n w";s:3:"170";s:3:"sha";s:3:"171";s:3:"utu";s:3:"172";s:4:" Æ´a";s:3:"173";s:3:"bay";s:3:"174";s:3:"tan";s:3:"175";s:4:"Æ´an";s:3:"176";s:3:"bin";s:3:"177";s:3:"duk";s:3:"178";s:3:"e m";s:3:"179";s:3:"n n";s:3:"180";s:3:"oka";s:3:"181";s:3:"yin";s:3:"182";s:4:"É—an";s:3:"183";s:3:" fa";s:3:"184";s:3:"a i";s:3:"185";s:3:"kki";s:3:"186";s:3:"re ";s:3:"187";s:3:"za ";s:3:"188";s:3:"ala";s:3:"189";s:3:"asu";s:3:"190";s:3:"han";s:3:"191";s:3:"i y";s:3:"192";s:3:"mar";s:3:"193";s:3:"ran";s:3:"194";s:4:"Æ™as";s:3:"195";s:3:"add";s:3:"196";s:3:"ars";s:3:"197";s:3:"gab";s:3:"198";s:3:"ira";s:3:"199";s:3:"mma";s:3:"200";s:3:"u d";s:3:"201";s:3:" ts";s:3:"202";s:3:"abb";s:3:"203";s:3:"abu";s:3:"204";s:3:"aga";s:3:"205";s:3:"gar";s:3:"206";s:3:"n b";s:3:"207";s:4:" É—a";s:3:"208";s:3:"aci";s:3:"209";s:3:"aik";s:3:"210";s:3:"am ";s:3:"211";s:3:"dun";s:3:"212";s:3:"e s";s:3:"213";s:3:"i b";s:3:"214";s:3:"i w";s:3:"215";s:3:"kas";s:3:"216";s:3:"kok";s:3:"217";s:3:"wam";s:3:"218";s:3:" am";s:3:"219";s:3:"amf";s:3:"220";s:3:"bba";s:3:"221";s:3:"din";s:3:"222";s:3:"fan";s:3:"223";s:3:"gwa";s:3:"224";s:3:"i s";s:3:"225";s:3:"wat";s:3:"226";s:3:"ano";s:3:"227";s:3:"are";s:3:"228";s:3:"dai";s:3:"229";s:3:"iri";s:3:"230";s:3:"ma'";s:3:"231";s:3:" la";s:3:"232";s:3:"all";s:3:"233";s:3:"dam";s:3:"234";s:3:"ika";s:3:"235";s:3:"mi ";s:3:"236";s:3:"she";s:3:"237";s:3:"tum";s:3:"238";s:3:"uni";s:3:"239";s:3:" an";s:3:"240";s:3:" ai";s:3:"241";s:3:" ke";s:3:"242";s:3:" ki";s:3:"243";s:3:"dag";s:3:"244";s:3:"mai";s:3:"245";s:3:"mfa";s:3:"246";s:3:"no ";s:3:"247";s:3:"nsu";s:3:"248";s:3:"o d";s:3:"249";s:3:"sak";s:3:"250";s:3:"um ";s:3:"251";s:3:" bi";s:3:"252";s:3:" gw";s:3:"253";s:3:" kw";s:3:"254";s:3:"jam";s:3:"255";s:3:"yya";s:3:"256";s:3:"a j";s:3:"257";s:3:"fa ";s:3:"258";s:3:"uta";s:3:"259";s:3:" hu";s:3:"260";s:3:"'a ";s:3:"261";s:3:"ans";s:3:"262";s:4:"aÉ—a";s:3:"263";s:3:"dda";s:3:"264";s:3:"hin";s:3:"265";s:3:"niy";s:3:"266";s:3:"r s";s:3:"267";s:3:"bat";s:3:"268";s:3:"dar";s:3:"269";s:3:"gan";s:3:"270";s:3:"i t";s:3:"271";s:3:"nta";s:3:"272";s:3:"oki";s:3:"273";s:3:"omi";s:3:"274";s:3:"sal";s:3:"275";s:3:"a l";s:3:"276";s:3:"kac";s:3:"277";s:3:"lla";s:3:"278";s:3:"wad";s:3:"279";s:3:"war";s:3:"280";s:3:"amm";s:3:"281";s:3:"dom";s:3:"282";s:3:"r m";s:3:"283";s:3:"ras";s:3:"284";s:3:"sai";s:3:"285";s:3:" lo";s:3:"286";s:3:"ats";s:3:"287";s:3:"hal";s:3:"288";s:3:"kat";s:3:"289";s:3:"li ";s:3:"290";s:3:"lok";s:3:"291";s:3:"n c";s:3:"292";s:3:"nar";s:3:"293";s:3:"tin";s:3:"294";s:3:"afa";s:3:"295";s:3:"bub";s:3:"296";s:3:"i g";s:3:"297";s:3:"isa";s:3:"298";s:3:"mak";s:3:"299";}s:8:"hawaiian";a:300:{s:3:" ka";s:1:"0";s:3:"na ";s:1:"1";s:3:" o ";s:1:"2";s:3:"ka ";s:1:"3";s:3:" ma";s:1:"4";s:3:" a ";s:1:"5";s:3:" la";s:1:"6";s:3:"a i";s:1:"7";s:3:"a m";s:1:"8";s:3:" i ";s:1:"9";s:3:"la ";s:2:"10";s:3:"ana";s:2:"11";s:3:"ai ";s:2:"12";s:3:"ia ";s:2:"13";s:3:"a o";s:2:"14";s:3:"a k";s:2:"15";s:3:"a h";s:2:"16";s:3:"o k";s:2:"17";s:3:" ke";s:2:"18";s:3:"a a";s:2:"19";s:3:"i k";s:2:"20";s:3:" ho";s:2:"21";s:3:" ia";s:2:"22";s:3:"ua ";s:2:"23";s:3:" na";s:2:"24";s:3:" me";s:2:"25";s:3:"e k";s:2:"26";s:3:"e a";s:2:"27";s:3:"au ";s:2:"28";s:3:"ke ";s:2:"29";s:3:"ma ";s:2:"30";s:3:"mai";s:2:"31";s:3:"aku";s:2:"32";s:3:" ak";s:2:"33";s:3:"ahi";s:2:"34";s:3:" ha";s:2:"35";s:3:" ko";s:2:"36";s:3:" e ";s:2:"37";s:3:"a l";s:2:"38";s:3:" no";s:2:"39";s:3:"me ";s:2:"40";s:3:"ku ";s:2:"41";s:3:"aka";s:2:"42";s:3:"kan";s:2:"43";s:3:"no ";s:2:"44";s:3:"i a";s:2:"45";s:3:"ho ";s:2:"46";s:3:"ou ";s:2:"47";s:3:" ai";s:2:"48";s:3:"i o";s:2:"49";s:3:"a p";s:2:"50";s:3:"o l";s:2:"51";s:3:"o a";s:2:"52";s:3:"ama";s:2:"53";s:3:"a n";s:2:"54";s:3:" an";s:2:"55";s:3:"i m";s:2:"56";s:3:"han";s:2:"57";s:3:"i i";s:2:"58";s:3:"iho";s:2:"59";s:3:"kou";s:2:"60";s:3:"ne ";s:2:"61";s:3:" ih";s:2:"62";s:3:"o i";s:2:"63";s:3:"iki";s:2:"64";s:3:"ona";s:2:"65";s:3:"hoo";s:2:"66";s:3:"le ";s:2:"67";s:3:"e h";s:2:"68";s:3:" he";s:2:"69";s:3:"ina";s:2:"70";s:3:" wa";s:2:"71";s:3:"ea ";s:2:"72";s:3:"ako";s:2:"73";s:3:"u i";s:2:"74";s:3:"kah";s:2:"75";s:3:"oe ";s:2:"76";s:3:"i l";s:2:"77";s:3:"u a";s:2:"78";s:3:" pa";s:2:"79";s:3:"hoi";s:2:"80";s:3:"e i";s:2:"81";s:3:"era";s:2:"82";s:3:"ko ";s:2:"83";s:3:"u m";s:2:"84";s:3:"kua";s:2:"85";s:3:"mak";s:2:"86";s:3:"oi ";s:2:"87";s:3:"kai";s:2:"88";s:3:"i n";s:2:"89";s:3:"a e";s:2:"90";s:3:"hin";s:2:"91";s:3:"ane";s:2:"92";s:3:" ol";s:2:"93";s:3:"i h";s:2:"94";s:3:"mea";s:2:"95";s:3:"wah";s:2:"96";s:3:"lak";s:2:"97";s:3:"e m";s:2:"98";s:3:"o n";s:2:"99";s:3:"u l";s:3:"100";s:3:"ika";s:3:"101";s:3:"ki ";s:3:"102";s:3:"a w";s:3:"103";s:3:"mal";s:3:"104";s:3:"hi ";s:3:"105";s:3:"e n";s:3:"106";s:3:"u o";s:3:"107";s:3:"hik";s:3:"108";s:3:" ku";s:3:"109";s:3:"e l";s:3:"110";s:3:"ele";s:3:"111";s:3:"ra ";s:3:"112";s:3:"ber";s:3:"113";s:3:"ine";s:3:"114";s:3:"abe";s:3:"115";s:3:"ain";s:3:"116";s:3:"ala";s:3:"117";s:3:"lo ";s:3:"118";s:3:" po";s:3:"119";s:3:"kon";s:3:"120";s:3:" ab";s:3:"121";s:3:"ole";s:3:"122";s:3:"he ";s:3:"123";s:3:"pau";s:3:"124";s:3:"mah";s:3:"125";s:3:"va ";s:3:"126";s:3:"ela";s:3:"127";s:3:"kau";s:3:"128";s:3:"nak";s:3:"129";s:3:" oe";s:3:"130";s:3:"kei";s:3:"131";s:3:"oia";s:3:"132";s:3:" ie";s:3:"133";s:3:"ram";s:3:"134";s:3:" oi";s:3:"135";s:3:"oa ";s:3:"136";s:3:"eho";s:3:"137";s:3:"hov";s:3:"138";s:3:"ieh";s:3:"139";s:3:"ova";s:3:"140";s:3:" ua";s:3:"141";s:3:"una";s:3:"142";s:3:"ara";s:3:"143";s:3:"o s";s:3:"144";s:3:"awa";s:3:"145";s:3:"o o";s:3:"146";s:3:"nau";s:3:"147";s:3:"u n";s:3:"148";s:3:"wa ";s:3:"149";s:3:"wai";s:3:"150";s:3:"hel";s:3:"151";s:3:" ae";s:3:"152";s:3:" al";s:3:"153";s:3:"ae ";s:3:"154";s:3:"ta ";s:3:"155";s:3:"aik";s:3:"156";s:3:" hi";s:3:"157";s:3:"ale";s:3:"158";s:3:"ila";s:3:"159";s:3:"lel";s:3:"160";s:3:"ali";s:3:"161";s:3:"eik";s:3:"162";s:3:"olo";s:3:"163";s:3:"onu";s:3:"164";s:3:" lo";s:3:"165";s:3:"aua";s:3:"166";s:3:"e o";s:3:"167";s:3:"ola";s:3:"168";s:3:"hon";s:3:"169";s:3:"mam";s:3:"170";s:3:"nan";s:3:"171";s:3:" au";s:3:"172";s:3:"aha";s:3:"173";s:3:"lau";s:3:"174";s:3:"nua";s:3:"175";s:3:"oho";s:3:"176";s:3:"oma";s:3:"177";s:3:" ao";s:3:"178";s:3:"ii ";s:3:"179";s:3:"alu";s:3:"180";s:3:"ima";s:3:"181";s:3:"mau";s:3:"182";s:3:"ike";s:3:"183";s:3:"apa";s:3:"184";s:3:"elo";s:3:"185";s:3:"lii";s:3:"186";s:3:"poe";s:3:"187";s:3:"aia";s:3:"188";s:3:"noa";s:3:"189";s:3:" in";s:3:"190";s:3:"o m";s:3:"191";s:3:"oka";s:3:"192";s:3:"'u ";s:3:"193";s:3:"aho";s:3:"194";s:3:"ei ";s:3:"195";s:3:"eka";s:3:"196";s:3:"ha ";s:3:"197";s:3:"lu ";s:3:"198";s:3:"nei";s:3:"199";s:3:"hol";s:3:"200";s:3:"ino";s:3:"201";s:3:"o e";s:3:"202";s:3:"ema";s:3:"203";s:3:"iwa";s:3:"204";s:3:"olu";s:3:"205";s:3:"ada";s:3:"206";s:3:"naa";s:3:"207";s:3:"pa ";s:3:"208";s:3:"u k";s:3:"209";s:3:"ewa";s:3:"210";s:3:"hua";s:3:"211";s:3:"lam";s:3:"212";s:3:"lua";s:3:"213";s:3:"o h";s:3:"214";s:3:"ook";s:3:"215";s:3:"u h";s:3:"216";s:3:" li";s:3:"217";s:3:"ahu";s:3:"218";s:3:"amu";s:3:"219";s:3:"ui ";s:3:"220";s:3:" il";s:3:"221";s:3:" mo";s:3:"222";s:3:" se";s:3:"223";s:3:"eia";s:3:"224";s:3:"law";s:3:"225";s:3:" hu";s:3:"226";s:3:" ik";s:3:"227";s:3:"ail";s:3:"228";s:3:"e p";s:3:"229";s:3:"li ";s:3:"230";s:3:"lun";s:3:"231";s:3:"uli";s:3:"232";s:3:"io ";s:3:"233";s:3:"kik";s:3:"234";s:3:"noh";s:3:"235";s:3:"u e";s:3:"236";s:3:" sa";s:3:"237";s:3:"aaw";s:3:"238";s:3:"awe";s:3:"239";s:3:"ena";s:3:"240";s:3:"hal";s:3:"241";s:3:"kol";s:3:"242";s:3:"lan";s:3:"243";s:3:" le";s:3:"244";s:3:" ne";s:3:"245";s:3:"a'u";s:3:"246";s:3:"ilo";s:3:"247";s:3:"kap";s:3:"248";s:3:"oko";s:3:"249";s:3:"sa ";s:3:"250";s:3:" pe";s:3:"251";s:3:"hop";s:3:"252";s:3:"loa";s:3:"253";s:3:"ope";s:3:"254";s:3:"pe ";s:3:"255";s:3:" ad";s:3:"256";s:3:" pu";s:3:"257";s:3:"ahe";s:3:"258";s:3:"aol";s:3:"259";s:3:"ia'";s:3:"260";s:3:"lai";s:3:"261";s:3:"loh";s:3:"262";s:3:"na'";s:3:"263";s:3:"oom";s:3:"264";s:3:"aau";s:3:"265";s:3:"eri";s:3:"266";s:3:"kul";s:3:"267";s:3:"we ";s:3:"268";s:3:"ake";s:3:"269";s:3:"kek";s:3:"270";s:3:"laa";s:3:"271";s:3:"ri ";s:3:"272";s:3:"iku";s:3:"273";s:3:"kak";s:3:"274";s:3:"lim";s:3:"275";s:3:"nah";s:3:"276";s:3:"ner";s:3:"277";s:3:"nui";s:3:"278";s:3:"ono";s:3:"279";s:3:"a u";s:3:"280";s:3:"dam";s:3:"281";s:3:"kum";s:3:"282";s:3:"lok";s:3:"283";s:3:"mua";s:3:"284";s:3:"uma";s:3:"285";s:3:"wal";s:3:"286";s:3:"wi ";s:3:"287";s:3:"'i ";s:3:"288";s:3:"a'i";s:3:"289";s:3:"aan";s:3:"290";s:3:"alo";s:3:"291";s:3:"eta";s:3:"292";s:3:"mu ";s:3:"293";s:3:"ohe";s:3:"294";s:3:"u p";s:3:"295";s:3:"ula";s:3:"296";s:3:"uwa";s:3:"297";s:3:" nu";s:3:"298";s:3:"amo";s:3:"299";}s:5:"hindi";a:300:{s:7:"ें ";s:1:"0";s:7:" है";s:1:"1";s:9:"में";s:1:"2";s:7:" मे";s:1:"3";s:7:"ने ";s:1:"4";s:7:"की ";s:1:"5";s:7:"के ";s:1:"6";s:7:"है ";s:1:"7";s:7:" के";s:1:"8";s:7:" की";s:1:"9";s:7:" को";s:2:"10";s:7:"ों ";s:2:"11";s:7:"को ";s:2:"12";s:7:"ा ह";s:2:"13";s:7:" का";s:2:"14";s:7:"से ";s:2:"15";s:7:"ा क";s:2:"16";s:7:"े क";s:2:"17";s:7:"ं क";s:2:"18";s:7:"या ";s:2:"19";s:7:" कि";s:2:"20";s:7:" से";s:2:"21";s:7:"का ";s:2:"22";s:7:"ी क";s:2:"23";s:7:" ने";s:2:"24";s:7:" और";s:2:"25";s:7:"और ";s:2:"26";s:7:"ना ";s:2:"27";s:7:"कि ";s:2:"28";s:7:"भी ";s:2:"29";s:7:"ी स";s:2:"30";s:7:" जा";s:2:"31";s:7:" पर";s:2:"32";s:7:"ार ";s:2:"33";s:7:" कर";s:2:"34";s:7:"ी ह";s:2:"35";s:7:" हो";s:2:"36";s:7:"ही ";s:2:"37";s:9:"िया";s:2:"38";s:7:" इस";s:2:"39";s:7:" रह";s:2:"40";s:7:"र क";s:2:"41";s:9:"à¥à¤¨à¤¾";s:2:"42";s:7:"ता ";s:2:"43";s:7:"ान ";s:2:"44";s:7:"े स";s:2:"45";s:7:" भी";s:2:"46";s:7:" रा";s:2:"47";s:7:"े ह";s:2:"48";s:7:" चà¥";s:2:"49";s:7:" पा";s:2:"50";s:7:"पर ";s:2:"51";s:9:"चà¥à¤¨";s:2:"52";s:9:"नाव";s:2:"53";s:7:" कह";s:2:"54";s:9:"पà¥à¤°";s:2:"55";s:7:" भा";s:2:"56";s:9:"राज";s:2:"57";s:9:"हैं";s:2:"58";s:7:"ा स";s:2:"59";s:7:"ै क";s:2:"60";s:7:"ैं ";s:2:"61";s:7:"नी ";s:2:"62";s:7:"ल क";s:2:"63";s:7:"ीं ";s:2:"64";s:7:"़ी ";s:2:"65";s:7:"था ";s:2:"66";s:7:"री ";s:2:"67";s:7:"ाव ";s:2:"68";s:7:"े ब";s:2:"69";s:7:" पà¥";s:2:"70";s:9:"कà¥à¤·";s:2:"71";s:7:"पा ";s:2:"72";s:7:"ले ";s:2:"73";s:7:" दे";s:2:"74";s:7:"ला ";s:2:"75";s:7:"हा ";s:2:"76";s:9:"ाजप";s:2:"77";s:7:" था";s:2:"78";s:7:" नह";s:2:"79";s:7:"इस ";s:2:"80";s:7:"कर ";s:2:"81";s:9:"जपा";s:2:"82";s:9:"नही";s:2:"83";s:9:"भाज";s:2:"84";s:9:"यों";s:2:"85";s:7:"र स";s:2:"86";s:9:"हीं";s:2:"87";s:7:" अम";s:2:"88";s:7:" बा";s:2:"89";s:7:" मा";s:2:"90";s:7:" वि";s:2:"91";s:9:"रीक";s:2:"92";s:7:"िठ";s:2:"93";s:7:"े प";s:2:"94";s:9:"à¥à¤¯à¤¾";s:2:"95";s:7:" ही";s:2:"96";s:7:"ं म";s:2:"97";s:9:"कार";s:2:"98";s:7:"ा ज";s:2:"99";s:7:"े ल";s:3:"100";s:7:" ता";s:3:"101";s:7:" दि";s:3:"102";s:7:" सा";s:3:"103";s:7:" हम";s:3:"104";s:7:"ा न";s:3:"105";s:7:"ा म";s:3:"106";s:9:"ाक़";s:3:"107";s:9:"à¥à¤¤à¤¾";s:3:"108";s:7:" à¤à¤•";s:3:"109";s:7:" सं";s:3:"110";s:7:" सà¥";s:3:"111";s:9:"अमर";s:3:"112";s:9:"क़ी";s:3:"113";s:9:"ताज";s:3:"114";s:9:"मरी";s:3:"115";s:9:"सà¥à¤¥";s:3:"116";s:7:"ा थ";s:3:"117";s:9:"ारà¥";s:3:"118";s:7:" हà¥";s:3:"119";s:9:"इरा";s:3:"120";s:7:"à¤à¤• ";s:3:"121";s:7:"न क";s:3:"122";s:7:"र म";s:3:"123";s:9:"राक";s:3:"124";s:7:"ी ज";s:3:"125";s:7:"ी न";s:3:"126";s:7:" इर";s:3:"127";s:7:" उन";s:3:"128";s:7:" पह";s:3:"129";s:9:"कहा";s:3:"130";s:7:"ते ";s:3:"131";s:7:"े अ";s:3:"132";s:7:" तो";s:3:"133";s:7:" सà¥";s:3:"134";s:7:"ति ";s:3:"135";s:7:"ती ";s:3:"136";s:7:"तो ";s:3:"137";s:9:"मिल";s:3:"138";s:7:"िक ";s:3:"139";s:9:"ियो";s:3:"140";s:9:"à¥à¤°à¥‡";s:3:"141";s:7:" अप";s:3:"142";s:7:" फ़";s:3:"143";s:7:" लि";s:3:"144";s:7:" लो";s:3:"145";s:7:" सम";s:3:"146";s:7:"म क";s:3:"147";s:9:"रà¥à¤Ÿ";s:3:"148";s:7:"हो ";s:3:"149";s:7:"ा च";s:3:"150";s:7:"ाई ";s:3:"151";s:9:"ाने";s:3:"152";s:7:"िन ";s:3:"153";s:7:"à¥à¤¯ ";s:3:"154";s:7:" उस";s:3:"155";s:7:" क़";s:3:"156";s:7:" सक";s:3:"157";s:7:" सै";s:3:"158";s:7:"ं प";s:3:"159";s:7:"ं ह";s:3:"160";s:7:"गी ";s:3:"161";s:7:"त क";s:3:"162";s:9:"मान";s:3:"163";s:7:"र न";s:3:"164";s:9:"षà¥à¤Ÿ";s:3:"165";s:7:"स क";s:3:"166";s:9:"सà¥à¤¤";s:3:"167";s:7:"ाठ";s:3:"168";s:7:"ी ब";s:3:"169";s:7:"ी म";s:3:"170";s:9:"à¥à¤°à¥€";s:3:"171";s:7:" दो";s:3:"172";s:7:" मि";s:3:"173";s:7:" मà¥";s:3:"174";s:7:" ले";s:3:"175";s:7:" शा";s:3:"176";s:7:"ं स";s:3:"177";s:9:"ज़ा";s:3:"178";s:9:"तà¥à¤°";s:3:"179";s:7:"थी ";s:3:"180";s:9:"लिà¤";s:3:"181";s:7:"सी ";s:3:"182";s:7:"़ा ";s:3:"183";s:9:"़ार";s:3:"184";s:9:"ांग";s:3:"185";s:7:"े द";s:3:"186";s:7:"े म";s:3:"187";s:7:"à¥à¤µ ";s:3:"188";s:7:" ना";s:3:"189";s:7:" बन";s:3:"190";s:9:"ंगà¥";s:3:"191";s:9:"कां";s:3:"192";s:7:"गा ";s:3:"193";s:9:"गà¥à¤°";s:3:"194";s:7:"जा ";s:3:"195";s:9:"जà¥à¤¯";s:3:"196";s:7:"दी ";s:3:"197";s:7:"न म";s:3:"198";s:9:"पार";s:3:"199";s:7:"भा ";s:3:"200";s:9:"रही";s:3:"201";s:7:"रे ";s:3:"202";s:9:"रेस";s:3:"203";s:7:"ली ";s:3:"204";s:9:"सभा";s:3:"205";s:7:"ा र";s:3:"206";s:7:"ाल ";s:3:"207";s:7:"ी अ";s:3:"208";s:9:"ीकी";s:3:"209";s:7:"े त";s:3:"210";s:7:"ेश ";s:3:"211";s:7:" अं";s:3:"212";s:7:" तक";s:3:"213";s:7:" या";s:3:"214";s:7:"ई ह";s:3:"215";s:9:"करन";s:3:"216";s:7:"तक ";s:3:"217";s:9:"देश";s:3:"218";s:9:"वरà¥";s:3:"219";s:9:"ाया";s:3:"220";s:7:"ी भ";s:3:"221";s:7:"ेस ";s:3:"222";s:7:"à¥à¤· ";s:3:"223";s:7:" गय";s:3:"224";s:7:" जि";s:3:"225";s:7:" थी";s:3:"226";s:7:" बड";s:3:"227";s:7:" यह";s:3:"228";s:7:" वा";s:3:"229";s:9:"ंतर";s:3:"230";s:9:"अंत";s:3:"231";s:7:"क़ ";s:3:"232";s:9:"गया";s:3:"233";s:7:"टी ";s:3:"234";s:9:"निक";s:3:"235";s:9:"नà¥à¤¹";s:3:"236";s:9:"पहल";s:3:"237";s:9:"बड़";s:3:"238";s:9:"मार";s:3:"239";s:7:"र प";s:3:"240";s:9:"रने";s:3:"241";s:9:"ाज़";s:3:"242";s:7:"ि इ";s:3:"243";s:7:"ी र";s:3:"244";s:7:"े ज";s:3:"245";s:7:"े व";s:3:"246";s:7:"à¥à¤Ÿ ";s:3:"247";s:9:"à¥à¤Ÿà¥€";s:3:"248";s:7:" अब";s:3:"249";s:7:" लग";s:3:"250";s:7:" वर";s:3:"251";s:7:" सी";s:3:"252";s:7:"ं भ";s:3:"253";s:9:"उनà¥";s:3:"254";s:7:"क क";s:3:"255";s:9:"किय";s:3:"256";s:9:"देख";s:3:"257";s:9:"पूर";s:3:"258";s:9:"फ़à¥";s:3:"259";s:7:"यह ";s:3:"260";s:9:"यान";s:3:"261";s:9:"रिक";s:3:"262";s:9:"रिय";s:3:"263";s:9:"रà¥à¤¡";s:3:"264";s:9:"लेक";s:3:"265";s:9:"सकत";s:3:"266";s:9:"हों";s:3:"267";s:9:"होग";s:3:"268";s:7:"ा अ";s:3:"269";s:7:"ा द";s:3:"270";s:7:"ा प";s:3:"271";s:7:"ाद ";s:3:"272";s:9:"ारा";s:3:"273";s:7:"ित ";s:3:"274";s:7:"ी त";s:3:"275";s:7:"ी प";s:3:"276";s:7:"ो क";s:3:"277";s:7:"ो द";s:3:"278";s:7:" ते";s:3:"279";s:7:" नि";s:3:"280";s:7:" सर";s:3:"281";s:7:" हा";s:3:"282";s:7:"ं द";s:3:"283";s:9:"अपन";s:3:"284";s:9:"जान";s:3:"285";s:7:"त म";s:3:"286";s:9:"थित";s:3:"287";s:9:"पनी";s:3:"288";s:9:"महल";s:3:"289";s:7:"र ह";s:3:"290";s:9:"लोग";s:3:"291";s:7:"व क";s:3:"292";s:9:"हना";s:3:"293";s:7:"हल ";s:3:"294";s:9:"हाà¤";s:3:"295";s:9:"ाजà¥";s:3:"296";s:9:"ाना";s:3:"297";s:9:"िकà¥";s:3:"298";s:9:"िसà¥";s:3:"299";}s:9:"hungarian";a:300:{s:3:" a ";s:1:"0";s:3:" az";s:1:"1";s:3:" sz";s:1:"2";s:3:"az ";s:1:"3";s:3:" me";s:1:"4";s:3:"en ";s:1:"5";s:3:" el";s:1:"6";s:3:" ho";s:1:"7";s:3:"ek ";s:1:"8";s:3:"gy ";s:1:"9";s:3:"tt ";s:2:"10";s:3:"ett";s:2:"11";s:3:"sze";s:2:"12";s:3:" fe";s:2:"13";s:4:"és ";s:2:"14";s:3:" ki";s:2:"15";s:3:"tet";s:2:"16";s:3:" be";s:2:"17";s:3:"et ";s:2:"18";s:3:"ter";s:2:"19";s:4:" kö";s:2:"20";s:4:" és";s:2:"21";s:3:"hog";s:2:"22";s:3:"meg";s:2:"23";s:3:"ogy";s:2:"24";s:3:"szt";s:2:"25";s:3:"te ";s:2:"26";s:3:"t a";s:2:"27";s:3:"zet";s:2:"28";s:3:"a m";s:2:"29";s:3:"nek";s:2:"30";s:3:"nt ";s:2:"31";s:4:"ség";s:2:"32";s:4:"szá";s:2:"33";s:3:"ak ";s:2:"34";s:3:" va";s:2:"35";s:3:"an ";s:2:"36";s:3:"eze";s:2:"37";s:3:"ra ";s:2:"38";s:3:"ta ";s:2:"39";s:3:" mi";s:2:"40";s:3:"int";s:2:"41";s:4:"köz";s:2:"42";s:3:" is";s:2:"43";s:3:"esz";s:2:"44";s:3:"fel";s:2:"45";s:3:"min";s:2:"46";s:3:"nak";s:2:"47";s:3:"ors";s:2:"48";s:3:"zer";s:2:"49";s:3:" te";s:2:"50";s:3:"a a";s:2:"51";s:3:"a k";s:2:"52";s:3:"is ";s:2:"53";s:3:" cs";s:2:"54";s:3:"ele";s:2:"55";s:3:"er ";s:2:"56";s:3:"men";s:2:"57";s:3:"si ";s:2:"58";s:3:"tek";s:2:"59";s:3:"ti ";s:2:"60";s:3:" ne";s:2:"61";s:3:"csa";s:2:"62";s:3:"ent";s:2:"63";s:3:"z e";s:2:"64";s:3:"a t";s:2:"65";s:3:"ala";s:2:"66";s:3:"ere";s:2:"67";s:3:"es ";s:2:"68";s:3:"lom";s:2:"69";s:3:"lte";s:2:"70";s:3:"mon";s:2:"71";s:3:"ond";s:2:"72";s:3:"rsz";s:2:"73";s:3:"sza";s:2:"74";s:3:"tte";s:2:"75";s:4:"zág";s:2:"76";s:4:"ány";s:2:"77";s:3:" fo";s:2:"78";s:3:" ma";s:2:"79";s:3:"ai ";s:2:"80";s:3:"ben";s:2:"81";s:3:"el ";s:2:"82";s:3:"ene";s:2:"83";s:3:"ik ";s:2:"84";s:3:"jel";s:2:"85";s:4:"tás";s:2:"86";s:4:"áll";s:2:"87";s:3:" ha";s:2:"88";s:3:" le";s:2:"89";s:4:" ál";s:2:"90";s:3:"agy";s:2:"91";s:4:"alá";s:2:"92";s:3:"isz";s:2:"93";s:3:"y a";s:2:"94";s:3:"zte";s:2:"95";s:4:"ás ";s:2:"96";s:3:" al";s:2:"97";s:3:"e a";s:2:"98";s:3:"egy";s:2:"99";s:3:"ely";s:3:"100";s:3:"for";s:3:"101";s:3:"lat";s:3:"102";s:3:"lt ";s:3:"103";s:3:"n a";s:3:"104";s:3:"oga";s:3:"105";s:3:"on ";s:3:"106";s:3:"re ";s:3:"107";s:3:"st ";s:3:"108";s:4:"ság";s:3:"109";s:3:"t m";s:3:"110";s:4:"án ";s:3:"111";s:4:"ét ";s:3:"112";s:4:"ült";s:3:"113";s:3:" je";s:3:"114";s:3:"gi ";s:3:"115";s:3:"k a";s:3:"116";s:4:"kül";s:3:"117";s:3:"lam";s:3:"118";s:3:"len";s:3:"119";s:4:"lás";s:3:"120";s:4:"más";s:3:"121";s:3:"s k";s:3:"122";s:3:"vez";s:3:"123";s:4:"áso";s:3:"124";s:5:"özö";s:3:"125";s:3:" ta";s:3:"126";s:3:"a s";s:3:"127";s:3:"a v";s:3:"128";s:3:"asz";s:3:"129";s:4:"atá";s:3:"130";s:4:"etÅ‘";s:3:"131";s:3:"kez";s:3:"132";s:3:"let";s:3:"133";s:3:"mag";s:3:"134";s:3:"nem";s:3:"135";s:4:"szé";s:3:"136";s:3:"z m";s:3:"137";s:4:"át ";s:3:"138";s:4:"éte";s:3:"139";s:4:"ölt";s:3:"140";s:3:" de";s:3:"141";s:3:" gy";s:3:"142";s:4:" ké";s:3:"143";s:3:" mo";s:3:"144";s:4:" vá";s:3:"145";s:4:" ér";s:3:"146";s:3:"a b";s:3:"147";s:3:"a f";s:3:"148";s:3:"ami";s:3:"149";s:3:"at ";s:3:"150";s:3:"ato";s:3:"151";s:3:"att";s:3:"152";s:3:"bef";s:3:"153";s:3:"dta";s:3:"154";s:3:"gya";s:3:"155";s:3:"hat";s:3:"156";s:3:"i s";s:3:"157";s:3:"las";s:3:"158";s:3:"ndt";s:3:"159";s:3:"rt ";s:3:"160";s:3:"szo";s:3:"161";s:3:"t k";s:3:"162";s:4:"tár";s:3:"163";s:4:"tés";s:3:"164";s:3:"van";s:3:"165";s:5:"ásá";s:3:"166";s:4:"ól ";s:3:"167";s:4:" bé";s:3:"168";s:3:" eg";s:3:"169";s:3:" or";s:3:"170";s:4:" pá";s:3:"171";s:4:" pé";s:3:"172";s:3:" ve";s:3:"173";s:3:"ban";s:3:"174";s:3:"eke";s:3:"175";s:4:"ekü";s:3:"176";s:4:"elÅ‘";s:3:"177";s:3:"erv";s:3:"178";s:3:"ete";s:3:"179";s:3:"fog";s:3:"180";s:3:"i a";s:3:"181";s:3:"kis";s:3:"182";s:4:"lád";s:3:"183";s:3:"nte";s:3:"184";s:3:"nye";s:3:"185";s:3:"nyi";s:3:"186";s:3:"ok ";s:3:"187";s:4:"omá";s:3:"188";s:3:"os ";s:3:"189";s:4:"rán";s:3:"190";s:4:"rás";s:3:"191";s:3:"sal";s:3:"192";s:3:"t e";s:3:"193";s:4:"vál";s:3:"194";s:3:"yar";s:3:"195";s:4:"ágo";s:3:"196";s:4:"ála";s:3:"197";s:4:"ége";s:3:"198";s:4:"ény";s:3:"199";s:4:"ött";s:3:"200";s:4:" tá";s:3:"201";s:4:"adó";s:3:"202";s:3:"elh";s:3:"203";s:3:"fej";s:3:"204";s:3:"het";s:3:"205";s:3:"hoz";s:3:"206";s:3:"ill";s:3:"207";s:4:"jár";s:3:"208";s:4:"kés";s:3:"209";s:3:"llo";s:3:"210";s:3:"mi ";s:3:"211";s:3:"ny ";s:3:"212";s:3:"ont";s:3:"213";s:3:"ren";s:3:"214";s:3:"res";s:3:"215";s:3:"rin";s:3:"216";s:3:"s a";s:3:"217";s:3:"s e";s:3:"218";s:3:"ssz";s:3:"219";s:3:"zt ";s:3:"220";s:3:" ez";s:3:"221";s:3:" ka";s:3:"222";s:3:" ke";s:3:"223";s:3:" ko";s:3:"224";s:3:" re";s:3:"225";s:3:"a h";s:3:"226";s:3:"a n";s:3:"227";s:3:"den";s:3:"228";s:4:"dó ";s:3:"229";s:3:"efo";s:3:"230";s:3:"gad";s:3:"231";s:3:"gat";s:3:"232";s:3:"gye";s:3:"233";s:3:"hel";s:3:"234";s:3:"k e";s:3:"235";s:3:"ket";s:3:"236";s:3:"les";s:3:"237";s:4:"mán";s:3:"238";s:3:"nde";s:3:"239";s:3:"nis";s:3:"240";s:3:"ozz";s:3:"241";s:3:"t b";s:3:"242";s:3:"t i";s:3:"243";s:4:"t é";s:3:"244";s:3:"tat";s:3:"245";s:3:"tos";s:3:"246";s:3:"val";s:3:"247";s:3:"z o";s:3:"248";s:3:"zak";s:3:"249";s:4:"ád ";s:3:"250";s:4:"ály";s:3:"251";s:4:"ára";s:3:"252";s:4:"ési";s:3:"253";s:4:"ész";s:3:"254";s:3:" ak";s:3:"255";s:3:" am";s:3:"256";s:3:" es";s:3:"257";s:4:" há";s:3:"258";s:3:" ny";s:3:"259";s:4:" tö";s:3:"260";s:3:"aka";s:3:"261";s:3:"art";s:3:"262";s:4:"ató";s:3:"263";s:3:"azt";s:3:"264";s:3:"bbe";s:3:"265";s:3:"ber";s:3:"266";s:4:"ció";s:3:"267";s:3:"cso";s:3:"268";s:3:"em ";s:3:"269";s:3:"eti";s:3:"270";s:4:"eté";s:3:"271";s:3:"gal";s:3:"272";s:3:"i t";s:3:"273";s:3:"ini";s:3:"274";s:3:"ist";s:3:"275";s:3:"ja ";s:3:"276";s:3:"ker";s:3:"277";s:3:"ki ";s:3:"278";s:3:"kor";s:3:"279";s:3:"koz";s:3:"280";s:4:"l é";s:3:"281";s:4:"ljá";s:3:"282";s:3:"lye";s:3:"283";s:3:"n v";s:3:"284";s:3:"ni ";s:3:"285";s:4:"pál";s:3:"286";s:3:"ror";s:3:"287";s:4:"ról";s:3:"288";s:4:"rül";s:3:"289";s:3:"s c";s:3:"290";s:3:"s p";s:3:"291";s:3:"s s";s:3:"292";s:3:"s v";s:3:"293";s:3:"sok";s:3:"294";s:3:"t j";s:3:"295";s:3:"t t";s:3:"296";s:3:"tar";s:3:"297";s:3:"tel";s:3:"298";s:3:"vat";s:3:"299";}s:9:"icelandic";a:300:{s:4:"að ";s:1:"0";s:3:"um ";s:1:"1";s:4:" að";s:1:"2";s:3:"ir ";s:1:"3";s:4:"ið ";s:1:"4";s:3:"ur ";s:1:"5";s:3:" ve";s:1:"6";s:4:" í ";s:1:"7";s:3:"na ";s:1:"8";s:4:" á ";s:1:"9";s:3:" se";s:2:"10";s:3:" er";s:2:"11";s:3:" og";s:2:"12";s:3:"ar ";s:2:"13";s:3:"og ";s:2:"14";s:3:"ver";s:2:"15";s:3:" mi";s:2:"16";s:3:"inn";s:2:"17";s:3:"nn ";s:2:"18";s:3:" fy";s:2:"19";s:3:"er ";s:2:"20";s:3:"fyr";s:2:"21";s:3:" ek";s:2:"22";s:3:" en";s:2:"23";s:3:" ha";s:2:"24";s:3:" he";s:2:"25";s:3:"ekk";s:2:"26";s:3:" st";s:2:"27";s:3:"ki ";s:2:"28";s:3:"st ";s:2:"29";s:4:"ði ";s:2:"30";s:3:" ba";s:2:"31";s:3:" me";s:2:"32";s:3:" vi";s:2:"33";s:3:"ig ";s:2:"34";s:3:"rir";s:2:"35";s:3:"yri";s:2:"36";s:3:" um";s:2:"37";s:3:"g f";s:2:"38";s:3:"leg";s:2:"39";s:3:"lei";s:2:"40";s:3:"ns ";s:2:"41";s:4:"ð s";s:2:"42";s:3:" ei";s:2:"43";s:4:" þa";s:2:"44";s:3:"in ";s:2:"45";s:3:"kki";s:2:"46";s:3:"r h";s:2:"47";s:3:"r s";s:2:"48";s:3:"egi";s:2:"49";s:3:"ein";s:2:"50";s:3:"ga ";s:2:"51";s:3:"ing";s:2:"52";s:3:"ra ";s:2:"53";s:3:"sta";s:2:"54";s:3:" va";s:2:"55";s:4:" þe";s:2:"56";s:3:"ann";s:2:"57";s:3:"en ";s:2:"58";s:3:"mil";s:2:"59";s:3:"sem";s:2:"60";s:4:"tjó";s:2:"61";s:4:"arð";s:2:"62";s:3:"di ";s:2:"63";s:3:"eit";s:2:"64";s:3:"haf";s:2:"65";s:3:"ill";s:2:"66";s:3:"ins";s:2:"67";s:3:"ist";s:2:"68";s:3:"llj";s:2:"69";s:3:"ndi";s:2:"70";s:3:"r a";s:2:"71";s:3:"r e";s:2:"72";s:3:"seg";s:2:"73";s:3:"un ";s:2:"74";s:3:"var";s:2:"75";s:3:" bi";s:2:"76";s:3:" el";s:2:"77";s:3:" fo";s:2:"78";s:3:" ge";s:2:"79";s:3:" yf";s:2:"80";s:3:"and";s:2:"81";s:3:"aug";s:2:"82";s:3:"bau";s:2:"83";s:3:"big";s:2:"84";s:3:"ega";s:2:"85";s:3:"eld";s:2:"86";s:4:"erð";s:2:"87";s:3:"fir";s:2:"88";s:3:"foo";s:2:"89";s:3:"gin";s:2:"90";s:3:"itt";s:2:"91";s:3:"n s";s:2:"92";s:3:"ngi";s:2:"93";s:3:"num";s:2:"94";s:3:"od ";s:2:"95";s:3:"ood";s:2:"96";s:3:"sin";s:2:"97";s:3:"ta ";s:2:"98";s:3:"tt ";s:2:"99";s:4:"við";s:3:"100";s:3:"yfi";s:3:"101";s:4:"ð e";s:3:"102";s:4:"ð f";s:3:"103";s:3:" hr";s:3:"104";s:4:" sé";s:3:"105";s:4:" þv";s:3:"106";s:3:"a e";s:3:"107";s:4:"a á";s:3:"108";s:3:"em ";s:3:"109";s:3:"gi ";s:3:"110";s:3:"i f";s:3:"111";s:3:"jar";s:3:"112";s:4:"jór";s:3:"113";s:3:"lja";s:3:"114";s:3:"m e";s:3:"115";s:4:"r á";s:3:"116";s:3:"rei";s:3:"117";s:3:"rst";s:3:"118";s:4:"rða";s:3:"119";s:4:"rði";s:3:"120";s:4:"rðu";s:3:"121";s:3:"stj";s:3:"122";s:3:"und";s:3:"123";s:3:"veg";s:3:"124";s:4:"ví ";s:3:"125";s:4:"ð v";s:3:"126";s:5:"það";s:3:"127";s:5:"því";s:3:"128";s:3:" fj";s:3:"129";s:3:" ko";s:3:"130";s:3:" sl";s:3:"131";s:3:"eik";s:3:"132";s:3:"end";s:3:"133";s:3:"ert";s:3:"134";s:3:"ess";s:3:"135";s:4:"fjá";s:3:"136";s:3:"fur";s:3:"137";s:3:"gir";s:3:"138";s:4:"hús";s:3:"139";s:4:"jár";s:3:"140";s:3:"n e";s:3:"141";s:3:"ri ";s:3:"142";s:3:"tar";s:3:"143";s:5:"ð þ";s:3:"144";s:4:"ðar";s:3:"145";s:4:"ður";s:3:"146";s:4:"þes";s:3:"147";s:3:" br";s:3:"148";s:4:" hú";s:3:"149";s:3:" kr";s:3:"150";s:3:" le";s:3:"151";s:3:" up";s:3:"152";s:3:"a s";s:3:"153";s:3:"egg";s:3:"154";s:3:"i s";s:3:"155";s:3:"irt";s:3:"156";s:3:"ja ";s:3:"157";s:4:"kið";s:3:"158";s:3:"len";s:3:"159";s:4:"með";s:3:"160";s:3:"mik";s:3:"161";s:3:"n b";s:3:"162";s:3:"nar";s:3:"163";s:3:"nir";s:3:"164";s:3:"nun";s:3:"165";s:3:"r f";s:3:"166";s:3:"r v";s:3:"167";s:4:"rið";s:3:"168";s:3:"rt ";s:3:"169";s:3:"sti";s:3:"170";s:3:"t v";s:3:"171";s:3:"ti ";s:3:"172";s:3:"una";s:3:"173";s:3:"upp";s:3:"174";s:4:"ða ";s:3:"175";s:4:"óna";s:3:"176";s:3:" al";s:3:"177";s:3:" fr";s:3:"178";s:3:" gr";s:3:"179";s:3:"a v";s:3:"180";s:3:"all";s:3:"181";s:3:"an ";s:3:"182";s:3:"da ";s:3:"183";s:4:"eið";s:3:"184";s:4:"eð ";s:3:"185";s:3:"fa ";s:3:"186";s:3:"fra";s:3:"187";s:3:"g e";s:3:"188";s:3:"ger";s:3:"189";s:4:"gið";s:3:"190";s:3:"gt ";s:3:"191";s:3:"han";s:3:"192";s:3:"hef";s:3:"193";s:3:"hel";s:3:"194";s:3:"her";s:3:"195";s:3:"hra";s:3:"196";s:3:"i a";s:3:"197";s:3:"i e";s:3:"198";s:3:"i v";s:3:"199";s:4:"i þ";s:3:"200";s:3:"iki";s:3:"201";s:4:"jón";s:3:"202";s:4:"jör";s:3:"203";s:3:"ka ";s:3:"204";s:4:"kró";s:3:"205";s:4:"lík";s:3:"206";s:3:"m h";s:3:"207";s:3:"n a";s:3:"208";s:3:"nga";s:3:"209";s:3:"r l";s:3:"210";s:3:"ram";s:3:"211";s:3:"ru ";s:3:"212";s:5:"ráð";s:3:"213";s:4:"rón";s:3:"214";s:3:"svo";s:3:"215";s:3:"vin";s:3:"216";s:4:"í b";s:3:"217";s:4:"í h";s:3:"218";s:4:"ð h";s:3:"219";s:4:"ð k";s:3:"220";s:4:"ð m";s:3:"221";s:5:"örð";s:3:"222";s:3:" af";s:3:"223";s:3:" fa";s:3:"224";s:4:" lí";s:3:"225";s:4:" rá";s:3:"226";s:3:" sk";s:3:"227";s:3:" sv";s:3:"228";s:3:" te";s:3:"229";s:3:"a b";s:3:"230";s:3:"a f";s:3:"231";s:3:"a h";s:3:"232";s:3:"a k";s:3:"233";s:3:"a u";s:3:"234";s:3:"afi";s:3:"235";s:3:"agn";s:3:"236";s:3:"arn";s:3:"237";s:3:"ast";s:3:"238";s:3:"ber";s:3:"239";s:3:"efu";s:3:"240";s:3:"enn";s:3:"241";s:3:"erb";s:3:"242";s:3:"erg";s:3:"243";s:3:"fi ";s:3:"244";s:3:"g a";s:3:"245";s:3:"gar";s:3:"246";s:4:"iðs";s:3:"247";s:3:"ker";s:3:"248";s:3:"kke";s:3:"249";s:3:"lan";s:3:"250";s:4:"ljó";s:3:"251";s:3:"llt";s:3:"252";s:3:"ma ";s:3:"253";s:4:"mið";s:3:"254";s:3:"n v";s:3:"255";s:4:"n í";s:3:"256";s:3:"nan";s:3:"257";s:3:"nda";s:3:"258";s:3:"ndu";s:3:"259";s:4:"nið";s:3:"260";s:3:"nna";s:3:"261";s:3:"nnu";s:3:"262";s:3:"nu ";s:3:"263";s:3:"r o";s:3:"264";s:3:"rbe";s:3:"265";s:3:"rgi";s:3:"266";s:4:"slö";s:3:"267";s:4:"sé ";s:3:"268";s:3:"t a";s:3:"269";s:3:"t h";s:3:"270";s:3:"til";s:3:"271";s:3:"tin";s:3:"272";s:3:"ugu";s:3:"273";s:3:"vil";s:3:"274";s:3:"ygg";s:3:"275";s:4:"á s";s:3:"276";s:4:"ð a";s:3:"277";s:4:"ð b";s:3:"278";s:4:"órn";s:3:"279";s:4:"ögn";s:3:"280";s:4:"öku";s:3:"281";s:3:" at";s:3:"282";s:3:" fi";s:3:"283";s:4:" fé";s:3:"284";s:3:" ka";s:3:"285";s:3:" ma";s:3:"286";s:3:" no";s:3:"287";s:3:" sa";s:3:"288";s:3:" si";s:3:"289";s:3:" ti";s:3:"290";s:4:" ák";s:3:"291";s:3:"a m";s:3:"292";s:3:"a t";s:3:"293";s:4:"a í";s:3:"294";s:4:"a þ";s:3:"295";s:3:"afa";s:3:"296";s:3:"afs";s:3:"297";s:3:"ald";s:3:"298";s:3:"arf";s:3:"299";}s:10:"indonesian";a:300:{s:3:"an ";s:1:"0";s:3:" me";s:1:"1";s:3:"kan";s:1:"2";s:3:"ang";s:1:"3";s:3:"ng ";s:1:"4";s:3:" pe";s:1:"5";s:3:"men";s:1:"6";s:3:" di";s:1:"7";s:3:" ke";s:1:"8";s:3:" da";s:1:"9";s:3:" se";s:2:"10";s:3:"eng";s:2:"11";s:3:" be";s:2:"12";s:3:"nga";s:2:"13";s:3:"nya";s:2:"14";s:3:" te";s:2:"15";s:3:"ah ";s:2:"16";s:3:"ber";s:2:"17";s:3:"aka";s:2:"18";s:3:" ya";s:2:"19";s:3:"dan";s:2:"20";s:3:"di ";s:2:"21";s:3:"yan";s:2:"22";s:3:"n p";s:2:"23";s:3:"per";s:2:"24";s:3:"a m";s:2:"25";s:3:"ita";s:2:"26";s:3:" pa";s:2:"27";s:3:"da ";s:2:"28";s:3:"ata";s:2:"29";s:3:"ada";s:2:"30";s:3:"ya ";s:2:"31";s:3:"ta ";s:2:"32";s:3:" in";s:2:"33";s:3:"ala";s:2:"34";s:3:"eri";s:2:"35";s:3:"ia ";s:2:"36";s:3:"a d";s:2:"37";s:3:"n k";s:2:"38";s:3:"am ";s:2:"39";s:3:"ga ";s:2:"40";s:3:"at ";s:2:"41";s:3:"era";s:2:"42";s:3:"n d";s:2:"43";s:3:"ter";s:2:"44";s:3:" ka";s:2:"45";s:3:"a p";s:2:"46";s:3:"ari";s:2:"47";s:3:"emb";s:2:"48";s:3:"n m";s:2:"49";s:3:"ri ";s:2:"50";s:3:" ba";s:2:"51";s:3:"aan";s:2:"52";s:3:"ak ";s:2:"53";s:3:"ra ";s:2:"54";s:3:" it";s:2:"55";s:3:"ara";s:2:"56";s:3:"ela";s:2:"57";s:3:"ni ";s:2:"58";s:3:"ali";s:2:"59";s:3:"ran";s:2:"60";s:3:"ar ";s:2:"61";s:3:"eru";s:2:"62";s:3:"lah";s:2:"63";s:3:"a b";s:2:"64";s:3:"asi";s:2:"65";s:3:"awa";s:2:"66";s:3:"eba";s:2:"67";s:3:"gan";s:2:"68";s:3:"n b";s:2:"69";s:3:" ha";s:2:"70";s:3:"ini";s:2:"71";s:3:"mer";s:2:"72";s:3:" la";s:2:"73";s:3:" mi";s:2:"74";s:3:"and";s:2:"75";s:3:"ena";s:2:"76";s:3:"wan";s:2:"77";s:3:" sa";s:2:"78";s:3:"aha";s:2:"79";s:3:"lam";s:2:"80";s:3:"n i";s:2:"81";s:3:"nda";s:2:"82";s:3:" wa";s:2:"83";s:3:"a i";s:2:"84";s:3:"dua";s:2:"85";s:3:"g m";s:2:"86";s:3:"mi ";s:2:"87";s:3:"n a";s:2:"88";s:3:"rus";s:2:"89";s:3:"tel";s:2:"90";s:3:"yak";s:2:"91";s:3:" an";s:2:"92";s:3:"dal";s:2:"93";s:3:"h d";s:2:"94";s:3:"i s";s:2:"95";s:3:"ing";s:2:"96";s:3:"min";s:2:"97";s:3:"ngg";s:2:"98";s:3:"tak";s:2:"99";s:3:"ami";s:3:"100";s:3:"beb";s:3:"101";s:3:"den";s:3:"102";s:3:"gat";s:3:"103";s:3:"ian";s:3:"104";s:3:"ih ";s:3:"105";s:3:"pad";s:3:"106";s:3:"rga";s:3:"107";s:3:"san";s:3:"108";s:3:"ua ";s:3:"109";s:3:" de";s:3:"110";s:3:"a t";s:3:"111";s:3:"arg";s:3:"112";s:3:"dar";s:3:"113";s:3:"elu";s:3:"114";s:3:"har";s:3:"115";s:3:"i k";s:3:"116";s:3:"i m";s:3:"117";s:3:"i p";s:3:"118";s:3:"ika";s:3:"119";s:3:"in ";s:3:"120";s:3:"iny";s:3:"121";s:3:"itu";s:3:"122";s:3:"mba";s:3:"123";s:3:"n t";s:3:"124";s:3:"ntu";s:3:"125";s:3:"pan";s:3:"126";s:3:"pen";s:3:"127";s:3:"sah";s:3:"128";s:3:"tan";s:3:"129";s:3:"tu ";s:3:"130";s:3:"a k";s:3:"131";s:3:"ban";s:3:"132";s:3:"edu";s:3:"133";s:3:"eka";s:3:"134";s:3:"g d";s:3:"135";s:3:"ka ";s:3:"136";s:3:"ker";s:3:"137";s:3:"nde";s:3:"138";s:3:"nta";s:3:"139";s:3:"ora";s:3:"140";s:3:"usa";s:3:"141";s:3:" du";s:3:"142";s:3:" ma";s:3:"143";s:3:"a s";s:3:"144";s:3:"ai ";s:3:"145";s:3:"ant";s:3:"146";s:3:"bas";s:3:"147";s:3:"end";s:3:"148";s:3:"i d";s:3:"149";s:3:"ira";s:3:"150";s:3:"kam";s:3:"151";s:3:"lan";s:3:"152";s:3:"n s";s:3:"153";s:3:"uli";s:3:"154";s:3:"al ";s:3:"155";s:3:"apa";s:3:"156";s:3:"ere";s:3:"157";s:3:"ert";s:3:"158";s:3:"lia";s:3:"159";s:3:"mem";s:3:"160";s:3:"rka";s:3:"161";s:3:"si ";s:3:"162";s:3:"tal";s:3:"163";s:3:"ung";s:3:"164";s:3:" ak";s:3:"165";s:3:"a a";s:3:"166";s:3:"a w";s:3:"167";s:3:"ani";s:3:"168";s:3:"ask";s:3:"169";s:3:"ent";s:3:"170";s:3:"gar";s:3:"171";s:3:"haa";s:3:"172";s:3:"i i";s:3:"173";s:3:"isa";s:3:"174";s:3:"ked";s:3:"175";s:3:"mbe";s:3:"176";s:3:"ska";s:3:"177";s:3:"tor";s:3:"178";s:3:"uan";s:3:"179";s:3:"uk ";s:3:"180";s:3:"uka";s:3:"181";s:3:" ad";s:3:"182";s:3:" to";s:3:"183";s:3:"asa";s:3:"184";s:3:"aya";s:3:"185";s:3:"bag";s:3:"186";s:3:"dia";s:3:"187";s:3:"dun";s:3:"188";s:3:"erj";s:3:"189";s:3:"mas";s:3:"190";s:3:"na ";s:3:"191";s:3:"rek";s:3:"192";s:3:"rit";s:3:"193";s:3:"sih";s:3:"194";s:3:"us ";s:3:"195";s:3:" bi";s:3:"196";s:3:"a h";s:3:"197";s:3:"ama";s:3:"198";s:3:"dib";s:3:"199";s:3:"ers";s:3:"200";s:3:"g s";s:3:"201";s:3:"han";s:3:"202";s:3:"ik ";s:3:"203";s:3:"kem";s:3:"204";s:3:"ma ";s:3:"205";s:3:"n l";s:3:"206";s:3:"nit";s:3:"207";s:3:"r b";s:3:"208";s:3:"rja";s:3:"209";s:3:"sa ";s:3:"210";s:3:" ju";s:3:"211";s:3:" or";s:3:"212";s:3:" si";s:3:"213";s:3:" ti";s:3:"214";s:3:"a y";s:3:"215";s:3:"aga";s:3:"216";s:3:"any";s:3:"217";s:3:"as ";s:3:"218";s:3:"cul";s:3:"219";s:3:"eme";s:3:"220";s:3:"emu";s:3:"221";s:3:"eny";s:3:"222";s:3:"epa";s:3:"223";s:3:"erb";s:3:"224";s:3:"erl";s:3:"225";s:3:"gi ";s:3:"226";s:3:"h m";s:3:"227";s:3:"i a";s:3:"228";s:3:"kel";s:3:"229";s:3:"li ";s:3:"230";s:3:"mel";s:3:"231";s:3:"nia";s:3:"232";s:3:"opa";s:3:"233";s:3:"rta";s:3:"234";s:3:"sia";s:3:"235";s:3:"tah";s:3:"236";s:3:"ula";s:3:"237";s:3:"un ";s:3:"238";s:3:"unt";s:3:"239";s:3:" at";s:3:"240";s:3:" bu";s:3:"241";s:3:" pu";s:3:"242";s:3:" ta";s:3:"243";s:3:"agi";s:3:"244";s:3:"alu";s:3:"245";s:3:"amb";s:3:"246";s:3:"bah";s:3:"247";s:3:"bis";s:3:"248";s:3:"er ";s:3:"249";s:3:"i t";s:3:"250";s:3:"ibe";s:3:"251";s:3:"ir ";s:3:"252";s:3:"ja ";s:3:"253";s:3:"k m";s:3:"254";s:3:"kar";s:3:"255";s:3:"lai";s:3:"256";s:3:"lal";s:3:"257";s:3:"lu ";s:3:"258";s:3:"mpa";s:3:"259";s:3:"ngk";s:3:"260";s:3:"nja";s:3:"261";s:3:"or ";s:3:"262";s:3:"pa ";s:3:"263";s:3:"pas";s:3:"264";s:3:"pem";s:3:"265";s:3:"rak";s:3:"266";s:3:"rik";s:3:"267";s:3:"seb";s:3:"268";s:3:"tam";s:3:"269";s:3:"tem";s:3:"270";s:3:"top";s:3:"271";s:3:"tuk";s:3:"272";s:3:"uni";s:3:"273";s:3:"war";s:3:"274";s:3:" al";s:3:"275";s:3:" ga";s:3:"276";s:3:" ge";s:3:"277";s:3:" ir";s:3:"278";s:3:" ja";s:3:"279";s:3:" mu";s:3:"280";s:3:" na";s:3:"281";s:3:" pr";s:3:"282";s:3:" su";s:3:"283";s:3:" un";s:3:"284";s:3:"ad ";s:3:"285";s:3:"adi";s:3:"286";s:3:"akt";s:3:"287";s:3:"ann";s:3:"288";s:3:"apo";s:3:"289";s:3:"bel";s:3:"290";s:3:"bul";s:3:"291";s:3:"der";s:3:"292";s:3:"ega";s:3:"293";s:3:"eke";s:3:"294";s:3:"ema";s:3:"295";s:3:"emp";s:3:"296";s:3:"ene";s:3:"297";s:3:"enj";s:3:"298";s:3:"esa";s:3:"299";}s:7:"italian";a:300:{s:3:" di";s:1:"0";s:3:"to ";s:1:"1";s:3:"la ";s:1:"2";s:3:" de";s:1:"3";s:3:"di ";s:1:"4";s:3:"no ";s:1:"5";s:3:" co";s:1:"6";s:3:"re ";s:1:"7";s:3:"ion";s:1:"8";s:3:"e d";s:1:"9";s:3:" e ";s:2:"10";s:3:"le ";s:2:"11";s:3:"del";s:2:"12";s:3:"ne ";s:2:"13";s:3:"ti ";s:2:"14";s:3:"ell";s:2:"15";s:3:" la";s:2:"16";s:3:" un";s:2:"17";s:3:"ni ";s:2:"18";s:3:"i d";s:2:"19";s:3:"per";s:2:"20";s:3:" pe";s:2:"21";s:3:"ent";s:2:"22";s:3:" in";s:2:"23";s:3:"one";s:2:"24";s:3:"he ";s:2:"25";s:3:"ta ";s:2:"26";s:3:"zio";s:2:"27";s:3:"che";s:2:"28";s:3:"o d";s:2:"29";s:3:"a d";s:2:"30";s:3:"na ";s:2:"31";s:3:"ato";s:2:"32";s:3:"e s";s:2:"33";s:3:" so";s:2:"34";s:3:"i s";s:2:"35";s:3:"lla";s:2:"36";s:3:"a p";s:2:"37";s:3:"li ";s:2:"38";s:3:"te ";s:2:"39";s:3:" al";s:2:"40";s:3:" ch";s:2:"41";s:3:"er ";s:2:"42";s:3:" pa";s:2:"43";s:3:" si";s:2:"44";s:3:"con";s:2:"45";s:3:"sta";s:2:"46";s:3:" pr";s:2:"47";s:3:"a c";s:2:"48";s:3:" se";s:2:"49";s:3:"el ";s:2:"50";s:3:"ia ";s:2:"51";s:3:"si ";s:2:"52";s:3:"e p";s:2:"53";s:3:" da";s:2:"54";s:3:"e i";s:2:"55";s:3:"i p";s:2:"56";s:3:"ont";s:2:"57";s:3:"ano";s:2:"58";s:3:"i c";s:2:"59";s:3:"all";s:2:"60";s:3:"azi";s:2:"61";s:3:"nte";s:2:"62";s:3:"on ";s:2:"63";s:3:"nti";s:2:"64";s:3:"o s";s:2:"65";s:3:" ri";s:2:"66";s:3:"i a";s:2:"67";s:3:"o a";s:2:"68";s:3:"un ";s:2:"69";s:3:" an";s:2:"70";s:3:"are";s:2:"71";s:3:"ari";s:2:"72";s:3:"e a";s:2:"73";s:3:"i e";s:2:"74";s:3:"ita";s:2:"75";s:3:"men";s:2:"76";s:3:"ri ";s:2:"77";s:3:" ca";s:2:"78";s:3:" il";s:2:"79";s:3:" no";s:2:"80";s:3:" po";s:2:"81";s:3:"a s";s:2:"82";s:3:"ant";s:2:"83";s:3:"il ";s:2:"84";s:3:"in ";s:2:"85";s:3:"a l";s:2:"86";s:3:"ati";s:2:"87";s:3:"cia";s:2:"88";s:3:"e c";s:2:"89";s:3:"ro ";s:2:"90";s:3:"ann";s:2:"91";s:3:"est";s:2:"92";s:3:"gli";s:2:"93";s:4:"tà ";s:2:"94";s:3:" qu";s:2:"95";s:3:"e l";s:2:"96";s:3:"nta";s:2:"97";s:3:" a ";s:2:"98";s:3:"com";s:2:"99";s:3:"o c";s:3:"100";s:3:"ra ";s:3:"101";s:3:" le";s:3:"102";s:3:" ne";s:3:"103";s:3:"ali";s:3:"104";s:3:"ere";s:3:"105";s:3:"ist";s:3:"106";s:3:" ma";s:3:"107";s:4:" è ";s:3:"108";s:3:"io ";s:3:"109";s:3:"lle";s:3:"110";s:3:"me ";s:3:"111";s:3:"era";s:3:"112";s:3:"ica";s:3:"113";s:3:"ost";s:3:"114";s:3:"pro";s:3:"115";s:3:"tar";s:3:"116";s:3:"una";s:3:"117";s:3:" pi";s:3:"118";s:3:"da ";s:3:"119";s:3:"tat";s:3:"120";s:3:" mi";s:3:"121";s:3:"att";s:3:"122";s:3:"ca ";s:3:"123";s:3:"mo ";s:3:"124";s:3:"non";s:3:"125";s:3:"par";s:3:"126";s:3:"sti";s:3:"127";s:3:" fa";s:3:"128";s:3:" i ";s:3:"129";s:3:" re";s:3:"130";s:3:" su";s:3:"131";s:3:"ess";s:3:"132";s:3:"ini";s:3:"133";s:3:"nto";s:3:"134";s:3:"o l";s:3:"135";s:3:"ssi";s:3:"136";s:3:"tto";s:3:"137";s:3:"a e";s:3:"138";s:3:"ame";s:3:"139";s:3:"col";s:3:"140";s:3:"ei ";s:3:"141";s:3:"ma ";s:3:"142";s:3:"o i";s:3:"143";s:3:"za ";s:3:"144";s:3:" st";s:3:"145";s:3:"a a";s:3:"146";s:3:"ale";s:3:"147";s:3:"anc";s:3:"148";s:3:"ani";s:3:"149";s:3:"i m";s:3:"150";s:3:"ian";s:3:"151";s:3:"o p";s:3:"152";s:3:"oni";s:3:"153";s:3:"sio";s:3:"154";s:3:"tan";s:3:"155";s:3:"tti";s:3:"156";s:3:" lo";s:3:"157";s:3:"i r";s:3:"158";s:3:"oci";s:3:"159";s:3:"oli";s:3:"160";s:3:"ona";s:3:"161";s:3:"ono";s:3:"162";s:3:"tra";s:3:"163";s:3:" l ";s:3:"164";s:3:"a r";s:3:"165";s:3:"eri";s:3:"166";s:3:"ett";s:3:"167";s:3:"lo ";s:3:"168";s:3:"nza";s:3:"169";s:3:"que";s:3:"170";s:3:"str";s:3:"171";s:3:"ter";s:3:"172";s:3:"tta";s:3:"173";s:3:" ba";s:3:"174";s:3:" li";s:3:"175";s:3:" te";s:3:"176";s:3:"ass";s:3:"177";s:3:"e f";s:3:"178";s:3:"enz";s:3:"179";s:3:"for";s:3:"180";s:3:"nno";s:3:"181";s:3:"olo";s:3:"182";s:3:"ori";s:3:"183";s:3:"res";s:3:"184";s:3:"tor";s:3:"185";s:3:" ci";s:3:"186";s:3:" vo";s:3:"187";s:3:"a i";s:3:"188";s:3:"al ";s:3:"189";s:3:"chi";s:3:"190";s:3:"e n";s:3:"191";s:3:"lia";s:3:"192";s:3:"pre";s:3:"193";s:3:"ria";s:3:"194";s:3:"uni";s:3:"195";s:3:"ver";s:3:"196";s:3:" sp";s:3:"197";s:3:"imo";s:3:"198";s:3:"l a";s:3:"199";s:3:"l c";s:3:"200";s:3:"ran";s:3:"201";s:3:"sen";s:3:"202";s:3:"soc";s:3:"203";s:3:"tic";s:3:"204";s:3:" fi";s:3:"205";s:3:" mo";s:3:"206";s:3:"a n";s:3:"207";s:3:"ce ";s:3:"208";s:3:"dei";s:3:"209";s:3:"ggi";s:3:"210";s:3:"gio";s:3:"211";s:3:"iti";s:3:"212";s:3:"l s";s:3:"213";s:3:"lit";s:3:"214";s:3:"ll ";s:3:"215";s:3:"mon";s:3:"216";s:3:"ola";s:3:"217";s:3:"pac";s:3:"218";s:3:"sim";s:3:"219";s:3:"tit";s:3:"220";s:3:"utt";s:3:"221";s:3:"vol";s:3:"222";s:3:" ar";s:3:"223";s:3:" fo";s:3:"224";s:3:" ha";s:3:"225";s:3:" sa";s:3:"226";s:3:"acc";s:3:"227";s:3:"e r";s:3:"228";s:3:"ire";s:3:"229";s:3:"man";s:3:"230";s:3:"ntr";s:3:"231";s:3:"rat";s:3:"232";s:3:"sco";s:3:"233";s:3:"tro";s:3:"234";s:3:"tut";s:3:"235";s:3:"va ";s:3:"236";s:3:" do";s:3:"237";s:3:" gi";s:3:"238";s:3:" me";s:3:"239";s:3:" sc";s:3:"240";s:3:" tu";s:3:"241";s:3:" ve";s:3:"242";s:3:" vi";s:3:"243";s:3:"a m";s:3:"244";s:3:"ber";s:3:"245";s:3:"can";s:3:"246";s:3:"cit";s:3:"247";s:3:"i l";s:3:"248";s:3:"ier";s:3:"249";s:4:"ità";s:3:"250";s:3:"lli";s:3:"251";s:3:"min";s:3:"252";s:3:"n p";s:3:"253";s:3:"nat";s:3:"254";s:3:"nda";s:3:"255";s:3:"o e";s:3:"256";s:3:"o f";s:3:"257";s:3:"o u";s:3:"258";s:3:"ore";s:3:"259";s:3:"oro";s:3:"260";s:3:"ort";s:3:"261";s:3:"sto";s:3:"262";s:3:"ten";s:3:"263";s:3:"tiv";s:3:"264";s:3:"van";s:3:"265";s:3:"art";s:3:"266";s:3:"cco";s:3:"267";s:3:"ci ";s:3:"268";s:3:"cos";s:3:"269";s:3:"dal";s:3:"270";s:3:"e v";s:3:"271";s:3:"i i";s:3:"272";s:3:"ila";s:3:"273";s:3:"ino";s:3:"274";s:3:"l p";s:3:"275";s:3:"n c";s:3:"276";s:3:"nit";s:3:"277";s:3:"ole";s:3:"278";s:3:"ome";s:3:"279";s:3:"po ";s:3:"280";s:3:"rio";s:3:"281";s:3:"sa ";s:3:"282";s:3:" ce";s:3:"283";s:3:" es";s:3:"284";s:3:" tr";s:3:"285";s:3:"a b";s:3:"286";s:3:"and";s:3:"287";s:3:"ata";s:3:"288";s:3:"der";s:3:"289";s:3:"ens";s:3:"290";s:3:"ers";s:3:"291";s:3:"gi ";s:3:"292";s:3:"ial";s:3:"293";s:3:"ina";s:3:"294";s:3:"itt";s:3:"295";s:3:"izi";s:3:"296";s:3:"lan";s:3:"297";s:3:"lor";s:3:"298";s:3:"mil";s:3:"299";}s:6:"kazakh";a:300:{s:5:"ан ";s:1:"0";s:5:"ен ";s:1:"1";s:5:"Ñ‹Ò£ ";s:1:"2";s:5:" қа";s:1:"3";s:5:" ба";s:1:"4";s:5:"ай ";s:1:"5";s:6:"нда";s:1:"6";s:5:"ын ";s:1:"7";s:5:" Ñа";s:1:"8";s:5:" ал";s:1:"9";s:5:"ді ";s:2:"10";s:6:"ары";s:2:"11";s:5:"ды ";s:2:"12";s:5:"ып ";s:2:"13";s:5:" мұ";s:2:"14";s:5:" бі";s:2:"15";s:6:"аÑÑ‹";s:2:"16";s:5:"да ";s:2:"17";s:6:"най";s:2:"18";s:5:" жа";s:2:"19";s:6:"мұн";s:2:"20";s:6:"Ñта";s:2:"21";s:6:"ған";s:2:"22";s:5:"н б";s:2:"23";s:6:"ұна";s:2:"24";s:5:" бо";s:2:"25";s:6:"ның";s:2:"26";s:5:"ін ";s:2:"27";s:6:"лар";s:2:"28";s:6:"Ñын";s:2:"29";s:5:" де";s:2:"30";s:6:"аға";s:2:"31";s:6:"тан";s:2:"32";s:5:" кө";s:2:"33";s:6:"бір";s:2:"34";s:5:"ер ";s:2:"35";s:6:"мен";s:2:"36";s:6:"аза";s:2:"37";s:6:"ынд";s:2:"38";s:6:"ыны";s:2:"39";s:5:" ме";s:2:"40";s:6:"анд";s:2:"41";s:6:"ері";s:2:"42";s:6:"бол";s:2:"43";s:6:"дың";s:2:"44";s:6:"қаз";s:2:"45";s:6:"аты";s:2:"46";s:5:"ÑÑ‹ ";s:2:"47";s:6:"тын";s:2:"48";s:5:"Ò“Ñ‹ ";s:2:"49";s:5:" ке";s:2:"50";s:5:"ар ";s:2:"51";s:6:"зақ";s:2:"52";s:5:"Ñ‹Ò› ";s:2:"53";s:6:"ала";s:2:"54";s:6:"алы";s:2:"55";s:6:"аны";s:2:"56";s:6:"ара";s:2:"57";s:6:"ағы";s:2:"58";s:6:"ген";s:2:"59";s:6:"тар";s:2:"60";s:6:"тер";s:2:"61";s:6:"Ñ‚Ñ‹Ñ€";s:2:"62";s:6:"айд";s:2:"63";s:6:"ард";s:2:"64";s:5:"де ";s:2:"65";s:5:"ға ";s:2:"66";s:5:" қо";s:2:"67";s:6:"бар";s:2:"68";s:5:"Ñ–Ò£ ";s:2:"69";s:6:"қан";s:2:"70";s:5:" бе";s:2:"71";s:5:" қы";s:2:"72";s:6:"ақÑ";s:2:"73";s:6:"гер";s:2:"74";s:6:"дан";s:2:"75";s:6:"дар";s:2:"76";s:6:"лық";s:2:"77";s:6:"лға";s:2:"78";s:6:"ына";s:2:"79";s:5:"Ñ–Ñ€ ";s:2:"80";s:6:"ірі";s:2:"81";s:6:"ғаÑ";s:2:"82";s:5:" та";s:2:"83";s:5:"а б";s:2:"84";s:5:"гі ";s:2:"85";s:6:"еді";s:2:"86";s:6:"еле";s:2:"87";s:6:"йды";s:2:"88";s:5:"н к";s:2:"89";s:5:"н Ñ‚";s:2:"90";s:6:"ола";s:2:"91";s:6:"рын";s:2:"92";s:5:"іп ";s:2:"93";s:6:"Ò›ÑÑ‚";s:2:"94";s:6:"қта";s:2:"95";s:5:"Ò£ б";s:2:"96";s:5:" ай";s:2:"97";s:5:" ол";s:2:"98";s:5:" Ñо";s:2:"99";s:6:"айт";s:3:"100";s:6:"дағ";s:3:"101";s:6:"иге";s:3:"102";s:6:"лер";s:3:"103";s:6:"лып";s:3:"104";s:5:"н а";s:3:"105";s:5:"ік ";s:3:"106";s:6:"ақт";s:3:"107";s:6:"бағ";s:3:"108";s:6:"кен";s:3:"109";s:5:"н Ò›";s:3:"110";s:5:"ны ";s:3:"111";s:6:"рге";s:3:"112";s:6:"рға";s:3:"113";s:5:"Ñ‹Ñ€ ";s:3:"114";s:5:" ар";s:3:"115";s:6:"алғ";s:3:"116";s:6:"аÑа";s:3:"117";s:6:"баÑ";s:3:"118";s:6:"бер";s:3:"119";s:5:"ге ";s:3:"120";s:6:"еті";s:3:"121";s:5:"на ";s:3:"122";s:6:"нде";s:3:"123";s:5:"не ";s:3:"124";s:6:"ниг";s:3:"125";s:6:"рды";s:3:"126";s:5:"ры ";s:3:"127";s:6:"Ñай";s:3:"128";s:5:" ау";s:3:"129";s:5:" кү";s:3:"130";s:5:" ни";s:3:"131";s:5:" от";s:3:"132";s:5:" өз";s:3:"133";s:6:"ауд";s:3:"134";s:5:"еп ";s:3:"135";s:6:"иÑл";s:3:"136";s:6:"лты";s:3:"137";s:5:"н ж";s:3:"138";s:5:"н о";s:3:"139";s:6:"оÑÑ‹";s:3:"140";s:6:"оты";s:3:"141";s:6:"рып";s:3:"142";s:5:"рі ";s:3:"143";s:6:"тке";s:3:"144";s:5:"Ñ‚Ñ‹ ";s:3:"145";s:5:"Ñ‹ б";s:3:"146";s:5:"Ñ‹ ж";s:3:"147";s:6:"ылы";s:3:"148";s:6:"Ñ‹ÑÑ‹";s:3:"149";s:5:"Ñ– Ñ";s:3:"150";s:6:"қар";s:3:"151";s:5:" бұ";s:3:"152";s:5:" да";s:3:"153";s:5:" же";s:3:"154";s:5:" Ñ‚Ò±";s:3:"155";s:5:" Ò›Ò±";s:3:"156";s:6:"ады";s:3:"157";s:6:"айл";s:3:"158";s:5:"ап ";s:3:"159";s:6:"ата";s:3:"160";s:6:"ені";s:3:"161";s:6:"йла";s:3:"162";s:5:"н м";s:3:"163";s:5:"н Ñ";s:3:"164";s:6:"нды";s:3:"165";s:6:"нді";s:3:"166";s:5:"Ñ€ м";s:3:"167";s:6:"тай";s:3:"168";s:6:"тін";s:3:"169";s:5:"Ñ‹ Ñ‚";s:3:"170";s:5:"Ñ‹Ñ ";s:3:"171";s:6:"інд";s:3:"172";s:5:" би";s:3:"173";s:5:"а ж";s:3:"174";s:6:"ауы";s:3:"175";s:6:"деп";s:3:"176";s:6:"дің";s:3:"177";s:6:"еке";s:3:"178";s:6:"ери";s:3:"179";s:6:"йын";s:3:"180";s:6:"кел";s:3:"181";s:6:"лды";s:3:"182";s:5:"ма ";s:3:"183";s:6:"нан";s:3:"184";s:6:"оны";s:3:"185";s:5:"п ж";s:3:"186";s:5:"п о";s:3:"187";s:5:"Ñ€ б";s:3:"188";s:6:"риÑ";s:3:"189";s:6:"рла";s:3:"190";s:6:"уда";s:3:"191";s:6:"шыл";s:3:"192";s:5:"Ñ‹ а";s:3:"193";s:6:"ықт";s:3:"194";s:5:"Ñ– а";s:3:"195";s:5:"Ñ– б";s:3:"196";s:5:"із ";s:3:"197";s:6:"ілі";s:3:"198";s:5:"Ò£ Ò›";s:3:"199";s:5:" аÑ";s:3:"200";s:5:" ек";s:3:"201";s:5:" жо";s:3:"202";s:5:" мә";s:3:"203";s:5:" оÑ";s:3:"204";s:5:" ре";s:3:"205";s:5:" Ñе";s:3:"206";s:6:"алд";s:3:"207";s:6:"дал";s:3:"208";s:6:"дег";s:3:"209";s:6:"дей";s:3:"210";s:5:"е б";s:3:"211";s:5:"ет ";s:3:"212";s:6:"жаÑ";s:3:"213";s:5:"й б";s:3:"214";s:6:"лау";s:3:"215";s:6:"лда";s:3:"216";s:6:"мет";s:3:"217";s:6:"нын";s:3:"218";s:6:"Ñар";s:3:"219";s:5:"ÑÑ– ";s:3:"220";s:5:"Ñ‚Ñ– ";s:3:"221";s:6:"ыры";s:3:"222";s:6:"ыта";s:3:"223";s:6:"Ñ–ÑÑ–";s:3:"224";s:5:"Ò£ а";s:3:"225";s:6:"өте";s:3:"226";s:5:" ат";s:3:"227";s:5:" ел";s:3:"228";s:5:" жү";s:3:"229";s:5:" ма";s:3:"230";s:5:" то";s:3:"231";s:5:" шы";s:3:"232";s:5:"а а";s:3:"233";s:6:"алт";s:3:"234";s:6:"ама";s:3:"235";s:6:"арл";s:3:"236";s:6:"аÑÑ‚";s:3:"237";s:6:"бұл";s:3:"238";s:6:"дай";s:3:"239";s:6:"дық";s:3:"240";s:5:"ек ";s:3:"241";s:6:"ель";s:3:"242";s:6:"еÑÑ–";s:3:"243";s:6:"зді";s:3:"244";s:6:"көт";s:3:"245";s:6:"лем";s:3:"246";s:5:"ль ";s:3:"247";s:5:"н е";s:3:"248";s:5:"п а";s:3:"249";s:5:"Ñ€ а";s:3:"250";s:6:"реÑ";s:3:"251";s:5:"Ñа ";s:3:"252";s:5:"та ";s:3:"253";s:6:"тте";s:3:"254";s:6:"тұр";s:3:"255";s:5:"шы ";s:3:"256";s:5:"Ñ‹ д";s:3:"257";s:5:"Ñ‹ Ò›";s:3:"258";s:5:"ыз ";s:3:"259";s:6:"қыт";s:3:"260";s:5:" ко";s:3:"261";s:5:" не";s:3:"262";s:5:" ой";s:3:"263";s:5:" ор";s:3:"264";s:5:" ÑÒ±";s:3:"265";s:5:" Ñ‚Ò¯";s:3:"266";s:6:"аль";s:3:"267";s:6:"аре";s:3:"268";s:6:"атт";s:3:"269";s:6:"дір";s:3:"270";s:5:"ев ";s:3:"271";s:6:"егі";s:3:"272";s:6:"еда";s:3:"273";s:6:"екі";s:3:"274";s:6:"елд";s:3:"275";s:6:"ерг";s:3:"276";s:6:"ерд";s:3:"277";s:6:"иÑд";s:3:"278";s:6:"кер";s:3:"279";s:6:"кет";s:3:"280";s:6:"лыÑ";s:3:"281";s:6:"ліÑ";s:3:"282";s:6:"мед";s:3:"283";s:6:"мпи";s:3:"284";s:5:"н д";s:3:"285";s:5:"ні ";s:3:"286";s:6:"нін";s:3:"287";s:5:"п Ñ‚";s:3:"288";s:6:"пек";s:3:"289";s:6:"рел";s:3:"290";s:6:"рта";s:3:"291";s:6:"ріл";s:3:"292";s:6:"рін";s:3:"293";s:6:"Ñен";s:3:"294";s:6:"тал";s:3:"295";s:6:"шіл";s:3:"296";s:5:"Ñ‹ к";s:3:"297";s:5:"Ñ‹ м";s:3:"298";s:6:"Ñ‹ÑÑ‚";s:3:"299";}s:6:"kyrgyz";a:300:{s:5:"ын ";s:1:"0";s:5:"ан ";s:1:"1";s:5:" жа";s:1:"2";s:5:"ен ";s:1:"3";s:5:"да ";s:1:"4";s:5:" та";s:1:"5";s:5:"ар ";s:1:"6";s:5:"ин ";s:1:"7";s:5:" ка";s:1:"8";s:6:"ары";s:1:"9";s:5:" ал";s:2:"10";s:5:" ба";s:2:"11";s:5:" би";s:2:"12";s:6:"лар";s:2:"13";s:5:" бо";s:2:"14";s:5:" кы";s:2:"15";s:6:"ала";s:2:"16";s:5:"н к";s:2:"17";s:5:" Ñа";s:2:"18";s:6:"нда";s:2:"19";s:6:"ган";s:2:"20";s:6:"тар";s:2:"21";s:5:" де";s:2:"22";s:6:"анд";s:2:"23";s:5:"н б";s:2:"24";s:5:" ке";s:2:"25";s:6:"ард";s:2:"26";s:6:"мен";s:2:"27";s:5:"н Ñ‚";s:2:"28";s:6:"ара";s:2:"29";s:6:"нын";s:2:"30";s:5:" да";s:2:"31";s:5:" ме";s:2:"32";s:6:"кыр";s:2:"33";s:5:" че";s:2:"34";s:5:"н а";s:2:"35";s:5:"ры ";s:2:"36";s:5:" ко";s:2:"37";s:6:"ген";s:2:"38";s:6:"дар";s:2:"39";s:6:"кен";s:2:"40";s:6:"кта";s:2:"41";s:5:"уу ";s:2:"42";s:6:"ене";s:2:"43";s:6:"ери";s:2:"44";s:5:" ша";s:2:"45";s:6:"алы";s:2:"46";s:5:"ат ";s:2:"47";s:5:"на ";s:2:"48";s:5:" кө";s:2:"49";s:5:" Ñм";s:2:"50";s:6:"аты";s:2:"51";s:6:"дан";s:2:"52";s:6:"деп";s:2:"53";s:6:"дын";s:2:"54";s:5:"еп ";s:2:"55";s:6:"нен";s:2:"56";s:6:"рын";s:2:"57";s:5:" бе";s:2:"58";s:6:"кан";s:2:"59";s:6:"луу";s:2:"60";s:6:"ргы";s:2:"61";s:6:"тан";s:2:"62";s:6:"шай";s:2:"63";s:6:"ырг";s:2:"64";s:5:"үн ";s:2:"65";s:5:" ар";s:2:"66";s:5:" ма";s:2:"67";s:6:"агы";s:2:"68";s:6:"акт";s:2:"69";s:6:"аны";s:2:"70";s:5:"гы ";s:2:"71";s:6:"гыз";s:2:"72";s:5:"ды ";s:2:"73";s:6:"рда";s:2:"74";s:5:"ай ";s:2:"75";s:6:"бир";s:2:"76";s:6:"бол";s:2:"77";s:5:"ер ";s:2:"78";s:5:"н Ñ";s:2:"79";s:6:"нды";s:2:"80";s:5:"ун ";s:2:"81";s:5:"ча ";s:2:"82";s:6:"ынд";s:2:"83";s:5:"а к";s:2:"84";s:6:"ага";s:2:"85";s:6:"айл";s:2:"86";s:6:"ана";s:2:"87";s:5:"ап ";s:2:"88";s:5:"га ";s:2:"89";s:6:"лге";s:2:"90";s:6:"нча";s:2:"91";s:5:"п к";s:2:"92";s:6:"рды";s:2:"93";s:6:"туу";s:2:"94";s:6:"ыны";s:2:"95";s:5:" ан";s:2:"96";s:5:" өз";s:2:"97";s:6:"ама";s:2:"98";s:6:"ата";s:2:"99";s:6:"дин";s:3:"100";s:5:"йт ";s:3:"101";s:6:"лга";s:3:"102";s:6:"лоо";s:3:"103";s:5:"оо ";s:3:"104";s:5:"ри ";s:3:"105";s:6:"тин";s:3:"106";s:5:"ыз ";s:3:"107";s:5:"ып ";s:3:"108";s:6:"Ó©Ñ€Ò¯";s:3:"109";s:5:" па";s:3:"110";s:5:" Ñк";s:3:"111";s:5:"а б";s:3:"112";s:6:"алг";s:3:"113";s:6:"аÑÑ‹";s:3:"114";s:6:"ашт";s:3:"115";s:6:"биз";s:3:"116";s:6:"кел";s:3:"117";s:6:"кте";s:3:"118";s:6:"тал";s:3:"119";s:5:" не";s:3:"120";s:5:" Ñу";s:3:"121";s:6:"акы";s:3:"122";s:6:"ент";s:3:"123";s:6:"инд";s:3:"124";s:5:"ир ";s:3:"125";s:6:"кал";s:3:"126";s:5:"н д";s:3:"127";s:6:"нде";s:3:"128";s:6:"ого";s:3:"129";s:6:"онд";s:3:"130";s:6:"оюн";s:3:"131";s:5:"Ñ€ б";s:3:"132";s:5:"Ñ€ м";s:3:"133";s:6:"ран";s:3:"134";s:6:"Ñал";s:3:"135";s:6:"Ñта";s:3:"136";s:5:"ÑÑ‹ ";s:3:"137";s:6:"ура";s:3:"138";s:6:"ыгы";s:3:"139";s:5:" аш";s:3:"140";s:5:" ми";s:3:"141";s:5:" ÑÑ‹";s:3:"142";s:5:" ту";s:3:"143";s:5:"ал ";s:3:"144";s:6:"арт";s:3:"145";s:6:"бор";s:3:"146";s:6:"елг";s:3:"147";s:6:"ени";s:3:"148";s:5:"ет ";s:3:"149";s:6:"жат";s:3:"150";s:6:"йло";s:3:"151";s:6:"кар";s:3:"152";s:5:"н м";s:3:"153";s:6:"огу";s:3:"154";s:5:"п а";s:3:"155";s:5:"п ж";s:3:"156";s:5:"Ñ€ Ñ";s:3:"157";s:6:"Ñын";s:3:"158";s:5:"ык ";s:3:"159";s:6:"юнч";s:3:"160";s:5:" бу";s:3:"161";s:5:" ур";s:3:"162";s:5:"а а";s:3:"163";s:5:"ак ";s:3:"164";s:6:"алд";s:3:"165";s:6:"алу";s:3:"166";s:6:"бар";s:3:"167";s:6:"бер";s:3:"168";s:6:"бою";s:3:"169";s:5:"ге ";s:3:"170";s:6:"дон";s:3:"171";s:6:"еги";s:3:"172";s:6:"ект";s:3:"173";s:6:"ефт";s:3:"174";s:5:"из ";s:3:"175";s:6:"кат";s:3:"176";s:6:"лды";s:3:"177";s:5:"н ч";s:3:"178";s:5:"н Ñ";s:3:"179";s:5:"н Ó©";s:3:"180";s:6:"ндо";s:3:"181";s:6:"неф";s:3:"182";s:5:"он ";s:3:"183";s:6:"Ñат";s:3:"184";s:6:"тор";s:3:"185";s:5:"Ñ‚Ñ‹ ";s:3:"186";s:6:"уда";s:3:"187";s:5:"ул ";s:3:"188";s:6:"ула";s:3:"189";s:6:"ууд";s:3:"190";s:5:"Ñ‹ б";s:3:"191";s:5:"Ñ‹ ж";s:3:"192";s:5:"Ñ‹ к";s:3:"193";s:5:"ыл ";s:3:"194";s:6:"ына";s:3:"195";s:6:"Ñке";s:3:"196";s:6:"ÑÑÑ‹";s:3:"197";s:5:" ат";s:3:"198";s:5:" до";s:3:"199";s:5:" жы";s:3:"200";s:5:" Ñо";s:3:"201";s:5:" чы";s:3:"202";s:6:"ааÑ";s:3:"203";s:6:"айт";s:3:"204";s:6:"аÑÑ‚";s:3:"205";s:6:"баа";s:3:"206";s:6:"баш";s:3:"207";s:6:"гар";s:3:"208";s:6:"гын";s:3:"209";s:5:"дө ";s:3:"210";s:5:"е б";s:3:"211";s:5:"ек ";s:3:"212";s:6:"жыл";s:3:"213";s:5:"и б";s:3:"214";s:5:"ик ";s:3:"215";s:6:"иÑÑ";s:3:"216";s:6:"кыз";s:3:"217";s:6:"лда";s:3:"218";s:6:"лык";s:3:"219";s:6:"мда";s:3:"220";s:5:"н ж";s:3:"221";s:6:"нди";s:3:"222";s:5:"ни ";s:3:"223";s:6:"нин";s:3:"224";s:6:"орд";s:3:"225";s:6:"рдо";s:3:"226";s:6:"Ñто";s:3:"227";s:5:"та ";s:3:"228";s:6:"тер";s:3:"229";s:6:"тти";s:3:"230";s:6:"тур";s:3:"231";s:6:"тын";s:3:"232";s:5:"уп ";s:3:"233";s:6:"ушу";s:3:"234";s:6:"фти";s:3:"235";s:6:"ыкт";s:3:"236";s:5:"үп ";s:3:"237";s:5:"өн ";s:3:"238";s:5:" ай";s:3:"239";s:5:" бү";s:3:"240";s:5:" ич";s:3:"241";s:5:" иш";s:3:"242";s:5:" мо";s:3:"243";s:5:" пр";s:3:"244";s:5:" ре";s:3:"245";s:5:" өк";s:3:"246";s:5:" Ó©Ñ‚";s:3:"247";s:5:"а д";s:3:"248";s:5:"а у";s:3:"249";s:5:"а Ñ";s:3:"250";s:6:"айм";s:3:"251";s:6:"амд";s:3:"252";s:6:"атт";s:3:"253";s:6:"бек";s:3:"254";s:6:"бул";s:3:"255";s:6:"гол";s:3:"256";s:6:"дег";s:3:"257";s:6:"еге";s:3:"258";s:6:"ейт";s:3:"259";s:6:"еле";s:3:"260";s:6:"енд";s:3:"261";s:6:"жак";s:3:"262";s:5:"и к";s:3:"263";s:6:"ини";s:3:"264";s:6:"ири";s:3:"265";s:6:"йма";s:3:"266";s:6:"кто";s:3:"267";s:6:"лик";s:3:"268";s:6:"мак";s:3:"269";s:6:"меÑ";s:3:"270";s:5:"н у";s:3:"271";s:5:"н ш";s:3:"272";s:6:"нтт";s:3:"273";s:5:"ол ";s:3:"274";s:6:"оло";s:3:"275";s:6:"пар";s:3:"276";s:6:"рак";s:3:"277";s:6:"Ñ€Ò¯Ò¯";s:3:"278";s:6:"ÑÑ‹Ñ€";s:3:"279";s:5:"ти ";s:3:"280";s:6:"тик";s:3:"281";s:6:"тта";s:3:"282";s:6:"Ñ‚Ó©Ñ€";s:3:"283";s:5:"у ж";s:3:"284";s:5:"у Ñ";s:3:"285";s:6:"шка";s:3:"286";s:5:"Ñ‹ м";s:3:"287";s:6:"ызы";s:3:"288";s:6:"ылд";s:3:"289";s:6:"Ñме";s:3:"290";s:6:"үрү";s:3:"291";s:6:"өлү";s:3:"292";s:6:"Ó©Ñ‚Ó©";s:3:"293";s:5:" же";s:3:"294";s:5:" Ñ‚Ò¯";s:3:"295";s:5:" Ñл";s:3:"296";s:5:" өн";s:3:"297";s:5:"а ж";s:3:"298";s:6:"ады";s:3:"299";}s:5:"latin";a:300:{s:3:"um ";s:1:"0";s:3:"us ";s:1:"1";s:3:"ut ";s:1:"2";s:3:"et ";s:1:"3";s:3:"is ";s:1:"4";s:3:" et";s:1:"5";s:3:" in";s:1:"6";s:3:" qu";s:1:"7";s:3:"tur";s:1:"8";s:3:" pr";s:1:"9";s:3:"est";s:2:"10";s:3:"tio";s:2:"11";s:3:" au";s:2:"12";s:3:"am ";s:2:"13";s:3:"em ";s:2:"14";s:3:"aut";s:2:"15";s:3:" di";s:2:"16";s:3:"ent";s:2:"17";s:3:"in ";s:2:"18";s:3:"dic";s:2:"19";s:3:"t e";s:2:"20";s:3:" es";s:2:"21";s:3:"ur ";s:2:"22";s:3:"ati";s:2:"23";s:3:"ion";s:2:"24";s:3:"st ";s:2:"25";s:3:" ut";s:2:"26";s:3:"ae ";s:2:"27";s:3:"qua";s:2:"28";s:3:" de";s:2:"29";s:3:"nt ";s:2:"30";s:3:" su";s:2:"31";s:3:" si";s:2:"32";s:3:"itu";s:2:"33";s:3:"unt";s:2:"34";s:3:"rum";s:2:"35";s:3:"ia ";s:2:"36";s:3:"es ";s:2:"37";s:3:"ter";s:2:"38";s:3:" re";s:2:"39";s:3:"nti";s:2:"40";s:3:"rae";s:2:"41";s:3:"s e";s:2:"42";s:3:"qui";s:2:"43";s:3:"io ";s:2:"44";s:3:"pro";s:2:"45";s:3:"it ";s:2:"46";s:3:"per";s:2:"47";s:3:"ita";s:2:"48";s:3:"one";s:2:"49";s:3:"ici";s:2:"50";s:3:"ius";s:2:"51";s:3:" co";s:2:"52";s:3:"t d";s:2:"53";s:3:"bus";s:2:"54";s:3:"pra";s:2:"55";s:3:"m e";s:2:"56";s:3:" no";s:2:"57";s:3:"edi";s:2:"58";s:3:"tia";s:2:"59";s:3:"ue ";s:2:"60";s:3:"ibu";s:2:"61";s:3:" se";s:2:"62";s:3:" ad";s:2:"63";s:3:"er ";s:2:"64";s:3:" fi";s:2:"65";s:3:"ili";s:2:"66";s:3:"que";s:2:"67";s:3:"t i";s:2:"68";s:3:"de ";s:2:"69";s:3:"oru";s:2:"70";s:3:" te";s:2:"71";s:3:"ali";s:2:"72";s:3:" pe";s:2:"73";s:3:"aed";s:2:"74";s:3:"cit";s:2:"75";s:3:"m d";s:2:"76";s:3:"t s";s:2:"77";s:3:"tat";s:2:"78";s:3:"tem";s:2:"79";s:3:"tis";s:2:"80";s:3:"t p";s:2:"81";s:3:"sti";s:2:"82";s:3:"te ";s:2:"83";s:3:"cum";s:2:"84";s:3:"ere";s:2:"85";s:3:"ium";s:2:"86";s:3:" ex";s:2:"87";s:3:"rat";s:2:"88";s:3:"ta ";s:2:"89";s:3:"con";s:2:"90";s:3:"cti";s:2:"91";s:3:"oni";s:2:"92";s:3:"ra ";s:2:"93";s:3:"s i";s:2:"94";s:3:" cu";s:2:"95";s:3:" sa";s:2:"96";s:3:"eni";s:2:"97";s:3:"nis";s:2:"98";s:3:"nte";s:2:"99";s:3:"eri";s:3:"100";s:3:"omi";s:3:"101";s:3:"re ";s:3:"102";s:3:"s a";s:3:"103";s:3:"min";s:3:"104";s:3:"os ";s:3:"105";s:3:"ti ";s:3:"106";s:3:"uer";s:3:"107";s:3:" ma";s:3:"108";s:3:" ue";s:3:"109";s:3:"m s";s:3:"110";s:3:"nem";s:3:"111";s:3:"t m";s:3:"112";s:3:" mo";s:3:"113";s:3:" po";s:3:"114";s:3:" ui";s:3:"115";s:3:"gen";s:3:"116";s:3:"ict";s:3:"117";s:3:"m i";s:3:"118";s:3:"ris";s:3:"119";s:3:"s s";s:3:"120";s:3:"t a";s:3:"121";s:3:"uae";s:3:"122";s:3:" do";s:3:"123";s:3:"m a";s:3:"124";s:3:"t c";s:3:"125";s:3:" ge";s:3:"126";s:3:"as ";s:3:"127";s:3:"e i";s:3:"128";s:3:"e p";s:3:"129";s:3:"ne ";s:3:"130";s:3:" ca";s:3:"131";s:3:"ine";s:3:"132";s:3:"quo";s:3:"133";s:3:"s p";s:3:"134";s:3:" al";s:3:"135";s:3:"e e";s:3:"136";s:3:"ntu";s:3:"137";s:3:"ro ";s:3:"138";s:3:"tri";s:3:"139";s:3:"tus";s:3:"140";s:3:"uit";s:3:"141";s:3:"atu";s:3:"142";s:3:"ini";s:3:"143";s:3:"iqu";s:3:"144";s:3:"m p";s:3:"145";s:3:"ost";s:3:"146";s:3:"res";s:3:"147";s:3:"ura";s:3:"148";s:3:" ac";s:3:"149";s:3:" fu";s:3:"150";s:3:"a e";s:3:"151";s:3:"ant";s:3:"152";s:3:"nes";s:3:"153";s:3:"nim";s:3:"154";s:3:"sun";s:3:"155";s:3:"tra";s:3:"156";s:3:"e a";s:3:"157";s:3:"s d";s:3:"158";s:3:" pa";s:3:"159";s:3:" uo";s:3:"160";s:3:"ecu";s:3:"161";s:3:" om";s:3:"162";s:3:" tu";s:3:"163";s:3:"ad ";s:3:"164";s:3:"cut";s:3:"165";s:3:"omn";s:3:"166";s:3:"s q";s:3:"167";s:3:" ei";s:3:"168";s:3:"ex ";s:3:"169";s:3:"icu";s:3:"170";s:3:"tor";s:3:"171";s:3:"uid";s:3:"172";s:3:" ip";s:3:"173";s:3:" me";s:3:"174";s:3:"e s";s:3:"175";s:3:"era";s:3:"176";s:3:"eru";s:3:"177";s:3:"iam";s:3:"178";s:3:"ide";s:3:"179";s:3:"ips";s:3:"180";s:3:" iu";s:3:"181";s:3:"a s";s:3:"182";s:3:"do ";s:3:"183";s:3:"e d";s:3:"184";s:3:"eiu";s:3:"185";s:3:"ica";s:3:"186";s:3:"im ";s:3:"187";s:3:"m c";s:3:"188";s:3:"m u";s:3:"189";s:3:"tiu";s:3:"190";s:3:" ho";s:3:"191";s:3:"cat";s:3:"192";s:3:"ist";s:3:"193";s:3:"nat";s:3:"194";s:3:"on ";s:3:"195";s:3:"pti";s:3:"196";s:3:"reg";s:3:"197";s:3:"rit";s:3:"198";s:3:"s t";s:3:"199";s:3:"sic";s:3:"200";s:3:"spe";s:3:"201";s:3:" en";s:3:"202";s:3:" sp";s:3:"203";s:3:"dis";s:3:"204";s:3:"eli";s:3:"205";s:3:"liq";s:3:"206";s:3:"lis";s:3:"207";s:3:"men";s:3:"208";s:3:"mus";s:3:"209";s:3:"num";s:3:"210";s:3:"pos";s:3:"211";s:3:"sio";s:3:"212";s:3:" an";s:3:"213";s:3:" gr";s:3:"214";s:3:"abi";s:3:"215";s:3:"acc";s:3:"216";s:3:"ect";s:3:"217";s:3:"ri ";s:3:"218";s:3:"uan";s:3:"219";s:3:" le";s:3:"220";s:3:"ecc";s:3:"221";s:3:"ete";s:3:"222";s:3:"gra";s:3:"223";s:3:"non";s:3:"224";s:3:"se ";s:3:"225";s:3:"uen";s:3:"226";s:3:"uis";s:3:"227";s:3:" fa";s:3:"228";s:3:" tr";s:3:"229";s:3:"ate";s:3:"230";s:3:"e c";s:3:"231";s:3:"fil";s:3:"232";s:3:"na ";s:3:"233";s:3:"ni ";s:3:"234";s:3:"pul";s:3:"235";s:3:"s f";s:3:"236";s:3:"ui ";s:3:"237";s:3:"at ";s:3:"238";s:3:"cce";s:3:"239";s:3:"dam";s:3:"240";s:3:"i e";s:3:"241";s:3:"ina";s:3:"242";s:3:"leg";s:3:"243";s:3:"nos";s:3:"244";s:3:"ori";s:3:"245";s:3:"pec";s:3:"246";s:3:"rop";s:3:"247";s:3:"sta";s:3:"248";s:3:"uia";s:3:"249";s:3:"ene";s:3:"250";s:3:"iue";s:3:"251";s:3:"iui";s:3:"252";s:3:"siu";s:3:"253";s:3:"t t";s:3:"254";s:3:"t u";s:3:"255";s:3:"tib";s:3:"256";s:3:"tit";s:3:"257";s:3:" da";s:3:"258";s:3:" ne";s:3:"259";s:3:"a d";s:3:"260";s:3:"and";s:3:"261";s:3:"ege";s:3:"262";s:3:"equ";s:3:"263";s:3:"hom";s:3:"264";s:3:"imu";s:3:"265";s:3:"lor";s:3:"266";s:3:"m m";s:3:"267";s:3:"mni";s:3:"268";s:3:"ndo";s:3:"269";s:3:"ner";s:3:"270";s:3:"o e";s:3:"271";s:3:"r e";s:3:"272";s:3:"sit";s:3:"273";s:3:"tum";s:3:"274";s:3:"utu";s:3:"275";s:3:"a p";s:3:"276";s:3:"bis";s:3:"277";s:3:"bit";s:3:"278";s:3:"cer";s:3:"279";s:3:"cta";s:3:"280";s:3:"dom";s:3:"281";s:3:"fut";s:3:"282";s:3:"i s";s:3:"283";s:3:"ign";s:3:"284";s:3:"int";s:3:"285";s:3:"mod";s:3:"286";s:3:"ndu";s:3:"287";s:3:"nit";s:3:"288";s:3:"rib";s:3:"289";s:3:"rti";s:3:"290";s:3:"tas";s:3:"291";s:3:"und";s:3:"292";s:3:" ab";s:3:"293";s:3:"err";s:3:"294";s:3:"ers";s:3:"295";s:3:"ite";s:3:"296";s:3:"iti";s:3:"297";s:3:"m t";s:3:"298";s:3:"o p";s:3:"299";}s:7:"latvian";a:300:{s:3:"as ";s:1:"0";s:3:" la";s:1:"1";s:3:" pa";s:1:"2";s:3:" ne";s:1:"3";s:3:"es ";s:1:"4";s:3:" un";s:1:"5";s:3:"un ";s:1:"6";s:3:" ka";s:1:"7";s:3:" va";s:1:"8";s:3:"ar ";s:1:"9";s:3:"s p";s:2:"10";s:3:" ar";s:2:"11";s:3:" vi";s:2:"12";s:3:"is ";s:2:"13";s:3:"ai ";s:2:"14";s:3:" no";s:2:"15";s:3:"ja ";s:2:"16";s:3:"ija";s:2:"17";s:3:"iem";s:2:"18";s:3:"em ";s:2:"19";s:3:"tu ";s:2:"20";s:3:"tie";s:2:"21";s:3:"vie";s:2:"22";s:3:"lat";s:2:"23";s:3:"aks";s:2:"24";s:3:"ien";s:2:"25";s:3:"kst";s:2:"26";s:3:"ies";s:2:"27";s:3:"s a";s:2:"28";s:3:"rak";s:2:"29";s:3:"atv";s:2:"30";s:3:"tvi";s:2:"31";s:3:" ja";s:2:"32";s:3:" pi";s:2:"33";s:3:"ka ";s:2:"34";s:3:" ir";s:2:"35";s:3:"ir ";s:2:"36";s:3:"ta ";s:2:"37";s:3:" sa";s:2:"38";s:3:"ts ";s:2:"39";s:4:" kÄ";s:2:"40";s:4:"Äs ";s:2:"41";s:3:" ti";s:2:"42";s:3:"ot ";s:2:"43";s:3:"s n";s:2:"44";s:3:" ie";s:2:"45";s:3:" ta";s:2:"46";s:4:"arÄ«";s:2:"47";s:3:"par";s:2:"48";s:3:"pie";s:2:"49";s:3:" pr";s:2:"50";s:4:"kÄ ";s:2:"51";s:3:" at";s:2:"52";s:3:" ra";s:2:"53";s:3:"am ";s:2:"54";s:4:"inÄ";s:2:"55";s:4:"tÄ ";s:2:"56";s:3:" iz";s:2:"57";s:3:"jas";s:2:"58";s:3:"lai";s:2:"59";s:3:" na";s:2:"60";s:3:"aut";s:2:"61";s:4:"ieÅ¡";s:2:"62";s:3:"s s";s:2:"63";s:3:" ap";s:2:"64";s:3:" ko";s:2:"65";s:3:" st";s:2:"66";s:3:"iek";s:2:"67";s:3:"iet";s:2:"68";s:3:"jau";s:2:"69";s:3:"us ";s:2:"70";s:4:"rÄ« ";s:2:"71";s:3:"tik";s:2:"72";s:4:"Ä«ba";s:2:"73";s:3:"na ";s:2:"74";s:3:" ga";s:2:"75";s:3:"cij";s:2:"76";s:3:"s i";s:2:"77";s:3:" uz";s:2:"78";s:3:"jum";s:2:"79";s:3:"s v";s:2:"80";s:3:"ms ";s:2:"81";s:3:"var";s:2:"82";s:3:" ku";s:2:"83";s:3:" ma";s:2:"84";s:4:"jÄ ";s:2:"85";s:3:"sta";s:2:"86";s:3:"s u";s:2:"87";s:4:" tÄ";s:2:"88";s:3:"die";s:2:"89";s:3:"kai";s:2:"90";s:3:"kas";s:2:"91";s:3:"ska";s:2:"92";s:3:" ci";s:2:"93";s:3:" da";s:2:"94";s:3:"kur";s:2:"95";s:3:"lie";s:2:"96";s:3:"tas";s:2:"97";s:3:"a p";s:2:"98";s:3:"est";s:2:"99";s:4:"stÄ";s:3:"100";s:4:"Å¡an";s:3:"101";s:3:"nes";s:3:"102";s:3:"nie";s:3:"103";s:3:"s d";s:3:"104";s:3:"s m";s:3:"105";s:3:"val";s:3:"106";s:3:" di";s:3:"107";s:3:" es";s:3:"108";s:3:" re";s:3:"109";s:3:"no ";s:3:"110";s:3:"to ";s:3:"111";s:3:"umu";s:3:"112";s:3:"vai";s:3:"113";s:4:"Å¡i ";s:3:"114";s:4:" vÄ“";s:3:"115";s:3:"kum";s:3:"116";s:3:"nu ";s:3:"117";s:3:"rie";s:3:"118";s:3:"s t";s:3:"119";s:4:"Äm ";s:3:"120";s:3:"ad ";s:3:"121";s:3:"et ";s:3:"122";s:3:"mu ";s:3:"123";s:3:"s l";s:3:"124";s:3:" be";s:3:"125";s:3:"aud";s:3:"126";s:3:"tur";s:3:"127";s:3:"vij";s:3:"128";s:4:"viņ";s:3:"129";s:4:"Äju";s:3:"130";s:3:"bas";s:3:"131";s:3:"gad";s:3:"132";s:3:"i n";s:3:"133";s:3:"ika";s:3:"134";s:3:"os ";s:3:"135";s:3:"a v";s:3:"136";s:3:"not";s:3:"137";s:3:"oti";s:3:"138";s:3:"sts";s:3:"139";s:3:"aik";s:3:"140";s:3:"u a";s:3:"141";s:4:"Ä a";s:3:"142";s:4:"Äk ";s:3:"143";s:3:" to";s:3:"144";s:3:"ied";s:3:"145";s:3:"stu";s:3:"146";s:3:"ti ";s:3:"147";s:3:"u p";s:3:"148";s:4:"vÄ“l";s:3:"149";s:4:"Äci";s:3:"150";s:4:" Å¡o";s:3:"151";s:3:"gi ";s:3:"152";s:3:"ko ";s:3:"153";s:3:"pro";s:3:"154";s:3:"s r";s:3:"155";s:4:"tÄj";s:3:"156";s:3:"u s";s:3:"157";s:3:"u v";s:3:"158";s:3:"vis";s:3:"159";s:3:"aun";s:3:"160";s:3:"ks ";s:3:"161";s:3:"str";s:3:"162";s:3:"zin";s:3:"163";s:3:"a a";s:3:"164";s:4:"adÄ«";s:3:"165";s:3:"da ";s:3:"166";s:3:"dar";s:3:"167";s:3:"ena";s:3:"168";s:3:"ici";s:3:"169";s:3:"kra";s:3:"170";s:3:"nas";s:3:"171";s:4:"stÄ«";s:3:"172";s:4:"Å¡u ";s:3:"173";s:4:" mÄ“";s:3:"174";s:3:"a n";s:3:"175";s:3:"eci";s:3:"176";s:3:"i s";s:3:"177";s:3:"ie ";s:3:"178";s:4:"iņa";s:3:"179";s:3:"ju ";s:3:"180";s:3:"las";s:3:"181";s:3:"r t";s:3:"182";s:3:"ums";s:3:"183";s:4:"Å¡ie";s:3:"184";s:3:"bu ";s:3:"185";s:3:"cit";s:3:"186";s:3:"i a";s:3:"187";s:3:"ina";s:3:"188";s:3:"ma ";s:3:"189";s:3:"pus";s:3:"190";s:3:"ra ";s:3:"191";s:3:" au";s:3:"192";s:3:" se";s:3:"193";s:3:" sl";s:3:"194";s:3:"a s";s:3:"195";s:3:"ais";s:3:"196";s:4:"eÅ¡i";s:3:"197";s:3:"iec";s:3:"198";s:3:"iku";s:3:"199";s:4:"pÄr";s:3:"200";s:3:"s b";s:3:"201";s:3:"s k";s:3:"202";s:3:"sot";s:3:"203";s:5:"ÄdÄ";s:3:"204";s:3:" in";s:3:"205";s:3:" li";s:3:"206";s:3:" tr";s:3:"207";s:3:"ana";s:3:"208";s:3:"eso";s:3:"209";s:3:"ikr";s:3:"210";s:3:"man";s:3:"211";s:3:"ne ";s:3:"212";s:3:"u k";s:3:"213";s:3:" tu";s:3:"214";s:3:"an ";s:3:"215";s:3:"av ";s:3:"216";s:3:"bet";s:3:"217";s:4:"bÅ«t";s:3:"218";s:3:"im ";s:3:"219";s:3:"isk";s:3:"220";s:4:"lÄ«d";s:3:"221";s:3:"nav";s:3:"222";s:3:"ras";s:3:"223";s:3:"ri ";s:3:"224";s:3:"s g";s:3:"225";s:3:"sti";s:3:"226";s:4:"Ä«dz";s:3:"227";s:3:" ai";s:3:"228";s:3:"arb";s:3:"229";s:3:"cin";s:3:"230";s:3:"das";s:3:"231";s:3:"ent";s:3:"232";s:3:"gal";s:3:"233";s:3:"i p";s:3:"234";s:3:"lik";s:3:"235";s:4:"mÄ ";s:3:"236";s:3:"nek";s:3:"237";s:3:"pat";s:3:"238";s:4:"rÄ“t";s:3:"239";s:3:"si ";s:3:"240";s:3:"tra";s:3:"241";s:4:"uÅ¡i";s:3:"242";s:3:"vei";s:3:"243";s:3:" br";s:3:"244";s:3:" pu";s:3:"245";s:3:" sk";s:3:"246";s:3:"als";s:3:"247";s:3:"ama";s:3:"248";s:3:"edz";s:3:"249";s:3:"eka";s:3:"250";s:4:"eÅ¡u";s:3:"251";s:3:"ieg";s:3:"252";s:3:"jis";s:3:"253";s:3:"kam";s:3:"254";s:3:"lst";s:3:"255";s:4:"nÄk";s:3:"256";s:3:"oli";s:3:"257";s:3:"pre";s:3:"258";s:4:"pÄ“c";s:3:"259";s:3:"rot";s:3:"260";s:4:"tÄs";s:3:"261";s:3:"usi";s:3:"262";s:4:"Ä“l ";s:3:"263";s:4:"Ä“s ";s:3:"264";s:3:" bi";s:3:"265";s:3:" de";s:3:"266";s:3:" me";s:3:"267";s:4:" pÄ";s:3:"268";s:3:"a i";s:3:"269";s:3:"aid";s:3:"270";s:4:"ajÄ";s:3:"271";s:3:"ikt";s:3:"272";s:3:"kat";s:3:"273";s:3:"lic";s:3:"274";s:3:"lod";s:3:"275";s:3:"mi ";s:3:"276";s:3:"ni ";s:3:"277";s:3:"pri";s:3:"278";s:4:"rÄd";s:3:"279";s:4:"rÄ«g";s:3:"280";s:3:"sim";s:3:"281";s:4:"trÄ";s:3:"282";s:3:"u l";s:3:"283";s:3:"uto";s:3:"284";s:3:"uz ";s:3:"285";s:4:"Ä“c ";s:3:"286";s:5:"Ä«tÄ";s:3:"287";s:3:" ce";s:3:"288";s:4:" jÄ";s:3:"289";s:3:" sv";s:3:"290";s:3:"a t";s:3:"291";s:3:"aga";s:3:"292";s:3:"aiz";s:3:"293";s:3:"atu";s:3:"294";s:3:"ba ";s:3:"295";s:3:"cie";s:3:"296";s:3:"du ";s:3:"297";s:3:"dzi";s:3:"298";s:4:"dzÄ«";s:3:"299";}s:10:"lithuanian";a:300:{s:3:"as ";s:1:"0";s:3:" pa";s:1:"1";s:3:" ka";s:1:"2";s:3:"ai ";s:1:"3";s:3:"us ";s:1:"4";s:3:"os ";s:1:"5";s:3:"is ";s:1:"6";s:3:" ne";s:1:"7";s:3:" ir";s:1:"8";s:3:"ir ";s:1:"9";s:3:"ti ";s:2:"10";s:3:" pr";s:2:"11";s:3:"aus";s:2:"12";s:3:"ini";s:2:"13";s:3:"s p";s:2:"14";s:3:"pas";s:2:"15";s:4:"ių ";s:2:"16";s:3:" ta";s:2:"17";s:3:" vi";s:2:"18";s:3:"iau";s:2:"19";s:3:" ko";s:2:"20";s:3:" su";s:2:"21";s:3:"kai";s:2:"22";s:3:"o p";s:2:"23";s:3:"usi";s:2:"24";s:3:" sa";s:2:"25";s:3:"vo ";s:2:"26";s:3:"tai";s:2:"27";s:3:"ali";s:2:"28";s:4:"tų ";s:2:"29";s:3:"io ";s:2:"30";s:3:"jo ";s:2:"31";s:3:"s k";s:2:"32";s:3:"sta";s:2:"33";s:3:"iai";s:2:"34";s:3:" bu";s:2:"35";s:3:" nu";s:2:"36";s:3:"ius";s:2:"37";s:3:"mo ";s:2:"38";s:3:" po";s:2:"39";s:3:"ien";s:2:"40";s:3:"s s";s:2:"41";s:3:"tas";s:2:"42";s:3:" me";s:2:"43";s:3:"uvo";s:2:"44";s:3:"kad";s:2:"45";s:4:" iÅ¡";s:2:"46";s:3:" la";s:2:"47";s:3:"to ";s:2:"48";s:3:"ais";s:2:"49";s:3:"ie ";s:2:"50";s:3:"kur";s:2:"51";s:3:"uri";s:2:"52";s:3:" ku";s:2:"53";s:3:"ijo";s:2:"54";s:4:"Äia";s:2:"55";s:3:"au ";s:2:"56";s:3:"met";s:2:"57";s:3:"je ";s:2:"58";s:3:" va";s:2:"59";s:3:"ad ";s:2:"60";s:3:" ap";s:2:"61";s:3:"and";s:2:"62";s:3:" gr";s:2:"63";s:3:" ti";s:2:"64";s:3:"kal";s:2:"65";s:3:"asi";s:2:"66";s:3:"i p";s:2:"67";s:4:"iÄi";s:2:"68";s:3:"s i";s:2:"69";s:3:"s v";s:2:"70";s:3:"ink";s:2:"71";s:3:"o n";s:2:"72";s:4:"Ä—s ";s:2:"73";s:3:"buv";s:2:"74";s:3:"s a";s:2:"75";s:3:" ga";s:2:"76";s:3:"aip";s:2:"77";s:3:"avi";s:2:"78";s:3:"mas";s:2:"79";s:3:"pri";s:2:"80";s:3:"tik";s:2:"81";s:3:" re";s:2:"82";s:3:"etu";s:2:"83";s:3:"jos";s:2:"84";s:3:" da";s:2:"85";s:3:"ent";s:2:"86";s:3:"oli";s:2:"87";s:3:"par";s:2:"88";s:3:"ant";s:2:"89";s:3:"ara";s:2:"90";s:3:"tar";s:2:"91";s:3:"ama";s:2:"92";s:3:"gal";s:2:"93";s:3:"imo";s:2:"94";s:4:"iÅ¡k";s:2:"95";s:3:"o s";s:2:"96";s:3:" at";s:2:"97";s:3:" be";s:2:"98";s:4:" į ";s:2:"99";s:3:"min";s:3:"100";s:3:"tin";s:3:"101";s:3:" tu";s:3:"102";s:3:"s n";s:3:"103";s:3:" jo";s:3:"104";s:3:"dar";s:3:"105";s:3:"ip ";s:3:"106";s:3:"rei";s:3:"107";s:3:" te";s:3:"108";s:4:"dži";s:3:"109";s:3:"kas";s:3:"110";s:3:"nin";s:3:"111";s:3:"tei";s:3:"112";s:3:"vie";s:3:"113";s:3:" li";s:3:"114";s:3:" se";s:3:"115";s:3:"cij";s:3:"116";s:3:"gar";s:3:"117";s:3:"lai";s:3:"118";s:3:"art";s:3:"119";s:3:"lau";s:3:"120";s:3:"ras";s:3:"121";s:3:"no ";s:3:"122";s:3:"o k";s:3:"123";s:4:"tÄ… ";s:3:"124";s:3:" ar";s:3:"125";s:4:"Ä—jo";s:3:"126";s:4:"viÄ";s:3:"127";s:3:"iga";s:3:"128";s:3:"pra";s:3:"129";s:3:"vis";s:3:"130";s:3:" na";s:3:"131";s:3:"men";s:3:"132";s:3:"oki";s:3:"133";s:4:"raÅ¡";s:3:"134";s:3:"s t";s:3:"135";s:3:"iet";s:3:"136";s:3:"ika";s:3:"137";s:3:"int";s:3:"138";s:3:"kom";s:3:"139";s:3:"tam";s:3:"140";s:3:"aug";s:3:"141";s:3:"avo";s:3:"142";s:3:"rie";s:3:"143";s:3:"s b";s:3:"144";s:3:" st";s:3:"145";s:3:"eim";s:3:"146";s:3:"ko ";s:3:"147";s:3:"nus";s:3:"148";s:3:"pol";s:3:"149";s:3:"ria";s:3:"150";s:3:"sau";s:3:"151";s:3:"api";s:3:"152";s:3:"me ";s:3:"153";s:3:"ne ";s:3:"154";s:3:"sik";s:3:"155";s:4:" Å¡i";s:3:"156";s:3:"i n";s:3:"157";s:3:"ia ";s:3:"158";s:3:"ici";s:3:"159";s:3:"oja";s:3:"160";s:3:"sak";s:3:"161";s:3:"sti";s:3:"162";s:3:"ui ";s:3:"163";s:3:"ame";s:3:"164";s:3:"lie";s:3:"165";s:3:"o t";s:3:"166";s:3:"pie";s:3:"167";s:4:"Äiu";s:3:"168";s:3:" di";s:3:"169";s:3:" pe";s:3:"170";s:3:"gri";s:3:"171";s:3:"ios";s:3:"172";s:3:"lia";s:3:"173";s:3:"lin";s:3:"174";s:3:"s d";s:3:"175";s:3:"s g";s:3:"176";s:3:"ta ";s:3:"177";s:3:"uot";s:3:"178";s:3:" ja";s:3:"179";s:4:" už";s:3:"180";s:3:"aut";s:3:"181";s:3:"i s";s:3:"182";s:3:"ino";s:3:"183";s:4:"mÄ… ";s:3:"184";s:3:"oje";s:3:"185";s:3:"rav";s:3:"186";s:4:"dÄ—l";s:3:"187";s:3:"nti";s:3:"188";s:3:"o a";s:3:"189";s:3:"toj";s:3:"190";s:4:"Ä—l ";s:3:"191";s:3:" to";s:3:"192";s:3:" vy";s:3:"193";s:3:"ar ";s:3:"194";s:3:"ina";s:3:"195";s:3:"lic";s:3:"196";s:3:"o v";s:3:"197";s:3:"sei";s:3:"198";s:3:"su ";s:3:"199";s:3:" mi";s:3:"200";s:3:" pi";s:3:"201";s:3:"din";s:3:"202";s:4:"iÅ¡ ";s:3:"203";s:3:"lan";s:3:"204";s:3:"si ";s:3:"205";s:3:"tus";s:3:"206";s:3:" ba";s:3:"207";s:3:"asa";s:3:"208";s:3:"ata";s:3:"209";s:3:"kla";s:3:"210";s:3:"omi";s:3:"211";s:3:"tat";s:3:"212";s:3:" an";s:3:"213";s:3:" ji";s:3:"214";s:3:"als";s:3:"215";s:3:"ena";s:3:"216";s:4:"jų ";s:3:"217";s:3:"nuo";s:3:"218";s:3:"per";s:3:"219";s:3:"rig";s:3:"220";s:3:"s m";s:3:"221";s:3:"val";s:3:"222";s:3:"yta";s:3:"223";s:4:"Äio";s:3:"224";s:3:" ra";s:3:"225";s:3:"i k";s:3:"226";s:3:"lik";s:3:"227";s:3:"net";s:3:"228";s:4:"nÄ— ";s:3:"229";s:3:"tis";s:3:"230";s:3:"tuo";s:3:"231";s:3:"yti";s:3:"232";s:4:"Ä™s ";s:3:"233";s:4:"ų s";s:3:"234";s:3:"ada";s:3:"235";s:3:"ari";s:3:"236";s:3:"do ";s:3:"237";s:3:"eik";s:3:"238";s:3:"eis";s:3:"239";s:3:"ist";s:3:"240";s:3:"lst";s:3:"241";s:3:"ma ";s:3:"242";s:3:"nes";s:3:"243";s:3:"sav";s:3:"244";s:3:"sio";s:3:"245";s:3:"tau";s:3:"246";s:3:" ki";s:3:"247";s:3:"aik";s:3:"248";s:3:"aud";s:3:"249";s:3:"ies";s:3:"250";s:3:"ori";s:3:"251";s:3:"s r";s:3:"252";s:3:"ska";s:3:"253";s:3:" ge";s:3:"254";s:3:"ast";s:3:"255";s:3:"eig";s:3:"256";s:3:"et ";s:3:"257";s:3:"iam";s:3:"258";s:3:"isa";s:3:"259";s:3:"mis";s:3:"260";s:3:"nam";s:3:"261";s:3:"ome";s:3:"262";s:4:"žia";s:3:"263";s:3:"aba";s:3:"264";s:3:"aul";s:3:"265";s:3:"ikr";s:3:"266";s:4:"kÄ… ";s:3:"267";s:3:"nta";s:3:"268";s:3:"ra ";s:3:"269";s:3:"tur";s:3:"270";s:3:" ma";s:3:"271";s:3:"die";s:3:"272";s:3:"ei ";s:3:"273";s:3:"i t";s:3:"274";s:3:"nas";s:3:"275";s:3:"rin";s:3:"276";s:3:"sto";s:3:"277";s:3:"tie";s:3:"278";s:3:"tuv";s:3:"279";s:3:"vos";s:3:"280";s:4:"ų p";s:3:"281";s:4:" dÄ—";s:3:"282";s:3:"are";s:3:"283";s:3:"ats";s:3:"284";s:4:"enÄ—";s:3:"285";s:3:"ili";s:3:"286";s:3:"ima";s:3:"287";s:3:"kar";s:3:"288";s:3:"ms ";s:3:"289";s:3:"nia";s:3:"290";s:3:"r p";s:3:"291";s:3:"rod";s:3:"292";s:3:"s l";s:3:"293";s:3:" o ";s:3:"294";s:3:"e p";s:3:"295";s:3:"es ";s:3:"296";s:3:"ide";s:3:"297";s:3:"ik ";s:3:"298";s:3:"ja ";s:3:"299";}s:10:"macedonian";a:300:{s:5:"на ";s:1:"0";s:5:" на";s:1:"1";s:5:"та ";s:1:"2";s:6:"ата";s:1:"3";s:6:"ија";s:1:"4";s:5:" пр";s:1:"5";s:5:"то ";s:1:"6";s:5:"ја ";s:1:"7";s:5:" за";s:1:"8";s:5:"а н";s:1:"9";s:4:" и ";s:2:"10";s:5:"а Ñ";s:2:"11";s:5:"те ";s:2:"12";s:6:"ите";s:2:"13";s:5:" ко";s:2:"14";s:5:"от ";s:2:"15";s:5:" де";s:2:"16";s:5:" по";s:2:"17";s:5:"а д";s:2:"18";s:5:"во ";s:2:"19";s:5:"за ";s:2:"20";s:5:" во";s:2:"21";s:5:" од";s:2:"22";s:5:" Ñе";s:2:"23";s:5:" не";s:2:"24";s:5:"Ñе ";s:2:"25";s:5:" до";s:2:"26";s:5:"а в";s:2:"27";s:5:"ка ";s:2:"28";s:6:"ање";s:2:"29";s:5:"а п";s:2:"30";s:5:"о п";s:2:"31";s:6:"ува";s:2:"32";s:6:"циј";s:2:"33";s:5:"а о";s:2:"34";s:6:"ици";s:2:"35";s:6:"ето";s:2:"36";s:5:"о н";s:2:"37";s:6:"ани";s:2:"38";s:5:"ни ";s:2:"39";s:5:" вл";s:2:"40";s:6:"дек";s:2:"41";s:6:"ека";s:2:"42";s:6:"њет";s:2:"43";s:5:"ќе ";s:2:"44";s:4:" е ";s:2:"45";s:5:"а з";s:2:"46";s:5:"а и";s:2:"47";s:5:"ат ";s:2:"48";s:6:"вла";s:2:"49";s:5:"го ";s:2:"50";s:5:"е н";s:2:"51";s:5:"од ";s:2:"52";s:6:"пре";s:2:"53";s:5:" го";s:2:"54";s:5:" да";s:2:"55";s:5:" ма";s:2:"56";s:5:" ре";s:2:"57";s:5:" ќе";s:2:"58";s:6:"али";s:2:"59";s:5:"и д";s:2:"60";s:5:"и н";s:2:"61";s:6:"иот";s:2:"62";s:6:"нат";s:2:"63";s:6:"ово";s:2:"64";s:5:" па";s:2:"65";s:5:" ра";s:2:"66";s:5:" Ñо";s:2:"67";s:6:"ове";s:2:"68";s:6:"пра";s:2:"69";s:6:"што";s:2:"70";s:5:"ње ";s:2:"71";s:5:"а е";s:2:"72";s:5:"да ";s:2:"73";s:6:"дат";s:2:"74";s:6:"дон";s:2:"75";s:5:"е в";s:2:"76";s:5:"е д";s:2:"77";s:5:"е з";s:2:"78";s:5:"е Ñ";s:2:"79";s:6:"кон";s:2:"80";s:6:"нит";s:2:"81";s:5:"но ";s:2:"82";s:6:"они";s:2:"83";s:6:"ото";s:2:"84";s:6:"пар";s:2:"85";s:6:"при";s:2:"86";s:6:"Ñта";s:2:"87";s:5:"Ñ‚ н";s:2:"88";s:5:" шт";s:2:"89";s:5:"а к";s:2:"90";s:6:"аци";s:2:"91";s:5:"ва ";s:2:"92";s:6:"вањ";s:2:"93";s:5:"е п";s:2:"94";s:6:"ени";s:2:"95";s:5:"ла ";s:2:"96";s:6:"лад";s:2:"97";s:6:"мак";s:2:"98";s:6:"неÑ";s:2:"99";s:6:"ноÑ";s:3:"100";s:6:"про";s:3:"101";s:6:"рен";s:3:"102";s:6:"јат";s:3:"103";s:5:" ин";s:3:"104";s:5:" ме";s:3:"105";s:5:" то";s:3:"106";s:5:"а г";s:3:"107";s:5:"а м";s:3:"108";s:5:"а Ñ€";s:3:"109";s:6:"аке";s:3:"110";s:6:"ако";s:3:"111";s:6:"вор";s:3:"112";s:6:"гов";s:3:"113";s:6:"едо";s:3:"114";s:6:"ена";s:3:"115";s:5:"и и";s:3:"116";s:6:"ира";s:3:"117";s:6:"кед";s:3:"118";s:5:"не ";s:3:"119";s:6:"ниц";s:3:"120";s:6:"ниј";s:3:"121";s:6:"оÑÑ‚";s:3:"122";s:5:"ра ";s:3:"123";s:6:"рат";s:3:"124";s:6:"ред";s:3:"125";s:6:"Ñка";s:3:"126";s:6:"тен";s:3:"127";s:5:" ка";s:3:"128";s:5:" Ñп";s:3:"129";s:5:" ја";s:3:"130";s:5:"а Ñ‚";s:3:"131";s:6:"аде";s:3:"132";s:6:"арт";s:3:"133";s:5:"е г";s:3:"134";s:5:"е и";s:3:"135";s:6:"кат";s:3:"136";s:6:"лаÑ";s:3:"137";s:6:"нио";s:3:"138";s:5:"о Ñ";s:3:"139";s:5:"ри ";s:3:"140";s:5:" ба";s:3:"141";s:5:" би";s:3:"142";s:6:"ава";s:3:"143";s:6:"ате";s:3:"144";s:6:"вни";s:3:"145";s:5:"д н";s:3:"146";s:6:"ден";s:3:"147";s:6:"дов";s:3:"148";s:6:"држ";s:3:"149";s:6:"дув";s:3:"150";s:5:"е о";s:3:"151";s:5:"ен ";s:3:"152";s:6:"ере";s:3:"153";s:6:"ери";s:3:"154";s:5:"и п";s:3:"155";s:5:"и Ñ";s:3:"156";s:6:"ина";s:3:"157";s:6:"кој";s:3:"158";s:6:"нци";s:3:"159";s:5:"о м";s:3:"160";s:5:"о о";s:3:"161";s:6:"одн";s:3:"162";s:6:"пор";s:3:"163";s:6:"Ñки";s:3:"164";s:6:"Ñпо";s:3:"165";s:6:"Ñтв";s:3:"166";s:6:"Ñти";s:3:"167";s:6:"тво";s:3:"168";s:5:"ти ";s:3:"169";s:5:" об";s:3:"170";s:5:" ов";s:3:"171";s:5:"а б";s:3:"172";s:6:"алн";s:3:"173";s:6:"ара";s:3:"174";s:6:"бар";s:3:"175";s:5:"е к";s:3:"176";s:5:"ед ";s:3:"177";s:6:"ент";s:3:"178";s:6:"еѓу";s:3:"179";s:5:"и о";s:3:"180";s:5:"ии ";s:3:"181";s:6:"меѓ";s:3:"182";s:5:"о д";s:3:"183";s:6:"оја";s:3:"184";s:6:"пот";s:3:"185";s:6:"раз";s:3:"186";s:6:"раш";s:3:"187";s:6:"Ñпр";s:3:"188";s:6:"Ñто";s:3:"189";s:5:"Ñ‚ д";s:3:"190";s:5:"ци ";s:3:"191";s:5:" бе";s:3:"192";s:5:" гр";s:3:"193";s:5:" др";s:3:"194";s:5:" из";s:3:"195";s:5:" ÑÑ‚";s:3:"196";s:5:"аа ";s:3:"197";s:6:"бид";s:3:"198";s:6:"вед";s:3:"199";s:6:"гла";s:3:"200";s:6:"еко";s:3:"201";s:6:"енд";s:3:"202";s:6:"еÑе";s:3:"203";s:6:"етÑ";s:3:"204";s:6:"зац";s:3:"205";s:5:"и Ñ‚";s:3:"206";s:6:"иза";s:3:"207";s:6:"инÑ";s:3:"208";s:6:"иÑÑ‚";s:3:"209";s:5:"ки ";s:3:"210";s:6:"ков";s:3:"211";s:6:"кол";s:3:"212";s:5:"ку ";s:3:"213";s:6:"лиц";s:3:"214";s:5:"о з";s:3:"215";s:5:"о и";s:3:"216";s:6:"ова";s:3:"217";s:6:"олк";s:3:"218";s:6:"оре";s:3:"219";s:6:"ори";s:3:"220";s:6:"под";s:3:"221";s:6:"рањ";s:3:"222";s:6:"реф";s:3:"223";s:6:"ржа";s:3:"224";s:6:"ров";s:3:"225";s:6:"рти";s:3:"226";s:5:"Ñо ";s:3:"227";s:6:"тор";s:3:"228";s:6:"фер";s:3:"229";s:6:"цен";s:3:"230";s:6:"цит";s:3:"231";s:4:" а ";s:3:"232";s:5:" вр";s:3:"233";s:5:" гл";s:3:"234";s:5:" дп";s:3:"235";s:5:" мо";s:3:"236";s:5:" ни";s:3:"237";s:5:" но";s:3:"238";s:5:" оп";s:3:"239";s:5:" от";s:3:"240";s:5:"а Ñœ";s:3:"241";s:6:"або";s:3:"242";s:6:"ада";s:3:"243";s:6:"аÑа";s:3:"244";s:6:"аша";s:3:"245";s:5:"ба ";s:3:"246";s:6:"бот";s:3:"247";s:6:"ваа";s:3:"248";s:6:"ват";s:3:"249";s:6:"вот";s:3:"250";s:5:"ги ";s:3:"251";s:6:"гра";s:3:"252";s:5:"де ";s:3:"253";s:6:"дин";s:3:"254";s:6:"дум";s:3:"255";s:6:"евр";s:3:"256";s:6:"еду";s:3:"257";s:6:"ено";s:3:"258";s:6:"ера";s:3:"259";s:5:"ÐµÑ ";s:3:"260";s:6:"ење";s:3:"261";s:5:"же ";s:3:"262";s:6:"зак";s:3:"263";s:5:"и в";s:3:"264";s:6:"ила";s:3:"265";s:6:"иту";s:3:"266";s:6:"коа";s:3:"267";s:6:"кои";s:3:"268";s:6:"лан";s:3:"269";s:6:"лку";s:3:"270";s:6:"лож";s:3:"271";s:6:"мот";s:3:"272";s:6:"нду";s:3:"273";s:6:"нÑÑ‚";s:3:"274";s:5:"о в";s:3:"275";s:5:"оа ";s:3:"276";s:6:"оал";s:3:"277";s:6:"обр";s:3:"278";s:5:"ов ";s:3:"279";s:6:"ови";s:3:"280";s:6:"овн";s:3:"281";s:5:"ои ";s:3:"282";s:5:"ор ";s:3:"283";s:6:"орм";s:3:"284";s:5:"ој ";s:3:"285";s:6:"рет";s:3:"286";s:6:"Ñед";s:3:"287";s:5:"ÑÑ‚ ";s:3:"288";s:6:"тер";s:3:"289";s:6:"тиј";s:3:"290";s:6:"тоа";s:3:"291";s:6:"фор";s:3:"292";s:6:"ции";s:3:"293";s:5:"ѓу ";s:3:"294";s:5:" ал";s:3:"295";s:5:" ве";s:3:"296";s:5:" вм";s:3:"297";s:5:" ги";s:3:"298";s:5:" ду";s:3:"299";}s:9:"mongolian";a:300:{s:5:"ын ";s:1:"0";s:5:" ба";s:1:"1";s:5:"йн ";s:1:"2";s:6:"бай";s:1:"3";s:6:"ийн";s:1:"4";s:6:"уул";s:1:"5";s:5:" ул";s:1:"6";s:6:"улÑ";s:1:"7";s:5:"ан ";s:1:"8";s:5:" ха";s:1:"9";s:6:"ний";s:2:"10";s:5:"н Ñ…";s:2:"11";s:6:"гаа";s:2:"12";s:6:"Ñын";s:2:"13";s:5:"ий ";s:2:"14";s:6:"лÑÑ‹";s:2:"15";s:5:" бо";s:2:"16";s:5:"й б";s:2:"17";s:5:"Ñн ";s:2:"18";s:5:"ах ";s:2:"19";s:6:"бол";s:2:"20";s:5:"ол ";s:2:"21";s:5:"н б";s:2:"22";s:6:"оло";s:2:"23";s:5:" Ñ…Ñ";s:2:"24";s:6:"онг";s:2:"25";s:6:"гол";s:2:"26";s:6:"гуу";s:2:"27";s:6:"нго";s:2:"28";s:5:"ыг ";s:2:"29";s:6:"жил";s:2:"30";s:5:" мо";s:2:"31";s:6:"лаг";s:2:"32";s:6:"лла";s:2:"33";s:6:"мон";s:2:"34";s:5:" Ñ‚Ñ”";s:2:"35";s:5:" ху";s:2:"36";s:6:"айд";s:2:"37";s:5:"ны ";s:2:"38";s:5:"он ";s:2:"39";s:6:"Ñан";s:2:"40";s:6:"хий";s:2:"41";s:5:" аж";s:2:"42";s:5:" ор";s:2:"43";s:5:"л у";s:2:"44";s:5:"н Ñ‚";s:2:"45";s:6:"улг";s:2:"46";s:6:"айг";s:2:"47";s:6:"длы";s:2:"48";s:5:"йг ";s:2:"49";s:5:" за";s:2:"50";s:6:"дÑÑ";s:2:"51";s:5:"н а";s:2:"52";s:6:"ндÑ";s:2:"53";s:6:"ула";s:2:"54";s:5:"ÑÑ ";s:2:"55";s:6:"ага";s:2:"56";s:6:"ийг";s:2:"57";s:4:"vй ";s:2:"58";s:5:"аа ";s:2:"59";s:5:"й а";s:2:"60";s:6:"лын";s:2:"61";s:5:"н з";s:2:"62";s:5:" аю";s:2:"63";s:5:" зє";s:2:"64";s:6:"аар";s:2:"65";s:5:"ад ";s:2:"66";s:5:"ар ";s:2:"67";s:5:"гvй";s:2:"68";s:6:"зєв";s:2:"69";s:6:"ажи";s:2:"70";s:5:"ал ";s:2:"71";s:6:"аюу";s:2:"72";s:5:"г Ñ…";s:2:"73";s:5:"лгv";s:2:"74";s:5:"лж ";s:2:"75";s:6:"Ñни";s:2:"76";s:6:"ÑÑн";s:2:"77";s:6:"юул";s:2:"78";s:6:"йдл";s:2:"79";s:6:"лыг";s:2:"80";s:6:"нхи";s:2:"81";s:6:"ууд";s:2:"82";s:6:"хам";s:2:"83";s:5:" нÑ";s:2:"84";s:5:" Ñа";s:2:"85";s:6:"гий";s:2:"86";s:6:"лах";s:2:"87";s:6:"лєл";s:2:"88";s:6:"рєн";s:2:"89";s:6:"єгч";s:2:"90";s:5:" та";s:2:"91";s:6:"илл";s:2:"92";s:6:"лий";s:2:"93";s:6:"лÑÑ…";s:2:"94";s:6:"рий";s:2:"95";s:5:"ÑÑ… ";s:2:"96";s:5:" ер";s:2:"97";s:5:" ÑÑ€";s:2:"98";s:6:"влє";s:2:"99";s:6:"ерє";s:3:"100";s:6:"ийл";s:3:"101";s:6:"лон";s:3:"102";s:6:"лєг";s:3:"103";s:6:"євл";s:3:"104";s:6:"єнх";s:3:"105";s:5:" хо";s:3:"106";s:6:"ари";s:3:"107";s:5:"их ";s:3:"108";s:6:"хан";s:3:"109";s:5:"ÑÑ€ ";s:3:"110";s:5:"єн ";s:3:"111";s:4:"vvл";s:3:"112";s:5:"ж б";s:3:"113";s:6:"Ñ‚Ñй";s:3:"114";s:5:"Ñ… Ñ…";s:3:"115";s:6:"Ñрх";s:3:"116";s:4:" vн";s:3:"117";s:5:" нь";s:3:"118";s:5:"vнд";s:3:"119";s:6:"алт";s:3:"120";s:6:"йлє";s:3:"121";s:5:"нь ";s:3:"122";s:6:"тєр";s:3:"123";s:5:" га";s:3:"124";s:5:" Ñу";s:3:"125";s:6:"аан";s:3:"126";s:6:"даа";s:3:"127";s:6:"илц";s:3:"128";s:6:"йгу";s:3:"129";s:5:"л а";s:3:"130";s:6:"лаа";s:3:"131";s:5:"н н";s:3:"132";s:6:"руу";s:3:"133";s:5:"Ñй ";s:3:"134";s:5:" то";s:3:"135";s:5:"н Ñ";s:3:"136";s:6:"рил";s:3:"137";s:6:"єри";s:3:"138";s:6:"ааг";s:3:"139";s:5:"гч ";s:3:"140";s:6:"лÑÑ";s:3:"141";s:5:"н о";s:3:"142";s:6:"Ñ€Ñг";s:3:"143";s:6:"Ñуу";s:3:"144";s:6:"ÑÑ€Ñ";s:3:"145";s:6:"їїл";s:3:"146";s:4:" yн";s:3:"147";s:5:" бу";s:3:"148";s:5:" дÑ";s:3:"149";s:5:" ол";s:3:"150";s:5:" ту";s:3:"151";s:5:" ши";s:3:"152";s:5:"yнд";s:3:"153";s:6:"аши";s:3:"154";s:5:"г Ñ‚";s:3:"155";s:5:"иг ";s:3:"156";s:5:"йл ";s:3:"157";s:6:"хар";s:3:"158";s:6:"шин";s:3:"159";s:5:"Ñг ";s:3:"160";s:5:"єр ";s:3:"161";s:5:" их";s:3:"162";s:5:" Ñ…Ñ”";s:3:"163";s:5:" Ñ…Ñ—";s:3:"164";s:5:"ам ";s:3:"165";s:6:"анг";s:3:"166";s:5:"ин ";s:3:"167";s:6:"йга";s:3:"168";s:6:"лÑа";s:3:"169";s:4:"н v";s:3:"170";s:5:"н е";s:3:"171";s:6:"нал";s:3:"172";s:5:"нд ";s:3:"173";s:6:"хуу";s:3:"174";s:6:"цаа";s:3:"175";s:5:"Ñд ";s:3:"176";s:6:"ÑÑÑ€";s:3:"177";s:5:"єл ";s:3:"178";s:5:"vйл";s:3:"179";s:6:"ада";s:3:"180";s:6:"айн";s:3:"181";s:6:"ала";s:3:"182";s:6:"амт";s:3:"183";s:6:"гах";s:3:"184";s:5:"д Ñ…";s:3:"185";s:6:"дал";s:3:"186";s:6:"зар";s:3:"187";s:5:"л б";s:3:"188";s:6:"лан";s:3:"189";s:5:"н д";s:3:"190";s:6:"ÑÑн";s:3:"191";s:6:"улл";s:3:"192";s:5:"Ñ… б";s:3:"193";s:6:"Ñ…ÑÑ€";s:3:"194";s:4:" бv";s:3:"195";s:5:" да";s:3:"196";s:5:" зо";s:3:"197";s:5:"vÑ€Ñ";s:3:"198";s:6:"аад";s:3:"199";s:6:"гÑÑ";s:3:"200";s:6:"лÑн";s:3:"201";s:5:"н и";s:3:"202";s:5:"н Ñ";s:3:"203";s:6:"нга";s:3:"204";s:5:"Ð½Ñ ";s:3:"205";s:6:"тал";s:3:"206";s:6:"тын";s:3:"207";s:6:"хур";s:3:"208";s:5:"Ñл ";s:3:"209";s:5:" на";s:3:"210";s:5:" ни";s:3:"211";s:5:" он";s:3:"212";s:5:"vлÑ";s:3:"213";s:5:"аг ";s:3:"214";s:5:"аж ";s:3:"215";s:5:"ай ";s:3:"216";s:6:"ата";s:3:"217";s:6:"бар";s:3:"218";s:5:"г б";s:3:"219";s:6:"гад";s:3:"220";s:6:"гїй";s:3:"221";s:5:"й Ñ…";s:3:"222";s:5:"лт ";s:3:"223";s:5:"н м";s:3:"224";s:5:"на ";s:3:"225";s:6:"оро";s:3:"226";s:6:"уль";s:3:"227";s:6:"чин";s:3:"228";s:5:"Ñж ";s:3:"229";s:6:"ÑнÑ";s:3:"230";s:6:"ÑÑд";s:3:"231";s:5:"їй ";s:3:"232";s:6:"їлÑ";s:3:"233";s:5:" би";s:3:"234";s:5:" Ñ‚Ñ";s:3:"235";s:5:" Ñн";s:3:"236";s:6:"аны";s:3:"237";s:6:"дий";s:3:"238";s:6:"дÑÑ";s:3:"239";s:6:"лал";s:3:"240";s:6:"лга";s:3:"241";s:5:"лд ";s:3:"242";s:6:"лог";s:3:"243";s:5:"ль ";s:3:"244";s:5:"н у";s:3:"245";s:5:"н Ñ—";s:3:"246";s:5:"Ñ€ б";s:3:"247";s:6:"рал";s:3:"248";s:6:"Ñон";s:3:"249";s:6:"тай";s:3:"250";s:6:"удл";s:3:"251";s:6:"Ñлт";s:3:"252";s:6:"Ñрг";s:3:"253";s:6:"єлє";s:3:"254";s:4:" vй";s:3:"255";s:4:" в ";s:3:"256";s:5:" гÑ";s:3:"257";s:4:" Ñ…v";s:3:"258";s:6:"ара";s:3:"259";s:5:"бvÑ€";s:3:"260";s:5:"д н";s:3:"261";s:5:"д о";s:3:"262";s:5:"л Ñ…";s:3:"263";s:5:"Ð»Ñ ";s:3:"264";s:6:"лты";s:3:"265";s:5:"н г";s:3:"266";s:6:"нÑг";s:3:"267";s:6:"огт";s:3:"268";s:6:"олы";s:3:"269";s:6:"оёр";s:3:"270";s:5:"Ñ€ Ñ‚";s:3:"271";s:6:"Ñ€ÑÑ";s:3:"272";s:6:"тав";s:3:"273";s:6:"тог";s:3:"274";s:6:"уур";s:3:"275";s:6:"хоё";s:3:"276";s:6:"Ñ…Ñл";s:3:"277";s:6:"Ñ…ÑÑ";s:3:"278";s:6:"ÑлÑ";s:3:"279";s:5:"Ñ‘Ñ€ ";s:3:"280";s:5:" ав";s:3:"281";s:5:" аÑ";s:3:"282";s:5:" аш";s:3:"283";s:5:" ду";s:3:"284";s:5:" Ñо";s:3:"285";s:5:" чи";s:3:"286";s:5:" Ñв";s:3:"287";s:5:" єр";s:3:"288";s:6:"аал";s:3:"289";s:6:"алд";s:3:"290";s:6:"амж";s:3:"291";s:6:"анд";s:3:"292";s:6:"аÑу";s:3:"293";s:6:"вÑÑ€";s:3:"294";s:5:"г у";s:3:"295";s:6:"двÑ";s:3:"296";s:4:"жvv";s:3:"297";s:6:"лца";s:3:"298";s:6:"лÑл";s:3:"299";}s:6:"nepali";a:300:{s:7:"को ";s:1:"0";s:7:"का ";s:1:"1";s:7:"मा ";s:1:"2";s:9:"हरà¥";s:1:"3";s:7:" ने";s:1:"4";s:9:"नेप";s:1:"5";s:9:"पाल";s:1:"6";s:9:"ेपा";s:1:"7";s:7:" सम";s:1:"8";s:7:"ले ";s:1:"9";s:7:" पà¥";s:2:"10";s:9:"पà¥à¤°";s:2:"11";s:9:"कार";s:2:"12";s:7:"ा स";s:2:"13";s:9:"à¤à¤•à¥‹";s:2:"14";s:7:" भà¤";s:2:"15";s:5:" छ ";s:2:"16";s:7:" भा";s:2:"17";s:9:"à¥à¤°à¤®";s:2:"18";s:7:" गर";s:2:"19";s:9:"रà¥à¤•";s:2:"20";s:5:" र ";s:2:"21";s:9:"भार";s:2:"22";s:9:"ारत";s:2:"23";s:7:" का";s:2:"24";s:7:" वि";s:2:"25";s:9:"भà¤à¤•";s:2:"26";s:9:"ाली";s:2:"27";s:7:"ली ";s:2:"28";s:7:"ा प";s:2:"29";s:9:"ीहर";s:2:"30";s:9:"ारà¥";s:2:"31";s:7:"ो छ";s:2:"32";s:7:"ना ";s:2:"33";s:7:"रॠ";s:2:"34";s:9:"ालक";s:2:"35";s:9:"à¥à¤¯à¤¾";s:2:"36";s:7:" बा";s:2:"37";s:9:"à¤à¤•à¤¾";s:2:"38";s:7:"ने ";s:2:"39";s:9:"नà¥à¤¤";s:2:"40";s:7:"ा ब";s:2:"41";s:9:"ाको";s:2:"42";s:7:"ार ";s:2:"43";s:7:"ा भ";s:2:"44";s:9:"ाहर";s:2:"45";s:9:"à¥à¤°à¥‹";s:2:"46";s:9:"कà¥à¤·";s:2:"47";s:7:"नॠ";s:2:"48";s:9:"ारी";s:2:"49";s:7:" नि";s:2:"50";s:7:"ा न";s:2:"51";s:7:"ी स";s:2:"52";s:7:" डà¥";s:2:"53";s:9:"कà¥à¤°";s:2:"54";s:9:"जना";s:2:"55";s:7:"यो ";s:2:"56";s:7:"ा छ";s:2:"57";s:9:"ेवा";s:2:"58";s:9:"à¥à¤¤à¤¾";s:2:"59";s:7:" रा";s:2:"60";s:9:"तà¥à¤¯";s:2:"61";s:9:"नà¥à¤¦";s:2:"62";s:9:"हà¥à¤¨";s:2:"63";s:7:"ा क";s:2:"64";s:9:"ामा";s:2:"65";s:7:"ी न";s:2:"66";s:9:"à¥à¤¦à¤¾";s:2:"67";s:7:" से";s:2:"68";s:9:"छनà¥";s:2:"69";s:9:"मà¥à¤¬";s:2:"70";s:9:"रोत";s:2:"71";s:9:"सेव";s:2:"72";s:9:"सà¥à¤¤";s:2:"73";s:9:"सà¥à¤°";s:2:"74";s:9:"ेका";s:2:"75";s:7:"à¥à¤¤ ";s:2:"76";s:7:" बी";s:2:"77";s:7:" हà¥";s:2:"78";s:9:"कà¥à¤¤";s:2:"79";s:9:"तà¥à¤°";s:2:"80";s:7:"रत ";s:2:"81";s:9:"रà¥à¤¨";s:2:"82";s:9:"रà¥à¤¯";s:2:"83";s:7:"ा र";s:2:"84";s:9:"ाका";s:2:"85";s:9:"à¥à¤•à¥‹";s:2:"86";s:7:" à¤à¤•";s:2:"87";s:7:" सं";s:2:"88";s:7:" सà¥";s:2:"89";s:9:"बीब";s:2:"90";s:9:"बीस";s:2:"91";s:9:"लको";s:2:"92";s:9:"सà¥à¤¯";s:2:"93";s:9:"ीबी";s:2:"94";s:9:"ीसी";s:2:"95";s:9:"ेको";s:2:"96";s:7:"ो स";s:2:"97";s:9:"à¥à¤¯à¤•";s:2:"98";s:7:" छन";s:2:"99";s:7:" जन";s:3:"100";s:7:" बि";s:3:"101";s:7:" मà¥";s:3:"102";s:7:" सà¥";s:3:"103";s:9:"गरà¥";s:3:"104";s:9:"ताह";s:3:"105";s:9:"नà¥à¤§";s:3:"106";s:9:"बार";s:3:"107";s:9:"मनà¥";s:3:"108";s:9:"मसà¥";s:3:"109";s:9:"रà¥à¤²";s:3:"110";s:9:"लाई";s:3:"111";s:7:"ा व";s:3:"112";s:7:"ाई ";s:3:"113";s:7:"ाल ";s:3:"114";s:9:"िका";s:3:"115";s:7:" तà¥";s:3:"116";s:7:" मा";s:3:"117";s:7:" यस";s:3:"118";s:7:" रà¥";s:3:"119";s:9:"ताक";s:3:"120";s:9:"बनà¥";s:3:"121";s:7:"र ब";s:3:"122";s:7:"रण ";s:3:"123";s:9:"रà¥à¤ª";s:3:"124";s:9:"रेक";s:3:"125";s:9:"षà¥à¤Ÿ";s:3:"126";s:9:"समà¥";s:3:"127";s:7:"सी ";s:3:"128";s:9:"ाà¤à¤•";s:3:"129";s:9:"à¥à¤•à¤¾";s:3:"130";s:9:"à¥à¤•à¥";s:3:"131";s:7:" अध";s:3:"132";s:7:" अन";s:3:"133";s:7:" तथ";s:3:"134";s:7:" थि";s:3:"135";s:7:" दे";s:3:"136";s:7:" पर";s:3:"137";s:7:" बै";s:3:"138";s:9:"तथा";s:3:"139";s:7:"ता ";s:3:"140";s:7:"दा ";s:3:"141";s:9:"दà¥à¤¦";s:3:"142";s:7:"नी ";s:3:"143";s:9:"बाट";s:3:"144";s:9:"यकà¥";s:3:"145";s:7:"री ";s:3:"146";s:9:"रीह";s:3:"147";s:9:"रà¥à¤®";s:3:"148";s:9:"लका";s:3:"149";s:9:"समस";s:3:"150";s:7:"ा अ";s:3:"151";s:7:"ा à¤";s:3:"152";s:7:"ाट ";s:3:"153";s:7:"िय ";s:3:"154";s:7:"ो प";s:3:"155";s:7:"ो म";s:3:"156";s:7:"à¥à¤¨ ";s:3:"157";s:9:"à¥à¤¨à¥‡";s:3:"158";s:9:"à¥à¤·à¤¾";s:3:"159";s:7:" पा";s:3:"160";s:7:" यो";s:3:"161";s:7:" हा";s:3:"162";s:9:"अधि";s:3:"163";s:9:"डà¥à¤µ";s:3:"164";s:7:"त भ";s:3:"165";s:7:"त स";s:3:"166";s:7:"था ";s:3:"167";s:9:"धिक";s:3:"168";s:9:"पमा";s:3:"169";s:9:"बैठ";s:3:"170";s:9:"मà¥à¤¦";s:3:"171";s:7:"या ";s:3:"172";s:9:"यà¥à¤•";s:3:"173";s:7:"र न";s:3:"174";s:9:"रति";s:3:"175";s:9:"वान";s:3:"176";s:9:"सार";s:3:"177";s:7:"ा आ";s:3:"178";s:7:"ा ज";s:3:"179";s:7:"ा ह";s:3:"180";s:9:"à¥à¤¦à¥";s:3:"181";s:9:"à¥à¤ªà¤®";s:3:"182";s:9:"à¥à¤²à¥‡";s:3:"183";s:9:"à¥à¤µà¤¾";s:3:"184";s:9:"ैठक";s:3:"185";s:7:"ो ब";s:3:"186";s:9:"à¥à¤¤à¤°";s:3:"187";s:7:"à¥à¤¯ ";s:3:"188";s:9:"à¥à¤¯à¤¸";s:3:"189";s:7:" कà¥";s:3:"190";s:7:" मन";s:3:"191";s:7:" रह";s:3:"192";s:9:"चार";s:3:"193";s:9:"तिय";s:3:"194";s:7:"दै ";s:3:"195";s:9:"निर";s:3:"196";s:7:"नॠ";s:3:"197";s:9:"परà¥";s:3:"198";s:9:"रकà¥";s:3:"199";s:9:"रà¥à¤¦";s:3:"200";s:9:"समा";s:3:"201";s:9:"सà¥à¤°";s:3:"202";s:9:"ाउन";s:3:"203";s:7:"ान ";s:3:"204";s:9:"ानम";s:3:"205";s:9:"ारण";s:3:"206";s:9:"ाले";s:3:"207";s:7:"ि ब";s:3:"208";s:9:"ियो";s:3:"209";s:9:"à¥à¤¨à¥";s:3:"210";s:9:"à¥à¤°à¤•";s:3:"211";s:9:"à¥à¤¤à¥";s:3:"212";s:9:"à¥à¤¬à¤¨";s:3:"213";s:9:"à¥à¤°à¤¾";s:3:"214";s:7:"à¥à¤· ";s:3:"215";s:7:" आर";s:3:"216";s:7:" जल";s:3:"217";s:7:" बे";s:3:"218";s:7:" या";s:3:"219";s:7:" सा";s:3:"220";s:9:"आà¤à¤•";s:3:"221";s:7:"à¤à¤• ";s:3:"222";s:9:"करà¥";s:3:"223";s:9:"जलस";s:3:"224";s:9:"णका";s:3:"225";s:7:"त र";s:3:"226";s:9:"दà¥à¤°";s:3:"227";s:9:"धान";s:3:"228";s:7:"धि ";s:3:"229";s:9:"नका";s:3:"230";s:9:"नमा";s:3:"231";s:7:"नि ";s:3:"232";s:9:"ममा";s:3:"233";s:7:"रम ";s:3:"234";s:9:"रहे";s:3:"235";s:9:"राज";s:3:"236";s:9:"लसà¥";s:3:"237";s:7:"ला ";s:3:"238";s:9:"वार";s:3:"239";s:9:"सका";s:3:"240";s:9:"हिल";s:3:"241";s:9:"हेक";s:3:"242";s:7:"ा त";s:3:"243";s:9:"ारे";s:3:"244";s:9:"िनà¥";s:3:"245";s:9:"िसà¥";s:3:"246";s:7:"े स";s:3:"247";s:7:"ो न";s:3:"248";s:7:"ो र";s:3:"249";s:7:"ोत ";s:3:"250";s:9:"à¥à¤§à¤¿";s:3:"251";s:9:"à¥à¤®à¥€";s:3:"252";s:9:"à¥à¤°à¤¸";s:3:"253";s:7:" दà¥";s:3:"254";s:7:" पन";s:3:"255";s:7:" बत";s:3:"256";s:7:" बन";s:3:"257";s:7:" भन";s:3:"258";s:9:"ंयà¥";s:3:"259";s:9:"आरम";s:3:"260";s:7:"खि ";s:3:"261";s:9:"णà¥à¤¡";s:3:"262";s:9:"तका";s:3:"263";s:9:"ताल";s:3:"264";s:7:"दी ";s:3:"265";s:9:"देख";s:3:"266";s:9:"निय";s:3:"267";s:9:"पनि";s:3:"268";s:9:"पà¥à¤¤";s:3:"269";s:9:"बता";s:3:"270";s:7:"मी ";s:3:"271";s:9:"मà¥à¤­";s:3:"272";s:7:"र स";s:3:"273";s:9:"रमà¥";s:3:"274";s:9:"लमा";s:3:"275";s:9:"विश";s:3:"276";s:9:"षाक";s:3:"277";s:9:"संय";s:3:"278";s:7:"ा ड";s:3:"279";s:7:"ा म";s:3:"280";s:9:"ानक";s:3:"281";s:9:"ालम";s:3:"282";s:7:"ि भ";s:3:"283";s:7:"ित ";s:3:"284";s:7:"ी प";s:3:"285";s:7:"ी र";s:3:"286";s:7:"ॠभ";s:3:"287";s:9:"à¥à¤¨à¥‡";s:3:"288";s:7:"े ग";s:3:"289";s:9:"ेखि";s:3:"290";s:7:"ेर ";s:3:"291";s:7:"ो भ";s:3:"292";s:7:"ो व";s:3:"293";s:7:"ो ह";s:3:"294";s:7:"à¥à¤­ ";s:3:"295";s:7:"à¥à¤° ";s:3:"296";s:7:" ता";s:3:"297";s:7:" नम";s:3:"298";s:7:" ना";s:3:"299";}s:9:"norwegian";a:300:{s:3:"er ";s:1:"0";s:3:"en ";s:1:"1";s:3:"et ";s:1:"2";s:3:" de";s:1:"3";s:3:"det";s:1:"4";s:3:" i ";s:1:"5";s:3:"for";s:1:"6";s:3:"il ";s:1:"7";s:3:" fo";s:1:"8";s:3:" me";s:1:"9";s:3:"ing";s:2:"10";s:3:"om ";s:2:"11";s:3:" ha";s:2:"12";s:3:" og";s:2:"13";s:3:"ter";s:2:"14";s:3:" er";s:2:"15";s:3:" ti";s:2:"16";s:3:" st";s:2:"17";s:3:"og ";s:2:"18";s:3:"til";s:2:"19";s:3:"ne ";s:2:"20";s:3:" vi";s:2:"21";s:3:"re ";s:2:"22";s:3:" en";s:2:"23";s:3:" se";s:2:"24";s:3:"te ";s:2:"25";s:3:"or ";s:2:"26";s:3:"de ";s:2:"27";s:3:"kke";s:2:"28";s:3:"ke ";s:2:"29";s:3:"ar ";s:2:"30";s:3:"ng ";s:2:"31";s:3:"r s";s:2:"32";s:3:"ene";s:2:"33";s:3:" so";s:2:"34";s:3:"e s";s:2:"35";s:3:"der";s:2:"36";s:3:"an ";s:2:"37";s:3:"som";s:2:"38";s:3:"ste";s:2:"39";s:3:"at ";s:2:"40";s:3:"ed ";s:2:"41";s:3:"r i";s:2:"42";s:3:" av";s:2:"43";s:3:" in";s:2:"44";s:3:"men";s:2:"45";s:3:" at";s:2:"46";s:3:" ko";s:2:"47";s:4:" pÃ¥";s:2:"48";s:3:"har";s:2:"49";s:3:" si";s:2:"50";s:3:"ere";s:2:"51";s:4:"pÃ¥ ";s:2:"52";s:3:"nde";s:2:"53";s:3:"and";s:2:"54";s:3:"els";s:2:"55";s:3:"ett";s:2:"56";s:3:"tte";s:2:"57";s:3:"lig";s:2:"58";s:3:"t s";s:2:"59";s:3:"den";s:2:"60";s:3:"t i";s:2:"61";s:3:"ikk";s:2:"62";s:3:"med";s:2:"63";s:3:"n s";s:2:"64";s:3:"rt ";s:2:"65";s:3:"ser";s:2:"66";s:3:"ska";s:2:"67";s:3:"t e";s:2:"68";s:3:"ker";s:2:"69";s:3:"sen";s:2:"70";s:3:"av ";s:2:"71";s:3:"ler";s:2:"72";s:3:"r a";s:2:"73";s:3:"ten";s:2:"74";s:3:"e f";s:2:"75";s:3:"r e";s:2:"76";s:3:"r t";s:2:"77";s:3:"ede";s:2:"78";s:3:"ig ";s:2:"79";s:3:" re";s:2:"80";s:3:"han";s:2:"81";s:3:"lle";s:2:"82";s:3:"ner";s:2:"83";s:3:" bl";s:2:"84";s:3:" fr";s:2:"85";s:3:"le ";s:2:"86";s:3:" ve";s:2:"87";s:3:"e t";s:2:"88";s:3:"lan";s:2:"89";s:3:"mme";s:2:"90";s:3:"nge";s:2:"91";s:3:" be";s:2:"92";s:3:" ik";s:2:"93";s:3:" om";s:2:"94";s:4:" Ã¥ ";s:2:"95";s:3:"ell";s:2:"96";s:3:"sel";s:2:"97";s:3:"sta";s:2:"98";s:3:"ver";s:2:"99";s:3:" et";s:3:"100";s:3:" sk";s:3:"101";s:3:"nte";s:3:"102";s:3:"one";s:3:"103";s:3:"ore";s:3:"104";s:3:"r d";s:3:"105";s:3:"ske";s:3:"106";s:3:" an";s:3:"107";s:3:" la";s:3:"108";s:3:"del";s:3:"109";s:3:"gen";s:3:"110";s:3:"nin";s:3:"111";s:3:"r f";s:3:"112";s:3:"r v";s:3:"113";s:3:"se ";s:3:"114";s:3:" po";s:3:"115";s:3:"ir ";s:3:"116";s:3:"jon";s:3:"117";s:3:"mer";s:3:"118";s:3:"nen";s:3:"119";s:3:"omm";s:3:"120";s:3:"sjo";s:3:"121";s:3:" fl";s:3:"122";s:3:" sa";s:3:"123";s:3:"ern";s:3:"124";s:3:"kom";s:3:"125";s:3:"r m";s:3:"126";s:3:"r o";s:3:"127";s:3:"ren";s:3:"128";s:3:"vil";s:3:"129";s:3:"ale";s:3:"130";s:3:"es ";s:3:"131";s:3:"n a";s:3:"132";s:3:"t f";s:3:"133";s:3:" le";s:3:"134";s:3:"bli";s:3:"135";s:3:"e e";s:3:"136";s:3:"e i";s:3:"137";s:3:"e v";s:3:"138";s:3:"het";s:3:"139";s:3:"ye ";s:3:"140";s:3:" ir";s:3:"141";s:3:"al ";s:3:"142";s:3:"e o";s:3:"143";s:3:"ide";s:3:"144";s:3:"iti";s:3:"145";s:3:"lit";s:3:"146";s:3:"nne";s:3:"147";s:3:"ran";s:3:"148";s:3:"t o";s:3:"149";s:3:"tal";s:3:"150";s:3:"tat";s:3:"151";s:3:"tt ";s:3:"152";s:3:" ka";s:3:"153";s:3:"ans";s:3:"154";s:3:"asj";s:3:"155";s:3:"ge ";s:3:"156";s:3:"inn";s:3:"157";s:3:"kon";s:3:"158";s:3:"lse";s:3:"159";s:3:"pet";s:3:"160";s:3:"t d";s:3:"161";s:3:"vi ";s:3:"162";s:3:" ut";s:3:"163";s:3:"ent";s:3:"164";s:3:"eri";s:3:"165";s:3:"oli";s:3:"166";s:3:"r p";s:3:"167";s:3:"ret";s:3:"168";s:3:"ris";s:3:"169";s:3:"sto";s:3:"170";s:3:"str";s:3:"171";s:3:"t a";s:3:"172";s:3:" ga";s:3:"173";s:3:"all";s:3:"174";s:3:"ape";s:3:"175";s:3:"g s";s:3:"176";s:3:"ill";s:3:"177";s:3:"ira";s:3:"178";s:3:"kap";s:3:"179";s:3:"nn ";s:3:"180";s:3:"opp";s:3:"181";s:3:"r h";s:3:"182";s:3:"rin";s:3:"183";s:3:" br";s:3:"184";s:3:" op";s:3:"185";s:3:"e m";s:3:"186";s:3:"ert";s:3:"187";s:3:"ger";s:3:"188";s:3:"ion";s:3:"189";s:3:"kal";s:3:"190";s:3:"lsk";s:3:"191";s:3:"nes";s:3:"192";s:3:" gj";s:3:"193";s:3:" mi";s:3:"194";s:3:" pr";s:3:"195";s:3:"ang";s:3:"196";s:3:"e h";s:3:"197";s:3:"e r";s:3:"198";s:3:"elt";s:3:"199";s:3:"enn";s:3:"200";s:3:"i s";s:3:"201";s:3:"ist";s:3:"202";s:3:"jen";s:3:"203";s:3:"kan";s:3:"204";s:3:"lt ";s:3:"205";s:3:"nal";s:3:"206";s:3:"res";s:3:"207";s:3:"tor";s:3:"208";s:3:"ass";s:3:"209";s:3:"dre";s:3:"210";s:3:"e b";s:3:"211";s:3:"e p";s:3:"212";s:3:"mel";s:3:"213";s:3:"n t";s:3:"214";s:3:"nse";s:3:"215";s:3:"ort";s:3:"216";s:3:"per";s:3:"217";s:3:"reg";s:3:"218";s:3:"sje";s:3:"219";s:3:"t p";s:3:"220";s:3:"t v";s:3:"221";s:3:" hv";s:3:"222";s:4:" nÃ¥";s:3:"223";s:3:" va";s:3:"224";s:3:"ann";s:3:"225";s:3:"ato";s:3:"226";s:3:"e a";s:3:"227";s:3:"est";s:3:"228";s:3:"ise";s:3:"229";s:3:"isk";s:3:"230";s:3:"oil";s:3:"231";s:3:"ord";s:3:"232";s:3:"pol";s:3:"233";s:3:"ra ";s:3:"234";s:3:"rak";s:3:"235";s:3:"sse";s:3:"236";s:3:"toi";s:3:"237";s:3:" gr";s:3:"238";s:3:"ak ";s:3:"239";s:3:"eg ";s:3:"240";s:3:"ele";s:3:"241";s:3:"g a";s:3:"242";s:3:"ige";s:3:"243";s:3:"igh";s:3:"244";s:3:"m e";s:3:"245";s:3:"n f";s:3:"246";s:3:"n v";s:3:"247";s:3:"ndr";s:3:"248";s:3:"nsk";s:3:"249";s:3:"rer";s:3:"250";s:3:"t m";s:3:"251";s:3:"und";s:3:"252";s:3:"var";s:3:"253";s:4:"Ã¥r ";s:3:"254";s:3:" he";s:3:"255";s:3:" no";s:3:"256";s:3:" ny";s:3:"257";s:3:"end";s:3:"258";s:3:"ete";s:3:"259";s:3:"fly";s:3:"260";s:3:"g i";s:3:"261";s:3:"ghe";s:3:"262";s:3:"ier";s:3:"263";s:3:"ind";s:3:"264";s:3:"int";s:3:"265";s:3:"lin";s:3:"266";s:3:"n d";s:3:"267";s:3:"n p";s:3:"268";s:3:"rne";s:3:"269";s:3:"sak";s:3:"270";s:3:"sie";s:3:"271";s:3:"t b";s:3:"272";s:3:"tid";s:3:"273";s:3:" al";s:3:"274";s:3:" pa";s:3:"275";s:3:" tr";s:3:"276";s:3:"ag ";s:3:"277";s:3:"dig";s:3:"278";s:3:"e d";s:3:"279";s:3:"e k";s:3:"280";s:3:"ess";s:3:"281";s:3:"hol";s:3:"282";s:3:"i d";s:3:"283";s:3:"lag";s:3:"284";s:3:"led";s:3:"285";s:3:"n e";s:3:"286";s:3:"n i";s:3:"287";s:3:"n o";s:3:"288";s:3:"pri";s:3:"289";s:3:"r b";s:3:"290";s:3:"st ";s:3:"291";s:3:" fe";s:3:"292";s:3:" li";s:3:"293";s:3:" ry";s:3:"294";s:3:"air";s:3:"295";s:3:"ake";s:3:"296";s:3:"d s";s:3:"297";s:3:"eas";s:3:"298";s:3:"egi";s:3:"299";}s:6:"pashto";a:300:{s:4:" د ";s:1:"0";s:5:"اؤ ";s:1:"1";s:5:" اؤ";s:1:"2";s:5:"نو ";s:1:"3";s:5:"Û Ø¯";s:1:"4";s:5:"ره ";s:1:"5";s:5:" په";s:1:"6";s:5:"نه ";s:1:"7";s:5:"Ú†Û ";s:1:"8";s:5:" Ú†Û";s:1:"9";s:5:"په ";s:2:"10";s:5:"Ù‡ د";s:2:"11";s:5:"ته ";s:2:"12";s:5:"Ùˆ ا";s:2:"13";s:6:"ونو";s:2:"14";s:5:"Ùˆ د";s:2:"15";s:5:" او";s:2:"16";s:6:"انو";s:2:"17";s:6:"ونه";s:2:"18";s:5:"Ù‡ Ú©";s:2:"19";s:5:" دا";s:2:"20";s:5:"Ù‡ ا";s:2:"21";s:5:"Ø¯Û ";s:2:"22";s:5:"ÚšÛ ";s:2:"23";s:5:" Ú©Û";s:2:"24";s:5:"ان ";s:2:"25";s:5:"لو ";s:2:"26";s:5:"هم ";s:2:"27";s:5:"Ùˆ Ù…";s:2:"28";s:6:"Ú©ÚšÛ";s:2:"29";s:5:"Ù‡ Ù…";s:2:"30";s:5:"Ù‰ ا";s:2:"31";s:5:" نو";s:2:"32";s:5:" ته";s:2:"33";s:5:" Ú©Úš";s:2:"34";s:6:"رون";s:2:"35";s:5:"Ú©Û ";s:2:"36";s:5:"ده ";s:2:"37";s:5:"له ";s:2:"38";s:5:"به ";s:2:"39";s:5:"رو ";s:2:"40";s:5:" هم";s:2:"41";s:5:"Ù‡ Ùˆ";s:2:"42";s:5:"وى ";s:2:"43";s:5:"او ";s:2:"44";s:6:"تون";s:2:"45";s:5:"دا ";s:2:"46";s:5:" Ú©Ùˆ";s:2:"47";s:5:" Ú©Ú“";s:2:"48";s:6:"قام";s:2:"49";s:5:" تر";s:2:"50";s:6:"ران";s:2:"51";s:5:"Ù‡ Ù¾";s:2:"52";s:5:"Û Ùˆ";s:2:"53";s:5:"Û Ù¾";s:2:"54";s:5:" به";s:2:"55";s:5:" خو";s:2:"56";s:5:"تو ";s:2:"57";s:5:"د د";s:2:"58";s:5:"د ا";s:2:"59";s:5:"Ù‡ ت";s:2:"60";s:5:"Ùˆ Ù¾";s:2:"61";s:5:"يا ";s:2:"62";s:5:" خپ";s:2:"63";s:5:" دو";s:2:"64";s:5:" را";s:2:"65";s:5:" مش";s:2:"66";s:5:" پر";s:2:"67";s:6:"ارو";s:2:"68";s:5:"Ø±Û ";s:2:"69";s:5:"Ù… د";s:2:"70";s:6:"مشر";s:2:"71";s:5:" شو";s:2:"72";s:5:" ور";s:2:"73";s:5:"ار ";s:2:"74";s:5:"دى ";s:2:"75";s:5:" اد";s:2:"76";s:5:" دى";s:2:"77";s:5:" مو";s:2:"78";s:5:"د Ù¾";s:2:"79";s:5:"لي ";s:2:"80";s:5:"Ùˆ Ú©";s:2:"81";s:5:" مق";s:2:"82";s:5:" يو";s:2:"83";s:5:"ؤ د";s:2:"84";s:6:"خپل";s:2:"85";s:6:"سره";s:2:"86";s:5:"Ù‡ Ú†";s:2:"87";s:5:"ور ";s:2:"88";s:5:" تا";s:2:"89";s:5:" دÛ";s:2:"90";s:5:" رو";s:2:"91";s:5:" سر";s:2:"92";s:5:" مل";s:2:"93";s:5:" کا";s:2:"94";s:5:"ؤ ا";s:2:"95";s:6:"اره";s:2:"96";s:6:"برو";s:2:"97";s:5:"مه ";s:2:"98";s:5:"Ù‡ ب";s:2:"99";s:5:"Ùˆ ت";s:3:"100";s:6:"پښت";s:3:"101";s:5:" با";s:3:"102";s:5:" دغ";s:3:"103";s:5:" قب";s:3:"104";s:5:" له";s:3:"105";s:5:" وا";s:3:"106";s:5:" پا";s:3:"107";s:5:" Ù¾Úš";s:3:"108";s:5:"د Ù…";s:3:"109";s:5:"د Ù‡";s:3:"110";s:5:"Ù„Û ";s:3:"111";s:6:"مات";s:3:"112";s:5:"مو ";s:3:"113";s:5:"Ù‡ Ù‡";s:3:"114";s:5:"وي ";s:3:"115";s:5:"Û Ø¨";s:3:"116";s:5:"Û Ú©";s:3:"117";s:5:" ده";s:3:"118";s:5:" قا";s:3:"119";s:5:"ال ";s:3:"120";s:6:"اما";s:3:"121";s:5:"د Ù†";s:3:"122";s:6:"قبر";s:3:"123";s:5:"Ù‡ Ù†";s:3:"124";s:6:"پار";s:3:"125";s:5:" اث";s:3:"126";s:5:" بي";s:3:"127";s:5:" لا";s:3:"128";s:5:" لر";s:3:"129";s:6:"اثا";s:3:"130";s:5:"د Ø®";s:3:"131";s:6:"دار";s:3:"132";s:6:"ريخ";s:3:"133";s:6:"شرا";s:3:"134";s:6:"مقا";s:3:"135";s:5:"Ù†Û ";s:3:"136";s:5:"Ù‡ ر";s:3:"137";s:5:"Ù‡ Ù„";s:3:"138";s:6:"ولو";s:3:"139";s:5:"يو ";s:3:"140";s:6:"کوم";s:3:"141";s:5:" دد";s:3:"142";s:5:" لو";s:3:"143";s:5:" مح";s:3:"144";s:5:" مر";s:3:"145";s:5:" وو";s:3:"146";s:6:"اتو";s:3:"147";s:6:"اري";s:3:"148";s:6:"الو";s:3:"149";s:6:"اند";s:3:"150";s:6:"خان";s:3:"151";s:5:"د ت";s:3:"152";s:5:"Ø³Û ";s:3:"153";s:5:"لى ";s:3:"154";s:6:"نور";s:3:"155";s:5:"Ùˆ Ù„";s:3:"156";s:5:"ÙŠ Ú†";s:3:"157";s:5:"Ú“ÙŠ ";s:3:"158";s:6:"ښتو";s:3:"159";s:5:"Û Ù„";s:3:"160";s:5:" جو";s:3:"161";s:5:" سي";s:3:"162";s:5:"ام ";s:3:"163";s:6:"بان";s:3:"164";s:6:"تار";s:3:"165";s:5:"تر ";s:3:"166";s:6:"ثار";s:3:"167";s:5:"خو ";s:3:"168";s:5:"دو ";s:3:"169";s:5:"ر Ú©";s:3:"170";s:5:"Ù„ د";s:3:"171";s:6:"مون";s:3:"172";s:6:"ندÛ";s:3:"173";s:5:"Ùˆ Ù†";s:3:"174";s:5:"ول ";s:3:"175";s:5:"وه ";s:3:"176";s:5:"Ù‰ Ùˆ";s:3:"177";s:5:"ÙŠ د";s:3:"178";s:5:"Û Ø§";s:3:"179";s:5:"Û Øª";s:3:"180";s:5:"Û ÙŠ";s:3:"181";s:5:" Ø­Ú©";s:3:"182";s:5:" خب";s:3:"183";s:5:" نه";s:3:"184";s:5:" پو";s:3:"185";s:5:"ا د";s:3:"186";s:5:"ØªÛ ";s:3:"187";s:6:"جوړ";s:3:"188";s:6:"Ø­Ú©Ù…";s:3:"189";s:6:"Ø­Ú©Ùˆ";s:3:"190";s:6:"خبر";s:3:"191";s:6:"دان";s:3:"192";s:5:"ر د";s:3:"193";s:5:"غه ";s:3:"194";s:6:"قاÙ";s:3:"195";s:6:"محک";s:3:"196";s:6:"وال";s:3:"197";s:6:"ومت";s:3:"198";s:6:"ويل";s:3:"199";s:5:"Ù‰ د";s:3:"200";s:5:"Ù‰ Ù…";s:3:"201";s:6:"يره";s:3:"202";s:5:"پر ";s:3:"203";s:6:"کول";s:3:"204";s:5:"Û Ù‡";s:3:"205";s:5:" تي";s:3:"206";s:5:" خا";s:3:"207";s:5:" ÙˆÚ©";s:3:"208";s:5:" يا";s:3:"209";s:5:" Úا";s:3:"210";s:5:"ؤ Ù‚";s:3:"211";s:6:"انÛ";s:3:"212";s:5:"بى ";s:3:"213";s:5:"غو ";s:3:"214";s:5:"Ù‡ Ø®";s:3:"215";s:5:"Ùˆ ب";s:3:"216";s:6:"ودا";s:3:"217";s:6:"يدو";s:3:"218";s:5:"Ú“Û ";s:3:"219";s:6:"کال";s:3:"220";s:5:" بر";s:3:"221";s:5:" قد";s:3:"222";s:5:" مي";s:3:"223";s:5:" وي";s:3:"224";s:5:" کر";s:3:"225";s:5:"ؤ Ù…";s:3:"226";s:5:"ات ";s:3:"227";s:6:"ايي";s:3:"228";s:5:"تى ";s:3:"229";s:6:"تيا";s:3:"230";s:6:"تير";s:3:"231";s:6:"خوا";s:3:"232";s:6:"دغو";s:3:"233";s:5:"دم ";s:3:"234";s:6:"ديم";s:3:"235";s:5:"ر Ùˆ";s:3:"236";s:6:"قدي";s:3:"237";s:5:"Ù… Ø®";s:3:"238";s:6:"مان";s:3:"239";s:5:"Ù…Û ";s:3:"240";s:6:"نيو";s:3:"241";s:5:"Ù†Ú– ";s:3:"242";s:5:"Ù‡ ÙŠ";s:3:"243";s:5:"Ùˆ س";s:3:"244";s:5:"Ùˆ Ú†";s:3:"245";s:6:"وان";s:3:"246";s:6:"ورو";s:3:"247";s:6:"ونږ";s:3:"248";s:6:"پور";s:3:"249";s:5:"Ú“Ù‡ ";s:3:"250";s:5:"Ú“Ùˆ ";s:3:"251";s:5:"Û Ø¯";s:3:"252";s:5:"Û Ù†";s:3:"253";s:5:" اه";s:3:"254";s:5:" زي";s:3:"255";s:5:" سو";s:3:"256";s:5:" شي";s:3:"257";s:5:" هر";s:3:"258";s:5:" هغ";s:3:"259";s:5:" ښا";s:3:"260";s:6:"اتل";s:3:"261";s:5:"اق ";s:3:"262";s:6:"اني";s:3:"263";s:6:"بري";s:3:"264";s:5:"Ø¨Û ";s:3:"265";s:5:"ت ا";s:3:"266";s:5:"د ب";s:3:"267";s:5:"د س";s:3:"268";s:5:"ر Ù…";s:3:"269";s:5:"رى ";s:3:"270";s:6:"عرا";s:3:"271";s:6:"لان";s:3:"272";s:5:"مى ";s:3:"273";s:5:"نى ";s:3:"274";s:5:"Ùˆ Ø®";s:3:"275";s:5:"وئ ";s:3:"276";s:6:"ورک";s:3:"277";s:6:"ورÛ";s:3:"278";s:5:"ون ";s:3:"279";s:6:"ÙˆÚ©Ú“";s:3:"280";s:5:"Ù‰ Ú†";s:3:"281";s:6:"يمه";s:3:"282";s:5:"ÙŠÛ ";s:3:"283";s:6:"ښتن";s:3:"284";s:5:"Ú©Ù‡ ";s:3:"285";s:6:"Ú©Ú“ÙŠ";s:3:"286";s:5:"Û Ø®";s:3:"287";s:5:"Û’ Ø´";s:3:"288";s:5:" تح";s:3:"289";s:5:" تو";s:3:"290";s:5:" در";s:3:"291";s:5:" دپ";s:3:"292";s:5:" صو";s:3:"293";s:5:" عر";s:3:"294";s:5:" ول";s:3:"295";s:5:" يؤ";s:3:"296";s:5:" Ù¾Û€";s:3:"297";s:5:" Ú…Ùˆ";s:3:"298";s:5:"ا ا";s:3:"299";}s:6:"pidgin";a:300:{s:3:" de";s:1:"0";s:3:" we";s:1:"1";s:3:" di";s:1:"2";s:3:"di ";s:1:"3";s:3:"dem";s:1:"4";s:3:"em ";s:1:"5";s:3:"ay ";s:1:"6";s:3:" sa";s:1:"7";s:3:"or ";s:1:"8";s:3:"say";s:1:"9";s:3:"ke ";s:2:"10";s:3:"ey ";s:2:"11";s:3:" an";s:2:"12";s:3:" go";s:2:"13";s:3:" e ";s:2:"14";s:3:" to";s:2:"15";s:3:" ma";s:2:"16";s:3:"e d";s:2:"17";s:3:"wey";s:2:"18";s:3:"for";s:2:"19";s:3:"nd ";s:2:"20";s:3:"to ";s:2:"21";s:3:" be";s:2:"22";s:3:" fo";s:2:"23";s:3:"ake";s:2:"24";s:3:"im ";s:2:"25";s:3:" pe";s:2:"26";s:3:"le ";s:2:"27";s:3:"go ";s:2:"28";s:3:"ll ";s:2:"29";s:3:"de ";s:2:"30";s:3:"e s";s:2:"31";s:3:"on ";s:2:"32";s:3:"get";s:2:"33";s:3:"ght";s:2:"34";s:3:"igh";s:2:"35";s:3:" ri";s:2:"36";s:3:"et ";s:2:"37";s:3:"rig";s:2:"38";s:3:" ge";s:2:"39";s:3:"y d";s:2:"40";s:3:" na";s:2:"41";s:3:"mak";s:2:"42";s:3:"t t";s:2:"43";s:3:" no";s:2:"44";s:3:"and";s:2:"45";s:3:"tin";s:2:"46";s:3:"ing";s:2:"47";s:3:"eve";s:2:"48";s:3:"ri ";s:2:"49";s:3:" im";s:2:"50";s:3:" am";s:2:"51";s:3:" or";s:2:"52";s:3:"am ";s:2:"53";s:3:"be ";s:2:"54";s:3:" ev";s:2:"55";s:3:" ta";s:2:"56";s:3:"ht ";s:2:"57";s:3:"e w";s:2:"58";s:3:" li";s:2:"59";s:3:"eri";s:2:"60";s:3:"ng ";s:2:"61";s:3:"ver";s:2:"62";s:3:"all";s:2:"63";s:3:"e f";s:2:"64";s:3:"ers";s:2:"65";s:3:"ntr";s:2:"66";s:3:"ont";s:2:"67";s:3:" do";s:2:"68";s:3:"r d";s:2:"69";s:3:" ko";s:2:"70";s:3:" ti";s:2:"71";s:3:"an ";s:2:"72";s:3:"kon";s:2:"73";s:3:"per";s:2:"74";s:3:"tri";s:2:"75";s:3:"y e";s:2:"76";s:3:"rso";s:2:"77";s:3:"son";s:2:"78";s:3:"no ";s:2:"79";s:3:"ome";s:2:"80";s:3:"is ";s:2:"81";s:3:"do ";s:2:"82";s:3:"ne ";s:2:"83";s:3:"one";s:2:"84";s:3:"ion";s:2:"85";s:3:"m g";s:2:"86";s:3:"i k";s:2:"87";s:3:" al";s:2:"88";s:3:"bod";s:2:"89";s:3:"i w";s:2:"90";s:3:"odi";s:2:"91";s:3:" so";s:2:"92";s:3:" wo";s:2:"93";s:3:"o d";s:2:"94";s:3:"st ";s:2:"95";s:3:"t r";s:2:"96";s:3:" of";s:2:"97";s:3:"aim";s:2:"98";s:3:"e g";s:2:"99";s:3:"nai";s:3:"100";s:3:" co";s:3:"101";s:3:"dis";s:3:"102";s:3:"me ";s:3:"103";s:3:"of ";s:3:"104";s:3:" wa";s:3:"105";s:3:"e t";s:3:"106";s:3:" ar";s:3:"107";s:3:"e l";s:3:"108";s:3:"ike";s:3:"109";s:3:"lik";s:3:"110";s:3:"t a";s:3:"111";s:3:"wor";s:3:"112";s:3:"alk";s:3:"113";s:3:"ell";s:3:"114";s:3:"eop";s:3:"115";s:3:"lk ";s:3:"116";s:3:"opl";s:3:"117";s:3:"peo";s:3:"118";s:3:"ple";s:3:"119";s:3:"re ";s:3:"120";s:3:"tal";s:3:"121";s:3:"any";s:3:"122";s:3:"e a";s:3:"123";s:3:"o g";s:3:"124";s:3:"art";s:3:"125";s:3:"cle";s:3:"126";s:3:"i p";s:3:"127";s:3:"icl";s:3:"128";s:3:"rti";s:3:"129";s:3:"the";s:3:"130";s:3:"tic";s:3:"131";s:3:"we ";s:3:"132";s:3:"f d";s:3:"133";s:3:"in ";s:3:"134";s:3:" mu";s:3:"135";s:3:"e n";s:3:"136";s:3:"e o";s:3:"137";s:3:"mus";s:3:"138";s:3:"n d";s:3:"139";s:3:"na ";s:3:"140";s:3:"o m";s:3:"141";s:3:"ust";s:3:"142";s:3:"wel";s:3:"143";s:3:"e e";s:3:"144";s:3:"her";s:3:"145";s:3:"m d";s:3:"146";s:3:"nt ";s:3:"147";s:3:" fi";s:3:"148";s:3:"at ";s:3:"149";s:3:"e b";s:3:"150";s:3:"it ";s:3:"151";s:3:"m w";s:3:"152";s:3:"o t";s:3:"153";s:3:"wan";s:3:"154";s:3:"com";s:3:"155";s:3:"da ";s:3:"156";s:3:"fit";s:3:"157";s:3:"m b";s:3:"158";s:3:"so ";s:3:"159";s:3:" fr";s:3:"160";s:3:"ce ";s:3:"161";s:3:"er ";s:3:"162";s:3:"o a";s:3:"163";s:3:" if";s:3:"164";s:3:" on";s:3:"165";s:3:"ent";s:3:"166";s:3:"if ";s:3:"167";s:3:"ind";s:3:"168";s:3:"kin";s:3:"169";s:3:"l d";s:3:"170";s:3:"man";s:3:"171";s:3:"o s";s:3:"172";s:3:" se";s:3:"173";s:3:"y a";s:3:"174";s:3:"y m";s:3:"175";s:3:" re";s:3:"176";s:3:"ee ";s:3:"177";s:3:"k a";s:3:"178";s:3:"t s";s:3:"179";s:3:"ve ";s:3:"180";s:3:"y w";s:3:"181";s:3:" ki";s:3:"182";s:3:"eti";s:3:"183";s:3:"men";s:3:"184";s:3:"ta ";s:3:"185";s:3:"y n";s:3:"186";s:3:"d t";s:3:"187";s:3:"dey";s:3:"188";s:3:"e c";s:3:"189";s:3:"i o";s:3:"190";s:3:"ibo";s:3:"191";s:3:"ld ";s:3:"192";s:3:"m t";s:3:"193";s:3:"n b";s:3:"194";s:3:"o b";s:3:"195";s:3:"ow ";s:3:"196";s:3:"ree";s:3:"197";s:3:"rio";s:3:"198";s:3:"t d";s:3:"199";s:3:" hu";s:3:"200";s:3:" su";s:3:"201";s:3:"en ";s:3:"202";s:3:"hts";s:3:"203";s:3:"ive";s:3:"204";s:3:"m n";s:3:"205";s:3:"n g";s:3:"206";s:3:"ny ";s:3:"207";s:3:"oth";s:3:"208";s:3:"ts ";s:3:"209";s:3:" as";s:3:"210";s:3:" wh";s:3:"211";s:3:"as ";s:3:"212";s:3:"gom";s:3:"213";s:3:"hum";s:3:"214";s:3:"k s";s:3:"215";s:3:"oda";s:3:"216";s:3:"ork";s:3:"217";s:3:"se ";s:3:"218";s:3:"uma";s:3:"219";s:3:"ut ";s:3:"220";s:3:" ba";s:3:"221";s:3:" ot";s:3:"222";s:3:"ano";s:3:"223";s:3:"m a";s:3:"224";s:3:"m s";s:3:"225";s:3:"nod";s:3:"226";s:3:"om ";s:3:"227";s:3:"r a";s:3:"228";s:3:"r i";s:3:"229";s:3:"rk ";s:3:"230";s:3:" fa";s:3:"231";s:3:" si";s:3:"232";s:3:" th";s:3:"233";s:3:"ad ";s:3:"234";s:3:"e m";s:3:"235";s:3:"eac";s:3:"236";s:3:"m m";s:3:"237";s:3:"n w";s:3:"238";s:3:"nob";s:3:"239";s:3:"orl";s:3:"240";s:3:"out";s:3:"241";s:3:"own";s:3:"242";s:3:"r s";s:3:"243";s:3:"r w";s:3:"244";s:3:"rib";s:3:"245";s:3:"rld";s:3:"246";s:3:"s w";s:3:"247";s:3:"ure";s:3:"248";s:3:"wn ";s:3:"249";s:3:" ow";s:3:"250";s:3:"a d";s:3:"251";s:3:"bad";s:3:"252";s:3:"ch ";s:3:"253";s:3:"fre";s:3:"254";s:3:"gs ";s:3:"255";s:3:"m k";s:3:"256";s:3:"nce";s:3:"257";s:3:"ngs";s:3:"258";s:3:"o f";s:3:"259";s:3:"obo";s:3:"260";s:3:"rea";s:3:"261";s:3:"sur";s:3:"262";s:3:"y o";s:3:"263";s:3:" ab";s:3:"264";s:3:" un";s:3:"265";s:3:"abo";s:3:"266";s:3:"ach";s:3:"267";s:3:"bou";s:3:"268";s:3:"d m";s:3:"269";s:3:"dat";s:3:"270";s:3:"e p";s:3:"271";s:3:"g w";s:3:"272";s:3:"hol";s:3:"273";s:3:"i m";s:3:"274";s:3:"i r";s:3:"275";s:3:"m f";s:3:"276";s:3:"m o";s:3:"277";s:3:"n o";s:3:"278";s:3:"now";s:3:"279";s:3:"ry ";s:3:"280";s:3:"s a";s:3:"281";s:3:"t o";s:3:"282";s:3:"tay";s:3:"283";s:3:"wet";s:3:"284";s:3:" ag";s:3:"285";s:3:" bo";s:3:"286";s:3:" da";s:3:"287";s:3:" pr";s:3:"288";s:3:"arr";s:3:"289";s:3:"ati";s:3:"290";s:3:"d d";s:3:"291";s:3:"d p";s:3:"292";s:3:"i g";s:3:"293";s:3:"i t";s:3:"294";s:3:"liv";s:3:"295";s:3:"ly ";s:3:"296";s:3:"n a";s:3:"297";s:3:"od ";s:3:"298";s:3:"ok ";s:3:"299";}s:6:"polish";a:300:{s:3:"ie ";s:1:"0";s:3:"nie";s:1:"1";s:3:"em ";s:1:"2";s:3:" ni";s:1:"3";s:3:" po";s:1:"4";s:3:" pr";s:1:"5";s:3:"dzi";s:1:"6";s:3:" na";s:1:"7";s:4:"że ";s:1:"8";s:3:"rze";s:1:"9";s:3:"na ";s:2:"10";s:4:"Å‚em";s:2:"11";s:3:"wie";s:2:"12";s:3:" w ";s:2:"13";s:4:" że";s:2:"14";s:3:"go ";s:2:"15";s:3:" by";s:2:"16";s:3:"prz";s:2:"17";s:3:"owa";s:2:"18";s:4:"iÄ™ ";s:2:"19";s:3:" do";s:2:"20";s:3:" si";s:2:"21";s:3:"owi";s:2:"22";s:3:" pa";s:2:"23";s:3:" za";s:2:"24";s:3:"ch ";s:2:"25";s:3:"ego";s:2:"26";s:4:"aÅ‚ ";s:2:"27";s:4:"siÄ™";s:2:"28";s:3:"ej ";s:2:"29";s:4:"waÅ‚";s:2:"30";s:3:"ym ";s:2:"31";s:3:"ani";s:2:"32";s:4:"aÅ‚e";s:2:"33";s:3:"to ";s:2:"34";s:3:" i ";s:2:"35";s:3:" to";s:2:"36";s:3:" te";s:2:"37";s:3:"e p";s:2:"38";s:3:" je";s:2:"39";s:3:" z ";s:2:"40";s:3:"czy";s:2:"41";s:4:"byÅ‚";s:2:"42";s:3:"pan";s:2:"43";s:3:"sta";s:2:"44";s:3:"kie";s:2:"45";s:3:" ja";s:2:"46";s:3:"do ";s:2:"47";s:3:" ch";s:2:"48";s:3:" cz";s:2:"49";s:3:" wi";s:2:"50";s:4:"iaÅ‚";s:2:"51";s:3:"a p";s:2:"52";s:3:"pow";s:2:"53";s:3:" mi";s:2:"54";s:3:"li ";s:2:"55";s:3:"eni";s:2:"56";s:3:"zie";s:2:"57";s:3:" ta";s:2:"58";s:3:" wa";s:2:"59";s:4:"Å‚o ";s:2:"60";s:4:"ać ";s:2:"61";s:3:"dy ";s:2:"62";s:3:"ak ";s:2:"63";s:3:"e w";s:2:"64";s:3:" a ";s:2:"65";s:3:" od";s:2:"66";s:3:" st";s:2:"67";s:3:"nia";s:2:"68";s:3:"rzy";s:2:"69";s:3:"ied";s:2:"70";s:3:" kt";s:2:"71";s:3:"odz";s:2:"72";s:3:"cie";s:2:"73";s:3:"cze";s:2:"74";s:3:"ia ";s:2:"75";s:3:"iel";s:2:"76";s:4:"któ";s:2:"77";s:3:"o p";s:2:"78";s:4:"tór";s:2:"79";s:4:"Å›ci";s:2:"80";s:3:" sp";s:2:"81";s:3:" wy";s:2:"82";s:3:"jak";s:2:"83";s:3:"tak";s:2:"84";s:3:"zy ";s:2:"85";s:3:" mo";s:2:"86";s:5:"aÅ‚Ä™";s:2:"87";s:3:"pro";s:2:"88";s:3:"ski";s:2:"89";s:3:"tem";s:2:"90";s:5:"Å‚Ä™s";s:2:"91";s:3:" tr";s:2:"92";s:3:"e m";s:2:"93";s:3:"jes";s:2:"94";s:3:"my ";s:2:"95";s:3:" ro";s:2:"96";s:3:"edz";s:2:"97";s:3:"eli";s:2:"98";s:3:"iej";s:2:"99";s:3:" rz";s:3:"100";s:3:"a n";s:3:"101";s:3:"ale";s:3:"102";s:3:"an ";s:3:"103";s:3:"e s";s:3:"104";s:3:"est";s:3:"105";s:3:"le ";s:3:"106";s:3:"o s";s:3:"107";s:3:"i p";s:3:"108";s:3:"ki ";s:3:"109";s:3:" co";s:3:"110";s:3:"ada";s:3:"111";s:3:"czn";s:3:"112";s:3:"e t";s:3:"113";s:3:"e z";s:3:"114";s:3:"ent";s:3:"115";s:3:"ny ";s:3:"116";s:3:"pre";s:3:"117";s:4:"rzÄ…";s:3:"118";s:3:"y s";s:3:"119";s:3:" ko";s:3:"120";s:3:" o ";s:3:"121";s:3:"ach";s:3:"122";s:3:"am ";s:3:"123";s:3:"e n";s:3:"124";s:3:"o t";s:3:"125";s:3:"oli";s:3:"126";s:3:"pod";s:3:"127";s:3:"zia";s:3:"128";s:3:" go";s:3:"129";s:3:" ka";s:3:"130";s:3:"by ";s:3:"131";s:3:"ieg";s:3:"132";s:3:"ier";s:3:"133";s:4:"noÅ›";s:3:"134";s:3:"roz";s:3:"135";s:3:"spo";s:3:"136";s:3:"ych";s:3:"137";s:4:"zÄ…d";s:3:"138";s:3:" mn";s:3:"139";s:3:"acz";s:3:"140";s:3:"adz";s:3:"141";s:3:"bie";s:3:"142";s:3:"cho";s:3:"143";s:3:"mni";s:3:"144";s:3:"o n";s:3:"145";s:3:"ost";s:3:"146";s:3:"pra";s:3:"147";s:3:"ze ";s:3:"148";s:4:"Å‚a ";s:3:"149";s:3:" so";s:3:"150";s:3:"a m";s:3:"151";s:3:"cza";s:3:"152";s:3:"iem";s:3:"153";s:4:"ić ";s:3:"154";s:3:"obi";s:3:"155";s:4:"yÅ‚ ";s:3:"156";s:4:"yÅ‚o";s:3:"157";s:3:" mu";s:3:"158";s:4:" mó";s:3:"159";s:3:"a t";s:3:"160";s:3:"acj";s:3:"161";s:3:"ci ";s:3:"162";s:3:"e b";s:3:"163";s:3:"ich";s:3:"164";s:3:"kan";s:3:"165";s:3:"mi ";s:3:"166";s:3:"mie";s:3:"167";s:4:"oÅ›c";s:3:"168";s:3:"row";s:3:"169";s:3:"zen";s:3:"170";s:3:"zyd";s:3:"171";s:3:" al";s:3:"172";s:3:" re";s:3:"173";s:3:"a w";s:3:"174";s:3:"den";s:3:"175";s:3:"edy";s:3:"176";s:4:"iÅ‚ ";s:3:"177";s:3:"ko ";s:3:"178";s:3:"o w";s:3:"179";s:3:"rac";s:3:"180";s:4:"Å›my";s:3:"181";s:3:" ma";s:3:"182";s:3:" ra";s:3:"183";s:3:" sz";s:3:"184";s:3:" ty";s:3:"185";s:3:"e j";s:3:"186";s:3:"isk";s:3:"187";s:3:"ji ";s:3:"188";s:3:"ka ";s:3:"189";s:3:"m s";s:3:"190";s:3:"no ";s:3:"191";s:3:"o z";s:3:"192";s:3:"rez";s:3:"193";s:3:"wa ";s:3:"194";s:4:"ów ";s:3:"195";s:4:"Å‚ow";s:3:"196";s:5:"ść ";s:3:"197";s:3:" ob";s:3:"198";s:3:"ech";s:3:"199";s:3:"ecz";s:3:"200";s:3:"ezy";s:3:"201";s:3:"i w";s:3:"202";s:3:"ja ";s:3:"203";s:3:"kon";s:3:"204";s:4:"mów";s:3:"205";s:3:"ne ";s:3:"206";s:3:"ni ";s:3:"207";s:3:"now";s:3:"208";s:3:"nym";s:3:"209";s:3:"pol";s:3:"210";s:3:"pot";s:3:"211";s:3:"yde";s:3:"212";s:3:" dl";s:3:"213";s:3:" sy";s:3:"214";s:3:"a s";s:3:"215";s:3:"aki";s:3:"216";s:3:"ali";s:3:"217";s:3:"dla";s:3:"218";s:3:"icz";s:3:"219";s:3:"ku ";s:3:"220";s:3:"ocz";s:3:"221";s:3:"st ";s:3:"222";s:3:"str";s:3:"223";s:3:"szy";s:3:"224";s:3:"trz";s:3:"225";s:3:"wia";s:3:"226";s:3:"y p";s:3:"227";s:3:"za ";s:3:"228";s:3:" wt";s:3:"229";s:3:"chc";s:3:"230";s:3:"esz";s:3:"231";s:3:"iec";s:3:"232";s:3:"im ";s:3:"233";s:3:"la ";s:3:"234";s:3:"o m";s:3:"235";s:3:"sa ";s:3:"236";s:4:"wać";s:3:"237";s:3:"y n";s:3:"238";s:3:"zac";s:3:"239";s:3:"zec";s:3:"240";s:3:" gd";s:3:"241";s:3:"a z";s:3:"242";s:3:"ard";s:3:"243";s:3:"co ";s:3:"244";s:3:"dar";s:3:"245";s:3:"e r";s:3:"246";s:3:"ien";s:3:"247";s:3:"m n";s:3:"248";s:3:"m w";s:3:"249";s:3:"mia";s:3:"250";s:4:"moż";s:3:"251";s:3:"raw";s:3:"252";s:3:"rdz";s:3:"253";s:3:"tan";s:3:"254";s:3:"ted";s:3:"255";s:3:"teg";s:3:"256";s:4:"wiÅ‚";s:3:"257";s:3:"wte";s:3:"258";s:3:"y z";s:3:"259";s:3:"zna";s:3:"260";s:4:"zÅ‚o";s:3:"261";s:3:"a r";s:3:"262";s:3:"awi";s:3:"263";s:3:"bar";s:3:"264";s:3:"cji";s:3:"265";s:4:"czÄ…";s:3:"266";s:3:"dow";s:3:"267";s:4:"eż ";s:3:"268";s:3:"gdy";s:3:"269";s:3:"iek";s:3:"270";s:3:"je ";s:3:"271";s:3:"o d";s:3:"272";s:4:"taÅ‚";s:3:"273";s:3:"wal";s:3:"274";s:3:"wsz";s:3:"275";s:3:"zed";s:3:"276";s:4:"ówi";s:3:"277";s:4:"Ä™sa";s:3:"278";s:3:" ba";s:3:"279";s:3:" lu";s:3:"280";s:3:" wo";s:3:"281";s:3:"aln";s:3:"282";s:3:"arn";s:3:"283";s:3:"ba ";s:3:"284";s:3:"dzo";s:3:"285";s:3:"e c";s:3:"286";s:3:"hod";s:3:"287";s:3:"igi";s:3:"288";s:3:"lig";s:3:"289";s:3:"m p";s:3:"290";s:4:"myÅ›";s:3:"291";s:3:"o c";s:3:"292";s:3:"oni";s:3:"293";s:3:"rel";s:3:"294";s:3:"sku";s:3:"295";s:3:"ste";s:3:"296";s:3:"y w";s:3:"297";s:3:"yst";s:3:"298";s:3:"z w";s:3:"299";}s:10:"portuguese";a:300:{s:3:"de ";s:1:"0";s:3:" de";s:1:"1";s:3:"os ";s:1:"2";s:3:"as ";s:1:"3";s:3:"que";s:1:"4";s:3:" co";s:1:"5";s:4:"ão ";s:1:"6";s:3:"o d";s:1:"7";s:3:" qu";s:1:"8";s:3:"ue ";s:1:"9";s:3:" a ";s:2:"10";s:3:"do ";s:2:"11";s:3:"ent";s:2:"12";s:3:" se";s:2:"13";s:3:"a d";s:2:"14";s:3:"s d";s:2:"15";s:3:"e a";s:2:"16";s:3:"es ";s:2:"17";s:3:" pr";s:2:"18";s:3:"ra ";s:2:"19";s:3:"da ";s:2:"20";s:3:" es";s:2:"21";s:3:" pa";s:2:"22";s:3:"to ";s:2:"23";s:3:" o ";s:2:"24";s:3:"em ";s:2:"25";s:3:"con";s:2:"26";s:3:"o p";s:2:"27";s:3:" do";s:2:"28";s:3:"est";s:2:"29";s:3:"nte";s:2:"30";s:5:"ção";s:2:"31";s:3:" da";s:2:"32";s:3:" re";s:2:"33";s:3:"ma ";s:2:"34";s:3:"par";s:2:"35";s:3:" te";s:2:"36";s:3:"ara";s:2:"37";s:3:"ida";s:2:"38";s:3:" e ";s:2:"39";s:3:"ade";s:2:"40";s:3:"is ";s:2:"41";s:3:" um";s:2:"42";s:3:" po";s:2:"43";s:3:"a a";s:2:"44";s:3:"a p";s:2:"45";s:3:"dad";s:2:"46";s:3:"no ";s:2:"47";s:3:"te ";s:2:"48";s:3:" no";s:2:"49";s:5:"açã";s:2:"50";s:3:"pro";s:2:"51";s:3:"al ";s:2:"52";s:3:"com";s:2:"53";s:3:"e d";s:2:"54";s:3:"s a";s:2:"55";s:3:" as";s:2:"56";s:3:"a c";s:2:"57";s:3:"er ";s:2:"58";s:3:"men";s:2:"59";s:3:"s e";s:2:"60";s:3:"ais";s:2:"61";s:3:"nto";s:2:"62";s:3:"res";s:2:"63";s:3:"a s";s:2:"64";s:3:"ado";s:2:"65";s:3:"ist";s:2:"66";s:3:"s p";s:2:"67";s:3:"tem";s:2:"68";s:3:"e c";s:2:"69";s:3:"e s";s:2:"70";s:3:"ia ";s:2:"71";s:3:"o s";s:2:"72";s:3:"o a";s:2:"73";s:3:"o c";s:2:"74";s:3:"e p";s:2:"75";s:3:"sta";s:2:"76";s:3:"ta ";s:2:"77";s:3:"tra";s:2:"78";s:3:"ura";s:2:"79";s:3:" di";s:2:"80";s:3:" pe";s:2:"81";s:3:"ar ";s:2:"82";s:3:"e e";s:2:"83";s:3:"ser";s:2:"84";s:3:"uma";s:2:"85";s:3:"mos";s:2:"86";s:3:"se ";s:2:"87";s:3:" ca";s:2:"88";s:3:"o e";s:2:"89";s:3:" na";s:2:"90";s:3:"a e";s:2:"91";s:3:"des";s:2:"92";s:3:"ont";s:2:"93";s:3:"por";s:2:"94";s:3:" in";s:2:"95";s:3:" ma";s:2:"96";s:3:"ect";s:2:"97";s:3:"o q";s:2:"98";s:3:"ria";s:2:"99";s:3:"s c";s:3:"100";s:3:"ste";s:3:"101";s:3:"ver";s:3:"102";s:3:"cia";s:3:"103";s:3:"dos";s:3:"104";s:3:"ica";s:3:"105";s:3:"str";s:3:"106";s:3:" ao";s:3:"107";s:3:" em";s:3:"108";s:3:"das";s:3:"109";s:3:"e t";s:3:"110";s:3:"ito";s:3:"111";s:3:"iza";s:3:"112";s:3:"pre";s:3:"113";s:3:"tos";s:3:"114";s:4:" nã";s:3:"115";s:3:"ada";s:3:"116";s:4:"não";s:3:"117";s:3:"ess";s:3:"118";s:3:"eve";s:3:"119";s:3:"or ";s:3:"120";s:3:"ran";s:3:"121";s:3:"s n";s:3:"122";s:3:"s t";s:3:"123";s:3:"tur";s:3:"124";s:3:" ac";s:3:"125";s:3:" fa";s:3:"126";s:3:"a r";s:3:"127";s:3:"ens";s:3:"128";s:3:"eri";s:3:"129";s:3:"na ";s:3:"130";s:3:"sso";s:3:"131";s:3:" si";s:3:"132";s:4:" é ";s:3:"133";s:3:"bra";s:3:"134";s:3:"esp";s:3:"135";s:3:"mo ";s:3:"136";s:3:"nos";s:3:"137";s:3:"ro ";s:3:"138";s:3:"um ";s:3:"139";s:3:"a n";s:3:"140";s:3:"ao ";s:3:"141";s:3:"ico";s:3:"142";s:3:"liz";s:3:"143";s:3:"min";s:3:"144";s:3:"o n";s:3:"145";s:3:"ons";s:3:"146";s:3:"pri";s:3:"147";s:3:"ten";s:3:"148";s:3:"tic";s:3:"149";s:4:"ões";s:3:"150";s:3:" tr";s:3:"151";s:3:"a m";s:3:"152";s:3:"aga";s:3:"153";s:3:"e n";s:3:"154";s:3:"ili";s:3:"155";s:3:"ime";s:3:"156";s:3:"m a";s:3:"157";s:3:"nci";s:3:"158";s:3:"nha";s:3:"159";s:3:"nta";s:3:"160";s:3:"spe";s:3:"161";s:3:"tiv";s:3:"162";s:3:"am ";s:3:"163";s:3:"ano";s:3:"164";s:3:"arc";s:3:"165";s:3:"ass";s:3:"166";s:3:"cer";s:3:"167";s:3:"e o";s:3:"168";s:3:"ece";s:3:"169";s:3:"emo";s:3:"170";s:3:"ga ";s:3:"171";s:3:"o m";s:3:"172";s:3:"rag";s:3:"173";s:3:"so ";s:3:"174";s:4:"são";s:3:"175";s:3:" au";s:3:"176";s:3:" os";s:3:"177";s:3:" sa";s:3:"178";s:3:"ali";s:3:"179";s:3:"ca ";s:3:"180";s:3:"ema";s:3:"181";s:3:"emp";s:3:"182";s:3:"ici";s:3:"183";s:3:"ido";s:3:"184";s:3:"inh";s:3:"185";s:3:"iss";s:3:"186";s:3:"l d";s:3:"187";s:3:"la ";s:3:"188";s:3:"lic";s:3:"189";s:3:"m c";s:3:"190";s:3:"mai";s:3:"191";s:3:"onc";s:3:"192";s:3:"pec";s:3:"193";s:3:"ram";s:3:"194";s:3:"s q";s:3:"195";s:3:" ci";s:3:"196";s:3:" en";s:3:"197";s:3:" fo";s:3:"198";s:3:"a o";s:3:"199";s:3:"ame";s:3:"200";s:3:"car";s:3:"201";s:3:"co ";s:3:"202";s:3:"der";s:3:"203";s:3:"eir";s:3:"204";s:3:"ho ";s:3:"205";s:3:"io ";s:3:"206";s:3:"om ";s:3:"207";s:3:"ora";s:3:"208";s:3:"r a";s:3:"209";s:3:"sen";s:3:"210";s:3:"ter";s:3:"211";s:3:" br";s:3:"212";s:3:" ex";s:3:"213";s:3:"a u";s:3:"214";s:3:"cul";s:3:"215";s:3:"dev";s:3:"216";s:3:"e u";s:3:"217";s:3:"ha ";s:3:"218";s:3:"mpr";s:3:"219";s:3:"nce";s:3:"220";s:3:"oca";s:3:"221";s:3:"ove";s:3:"222";s:3:"rio";s:3:"223";s:3:"s o";s:3:"224";s:3:"sa ";s:3:"225";s:3:"sem";s:3:"226";s:3:"tes";s:3:"227";s:3:"uni";s:3:"228";s:3:"ven";s:3:"229";s:4:"zaç";s:3:"230";s:5:"çõe";s:3:"231";s:3:" ad";s:3:"232";s:3:" al";s:3:"233";s:3:" an";s:3:"234";s:3:" mi";s:3:"235";s:3:" mo";s:3:"236";s:3:" ve";s:3:"237";s:4:" à ";s:3:"238";s:3:"a i";s:3:"239";s:3:"a q";s:3:"240";s:3:"ala";s:3:"241";s:3:"amo";s:3:"242";s:3:"bli";s:3:"243";s:3:"cen";s:3:"244";s:3:"col";s:3:"245";s:3:"cos";s:3:"246";s:3:"cto";s:3:"247";s:3:"e m";s:3:"248";s:3:"e v";s:3:"249";s:3:"ede";s:3:"250";s:4:"gás";s:3:"251";s:3:"ias";s:3:"252";s:3:"ita";s:3:"253";s:3:"iva";s:3:"254";s:3:"ndo";s:3:"255";s:3:"o t";s:3:"256";s:3:"ore";s:3:"257";s:3:"r d";s:3:"258";s:3:"ral";s:3:"259";s:3:"rea";s:3:"260";s:3:"s f";s:3:"261";s:3:"sid";s:3:"262";s:3:"tro";s:3:"263";s:3:"vel";s:3:"264";s:3:"vid";s:3:"265";s:4:"ás ";s:3:"266";s:3:" ap";s:3:"267";s:3:" ar";s:3:"268";s:3:" ce";s:3:"269";s:3:" ou";s:3:"270";s:4:" pú";s:3:"271";s:3:" so";s:3:"272";s:3:" vi";s:3:"273";s:3:"a f";s:3:"274";s:3:"act";s:3:"275";s:3:"arr";s:3:"276";s:3:"bil";s:3:"277";s:3:"cam";s:3:"278";s:3:"e f";s:3:"279";s:3:"e i";s:3:"280";s:3:"el ";s:3:"281";s:3:"for";s:3:"282";s:3:"lem";s:3:"283";s:3:"lid";s:3:"284";s:3:"lo ";s:3:"285";s:3:"m d";s:3:"286";s:3:"mar";s:3:"287";s:3:"nde";s:3:"288";s:3:"o o";s:3:"289";s:3:"omo";s:3:"290";s:3:"ort";s:3:"291";s:3:"per";s:3:"292";s:4:"púb";s:3:"293";s:3:"r u";s:3:"294";s:3:"rei";s:3:"295";s:3:"rem";s:3:"296";s:3:"ros";s:3:"297";s:3:"rre";s:3:"298";s:3:"ssi";s:3:"299";}s:8:"romanian";a:300:{s:3:" de";s:1:"0";s:4:" în";s:1:"1";s:3:"de ";s:1:"2";s:3:" a ";s:1:"3";s:3:"ul ";s:1:"4";s:3:" co";s:1:"5";s:4:"în ";s:1:"6";s:3:"re ";s:1:"7";s:3:"e d";s:1:"8";s:3:"ea ";s:1:"9";s:3:" di";s:2:"10";s:3:" pr";s:2:"11";s:3:"le ";s:2:"12";s:4:"ÅŸi ";s:2:"13";s:3:"are";s:2:"14";s:3:"at ";s:2:"15";s:3:"con";s:2:"16";s:3:"ui ";s:2:"17";s:4:" ÅŸi";s:2:"18";s:3:"i d";s:2:"19";s:3:"ii ";s:2:"20";s:3:" cu";s:2:"21";s:3:"e a";s:2:"22";s:3:"lui";s:2:"23";s:3:"ern";s:2:"24";s:3:"te ";s:2:"25";s:3:"cu ";s:2:"26";s:3:" la";s:2:"27";s:3:"a c";s:2:"28";s:4:"că ";s:2:"29";s:3:"din";s:2:"30";s:3:"e c";s:2:"31";s:3:"or ";s:2:"32";s:3:"ulu";s:2:"33";s:3:"ne ";s:2:"34";s:3:"ter";s:2:"35";s:3:"la ";s:2:"36";s:4:"să ";s:2:"37";s:3:"tat";s:2:"38";s:3:"tre";s:2:"39";s:3:" ac";s:2:"40";s:4:" să";s:2:"41";s:3:"est";s:2:"42";s:3:"st ";s:2:"43";s:4:"tă ";s:2:"44";s:3:" ca";s:2:"45";s:3:" ma";s:2:"46";s:3:" pe";s:2:"47";s:3:"cur";s:2:"48";s:3:"ist";s:2:"49";s:4:"mân";s:2:"50";s:3:"a d";s:2:"51";s:3:"i c";s:2:"52";s:3:"nat";s:2:"53";s:3:" ce";s:2:"54";s:3:"i a";s:2:"55";s:3:"ia ";s:2:"56";s:3:"in ";s:2:"57";s:3:"scu";s:2:"58";s:3:" mi";s:2:"59";s:3:"ato";s:2:"60";s:4:"aÅ£i";s:2:"61";s:3:"ie ";s:2:"62";s:3:" re";s:2:"63";s:3:" se";s:2:"64";s:3:"a a";s:2:"65";s:3:"int";s:2:"66";s:3:"ntr";s:2:"67";s:3:"tru";s:2:"68";s:3:"uri";s:2:"69";s:4:"ă a";s:2:"70";s:3:" fo";s:2:"71";s:3:" pa";s:2:"72";s:3:"ate";s:2:"73";s:3:"ini";s:2:"74";s:3:"tul";s:2:"75";s:3:"ent";s:2:"76";s:3:"min";s:2:"77";s:3:"pre";s:2:"78";s:3:"pro";s:2:"79";s:3:"a p";s:2:"80";s:3:"e p";s:2:"81";s:3:"e s";s:2:"82";s:3:"ei ";s:2:"83";s:4:"nă ";s:2:"84";s:3:"par";s:2:"85";s:3:"rna";s:2:"86";s:3:"rul";s:2:"87";s:3:"tor";s:2:"88";s:3:" in";s:2:"89";s:3:" ro";s:2:"90";s:3:" tr";s:2:"91";s:3:" un";s:2:"92";s:3:"al ";s:2:"93";s:3:"ale";s:2:"94";s:3:"art";s:2:"95";s:3:"ce ";s:2:"96";s:3:"e e";s:2:"97";s:4:"e î";s:2:"98";s:3:"fos";s:2:"99";s:3:"ita";s:3:"100";s:3:"nte";s:3:"101";s:4:"omâ";s:3:"102";s:3:"ost";s:3:"103";s:3:"rom";s:3:"104";s:3:"ru ";s:3:"105";s:3:"str";s:3:"106";s:3:"ver";s:3:"107";s:3:" ex";s:3:"108";s:3:" na";s:3:"109";s:3:"a f";s:3:"110";s:3:"lor";s:3:"111";s:3:"nis";s:3:"112";s:3:"rea";s:3:"113";s:3:"rit";s:3:"114";s:3:" al";s:3:"115";s:3:" eu";s:3:"116";s:3:" no";s:3:"117";s:3:"ace";s:3:"118";s:3:"cer";s:3:"119";s:3:"ile";s:3:"120";s:3:"nal";s:3:"121";s:3:"pri";s:3:"122";s:3:"ri ";s:3:"123";s:3:"sta";s:3:"124";s:3:"ste";s:3:"125";s:4:"Å£ie";s:3:"126";s:3:" au";s:3:"127";s:3:" da";s:3:"128";s:3:" ju";s:3:"129";s:3:" po";s:3:"130";s:3:"ar ";s:3:"131";s:3:"au ";s:3:"132";s:3:"ele";s:3:"133";s:3:"ere";s:3:"134";s:3:"eri";s:3:"135";s:3:"ina";s:3:"136";s:3:"n a";s:3:"137";s:3:"n c";s:3:"138";s:3:"res";s:3:"139";s:3:"se ";s:3:"140";s:3:"t a";s:3:"141";s:3:"tea";s:3:"142";s:4:" că";s:3:"143";s:3:" do";s:3:"144";s:3:" fi";s:3:"145";s:3:"a s";s:3:"146";s:4:"ată";s:3:"147";s:3:"com";s:3:"148";s:4:"e ÅŸ";s:3:"149";s:3:"eur";s:3:"150";s:3:"guv";s:3:"151";s:3:"i s";s:3:"152";s:3:"ice";s:3:"153";s:3:"ili";s:3:"154";s:3:"na ";s:3:"155";s:3:"rec";s:3:"156";s:3:"rep";s:3:"157";s:3:"ril";s:3:"158";s:3:"rne";s:3:"159";s:3:"rti";s:3:"160";s:3:"uro";s:3:"161";s:3:"uve";s:3:"162";s:4:"ă p";s:3:"163";s:3:" ar";s:3:"164";s:3:" o ";s:3:"165";s:3:" su";s:3:"166";s:3:" vi";s:3:"167";s:3:"dec";s:3:"168";s:3:"dre";s:3:"169";s:3:"oar";s:3:"170";s:3:"ons";s:3:"171";s:3:"pe ";s:3:"172";s:3:"rii";s:3:"173";s:3:" ad";s:3:"174";s:3:" ge";s:3:"175";s:3:"a m";s:3:"176";s:3:"a r";s:3:"177";s:3:"ain";s:3:"178";s:3:"ali";s:3:"179";s:3:"car";s:3:"180";s:3:"cat";s:3:"181";s:3:"ecu";s:3:"182";s:3:"ene";s:3:"183";s:3:"ept";s:3:"184";s:3:"ext";s:3:"185";s:3:"ilo";s:3:"186";s:3:"iu ";s:3:"187";s:3:"n p";s:3:"188";s:3:"ori";s:3:"189";s:3:"sec";s:3:"190";s:3:"u p";s:3:"191";s:3:"une";s:3:"192";s:4:"ă c";s:3:"193";s:4:"ÅŸti";s:3:"194";s:4:"Å£ia";s:3:"195";s:3:" ch";s:3:"196";s:3:" gu";s:3:"197";s:3:"ai ";s:3:"198";s:3:"ani";s:3:"199";s:3:"cea";s:3:"200";s:3:"e f";s:3:"201";s:3:"isc";s:3:"202";s:3:"l a";s:3:"203";s:3:"lic";s:3:"204";s:3:"liu";s:3:"205";s:3:"mar";s:3:"206";s:3:"nic";s:3:"207";s:3:"nt ";s:3:"208";s:3:"nul";s:3:"209";s:3:"ris";s:3:"210";s:3:"t c";s:3:"211";s:3:"t p";s:3:"212";s:3:"tic";s:3:"213";s:3:"tid";s:3:"214";s:3:"u a";s:3:"215";s:3:"ucr";s:3:"216";s:3:" as";s:3:"217";s:3:" dr";s:3:"218";s:3:" fa";s:3:"219";s:3:" nu";s:3:"220";s:3:" pu";s:3:"221";s:3:" to";s:3:"222";s:3:"cra";s:3:"223";s:3:"dis";s:3:"224";s:4:"enÅ£";s:3:"225";s:3:"esc";s:3:"226";s:3:"gen";s:3:"227";s:3:"it ";s:3:"228";s:3:"ivi";s:3:"229";s:3:"l d";s:3:"230";s:3:"n d";s:3:"231";s:3:"nd ";s:3:"232";s:3:"nu ";s:3:"233";s:3:"ond";s:3:"234";s:3:"pen";s:3:"235";s:3:"ral";s:3:"236";s:3:"riv";s:3:"237";s:3:"rte";s:3:"238";s:3:"sti";s:3:"239";s:3:"t d";s:3:"240";s:3:"ta ";s:3:"241";s:3:"to ";s:3:"242";s:3:"uni";s:3:"243";s:3:"xte";s:3:"244";s:4:"ând";s:3:"245";s:4:"îns";s:3:"246";s:4:"ă s";s:3:"247";s:3:" bl";s:3:"248";s:3:" st";s:3:"249";s:3:" uc";s:3:"250";s:3:"a b";s:3:"251";s:3:"a i";s:3:"252";s:3:"a l";s:3:"253";s:3:"air";s:3:"254";s:3:"ast";s:3:"255";s:3:"bla";s:3:"256";s:3:"bri";s:3:"257";s:3:"che";s:3:"258";s:3:"duc";s:3:"259";s:3:"dul";s:3:"260";s:3:"e m";s:3:"261";s:3:"eas";s:3:"262";s:3:"edi";s:3:"263";s:3:"esp";s:3:"264";s:3:"i l";s:3:"265";s:3:"i p";s:3:"266";s:3:"ica";s:3:"267";s:4:"ică";s:3:"268";s:3:"ir ";s:3:"269";s:3:"iun";s:3:"270";s:3:"jud";s:3:"271";s:3:"lai";s:3:"272";s:3:"lul";s:3:"273";s:3:"mai";s:3:"274";s:3:"men";s:3:"275";s:3:"ni ";s:3:"276";s:3:"pus";s:3:"277";s:3:"put";s:3:"278";s:3:"ra ";s:3:"279";s:3:"rai";s:3:"280";s:3:"rop";s:3:"281";s:3:"sil";s:3:"282";s:3:"ti ";s:3:"283";s:3:"tra";s:3:"284";s:3:"u s";s:3:"285";s:3:"ua ";s:3:"286";s:3:"ude";s:3:"287";s:3:"urs";s:3:"288";s:4:"ân ";s:3:"289";s:4:"înt";s:3:"290";s:5:"ţă ";s:3:"291";s:3:" lu";s:3:"292";s:3:" mo";s:3:"293";s:3:" s ";s:3:"294";s:3:" sa";s:3:"295";s:3:" sc";s:3:"296";s:3:"a u";s:3:"297";s:3:"an ";s:3:"298";s:3:"atu";s:3:"299";}s:7:"russian";a:300:{s:5:" на";s:1:"0";s:5:" пр";s:1:"1";s:5:"то ";s:1:"2";s:5:" не";s:1:"3";s:5:"ли ";s:1:"4";s:5:" по";s:1:"5";s:5:"но ";s:1:"6";s:4:" в ";s:1:"7";s:5:"на ";s:1:"8";s:5:"Ñ‚ÑŒ ";s:1:"9";s:5:"не ";s:2:"10";s:4:" и ";s:2:"11";s:5:" ко";s:2:"12";s:5:"ом ";s:2:"13";s:6:"про";s:2:"14";s:5:" то";s:2:"15";s:5:"их ";s:2:"16";s:5:" ка";s:2:"17";s:6:"ать";s:2:"18";s:6:"ото";s:2:"19";s:5:" за";s:2:"20";s:5:"ие ";s:2:"21";s:6:"ова";s:2:"22";s:6:"тел";s:2:"23";s:6:"тор";s:2:"24";s:5:" де";s:2:"25";s:5:"ой ";s:2:"26";s:6:"Ñти";s:2:"27";s:5:" от";s:2:"28";s:5:"ах ";s:2:"29";s:5:"ми ";s:2:"30";s:6:"ÑÑ‚Ñ€";s:2:"31";s:5:" бе";s:2:"32";s:5:" во";s:2:"33";s:5:" ра";s:2:"34";s:5:"Ð°Ñ ";s:2:"35";s:6:"ват";s:2:"36";s:5:"ей ";s:2:"37";s:5:"ет ";s:2:"38";s:5:"же ";s:2:"39";s:6:"иче";s:2:"40";s:5:"Ð¸Ñ ";s:2:"41";s:5:"ов ";s:2:"42";s:6:"Ñто";s:2:"43";s:5:" об";s:2:"44";s:6:"вер";s:2:"45";s:5:"го ";s:2:"46";s:5:"и в";s:2:"47";s:5:"и п";s:2:"48";s:5:"и Ñ";s:2:"49";s:5:"ии ";s:2:"50";s:6:"иÑÑ‚";s:2:"51";s:5:"о в";s:2:"52";s:6:"оÑÑ‚";s:2:"53";s:6:"тра";s:2:"54";s:5:" те";s:2:"55";s:6:"ели";s:2:"56";s:6:"ере";s:2:"57";s:6:"кот";s:2:"58";s:6:"льн";s:2:"59";s:6:"ник";s:2:"60";s:6:"нти";s:2:"61";s:5:"о Ñ";s:2:"62";s:6:"рор";s:2:"63";s:6:"Ñтв";s:2:"64";s:6:"чеÑ";s:2:"65";s:5:" бо";s:2:"66";s:5:" ве";s:2:"67";s:5:" да";s:2:"68";s:5:" ин";s:2:"69";s:5:" но";s:2:"70";s:4:" Ñ ";s:2:"71";s:5:" Ñо";s:2:"72";s:5:" Ñп";s:2:"73";s:5:" ÑÑ‚";s:2:"74";s:5:" чт";s:2:"75";s:6:"али";s:2:"76";s:6:"ами";s:2:"77";s:6:"вид";s:2:"78";s:6:"дет";s:2:"79";s:5:"е н";s:2:"80";s:6:"ель";s:2:"81";s:6:"еÑк";s:2:"82";s:6:"еÑÑ‚";s:2:"83";s:6:"зал";s:2:"84";s:5:"и н";s:2:"85";s:6:"ива";s:2:"86";s:6:"кон";s:2:"87";s:6:"ого";s:2:"88";s:6:"одн";s:2:"89";s:6:"ожн";s:2:"90";s:6:"оль";s:2:"91";s:6:"ори";s:2:"92";s:6:"ров";s:2:"93";s:6:"Ñко";s:2:"94";s:5:"ÑÑ ";s:2:"95";s:6:"тер";s:2:"96";s:6:"что";s:2:"97";s:5:" мо";s:2:"98";s:5:" Ñа";s:2:"99";s:5:" ÑÑ‚";s:3:"100";s:6:"ант";s:3:"101";s:6:"вÑе";s:3:"102";s:6:"ерр";s:3:"103";s:6:"еÑл";s:3:"104";s:6:"иде";s:3:"105";s:6:"ина";s:3:"106";s:6:"ино";s:3:"107";s:6:"иро";s:3:"108";s:6:"ите";s:3:"109";s:5:"ка ";s:3:"110";s:5:"ко ";s:3:"111";s:6:"кол";s:3:"112";s:6:"ком";s:3:"113";s:5:"ла ";s:3:"114";s:6:"ниÑ";s:3:"115";s:5:"о Ñ‚";s:3:"116";s:6:"оло";s:3:"117";s:6:"ран";s:3:"118";s:6:"ред";s:3:"119";s:5:"ÑÑŒ ";s:3:"120";s:6:"тив";s:3:"121";s:6:"тич";s:3:"122";s:5:"Ñ‹Ñ… ";s:3:"123";s:5:" ви";s:3:"124";s:5:" вÑ";s:3:"125";s:5:" го";s:3:"126";s:5:" ма";s:3:"127";s:5:" Ñл";s:3:"128";s:6:"ако";s:3:"129";s:6:"ани";s:3:"130";s:6:"аÑÑ‚";s:3:"131";s:6:"без";s:3:"132";s:6:"дел";s:3:"133";s:5:"е д";s:3:"134";s:5:"е п";s:3:"135";s:5:"ем ";s:3:"136";s:6:"жно";s:3:"137";s:5:"и д";s:3:"138";s:6:"ика";s:3:"139";s:6:"каз";s:3:"140";s:6:"как";s:3:"141";s:5:"ки ";s:3:"142";s:6:"ноÑ";s:3:"143";s:5:"о н";s:3:"144";s:6:"опа";s:3:"145";s:6:"при";s:3:"146";s:6:"рро";s:3:"147";s:6:"Ñки";s:3:"148";s:5:"ти ";s:3:"149";s:6:"тов";s:3:"150";s:5:"ые ";s:3:"151";s:5:" вы";s:3:"152";s:5:" до";s:3:"153";s:5:" ме";s:3:"154";s:5:" ни";s:3:"155";s:5:" од";s:3:"156";s:5:" ро";s:3:"157";s:5:" Ñв";s:3:"158";s:5:" чи";s:3:"159";s:5:"а н";s:3:"160";s:6:"ает";s:3:"161";s:6:"аза";s:3:"162";s:6:"ате";s:3:"163";s:6:"беÑ";s:3:"164";s:5:"в п";s:3:"165";s:5:"ва ";s:3:"166";s:5:"е в";s:3:"167";s:5:"е м";s:3:"168";s:5:"е Ñ";s:3:"169";s:5:"ез ";s:3:"170";s:6:"ени";s:3:"171";s:5:"за ";s:3:"172";s:6:"зна";s:3:"173";s:6:"ини";s:3:"174";s:6:"кам";s:3:"175";s:6:"ках";s:3:"176";s:6:"кто";s:3:"177";s:6:"лов";s:3:"178";s:6:"мер";s:3:"179";s:6:"мож";s:3:"180";s:6:"нал";s:3:"181";s:6:"ниц";s:3:"182";s:5:"ны ";s:3:"183";s:6:"ным";s:3:"184";s:6:"ора";s:3:"185";s:6:"оро";s:3:"186";s:5:"от ";s:3:"187";s:6:"пор";s:3:"188";s:6:"рав";s:3:"189";s:6:"реÑ";s:3:"190";s:6:"риÑ";s:3:"191";s:6:"роÑ";s:3:"192";s:6:"Ñка";s:3:"193";s:5:"Ñ‚ н";s:3:"194";s:6:"том";s:3:"195";s:6:"чит";s:3:"196";s:6:"шко";s:3:"197";s:5:" бы";s:3:"198";s:4:" о ";s:3:"199";s:5:" Ñ‚Ñ€";s:3:"200";s:5:" уж";s:3:"201";s:5:" чу";s:3:"202";s:5:" шк";s:3:"203";s:5:"а б";s:3:"204";s:5:"а в";s:3:"205";s:5:"а Ñ€";s:3:"206";s:6:"аби";s:3:"207";s:6:"ала";s:3:"208";s:6:"ало";s:3:"209";s:6:"аль";s:3:"210";s:6:"анн";s:3:"211";s:6:"ати";s:3:"212";s:6:"бин";s:3:"213";s:6:"веÑ";s:3:"214";s:6:"вно";s:3:"215";s:5:"во ";s:3:"216";s:6:"вши";s:3:"217";s:6:"дал";s:3:"218";s:6:"дат";s:3:"219";s:6:"дно";s:3:"220";s:5:"е з";s:3:"221";s:6:"его";s:3:"222";s:6:"еле";s:3:"223";s:6:"енн";s:3:"224";s:6:"ент";s:3:"225";s:6:"ете";s:3:"226";s:5:"и о";s:3:"227";s:6:"или";s:3:"228";s:6:"иÑÑŒ";s:3:"229";s:5:"ит ";s:3:"230";s:6:"ици";s:3:"231";s:6:"ков";s:3:"232";s:6:"лен";s:3:"233";s:6:"льк";s:3:"234";s:6:"мен";s:3:"235";s:5:"мы ";s:3:"236";s:6:"нет";s:3:"237";s:5:"ни ";s:3:"238";s:6:"нны";s:3:"239";s:6:"ног";s:3:"240";s:6:"ной";s:3:"241";s:6:"ном";s:3:"242";s:5:"о п";s:3:"243";s:6:"обн";s:3:"244";s:6:"ове";s:3:"245";s:6:"овн";s:3:"246";s:6:"оры";s:3:"247";s:6:"пер";s:3:"248";s:5:"по ";s:3:"249";s:6:"пра";s:3:"250";s:6:"пре";s:3:"251";s:6:"раз";s:3:"252";s:6:"роп";s:3:"253";s:5:"ры ";s:3:"254";s:5:"Ñе ";s:3:"255";s:6:"Ñли";s:3:"256";s:6:"Ñов";s:3:"257";s:6:"тре";s:3:"258";s:6:"Ñ‚ÑÑ";s:3:"259";s:6:"уро";s:3:"260";s:6:"цел";s:3:"261";s:6:"чно";s:3:"262";s:5:"ÑŒ в";s:3:"263";s:6:"ько";s:3:"264";s:6:"ьно";s:3:"265";s:6:"Ñто";s:3:"266";s:5:"ÑŽÑ‚ ";s:3:"267";s:5:"Ñ Ð½";s:3:"268";s:5:" ан";s:3:"269";s:5:" еÑ";s:3:"270";s:5:" же";s:3:"271";s:5:" из";s:3:"272";s:5:" кт";s:3:"273";s:5:" ми";s:3:"274";s:5:" мы";s:3:"275";s:5:" пе";s:3:"276";s:5:" Ñе";s:3:"277";s:5:" це";s:3:"278";s:5:"а м";s:3:"279";s:5:"а п";s:3:"280";s:5:"а Ñ‚";s:3:"281";s:6:"авш";s:3:"282";s:6:"аже";s:3:"283";s:5:"ак ";s:3:"284";s:5:"ал ";s:3:"285";s:6:"але";s:3:"286";s:6:"ане";s:3:"287";s:6:"ачи";s:3:"288";s:6:"ают";s:3:"289";s:6:"бна";s:3:"290";s:6:"бол";s:3:"291";s:5:"бы ";s:3:"292";s:5:"в и";s:3:"293";s:5:"в Ñ";s:3:"294";s:6:"ван";s:3:"295";s:6:"гра";s:3:"296";s:6:"даж";s:3:"297";s:6:"ден";s:3:"298";s:5:"е к";s:3:"299";}s:7:"serbian";a:300:{s:5:" на";s:1:"0";s:5:" је";s:1:"1";s:5:" по";s:1:"2";s:5:"је ";s:1:"3";s:4:" и ";s:1:"4";s:5:" не";s:1:"5";s:5:" пр";s:1:"6";s:5:"га ";s:1:"7";s:5:" Ñв";s:1:"8";s:5:"ог ";s:1:"9";s:5:"а Ñ";s:2:"10";s:5:"их ";s:2:"11";s:5:"на ";s:2:"12";s:6:"кој";s:2:"13";s:6:"ога";s:2:"14";s:4:" у ";s:2:"15";s:5:"а п";s:2:"16";s:5:"не ";s:2:"17";s:5:"ни ";s:2:"18";s:5:"ти ";s:2:"19";s:5:" да";s:2:"20";s:5:"ом ";s:2:"21";s:5:" ве";s:2:"22";s:5:" ÑÑ€";s:2:"23";s:5:"и Ñ";s:2:"24";s:6:"Ñко";s:2:"25";s:5:" об";s:2:"26";s:5:"а н";s:2:"27";s:5:"да ";s:2:"28";s:5:"е н";s:2:"29";s:5:"но ";s:2:"30";s:6:"ног";s:2:"31";s:5:"о ј";s:2:"32";s:5:"ој ";s:2:"33";s:5:" за";s:2:"34";s:5:"ва ";s:2:"35";s:5:"е Ñ";s:2:"36";s:5:"и п";s:2:"37";s:5:"ма ";s:2:"38";s:6:"ник";s:2:"39";s:6:"обр";s:2:"40";s:6:"ова";s:2:"41";s:5:" ко";s:2:"42";s:5:"а и";s:2:"43";s:6:"диј";s:2:"44";s:5:"е п";s:2:"45";s:5:"ка ";s:2:"46";s:5:"ко ";s:2:"47";s:6:"ког";s:2:"48";s:6:"оÑÑ‚";s:2:"49";s:6:"Ñве";s:2:"50";s:6:"Ñтв";s:2:"51";s:6:"Ñти";s:2:"52";s:6:"тра";s:2:"53";s:6:"еди";s:2:"54";s:6:"има";s:2:"55";s:6:"пок";s:2:"56";s:6:"пра";s:2:"57";s:6:"раз";s:2:"58";s:5:"те ";s:2:"59";s:5:" бо";s:2:"60";s:5:" ви";s:2:"61";s:5:" Ñа";s:2:"62";s:6:"аво";s:2:"63";s:6:"бра";s:2:"64";s:6:"гоÑ";s:2:"65";s:5:"е и";s:2:"66";s:6:"ели";s:2:"67";s:6:"ени";s:2:"68";s:5:"за ";s:2:"69";s:6:"ики";s:2:"70";s:5:"ио ";s:2:"71";s:6:"пре";s:2:"72";s:6:"рав";s:2:"73";s:6:"рад";s:2:"74";s:5:"у Ñ";s:2:"75";s:5:"ју ";s:2:"76";s:5:"ња ";s:2:"77";s:5:" би";s:2:"78";s:5:" до";s:2:"79";s:5:" ÑÑ‚";s:2:"80";s:6:"аÑÑ‚";s:2:"81";s:6:"бој";s:2:"82";s:6:"ебо";s:2:"83";s:5:"и н";s:2:"84";s:5:"им ";s:2:"85";s:5:"ку ";s:2:"86";s:6:"лан";s:2:"87";s:6:"неб";s:2:"88";s:6:"ово";s:2:"89";s:6:"ого";s:2:"90";s:6:"оÑл";s:2:"91";s:6:"ојш";s:2:"92";s:6:"пед";s:2:"93";s:6:"ÑÑ‚Ñ€";s:2:"94";s:6:"чаÑ";s:2:"95";s:5:" го";s:2:"96";s:5:" кр";s:2:"97";s:5:" мо";s:2:"98";s:5:" чл";s:2:"99";s:5:"а м";s:3:"100";s:5:"а о";s:3:"101";s:6:"ако";s:3:"102";s:6:"ача";s:3:"103";s:6:"вел";s:3:"104";s:6:"вет";s:3:"105";s:6:"вог";s:3:"106";s:6:"еда";s:3:"107";s:6:"иÑÑ‚";s:3:"108";s:6:"ити";s:3:"109";s:6:"ије";s:3:"110";s:6:"око";s:3:"111";s:6:"Ñло";s:3:"112";s:6:"Ñрб";s:3:"113";s:6:"чла";s:3:"114";s:5:" бе";s:3:"115";s:5:" оÑ";s:3:"116";s:5:" от";s:3:"117";s:5:" ре";s:3:"118";s:5:" Ñе";s:3:"119";s:5:"а в";s:3:"120";s:5:"ан ";s:3:"121";s:6:"бог";s:3:"122";s:6:"бро";s:3:"123";s:6:"вен";s:3:"124";s:6:"гра";s:3:"125";s:5:"е о";s:3:"126";s:6:"ика";s:3:"127";s:6:"ија";s:3:"128";s:6:"ких";s:3:"129";s:6:"ком";s:3:"130";s:5:"ли ";s:3:"131";s:5:"ну ";s:3:"132";s:6:"ота";s:3:"133";s:6:"ојн";s:3:"134";s:6:"под";s:3:"135";s:6:"рбÑ";s:3:"136";s:6:"ред";s:3:"137";s:6:"рој";s:3:"138";s:5:"Ñа ";s:3:"139";s:6:"Ñни";s:3:"140";s:6:"тач";s:3:"141";s:6:"тва";s:3:"142";s:5:"ја ";s:3:"143";s:5:"ји ";s:3:"144";s:5:" ка";s:3:"145";s:5:" ов";s:3:"146";s:5:" Ñ‚Ñ€";s:3:"147";s:5:"а ј";s:3:"148";s:6:"ави";s:3:"149";s:5:"аз ";s:3:"150";s:6:"ано";s:3:"151";s:6:"био";s:3:"152";s:6:"вик";s:3:"153";s:5:"во ";s:3:"154";s:6:"гов";s:3:"155";s:6:"дни";s:3:"156";s:5:"е ч";s:3:"157";s:6:"его";s:3:"158";s:5:"и о";s:3:"159";s:6:"ива";s:3:"160";s:6:"иво";s:3:"161";s:5:"ик ";s:3:"162";s:6:"ине";s:3:"163";s:6:"ини";s:3:"164";s:6:"ипе";s:3:"165";s:6:"кип";s:3:"166";s:6:"лик";s:3:"167";s:5:"ло ";s:3:"168";s:6:"наш";s:3:"169";s:6:"ноÑ";s:3:"170";s:5:"о Ñ‚";s:3:"171";s:5:"од ";s:3:"172";s:6:"оди";s:3:"173";s:6:"она";s:3:"174";s:6:"оји";s:3:"175";s:6:"поч";s:3:"176";s:6:"про";s:3:"177";s:5:"ра ";s:3:"178";s:6:"риÑ";s:3:"179";s:6:"род";s:3:"180";s:6:"Ñ€ÑÑ‚";s:3:"181";s:5:"Ñе ";s:3:"182";s:6:"Ñпо";s:3:"183";s:6:"Ñта";s:3:"184";s:6:"тић";s:3:"185";s:5:"у д";s:3:"186";s:5:"у н";s:3:"187";s:5:"у о";s:3:"188";s:6:"чин";s:3:"189";s:5:"ша ";s:3:"190";s:6:"јед";s:3:"191";s:6:"јни";s:3:"192";s:5:"ће ";s:3:"193";s:4:" м ";s:3:"194";s:5:" ме";s:3:"195";s:5:" ни";s:3:"196";s:5:" он";s:3:"197";s:5:" па";s:3:"198";s:5:" Ñл";s:3:"199";s:5:" те";s:3:"200";s:5:"а у";s:3:"201";s:6:"ава";s:3:"202";s:6:"аве";s:3:"203";s:6:"авн";s:3:"204";s:6:"ана";s:3:"205";s:5:"ао ";s:3:"206";s:6:"ати";s:3:"207";s:6:"аци";s:3:"208";s:6:"ају";s:3:"209";s:6:"ања";s:3:"210";s:6:"бÑк";s:3:"211";s:6:"вор";s:3:"212";s:6:"воÑ";s:3:"213";s:6:"вÑк";s:3:"214";s:6:"дин";s:3:"215";s:5:"е у";s:3:"216";s:6:"едн";s:3:"217";s:6:"ези";s:3:"218";s:6:"ека";s:3:"219";s:6:"ено";s:3:"220";s:6:"ето";s:3:"221";s:6:"ења";s:3:"222";s:6:"жив";s:3:"223";s:5:"и г";s:3:"224";s:5:"и и";s:3:"225";s:5:"и к";s:3:"226";s:5:"и Ñ‚";s:3:"227";s:6:"ику";s:3:"228";s:6:"ичк";s:3:"229";s:5:"ки ";s:3:"230";s:6:"крÑ";s:3:"231";s:5:"ла ";s:3:"232";s:6:"лав";s:3:"233";s:6:"лит";s:3:"234";s:5:"ме ";s:3:"235";s:6:"мен";s:3:"236";s:6:"нац";s:3:"237";s:5:"о н";s:3:"238";s:5:"о п";s:3:"239";s:5:"о у";s:3:"240";s:6:"одн";s:3:"241";s:6:"оли";s:3:"242";s:6:"орн";s:3:"243";s:6:"оÑн";s:3:"244";s:6:"оÑп";s:3:"245";s:6:"оче";s:3:"246";s:6:"пÑк";s:3:"247";s:6:"реч";s:3:"248";s:6:"рпÑ";s:3:"249";s:6:"Ñво";s:3:"250";s:6:"Ñки";s:3:"251";s:6:"Ñла";s:3:"252";s:6:"Ñрп";s:3:"253";s:5:"Ñу ";s:3:"254";s:5:"та ";s:3:"255";s:6:"тав";s:3:"256";s:6:"тве";s:3:"257";s:5:"у б";s:3:"258";s:6:"јез";s:3:"259";s:5:"ћи ";s:3:"260";s:5:" ен";s:3:"261";s:5:" жи";s:3:"262";s:5:" им";s:3:"263";s:5:" му";s:3:"264";s:5:" од";s:3:"265";s:5:" Ñу";s:3:"266";s:5:" та";s:3:"267";s:5:" Ñ…Ñ€";s:3:"268";s:5:" ча";s:3:"269";s:5:" шт";s:3:"270";s:5:" ње";s:3:"271";s:5:"а д";s:3:"272";s:5:"а з";s:3:"273";s:5:"а к";s:3:"274";s:5:"а Ñ‚";s:3:"275";s:6:"аду";s:3:"276";s:6:"ало";s:3:"277";s:6:"ани";s:3:"278";s:6:"аÑо";s:3:"279";s:6:"ван";s:3:"280";s:6:"вач";s:3:"281";s:6:"вањ";s:3:"282";s:6:"вед";s:3:"283";s:5:"ви ";s:3:"284";s:6:"вно";s:3:"285";s:6:"вот";s:3:"286";s:6:"вој";s:3:"287";s:5:"ву ";s:3:"288";s:6:"доб";s:3:"289";s:6:"дру";s:3:"290";s:6:"дÑе";s:3:"291";s:5:"ду ";s:3:"292";s:5:"е б";s:3:"293";s:5:"е д";s:3:"294";s:5:"е м";s:3:"295";s:5:"ем ";s:3:"296";s:6:"ема";s:3:"297";s:6:"ент";s:3:"298";s:6:"енц";s:3:"299";}s:6:"slovak";a:300:{s:3:" pr";s:1:"0";s:3:" po";s:1:"1";s:3:" ne";s:1:"2";s:3:" a ";s:1:"3";s:3:"ch ";s:1:"4";s:3:" na";s:1:"5";s:3:" je";s:1:"6";s:4:"ní ";s:1:"7";s:3:"je ";s:1:"8";s:3:" do";s:1:"9";s:3:"na ";s:2:"10";s:3:"ova";s:2:"11";s:3:" v ";s:2:"12";s:3:"to ";s:2:"13";s:3:"ho ";s:2:"14";s:3:"ou ";s:2:"15";s:3:" to";s:2:"16";s:3:"ick";s:2:"17";s:3:"ter";s:2:"18";s:4:"že ";s:2:"19";s:3:" st";s:2:"20";s:3:" za";s:2:"21";s:3:"ost";s:2:"22";s:4:"ých";s:2:"23";s:3:" se";s:2:"24";s:3:"pro";s:2:"25";s:3:" te";s:2:"26";s:3:"e s";s:2:"27";s:4:" že";s:2:"28";s:3:"a p";s:2:"29";s:3:" kt";s:2:"30";s:3:"pre";s:2:"31";s:3:" by";s:2:"32";s:3:" o ";s:2:"33";s:3:"se ";s:2:"34";s:3:"kon";s:2:"35";s:4:" pÅ™";s:2:"36";s:3:"a s";s:2:"37";s:4:"né ";s:2:"38";s:4:"nÄ› ";s:2:"39";s:3:"sti";s:2:"40";s:3:"ako";s:2:"41";s:3:"ist";s:2:"42";s:3:"mu ";s:2:"43";s:3:"ame";s:2:"44";s:3:"ent";s:2:"45";s:3:"ky ";s:2:"46";s:3:"la ";s:2:"47";s:3:"pod";s:2:"48";s:3:" ve";s:2:"49";s:3:" ob";s:2:"50";s:3:"om ";s:2:"51";s:3:"vat";s:2:"52";s:3:" ko";s:2:"53";s:3:"sta";s:2:"54";s:3:"em ";s:2:"55";s:3:"le ";s:2:"56";s:3:"a v";s:2:"57";s:3:"by ";s:2:"58";s:3:"e p";s:2:"59";s:3:"ko ";s:2:"60";s:3:"eri";s:2:"61";s:3:"kte";s:2:"62";s:3:"sa ";s:2:"63";s:4:"ého";s:2:"64";s:3:"e v";s:2:"65";s:3:"mer";s:2:"66";s:3:"tel";s:2:"67";s:3:" ak";s:2:"68";s:3:" sv";s:2:"69";s:4:" zá";s:2:"70";s:3:"hla";s:2:"71";s:3:"las";s:2:"72";s:3:"lo ";s:2:"73";s:3:" ta";s:2:"74";s:3:"a n";s:2:"75";s:3:"ej ";s:2:"76";s:3:"li ";s:2:"77";s:3:"ne ";s:2:"78";s:3:" sa";s:2:"79";s:3:"ak ";s:2:"80";s:3:"ani";s:2:"81";s:3:"ate";s:2:"82";s:3:"ia ";s:2:"83";s:3:"sou";s:2:"84";s:3:" so";s:2:"85";s:4:"ení";s:2:"86";s:3:"ie ";s:2:"87";s:3:" re";s:2:"88";s:3:"ce ";s:2:"89";s:3:"e n";s:2:"90";s:3:"ori";s:2:"91";s:3:"tic";s:2:"92";s:3:" vy";s:2:"93";s:3:"a t";s:2:"94";s:4:"ké ";s:2:"95";s:3:"nos";s:2:"96";s:3:"o s";s:2:"97";s:3:"str";s:2:"98";s:3:"ti ";s:2:"99";s:3:"uje";s:3:"100";s:3:" sp";s:3:"101";s:3:"lov";s:3:"102";s:3:"o p";s:3:"103";s:3:"oli";s:3:"104";s:4:"ová";s:3:"105";s:4:" ná";s:3:"106";s:3:"ale";s:3:"107";s:3:"den";s:3:"108";s:3:"e o";s:3:"109";s:3:"ku ";s:3:"110";s:3:"val";s:3:"111";s:3:" am";s:3:"112";s:3:" ro";s:3:"113";s:3:" si";s:3:"114";s:3:"nie";s:3:"115";s:3:"pol";s:3:"116";s:3:"tra";s:3:"117";s:3:" al";s:3:"118";s:3:"ali";s:3:"119";s:3:"o v";s:3:"120";s:3:"tor";s:3:"121";s:3:" mo";s:3:"122";s:3:" ni";s:3:"123";s:3:"ci ";s:3:"124";s:3:"o n";s:3:"125";s:4:"ím ";s:3:"126";s:3:" le";s:3:"127";s:3:" pa";s:3:"128";s:3:" s ";s:3:"129";s:3:"al ";s:3:"130";s:3:"ati";s:3:"131";s:3:"ero";s:3:"132";s:3:"ove";s:3:"133";s:3:"rov";s:3:"134";s:4:"ván";s:3:"135";s:4:"ích";s:3:"136";s:3:" ja";s:3:"137";s:3:" z ";s:3:"138";s:4:"cké";s:3:"139";s:3:"e z";s:3:"140";s:3:" od";s:3:"141";s:3:"byl";s:3:"142";s:3:"de ";s:3:"143";s:3:"dob";s:3:"144";s:3:"nep";s:3:"145";s:3:"pra";s:3:"146";s:3:"ric";s:3:"147";s:3:"spo";s:3:"148";s:3:"tak";s:3:"149";s:4:" vÅ¡";s:3:"150";s:3:"a a";s:3:"151";s:3:"e t";s:3:"152";s:3:"lit";s:3:"153";s:3:"me ";s:3:"154";s:3:"nej";s:3:"155";s:3:"no ";s:3:"156";s:4:"nýc";s:3:"157";s:3:"o t";s:3:"158";s:3:"a j";s:3:"159";s:3:"e a";s:3:"160";s:3:"en ";s:3:"161";s:3:"est";s:3:"162";s:4:"jí ";s:3:"163";s:3:"mi ";s:3:"164";s:3:"slo";s:3:"165";s:4:"stá";s:3:"166";s:3:"u v";s:3:"167";s:3:"for";s:3:"168";s:3:"nou";s:3:"169";s:3:"pos";s:3:"170";s:4:"pÅ™e";s:3:"171";s:3:"si ";s:3:"172";s:3:"tom";s:3:"173";s:3:" vl";s:3:"174";s:3:"a z";s:3:"175";s:3:"ly ";s:3:"176";s:3:"orm";s:3:"177";s:3:"ris";s:3:"178";s:3:"za ";s:3:"179";s:4:"zák";s:3:"180";s:3:" k ";s:3:"181";s:3:"at ";s:3:"182";s:4:"cký";s:3:"183";s:3:"dno";s:3:"184";s:3:"dos";s:3:"185";s:3:"dy ";s:3:"186";s:3:"jak";s:3:"187";s:3:"kov";s:3:"188";s:3:"ny ";s:3:"189";s:3:"res";s:3:"190";s:3:"ror";s:3:"191";s:3:"sto";s:3:"192";s:3:"van";s:3:"193";s:3:" op";s:3:"194";s:3:"da ";s:3:"195";s:3:"do ";s:3:"196";s:3:"e j";s:3:"197";s:3:"hod";s:3:"198";s:3:"len";s:3:"199";s:4:"ný ";s:3:"200";s:3:"o z";s:3:"201";s:3:"poz";s:3:"202";s:3:"pri";s:3:"203";s:3:"ran";s:3:"204";s:3:"u s";s:3:"205";s:3:" ab";s:3:"206";s:3:"aj ";s:3:"207";s:3:"ast";s:3:"208";s:3:"it ";s:3:"209";s:3:"kto";s:3:"210";s:3:"o o";s:3:"211";s:3:"oby";s:3:"212";s:3:"odo";s:3:"213";s:3:"u p";s:3:"214";s:3:"va ";s:3:"215";s:5:"ání";s:3:"216";s:4:"í p";s:3:"217";s:4:"ým ";s:3:"218";s:3:" in";s:3:"219";s:3:" mi";s:3:"220";s:4:"aÅ¥ ";s:3:"221";s:3:"dov";s:3:"222";s:3:"ka ";s:3:"223";s:3:"nsk";s:3:"224";s:4:"áln";s:3:"225";s:3:" an";s:3:"226";s:3:" bu";s:3:"227";s:3:" sl";s:3:"228";s:3:" tr";s:3:"229";s:3:"e m";s:3:"230";s:3:"ech";s:3:"231";s:3:"edn";s:3:"232";s:3:"i n";s:3:"233";s:4:"kýc";s:3:"234";s:4:"níc";s:3:"235";s:3:"ov ";s:3:"236";s:5:"pří";s:3:"237";s:4:"í a";s:3:"238";s:3:" aj";s:3:"239";s:3:" bo";s:3:"240";s:3:"a d";s:3:"241";s:3:"ide";s:3:"242";s:3:"o a";s:3:"243";s:3:"o d";s:3:"244";s:3:"och";s:3:"245";s:3:"pov";s:3:"246";s:3:"svo";s:3:"247";s:4:"é s";s:3:"248";s:3:" kd";s:3:"249";s:3:" vo";s:3:"250";s:4:" vý";s:3:"251";s:3:"bud";s:3:"252";s:3:"ich";s:3:"253";s:3:"il ";s:3:"254";s:3:"ili";s:3:"255";s:3:"ni ";s:3:"256";s:4:"ním";s:3:"257";s:3:"od ";s:3:"258";s:3:"osl";s:3:"259";s:3:"ouh";s:3:"260";s:3:"rav";s:3:"261";s:3:"roz";s:3:"262";s:3:"st ";s:3:"263";s:3:"stv";s:3:"264";s:3:"tu ";s:3:"265";s:3:"u a";s:3:"266";s:4:"vál";s:3:"267";s:3:"y s";s:3:"268";s:4:"í s";s:3:"269";s:4:"í v";s:3:"270";s:3:" hl";s:3:"271";s:3:" li";s:3:"272";s:3:" me";s:3:"273";s:3:"a m";s:3:"274";s:3:"e b";s:3:"275";s:3:"h s";s:3:"276";s:3:"i p";s:3:"277";s:3:"i s";s:3:"278";s:3:"iti";s:3:"279";s:4:"lád";s:3:"280";s:3:"nem";s:3:"281";s:3:"nov";s:3:"282";s:3:"opo";s:3:"283";s:3:"uhl";s:3:"284";s:3:"eno";s:3:"285";s:3:"ens";s:3:"286";s:3:"men";s:3:"287";s:3:"nes";s:3:"288";s:3:"obo";s:3:"289";s:3:"te ";s:3:"290";s:3:"ved";s:3:"291";s:4:"vlá";s:3:"292";s:3:"y n";s:3:"293";s:3:" ma";s:3:"294";s:3:" mu";s:3:"295";s:4:" vá";s:3:"296";s:3:"bez";s:3:"297";s:3:"byv";s:3:"298";s:3:"cho";s:3:"299";}s:7:"slovene";a:300:{s:3:"je ";s:1:"0";s:3:" pr";s:1:"1";s:3:" po";s:1:"2";s:3:" je";s:1:"3";s:3:" v ";s:1:"4";s:3:" za";s:1:"5";s:3:" na";s:1:"6";s:3:"pre";s:1:"7";s:3:"da ";s:1:"8";s:3:" da";s:1:"9";s:3:"ki ";s:2:"10";s:3:"ti ";s:2:"11";s:3:"ja ";s:2:"12";s:3:"ne ";s:2:"13";s:3:" in";s:2:"14";s:3:"in ";s:2:"15";s:3:"li ";s:2:"16";s:3:"no ";s:2:"17";s:3:"na ";s:2:"18";s:3:"ni ";s:2:"19";s:3:" bi";s:2:"20";s:3:"jo ";s:2:"21";s:3:" ne";s:2:"22";s:3:"nje";s:2:"23";s:3:"e p";s:2:"24";s:3:"i p";s:2:"25";s:3:"pri";s:2:"26";s:3:"o p";s:2:"27";s:3:"red";s:2:"28";s:3:" do";s:2:"29";s:3:"anj";s:2:"30";s:3:"em ";s:2:"31";s:3:"ih ";s:2:"32";s:3:" bo";s:2:"33";s:3:" ki";s:2:"34";s:3:" iz";s:2:"35";s:3:" se";s:2:"36";s:3:" so";s:2:"37";s:3:"al ";s:2:"38";s:3:" de";s:2:"39";s:3:"e v";s:2:"40";s:3:"i s";s:2:"41";s:3:"ko ";s:2:"42";s:3:"bil";s:2:"43";s:3:"ira";s:2:"44";s:3:"ove";s:2:"45";s:3:" br";s:2:"46";s:3:" ob";s:2:"47";s:3:"e b";s:2:"48";s:3:"i n";s:2:"49";s:3:"ova";s:2:"50";s:3:"se ";s:2:"51";s:3:"za ";s:2:"52";s:3:"la ";s:2:"53";s:3:" ja";s:2:"54";s:3:"ati";s:2:"55";s:3:"so ";s:2:"56";s:3:"ter";s:2:"57";s:3:" ta";s:2:"58";s:3:"a s";s:2:"59";s:3:"del";s:2:"60";s:3:"e d";s:2:"61";s:3:" dr";s:2:"62";s:3:" od";s:2:"63";s:3:"a n";s:2:"64";s:3:"ar ";s:2:"65";s:3:"jal";s:2:"66";s:3:"ji ";s:2:"67";s:3:"rit";s:2:"68";s:3:" ka";s:2:"69";s:3:" ko";s:2:"70";s:3:" pa";s:2:"71";s:3:"a b";s:2:"72";s:3:"ani";s:2:"73";s:3:"e s";s:2:"74";s:3:"er ";s:2:"75";s:3:"ili";s:2:"76";s:3:"lov";s:2:"77";s:3:"o v";s:2:"78";s:3:"tov";s:2:"79";s:3:" ir";s:2:"80";s:3:" ni";s:2:"81";s:3:" vo";s:2:"82";s:3:"a j";s:2:"83";s:3:"bi ";s:2:"84";s:3:"bri";s:2:"85";s:3:"iti";s:2:"86";s:3:"let";s:2:"87";s:3:"o n";s:2:"88";s:3:"tan";s:2:"89";s:4:"Å¡e ";s:2:"90";s:3:" le";s:2:"91";s:3:" te";s:2:"92";s:3:"eni";s:2:"93";s:3:"eri";s:2:"94";s:3:"ita";s:2:"95";s:3:"kat";s:2:"96";s:3:"por";s:2:"97";s:3:"pro";s:2:"98";s:3:"ali";s:2:"99";s:3:"ke ";s:3:"100";s:3:"oli";s:3:"101";s:3:"ov ";s:3:"102";s:3:"pra";s:3:"103";s:3:"ri ";s:3:"104";s:3:"uar";s:3:"105";s:3:"ve ";s:3:"106";s:3:" to";s:3:"107";s:3:"a i";s:3:"108";s:3:"a v";s:3:"109";s:3:"ako";s:3:"110";s:3:"arj";s:3:"111";s:3:"ate";s:3:"112";s:3:"di ";s:3:"113";s:3:"do ";s:3:"114";s:3:"ga ";s:3:"115";s:3:"le ";s:3:"116";s:3:"lo ";s:3:"117";s:3:"mer";s:3:"118";s:3:"o s";s:3:"119";s:3:"oda";s:3:"120";s:3:"oro";s:3:"121";s:3:"pod";s:3:"122";s:3:" ma";s:3:"123";s:3:" mo";s:3:"124";s:3:" si";s:3:"125";s:3:"a p";s:3:"126";s:3:"bod";s:3:"127";s:3:"e n";s:3:"128";s:3:"ega";s:3:"129";s:3:"ju ";s:3:"130";s:3:"ka ";s:3:"131";s:3:"lje";s:3:"132";s:3:"rav";s:3:"133";s:3:"ta ";s:3:"134";s:3:"a o";s:3:"135";s:3:"e t";s:3:"136";s:3:"e z";s:3:"137";s:3:"i d";s:3:"138";s:3:"i v";s:3:"139";s:3:"ila";s:3:"140";s:3:"lit";s:3:"141";s:3:"nih";s:3:"142";s:3:"odo";s:3:"143";s:3:"sti";s:3:"144";s:3:"to ";s:3:"145";s:3:"var";s:3:"146";s:3:"ved";s:3:"147";s:3:"vol";s:3:"148";s:3:" la";s:3:"149";s:3:" no";s:3:"150";s:3:" vs";s:3:"151";s:3:"a d";s:3:"152";s:3:"agu";s:3:"153";s:3:"aja";s:3:"154";s:3:"dej";s:3:"155";s:3:"dnj";s:3:"156";s:3:"eda";s:3:"157";s:3:"gov";s:3:"158";s:3:"gua";s:3:"159";s:3:"jag";s:3:"160";s:3:"jem";s:3:"161";s:3:"kon";s:3:"162";s:3:"ku ";s:3:"163";s:3:"nij";s:3:"164";s:3:"omo";s:3:"165";s:4:"oÄi";s:3:"166";s:3:"pov";s:3:"167";s:3:"rak";s:3:"168";s:3:"rja";s:3:"169";s:3:"sta";s:3:"170";s:3:"tev";s:3:"171";s:3:"a t";s:3:"172";s:3:"aj ";s:3:"173";s:3:"ed ";s:3:"174";s:3:"eja";s:3:"175";s:3:"ent";s:3:"176";s:3:"ev ";s:3:"177";s:3:"i i";s:3:"178";s:3:"i o";s:3:"179";s:3:"ijo";s:3:"180";s:3:"ist";s:3:"181";s:3:"ost";s:3:"182";s:3:"ske";s:3:"183";s:3:"str";s:3:"184";s:3:" ra";s:3:"185";s:3:" s ";s:3:"186";s:3:" tr";s:3:"187";s:4:" Å¡e";s:3:"188";s:3:"arn";s:3:"189";s:3:"bo ";s:3:"190";s:4:"drž";s:3:"191";s:3:"i j";s:3:"192";s:3:"ilo";s:3:"193";s:3:"izv";s:3:"194";s:3:"jen";s:3:"195";s:3:"lja";s:3:"196";s:3:"nsk";s:3:"197";s:3:"o d";s:3:"198";s:3:"o i";s:3:"199";s:3:"om ";s:3:"200";s:3:"ora";s:3:"201";s:3:"ovo";s:3:"202";s:3:"raz";s:3:"203";s:4:"rža";s:3:"204";s:3:"tak";s:3:"205";s:3:"va ";s:3:"206";s:3:"ven";s:3:"207";s:4:"žav";s:3:"208";s:3:" me";s:3:"209";s:4:" Äe";s:3:"210";s:3:"ame";s:3:"211";s:3:"avi";s:3:"212";s:3:"e i";s:3:"213";s:3:"e o";s:3:"214";s:3:"eka";s:3:"215";s:3:"gre";s:3:"216";s:3:"i t";s:3:"217";s:3:"ija";s:3:"218";s:3:"il ";s:3:"219";s:3:"ite";s:3:"220";s:3:"kra";s:3:"221";s:3:"lju";s:3:"222";s:3:"mor";s:3:"223";s:3:"nik";s:3:"224";s:3:"o t";s:3:"225";s:3:"obi";s:3:"226";s:3:"odn";s:3:"227";s:3:"ran";s:3:"228";s:3:"re ";s:3:"229";s:3:"sto";s:3:"230";s:3:"stv";s:3:"231";s:3:"udi";s:3:"232";s:3:"v i";s:3:"233";s:3:"van";s:3:"234";s:3:" am";s:3:"235";s:3:" sp";s:3:"236";s:3:" st";s:3:"237";s:3:" tu";s:3:"238";s:3:" ve";s:3:"239";s:4:" že";s:3:"240";s:3:"ajo";s:3:"241";s:3:"ale";s:3:"242";s:3:"apo";s:3:"243";s:3:"dal";s:3:"244";s:3:"dru";s:3:"245";s:3:"e j";s:3:"246";s:3:"edn";s:3:"247";s:3:"ejo";s:3:"248";s:3:"elo";s:3:"249";s:3:"est";s:3:"250";s:3:"etj";s:3:"251";s:3:"eva";s:3:"252";s:3:"iji";s:3:"253";s:3:"ik ";s:3:"254";s:3:"im ";s:3:"255";s:3:"itv";s:3:"256";s:3:"mob";s:3:"257";s:3:"nap";s:3:"258";s:3:"nek";s:3:"259";s:3:"pol";s:3:"260";s:3:"pos";s:3:"261";s:3:"rat";s:3:"262";s:3:"ski";s:3:"263";s:4:"tiÄ";s:3:"264";s:3:"tom";s:3:"265";s:3:"ton";s:3:"266";s:3:"tra";s:3:"267";s:3:"tud";s:3:"268";s:3:"tve";s:3:"269";s:3:"v b";s:3:"270";s:3:"vil";s:3:"271";s:3:"vse";s:3:"272";s:4:"Äit";s:3:"273";s:3:" av";s:3:"274";s:3:" gr";s:3:"275";s:3:"a z";s:3:"276";s:3:"ans";s:3:"277";s:3:"ast";s:3:"278";s:3:"avt";s:3:"279";s:3:"dan";s:3:"280";s:3:"e m";s:3:"281";s:3:"eds";s:3:"282";s:3:"for";s:3:"283";s:3:"i z";s:3:"284";s:3:"kot";s:3:"285";s:3:"mi ";s:3:"286";s:3:"nim";s:3:"287";s:3:"o b";s:3:"288";s:3:"o o";s:3:"289";s:3:"od ";s:3:"290";s:3:"odl";s:3:"291";s:3:"oiz";s:3:"292";s:3:"ot ";s:3:"293";s:3:"par";s:3:"294";s:3:"pot";s:3:"295";s:3:"rje";s:3:"296";s:3:"roi";s:3:"297";s:3:"tem";s:3:"298";s:3:"val";s:3:"299";}s:6:"somali";a:300:{s:3:"ka ";s:1:"0";s:3:"ay ";s:1:"1";s:3:"da ";s:1:"2";s:3:" ay";s:1:"3";s:3:"aal";s:1:"4";s:3:"oo ";s:1:"5";s:3:"aan";s:1:"6";s:3:" ka";s:1:"7";s:3:"an ";s:1:"8";s:3:"in ";s:1:"9";s:3:" in";s:2:"10";s:3:"ada";s:2:"11";s:3:"maa";s:2:"12";s:3:"aba";s:2:"13";s:3:" so";s:2:"14";s:3:"ali";s:2:"15";s:3:"bad";s:2:"16";s:3:"add";s:2:"17";s:3:"soo";s:2:"18";s:3:" na";s:2:"19";s:3:"aha";s:2:"20";s:3:"ku ";s:2:"21";s:3:"ta ";s:2:"22";s:3:" wa";s:2:"23";s:3:"yo ";s:2:"24";s:3:"a s";s:2:"25";s:3:"oma";s:2:"26";s:3:"yaa";s:2:"27";s:3:" ba";s:2:"28";s:3:" ku";s:2:"29";s:3:" la";s:2:"30";s:3:" oo";s:2:"31";s:3:"iya";s:2:"32";s:3:"sha";s:2:"33";s:3:"a a";s:2:"34";s:3:"dda";s:2:"35";s:3:"nab";s:2:"36";s:3:"nta";s:2:"37";s:3:" da";s:2:"38";s:3:" ma";s:2:"39";s:3:"nka";s:2:"40";s:3:"uu ";s:2:"41";s:3:"y i";s:2:"42";s:3:"aya";s:2:"43";s:3:"ha ";s:2:"44";s:3:"raa";s:2:"45";s:3:" dh";s:2:"46";s:3:" qa";s:2:"47";s:3:"a k";s:2:"48";s:3:"ala";s:2:"49";s:3:"baa";s:2:"50";s:3:"doo";s:2:"51";s:3:"had";s:2:"52";s:3:"liy";s:2:"53";s:3:"oom";s:2:"54";s:3:" ha";s:2:"55";s:3:" sh";s:2:"56";s:3:"a d";s:2:"57";s:3:"a i";s:2:"58";s:3:"a n";s:2:"59";s:3:"aar";s:2:"60";s:3:"ee ";s:2:"61";s:3:"ey ";s:2:"62";s:3:"y k";s:2:"63";s:3:"ya ";s:2:"64";s:3:" ee";s:2:"65";s:3:" iy";s:2:"66";s:3:"aa ";s:2:"67";s:3:"aaq";s:2:"68";s:3:"gaa";s:2:"69";s:3:"lam";s:2:"70";s:3:" bu";s:2:"71";s:3:"a b";s:2:"72";s:3:"a m";s:2:"73";s:3:"ad ";s:2:"74";s:3:"aga";s:2:"75";s:3:"ama";s:2:"76";s:3:"iyo";s:2:"77";s:3:"la ";s:2:"78";s:3:"a c";s:2:"79";s:3:"a l";s:2:"80";s:3:"een";s:2:"81";s:3:"int";s:2:"82";s:3:"she";s:2:"83";s:3:"wax";s:2:"84";s:3:"yee";s:2:"85";s:3:" si";s:2:"86";s:3:" uu";s:2:"87";s:3:"a h";s:2:"88";s:3:"aas";s:2:"89";s:3:"alk";s:2:"90";s:3:"dha";s:2:"91";s:3:"gu ";s:2:"92";s:3:"hee";s:2:"93";s:3:"ii ";s:2:"94";s:3:"ira";s:2:"95";s:3:"mad";s:2:"96";s:3:"o a";s:2:"97";s:3:"o k";s:2:"98";s:3:"qay";s:2:"99";s:3:" ah";s:3:"100";s:3:" ca";s:3:"101";s:3:" wu";s:3:"102";s:3:"ank";s:3:"103";s:3:"ash";s:3:"104";s:3:"axa";s:3:"105";s:3:"eed";s:3:"106";s:3:"en ";s:3:"107";s:3:"ga ";s:3:"108";s:3:"haa";s:3:"109";s:3:"n a";s:3:"110";s:3:"n s";s:3:"111";s:3:"naa";s:3:"112";s:3:"nay";s:3:"113";s:3:"o d";s:3:"114";s:3:"taa";s:3:"115";s:3:"u b";s:3:"116";s:3:"uxu";s:3:"117";s:3:"wux";s:3:"118";s:3:"xuu";s:3:"119";s:3:" ci";s:3:"120";s:3:" do";s:3:"121";s:3:" ho";s:3:"122";s:3:" ta";s:3:"123";s:3:"a g";s:3:"124";s:3:"a u";s:3:"125";s:3:"ana";s:3:"126";s:3:"ayo";s:3:"127";s:3:"dhi";s:3:"128";s:3:"iin";s:3:"129";s:3:"lag";s:3:"130";s:3:"lin";s:3:"131";s:3:"lka";s:3:"132";s:3:"o i";s:3:"133";s:3:"san";s:3:"134";s:3:"u s";s:3:"135";s:3:"una";s:3:"136";s:3:"uun";s:3:"137";s:3:" ga";s:3:"138";s:3:" xa";s:3:"139";s:3:" xu";s:3:"140";s:3:"aab";s:3:"141";s:3:"abt";s:3:"142";s:3:"aq ";s:3:"143";s:3:"aqa";s:3:"144";s:3:"ara";s:3:"145";s:3:"arl";s:3:"146";s:3:"caa";s:3:"147";s:3:"cir";s:3:"148";s:3:"eeg";s:3:"149";s:3:"eel";s:3:"150";s:3:"isa";s:3:"151";s:3:"kal";s:3:"152";s:3:"lah";s:3:"153";s:3:"ney";s:3:"154";s:3:"qaa";s:3:"155";s:3:"rla";s:3:"156";s:3:"sad";s:3:"157";s:3:"sii";s:3:"158";s:3:"u d";s:3:"159";s:3:"wad";s:3:"160";s:3:" ad";s:3:"161";s:3:" ar";s:3:"162";s:3:" di";s:3:"163";s:3:" jo";s:3:"164";s:3:" ra";s:3:"165";s:3:" sa";s:3:"166";s:3:" u ";s:3:"167";s:3:" yi";s:3:"168";s:3:"a j";s:3:"169";s:3:"a q";s:3:"170";s:3:"aad";s:3:"171";s:3:"aat";s:3:"172";s:3:"aay";s:3:"173";s:3:"ah ";s:3:"174";s:3:"ale";s:3:"175";s:3:"amk";s:3:"176";s:3:"ari";s:3:"177";s:3:"as ";s:3:"178";s:3:"aye";s:3:"179";s:3:"bus";s:3:"180";s:3:"dal";s:3:"181";s:3:"ddu";s:3:"182";s:3:"dii";s:3:"183";s:3:"du ";s:3:"184";s:3:"duu";s:3:"185";s:3:"ed ";s:3:"186";s:3:"ege";s:3:"187";s:3:"gey";s:3:"188";s:3:"hay";s:3:"189";s:3:"hii";s:3:"190";s:3:"ida";s:3:"191";s:3:"ine";s:3:"192";s:3:"joo";s:3:"193";s:3:"laa";s:3:"194";s:3:"lay";s:3:"195";s:3:"mar";s:3:"196";s:3:"mee";s:3:"197";s:3:"n b";s:3:"198";s:3:"n d";s:3:"199";s:3:"n m";s:3:"200";s:3:"no ";s:3:"201";s:3:"o b";s:3:"202";s:3:"o l";s:3:"203";s:3:"oog";s:3:"204";s:3:"oon";s:3:"205";s:3:"rga";s:3:"206";s:3:"sh ";s:3:"207";s:3:"sid";s:3:"208";s:3:"u q";s:3:"209";s:3:"unk";s:3:"210";s:3:"ush";s:3:"211";s:3:"xa ";s:3:"212";s:3:"y d";s:3:"213";s:3:" bi";s:3:"214";s:3:" gu";s:3:"215";s:3:" is";s:3:"216";s:3:" ke";s:3:"217";s:3:" lo";s:3:"218";s:3:" me";s:3:"219";s:3:" mu";s:3:"220";s:3:" qo";s:3:"221";s:3:" ug";s:3:"222";s:3:"a e";s:3:"223";s:3:"a o";s:3:"224";s:3:"a w";s:3:"225";s:3:"adi";s:3:"226";s:3:"ado";s:3:"227";s:3:"agu";s:3:"228";s:3:"al ";s:3:"229";s:3:"ant";s:3:"230";s:3:"ark";s:3:"231";s:3:"asa";s:3:"232";s:3:"awi";s:3:"233";s:3:"bta";s:3:"234";s:3:"bul";s:3:"235";s:3:"d a";s:3:"236";s:3:"dag";s:3:"237";s:3:"dan";s:3:"238";s:3:"do ";s:3:"239";s:3:"e s";s:3:"240";s:3:"gal";s:3:"241";s:3:"gay";s:3:"242";s:3:"guu";s:3:"243";s:3:"h e";s:3:"244";s:3:"hal";s:3:"245";s:3:"iga";s:3:"246";s:3:"ihi";s:3:"247";s:3:"iri";s:3:"248";s:3:"iye";s:3:"249";s:3:"ken";s:3:"250";s:3:"lad";s:3:"251";s:3:"lid";s:3:"252";s:3:"lsh";s:3:"253";s:3:"mag";s:3:"254";s:3:"mun";s:3:"255";s:3:"n h";s:3:"256";s:3:"n i";s:3:"257";s:3:"na ";s:3:"258";s:3:"o n";s:3:"259";s:3:"o w";s:3:"260";s:3:"ood";s:3:"261";s:3:"oor";s:3:"262";s:3:"ora";s:3:"263";s:3:"qab";s:3:"264";s:3:"qor";s:3:"265";s:3:"rab";s:3:"266";s:3:"rit";s:3:"267";s:3:"rta";s:3:"268";s:3:"s o";s:3:"269";s:3:"sab";s:3:"270";s:3:"ska";s:3:"271";s:3:"to ";s:3:"272";s:3:"u a";s:3:"273";s:3:"u h";s:3:"274";s:3:"u u";s:3:"275";s:3:"ud ";s:3:"276";s:3:"ugu";s:3:"277";s:3:"uls";s:3:"278";s:3:"uud";s:3:"279";s:3:"waa";s:3:"280";s:3:"xus";s:3:"281";s:3:"y b";s:3:"282";s:3:"y q";s:3:"283";s:3:"y s";s:3:"284";s:3:"yad";s:3:"285";s:3:"yay";s:3:"286";s:3:"yih";s:3:"287";s:3:" aa";s:3:"288";s:3:" bo";s:3:"289";s:3:" br";s:3:"290";s:3:" go";s:3:"291";s:3:" ji";s:3:"292";s:3:" mi";s:3:"293";s:3:" of";s:3:"294";s:3:" ti";s:3:"295";s:3:" um";s:3:"296";s:3:" wi";s:3:"297";s:3:" xo";s:3:"298";s:3:"a x";s:3:"299";}s:7:"spanish";a:300:{s:3:" de";s:1:"0";s:3:"de ";s:1:"1";s:3:" la";s:1:"2";s:3:"os ";s:1:"3";s:3:"la ";s:1:"4";s:3:"el ";s:1:"5";s:3:"es ";s:1:"6";s:3:" qu";s:1:"7";s:3:" co";s:1:"8";s:3:"e l";s:1:"9";s:3:"as ";s:2:"10";s:3:"que";s:2:"11";s:3:" el";s:2:"12";s:3:"ue ";s:2:"13";s:3:"en ";s:2:"14";s:3:"ent";s:2:"15";s:3:" en";s:2:"16";s:3:" se";s:2:"17";s:3:"nte";s:2:"18";s:3:"res";s:2:"19";s:3:"con";s:2:"20";s:3:"est";s:2:"21";s:3:" es";s:2:"22";s:3:"s d";s:2:"23";s:3:" lo";s:2:"24";s:3:" pr";s:2:"25";s:3:"los";s:2:"26";s:3:" y ";s:2:"27";s:3:"do ";s:2:"28";s:4:"ón ";s:2:"29";s:4:"ión";s:2:"30";s:3:" un";s:2:"31";s:4:"ció";s:2:"32";s:3:"del";s:2:"33";s:3:"o d";s:2:"34";s:3:" po";s:2:"35";s:3:"a d";s:2:"36";s:3:"aci";s:2:"37";s:3:"sta";s:2:"38";s:3:"te ";s:2:"39";s:3:"ado";s:2:"40";s:3:"pre";s:2:"41";s:3:"to ";s:2:"42";s:3:"par";s:2:"43";s:3:"a e";s:2:"44";s:3:"a l";s:2:"45";s:3:"ra ";s:2:"46";s:3:"al ";s:2:"47";s:3:"e e";s:2:"48";s:3:"se ";s:2:"49";s:3:"pro";s:2:"50";s:3:"ar ";s:2:"51";s:3:"ia ";s:2:"52";s:3:"o e";s:2:"53";s:3:" re";s:2:"54";s:3:"ida";s:2:"55";s:3:"dad";s:2:"56";s:3:"tra";s:2:"57";s:3:"por";s:2:"58";s:3:"s p";s:2:"59";s:3:" a ";s:2:"60";s:3:"a p";s:2:"61";s:3:"ara";s:2:"62";s:3:"cia";s:2:"63";s:3:" pa";s:2:"64";s:3:"com";s:2:"65";s:3:"no ";s:2:"66";s:3:" di";s:2:"67";s:3:" in";s:2:"68";s:3:"ien";s:2:"69";s:3:"n l";s:2:"70";s:3:"ad ";s:2:"71";s:3:"ant";s:2:"72";s:3:"e s";s:2:"73";s:3:"men";s:2:"74";s:3:"a c";s:2:"75";s:3:"on ";s:2:"76";s:3:"un ";s:2:"77";s:3:"las";s:2:"78";s:3:"nci";s:2:"79";s:3:" tr";s:2:"80";s:3:"cio";s:2:"81";s:3:"ier";s:2:"82";s:3:"nto";s:2:"83";s:3:"tiv";s:2:"84";s:3:"n d";s:2:"85";s:3:"n e";s:2:"86";s:3:"or ";s:2:"87";s:3:"s c";s:2:"88";s:3:"enc";s:2:"89";s:3:"ern";s:2:"90";s:3:"io ";s:2:"91";s:3:"a s";s:2:"92";s:3:"ici";s:2:"93";s:3:"s e";s:2:"94";s:3:" ma";s:2:"95";s:3:"dos";s:2:"96";s:3:"e a";s:2:"97";s:3:"e c";s:2:"98";s:3:"emp";s:2:"99";s:3:"ica";s:3:"100";s:3:"ivo";s:3:"101";s:3:"l p";s:3:"102";s:3:"n c";s:3:"103";s:3:"r e";s:3:"104";s:3:"ta ";s:3:"105";s:3:"ter";s:3:"106";s:3:"e d";s:3:"107";s:3:"esa";s:3:"108";s:3:"ez ";s:3:"109";s:3:"mpr";s:3:"110";s:3:"o a";s:3:"111";s:3:"s a";s:3:"112";s:3:" ca";s:3:"113";s:3:" su";s:3:"114";s:3:"ion";s:3:"115";s:3:" cu";s:3:"116";s:3:" ju";s:3:"117";s:3:"an ";s:3:"118";s:3:"da ";s:3:"119";s:3:"ene";s:3:"120";s:3:"ero";s:3:"121";s:3:"na ";s:3:"122";s:3:"rec";s:3:"123";s:3:"ro ";s:3:"124";s:3:"tar";s:3:"125";s:3:" al";s:3:"126";s:3:" an";s:3:"127";s:3:"bie";s:3:"128";s:3:"e p";s:3:"129";s:3:"er ";s:3:"130";s:3:"l c";s:3:"131";s:3:"n p";s:3:"132";s:3:"omp";s:3:"133";s:3:"ten";s:3:"134";s:3:" em";s:3:"135";s:3:"ist";s:3:"136";s:3:"nes";s:3:"137";s:3:"nta";s:3:"138";s:3:"o c";s:3:"139";s:3:"so ";s:3:"140";s:3:"tes";s:3:"141";s:3:"era";s:3:"142";s:3:"l d";s:3:"143";s:3:"l m";s:3:"144";s:3:"les";s:3:"145";s:3:"ntr";s:3:"146";s:3:"o s";s:3:"147";s:3:"ore";s:3:"148";s:4:"rá ";s:3:"149";s:3:"s q";s:3:"150";s:3:"s y";s:3:"151";s:3:"sto";s:3:"152";s:3:"a a";s:3:"153";s:3:"a r";s:3:"154";s:3:"ari";s:3:"155";s:3:"des";s:3:"156";s:3:"e q";s:3:"157";s:3:"ivi";s:3:"158";s:3:"lic";s:3:"159";s:3:"lo ";s:3:"160";s:3:"n a";s:3:"161";s:3:"one";s:3:"162";s:3:"ora";s:3:"163";s:3:"per";s:3:"164";s:3:"pue";s:3:"165";s:3:"r l";s:3:"166";s:3:"re ";s:3:"167";s:3:"ren";s:3:"168";s:3:"una";s:3:"169";s:4:"ía ";s:3:"170";s:3:"ada";s:3:"171";s:3:"cas";s:3:"172";s:3:"ere";s:3:"173";s:3:"ide";s:3:"174";s:3:"min";s:3:"175";s:3:"n s";s:3:"176";s:3:"ndo";s:3:"177";s:3:"ran";s:3:"178";s:3:"rno";s:3:"179";s:3:" ac";s:3:"180";s:3:" ex";s:3:"181";s:3:" go";s:3:"182";s:3:" no";s:3:"183";s:3:"a t";s:3:"184";s:3:"aba";s:3:"185";s:3:"ble";s:3:"186";s:3:"ece";s:3:"187";s:3:"ect";s:3:"188";s:3:"l a";s:3:"189";s:3:"l g";s:3:"190";s:3:"lid";s:3:"191";s:3:"nsi";s:3:"192";s:3:"ons";s:3:"193";s:3:"rac";s:3:"194";s:3:"rio";s:3:"195";s:3:"str";s:3:"196";s:3:"uer";s:3:"197";s:3:"ust";s:3:"198";s:3:" ha";s:3:"199";s:3:" le";s:3:"200";s:3:" mi";s:3:"201";s:3:" mu";s:3:"202";s:3:" ob";s:3:"203";s:3:" pe";s:3:"204";s:3:" pu";s:3:"205";s:3:" so";s:3:"206";s:3:"a i";s:3:"207";s:3:"ale";s:3:"208";s:3:"ca ";s:3:"209";s:3:"cto";s:3:"210";s:3:"e i";s:3:"211";s:3:"e u";s:3:"212";s:3:"eso";s:3:"213";s:3:"fer";s:3:"214";s:3:"fic";s:3:"215";s:3:"gob";s:3:"216";s:3:"jo ";s:3:"217";s:3:"ma ";s:3:"218";s:3:"mpl";s:3:"219";s:3:"o p";s:3:"220";s:3:"obi";s:3:"221";s:3:"s m";s:3:"222";s:3:"sa ";s:3:"223";s:3:"sep";s:3:"224";s:3:"ste";s:3:"225";s:3:"sti";s:3:"226";s:3:"tad";s:3:"227";s:3:"tod";s:3:"228";s:3:"y s";s:3:"229";s:3:" ci";s:3:"230";s:3:"and";s:3:"231";s:3:"ces";s:3:"232";s:4:"có ";s:3:"233";s:3:"dor";s:3:"234";s:3:"e m";s:3:"235";s:3:"eci";s:3:"236";s:3:"eco";s:3:"237";s:3:"esi";s:3:"238";s:3:"int";s:3:"239";s:3:"iza";s:3:"240";s:3:"l e";s:3:"241";s:3:"lar";s:3:"242";s:3:"mie";s:3:"243";s:3:"ner";s:3:"244";s:3:"orc";s:3:"245";s:3:"rci";s:3:"246";s:3:"ria";s:3:"247";s:3:"tic";s:3:"248";s:3:"tor";s:3:"249";s:3:" as";s:3:"250";s:3:" si";s:3:"251";s:3:"ce ";s:3:"252";s:3:"den";s:3:"253";s:3:"e r";s:3:"254";s:3:"e t";s:3:"255";s:3:"end";s:3:"256";s:3:"eri";s:3:"257";s:3:"esp";s:3:"258";s:3:"ial";s:3:"259";s:3:"ido";s:3:"260";s:3:"ina";s:3:"261";s:3:"inc";s:3:"262";s:3:"mit";s:3:"263";s:3:"o l";s:3:"264";s:3:"ome";s:3:"265";s:3:"pli";s:3:"266";s:3:"ras";s:3:"267";s:3:"s t";s:3:"268";s:3:"sid";s:3:"269";s:3:"sup";s:3:"270";s:3:"tab";s:3:"271";s:3:"uen";s:3:"272";s:3:"ues";s:3:"273";s:3:"ura";s:3:"274";s:3:"vo ";s:3:"275";s:3:"vor";s:3:"276";s:3:" sa";s:3:"277";s:3:" ti";s:3:"278";s:3:"abl";s:3:"279";s:3:"ali";s:3:"280";s:3:"aso";s:3:"281";s:3:"ast";s:3:"282";s:3:"cor";s:3:"283";s:3:"cti";s:3:"284";s:3:"cue";s:3:"285";s:3:"div";s:3:"286";s:3:"duc";s:3:"287";s:3:"ens";s:3:"288";s:3:"eti";s:3:"289";s:3:"imi";s:3:"290";s:3:"ini";s:3:"291";s:3:"lec";s:3:"292";s:3:"o q";s:3:"293";s:3:"oce";s:3:"294";s:3:"ort";s:3:"295";s:3:"ral";s:3:"296";s:3:"rma";s:3:"297";s:3:"roc";s:3:"298";s:3:"rod";s:3:"299";}s:7:"swahili";a:300:{s:3:" wa";s:1:"0";s:3:"wa ";s:1:"1";s:3:"a k";s:1:"2";s:3:"a m";s:1:"3";s:3:" ku";s:1:"4";s:3:" ya";s:1:"5";s:3:"a w";s:1:"6";s:3:"ya ";s:1:"7";s:3:"ni ";s:1:"8";s:3:" ma";s:1:"9";s:3:"ka ";s:2:"10";s:3:"a u";s:2:"11";s:3:"na ";s:2:"12";s:3:"za ";s:2:"13";s:3:"ia ";s:2:"14";s:3:" na";s:2:"15";s:3:"ika";s:2:"16";s:3:"ma ";s:2:"17";s:3:"ali";s:2:"18";s:3:"a n";s:2:"19";s:3:" am";s:2:"20";s:3:"ili";s:2:"21";s:3:"kwa";s:2:"22";s:3:" kw";s:2:"23";s:3:"ini";s:2:"24";s:3:" ha";s:2:"25";s:3:"ame";s:2:"26";s:3:"ana";s:2:"27";s:3:"i n";s:2:"28";s:3:" za";s:2:"29";s:3:"a h";s:2:"30";s:3:"ema";s:2:"31";s:3:"i m";s:2:"32";s:3:"i y";s:2:"33";s:3:"kuw";s:2:"34";s:3:"la ";s:2:"35";s:3:"o w";s:2:"36";s:3:"a y";s:2:"37";s:3:"ata";s:2:"38";s:3:"sem";s:2:"39";s:3:" la";s:2:"40";s:3:"ati";s:2:"41";s:3:"chi";s:2:"42";s:3:"i w";s:2:"43";s:3:"uwa";s:2:"44";s:3:"aki";s:2:"45";s:3:"li ";s:2:"46";s:3:"eka";s:2:"47";s:3:"ira";s:2:"48";s:3:" nc";s:2:"49";s:3:"a s";s:2:"50";s:3:"iki";s:2:"51";s:3:"kat";s:2:"52";s:3:"nch";s:2:"53";s:3:" ka";s:2:"54";s:3:" ki";s:2:"55";s:3:"a b";s:2:"56";s:3:"aji";s:2:"57";s:3:"amb";s:2:"58";s:3:"ra ";s:2:"59";s:3:"ri ";s:2:"60";s:3:"rik";s:2:"61";s:3:"ada";s:2:"62";s:3:"mat";s:2:"63";s:3:"mba";s:2:"64";s:3:"mes";s:2:"65";s:3:"yo ";s:2:"66";s:3:"zi ";s:2:"67";s:3:"da ";s:2:"68";s:3:"hi ";s:2:"69";s:3:"i k";s:2:"70";s:3:"ja ";s:2:"71";s:3:"kut";s:2:"72";s:3:"tek";s:2:"73";s:3:"wan";s:2:"74";s:3:" bi";s:2:"75";s:3:"a a";s:2:"76";s:3:"aka";s:2:"77";s:3:"ao ";s:2:"78";s:3:"asi";s:2:"79";s:3:"cha";s:2:"80";s:3:"ese";s:2:"81";s:3:"eza";s:2:"82";s:3:"ke ";s:2:"83";s:3:"moj";s:2:"84";s:3:"oja";s:2:"85";s:3:" hi";s:2:"86";s:3:"a z";s:2:"87";s:3:"end";s:2:"88";s:3:"ha ";s:2:"89";s:3:"ji ";s:2:"90";s:3:"mu ";s:2:"91";s:3:"shi";s:2:"92";s:3:"wat";s:2:"93";s:3:" bw";s:2:"94";s:3:"ake";s:2:"95";s:3:"ara";s:2:"96";s:3:"bw ";s:2:"97";s:3:"i h";s:2:"98";s:3:"imb";s:2:"99";s:3:"tik";s:3:"100";s:3:"wak";s:3:"101";s:3:"wal";s:3:"102";s:3:" hu";s:3:"103";s:3:" mi";s:3:"104";s:3:" mk";s:3:"105";s:3:" ni";s:3:"106";s:3:" ra";s:3:"107";s:3:" um";s:3:"108";s:3:"a l";s:3:"109";s:3:"ate";s:3:"110";s:3:"esh";s:3:"111";s:3:"ina";s:3:"112";s:3:"ish";s:3:"113";s:3:"kim";s:3:"114";s:3:"o k";s:3:"115";s:3:" ir";s:3:"116";s:3:"a i";s:3:"117";s:3:"ala";s:3:"118";s:3:"ani";s:3:"119";s:3:"aq ";s:3:"120";s:3:"azi";s:3:"121";s:3:"hin";s:3:"122";s:3:"i a";s:3:"123";s:3:"idi";s:3:"124";s:3:"ima";s:3:"125";s:3:"ita";s:3:"126";s:3:"rai";s:3:"127";s:3:"raq";s:3:"128";s:3:"sha";s:3:"129";s:3:" ms";s:3:"130";s:3:" se";s:3:"131";s:3:"afr";s:3:"132";s:3:"ama";s:3:"133";s:3:"ano";s:3:"134";s:3:"ea ";s:3:"135";s:3:"ele";s:3:"136";s:3:"fri";s:3:"137";s:3:"go ";s:3:"138";s:3:"i i";s:3:"139";s:3:"ifa";s:3:"140";s:3:"iwa";s:3:"141";s:3:"iyo";s:3:"142";s:3:"kus";s:3:"143";s:3:"lia";s:3:"144";s:3:"lio";s:3:"145";s:3:"maj";s:3:"146";s:3:"mku";s:3:"147";s:3:"no ";s:3:"148";s:3:"tan";s:3:"149";s:3:"uli";s:3:"150";s:3:"uta";s:3:"151";s:3:"wen";s:3:"152";s:3:" al";s:3:"153";s:3:"a j";s:3:"154";s:3:"aad";s:3:"155";s:3:"aid";s:3:"156";s:3:"ari";s:3:"157";s:3:"awa";s:3:"158";s:3:"ba ";s:3:"159";s:3:"fa ";s:3:"160";s:3:"nde";s:3:"161";s:3:"nge";s:3:"162";s:3:"nya";s:3:"163";s:3:"o y";s:3:"164";s:3:"u w";s:3:"165";s:3:"ua ";s:3:"166";s:3:"umo";s:3:"167";s:3:"waz";s:3:"168";s:3:"ye ";s:3:"169";s:3:" ut";s:3:"170";s:3:" vi";s:3:"171";s:3:"a d";s:3:"172";s:3:"a t";s:3:"173";s:3:"aif";s:3:"174";s:3:"di ";s:3:"175";s:3:"ere";s:3:"176";s:3:"ing";s:3:"177";s:3:"kin";s:3:"178";s:3:"nda";s:3:"179";s:3:"o n";s:3:"180";s:3:"oa ";s:3:"181";s:3:"tai";s:3:"182";s:3:"toa";s:3:"183";s:3:"usa";s:3:"184";s:3:"uto";s:3:"185";s:3:"was";s:3:"186";s:3:"yak";s:3:"187";s:3:"zo ";s:3:"188";s:3:" ji";s:3:"189";s:3:" mw";s:3:"190";s:3:"a p";s:3:"191";s:3:"aia";s:3:"192";s:3:"amu";s:3:"193";s:3:"ang";s:3:"194";s:3:"bik";s:3:"195";s:3:"bo ";s:3:"196";s:3:"del";s:3:"197";s:3:"e w";s:3:"198";s:3:"ene";s:3:"199";s:3:"eng";s:3:"200";s:3:"ich";s:3:"201";s:3:"iri";s:3:"202";s:3:"iti";s:3:"203";s:3:"ito";s:3:"204";s:3:"ki ";s:3:"205";s:3:"kir";s:3:"206";s:3:"ko ";s:3:"207";s:3:"kuu";s:3:"208";s:3:"mar";s:3:"209";s:3:"mbo";s:3:"210";s:3:"mil";s:3:"211";s:3:"ngi";s:3:"212";s:3:"ngo";s:3:"213";s:3:"o l";s:3:"214";s:3:"ong";s:3:"215";s:3:"si ";s:3:"216";s:3:"ta ";s:3:"217";s:3:"tak";s:3:"218";s:3:"u y";s:3:"219";s:3:"umu";s:3:"220";s:3:"usi";s:3:"221";s:3:"uu ";s:3:"222";s:3:"wam";s:3:"223";s:3:" af";s:3:"224";s:3:" ba";s:3:"225";s:3:" li";s:3:"226";s:3:" si";s:3:"227";s:3:" zi";s:3:"228";s:3:"a v";s:3:"229";s:3:"ami";s:3:"230";s:3:"atu";s:3:"231";s:3:"awi";s:3:"232";s:3:"eri";s:3:"233";s:3:"fan";s:3:"234";s:3:"fur";s:3:"235";s:3:"ger";s:3:"236";s:3:"i z";s:3:"237";s:3:"isi";s:3:"238";s:3:"izo";s:3:"239";s:3:"lea";s:3:"240";s:3:"mbi";s:3:"241";s:3:"mwa";s:3:"242";s:3:"nye";s:3:"243";s:3:"o h";s:3:"244";s:3:"o m";s:3:"245";s:3:"oni";s:3:"246";s:3:"rez";s:3:"247";s:3:"saa";s:3:"248";s:3:"ser";s:3:"249";s:3:"sin";s:3:"250";s:3:"tat";s:3:"251";s:3:"tis";s:3:"252";s:3:"tu ";s:3:"253";s:3:"uin";s:3:"254";s:3:"uki";s:3:"255";s:3:"ur ";s:3:"256";s:3:"wi ";s:3:"257";s:3:"yar";s:3:"258";s:3:" da";s:3:"259";s:3:" en";s:3:"260";s:3:" mp";s:3:"261";s:3:" ny";s:3:"262";s:3:" ta";s:3:"263";s:3:" ul";s:3:"264";s:3:" we";s:3:"265";s:3:"a c";s:3:"266";s:3:"a f";s:3:"267";s:3:"ais";s:3:"268";s:3:"apo";s:3:"269";s:3:"ayo";s:3:"270";s:3:"bar";s:3:"271";s:3:"dhi";s:3:"272";s:3:"e a";s:3:"273";s:3:"eke";s:3:"274";s:3:"eny";s:3:"275";s:3:"eon";s:3:"276";s:3:"hai";s:3:"277";s:3:"han";s:3:"278";s:3:"hiy";s:3:"279";s:3:"hur";s:3:"280";s:3:"i s";s:3:"281";s:3:"imw";s:3:"282";s:3:"kal";s:3:"283";s:3:"kwe";s:3:"284";s:3:"lak";s:3:"285";s:3:"lam";s:3:"286";s:3:"mak";s:3:"287";s:3:"msa";s:3:"288";s:3:"ne ";s:3:"289";s:3:"ngu";s:3:"290";s:3:"ru ";s:3:"291";s:3:"sal";s:3:"292";s:3:"swa";s:3:"293";s:3:"te ";s:3:"294";s:3:"ti ";s:3:"295";s:3:"uku";s:3:"296";s:3:"uma";s:3:"297";s:3:"una";s:3:"298";s:3:"uru";s:3:"299";}s:7:"swedish";a:300:{s:3:"en ";s:1:"0";s:3:" de";s:1:"1";s:3:"et ";s:1:"2";s:3:"er ";s:1:"3";s:3:"tt ";s:1:"4";s:3:"om ";s:1:"5";s:4:"för";s:1:"6";s:3:"ar ";s:1:"7";s:3:"de ";s:1:"8";s:3:"att";s:1:"9";s:4:" fö";s:2:"10";s:3:"ing";s:2:"11";s:3:" in";s:2:"12";s:3:" at";s:2:"13";s:3:" i ";s:2:"14";s:3:"det";s:2:"15";s:3:"ch ";s:2:"16";s:3:"an ";s:2:"17";s:3:"gen";s:2:"18";s:3:" an";s:2:"19";s:3:"t s";s:2:"20";s:3:"som";s:2:"21";s:3:"te ";s:2:"22";s:3:" oc";s:2:"23";s:3:"ter";s:2:"24";s:3:" ha";s:2:"25";s:3:"lle";s:2:"26";s:3:"och";s:2:"27";s:3:" sk";s:2:"28";s:3:" so";s:2:"29";s:3:"ra ";s:2:"30";s:3:"r a";s:2:"31";s:3:" me";s:2:"32";s:3:"var";s:2:"33";s:3:"nde";s:2:"34";s:4:"är ";s:2:"35";s:3:" ko";s:2:"36";s:3:"on ";s:2:"37";s:3:"ans";s:2:"38";s:3:"int";s:2:"39";s:3:"n s";s:2:"40";s:3:"na ";s:2:"41";s:3:" en";s:2:"42";s:3:" fr";s:2:"43";s:4:" pÃ¥";s:2:"44";s:3:" st";s:2:"45";s:3:" va";s:2:"46";s:3:"and";s:2:"47";s:3:"nte";s:2:"48";s:4:"pÃ¥ ";s:2:"49";s:3:"ska";s:2:"50";s:3:"ta ";s:2:"51";s:3:" vi";s:2:"52";s:3:"der";s:2:"53";s:4:"äll";s:2:"54";s:4:"örs";s:2:"55";s:3:" om";s:2:"56";s:3:"da ";s:2:"57";s:3:"kri";s:2:"58";s:3:"ka ";s:2:"59";s:3:"nst";s:2:"60";s:3:" ho";s:2:"61";s:3:"as ";s:2:"62";s:4:"stä";s:2:"63";s:3:"r d";s:2:"64";s:3:"t f";s:2:"65";s:3:"upp";s:2:"66";s:3:" be";s:2:"67";s:3:"nge";s:2:"68";s:3:"r s";s:2:"69";s:3:"tal";s:2:"70";s:4:"täl";s:2:"71";s:4:"ör ";s:2:"72";s:3:" av";s:2:"73";s:3:"ger";s:2:"74";s:3:"ill";s:2:"75";s:3:"ng ";s:2:"76";s:3:"e s";s:2:"77";s:3:"ekt";s:2:"78";s:3:"ade";s:2:"79";s:3:"era";s:2:"80";s:3:"ers";s:2:"81";s:3:"har";s:2:"82";s:3:"ll ";s:2:"83";s:3:"lld";s:2:"84";s:3:"rin";s:2:"85";s:3:"rna";s:2:"86";s:4:"säk";s:2:"87";s:3:"und";s:2:"88";s:3:"inn";s:2:"89";s:3:"lig";s:2:"90";s:3:"ns ";s:2:"91";s:3:" ma";s:2:"92";s:3:" pr";s:2:"93";s:3:" up";s:2:"94";s:3:"age";s:2:"95";s:3:"av ";s:2:"96";s:3:"iva";s:2:"97";s:3:"kti";s:2:"98";s:3:"lda";s:2:"99";s:3:"orn";s:3:"100";s:3:"son";s:3:"101";s:3:"ts ";s:3:"102";s:3:"tta";s:3:"103";s:4:"äkr";s:3:"104";s:3:" sj";s:3:"105";s:3:" ti";s:3:"106";s:3:"avt";s:3:"107";s:3:"ber";s:3:"108";s:3:"els";s:3:"109";s:3:"eta";s:3:"110";s:3:"kol";s:3:"111";s:3:"men";s:3:"112";s:3:"n d";s:3:"113";s:3:"t k";s:3:"114";s:3:"vta";s:3:"115";s:4:"Ã¥r ";s:3:"116";s:3:"juk";s:3:"117";s:3:"man";s:3:"118";s:3:"n f";s:3:"119";s:3:"nin";s:3:"120";s:3:"r i";s:3:"121";s:4:"rsä";s:3:"122";s:3:"sju";s:3:"123";s:3:"sso";s:3:"124";s:4:" är";s:3:"125";s:3:"a s";s:3:"126";s:3:"ach";s:3:"127";s:3:"ag ";s:3:"128";s:3:"bac";s:3:"129";s:3:"den";s:3:"130";s:3:"ett";s:3:"131";s:3:"fte";s:3:"132";s:3:"hor";s:3:"133";s:3:"nba";s:3:"134";s:3:"oll";s:3:"135";s:3:"rnb";s:3:"136";s:3:"ste";s:3:"137";s:3:"til";s:3:"138";s:3:" ef";s:3:"139";s:3:" si";s:3:"140";s:3:"a a";s:3:"141";s:3:"e h";s:3:"142";s:3:"ed ";s:3:"143";s:3:"eft";s:3:"144";s:3:"ga ";s:3:"145";s:3:"ig ";s:3:"146";s:3:"it ";s:3:"147";s:3:"ler";s:3:"148";s:3:"med";s:3:"149";s:3:"n i";s:3:"150";s:3:"nd ";s:3:"151";s:4:"sÃ¥ ";s:3:"152";s:3:"tiv";s:3:"153";s:3:" bl";s:3:"154";s:3:" et";s:3:"155";s:3:" fi";s:3:"156";s:4:" sä";s:3:"157";s:3:"at ";s:3:"158";s:3:"des";s:3:"159";s:3:"e a";s:3:"160";s:3:"gar";s:3:"161";s:3:"get";s:3:"162";s:3:"lan";s:3:"163";s:3:"lss";s:3:"164";s:3:"ost";s:3:"165";s:3:"r b";s:3:"166";s:3:"r e";s:3:"167";s:3:"re ";s:3:"168";s:3:"ret";s:3:"169";s:3:"sta";s:3:"170";s:3:"t i";s:3:"171";s:3:" ge";s:3:"172";s:3:" he";s:3:"173";s:3:" re";s:3:"174";s:3:"a f";s:3:"175";s:3:"all";s:3:"176";s:3:"bos";s:3:"177";s:3:"ets";s:3:"178";s:3:"lek";s:3:"179";s:3:"let";s:3:"180";s:3:"ner";s:3:"181";s:3:"nna";s:3:"182";s:3:"nne";s:3:"183";s:3:"r f";s:3:"184";s:3:"rit";s:3:"185";s:3:"s s";s:3:"186";s:3:"sen";s:3:"187";s:3:"sto";s:3:"188";s:3:"tor";s:3:"189";s:3:"vav";s:3:"190";s:3:"ygg";s:3:"191";s:3:" ka";s:3:"192";s:4:" sÃ¥";s:3:"193";s:3:" tr";s:3:"194";s:3:" ut";s:3:"195";s:3:"ad ";s:3:"196";s:3:"al ";s:3:"197";s:3:"are";s:3:"198";s:3:"e o";s:3:"199";s:3:"gon";s:3:"200";s:3:"kom";s:3:"201";s:3:"n a";s:3:"202";s:3:"n h";s:3:"203";s:3:"nga";s:3:"204";s:3:"r h";s:3:"205";s:3:"ren";s:3:"206";s:3:"t d";s:3:"207";s:3:"tag";s:3:"208";s:3:"tar";s:3:"209";s:3:"tre";s:3:"210";s:4:"ätt";s:3:"211";s:4:" fÃ¥";s:3:"212";s:4:" hä";s:3:"213";s:3:" se";s:3:"214";s:3:"a d";s:3:"215";s:3:"a i";s:3:"216";s:3:"a p";s:3:"217";s:3:"ale";s:3:"218";s:3:"ann";s:3:"219";s:3:"ara";s:3:"220";s:3:"byg";s:3:"221";s:3:"gt ";s:3:"222";s:3:"han";s:3:"223";s:3:"igt";s:3:"224";s:3:"kan";s:3:"225";s:3:"la ";s:3:"226";s:3:"n o";s:3:"227";s:3:"nom";s:3:"228";s:3:"nsk";s:3:"229";s:3:"omm";s:3:"230";s:3:"r k";s:3:"231";s:3:"r p";s:3:"232";s:3:"r v";s:3:"233";s:3:"s f";s:3:"234";s:3:"s k";s:3:"235";s:3:"t a";s:3:"236";s:3:"t p";s:3:"237";s:3:"ver";s:3:"238";s:3:" bo";s:3:"239";s:3:" br";s:3:"240";s:3:" ku";s:3:"241";s:4:" nÃ¥";s:3:"242";s:3:"a b";s:3:"243";s:3:"a e";s:3:"244";s:3:"del";s:3:"245";s:3:"ens";s:3:"246";s:3:"es ";s:3:"247";s:3:"fin";s:3:"248";s:3:"ige";s:3:"249";s:3:"m s";s:3:"250";s:3:"n p";s:3:"251";s:4:"nÃ¥g";s:3:"252";s:3:"or ";s:3:"253";s:3:"r o";s:3:"254";s:3:"rbe";s:3:"255";s:3:"rs ";s:3:"256";s:3:"rt ";s:3:"257";s:3:"s a";s:3:"258";s:3:"s n";s:3:"259";s:3:"skr";s:3:"260";s:3:"t o";s:3:"261";s:3:"ten";s:3:"262";s:3:"tio";s:3:"263";s:3:"ven";s:3:"264";s:3:" al";s:3:"265";s:3:" ja";s:3:"266";s:3:" p ";s:3:"267";s:3:" r ";s:3:"268";s:3:" sa";s:3:"269";s:3:"a h";s:3:"270";s:3:"bet";s:3:"271";s:3:"cke";s:3:"272";s:3:"dra";s:3:"273";s:3:"e f";s:3:"274";s:3:"e i";s:3:"275";s:3:"eda";s:3:"276";s:3:"eno";s:3:"277";s:4:"erä";s:3:"278";s:3:"ess";s:3:"279";s:3:"ion";s:3:"280";s:3:"jag";s:3:"281";s:3:"m f";s:3:"282";s:3:"ne ";s:3:"283";s:3:"nns";s:3:"284";s:3:"pro";s:3:"285";s:3:"r t";s:3:"286";s:3:"rar";s:3:"287";s:3:"riv";s:3:"288";s:4:"rät";s:3:"289";s:3:"t e";s:3:"290";s:3:"t t";s:3:"291";s:3:"ust";s:3:"292";s:3:"vad";s:3:"293";s:4:"öre";s:3:"294";s:3:" ar";s:3:"295";s:3:" by";s:3:"296";s:3:" kr";s:3:"297";s:3:" mi";s:3:"298";s:3:"arb";s:3:"299";}s:7:"tagalog";a:300:{s:3:"ng ";s:1:"0";s:3:"ang";s:1:"1";s:3:" na";s:1:"2";s:3:" sa";s:1:"3";s:3:"an ";s:1:"4";s:3:"nan";s:1:"5";s:3:"sa ";s:1:"6";s:3:"na ";s:1:"7";s:3:" ma";s:1:"8";s:3:" ca";s:1:"9";s:3:"ay ";s:2:"10";s:3:"n g";s:2:"11";s:3:" an";s:2:"12";s:3:"ong";s:2:"13";s:3:" ga";s:2:"14";s:3:"at ";s:2:"15";s:3:" pa";s:2:"16";s:3:"ala";s:2:"17";s:3:" si";s:2:"18";s:3:"a n";s:2:"19";s:3:"ga ";s:2:"20";s:3:"g n";s:2:"21";s:3:"g m";s:2:"22";s:3:"ito";s:2:"23";s:3:"g c";s:2:"24";s:3:"man";s:2:"25";s:3:"san";s:2:"26";s:3:"g s";s:2:"27";s:3:"ing";s:2:"28";s:3:"to ";s:2:"29";s:3:"ila";s:2:"30";s:3:"ina";s:2:"31";s:3:" di";s:2:"32";s:3:" ta";s:2:"33";s:3:"aga";s:2:"34";s:3:"iya";s:2:"35";s:3:"aca";s:2:"36";s:3:"g t";s:2:"37";s:3:" at";s:2:"38";s:3:"aya";s:2:"39";s:3:"ama";s:2:"40";s:3:"lan";s:2:"41";s:3:"a a";s:2:"42";s:3:"qui";s:2:"43";s:3:"a c";s:2:"44";s:3:"a s";s:2:"45";s:3:"nag";s:2:"46";s:3:" ba";s:2:"47";s:3:"g i";s:2:"48";s:3:"tan";s:2:"49";s:3:"'t ";s:2:"50";s:3:" cu";s:2:"51";s:3:"aua";s:2:"52";s:3:"g p";s:2:"53";s:3:" ni";s:2:"54";s:3:"os ";s:2:"55";s:3:"'y ";s:2:"56";s:3:"a m";s:2:"57";s:3:" n ";s:2:"58";s:3:"la ";s:2:"59";s:3:" la";s:2:"60";s:3:"o n";s:2:"61";s:3:"yan";s:2:"62";s:3:" ay";s:2:"63";s:3:"usa";s:2:"64";s:3:"cay";s:2:"65";s:3:"on ";s:2:"66";s:3:"ya ";s:2:"67";s:3:" it";s:2:"68";s:3:"al ";s:2:"69";s:3:"apa";s:2:"70";s:3:"ata";s:2:"71";s:3:"t n";s:2:"72";s:3:"uan";s:2:"73";s:3:"aha";s:2:"74";s:3:"asa";s:2:"75";s:3:"pag";s:2:"76";s:3:" gu";s:2:"77";s:3:"g l";s:2:"78";s:3:"di ";s:2:"79";s:3:"mag";s:2:"80";s:3:"aba";s:2:"81";s:3:"g a";s:2:"82";s:3:"ara";s:2:"83";s:3:"a p";s:2:"84";s:3:"in ";s:2:"85";s:3:"ana";s:2:"86";s:3:"it ";s:2:"87";s:3:"si ";s:2:"88";s:3:"cus";s:2:"89";s:3:"g b";s:2:"90";s:3:"uin";s:2:"91";s:3:"a t";s:2:"92";s:3:"as ";s:2:"93";s:3:"n n";s:2:"94";s:3:"hin";s:2:"95";s:3:" hi";s:2:"96";s:3:"a't";s:2:"97";s:3:"ali";s:2:"98";s:3:" bu";s:2:"99";s:3:"gan";s:3:"100";s:3:"uma";s:3:"101";s:3:"a d";s:3:"102";s:3:"agc";s:3:"103";s:3:"aqu";s:3:"104";s:3:"g d";s:3:"105";s:3:" tu";s:3:"106";s:3:"aon";s:3:"107";s:3:"ari";s:3:"108";s:3:"cas";s:3:"109";s:3:"i n";s:3:"110";s:3:"niy";s:3:"111";s:3:"pin";s:3:"112";s:3:"a i";s:3:"113";s:3:"gca";s:3:"114";s:3:"siy";s:3:"115";s:3:"a'y";s:3:"116";s:3:"yao";s:3:"117";s:3:"ag ";s:3:"118";s:3:"ca ";s:3:"119";s:3:"han";s:3:"120";s:3:"ili";s:3:"121";s:3:"pan";s:3:"122";s:3:"sin";s:3:"123";s:3:"ual";s:3:"124";s:3:"n s";s:3:"125";s:3:"nam";s:3:"126";s:3:" lu";s:3:"127";s:3:"can";s:3:"128";s:3:"dit";s:3:"129";s:3:"gui";s:3:"130";s:3:"y n";s:3:"131";s:3:"gal";s:3:"132";s:3:"hat";s:3:"133";s:3:"nal";s:3:"134";s:3:" is";s:3:"135";s:3:"bag";s:3:"136";s:3:"fra";s:3:"137";s:3:" fr";s:3:"138";s:3:" su";s:3:"139";s:3:"a l";s:3:"140";s:3:" co";s:3:"141";s:3:"ani";s:3:"142";s:3:" bi";s:3:"143";s:3:" da";s:3:"144";s:3:"alo";s:3:"145";s:3:"isa";s:3:"146";s:3:"ita";s:3:"147";s:3:"may";s:3:"148";s:3:"o s";s:3:"149";s:3:"sil";s:3:"150";s:3:"una";s:3:"151";s:3:" in";s:3:"152";s:3:" pi";s:3:"153";s:3:"l n";s:3:"154";s:3:"nil";s:3:"155";s:3:"o a";s:3:"156";s:3:"pat";s:3:"157";s:3:"sac";s:3:"158";s:3:"t s";s:3:"159";s:3:" ua";s:3:"160";s:3:"agu";s:3:"161";s:3:"ail";s:3:"162";s:3:"bin";s:3:"163";s:3:"dal";s:3:"164";s:3:"g h";s:3:"165";s:3:"ndi";s:3:"166";s:3:"oon";s:3:"167";s:3:"ua ";s:3:"168";s:3:" ha";s:3:"169";s:3:"ind";s:3:"170";s:3:"ran";s:3:"171";s:3:"s n";s:3:"172";s:3:"tin";s:3:"173";s:3:"ulo";s:3:"174";s:3:"eng";s:3:"175";s:3:"g f";s:3:"176";s:3:"ini";s:3:"177";s:3:"lah";s:3:"178";s:3:"lo ";s:3:"179";s:3:"rai";s:3:"180";s:3:"rin";s:3:"181";s:3:"ton";s:3:"182";s:3:"g u";s:3:"183";s:3:"inu";s:3:"184";s:3:"lon";s:3:"185";s:3:"o'y";s:3:"186";s:3:"t a";s:3:"187";s:3:" ar";s:3:"188";s:3:"a b";s:3:"189";s:3:"ad ";s:3:"190";s:3:"bay";s:3:"191";s:3:"cal";s:3:"192";s:3:"gya";s:3:"193";s:3:"ile";s:3:"194";s:3:"mat";s:3:"195";s:3:"n a";s:3:"196";s:3:"pau";s:3:"197";s:3:"ra ";s:3:"198";s:3:"tay";s:3:"199";s:3:"y m";s:3:"200";s:3:"ant";s:3:"201";s:3:"ban";s:3:"202";s:3:"i m";s:3:"203";s:3:"nas";s:3:"204";s:3:"nay";s:3:"205";s:3:"no ";s:3:"206";s:3:"sti";s:3:"207";s:3:" ti";s:3:"208";s:3:"ags";s:3:"209";s:3:"g g";s:3:"210";s:3:"ta ";s:3:"211";s:3:"uit";s:3:"212";s:3:"uno";s:3:"213";s:3:" ib";s:3:"214";s:3:" ya";s:3:"215";s:3:"a u";s:3:"216";s:3:"abi";s:3:"217";s:3:"ati";s:3:"218";s:3:"cap";s:3:"219";s:3:"ig ";s:3:"220";s:3:"is ";s:3:"221";s:3:"la'";s:3:"222";s:3:" do";s:3:"223";s:3:" pu";s:3:"224";s:3:"api";s:3:"225";s:3:"ayo";s:3:"226";s:3:"gos";s:3:"227";s:3:"gul";s:3:"228";s:3:"lal";s:3:"229";s:3:"tag";s:3:"230";s:3:"til";s:3:"231";s:3:"tun";s:3:"232";s:3:"y c";s:3:"233";s:3:"y s";s:3:"234";s:3:"yon";s:3:"235";s:3:"ano";s:3:"236";s:3:"bur";s:3:"237";s:3:"iba";s:3:"238";s:3:"isi";s:3:"239";s:3:"lam";s:3:"240";s:3:"nac";s:3:"241";s:3:"nat";s:3:"242";s:3:"ni ";s:3:"243";s:3:"nto";s:3:"244";s:3:"od ";s:3:"245";s:3:"pa ";s:3:"246";s:3:"rgo";s:3:"247";s:3:"urg";s:3:"248";s:3:" m ";s:3:"249";s:3:"adr";s:3:"250";s:3:"ast";s:3:"251";s:3:"cag";s:3:"252";s:3:"gay";s:3:"253";s:3:"gsi";s:3:"254";s:3:"i p";s:3:"255";s:3:"ino";s:3:"256";s:3:"len";s:3:"257";s:3:"lin";s:3:"258";s:3:"m g";s:3:"259";s:3:"mar";s:3:"260";s:3:"nah";s:3:"261";s:3:"to'";s:3:"262";s:3:" de";s:3:"263";s:3:"a h";s:3:"264";s:3:"cat";s:3:"265";s:3:"cau";s:3:"266";s:3:"con";s:3:"267";s:3:"iqu";s:3:"268";s:3:"lac";s:3:"269";s:3:"mab";s:3:"270";s:3:"min";s:3:"271";s:3:"og ";s:3:"272";s:3:"par";s:3:"273";s:3:"sal";s:3:"274";s:3:" za";s:3:"275";s:3:"ao ";s:3:"276";s:3:"doo";s:3:"277";s:3:"ipi";s:3:"278";s:3:"nod";s:3:"279";s:3:"nte";s:3:"280";s:3:"uha";s:3:"281";s:3:"ula";s:3:"282";s:3:" re";s:3:"283";s:3:"ill";s:3:"284";s:3:"lit";s:3:"285";s:3:"mac";s:3:"286";s:3:"nit";s:3:"287";s:3:"o't";s:3:"288";s:3:"or ";s:3:"289";s:3:"ora";s:3:"290";s:3:"sum";s:3:"291";s:3:"y p";s:3:"292";s:3:" al";s:3:"293";s:3:" mi";s:3:"294";s:3:" um";s:3:"295";s:3:"aco";s:3:"296";s:3:"ada";s:3:"297";s:3:"agd";s:3:"298";s:3:"cab";s:3:"299";}s:7:"turkish";a:300:{s:3:"lar";s:1:"0";s:3:"en ";s:1:"1";s:3:"ler";s:1:"2";s:3:"an ";s:1:"3";s:3:"in ";s:1:"4";s:3:" bi";s:1:"5";s:3:" ya";s:1:"6";s:3:"eri";s:1:"7";s:3:"de ";s:1:"8";s:3:" ka";s:1:"9";s:3:"ir ";s:2:"10";s:4:"arı";s:2:"11";s:3:" ba";s:2:"12";s:3:" de";s:2:"13";s:3:" ha";s:2:"14";s:4:"ın ";s:2:"15";s:3:"ara";s:2:"16";s:3:"bir";s:2:"17";s:3:" ve";s:2:"18";s:3:" sa";s:2:"19";s:3:"ile";s:2:"20";s:3:"le ";s:2:"21";s:3:"nde";s:2:"22";s:3:"da ";s:2:"23";s:3:" bu";s:2:"24";s:3:"ana";s:2:"25";s:3:"ini";s:2:"26";s:5:"ını";s:2:"27";s:3:"er ";s:2:"28";s:3:"ve ";s:2:"29";s:4:" yı";s:2:"30";s:3:"lma";s:2:"31";s:4:"yıl";s:2:"32";s:3:" ol";s:2:"33";s:3:"ar ";s:2:"34";s:3:"n b";s:2:"35";s:3:"nda";s:2:"36";s:3:"aya";s:2:"37";s:3:"li ";s:2:"38";s:4:"ası";s:2:"39";s:3:" ge";s:2:"40";s:3:"ind";s:2:"41";s:3:"n k";s:2:"42";s:3:"esi";s:2:"43";s:3:"lan";s:2:"44";s:3:"nla";s:2:"45";s:3:"ak ";s:2:"46";s:4:"anı";s:2:"47";s:3:"eni";s:2:"48";s:3:"ni ";s:2:"49";s:4:"nı ";s:2:"50";s:4:"rın";s:2:"51";s:3:"san";s:2:"52";s:3:" ko";s:2:"53";s:3:" ye";s:2:"54";s:3:"maz";s:2:"55";s:4:"baÅŸ";s:2:"56";s:3:"ili";s:2:"57";s:3:"rin";s:2:"58";s:4:"alı";s:2:"59";s:3:"az ";s:2:"60";s:3:"hal";s:2:"61";s:4:"ınd";s:2:"62";s:3:" da";s:2:"63";s:4:" gü";s:2:"64";s:3:"ele";s:2:"65";s:4:"ılm";s:2:"66";s:6:"ığı";s:2:"67";s:3:"eki";s:2:"68";s:4:"gün";s:2:"69";s:3:"i b";s:2:"70";s:4:"içi";s:2:"71";s:3:"den";s:2:"72";s:3:"kar";s:2:"73";s:3:"si ";s:2:"74";s:3:" il";s:2:"75";s:3:"e y";s:2:"76";s:3:"na ";s:2:"77";s:3:"yor";s:2:"78";s:3:"ek ";s:2:"79";s:3:"n s";s:2:"80";s:4:" iç";s:2:"81";s:3:"bu ";s:2:"82";s:3:"e b";s:2:"83";s:3:"im ";s:2:"84";s:3:"ki ";s:2:"85";s:3:"len";s:2:"86";s:3:"ri ";s:2:"87";s:4:"sın";s:2:"88";s:3:" so";s:2:"89";s:4:"ün ";s:2:"90";s:3:" ta";s:2:"91";s:3:"nin";s:2:"92";s:4:"iÄŸi";s:2:"93";s:3:"tan";s:2:"94";s:3:"yan";s:2:"95";s:3:" si";s:2:"96";s:3:"nat";s:2:"97";s:4:"nın";s:2:"98";s:3:"kan";s:2:"99";s:4:"rı ";s:3:"100";s:4:"çin";s:3:"101";s:5:"ğı ";s:3:"102";s:3:"eli";s:3:"103";s:3:"n a";s:3:"104";s:4:"ır ";s:3:"105";s:3:" an";s:3:"106";s:3:"ine";s:3:"107";s:3:"n y";s:3:"108";s:3:"ola";s:3:"109";s:3:" ar";s:3:"110";s:3:"al ";s:3:"111";s:3:"e s";s:3:"112";s:3:"lik";s:3:"113";s:3:"n d";s:3:"114";s:3:"sin";s:3:"115";s:3:" al";s:3:"116";s:4:" dü";s:3:"117";s:3:"anl";s:3:"118";s:3:"ne ";s:3:"119";s:3:"ya ";s:3:"120";s:4:"ım ";s:3:"121";s:4:"ına";s:3:"122";s:3:" be";s:3:"123";s:3:"ada";s:3:"124";s:3:"ala";s:3:"125";s:3:"ama";s:3:"126";s:3:"ilm";s:3:"127";s:3:"or ";s:3:"128";s:4:"sı ";s:3:"129";s:3:"yen";s:3:"130";s:3:" me";s:3:"131";s:4:"atı";s:3:"132";s:3:"di ";s:3:"133";s:3:"eti";s:3:"134";s:3:"ken";s:3:"135";s:3:"la ";s:3:"136";s:4:"lı ";s:3:"137";s:3:"oru";s:3:"138";s:4:" gö";s:3:"139";s:3:" in";s:3:"140";s:3:"and";s:3:"141";s:3:"e d";s:3:"142";s:3:"men";s:3:"143";s:3:"un ";s:3:"144";s:4:"öne";s:3:"145";s:3:"a d";s:3:"146";s:3:"at ";s:3:"147";s:3:"e a";s:3:"148";s:3:"e g";s:3:"149";s:3:"yar";s:3:"150";s:3:" ku";s:3:"151";s:4:"ayı";s:3:"152";s:3:"dan";s:3:"153";s:3:"edi";s:3:"154";s:3:"iri";s:3:"155";s:5:"ünü";s:3:"156";s:4:"ÄŸi ";s:3:"157";s:5:"ılı";s:3:"158";s:3:"eme";s:3:"159";s:4:"eÄŸi";s:3:"160";s:3:"i k";s:3:"161";s:3:"i y";s:3:"162";s:4:"ıla";s:3:"163";s:4:" ça";s:3:"164";s:3:"a y";s:3:"165";s:3:"alk";s:3:"166";s:4:"dı ";s:3:"167";s:3:"ede";s:3:"168";s:3:"el ";s:3:"169";s:4:"ndı";s:3:"170";s:3:"ra ";s:3:"171";s:4:"üne";s:3:"172";s:4:" sü";s:3:"173";s:4:"dır";s:3:"174";s:3:"e k";s:3:"175";s:3:"ere";s:3:"176";s:3:"ik ";s:3:"177";s:3:"imi";s:3:"178";s:4:"iÅŸi";s:3:"179";s:3:"mas";s:3:"180";s:3:"n h";s:3:"181";s:4:"sür";s:3:"182";s:3:"yle";s:3:"183";s:3:" ad";s:3:"184";s:3:" fi";s:3:"185";s:3:" gi";s:3:"186";s:3:" se";s:3:"187";s:3:"a k";s:3:"188";s:3:"arl";s:3:"189";s:5:"aşı";s:3:"190";s:3:"iyo";s:3:"191";s:3:"kla";s:3:"192";s:5:"lığ";s:3:"193";s:3:"nem";s:3:"194";s:3:"ney";s:3:"195";s:3:"rme";s:3:"196";s:3:"ste";s:3:"197";s:4:"tı ";s:3:"198";s:3:"unl";s:3:"199";s:3:"ver";s:3:"200";s:4:" sı";s:3:"201";s:3:" te";s:3:"202";s:3:" to";s:3:"203";s:3:"a s";s:3:"204";s:4:"aÅŸk";s:3:"205";s:3:"ekl";s:3:"206";s:3:"end";s:3:"207";s:3:"kal";s:3:"208";s:4:"liÄŸ";s:3:"209";s:3:"min";s:3:"210";s:4:"tır";s:3:"211";s:3:"ulu";s:3:"212";s:3:"unu";s:3:"213";s:3:"yap";s:3:"214";s:3:"ye ";s:3:"215";s:4:"ı i";s:3:"216";s:4:"ÅŸka";s:3:"217";s:5:"ÅŸtı";s:3:"218";s:4:" bü";s:3:"219";s:3:" ke";s:3:"220";s:3:" ki";s:3:"221";s:3:"ard";s:3:"222";s:3:"art";s:3:"223";s:4:"aÅŸa";s:3:"224";s:3:"n i";s:3:"225";s:3:"ndi";s:3:"226";s:3:"ti ";s:3:"227";s:3:"top";s:3:"228";s:4:"ı b";s:3:"229";s:3:" va";s:3:"230";s:4:" ön";s:3:"231";s:3:"aki";s:3:"232";s:3:"cak";s:3:"233";s:3:"ey ";s:3:"234";s:3:"fil";s:3:"235";s:3:"isi";s:3:"236";s:3:"kle";s:3:"237";s:3:"kur";s:3:"238";s:3:"man";s:3:"239";s:3:"nce";s:3:"240";s:3:"nle";s:3:"241";s:3:"nun";s:3:"242";s:3:"rak";s:3:"243";s:4:"ık ";s:3:"244";s:3:" en";s:3:"245";s:3:" yo";s:3:"246";s:3:"a g";s:3:"247";s:3:"lis";s:3:"248";s:3:"mak";s:3:"249";s:3:"n g";s:3:"250";s:3:"tir";s:3:"251";s:3:"yas";s:3:"252";s:4:" iÅŸ";s:3:"253";s:4:" yö";s:3:"254";s:3:"ale";s:3:"255";s:3:"bil";s:3:"256";s:3:"bul";s:3:"257";s:3:"et ";s:3:"258";s:3:"i d";s:3:"259";s:3:"iye";s:3:"260";s:3:"kil";s:3:"261";s:3:"ma ";s:3:"262";s:3:"n e";s:3:"263";s:3:"n t";s:3:"264";s:3:"nu ";s:3:"265";s:3:"olu";s:3:"266";s:3:"rla";s:3:"267";s:3:"te ";s:3:"268";s:4:"yön";s:3:"269";s:5:"çık";s:3:"270";s:3:" ay";s:3:"271";s:4:" mü";s:3:"272";s:4:" ço";s:3:"273";s:5:" çı";s:3:"274";s:3:"a a";s:3:"275";s:3:"a b";s:3:"276";s:3:"ata";s:3:"277";s:3:"der";s:3:"278";s:3:"gel";s:3:"279";s:3:"i g";s:3:"280";s:3:"i i";s:3:"281";s:3:"ill";s:3:"282";s:3:"ist";s:3:"283";s:4:"ldı";s:3:"284";s:3:"lu ";s:3:"285";s:3:"mek";s:3:"286";s:3:"mle";s:3:"287";s:4:"n ç";s:3:"288";s:3:"onu";s:3:"289";s:3:"opl";s:3:"290";s:3:"ran";s:3:"291";s:3:"rat";s:3:"292";s:4:"rdı";s:3:"293";s:3:"rke";s:3:"294";s:3:"siy";s:3:"295";s:3:"son";s:3:"296";s:3:"ta ";s:3:"297";s:5:"tçı";s:3:"298";s:4:"tın";s:3:"299";}s:9:"ukrainian";a:300:{s:5:" на";s:1:"0";s:5:" за";s:1:"1";s:6:"ннÑ";s:1:"2";s:5:"Ð½Ñ ";s:1:"3";s:5:"на ";s:1:"4";s:5:" пр";s:1:"5";s:6:"ого";s:1:"6";s:5:"го ";s:1:"7";s:6:"Ñьк";s:1:"8";s:5:" по";s:1:"9";s:4:" у ";s:2:"10";s:6:"від";s:2:"11";s:6:"ере";s:2:"12";s:5:" мі";s:2:"13";s:5:" не";s:2:"14";s:5:"их ";s:2:"15";s:5:"Ñ‚ÑŒ ";s:2:"16";s:6:"пер";s:2:"17";s:5:" ві";s:2:"18";s:5:"ів ";s:2:"19";s:5:" пе";s:2:"20";s:5:" що";s:2:"21";s:6:"льн";s:2:"22";s:5:"ми ";s:2:"23";s:5:"ні ";s:2:"24";s:5:"не ";s:2:"25";s:5:"ти ";s:2:"26";s:6:"ати";s:2:"27";s:6:"енн";s:2:"28";s:6:"міÑ";s:2:"29";s:6:"пра";s:2:"30";s:6:"ува";s:2:"31";s:6:"ник";s:2:"32";s:6:"про";s:2:"33";s:6:"рав";s:2:"34";s:6:"івн";s:2:"35";s:5:" та";s:2:"36";s:6:"буд";s:2:"37";s:6:"влі";s:2:"38";s:6:"рів";s:2:"39";s:5:" ко";s:2:"40";s:5:" рі";s:2:"41";s:6:"аль";s:2:"42";s:5:"но ";s:2:"43";s:6:"ому";s:2:"44";s:5:"що ";s:2:"45";s:5:" ви";s:2:"46";s:5:"му ";s:2:"47";s:6:"рев";s:2:"48";s:5:"ÑÑ ";s:2:"49";s:6:"інн";s:2:"50";s:5:" до";s:2:"51";s:5:" уп";s:2:"52";s:6:"авл";s:2:"53";s:6:"анн";s:2:"54";s:6:"ком";s:2:"55";s:5:"ли ";s:2:"56";s:6:"лін";s:2:"57";s:6:"ног";s:2:"58";s:6:"упр";s:2:"59";s:5:" бу";s:2:"60";s:4:" з ";s:2:"61";s:5:" ро";s:2:"62";s:5:"за ";s:2:"63";s:5:"и н";s:2:"64";s:6:"нов";s:2:"65";s:6:"оро";s:2:"66";s:6:"оÑÑ‚";s:2:"67";s:6:"Ñта";s:2:"68";s:5:"Ñ‚Ñ– ";s:2:"69";s:6:"ÑŽÑ‚ÑŒ";s:2:"70";s:5:" мо";s:2:"71";s:5:" ні";s:2:"72";s:5:" Ñк";s:2:"73";s:6:"бор";s:2:"74";s:5:"ва ";s:2:"75";s:6:"ван";s:2:"76";s:6:"ень";s:2:"77";s:5:"и п";s:2:"78";s:5:"нь ";s:2:"79";s:6:"ові";s:2:"80";s:6:"рон";s:2:"81";s:6:"ÑÑ‚Ñ–";s:2:"82";s:5:"та ";s:2:"83";s:5:"у в";s:2:"84";s:6:"ько";s:2:"85";s:6:"Ñ–ÑÑ‚";s:2:"86";s:4:" в ";s:2:"87";s:5:" ре";s:2:"88";s:5:"до ";s:2:"89";s:5:"е п";s:2:"90";s:6:"заб";s:2:"91";s:5:"ий ";s:2:"92";s:6:"нÑÑŒ";s:2:"93";s:5:"о в";s:2:"94";s:5:"о п";s:2:"95";s:6:"при";s:2:"96";s:5:"Ñ– п";s:2:"97";s:5:" ку";s:2:"98";s:5:" пі";s:2:"99";s:5:" Ñп";s:3:"100";s:5:"а п";s:3:"101";s:6:"або";s:3:"102";s:6:"анÑ";s:3:"103";s:6:"аці";s:3:"104";s:6:"ват";s:3:"105";s:6:"вни";s:3:"106";s:5:"и в";s:3:"107";s:6:"ими";s:3:"108";s:5:"ка ";s:3:"109";s:6:"нен";s:3:"110";s:6:"ніч";s:3:"111";s:6:"она";s:3:"112";s:5:"ої ";s:3:"113";s:6:"пов";s:3:"114";s:6:"ьки";s:3:"115";s:6:"ьно";s:3:"116";s:6:"ізн";s:3:"117";s:6:"ічн";s:3:"118";s:5:" ав";s:3:"119";s:5:" ма";s:3:"120";s:5:" ор";s:3:"121";s:5:" Ñу";s:3:"122";s:5:" чи";s:3:"123";s:5:" ін";s:3:"124";s:5:"а з";s:3:"125";s:5:"ам ";s:3:"126";s:5:"ає ";s:3:"127";s:6:"вне";s:3:"128";s:6:"вто";s:3:"129";s:6:"дом";s:3:"130";s:6:"ент";s:3:"131";s:6:"жит";s:3:"132";s:6:"зни";s:3:"133";s:5:"им ";s:3:"134";s:6:"итл";s:3:"135";s:5:"ла ";s:3:"136";s:6:"них";s:3:"137";s:6:"ниц";s:3:"138";s:6:"ова";s:3:"139";s:6:"ови";s:3:"140";s:5:"ом ";s:3:"141";s:6:"пор";s:3:"142";s:6:"Ñ‚ÑŒÑ";s:3:"143";s:5:"у Ñ€";s:3:"144";s:6:"ÑŒÑÑ";s:3:"145";s:6:"ідо";s:3:"146";s:6:"іль";s:3:"147";s:6:"Ñ–ÑÑŒ";s:3:"148";s:5:" ва";s:3:"149";s:5:" ді";s:3:"150";s:5:" жи";s:3:"151";s:5:" че";s:3:"152";s:4:" Ñ– ";s:3:"153";s:5:"а в";s:3:"154";s:5:"а н";s:3:"155";s:6:"али";s:3:"156";s:6:"вез";s:3:"157";s:6:"вно";s:3:"158";s:6:"еве";s:3:"159";s:6:"езе";s:3:"160";s:6:"зен";s:3:"161";s:6:"ицт";s:3:"162";s:5:"ки ";s:3:"163";s:6:"ких";s:3:"164";s:6:"кон";s:3:"165";s:5:"ку ";s:3:"166";s:6:"лаÑ";s:3:"167";s:5:"Ð»Ñ ";s:3:"168";s:6:"мож";s:3:"169";s:6:"нач";s:3:"170";s:6:"ним";s:3:"171";s:6:"ної";s:3:"172";s:5:"о б";s:3:"173";s:6:"ову";s:3:"174";s:6:"оди";s:3:"175";s:5:"ою ";s:3:"176";s:5:"ро ";s:3:"177";s:6:"рок";s:3:"178";s:6:"Ñно";s:3:"179";s:6:"Ñпо";s:3:"180";s:6:"так";s:3:"181";s:6:"тва";s:3:"182";s:5:"ту ";s:3:"183";s:5:"у п";s:3:"184";s:6:"цтв";s:3:"185";s:6:"ьни";s:3:"186";s:5:"Ñ Ð·";s:3:"187";s:5:"Ñ– м";s:3:"188";s:5:"Ñ–Ñ— ";s:3:"189";s:5:" вÑ";s:3:"190";s:5:" гр";s:3:"191";s:5:" де";s:3:"192";s:5:" но";s:3:"193";s:5:" па";s:3:"194";s:5:" Ñе";s:3:"195";s:5:" ук";s:3:"196";s:5:" Ñ—Ñ…";s:3:"197";s:5:"а о";s:3:"198";s:6:"авт";s:3:"199";s:6:"аÑÑ‚";s:3:"200";s:6:"ают";s:3:"201";s:6:"вар";s:3:"202";s:6:"ден";s:3:"203";s:5:"ди ";s:3:"204";s:5:"ду ";s:3:"205";s:6:"зна";s:3:"206";s:5:"и з";s:3:"207";s:6:"ико";s:3:"208";s:6:"иÑÑ";s:3:"209";s:6:"ити";s:3:"210";s:6:"ког";s:3:"211";s:6:"мен";s:3:"212";s:6:"ном";s:3:"213";s:5:"ну ";s:3:"214";s:5:"о н";s:3:"215";s:5:"о Ñ";s:3:"216";s:6:"обу";s:3:"217";s:6:"ово";s:3:"218";s:6:"пла";s:3:"219";s:6:"ран";s:3:"220";s:6:"рив";s:3:"221";s:6:"роб";s:3:"222";s:6:"Ñка";s:3:"223";s:6:"тан";s:3:"224";s:6:"тим";s:3:"225";s:6:"тиÑ";s:3:"226";s:5:"то ";s:3:"227";s:6:"тра";s:3:"228";s:6:"удо";s:3:"229";s:6:"чин";s:3:"230";s:6:"чни";s:3:"231";s:5:"Ñ– в";s:3:"232";s:5:"Ñ–ÑŽ ";s:3:"233";s:4:" а ";s:3:"234";s:5:" во";s:3:"235";s:5:" да";s:3:"236";s:5:" кв";s:3:"237";s:5:" ме";s:3:"238";s:5:" об";s:3:"239";s:5:" Ñк";s:3:"240";s:5:" ти";s:3:"241";s:5:" Ñ„Ñ–";s:3:"242";s:4:" Ñ” ";s:3:"243";s:5:"а Ñ€";s:3:"244";s:5:"а Ñ";s:3:"245";s:5:"а у";s:3:"246";s:5:"ак ";s:3:"247";s:6:"ані";s:3:"248";s:6:"арт";s:3:"249";s:6:"аÑн";s:3:"250";s:5:"в у";s:3:"251";s:6:"вик";s:3:"252";s:6:"віз";s:3:"253";s:6:"дов";s:3:"254";s:6:"дпо";s:3:"255";s:6:"дів";s:3:"256";s:6:"еві";s:3:"257";s:6:"енÑ";s:3:"258";s:5:"же ";s:3:"259";s:5:"и м";s:3:"260";s:5:"и Ñ";s:3:"261";s:6:"ика";s:3:"262";s:6:"ичн";s:3:"263";s:5:"кі ";s:3:"264";s:6:"ків";s:3:"265";s:6:"між";s:3:"266";s:6:"нан";s:3:"267";s:6:"ноÑ";s:3:"268";s:5:"о у";s:3:"269";s:6:"обл";s:3:"270";s:6:"одн";s:3:"271";s:5:"ок ";s:3:"272";s:6:"оло";s:3:"273";s:6:"отр";s:3:"274";s:6:"рен";s:3:"275";s:6:"рим";s:3:"276";s:6:"роз";s:3:"277";s:5:"ÑÑŒ ";s:3:"278";s:5:"ÑÑ– ";s:3:"279";s:6:"тла";s:3:"280";s:6:"тів";s:3:"281";s:5:"у з";s:3:"282";s:6:"уго";s:3:"283";s:6:"уді";s:3:"284";s:5:"чи ";s:3:"285";s:5:"ше ";s:3:"286";s:5:"Ñ Ð½";s:3:"287";s:5:"Ñ Ñƒ";s:3:"288";s:6:"ідп";s:3:"289";s:5:"ій ";s:3:"290";s:6:"іна";s:3:"291";s:5:"Ñ–Ñ ";s:3:"292";s:5:" ка";s:3:"293";s:5:" ни";s:3:"294";s:5:" оÑ";s:3:"295";s:5:" Ñи";s:3:"296";s:5:" то";s:3:"297";s:5:" Ñ‚Ñ€";s:3:"298";s:5:" уг";s:3:"299";}s:4:"urdu";a:300:{s:5:"یں ";s:1:"0";s:5:" Ú©ÛŒ";s:1:"1";s:5:"Ú©Û’ ";s:1:"2";s:5:" Ú©Û’";s:1:"3";s:5:"Ù†Û’ ";s:1:"4";s:5:" Ú©Û";s:1:"5";s:5:"Û’ Ú©";s:1:"6";s:5:"Ú©ÛŒ ";s:1:"7";s:6:"میں";s:1:"8";s:5:" Ù…ÛŒ";s:1:"9";s:5:"ÛÛ’ ";s:2:"10";s:5:"ÙˆÚº ";s:2:"11";s:5:"Ú©Û ";s:2:"12";s:5:" ÛÛ’";s:2:"13";s:5:"ان ";s:2:"14";s:6:"Ûیں";s:2:"15";s:5:"ور ";s:2:"16";s:5:" Ú©Ùˆ";s:2:"17";s:5:"یا ";s:2:"18";s:5:" ان";s:2:"19";s:5:" Ù†Û’";s:2:"20";s:5:"سے ";s:2:"21";s:5:" سے";s:2:"22";s:5:" کر";s:2:"23";s:6:"ستا";s:2:"24";s:5:" او";s:2:"25";s:6:"اور";s:2:"26";s:6:"تان";s:2:"27";s:5:"ر Ú©";s:2:"28";s:5:"ÛŒ Ú©";s:2:"29";s:5:" اس";s:2:"30";s:5:"Û’ ا";s:2:"31";s:5:" پا";s:2:"32";s:5:" ÛÙˆ";s:2:"33";s:5:" پر";s:2:"34";s:5:"ر٠";s:2:"35";s:5:" کا";s:2:"36";s:5:"ا Ú©";s:2:"37";s:5:"ÛŒ ا";s:2:"38";s:5:" ÛÛŒ";s:2:"39";s:5:"در ";s:2:"40";s:5:"Ú©Ùˆ ";s:2:"41";s:5:" ای";s:2:"42";s:5:"Úº Ú©";s:2:"43";s:5:" مش";s:2:"44";s:5:" مل";s:2:"45";s:5:"ات ";s:2:"46";s:6:"صدر";s:2:"47";s:6:"اکس";s:2:"48";s:6:"شرÙ";s:2:"49";s:6:"مشر";s:2:"50";s:6:"پاک";s:2:"51";s:6:"کست";s:2:"52";s:5:"ÛŒ Ù…";s:2:"53";s:5:" دی";s:2:"54";s:5:" صد";s:2:"55";s:5:" ÛŒÛ";s:2:"56";s:5:"ا Û";s:2:"57";s:5:"Ù† Ú©";s:2:"58";s:6:"وال";s:2:"59";s:5:"ÛŒÛ ";s:2:"60";s:5:"Û’ Ùˆ";s:2:"61";s:5:" بھ";s:2:"62";s:5:" دو";s:2:"63";s:5:"اس ";s:2:"64";s:5:"ر ا";s:2:"65";s:6:"Ù†ÛÛŒ";s:2:"66";s:5:"کا ";s:2:"67";s:5:"Û’ س";s:2:"68";s:5:"ئی ";s:2:"69";s:5:"Û Ø§";s:2:"70";s:5:"یت ";s:2:"71";s:5:"Û’ Û";s:2:"72";s:5:"ت Ú©";s:2:"73";s:5:" سا";s:2:"74";s:5:"Ù„Û’ ";s:2:"75";s:5:"Ûا ";s:2:"76";s:5:"Û’ ب";s:2:"77";s:5:" وا";s:2:"78";s:5:"ار ";s:2:"79";s:5:"Ù†ÛŒ ";s:2:"80";s:6:"Ú©Ûا";s:2:"81";s:5:"ÛŒ Û";s:2:"82";s:5:"Û’ Ù…";s:2:"83";s:5:" سی";s:2:"84";s:5:" Ù„ÛŒ";s:2:"85";s:6:"انÛ";s:2:"86";s:6:"انی";s:2:"87";s:5:"ر Ù…";s:2:"88";s:5:"ر Ù¾";s:2:"89";s:6:"ریت";s:2:"90";s:5:"Ù† Ù…";s:2:"91";s:5:"ھا ";s:2:"92";s:5:"یر ";s:2:"93";s:5:" جا";s:2:"94";s:5:" جن";s:2:"95";s:5:"ئے ";s:2:"96";s:5:"پر ";s:2:"97";s:5:"Úº Ù†";s:2:"98";s:5:"Û Ú©";s:2:"99";s:5:"ÛŒ Ùˆ";s:3:"100";s:5:"Û’ د";s:3:"101";s:5:" تو";s:3:"102";s:5:" تھ";s:3:"103";s:5:" Ú¯ÛŒ";s:3:"104";s:6:"ایک";s:3:"105";s:5:"Ù„ Ú©";s:3:"106";s:5:"نا ";s:3:"107";s:5:"کر ";s:3:"108";s:5:"Úº Ù…";s:3:"109";s:5:"یک ";s:3:"110";s:5:" با";s:3:"111";s:5:"ا ت";s:3:"112";s:5:"دی ";s:3:"113";s:5:"Ù† س";s:3:"114";s:6:"کیا";s:3:"115";s:6:"یوں";s:3:"116";s:5:"Û’ ج";s:3:"117";s:5:"ال ";s:3:"118";s:5:"تو ";s:3:"119";s:5:"Úº ا";s:3:"120";s:5:"Û’ Ù¾";s:3:"121";s:5:" چا";s:3:"122";s:5:"ام ";s:3:"123";s:6:"بھی";s:3:"124";s:5:"تی ";s:3:"125";s:5:"تے ";s:3:"126";s:6:"دوس";s:3:"127";s:5:"س Ú©";s:3:"128";s:6:"ملک";s:3:"129";s:5:"Ù† ا";s:3:"130";s:6:"Ûور";s:3:"131";s:5:"یے ";s:3:"132";s:5:" مو";s:3:"133";s:5:" ÙˆÚ©";s:3:"134";s:6:"ائی";s:3:"135";s:6:"ارت";s:3:"136";s:6:"الے";s:3:"137";s:6:"بھا";s:3:"138";s:6:"ردی";s:3:"139";s:5:"ری ";s:3:"140";s:5:"ÙˆÛ ";s:3:"141";s:6:"ویز";s:3:"142";s:5:"Úº د";s:3:"143";s:5:"Ú¾ÛŒ ";s:3:"144";s:5:"ÛŒ س";s:3:"145";s:5:" رÛ";s:3:"146";s:5:" من";s:3:"147";s:5:" Ù†Û";s:3:"148";s:5:" ور";s:3:"149";s:5:" ÙˆÛ";s:3:"150";s:5:" ÛÙ†";s:3:"151";s:5:"ا ا";s:3:"152";s:6:"است";s:3:"153";s:5:"ت ا";s:3:"154";s:5:"ت Ù¾";s:3:"155";s:5:"د Ú©";s:3:"156";s:5:"ز Ù…";s:3:"157";s:5:"ند ";s:3:"158";s:6:"ورد";s:3:"159";s:6:"ÙˆÚ©Ù„";s:3:"160";s:5:"Ú¯ÛŒ ";s:3:"161";s:6:"گیا";s:3:"162";s:5:"Û Ù¾";s:3:"163";s:5:"یز ";s:3:"164";s:5:"Û’ ت";s:3:"165";s:5:" اع";s:3:"166";s:5:" اپ";s:3:"167";s:5:" جس";s:3:"168";s:5:" جم";s:3:"169";s:5:" جو";s:3:"170";s:5:" سر";s:3:"171";s:6:"اپن";s:3:"172";s:6:"اکث";s:3:"173";s:6:"تھا";s:3:"174";s:6:"ثری";s:3:"175";s:6:"دیا";s:3:"176";s:5:"ر د";s:3:"177";s:5:"رت ";s:3:"178";s:6:"روی";s:3:"179";s:5:"سی ";s:3:"180";s:6:"ملا";s:3:"181";s:6:"ندو";s:3:"182";s:6:"وست";s:3:"183";s:6:"پرو";s:3:"184";s:6:"چاÛ";s:3:"185";s:6:"کثر";s:3:"186";s:6:"کلا";s:3:"187";s:5:"Û Û";s:3:"188";s:6:"Ûند";s:3:"189";s:5:"ÛÙˆ ";s:3:"190";s:5:"Û’ Ù„";s:3:"191";s:5:" اک";s:3:"192";s:5:" دا";s:3:"193";s:5:" سن";s:3:"194";s:5:" وز";s:3:"195";s:5:" Ù¾ÛŒ";s:3:"196";s:5:"ا Ú†";s:3:"197";s:5:"اء ";s:3:"198";s:6:"اتھ";s:3:"199";s:6:"اقا";s:3:"200";s:5:"Ø§Û ";s:3:"201";s:5:"تھ ";s:3:"202";s:5:"دو ";s:3:"203";s:5:"ر ب";s:3:"204";s:6:"روا";s:3:"205";s:5:"رے ";s:3:"206";s:6:"سات";s:3:"207";s:5:"Ù Ú©";s:3:"208";s:6:"قات";s:3:"209";s:5:"لا ";s:3:"210";s:6:"لاء";s:3:"211";s:5:"Ù… Ù…";s:3:"212";s:5:"Ù… Ú©";s:3:"213";s:5:"من ";s:3:"214";s:6:"نوں";s:3:"215";s:5:"Ùˆ ا";s:3:"216";s:6:"کرن";s:3:"217";s:5:"Úº Û";s:3:"218";s:6:"ھار";s:3:"219";s:6:"Ûوئ";s:3:"220";s:5:"ÛÛŒ ";s:3:"221";s:5:"یش ";s:3:"222";s:5:" ام";s:3:"223";s:5:" لا";s:3:"224";s:5:" مس";s:3:"225";s:5:" پو";s:3:"226";s:5:" Ù¾Û";s:3:"227";s:6:"انے";s:3:"228";s:5:"ت Ù…";s:3:"229";s:5:"ت Û";s:3:"230";s:5:"ج Ú©";s:3:"231";s:6:"دون";s:3:"232";s:6:"زیر";s:3:"233";s:5:"س س";s:3:"234";s:5:"Ø´ Ú©";s:3:"235";s:5:"Ù Ù†";s:3:"236";s:5:"Ù„ Û";s:3:"237";s:6:"لاق";s:3:"238";s:5:"Ù„ÛŒ ";s:3:"239";s:6:"وری";s:3:"240";s:6:"وزی";s:3:"241";s:6:"ونو";s:3:"242";s:6:"Ú©Ú¾Ù†";s:3:"243";s:5:"گا ";s:3:"244";s:5:"Úº س";s:3:"245";s:5:"Úº Ú¯";s:3:"246";s:6:"Ú¾Ù†Û’";s:3:"247";s:5:"Ú¾Û’ ";s:3:"248";s:5:"Û Ø¨";s:3:"249";s:5:"Û Ø¬";s:3:"250";s:5:"Ûر ";s:3:"251";s:5:"ÛŒ Ø¢";s:3:"252";s:5:"ÛŒ Ù¾";s:3:"253";s:5:" حا";s:3:"254";s:5:" ÙˆÙ";s:3:"255";s:5:" گا";s:3:"256";s:5:"ا ج";s:3:"257";s:5:"ا Ú¯";s:3:"258";s:5:"اد ";s:3:"259";s:6:"ادی";s:3:"260";s:6:"اعظ";s:3:"261";s:6:"اÛت";s:3:"262";s:5:"جس ";s:3:"263";s:6:"جمÛ";s:3:"264";s:5:"جو ";s:3:"265";s:5:"ر س";s:3:"266";s:5:"ر Û";s:3:"267";s:6:"رنے";s:3:"268";s:5:"س Ù…";s:3:"269";s:5:"سا ";s:3:"270";s:6:"سند";s:3:"271";s:6:"سنگ";s:3:"272";s:5:"ظم ";s:3:"273";s:6:"عظم";s:3:"274";s:5:"Ù„ Ù…";s:3:"275";s:6:"لیے";s:3:"276";s:5:"مل ";s:3:"277";s:6:"موÛ";s:3:"278";s:6:"Ù…ÛÙˆ";s:3:"279";s:6:"Ù†Ú¯Ú¾";s:3:"280";s:5:"Ùˆ ص";s:3:"281";s:6:"ورٹ";s:3:"282";s:6:"ÙˆÛÙ†";s:3:"283";s:5:"Ú©Ù† ";s:3:"284";s:5:"Ú¯Ú¾ ";s:3:"285";s:5:"Ú¯Û’ ";s:3:"286";s:5:"Úº ج";s:3:"287";s:5:"Úº Ùˆ";s:3:"288";s:5:"Úº ÛŒ";s:3:"289";s:5:"Û Ø¯";s:3:"290";s:5:"ÛÙ† ";s:3:"291";s:6:"ÛÙˆÚº";s:3:"292";s:5:"Û’ Ø­";s:3:"293";s:5:"Û’ Ú¯";s:3:"294";s:5:"Û’ ÛŒ";s:3:"295";s:5:" اگ";s:3:"296";s:5:" بع";s:3:"297";s:5:" رو";s:3:"298";s:5:" شا";s:3:"299";}s:5:"uzbek";a:300:{s:5:"ан ";s:1:"0";s:6:"ган";s:1:"1";s:6:"лар";s:1:"2";s:5:"га ";s:1:"3";s:5:"нг ";s:1:"4";s:6:"инг";s:1:"5";s:6:"нин";s:1:"6";s:5:"да ";s:1:"7";s:5:"ни ";s:1:"8";s:6:"ида";s:1:"9";s:6:"ари";s:2:"10";s:6:"ига";s:2:"11";s:6:"ини";s:2:"12";s:5:"ар ";s:2:"13";s:5:"ди ";s:2:"14";s:5:" би";s:2:"15";s:6:"ани";s:2:"16";s:5:" бо";s:2:"17";s:6:"дан";s:2:"18";s:6:"лга";s:2:"19";s:5:" ҳа";s:2:"20";s:5:" ва";s:2:"21";s:5:" Ñа";s:2:"22";s:5:"ги ";s:2:"23";s:6:"ила";s:2:"24";s:5:"н б";s:2:"25";s:5:"и б";s:2:"26";s:5:" кў";s:2:"27";s:5:" та";s:2:"28";s:5:"ир ";s:2:"29";s:5:" ма";s:2:"30";s:6:"ага";s:2:"31";s:6:"ала";s:2:"32";s:6:"бир";s:2:"33";s:5:"ри ";s:2:"34";s:6:"тга";s:2:"35";s:6:"лан";s:2:"36";s:6:"лик";s:2:"37";s:5:"а к";s:2:"38";s:6:"аги";s:2:"39";s:6:"ати";s:2:"40";s:5:"та ";s:2:"41";s:6:"ади";s:2:"42";s:6:"даг";s:2:"43";s:6:"рга";s:2:"44";s:5:" йи";s:2:"45";s:5:" ми";s:2:"46";s:5:" па";s:2:"47";s:5:" бў";s:2:"48";s:5:" қа";s:2:"49";s:5:" қи";s:2:"50";s:5:"а б";s:2:"51";s:6:"илл";s:2:"52";s:5:"ли ";s:2:"53";s:6:"аÑи";s:2:"54";s:5:"и Ñ‚";s:2:"55";s:5:"ик ";s:2:"56";s:6:"или";s:2:"57";s:6:"лла";s:2:"58";s:6:"ард";s:2:"59";s:6:"вчи";s:2:"60";s:5:"ва ";s:2:"61";s:5:"иб ";s:2:"62";s:6:"ири";s:2:"63";s:6:"лиг";s:2:"64";s:6:"нга";s:2:"65";s:6:"ран";s:2:"66";s:5:" ке";s:2:"67";s:5:" ўз";s:2:"68";s:5:"а Ñ";s:2:"69";s:6:"ахт";s:2:"70";s:6:"бўл";s:2:"71";s:6:"иги";s:2:"72";s:6:"кўр";s:2:"73";s:6:"рда";s:2:"74";s:6:"рни";s:2:"75";s:5:"Ñа ";s:2:"76";s:5:" бе";s:2:"77";s:5:" бу";s:2:"78";s:5:" да";s:2:"79";s:5:" жа";s:2:"80";s:5:"а Ñ‚";s:2:"81";s:6:"ази";s:2:"82";s:6:"ери";s:2:"83";s:5:"и а";s:2:"84";s:6:"илг";s:2:"85";s:6:"йил";s:2:"86";s:6:"ман";s:2:"87";s:6:"пах";s:2:"88";s:6:"рид";s:2:"89";s:5:"ти ";s:2:"90";s:6:"увч";s:2:"91";s:6:"хта";s:2:"92";s:5:" не";s:2:"93";s:5:" Ñо";s:2:"94";s:5:" уч";s:2:"95";s:6:"айт";s:2:"96";s:6:"лли";s:2:"97";s:6:"тла";s:2:"98";s:5:" ай";s:2:"99";s:5:" Ñ„Ñ€";s:3:"100";s:5:" ÑÑ‚";s:3:"101";s:5:" ҳо";s:3:"102";s:5:"а Ò›";s:3:"103";s:6:"али";s:3:"104";s:6:"аро";s:3:"105";s:6:"бер";s:3:"106";s:6:"бил";s:3:"107";s:6:"бор";s:3:"108";s:6:"ими";s:3:"109";s:6:"иÑÑ‚";s:3:"110";s:5:"он ";s:3:"111";s:6:"рин";s:3:"112";s:6:"тер";s:3:"113";s:6:"тил";s:3:"114";s:5:"ун ";s:3:"115";s:6:"фра";s:3:"116";s:6:"қил";s:3:"117";s:5:" ба";s:3:"118";s:5:" ол";s:3:"119";s:6:"анÑ";s:3:"120";s:6:"ефт";s:3:"121";s:6:"зир";s:3:"122";s:6:"кат";s:3:"123";s:6:"мил";s:3:"124";s:6:"неф";s:3:"125";s:6:"Ñаг";s:3:"126";s:5:"чи ";s:3:"127";s:6:"ўра";s:3:"128";s:5:" на";s:3:"129";s:5:" те";s:3:"130";s:5:" Ñн";s:3:"131";s:5:"а Ñ";s:3:"132";s:5:"ам ";s:3:"133";s:6:"арн";s:3:"134";s:5:"ат ";s:3:"135";s:5:"иш ";s:3:"136";s:5:"ма ";s:3:"137";s:6:"нла";s:3:"138";s:6:"рли";s:3:"139";s:6:"чил";s:3:"140";s:6:"шга";s:3:"141";s:5:" иш";s:3:"142";s:5:" му";s:3:"143";s:5:" ÑžÒ›";s:3:"144";s:6:"ара";s:3:"145";s:6:"ваз";s:3:"146";s:5:"и у";s:3:"147";s:5:"иқ ";s:3:"148";s:6:"моқ";s:3:"149";s:6:"рим";s:3:"150";s:6:"учу";s:3:"151";s:6:"чун";s:3:"152";s:5:"ши ";s:3:"153";s:6:"Ñнг";s:3:"154";s:6:"қув";s:3:"155";s:6:"ҳам";s:3:"156";s:5:" ÑÑž";s:3:"157";s:5:" ши";s:3:"158";s:6:"бар";s:3:"159";s:6:"бек";s:3:"160";s:6:"дам";s:3:"161";s:5:"и Ò³";s:3:"162";s:6:"иши";s:3:"163";s:6:"лад";s:3:"164";s:6:"оли";s:3:"165";s:6:"олл";s:3:"166";s:6:"ори";s:3:"167";s:6:"оқд";s:3:"168";s:5:"Ñ€ б";s:3:"169";s:5:"ра ";s:3:"170";s:6:"рла";s:3:"171";s:6:"уни";s:3:"172";s:5:"Ñ„Ñ‚ ";s:3:"173";s:6:"ўлг";s:3:"174";s:6:"ўқу";s:3:"175";s:5:" де";s:3:"176";s:5:" ка";s:3:"177";s:5:" қў";s:3:"178";s:5:"а Ñž";s:3:"179";s:6:"аба";s:3:"180";s:6:"амм";s:3:"181";s:6:"атл";s:3:"182";s:5:"б к";s:3:"183";s:6:"бош";s:3:"184";s:6:"збе";s:3:"185";s:5:"и в";s:3:"186";s:5:"им ";s:3:"187";s:5:"ин ";s:3:"188";s:6:"ишл";s:3:"189";s:6:"лаб";s:3:"190";s:6:"лей";s:3:"191";s:6:"мин";s:3:"192";s:5:"н д";s:3:"193";s:6:"нда";s:3:"194";s:5:"оқ ";s:3:"195";s:5:"Ñ€ м";s:3:"196";s:6:"рил";s:3:"197";s:6:"Ñид";s:3:"198";s:6:"тал";s:3:"199";s:6:"тан";s:3:"200";s:6:"тид";s:3:"201";s:6:"тон";s:3:"202";s:6:"ўзб";s:3:"203";s:5:" ам";s:3:"204";s:5:" ки";s:3:"205";s:5:"а Ò³";s:3:"206";s:6:"анг";s:3:"207";s:6:"анд";s:3:"208";s:6:"арт";s:3:"209";s:6:"аёт";s:3:"210";s:6:"дир";s:3:"211";s:6:"ент";s:3:"212";s:5:"и д";s:3:"213";s:5:"и м";s:3:"214";s:5:"и о";s:3:"215";s:5:"и Ñ";s:3:"216";s:6:"иро";s:3:"217";s:6:"йти";s:3:"218";s:6:"нÑу";s:3:"219";s:6:"оди";s:3:"220";s:5:"ор ";s:3:"221";s:5:"Ñи ";s:3:"222";s:6:"тиш";s:3:"223";s:6:"тоб";s:3:"224";s:6:"Ñти";s:3:"225";s:6:"қар";s:3:"226";s:6:"қда";s:3:"227";s:5:" бл";s:3:"228";s:5:" ге";s:3:"229";s:5:" до";s:3:"230";s:5:" ду";s:3:"231";s:5:" но";s:3:"232";s:5:" пр";s:3:"233";s:5:" ра";s:3:"234";s:5:" фо";s:3:"235";s:5:" қо";s:3:"236";s:5:"а м";s:3:"237";s:5:"а о";s:3:"238";s:6:"айд";s:3:"239";s:6:"ало";s:3:"240";s:6:"ама";s:3:"241";s:6:"бле";s:3:"242";s:5:"г н";s:3:"243";s:6:"дол";s:3:"244";s:6:"ейр";s:3:"245";s:5:"ек ";s:3:"246";s:6:"ерг";s:3:"247";s:6:"жар";s:3:"248";s:6:"зид";s:3:"249";s:5:"и к";s:3:"250";s:5:"и Ñ„";s:3:"251";s:5:"ий ";s:3:"252";s:6:"ило";s:3:"253";s:6:"лди";s:3:"254";s:6:"либ";s:3:"255";s:6:"лин";s:3:"256";s:5:"ми ";s:3:"257";s:6:"мма";s:3:"258";s:5:"н в";s:3:"259";s:5:"н к";s:3:"260";s:5:"н Ñž";s:3:"261";s:5:"н Ò³";s:3:"262";s:6:"ози";s:3:"263";s:6:"ора";s:3:"264";s:6:"оÑи";s:3:"265";s:6:"раÑ";s:3:"266";s:6:"риш";s:3:"267";s:6:"рка";s:3:"268";s:6:"роқ";s:3:"269";s:6:"Ñто";s:3:"270";s:6:"тин";s:3:"271";s:6:"хат";s:3:"272";s:6:"шир";s:3:"273";s:5:" ав";s:3:"274";s:5:" рў";s:3:"275";s:5:" ту";s:3:"276";s:5:" ўт";s:3:"277";s:5:"а п";s:3:"278";s:6:"авт";s:3:"279";s:6:"ада";s:3:"280";s:6:"аза";s:3:"281";s:6:"анл";s:3:"282";s:5:"б б";s:3:"283";s:6:"бой";s:3:"284";s:5:"бу ";s:3:"285";s:6:"вто";s:3:"286";s:5:"г Ñ";s:3:"287";s:6:"гин";s:3:"288";s:6:"дар";s:3:"289";s:6:"ден";s:3:"290";s:6:"дун";s:3:"291";s:6:"иде";s:3:"292";s:6:"ион";s:3:"293";s:6:"ирл";s:3:"294";s:6:"ишг";s:3:"295";s:6:"йха";s:3:"296";s:6:"кел";s:3:"297";s:6:"кўп";s:3:"298";s:6:"лио";s:3:"299";}s:10:"vietnamese";a:300:{s:3:"ng ";s:1:"0";s:3:" th";s:1:"1";s:3:" ch";s:1:"2";s:3:"g t";s:1:"3";s:3:" nh";s:1:"4";s:4:"ông";s:1:"5";s:3:" kh";s:1:"6";s:3:" tr";s:1:"7";s:3:"nh ";s:1:"8";s:4:" cô";s:1:"9";s:4:"côn";s:2:"10";s:3:" ty";s:2:"11";s:3:"ty ";s:2:"12";s:3:"i t";s:2:"13";s:3:"n t";s:2:"14";s:3:" ng";s:2:"15";s:5:"ại ";s:2:"16";s:3:" ti";s:2:"17";s:3:"ch ";s:2:"18";s:3:"y l";s:2:"19";s:5:"á»n ";s:2:"20";s:5:" Ä‘Æ°";s:2:"21";s:3:"hi ";s:2:"22";s:5:" gở";s:2:"23";s:5:"gởi";s:2:"24";s:5:"iá»n";s:2:"25";s:5:"tiá»";s:2:"26";s:5:"ởi ";s:2:"27";s:3:" gi";s:2:"28";s:3:" le";s:2:"29";s:3:" vi";s:2:"30";s:3:"cho";s:2:"31";s:3:"ho ";s:2:"32";s:4:"khá";s:2:"33";s:4:" và";s:2:"34";s:4:"hác";s:2:"35";s:3:" ph";s:2:"36";s:3:"am ";s:2:"37";s:4:"hàn";s:2:"38";s:4:"ách";s:2:"39";s:4:"ôi ";s:2:"40";s:3:"i n";s:2:"41";s:6:"ược";s:2:"42";s:5:"ợc ";s:2:"43";s:4:" tô";s:2:"44";s:4:"chú";s:2:"45";s:5:"iệt";s:2:"46";s:4:"tôi";s:2:"47";s:4:"ên ";s:2:"48";s:4:"úng";s:2:"49";s:5:"ệt ";s:2:"50";s:4:" có";s:2:"51";s:3:"c t";s:2:"52";s:4:"có ";s:2:"53";s:4:"hún";s:2:"54";s:5:"việ";s:2:"55";s:7:"đượ";s:2:"56";s:3:" na";s:2:"57";s:3:"g c";s:2:"58";s:3:"i c";s:2:"59";s:3:"n c";s:2:"60";s:3:"n n";s:2:"61";s:3:"t n";s:2:"62";s:4:"và ";s:2:"63";s:3:"n l";s:2:"64";s:4:"n Ä‘";s:2:"65";s:4:"àng";s:2:"66";s:4:"ác ";s:2:"67";s:5:"ất ";s:2:"68";s:3:"h l";s:2:"69";s:3:"nam";s:2:"70";s:4:"ân ";s:2:"71";s:4:"ăm ";s:2:"72";s:4:" hà";s:2:"73";s:4:" là";s:2:"74";s:4:" nă";s:2:"75";s:3:" qu";s:2:"76";s:5:" tạ";s:2:"77";s:3:"g m";s:2:"78";s:4:"năm";s:2:"79";s:5:"tại";s:2:"80";s:5:"á»›i ";s:2:"81";s:5:" lẹ";s:2:"82";s:3:"ay ";s:2:"83";s:3:"e g";s:2:"84";s:3:"h h";s:2:"85";s:3:"i v";s:2:"86";s:4:"i Ä‘";s:2:"87";s:3:"le ";s:2:"88";s:5:"lẹ ";s:2:"89";s:5:"á»u ";s:2:"90";s:5:"á»i ";s:2:"91";s:4:"hân";s:2:"92";s:3:"nhi";s:2:"93";s:3:"t t";s:2:"94";s:5:" củ";s:2:"95";s:5:" má»™";s:2:"96";s:5:" vá»";s:2:"97";s:4:" Ä‘i";s:2:"98";s:3:"an ";s:2:"99";s:5:"của";s:3:"100";s:4:"là ";s:3:"101";s:5:"má»™t";s:3:"102";s:5:"vá» ";s:3:"103";s:4:"ành";s:3:"104";s:5:"ết ";s:3:"105";s:5:"á»™t ";s:3:"106";s:5:"ủa ";s:3:"107";s:3:" bi";s:3:"108";s:4:" cá";s:3:"109";s:3:"a c";s:3:"110";s:3:"anh";s:3:"111";s:4:"các";s:3:"112";s:3:"h c";s:3:"113";s:5:"iá»u";s:3:"114";s:3:"m t";s:3:"115";s:5:"ện ";s:3:"116";s:3:" ho";s:3:"117";s:3:"'s ";s:3:"118";s:3:"ave";s:3:"119";s:3:"e's";s:3:"120";s:3:"el ";s:3:"121";s:3:"g n";s:3:"122";s:3:"le'";s:3:"123";s:3:"n v";s:3:"124";s:3:"o c";s:3:"125";s:3:"rav";s:3:"126";s:3:"s t";s:3:"127";s:3:"thi";s:3:"128";s:3:"tra";s:3:"129";s:3:"vel";s:3:"130";s:5:"ận ";s:3:"131";s:5:"ến ";s:3:"132";s:3:" ba";s:3:"133";s:3:" cu";s:3:"134";s:3:" sa";s:3:"135";s:5:" đó";s:3:"136";s:6:" đế";s:3:"137";s:3:"c c";s:3:"138";s:3:"chu";s:3:"139";s:5:"hiá»";s:3:"140";s:3:"huy";s:3:"141";s:3:"khi";s:3:"142";s:4:"nhâ";s:3:"143";s:4:"nhÆ°";s:3:"144";s:3:"ong";s:3:"145";s:3:"ron";s:3:"146";s:3:"thu";s:3:"147";s:4:"thÆ°";s:3:"148";s:3:"tro";s:3:"149";s:3:"y c";s:3:"150";s:4:"ày ";s:3:"151";s:6:"đến";s:3:"152";s:6:"Æ°á»i";s:3:"153";s:6:"Æ°á»n";s:3:"154";s:5:"á» v";s:3:"155";s:5:"á»ng";s:3:"156";s:5:" vá»›";s:3:"157";s:5:"cuá»™";s:3:"158";s:4:"g Ä‘";s:3:"159";s:5:"iết";s:3:"160";s:5:"iện";s:3:"161";s:4:"ngà";s:3:"162";s:3:"o t";s:3:"163";s:3:"u c";s:3:"164";s:5:"uá»™c";s:3:"165";s:5:"vá»›i";s:3:"166";s:4:"à c";s:3:"167";s:4:"ài ";s:3:"168";s:4:"Æ¡ng";s:3:"169";s:5:"Æ°Æ¡n";s:3:"170";s:5:"ải ";s:3:"171";s:5:"á»™c ";s:3:"172";s:5:"ức ";s:3:"173";s:3:" an";s:3:"174";s:5:" lậ";s:3:"175";s:3:" ra";s:3:"176";s:5:" sẽ";s:3:"177";s:5:" số";s:3:"178";s:5:" tổ";s:3:"179";s:3:"a k";s:3:"180";s:5:"biế";s:3:"181";s:3:"c n";s:3:"182";s:4:"c Ä‘";s:3:"183";s:5:"chứ";s:3:"184";s:3:"g v";s:3:"185";s:3:"gia";s:3:"186";s:4:"gày";s:3:"187";s:4:"hán";s:3:"188";s:4:"hôn";s:3:"189";s:4:"hÆ° ";s:3:"190";s:5:"hức";s:3:"191";s:3:"i g";s:3:"192";s:3:"i h";s:3:"193";s:3:"i k";s:3:"194";s:3:"i p";s:3:"195";s:4:"iên";s:3:"196";s:4:"khô";s:3:"197";s:5:"lập";s:3:"198";s:3:"n k";s:3:"199";s:3:"ra ";s:3:"200";s:4:"rên";s:3:"201";s:5:"sẽ ";s:3:"202";s:3:"t c";s:3:"203";s:4:"thà";s:3:"204";s:4:"trê";s:3:"205";s:5:"tổ ";s:3:"206";s:3:"u n";s:3:"207";s:3:"y t";s:3:"208";s:4:"ình";s:3:"209";s:5:"ấy ";s:3:"210";s:5:"ập ";s:3:"211";s:5:"ổ c";s:3:"212";s:4:" má";s:3:"213";s:6:" để";s:3:"214";s:3:"ai ";s:3:"215";s:3:"c s";s:3:"216";s:6:"gÆ°á»";s:3:"217";s:3:"h v";s:3:"218";s:3:"hoa";s:3:"219";s:5:"hoạ";s:3:"220";s:3:"inh";s:3:"221";s:3:"m n";s:3:"222";s:4:"máy";s:3:"223";s:3:"n g";s:3:"224";s:4:"ngÆ°";s:3:"225";s:5:"nhậ";s:3:"226";s:3:"o n";s:3:"227";s:3:"oa ";s:3:"228";s:4:"oàn";s:3:"229";s:3:"p c";s:3:"230";s:5:"số ";s:3:"231";s:4:"t Ä‘";s:3:"232";s:3:"y v";s:3:"233";s:4:"ào ";s:3:"234";s:4:"áy ";s:3:"235";s:4:"ăn ";s:3:"236";s:5:"đó ";s:3:"237";s:6:"để ";s:3:"238";s:6:"Æ°á»›c";s:3:"239";s:5:"ần ";s:3:"240";s:5:"ển ";s:3:"241";s:5:"á»›c ";s:3:"242";s:4:" bá";s:3:"243";s:4:" cÆ¡";s:3:"244";s:5:" cả";s:3:"245";s:5:" cầ";s:3:"246";s:5:" há»";s:3:"247";s:5:" kỳ";s:3:"248";s:3:" li";s:3:"249";s:5:" mạ";s:3:"250";s:5:" sở";s:3:"251";s:5:" tặ";s:3:"252";s:4:" vé";s:3:"253";s:5:" vụ";s:3:"254";s:6:" đạ";s:3:"255";s:4:"a Ä‘";s:3:"256";s:3:"bay";s:3:"257";s:4:"cÆ¡ ";s:3:"258";s:3:"g s";s:3:"259";s:3:"han";s:3:"260";s:5:"hÆ°Æ¡";s:3:"261";s:3:"i s";s:3:"262";s:5:"kỳ ";s:3:"263";s:3:"m c";s:3:"264";s:3:"n m";s:3:"265";s:3:"n p";s:3:"266";s:3:"o b";s:3:"267";s:5:"oại";s:3:"268";s:3:"qua";s:3:"269";s:5:"sở ";s:3:"270";s:3:"tha";s:3:"271";s:4:"thá";s:3:"272";s:5:"tặn";s:3:"273";s:4:"vào";s:3:"274";s:4:"vé ";s:3:"275";s:5:"vụ ";s:3:"276";s:3:"y b";s:3:"277";s:4:"àn ";s:3:"278";s:4:"áng";s:3:"279";s:4:"Æ¡ s";s:3:"280";s:5:"ầu ";s:3:"281";s:5:"ật ";s:3:"282";s:5:"ặng";s:3:"283";s:5:"á»c ";s:3:"284";s:5:"ở t";s:3:"285";s:5:"ững";s:3:"286";s:3:" du";s:3:"287";s:3:" lu";s:3:"288";s:3:" ta";s:3:"289";s:3:" to";s:3:"290";s:5:" từ";s:3:"291";s:5:" ở ";s:3:"292";s:3:"a v";s:3:"293";s:3:"ao ";s:3:"294";s:3:"c v";s:3:"295";s:5:"cả ";s:3:"296";s:3:"du ";s:3:"297";s:3:"g l";s:3:"298";s:5:"giả";s:3:"299";}s:5:"welsh";a:300:{s:3:"yn ";s:1:"0";s:3:"dd ";s:1:"1";s:3:" yn";s:1:"2";s:3:" y ";s:1:"3";s:3:"ydd";s:1:"4";s:3:"eth";s:1:"5";s:3:"th ";s:1:"6";s:3:" i ";s:1:"7";s:3:"aet";s:1:"8";s:3:"d y";s:1:"9";s:3:"ch ";s:2:"10";s:3:"od ";s:2:"11";s:3:"ol ";s:2:"12";s:3:"edd";s:2:"13";s:3:" ga";s:2:"14";s:3:" gw";s:2:"15";s:3:"'r ";s:2:"16";s:3:"au ";s:2:"17";s:3:"ddi";s:2:"18";s:3:"ad ";s:2:"19";s:3:" cy";s:2:"20";s:3:" gy";s:2:"21";s:3:" ei";s:2:"22";s:3:" o ";s:2:"23";s:3:"iad";s:2:"24";s:3:"yr ";s:2:"25";s:3:"an ";s:2:"26";s:3:"bod";s:2:"27";s:3:"wed";s:2:"28";s:3:" bo";s:2:"29";s:3:" dd";s:2:"30";s:3:"el ";s:2:"31";s:3:"n y";s:2:"32";s:3:" am";s:2:"33";s:3:"di ";s:2:"34";s:3:"edi";s:2:"35";s:3:"on ";s:2:"36";s:3:" we";s:2:"37";s:3:" ym";s:2:"38";s:3:" ar";s:2:"39";s:3:" rh";s:2:"40";s:3:"odd";s:2:"41";s:3:" ca";s:2:"42";s:3:" ma";s:2:"43";s:3:"ael";s:2:"44";s:3:"oed";s:2:"45";s:3:"dae";s:2:"46";s:3:"n a";s:2:"47";s:3:"dda";s:2:"48";s:3:"er ";s:2:"49";s:3:"h y";s:2:"50";s:3:"all";s:2:"51";s:3:"ei ";s:2:"52";s:3:" ll";s:2:"53";s:3:"am ";s:2:"54";s:3:"eu ";s:2:"55";s:3:"fod";s:2:"56";s:3:"fyd";s:2:"57";s:3:"l y";s:2:"58";s:3:"n g";s:2:"59";s:3:"wyn";s:2:"60";s:3:"d a";s:2:"61";s:3:"i g";s:2:"62";s:3:"mae";s:2:"63";s:3:"neu";s:2:"64";s:3:"os ";s:2:"65";s:3:" ne";s:2:"66";s:3:"d i";s:2:"67";s:3:"dod";s:2:"68";s:3:"dol";s:2:"69";s:3:"n c";s:2:"70";s:3:"r h";s:2:"71";s:3:"wyd";s:2:"72";s:3:"wyr";s:2:"73";s:3:"ai ";s:2:"74";s:3:"ar ";s:2:"75";s:3:"in ";s:2:"76";s:3:"rth";s:2:"77";s:3:" fy";s:2:"78";s:3:" he";s:2:"79";s:3:" me";s:2:"80";s:3:" yr";s:2:"81";s:3:"'n ";s:2:"82";s:3:"dia";s:2:"83";s:3:"est";s:2:"84";s:3:"h c";s:2:"85";s:3:"hai";s:2:"86";s:3:"i d";s:2:"87";s:3:"id ";s:2:"88";s:3:"r y";s:2:"89";s:3:"y b";s:2:"90";s:3:" dy";s:2:"91";s:3:" ha";s:2:"92";s:3:"ada";s:2:"93";s:3:"i b";s:2:"94";s:3:"n i";s:2:"95";s:3:"ote";s:2:"96";s:3:"rot";s:2:"97";s:3:"tes";s:2:"98";s:3:"y g";s:2:"99";s:3:"yd ";s:3:"100";s:3:" ad";s:3:"101";s:3:" mr";s:3:"102";s:3:" un";s:3:"103";s:3:"cyn";s:3:"104";s:3:"dau";s:3:"105";s:3:"ddy";s:3:"106";s:3:"edo";s:3:"107";s:3:"i c";s:3:"108";s:3:"i w";s:3:"109";s:3:"ith";s:3:"110";s:3:"lae";s:3:"111";s:3:"lla";s:3:"112";s:3:"nd ";s:3:"113";s:3:"oda";s:3:"114";s:3:"ryd";s:3:"115";s:3:"tho";s:3:"116";s:3:" a ";s:3:"117";s:3:" dr";s:3:"118";s:3:"aid";s:3:"119";s:3:"ain";s:3:"120";s:3:"ddo";s:3:"121";s:3:"dyd";s:3:"122";s:3:"fyn";s:3:"123";s:3:"gyn";s:3:"124";s:3:"hol";s:3:"125";s:3:"io ";s:3:"126";s:3:"o a";s:3:"127";s:3:"wch";s:3:"128";s:3:"wyb";s:3:"129";s:3:"ybo";s:3:"130";s:3:"ych";s:3:"131";s:3:" br";s:3:"132";s:3:" by";s:3:"133";s:3:" di";s:3:"134";s:3:" fe";s:3:"135";s:3:" na";s:3:"136";s:3:" o'";s:3:"137";s:3:" pe";s:3:"138";s:3:"art";s:3:"139";s:3:"byd";s:3:"140";s:3:"dro";s:3:"141";s:3:"gal";s:3:"142";s:3:"l e";s:3:"143";s:3:"lai";s:3:"144";s:3:"mr ";s:3:"145";s:3:"n n";s:3:"146";s:3:"r a";s:3:"147";s:3:"rhy";s:3:"148";s:3:"wn ";s:3:"149";s:3:"ynn";s:3:"150";s:3:" on";s:3:"151";s:3:" r ";s:3:"152";s:3:"cae";s:3:"153";s:3:"d g";s:3:"154";s:3:"d o";s:3:"155";s:3:"d w";s:3:"156";s:3:"gan";s:3:"157";s:3:"gwy";s:3:"158";s:3:"n d";s:3:"159";s:3:"n f";s:3:"160";s:3:"n o";s:3:"161";s:3:"ned";s:3:"162";s:3:"ni ";s:3:"163";s:3:"o'r";s:3:"164";s:3:"r d";s:3:"165";s:3:"ud ";s:3:"166";s:3:"wei";s:3:"167";s:3:"wrt";s:3:"168";s:3:" an";s:3:"169";s:3:" cw";s:3:"170";s:3:" da";s:3:"171";s:3:" ni";s:3:"172";s:3:" pa";s:3:"173";s:3:" pr";s:3:"174";s:3:" wy";s:3:"175";s:3:"d e";s:3:"176";s:3:"dai";s:3:"177";s:3:"dim";s:3:"178";s:3:"eud";s:3:"179";s:3:"gwa";s:3:"180";s:3:"idd";s:3:"181";s:3:"im ";s:3:"182";s:3:"iri";s:3:"183";s:3:"lwy";s:3:"184";s:3:"n b";s:3:"185";s:3:"nol";s:3:"186";s:3:"r o";s:3:"187";s:3:"rwy";s:3:"188";s:3:" ch";s:3:"189";s:3:" er";s:3:"190";s:3:" fo";s:3:"191";s:3:" ge";s:3:"192";s:3:" hy";s:3:"193";s:3:" i'";s:3:"194";s:3:" ro";s:3:"195";s:3:" sa";s:3:"196";s:3:" tr";s:3:"197";s:3:"bob";s:3:"198";s:3:"cwy";s:3:"199";s:3:"cyf";s:3:"200";s:3:"dio";s:3:"201";s:3:"dyn";s:3:"202";s:3:"eit";s:3:"203";s:3:"hel";s:3:"204";s:3:"hyn";s:3:"205";s:3:"ich";s:3:"206";s:3:"ll ";s:3:"207";s:3:"mdd";s:3:"208";s:3:"n r";s:3:"209";s:3:"ond";s:3:"210";s:3:"pro";s:3:"211";s:3:"r c";s:3:"212";s:3:"r g";s:3:"213";s:3:"red";s:3:"214";s:3:"rha";s:3:"215";s:3:"u a";s:3:"216";s:3:"u c";s:3:"217";s:3:"u y";s:3:"218";s:3:"y c";s:3:"219";s:3:"ymd";s:3:"220";s:3:"ymr";s:3:"221";s:3:"yw ";s:3:"222";s:3:" ac";s:3:"223";s:3:" be";s:3:"224";s:3:" bl";s:3:"225";s:3:" co";s:3:"226";s:3:" os";s:3:"227";s:3:"adw";s:3:"228";s:3:"ae ";s:3:"229";s:3:"af ";s:3:"230";s:3:"d p";s:3:"231";s:3:"efn";s:3:"232";s:3:"eic";s:3:"233";s:3:"en ";s:3:"234";s:3:"eol";s:3:"235";s:3:"es ";s:3:"236";s:3:"fer";s:3:"237";s:3:"gel";s:3:"238";s:3:"h g";s:3:"239";s:3:"hod";s:3:"240";s:3:"ied";s:3:"241";s:3:"ir ";s:3:"242";s:3:"laf";s:3:"243";s:3:"n h";s:3:"244";s:3:"na ";s:3:"245";s:3:"nyd";s:3:"246";s:3:"odo";s:3:"247";s:3:"ofy";s:3:"248";s:3:"rdd";s:3:"249";s:3:"rie";s:3:"250";s:3:"ros";s:3:"251";s:3:"stw";s:3:"252";s:3:"twy";s:3:"253";s:3:"yda";s:3:"254";s:3:"yng";s:3:"255";s:3:" at";s:3:"256";s:3:" de";s:3:"257";s:3:" go";s:3:"258";s:3:" id";s:3:"259";s:3:" oe";s:3:"260";s:4:" â ";s:3:"261";s:3:"'ch";s:3:"262";s:3:"ac ";s:3:"263";s:3:"ach";s:3:"264";s:3:"ae'";s:3:"265";s:3:"al ";s:3:"266";s:3:"bl ";s:3:"267";s:3:"d c";s:3:"268";s:3:"d l";s:3:"269";s:3:"dan";s:3:"270";s:3:"dde";s:3:"271";s:3:"ddw";s:3:"272";s:3:"dir";s:3:"273";s:3:"dla";s:3:"274";s:3:"ed ";s:3:"275";s:3:"ela";s:3:"276";s:3:"ell";s:3:"277";s:3:"ene";s:3:"278";s:3:"ewn";s:3:"279";s:3:"gyd";s:3:"280";s:3:"hau";s:3:"281";s:3:"hyw";s:3:"282";s:3:"i a";s:3:"283";s:3:"i f";s:3:"284";s:3:"iol";s:3:"285";s:3:"ion";s:3:"286";s:3:"l a";s:3:"287";s:3:"l i";s:3:"288";s:3:"lia";s:3:"289";s:3:"med";s:3:"290";s:3:"mon";s:3:"291";s:3:"n s";s:3:"292";s:3:"no ";s:3:"293";s:3:"obl";s:3:"294";s:3:"ola";s:3:"295";s:3:"ref";s:3:"296";s:3:"rn ";s:3:"297";s:3:"thi";s:3:"298";s:3:"un ";s:3:"299";}}s:18:"trigram-unicodemap";a:13:{s:11:"Basic Latin";a:38:{s:8:"albanian";i:661;s:5:"azeri";i:653;s:7:"bengali";i:1;s:7:"cebuano";i:750;s:8:"croatian";i:733;s:5:"czech";i:652;s:6:"danish";i:734;s:5:"dutch";i:741;s:7:"english";i:723;s:8:"estonian";i:739;s:7:"finnish";i:743;s:6:"french";i:733;s:6:"german";i:750;s:5:"hausa";i:752;s:8:"hawaiian";i:751;s:9:"hungarian";i:693;s:9:"icelandic";i:662;s:10:"indonesian";i:776;s:7:"italian";i:741;s:5:"latin";i:764;s:7:"latvian";i:693;s:10:"lithuanian";i:738;s:9:"mongolian";i:19;s:9:"norwegian";i:742;s:6:"pidgin";i:702;s:6:"polish";i:701;s:10:"portuguese";i:726;s:8:"romanian";i:714;s:6:"slovak";i:677;s:7:"slovene";i:740;s:6:"somali";i:755;s:7:"spanish";i:749;s:7:"swahili";i:770;s:7:"swedish";i:717;s:7:"tagalog";i:767;s:7:"turkish";i:673;s:10:"vietnamese";i:503;s:5:"welsh";i:728;}s:18:"Latin-1 Supplement";a:21:{s:8:"albanian";i:68;s:5:"azeri";i:10;s:5:"czech";i:51;s:6:"danish";i:13;s:8:"estonian";i:19;s:7:"finnish";i:39;s:6:"french";i:21;s:6:"german";i:8;s:9:"hungarian";i:72;s:9:"icelandic";i:80;s:7:"italian";i:3;s:9:"norwegian";i:5;s:6:"polish";i:6;s:10:"portuguese";i:18;s:8:"romanian";i:9;s:6:"slovak";i:37;s:7:"spanish";i:6;s:7:"swedish";i:26;s:7:"turkish";i:25;s:10:"vietnamese";i:56;s:5:"welsh";i:1;}s:14:"[Malformatted]";a:42:{s:8:"albanian";i:68;s:6:"arabic";i:724;s:5:"azeri";i:109;s:7:"bengali";i:1472;s:9:"bulgarian";i:750;s:8:"croatian";i:10;s:5:"czech";i:78;s:6:"danish";i:13;s:8:"estonian";i:19;s:5:"farsi";i:706;s:7:"finnish";i:39;s:6:"french";i:21;s:6:"german";i:8;s:5:"hausa";i:8;s:5:"hindi";i:1386;s:9:"hungarian";i:74;s:9:"icelandic";i:80;s:7:"italian";i:3;s:6:"kazakh";i:767;s:6:"kyrgyz";i:767;s:7:"latvian";i:56;s:10:"lithuanian";i:30;s:10:"macedonian";i:755;s:9:"mongolian";i:743;s:6:"nepali";i:1514;s:9:"norwegian";i:5;s:6:"pashto";i:677;s:6:"polish";i:45;s:10:"portuguese";i:18;s:8:"romanian";i:31;s:7:"russian";i:759;s:7:"serbian";i:757;s:6:"slovak";i:45;s:7:"slovene";i:10;s:7:"spanish";i:6;s:7:"swedish";i:26;s:7:"turkish";i:87;s:9:"ukrainian";i:748;s:4:"urdu";i:682;s:5:"uzbek";i:773;s:10:"vietnamese";i:289;s:5:"welsh";i:1;}s:6:"Arabic";a:4:{s:6:"arabic";i:724;s:5:"farsi";i:706;s:6:"pashto";i:677;s:4:"urdu";i:682;}s:16:"Latin Extended-B";a:3:{s:5:"azeri";i:73;s:5:"hausa";i:8;s:10:"vietnamese";i:19;}s:16:"Latin Extended-A";a:12:{s:5:"azeri";i:25;s:8:"croatian";i:10;s:5:"czech";i:27;s:9:"hungarian";i:2;s:7:"latvian";i:56;s:10:"lithuanian";i:30;s:6:"polish";i:39;s:8:"romanian";i:22;s:6:"slovak";i:8;s:7:"slovene";i:10;s:7:"turkish";i:62;s:10:"vietnamese";i:20;}s:27:"Combining Diacritical Marks";a:1:{s:5:"azeri";i:1;}s:7:"Bengali";a:1:{s:7:"bengali";i:714;}s:8:"Gujarati";a:1:{s:7:"bengali";i:16;}s:8:"Gurmukhi";a:1:{s:7:"bengali";i:6;}s:8:"Cyrillic";a:9:{s:9:"bulgarian";i:750;s:6:"kazakh";i:767;s:6:"kyrgyz";i:767;s:10:"macedonian";i:755;s:9:"mongolian";i:743;s:7:"russian";i:759;s:7:"serbian";i:757;s:9:"ukrainian";i:748;s:5:"uzbek";i:773;}s:10:"Devanagari";a:2:{s:5:"hindi";i:693;s:6:"nepali";i:757;}s:25:"Latin Extended Additional";a:1:{s:10:"vietnamese";i:97;}}} \ No newline at end of file diff --git a/sources/library/langdet/data/unicode_blocks.dat b/sources/library/langdet/data/unicode_blocks.dat new file mode 100644 index 00000000..3b24cd2c --- /dev/null +++ b/sources/library/langdet/data/unicode_blocks.dat @@ -0,0 +1 @@ +a:145:{i:0;a:3:{i:0;s:6:"0x0000";i:1;s:6:"0x007F";i:2;s:11:"Basic Latin";}i:1;a:3:{i:0;s:6:"0x0080";i:1;s:6:"0x00FF";i:2;s:18:"Latin-1 Supplement";}i:2;a:3:{i:0;s:6:"0x0100";i:1;s:6:"0x017F";i:2;s:16:"Latin Extended-A";}i:3;a:3:{i:0;s:6:"0x0180";i:1;s:6:"0x024F";i:2;s:16:"Latin Extended-B";}i:4;a:3:{i:0;s:6:"0x0250";i:1;s:6:"0x02AF";i:2;s:14:"IPA Extensions";}i:5;a:3:{i:0;s:6:"0x02B0";i:1;s:6:"0x02FF";i:2;s:24:"Spacing Modifier Letters";}i:6;a:3:{i:0;s:6:"0x0300";i:1;s:6:"0x036F";i:2;s:27:"Combining Diacritical Marks";}i:7;a:3:{i:0;s:6:"0x0370";i:1;s:6:"0x03FF";i:2;s:16:"Greek and Coptic";}i:8;a:3:{i:0;s:6:"0x0400";i:1;s:6:"0x04FF";i:2;s:8:"Cyrillic";}i:9;a:3:{i:0;s:6:"0x0500";i:1;s:6:"0x052F";i:2;s:19:"Cyrillic Supplement";}i:10;a:3:{i:0;s:6:"0x0530";i:1;s:6:"0x058F";i:2;s:8:"Armenian";}i:11;a:3:{i:0;s:6:"0x0590";i:1;s:6:"0x05FF";i:2;s:6:"Hebrew";}i:12;a:3:{i:0;s:6:"0x0600";i:1;s:6:"0x06FF";i:2;s:6:"Arabic";}i:13;a:3:{i:0;s:6:"0x0700";i:1;s:6:"0x074F";i:2;s:6:"Syriac";}i:14;a:3:{i:0;s:6:"0x0750";i:1;s:6:"0x077F";i:2;s:17:"Arabic Supplement";}i:15;a:3:{i:0;s:6:"0x0780";i:1;s:6:"0x07BF";i:2;s:6:"Thaana";}i:16;a:3:{i:0;s:6:"0x0900";i:1;s:6:"0x097F";i:2;s:10:"Devanagari";}i:17;a:3:{i:0;s:6:"0x0980";i:1;s:6:"0x09FF";i:2;s:7:"Bengali";}i:18;a:3:{i:0;s:6:"0x0A00";i:1;s:6:"0x0A7F";i:2;s:8:"Gurmukhi";}i:19;a:3:{i:0;s:6:"0x0A80";i:1;s:6:"0x0AFF";i:2;s:8:"Gujarati";}i:20;a:3:{i:0;s:6:"0x0B00";i:1;s:6:"0x0B7F";i:2;s:5:"Oriya";}i:21;a:3:{i:0;s:6:"0x0B80";i:1;s:6:"0x0BFF";i:2;s:5:"Tamil";}i:22;a:3:{i:0;s:6:"0x0C00";i:1;s:6:"0x0C7F";i:2;s:6:"Telugu";}i:23;a:3:{i:0;s:6:"0x0C80";i:1;s:6:"0x0CFF";i:2;s:7:"Kannada";}i:24;a:3:{i:0;s:6:"0x0D00";i:1;s:6:"0x0D7F";i:2;s:9:"Malayalam";}i:25;a:3:{i:0;s:6:"0x0D80";i:1;s:6:"0x0DFF";i:2;s:7:"Sinhala";}i:26;a:3:{i:0;s:6:"0x0E00";i:1;s:6:"0x0E7F";i:2;s:4:"Thai";}i:27;a:3:{i:0;s:6:"0x0E80";i:1;s:6:"0x0EFF";i:2;s:3:"Lao";}i:28;a:3:{i:0;s:6:"0x0F00";i:1;s:6:"0x0FFF";i:2;s:7:"Tibetan";}i:29;a:3:{i:0;s:6:"0x1000";i:1;s:6:"0x109F";i:2;s:7:"Myanmar";}i:30;a:3:{i:0;s:6:"0x10A0";i:1;s:6:"0x10FF";i:2;s:8:"Georgian";}i:31;a:3:{i:0;s:6:"0x1100";i:1;s:6:"0x11FF";i:2;s:11:"Hangul Jamo";}i:32;a:3:{i:0;s:6:"0x1200";i:1;s:6:"0x137F";i:2;s:8:"Ethiopic";}i:33;a:3:{i:0;s:6:"0x1380";i:1;s:6:"0x139F";i:2;s:19:"Ethiopic Supplement";}i:34;a:3:{i:0;s:6:"0x13A0";i:1;s:6:"0x13FF";i:2;s:8:"Cherokee";}i:35;a:3:{i:0;s:6:"0x1400";i:1;s:6:"0x167F";i:2;s:37:"Unified Canadian Aboriginal Syllabics";}i:36;a:3:{i:0;s:6:"0x1680";i:1;s:6:"0x169F";i:2;s:5:"Ogham";}i:37;a:3:{i:0;s:6:"0x16A0";i:1;s:6:"0x16FF";i:2;s:5:"Runic";}i:38;a:3:{i:0;s:6:"0x1700";i:1;s:6:"0x171F";i:2;s:7:"Tagalog";}i:39;a:3:{i:0;s:6:"0x1720";i:1;s:6:"0x173F";i:2;s:7:"Hanunoo";}i:40;a:3:{i:0;s:6:"0x1740";i:1;s:6:"0x175F";i:2;s:5:"Buhid";}i:41;a:3:{i:0;s:6:"0x1760";i:1;s:6:"0x177F";i:2;s:8:"Tagbanwa";}i:42;a:3:{i:0;s:6:"0x1780";i:1;s:6:"0x17FF";i:2;s:5:"Khmer";}i:43;a:3:{i:0;s:6:"0x1800";i:1;s:6:"0x18AF";i:2;s:9:"Mongolian";}i:44;a:3:{i:0;s:6:"0x1900";i:1;s:6:"0x194F";i:2;s:5:"Limbu";}i:45;a:3:{i:0;s:6:"0x1950";i:1;s:6:"0x197F";i:2;s:6:"Tai Le";}i:46;a:3:{i:0;s:6:"0x1980";i:1;s:6:"0x19DF";i:2;s:11:"New Tai Lue";}i:47;a:3:{i:0;s:6:"0x19E0";i:1;s:6:"0x19FF";i:2;s:13:"Khmer Symbols";}i:48;a:3:{i:0;s:6:"0x1A00";i:1;s:6:"0x1A1F";i:2;s:8:"Buginese";}i:49;a:3:{i:0;s:6:"0x1D00";i:1;s:6:"0x1D7F";i:2;s:19:"Phonetic Extensions";}i:50;a:3:{i:0;s:6:"0x1D80";i:1;s:6:"0x1DBF";i:2;s:30:"Phonetic Extensions Supplement";}i:51;a:3:{i:0;s:6:"0x1DC0";i:1;s:6:"0x1DFF";i:2;s:38:"Combining Diacritical Marks Supplement";}i:52;a:3:{i:0;s:6:"0x1E00";i:1;s:6:"0x1EFF";i:2;s:25:"Latin Extended Additional";}i:53;a:3:{i:0;s:6:"0x1F00";i:1;s:6:"0x1FFF";i:2;s:14:"Greek Extended";}i:54;a:3:{i:0;s:6:"0x2000";i:1;s:6:"0x206F";i:2;s:19:"General Punctuation";}i:55;a:3:{i:0;s:6:"0x2070";i:1;s:6:"0x209F";i:2;s:27:"Superscripts and Subscripts";}i:56;a:3:{i:0;s:6:"0x20A0";i:1;s:6:"0x20CF";i:2;s:16:"Currency Symbols";}i:57;a:3:{i:0;s:6:"0x20D0";i:1;s:6:"0x20FF";i:2;s:39:"Combining Diacritical Marks for Symbols";}i:58;a:3:{i:0;s:6:"0x2100";i:1;s:6:"0x214F";i:2;s:18:"Letterlike Symbols";}i:59;a:3:{i:0;s:6:"0x2150";i:1;s:6:"0x218F";i:2;s:12:"Number Forms";}i:60;a:3:{i:0;s:6:"0x2190";i:1;s:6:"0x21FF";i:2;s:6:"Arrows";}i:61;a:3:{i:0;s:6:"0x2200";i:1;s:6:"0x22FF";i:2;s:22:"Mathematical Operators";}i:62;a:3:{i:0;s:6:"0x2300";i:1;s:6:"0x23FF";i:2;s:23:"Miscellaneous Technical";}i:63;a:3:{i:0;s:6:"0x2400";i:1;s:6:"0x243F";i:2;s:16:"Control Pictures";}i:64;a:3:{i:0;s:6:"0x2440";i:1;s:6:"0x245F";i:2;s:29:"Optical Character Recognition";}i:65;a:3:{i:0;s:6:"0x2460";i:1;s:6:"0x24FF";i:2;s:22:"Enclosed Alphanumerics";}i:66;a:3:{i:0;s:6:"0x2500";i:1;s:6:"0x257F";i:2;s:11:"Box Drawing";}i:67;a:3:{i:0;s:6:"0x2580";i:1;s:6:"0x259F";i:2;s:14:"Block Elements";}i:68;a:3:{i:0;s:6:"0x25A0";i:1;s:6:"0x25FF";i:2;s:16:"Geometric Shapes";}i:69;a:3:{i:0;s:6:"0x2600";i:1;s:6:"0x26FF";i:2;s:21:"Miscellaneous Symbols";}i:70;a:3:{i:0;s:6:"0x2700";i:1;s:6:"0x27BF";i:2;s:8:"Dingbats";}i:71;a:3:{i:0;s:6:"0x27C0";i:1;s:6:"0x27EF";i:2;s:36:"Miscellaneous Mathematical Symbols-A";}i:72;a:3:{i:0;s:6:"0x27F0";i:1;s:6:"0x27FF";i:2;s:21:"Supplemental Arrows-A";}i:73;a:3:{i:0;s:6:"0x2800";i:1;s:6:"0x28FF";i:2;s:16:"Braille Patterns";}i:74;a:3:{i:0;s:6:"0x2900";i:1;s:6:"0x297F";i:2;s:21:"Supplemental Arrows-B";}i:75;a:3:{i:0;s:6:"0x2980";i:1;s:6:"0x29FF";i:2;s:36:"Miscellaneous Mathematical Symbols-B";}i:76;a:3:{i:0;s:6:"0x2A00";i:1;s:6:"0x2AFF";i:2;s:35:"Supplemental Mathematical Operators";}i:77;a:3:{i:0;s:6:"0x2B00";i:1;s:6:"0x2BFF";i:2;s:32:"Miscellaneous Symbols and Arrows";}i:78;a:3:{i:0;s:6:"0x2C00";i:1;s:6:"0x2C5F";i:2;s:10:"Glagolitic";}i:79;a:3:{i:0;s:6:"0x2C80";i:1;s:6:"0x2CFF";i:2;s:6:"Coptic";}i:80;a:3:{i:0;s:6:"0x2D00";i:1;s:6:"0x2D2F";i:2;s:19:"Georgian Supplement";}i:81;a:3:{i:0;s:6:"0x2D30";i:1;s:6:"0x2D7F";i:2;s:8:"Tifinagh";}i:82;a:3:{i:0;s:6:"0x2D80";i:1;s:6:"0x2DDF";i:2;s:17:"Ethiopic Extended";}i:83;a:3:{i:0;s:6:"0x2E00";i:1;s:6:"0x2E7F";i:2;s:24:"Supplemental Punctuation";}i:84;a:3:{i:0;s:6:"0x2E80";i:1;s:6:"0x2EFF";i:2;s:23:"CJK Radicals Supplement";}i:85;a:3:{i:0;s:6:"0x2F00";i:1;s:6:"0x2FDF";i:2;s:15:"Kangxi Radicals";}i:86;a:3:{i:0;s:6:"0x2FF0";i:1;s:6:"0x2FFF";i:2;s:34:"Ideographic Description Characters";}i:87;a:3:{i:0;s:6:"0x3000";i:1;s:6:"0x303F";i:2;s:27:"CJK Symbols and Punctuation";}i:88;a:3:{i:0;s:6:"0x3040";i:1;s:6:"0x309F";i:2;s:8:"Hiragana";}i:89;a:3:{i:0;s:6:"0x30A0";i:1;s:6:"0x30FF";i:2;s:8:"Katakana";}i:90;a:3:{i:0;s:6:"0x3100";i:1;s:6:"0x312F";i:2;s:8:"Bopomofo";}i:91;a:3:{i:0;s:6:"0x3130";i:1;s:6:"0x318F";i:2;s:25:"Hangul Compatibility Jamo";}i:92;a:3:{i:0;s:6:"0x3190";i:1;s:6:"0x319F";i:2;s:6:"Kanbun";}i:93;a:3:{i:0;s:6:"0x31A0";i:1;s:6:"0x31BF";i:2;s:17:"Bopomofo Extended";}i:94;a:3:{i:0;s:6:"0x31C0";i:1;s:6:"0x31EF";i:2;s:11:"CJK Strokes";}i:95;a:3:{i:0;s:6:"0x31F0";i:1;s:6:"0x31FF";i:2;s:28:"Katakana Phonetic Extensions";}i:96;a:3:{i:0;s:6:"0x3200";i:1;s:6:"0x32FF";i:2;s:31:"Enclosed CJK Letters and Months";}i:97;a:3:{i:0;s:6:"0x3300";i:1;s:6:"0x33FF";i:2;s:17:"CJK Compatibility";}i:98;a:3:{i:0;s:6:"0x3400";i:1;s:6:"0x4DBF";i:2;s:34:"CJK Unified Ideographs Extension A";}i:99;a:3:{i:0;s:6:"0x4DC0";i:1;s:6:"0x4DFF";i:2;s:23:"Yijing Hexagram Symbols";}i:100;a:3:{i:0;s:6:"0x4E00";i:1;s:6:"0x9FFF";i:2;s:22:"CJK Unified Ideographs";}i:101;a:3:{i:0;s:6:"0xA000";i:1;s:6:"0xA48F";i:2;s:12:"Yi Syllables";}i:102;a:3:{i:0;s:6:"0xA490";i:1;s:6:"0xA4CF";i:2;s:11:"Yi Radicals";}i:103;a:3:{i:0;s:6:"0xA700";i:1;s:6:"0xA71F";i:2;s:21:"Modifier Tone Letters";}i:104;a:3:{i:0;s:6:"0xA800";i:1;s:6:"0xA82F";i:2;s:12:"Syloti Nagri";}i:105;a:3:{i:0;s:6:"0xAC00";i:1;s:6:"0xD7AF";i:2;s:16:"Hangul Syllables";}i:106;a:3:{i:0;s:6:"0xD800";i:1;s:6:"0xDB7F";i:2;s:15:"High Surrogates";}i:107;a:3:{i:0;s:6:"0xDB80";i:1;s:6:"0xDBFF";i:2;s:27:"High Private Use Surrogates";}i:108;a:3:{i:0;s:6:"0xDC00";i:1;s:6:"0xDFFF";i:2;s:14:"Low Surrogates";}i:109;a:3:{i:0;s:6:"0xE000";i:1;s:6:"0xF8FF";i:2;s:16:"Private Use Area";}i:110;a:3:{i:0;s:6:"0xF900";i:1;s:6:"0xFAFF";i:2;s:28:"CJK Compatibility Ideographs";}i:111;a:3:{i:0;s:6:"0xFB00";i:1;s:6:"0xFB4F";i:2;s:29:"Alphabetic Presentation Forms";}i:112;a:3:{i:0;s:6:"0xFB50";i:1;s:6:"0xFDFF";i:2;s:27:"Arabic Presentation Forms-A";}i:113;a:3:{i:0;s:6:"0xFE00";i:1;s:6:"0xFE0F";i:2;s:19:"Variation Selectors";}i:114;a:3:{i:0;s:6:"0xFE10";i:1;s:6:"0xFE1F";i:2;s:14:"Vertical Forms";}i:115;a:3:{i:0;s:6:"0xFE20";i:1;s:6:"0xFE2F";i:2;s:20:"Combining Half Marks";}i:116;a:3:{i:0;s:6:"0xFE30";i:1;s:6:"0xFE4F";i:2;s:23:"CJK Compatibility Forms";}i:117;a:3:{i:0;s:6:"0xFE50";i:1;s:6:"0xFE6F";i:2;s:19:"Small Form Variants";}i:118;a:3:{i:0;s:6:"0xFE70";i:1;s:6:"0xFEFF";i:2;s:27:"Arabic Presentation Forms-B";}i:119;a:3:{i:0;s:6:"0xFF00";i:1;s:6:"0xFFEF";i:2;s:29:"Halfwidth and Fullwidth Forms";}i:120;a:3:{i:0;s:6:"0xFFF0";i:1;s:6:"0xFFFF";i:2;s:8:"Specials";}i:121;a:3:{i:0;s:7:"0x10000";i:1;s:7:"0x1007F";i:2;s:18:"Linear B Syllabary";}i:122;a:3:{i:0;s:7:"0x10080";i:1;s:7:"0x100FF";i:2;s:18:"Linear B Ideograms";}i:123;a:3:{i:0;s:7:"0x10100";i:1;s:7:"0x1013F";i:2;s:14:"Aegean Numbers";}i:124;a:3:{i:0;s:7:"0x10140";i:1;s:7:"0x1018F";i:2;s:21:"Ancient Greek Numbers";}i:125;a:3:{i:0;s:7:"0x10300";i:1;s:7:"0x1032F";i:2;s:10:"Old Italic";}i:126;a:3:{i:0;s:7:"0x10330";i:1;s:7:"0x1034F";i:2;s:6:"Gothic";}i:127;a:3:{i:0;s:7:"0x10380";i:1;s:7:"0x1039F";i:2;s:8:"Ugaritic";}i:128;a:3:{i:0;s:7:"0x103A0";i:1;s:7:"0x103DF";i:2;s:11:"Old Persian";}i:129;a:3:{i:0;s:7:"0x10400";i:1;s:7:"0x1044F";i:2;s:7:"Deseret";}i:130;a:3:{i:0;s:7:"0x10450";i:1;s:7:"0x1047F";i:2;s:7:"Shavian";}i:131;a:3:{i:0;s:7:"0x10480";i:1;s:7:"0x104AF";i:2;s:7:"Osmanya";}i:132;a:3:{i:0;s:7:"0x10800";i:1;s:7:"0x1083F";i:2;s:17:"Cypriot Syllabary";}i:133;a:3:{i:0;s:7:"0x10A00";i:1;s:7:"0x10A5F";i:2;s:10:"Kharoshthi";}i:134;a:3:{i:0;s:7:"0x1D000";i:1;s:7:"0x1D0FF";i:2;s:25:"Byzantine Musical Symbols";}i:135;a:3:{i:0;s:7:"0x1D100";i:1;s:7:"0x1D1FF";i:2;s:15:"Musical Symbols";}i:136;a:3:{i:0;s:7:"0x1D200";i:1;s:7:"0x1D24F";i:2;s:30:"Ancient Greek Musical Notation";}i:137;a:3:{i:0;s:7:"0x1D300";i:1;s:7:"0x1D35F";i:2;s:21:"Tai Xuan Jing Symbols";}i:138;a:3:{i:0;s:7:"0x1D400";i:1;s:7:"0x1D7FF";i:2;s:33:"Mathematical Alphanumeric Symbols";}i:139;a:3:{i:0;s:7:"0x20000";i:1;s:7:"0x2A6DF";i:2;s:34:"CJK Unified Ideographs Extension B";}i:140;a:3:{i:0;s:7:"0x2F800";i:1;s:7:"0x2FA1F";i:2;s:39:"CJK Compatibility Ideographs Supplement";}i:141;a:3:{i:0;s:7:"0xE0000";i:1;s:7:"0xE007F";i:2;s:4:"Tags";}i:142;a:3:{i:0;s:7:"0xE0100";i:1;s:7:"0xE01EF";i:2;s:30:"Variation Selectors Supplement";}i:143;a:3:{i:0;s:7:"0xF0000";i:1;s:7:"0xFFFFF";i:2;s:32:"Supplementary Private Use Area-A";}i:144;a:3:{i:0;s:8:"0x100000";i:1;s:8:"0x10FFFF";i:2;s:32:"Supplementary Private Use Area-B";}} \ No newline at end of file diff --git a/sources/library/langdet/docs/example_clui.php b/sources/library/langdet/docs/example_clui.php new file mode 100644 index 00000000..8e7d8577 --- /dev/null +++ b/sources/library/langdet/docs/example_clui.php @@ -0,0 +1,35 @@ +getLanguages(); +sort($langs); +echo join(', ', $langs); + +echo "\ntotal ", count($langs), "\n\n"; + +while ($line = fgets($stdin)) { + $result = $l->detect($line, 4); + print_r($result); + $blocks = $l->detectUnicodeBlocks($line, true); + print_r($blocks); +} + +fclose($stdin); +unset($l); + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +?> diff --git a/sources/library/langdet/docs/example_web.php b/sources/library/langdet/docs/example_web.php new file mode 100644 index 00000000..1e155fef --- /dev/null +++ b/sources/library/langdet/docs/example_web.php @@ -0,0 +1,72 @@ + + + +Text_LanguageDetect demonstration + + +

    Text_LanguageDetect

    +Supported languages:\n"; +$langs = $l->getLanguages(); +sort($langs); +foreach ($langs as $lang) { + echo ucfirst($lang), ', '; + $i++; +} + +echo "
    total $i

    "; + +?> +
    +Enter text to identify language (at least a couple of sentences):
    + +
    + +
    +utf8strlen($q); + if ($len < 20) { // this value picked somewhat arbitrarily + echo "Warning: string not very long ($len chars)
    \n"; + } + + $result = $l->detectConfidence($q); + + if ($result == null) { + echo "Text_LanguageDetect cannot identify this piece of text.

    \n"; + } else { + echo "Text_LanguageDetect thinks this text is written in {$result['language']} ({$result['similarity']}, {$result['confidence']})

    \n"; + } + + $result = $l->detectUnicodeBlocks($q, false); + if (!empty($result)) { + arsort($result); + echo "Unicode blocks present: ", join(', ', array_keys($result)), "\n

    "; + } +} + +unset($l); + +/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */ + +?> + diff --git a/sources/library/langdet/docs/iso.php b/sources/library/langdet/docs/iso.php new file mode 100644 index 00000000..6d7ec1d2 --- /dev/null +++ b/sources/library/langdet/docs/iso.php @@ -0,0 +1,21 @@ +setNameMode(2); +echo $l->detectSimple('Das ist ein kleiner Text') . "\n"; + +//will output the ISO 639-2 three-letter language code +// "deu" +$l->setNameMode(3); +echo $l->detectSimple('Das ist ein kleiner Text') . "\n"; + +?> \ No newline at end of file diff --git a/sources/library/langdet/tests/Text_LanguageDetectTest.php b/sources/library/langdet/tests/Text_LanguageDetectTest.php new file mode 100644 index 00000000..bbf4dd77 --- /dev/null +++ b/sources/library/langdet/tests/Text_LanguageDetectTest.php @@ -0,0 +1,2056 @@ +x = new Text_LanguageDetect(); + } + + function tearDown () + { + unset($this->x); + } + + function test_get_data_locAbsolute() + { + $this->assertEquals( + '/path/to/file', + $this->x->_get_data_loc('/path/to/file') + ); + } + + function test_get_data_locPearPath() + { + $this->x->_data_dir = '/path/to/pear/data'; + $this->assertEquals( + '/path/to/pear/data/Text_LanguageDetect/file', + $this->x->_get_data_loc('file') + ); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Language database does not exist: + */ + function test_readdbNonexistingFile() + { + $this->x->_readdb('thisfiledoesnotexist'); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Language database is not readable: + */ + function test_readdbUnreadableFile() + { + $name = tempnam(sys_get_temp_dir(), 'unittest-Text_LanguageDetect-'); + chmod($name, 0000); + $this->x->_readdb($name); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Language database has no elements. + */ + function test_checkTrigramEmpty() + { + $this->x->_checkTrigram(array()); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Language database is not an array + */ + function test_checkTrigramNoArray() + { + $this->x->_checkTrigram('foo'); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Error loading database. Try turning magic_quotes_runtime off + */ + function test_checkTrigramNoArrayMagicQuotes() + { + if (version_compare(PHP_VERSION, '5.4.0-dev') >= 0) { + $this->markTestSkipped('5.4.0 has no magic quotes anymore'); + } + ini_set('magic_quotes_runtime', 1); + $this->x->_checkTrigram('foo'); + } + + function test_splitter () + { + $str = 'hello'; + + $result = $this->x->_trigram($str); + + $this->assertEquals(array(' he' => 1, 'hel' => 1, 'ell' => 1, 'llo' => 1, 'lo ' => 1), $result); + + $str = 'aa aa whatever'; + + $result = $this->x->_trigram($str); + $this->assertEquals(2, $result[' aa']); + $this->assertEquals(2, $result['aa ']); + $this->assertEquals(1, $result['a a']); + + $str = 'aa aa'; + $result = $this->x->_trigram($str); + $this->assertArrayNotHasKey(' a', $result, ' a'); + $this->assertArrayNotHasKey('a ', $result, 'a '); + } + + function test_splitter2 () + { + $str = 'resumé'; + + $result = $this->x->_trigram($str); + + $this->assertTrue(isset($result['mé ']), 'mé '); + $this->assertTrue(isset($result['umé']), 'umé'); + $this->assertTrue(!isset($result['é ']), 'é'); + + // tests lower-casing accented characters + $str = 'resumÉ'; + + $result = $this->x->_trigram($str); + + $this->assertTrue(isset($result['mé ']),'mé '); + $this->assertTrue(isset($result['umé']),'umé'); + $this->assertTrue(!isset($result['é ']),'é'); + } + + function test_sort () + { + $arr = array('a' => 1, 'b' => 2, 'c' => 2); + $this->x->_bub_sort($arr); + + $final_arr = array('b' => 2, 'c' => 2, 'a' => 1); + + $this->assertEquals($final_arr, $arr); + } + + function test_error () + { + // this test passes the object a series of bad strings to see how it handles them + + $result = $this->x->detectSimple(""); + + $this->assertTrue(!$result); + + $result = $this->x->detectSimple("\n"); + + $this->assertTrue(!$result); + + // should fail on extremely short strings + $result = $this->x->detectSimple("a"); + + $this->assertTrue(!$result); + + $result = $this->x->detectSimple("aa"); + + $this->assertTrue(!$result); + + $result = $this->x->detectSimple('xxxxxxxxxxxxxxxxxxx'); + + $this->assertEquals(null, $result); + } + + function testOmitLanguages() + { + $str = 'This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE, such as 0 or "". Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.'; + + $myobj = new Text_LanguageDetect; + + $myobj->_use_unicode_narrowing = false; + + $count = $myobj->getLanguageCount(); + $returnval = $myobj->omitLanguages('english'); + $newcount = $myobj->getLanguageCount(); + + $this->assertEquals(1, $returnval); + $this->assertEquals(1, $count - $newcount); + + $result = strtolower($myobj->detectSimple($str)); + + $this->assertTrue($result != 'english', $result); + + $myobj = new Text_LanguageDetect; + + $count = $myobj->getLanguageCount(); + $returnval = $myobj->omitLanguages(array('danish', 'italian'), true); + $newcount = $myobj->getLanguageCount(); + + $this->assertEquals($count - $newcount, $returnval); + $this->assertEquals($count - $returnval, $newcount); + + $result = strtolower($myobj->detectSimple($str)); + + $this->assertTrue($result == 'danish' || $result == 'italian', $result); + + $result = $myobj->detect($str); + + $this->assertEquals(2, count($result)); + $this->assertTrue(isset($result['danish'])); + $this->assertTrue(isset($result['italian'])); + + unset($myobj); + } + + function testOmitLanguagesNameMode2() + { + $this->x->setNameMode(2); + $this->assertEquals(1, $this->x->omitLanguages('en')); + } + + function testOmitLanguagesIncludeString() + { + $this->assertGreaterThan(1, $this->x->omitLanguages('english', true)); + $langs = $this->x->getLanguages(); + $this->assertEquals(1, count($langs)); + $this->assertContains('english', $langs); + } + + function testOmitLanguagesClearsClusterCache() + { + $this->x->omitLanguages(array('english', 'german'), true); + $this->assertNull($this->x->_clusters); + $this->x->clusterLanguages(); + $this->assertNotNull($this->x->_clusters); + $this->x->omitLanguages('german'); + $this->assertNull($this->x->_clusters, 'cluster cache be empty now'); + } + + function test_perl_compatibility() + { + // if this test fails, then many of the others will + + $myobj = new Text_LanguageDetect; + $myobj->setPerlCompatible(true); + + $testtext = "hello"; + + $result = $myobj->_trigram($testtext); + + $this->assertTrue(!isset($result[' he'])); + } + + function test_french_db () + { + + $safe_model = array( + "es " => 0, " de" => 1, "de " => 2, " le" => 3, "ent" => 4, + "le " => 5, "nt " => 6, "la " => 7, "s d" => 8, " la" => 9, + "ion" => 10, "on " => 11, "re " => 12, " pa" => 13, "e l" => 14, + "e d" => 15, " l'" => 16, "e p" => 17, " co" => 18, " pr" => 19, + "tio" => 20, "ns " => 21, " en" => 22, "ne " => 23, "que" => 24, + "r l" => 25, "les" => 26, "ur " => 27, "en " => 28, "ati" => 29, + "ue " => 30, " po" => 31, " d'" => 32, "par" => 33, " a " => 34, + "et " => 35, "it " => 36, " qu" => 37, "men" => 38, "ons" => 39, + "te " => 40, " et" => 41, "t d" => 42, " re" => 43, "des" => 44, + " un" => 45, "ie " => 46, "s l" => 47, " su" => 48, "pou" => 49, + " au" => 50, " à " => 51, "con" => 52, "er " => 53, " no" => 54, + "ait" => 55, "e c" => 56, "se " => 57, "té " => 58, "du " => 59, + " du" => 60, " dé" => 61, "ce " => 62, "e e" => 63, "is " => 64, + "n d" => 65, "s a" => 66, " so" => 67, "e r" => 68, "e s" => 69, + "our" => 70, "res" => 71, "ssi" => 72, "eur" => 73, " se" => 74, + "eme" => 75, "est" => 76, "us " => 77, "sur" => 78, "ant" => 79, + "iqu" => 80, "s p" => 81, "une" => 82, "uss" => 83, "l'a" => 84, + "pro" => 85, "ter" => 86, "tre" => 87, "end" => 88, "rs " => 89, + " ce" => 90, "e a" => 91, "t p" => 92, "un " => 93, " ma" => 94, + " ru" => 95, " ré" => 96, "ous" => 97, "ris" => 98, "rus" => 99, + "sse" => 100, "ans" => 101, "ar " => 102, "com" => 103, "e m" => 104, + "ire" => 105, "nce" => 106, "nte" => 107, "t l" => 108, " av" => 109, + " mo" => 110, " te" => 111, "il " => 112, "me " => 113, "ont" => 114, + "ten" => 115, "a p" => 116, "dan" => 117, "pas" => 118, "qui" => 119, + "s e" => 120, "s s" => 121, " in" => 122, "ist" => 123, "lle" => 124, + "nou" => 125, "pré" => 126, "'un" => 127, "air" => 128, "d'a" => 129, + "ir " => 130, "n e" => 131, "rop" => 132, "ts " => 133, " da" => 134, + "a s" => 135, "as " => 136, "au " => 137, "den" => 138, "mai" => 139, + "mis" => 140, "ori" => 141, "out" => 142, "rme" => 143, "sio" => 144, + "tte" => 145, "ux " => 146, "a d" => 147, "ien" => 148, "n a" => 149, + "ntr" => 150, "omm" => 151, "ort" => 152, "ouv" => 153, "s c" => 154, + "son" => 155, "tes" => 156, "ver" => 157, "ère" => 158, " il" => 159, + " m " => 160, " sa" => 161, " ve" => 162, "a r" => 163, "ais" => 164, + "ava" => 165, "di " => 166, "n p" => 167, "sti" => 168, "ven" => 169, + " mi" => 170, "ain" => 171, "enc" => 172, "for" => 173, "ité" => 174, + "lar" => 175, "oir" => 176, "rem" => 177, "ren" => 178, "rro" => 179, + "rés" => 180, "sie" => 181, "t a" => 182, "tur" => 183, " pe" => 184, + " to" => 185, "d'u" => 186, "ell" => 187, "err" => 188, "ers" => 189, + "ide" => 190, "ine" => 191, "iss" => 192, "mes" => 193, "por" => 194, + "ran" => 195, "sit" => 196, "st " => 197, "t r" => 198, "uti" => 199, + "vai" => 200, "é l" => 201, "ési" => 202, " di" => 203, " n'" => 204, + " ét" => 205, "a c" => 206, "ass" => 207, "e t" => 208, "in " => 209, + "nde" => 210, "pre" => 211, "rat" => 212, "s m" => 213, "ste" => 214, + "tai" => 215, "tch" => 216, "ui " => 217, "uro" => 218, "ès " => 219, + " es" => 220, " fo" => 221, " tr" => 222, "'ad" => 223, "app" => 224, + "aux" => 225, "e à" => 226, "ett" => 227, "iti" => 228, "lit" => 229, + "nal" => 230, "opé" => 231, "r d" => 232, "ra " => 233, "rai" => 234, + "ror" => 235, "s r" => 236, "tat" => 237, "uté" => 238, "à l" => 239, + " af" => 240, "anc" => 241, "ara" => 242, "art" => 243, "bre" => 244, + "ché" => 245, "dre" => 246, "e f" => 247, "ens" => 248, "lem" => 249, + "n r" => 250, "n t" => 251, "ndr" => 252, "nne" => 253, "onn" => 254, + "pos" => 255, "s t" => 256, "tiq" => 257, "ure" => 258, " tu" => 259, + "ale" => 260, "and" => 261, "ave" => 262, "cla" => 263, "cou" => 264, + "e n" => 265, "emb" => 266, "ins" => 267, "jou" => 268, "mme" => 269, + "rie" => 270, "rès" => 271, "sem" => 272, "str" => 273, "t i" => 274, + "ues" => 275, "uni" => 276, "uve" => 277, "é d" => 278, "ée " => 279, + " ch" => 280, " do" => 281, " eu" => 282, " fa" => 283, " lo" => 284, + " ne" => 285, " ra" => 286, "arl" => 287, "att" => 288, "ec " => 289, + "ica" => 290, "l a" => 291, "l'o" => 292, "l'é" => 293, "mmi" => 294, + "nta" => 295, "orm" => 296, "ou " => 297, "r u" => 298, "rle" => 299 + ); + + + $my_arr = $this->x->_lang_db['french']; + + foreach ($safe_model as $key => $value) { + $this->assertTrue(isset($my_arr[$key]),$key); + if (isset($my_arr[$key])) { + $this->assertEquals($value, $my_arr[$key], $key); + } + } + } + + function test_english_db () + { + + $realdb = array( + " th" => 0, "the" => 1, "he " => 2, "ed " => 3, " to" => 4, + " in" => 5, "er " => 6, "ing" => 7, "ng " => 8, " an" => 9, + "nd " => 10, " of" => 11, "and" => 12, "to " => 13, "of " => 14, + " co" => 15, "at " => 16, "on " => 17, "in " => 18, " a " => 19, + "d t" => 20, " he" => 21, "e t" => 22, "ion" => 23, "es " => 24, + " re" => 25, "re " => 26, "hat" => 27, " sa" => 28, " st" => 29, + " ha" => 30, "her" => 31, "tha" => 32, "tio" => 33, "or " => 34, + " ''" => 35, "en " => 36, " wh" => 37, "e s" => 38, "ent" => 39, + "n t" => 40, "s a" => 41, "as " => 42, "for" => 43, "is " => 44, + "t t" => 45, " be" => 46, "ld " => 47, "e a" => 48, "rs " => 49, + " wa" => 50, "ut " => 51, "ve " => 52, "ll " => 53, "al " => 54, + " ma" => 55, "e i" => 56, " fo" => 57, "'s " => 58, "an " => 59, + "est" => 60, " hi" => 61, " mo" => 62, " se" => 63, " pr" => 64, + "s t" => 65, "ate" => 66, "st " => 67, "ter" => 68, "ere" => 69, + "ted" => 70, "nt " => 71, "ver" => 72, "d a" => 73, " wi" => 74, + "se " => 75, "e c" => 76, "ect" => 77, "ns " => 78, " on" => 79, + "ly " => 80, "tol" => 81, "ey " => 82, "r t" => 83, " ca" => 84, + "ati" => 85, "ts " => 86, "all" => 87, " no" => 88, "his" => 89, + "s o" => 90, "ers" => 91, "con" => 92, "e o" => 93, "ear" => 94, + "f t" => 95, "e w" => 96, "was" => 97, "ons" => 98, "sta" => 99, + "'' " => 100, "sti" => 101, "n a" => 102, "sto" => 103, "t h" => 104, + " we" => 105, "id " => 106, "th " => 107, " it" => 108, "ce " => 109, + " di" => 110, "ave" => 111, "d h" => 112, "cou" => 113, "pro" => 114, + "ad " => 115, "oll" => 116, "ry " => 117, "d s" => 118, "e m" => 119, + " so" => 120, "ill" => 121, "cti" => 122, "te " => 123, "tor" => 124, + "eve" => 125, "g t" => 126, "it " => 127, " ch" => 128, " de" => 129, + "hav" => 130, "oul" => 131, "ty " => 132, "uld" => 133, "use" => 134, + " al" => 135, "are" => 136, "ch " => 137, "me " => 138, "out" => 139, + "ove" => 140, "wit" => 141, "ys " => 142, "chi" => 143, "t a" => 144, + "ith" => 145, "oth" => 146, " ab" => 147, " te" => 148, " wo" => 149, + "s s" => 150, "res" => 151, "t w" => 152, "tin" => 153, "e b" => 154, + "e h" => 155, "nce" => 156, "t s" => 157, "y t" => 158, "e p" => 159, + "ele" => 160, "hin" => 161, "s i" => 162, "nte" => 163, " li" => 164, + "le " => 165, " do" => 166, "aid" => 167, "hey" => 168, "ne " => 169, + "s w" => 170, " as" => 171, " fr" => 172, " tr" => 173, "end" => 174, + "sai" => 175, " el" => 176, " ne" => 177, " su" => 178, "'t " => 179, + "ay " => 180, "hou" => 181, "ive" => 182, "lec" => 183, "n't" => 184, + " ye" => 185, "but" => 186, "d o" => 187, "o t" => 188, "y o" => 189, + " ho" => 190, " me" => 191, "be " => 192, "cal" => 193, "e e" => 194, + "had" => 195, "ple" => 196, " at" => 197, " bu" => 198, " la" => 199, + "d b" => 200, "s h" => 201, "say" => 202, "t i" => 203, " ar" => 204, + "e f" => 205, "ght" => 206, "hil" => 207, "igh" => 208, "int" => 209, + "not" => 210, "ren" => 211, " is" => 212, " pa" => 213, " sh" => 214, + "ays" => 215, "com" => 216, "n s" => 217, "r a" => 218, "rin" => 219, + "y a" => 220, " un" => 221, "n c" => 222, "om " => 223, "thi" => 224, + " mi" => 225, "by " => 226, "d i" => 227, "e d" => 228, "e n" => 229, + "t o" => 230, " by" => 231, "e r" => 232, "eri" => 233, "old" => 234, + "ome" => 235, "whe" => 236, "yea" => 237, " gr" => 238, "ar " => 239, + "ity" => 240, "mpl" => 241, "oun" => 242, "one" => 243, "ow " => 244, + "r s" => 245, "s f" => 246, "tat" => 247, " ba" => 248, " vo" => 249, + "bou" => 250, "sam" => 251, "tim" => 252, "vot" => 253, "abo" => 254, + "ant" => 255, "ds " => 256, "ial" => 257, "ine" => 258, "man" => 259, + "men" => 260, " or" => 261, " po" => 262, "amp" => 263, "can" => 264, + "der" => 265, "e l" => 266, "les" => 267, "ny " => 268, "ot " => 269, + "rec" => 270, "tes" => 271, "tho" => 272, "ica" => 273, "ild" => 274, + "ir " => 275, "nde" => 276, "ose" => 277, "ous" => 278, "pre" => 279, + "ste" => 280, "era" => 281, "per" => 282, "r o" => 283, "red" => 284, + "rie" => 285, " bo" => 286, " le" => 287, "ali" => 288, "ars" => 289, + "ore" => 290, "ric" => 291, "s m" => 292, "str" => 293, " fa" => 294, + "ess" => 295, "ie " => 296, "ist" => 297, "lat" => 298, "uri" => 299, + ); + + $mod = $this->x->_lang_db['english']; + + foreach ($realdb as $key => $value) { + $this->assertTrue(isset($mod[$key]), $key); + if (isset($mod[$key])) { + $this->assertEquals($value, $mod[$key], $key); + } + } + + foreach ($mod as $key => $value) { + $this->assertTrue(isset($realdb[$key])); + if (isset($realdb[$key])) { + $this->assertEquals($value, $realdb[$key], $key); + } + } + } + + function test_confidence () + { + $str = 'The next thing to notice is the Content-length header. The Content-length header notifies the server of the size of the data that you intend to send. This prevents unexpected end-of-data errors from the server when dealing with binary data, because the server will read the specified number of bytes from the data stream regardless of any spurious end-of-data characters.'; + + $result = $this->x->detectConfidence($str); + + $this->assertEquals(3, count($result)); + $this->assertTrue(isset($result['language']), 'language'); + $this->assertTrue(isset($result['similarity']), 'similarity'); + $this->assertTrue(isset($result['confidence']), 'confidence'); + $this->assertEquals('english', $result['language']); + $this->assertTrue($result['similarity'] <= 300 && $result['similarity'] >= 0, $result['similarity']); + $this->assertTrue($result['confidence'] <= 1 && $result['confidence'] >= 0, $result['confidence']); + + // todo: tests for Danish and Norwegian should have lower confidence + } + + function test_long_example () + { + // an example that is more than 300 trigrams long + $str = 'The Italian Renaissance began the opening phase of the Renaissance, a period of great cultural change and achievement from the 14th to the 16th century. The word renaissance means "rebirth," and the era is best known for the renewed interest in the culture of classical antiquity. The Italian Renaissance began in northern Italy, centering in Florence. It then spread south, having an especially significant impact on Rome, which was largely rebuilt by the Renaissance popes. The Italian Renaissance is best known for its cultural achievements. This includes works of literature by such figures as Petrarch, Castiglione, and Machiavelli; artists such as Michaelangelo and Leonardo da Vinci, and great works of architecture such as The Duomo in Florence and St. Peter\'s Basilica in Rome. At the same time, present-day historians also see the era as one of economic regression and of little progress in science. Furthermore, some historians argue that the lot of the peasants and urban poor, the majority of the population, worsened during this period.'; + + $this->x->setPerlCompatible(); + $tri = $this->x->_trigram($str); + + $exp_tri = array( + ' th', + 'the', + 'he ', + ' an', + ' re', + ' of', + 'ce ', + 'nce', + 'of ', + 'ren', + ' in', + 'and', + 'nd ', + 'an ', + 'san', + ' it', + 'ais', + 'anc', + 'ena', + 'in ', + 'iss', + 'nai', + 'ssa', + 'tur', + ' pe', + 'as ', + 'ch ', + 'ent', + 'ian', + 'me ', + 'n r', + 'res', + ' as', + ' be', + ' wo', + 'at ', + 'chi', + 'e i', + 'e o', + 'e p', + 'gre', + 'his', + 'ing', + 'is ', + 'ita', + 'n f', + 'ng ', + 're ', + 's a', + 'st ', + 'tal', + 'ter', + 'th ', + 'ts ', + 'ure', + 'wor', + ' ar', + ' cu', + ' po', + ' su', + 'ach', + 'al ', + 'ali', + 'ans', + 'ant', + 'cul', + 'e b', + 'e r', + 'e t', + 'enc', + 'era', + 'eri', + 'es ', + 'est', + 'f t', + 'ica', + 'ion', + 'ist', + 'lia', + 'ltu', + 'ly ', + 'ns ', + 'nt ', + 'ome', + 'on ', + 'or ', + 'ore', + 'ori', + 'rea', + 'rom', + 'rth', + 's b', + 's o', + 'suc', + 't t', + 'uch', + 'ult', + ' ac', + ' by', + ' ce', + ' da', + ' du', + ' er', + ' fl', + ' fo', + ' gr', + ' hi', + ' is', + ' kn', + ' li', + ' ma', + ' on', + ' pr', + ' ro', + ' so', + 'a i', + 'ang', + 'arc', + 'arg', + 'beg', + 'bes', + 'by ', + 'cen', + 'cha', + 'd o', + 'd s', + 'e a', + 'e e', + 'e m', + 'e s', + 'eat', + 'ed ', + 'ega', + 'eme', + 'ene', + 'ess', + 'eve', + 'f l', + 'flo', + 'for', + 'gan', + 'gel', + 'h a', + 'her', + 'hie', + 'ich', + 'iev', + 'inc', + 'iod', + 'ite', + 'ity', + 'kno', + 'ks ', + 'l a', + 'lit', + 'lor', + 'men', + 'mic', + 'n i', + 'n s', + 'n t', + 'ne ', + 'nge', + 'now', + 'nte', + 'nts', + 'od ', + 'one', + 'ope', + 'ork', + 'own', + 'per', + 'pet', + 'pop', + 'pre', + 'ra ', + 'ral', + 'rch', + 'reb', + 'ria', + 'rin', + 'rio', + 'rks', + 's i', + 's p', + 'sen', + 'ssi', + 'sto', + 't i', + 't k', + 't o', + 'thi', + 'tor', + 'ty ', + 'ura', + 'vem', + 'vin', + 'wn ', + 'y s', + ' a ', + ' al', + ' at', + ' ba', + ' ca', + ' ch', + ' cl', + ' ec', + ' es', + ' fi', + ' fr', + ' fu', + ' ha', + ' im', + ' la', + ' le', + ' lo', + ' me', + ' mi', + ' no', + ' op', + ' ph', + ' sa', + ' sc', + ' se', + ' si', + ' sp', + ' st', + ' ti', + ' to', + ' ur', + ' vi', + ' wa', + ' wh', + '\'s ', + 'a a', + 'a p', + 'a v', + 'act', + 'ad ', + 'ael', + 'ajo', + 'all', + 'als', + 'aly', + 'ame', + 'ard', + 'art', + 'asa', + 'ase', + 'asi', + 'ass', + 'ast', + 'ati', + 'atu', + 'ave', + 'avi', + 'ay ', + 'ban', + 'bas', + 'bir', + 'bui', + 'c r', + 'ca ', + 'cal', + 'can', + 'cas', + 'ci ', + 'cia', + 'cie', + 'cla', + 'clu', + 'con', + 'ct ', + 'ctu', + 'd a', + 'd d', + 'd g', + 'd i', + 'd l', + 'd m', + 'd r', + 'd t', + 'd u', + 'da ', + 'day', + 'des', + 'do ', + 'duo', + 'dur', + 'e c', + 'e d', + 'e h', + 'e l', + 'e w', + 'ead', + 'ean', + 'eas', + 'ebi', + 'ebu', + 'eci', + 'eco', + 'ect', + 'ee ', + 'egr', + 'ela', + 'ell', + 'elo', + 'ely', + 'en ', + 'eni', + 'eon', + 'er\'', + 'ere', + 'erm', + 'ern', + 'ese', + 'esp', + 'ete', + 'etr', + 'ewe', + 'f a', + 'f c', + 'f e', + 'f g', + 'fic', + 'fig', + 'fro', + 'fur', + 'g a', + 'g i', + 'g p', + 'g t', + 'ge ', + 'gli', + 'gni', + 'gue', + 'gur', + 'h c', + 'h f', + 'h t', + 'h w', + 'hae', + 'han', + 'has', + 'hat', + 'hav', + 'hen', + 'hia', + 'hic', + 'hit', + 'ial', + 'iav', + 'ic ', + 'ien', + 'ifi', + 'igl', + 'ign', + 'igu', + 'ili', + 'ilt', + 'ime', + 'imp', + 'int', + 'iqu', + 'irt', + 'it ', + 'its', + 'itt', + 'jor', + 'l c', + 'lan', + 'lar', + 'las', + 'lat', + 'le ', + 'leo', + 'li ', + 'lic', + 'lio', + 'lli', + 'lly', + 'lo ', + 'lot', + 'lso', + 'lt ', + 'lud', + 'm t', + 'mac', + 'maj', + 'mea', + 'mo ', + 'mor', + 'mpa', + 'n a', + 'n e', + 'n n', + 'n p', + 'nar', + 'nci', + 'ncl', + 'ned', + 'new', + 'nif', + 'nin', + 'nom', + 'nor', + 'nti', + 'ntu', + 'o a', + 'o d', + 'o i', + 'o s', + 'o t', + 'ogr', + 'om ', + 'omi', + 'omo', + 'ona', + 'ono', + 'oor', + 'opu', + 'ord', + 'ors', + 'ort', + 'ot ', + 'out', + 'pac', + 'pea', + 'pec', + 'pen', + 'pes', + 'pha', + 'poo', + 'pro', + 'pul', + 'qui', + 'r i', + 'r t', + 'r\'s', + 'rar', + 'rat', + 'rba', + 'rd ', + 'rdo', + 'reg', + 'rge', + 'rgu', + 'rit', + 'rmo', + 'rn ', + 'rog', + 'rse', + 'rti', + 'ry ', + 's c', + 's l', + 's m', + 's s', + 's t', + 's w', + 'sam', + 'sci', + 'se ', + 'see', + 'sic', + 'sig', + 'sil', + 'sio', + 'so ', + 'som', + 'sou', + 'spe', + 'spr', + 'ss ', + 'sti', + 'sts', + 't b', + 't c', + 't d', + 't f', + 't w', + 'tec', + 'tha', + 'tig', + 'tim', + 'tio', + 'tiq', + 'tis', + 'tle', + 'to ', + 'tra', + 'ttl', + 'ude', + 'ue ', + 'uil', + 'uit', + 'ula', + 'uom', + 'urb', + 'uri', + 'urt', + 'ury', + 'uth', + 'vel', + 'was', + 'wed', + 'whi', + 'y h', + 'y o', + 'y r', + 'y t' + ); + + $differences = array_diff(array_keys($tri), $exp_tri); + $this->assertEquals(0, count($differences)); + $this->assertEquals(0, count(array_diff($exp_tri, array_keys($tri)))); + $this->assertEquals(count($exp_tri), count($tri)); + //print_r(array_diff($exp_tri, array_keys($tri))); + //print_r(array_diff(array_keys($tri), $exp_tri)); + + // tests the bubble sort mechanism + $this->x->_bub_sort($tri); + $this->assertEquals($exp_tri, array_keys($tri)); + + $true_differences = array( + "cas" => array('change' => 300, 'baserank' => 265, 'refrank' => null), "s i" => array('change' => 21, 'baserank' => 183, 'refrank' => 162), + "e b" => array('change' => 88, 'baserank' => 66, 'refrank' => 154), "ent" => array('change' => 12, 'baserank' => 27, 'refrank' => 39), + "ome" => array('change' => 152, 'baserank' => 83, 'refrank' => 235), "ral" => array('change' => 300, 'baserank' => 176, 'refrank' => null), + "ita" => array('change' => 300, 'baserank' => 44, 'refrank' => null), "bas" => array('change' => 300, 'baserank' => 258, 'refrank' => null), + " ar" => array('change' => 148, 'baserank' => 56, 'refrank' => 204), " in" => array('change' => 5, 'baserank' => 10, 'refrank' => 5), + " ti" => array('change' => 300, 'baserank' => 227, 'refrank' => null), "ty " => array('change' => 61, 'baserank' => 193, 'refrank' => 132), + "tur" => array('change' => 300, 'baserank' => 23, 'refrank' => null), "iss" => array('change' => 300, 'baserank' => 20, 'refrank' => null), + "ria" => array('change' => 300, 'baserank' => 179, 'refrank' => null), " me" => array('change' => 25, 'baserank' => 216, 'refrank' => 191), + "t k" => array('change' => 300, 'baserank' => 189, 'refrank' => null), " es" => array('change' => 300, 'baserank' => 207, 'refrank' => null), + "ren" => array('change' => 202, 'baserank' => 9, 'refrank' => 211), "in " => array('change' => 1, 'baserank' => 19, 'refrank' => 18), + "ly " => array('change' => 0, 'baserank' => 80, 'refrank' => 80), "st " => array('change' => 18, 'baserank' => 49, 'refrank' => 67), + "ne " => array('change' => 8, 'baserank' => 161, 'refrank' => 169), "all" => array('change' => 154, 'baserank' => 241, 'refrank' => 87), + "vin" => array('change' => 300, 'baserank' => 196, 'refrank' => null), " op" => array('change' => 300, 'baserank' => 219, 'refrank' => null), + "chi" => array('change' => 107, 'baserank' => 36, 'refrank' => 143), "e w" => array('change' => 197, 'baserank' => 293, 'refrank' => 96), + " ro" => array('change' => 300, 'baserank' => 113, 'refrank' => null), "act" => array('change' => 300, 'baserank' => 237, 'refrank' => null), + "d r" => array('change' => 300, 'baserank' => 280, 'refrank' => null), "nt " => array('change' => 11, 'baserank' => 82, 'refrank' => 71), + "can" => array('change' => 0, 'baserank' => 264, 'refrank' => 264), "rea" => array('change' => 300, 'baserank' => 88, 'refrank' => null), + "ssa" => array('change' => 300, 'baserank' => 22, 'refrank' => null), " fo" => array('change' => 47, 'baserank' => 104, 'refrank' => 57), + "eas" => array('change' => 300, 'baserank' => 296, 'refrank' => null), "mic" => array('change' => 300, 'baserank' => 157, 'refrank' => null), + "cul" => array('change' => 300, 'baserank' => 65, 'refrank' => null), " an" => array('change' => 6, 'baserank' => 3, 'refrank' => 9), + "n t" => array('change' => 120, 'baserank' => 160, 'refrank' => 40), "arg" => array('change' => 300, 'baserank' => 118, 'refrank' => null), + " it" => array('change' => 93, 'baserank' => 15, 'refrank' => 108), "ebi" => array('change' => 300, 'baserank' => 297, 'refrank' => null), + " re" => array('change' => 21, 'baserank' => 4, 'refrank' => 25), "res" => array('change' => 120, 'baserank' => 31, 'refrank' => 151), + " be" => array('change' => 13, 'baserank' => 33, 'refrank' => 46), "rom" => array('change' => 300, 'baserank' => 89, 'refrank' => null), + "'s " => array('change' => 175, 'baserank' => 233, 'refrank' => 58), "arc" => array('change' => 300, 'baserank' => 117, 'refrank' => null), + " su" => array('change' => 119, 'baserank' => 59, 'refrank' => 178), "s p" => array('change' => 300, 'baserank' => 184, 'refrank' => null), + "ich" => array('change' => 300, 'baserank' => 145, 'refrank' => null), "d d" => array('change' => 300, 'baserank' => 275, 'refrank' => null), + "cal" => array('change' => 70, 'baserank' => 263, 'refrank' => 193), "ci " => array('change' => 300, 'baserank' => 266, 'refrank' => null), + "ssi" => array('change' => 300, 'baserank' => 186, 'refrank' => null), "bes" => array('change' => 300, 'baserank' => 120, 'refrank' => null), + "des" => array('change' => 300, 'baserank' => 285, 'refrank' => null), "e s" => array('change' => 91, 'baserank' => 129, 'refrank' => 38), + "ch " => array('change' => 111, 'baserank' => 26, 'refrank' => 137), "san" => array('change' => 300, 'baserank' => 14, 'refrank' => null), + "asi" => array('change' => 300, 'baserank' => 249, 'refrank' => null), "ajo" => array('change' => 300, 'baserank' => 240, 'refrank' => null), + "ase" => array('change' => 300, 'baserank' => 248, 'refrank' => null), " wa" => array('change' => 181, 'baserank' => 231, 'refrank' => 50), + "vem" => array('change' => 300, 'baserank' => 195, 'refrank' => null), "ed " => array('change' => 128, 'baserank' => 131, 'refrank' => 3), + "ant" => array('change' => 191, 'baserank' => 64, 'refrank' => 255), "a p" => array('change' => 300, 'baserank' => 235, 'refrank' => null), + "lor" => array('change' => 300, 'baserank' => 155, 'refrank' => null), "kno" => array('change' => 300, 'baserank' => 151, 'refrank' => null), + "ais" => array('change' => 300, 'baserank' => 16, 'refrank' => null), " pe" => array('change' => 300, 'baserank' => 24, 'refrank' => null), + "or " => array('change' => 51, 'baserank' => 85, 'refrank' => 34), "e i" => array('change' => 19, 'baserank' => 37, 'refrank' => 56), + " sp" => array('change' => 300, 'baserank' => 225, 'refrank' => null), "ad " => array('change' => 123, 'baserank' => 238, 'refrank' => 115), + " kn" => array('change' => 300, 'baserank' => 108, 'refrank' => null), "ega" => array('change' => 300, 'baserank' => 132, 'refrank' => null), + " ba" => array('change' => 46, 'baserank' => 202, 'refrank' => 248), "d t" => array('change' => 261, 'baserank' => 281, 'refrank' => 20), + "ork" => array('change' => 300, 'baserank' => 169, 'refrank' => null), "lia" => array('change' => 300, 'baserank' => 78, 'refrank' => null), + "ard" => array('change' => 300, 'baserank' => 245, 'refrank' => null), "iev" => array('change' => 300, 'baserank' => 146, 'refrank' => null), + "of " => array('change' => 6, 'baserank' => 8, 'refrank' => 14), " cu" => array('change' => 300, 'baserank' => 57, 'refrank' => null), + "day" => array('change' => 300, 'baserank' => 284, 'refrank' => null), "cen" => array('change' => 300, 'baserank' => 122, 'refrank' => null), + "re " => array('change' => 21, 'baserank' => 47, 'refrank' => 26), "ist" => array('change' => 220, 'baserank' => 77, 'refrank' => 297), + " fl" => array('change' => 300, 'baserank' => 103, 'refrank' => null), "anc" => array('change' => 300, 'baserank' => 17, 'refrank' => null), + "at " => array('change' => 19, 'baserank' => 35, 'refrank' => 16), "rch" => array('change' => 300, 'baserank' => 177, 'refrank' => null), + "ang" => array('change' => 300, 'baserank' => 116, 'refrank' => null), " mi" => array('change' => 8, 'baserank' => 217, 'refrank' => 225), + "y s" => array('change' => 300, 'baserank' => 198, 'refrank' => null), "ca " => array('change' => 300, 'baserank' => 262, 'refrank' => null), + " ma" => array('change' => 55, 'baserank' => 110, 'refrank' => 55), " lo" => array('change' => 300, 'baserank' => 215, 'refrank' => null), + "rin" => array('change' => 39, 'baserank' => 180, 'refrank' => 219), " im" => array('change' => 300, 'baserank' => 212, 'refrank' => null), + " er" => array('change' => 300, 'baserank' => 102, 'refrank' => null), "ce " => array('change' => 103, 'baserank' => 6, 'refrank' => 109), + "bui" => array('change' => 300, 'baserank' => 260, 'refrank' => null), "lit" => array('change' => 300, 'baserank' => 154, 'refrank' => null), + "iod" => array('change' => 300, 'baserank' => 148, 'refrank' => null), "ame" => array('change' => 300, 'baserank' => 244, 'refrank' => null), + "ter" => array('change' => 17, 'baserank' => 51, 'refrank' => 68), "e a" => array('change' => 78, 'baserank' => 126, 'refrank' => 48), + "f l" => array('change' => 300, 'baserank' => 137, 'refrank' => null), "eri" => array('change' => 162, 'baserank' => 71, 'refrank' => 233), + "ra " => array('change' => 300, 'baserank' => 175, 'refrank' => null), "ng " => array('change' => 38, 'baserank' => 46, 'refrank' => 8), + "d i" => array('change' => 50, 'baserank' => 277, 'refrank' => 227), "asa" => array('change' => 300, 'baserank' => 247, 'refrank' => null), + "wn " => array('change' => 300, 'baserank' => 197, 'refrank' => null), " at" => array('change' => 4, 'baserank' => 201, 'refrank' => 197), + "now" => array('change' => 300, 'baserank' => 163, 'refrank' => null), " by" => array('change' => 133, 'baserank' => 98, 'refrank' => 231), + "n s" => array('change' => 58, 'baserank' => 159, 'refrank' => 217), " li" => array('change' => 55, 'baserank' => 109, 'refrank' => 164), + "l a" => array('change' => 300, 'baserank' => 153, 'refrank' => null), "da " => array('change' => 300, 'baserank' => 283, 'refrank' => null), + "ean" => array('change' => 300, 'baserank' => 295, 'refrank' => null), "tal" => array('change' => 300, 'baserank' => 50, 'refrank' => null), + "d a" => array('change' => 201, 'baserank' => 274, 'refrank' => 73), "ct " => array('change' => 300, 'baserank' => 272, 'refrank' => null), + "ali" => array('change' => 226, 'baserank' => 62, 'refrank' => 288), "ian" => array('change' => 300, 'baserank' => 28, 'refrank' => null), + " sa" => array('change' => 193, 'baserank' => 221, 'refrank' => 28), "do " => array('change' => 300, 'baserank' => 286, 'refrank' => null), + "t o" => array('change' => 40, 'baserank' => 190, 'refrank' => 230), "ure" => array('change' => 300, 'baserank' => 54, 'refrank' => null), + "e c" => array('change' => 213, 'baserank' => 289, 'refrank' => 76), "ing" => array('change' => 35, 'baserank' => 42, 'refrank' => 7), + "d o" => array('change' => 63, 'baserank' => 124, 'refrank' => 187), " ha" => array('change' => 181, 'baserank' => 211, 'refrank' => 30), + "ts " => array('change' => 33, 'baserank' => 53, 'refrank' => 86), "rth" => array('change' => 300, 'baserank' => 90, 'refrank' => null), + "cla" => array('change' => 300, 'baserank' => 269, 'refrank' => null), " ac" => array('change' => 300, 'baserank' => 97, 'refrank' => null), + "th " => array('change' => 55, 'baserank' => 52, 'refrank' => 107), "rio" => array('change' => 300, 'baserank' => 181, 'refrank' => null), + "al " => array('change' => 7, 'baserank' => 61, 'refrank' => 54), "sto" => array('change' => 84, 'baserank' => 187, 'refrank' => 103), + "e o" => array('change' => 55, 'baserank' => 38, 'refrank' => 93), "bir" => array('change' => 300, 'baserank' => 259, 'refrank' => null), + " pr" => array('change' => 48, 'baserank' => 112, 'refrank' => 64), " le" => array('change' => 73, 'baserank' => 214, 'refrank' => 287), + "nai" => array('change' => 300, 'baserank' => 21, 'refrank' => null), "t i" => array('change' => 15, 'baserank' => 188, 'refrank' => 203), + " po" => array('change' => 204, 'baserank' => 58, 'refrank' => 262), "f t" => array('change' => 21, 'baserank' => 74, 'refrank' => 95), + "ban" => array('change' => 300, 'baserank' => 257, 'refrank' => null), "an " => array('change' => 46, 'baserank' => 13, 'refrank' => 59), + "wor" => array('change' => 300, 'baserank' => 55, 'refrank' => null), "pet" => array('change' => 300, 'baserank' => 172, 'refrank' => null), + "ael" => array('change' => 300, 'baserank' => 239, 'refrank' => null), "ura" => array('change' => 300, 'baserank' => 194, 'refrank' => null), + "eve" => array('change' => 11, 'baserank' => 136, 'refrank' => 125), "ion" => array('change' => 53, 'baserank' => 76, 'refrank' => 23), + "nge" => array('change' => 300, 'baserank' => 162, 'refrank' => null), "cha" => array('change' => 300, 'baserank' => 123, 'refrank' => null), + "ity" => array('change' => 90, 'baserank' => 150, 'refrank' => 240), " se" => array('change' => 160, 'baserank' => 223, 'refrank' => 63), + " on" => array('change' => 32, 'baserank' => 111, 'refrank' => 79), "s b" => array('change' => 300, 'baserank' => 91, 'refrank' => null), + "ans" => array('change' => 300, 'baserank' => 63, 'refrank' => null), "own" => array('change' => 300, 'baserank' => 170, 'refrank' => null), + " si" => array('change' => 300, 'baserank' => 224, 'refrank' => null), "e r" => array('change' => 165, 'baserank' => 67, 'refrank' => 232), + "est" => array('change' => 13, 'baserank' => 73, 'refrank' => 60), "hie" => array('change' => 300, 'baserank' => 144, 'refrank' => null), + "aly" => array('change' => 300, 'baserank' => 243, 'refrank' => null), "and" => array('change' => 1, 'baserank' => 11, 'refrank' => 12), + "beg" => array('change' => 300, 'baserank' => 119, 'refrank' => null), "dur" => array('change' => 300, 'baserank' => 288, 'refrank' => null), + "reb" => array('change' => 300, 'baserank' => 178, 'refrank' => null), "e e" => array('change' => 67, 'baserank' => 127, 'refrank' => 194), + "men" => array('change' => 104, 'baserank' => 156, 'refrank' => 260), " la" => array('change' => 14, 'baserank' => 213, 'refrank' => 199), + "con" => array('change' => 179, 'baserank' => 271, 'refrank' => 92), " fu" => array('change' => 300, 'baserank' => 210, 'refrank' => null), + "e l" => array('change' => 26, 'baserank' => 292, 'refrank' => 266), "s a" => array('change' => 7, 'baserank' => 48, 'refrank' => 41), + "art" => array('change' => 300, 'baserank' => 246, 'refrank' => null), "ltu" => array('change' => 300, 'baserank' => 79, 'refrank' => null), + "a i" => array('change' => 300, 'baserank' => 115, 'refrank' => null), "ctu" => array('change' => 300, 'baserank' => 273, 'refrank' => null), + "tor" => array('change' => 68, 'baserank' => 192, 'refrank' => 124), "ach" => array('change' => 300, 'baserank' => 60, 'refrank' => null), + "d g" => array('change' => 300, 'baserank' => 276, 'refrank' => null), "od " => array('change' => 300, 'baserank' => 166, 'refrank' => null), + "nte" => array('change' => 1, 'baserank' => 164, 'refrank' => 163), "ena" => array('change' => 300, 'baserank' => 18, 'refrank' => null), + "d l" => array('change' => 300, 'baserank' => 278, 'refrank' => null), "ene" => array('change' => 300, 'baserank' => 134, 'refrank' => null), + "e h" => array('change' => 136, 'baserank' => 291, 'refrank' => 155), "era" => array('change' => 211, 'baserank' => 70, 'refrank' => 281), + "on " => array('change' => 67, 'baserank' => 84, 'refrank' => 17), " ce" => array('change' => 300, 'baserank' => 99, 'refrank' => null), + "ay " => array('change' => 76, 'baserank' => 256, 'refrank' => 180), " da" => array('change' => 300, 'baserank' => 100, 'refrank' => null), + "ori" => array('change' => 300, 'baserank' => 87, 'refrank' => null), "atu" => array('change' => 300, 'baserank' => 253, 'refrank' => null), + "ave" => array('change' => 143, 'baserank' => 254, 'refrank' => 111), "rks" => array('change' => 300, 'baserank' => 182, 'refrank' => null), + "e d" => array('change' => 62, 'baserank' => 290, 'refrank' => 228), "ns " => array('change' => 3, 'baserank' => 81, 'refrank' => 78), + " ca" => array('change' => 119, 'baserank' => 203, 'refrank' => 84), "d s" => array('change' => 7, 'baserank' => 125, 'refrank' => 118), + "uch" => array('change' => 300, 'baserank' => 95, 'refrank' => null), "a v" => array('change' => 300, 'baserank' => 236, 'refrank' => null), + "nce" => array('change' => 149, 'baserank' => 7, 'refrank' => 156), "his" => array('change' => 48, 'baserank' => 41, 'refrank' => 89), + "flo" => array('change' => 300, 'baserank' => 138, 'refrank' => null), "ead" => array('change' => 300, 'baserank' => 294, 'refrank' => null), + " vi" => array('change' => 300, 'baserank' => 230, 'refrank' => null), "me " => array('change' => 109, 'baserank' => 29, 'refrank' => 138), + "suc" => array('change' => 300, 'baserank' => 93, 'refrank' => null), "e p" => array('change' => 120, 'baserank' => 39, 'refrank' => 159), + "eci" => array('change' => 300, 'baserank' => 299, 'refrank' => null), "eme" => array('change' => 300, 'baserank' => 133, 'refrank' => null), + "sen" => array('change' => 300, 'baserank' => 185, 'refrank' => null), "ks " => array('change' => 300, 'baserank' => 152, 'refrank' => null), + " to" => array('change' => 224, 'baserank' => 228, 'refrank' => 4), " gr" => array('change' => 133, 'baserank' => 105, 'refrank' => 238), + " ch" => array('change' => 76, 'baserank' => 204, 'refrank' => 128), "ati" => array('change' => 167, 'baserank' => 252, 'refrank' => 85), + " th" => array('change' => 0, 'baserank' => 0, 'refrank' => 0), " ec" => array('change' => 300, 'baserank' => 206, 'refrank' => null), + " wo" => array('change' => 115, 'baserank' => 34, 'refrank' => 149), "ope" => array('change' => 300, 'baserank' => 168, 'refrank' => null), + " a " => array('change' => 180, 'baserank' => 199, 'refrank' => 19), "one" => array('change' => 76, 'baserank' => 167, 'refrank' => 243), + "n f" => array('change' => 300, 'baserank' => 45, 'refrank' => null), "eat" => array('change' => 300, 'baserank' => 130, 'refrank' => null), + "ica" => array('change' => 198, 'baserank' => 75, 'refrank' => 273), "inc" => array('change' => 300, 'baserank' => 147, 'refrank' => null), + "enc" => array('change' => 300, 'baserank' => 69, 'refrank' => null), "ore" => array('change' => 204, 'baserank' => 86, 'refrank' => 290), + "is " => array('change' => 1, 'baserank' => 43, 'refrank' => 44), " as" => array('change' => 139, 'baserank' => 32, 'refrank' => 171), + "nts" => array('change' => 300, 'baserank' => 165, 'refrank' => null), "d m" => array('change' => 300, 'baserank' => 279, 'refrank' => null), + "her" => array('change' => 112, 'baserank' => 143, 'refrank' => 31), " al" => array('change' => 65, 'baserank' => 200, 'refrank' => 135), + " is" => array('change' => 105, 'baserank' => 107, 'refrank' => 212), "e t" => array('change' => 46, 'baserank' => 68, 'refrank' => 22), + "c r" => array('change' => 300, 'baserank' => 261, 'refrank' => null), " hi" => array('change' => 45, 'baserank' => 106, 'refrank' => 61), + "cia" => array('change' => 300, 'baserank' => 267, 'refrank' => null), " fr" => array('change' => 37, 'baserank' => 209, 'refrank' => 172), + "ult" => array('change' => 300, 'baserank' => 96, 'refrank' => null), "e m" => array('change' => 9, 'baserank' => 128, 'refrank' => 119), + "ass" => array('change' => 300, 'baserank' => 250, 'refrank' => null), "s o" => array('change' => 2, 'baserank' => 92, 'refrank' => 90), + "pop" => array('change' => 300, 'baserank' => 173, 'refrank' => null), "nd " => array('change' => 2, 'baserank' => 12, 'refrank' => 10), + "the" => array('change' => 0, 'baserank' => 1, 'refrank' => 1), " st" => array('change' => 197, 'baserank' => 226, 'refrank' => 29), + " no" => array('change' => 130, 'baserank' => 218, 'refrank' => 88), "ast" => array('change' => 300, 'baserank' => 251, 'refrank' => null), + " fi" => array('change' => 300, 'baserank' => 208, 'refrank' => null), "ess" => array('change' => 160, 'baserank' => 135, 'refrank' => 295), + "gre" => array('change' => 300, 'baserank' => 40, 'refrank' => null), "h a" => array('change' => 300, 'baserank' => 142, 'refrank' => null), + "duo" => array('change' => 300, 'baserank' => 287, 'refrank' => null), " so" => array('change' => 6, 'baserank' => 114, 'refrank' => 120), + "es " => array('change' => 48, 'baserank' => 72, 'refrank' => 24), "for" => array('change' => 96, 'baserank' => 139, 'refrank' => 43), + "gan" => array('change' => 300, 'baserank' => 140, 'refrank' => null), "per" => array('change' => 111, 'baserank' => 171, 'refrank' => 282), + "thi" => array('change' => 33, 'baserank' => 191, 'refrank' => 224), " of" => array('change' => 6, 'baserank' => 5, 'refrank' => 11), + " cl" => array('change' => 300, 'baserank' => 205, 'refrank' => null), " sc" => array('change' => 300, 'baserank' => 222, 'refrank' => null), + "t t" => array('change' => 49, 'baserank' => 94, 'refrank' => 45), "als" => array('change' => 300, 'baserank' => 242, 'refrank' => null), + "avi" => array('change' => 300, 'baserank' => 255, 'refrank' => null), "cie" => array('change' => 300, 'baserank' => 268, 'refrank' => null), + " du" => array('change' => 300, 'baserank' => 101, 'refrank' => null), "pre" => array('change' => 105, 'baserank' => 174, 'refrank' => 279), + "as " => array('change' => 17, 'baserank' => 25, 'refrank' => 42), "a a" => array('change' => 300, 'baserank' => 234, 'refrank' => null), + "gel" => array('change' => 300, 'baserank' => 141, 'refrank' => null), "ite" => array('change' => 300, 'baserank' => 149, 'refrank' => null), + "n r" => array('change' => 300, 'baserank' => 30, 'refrank' => null), "by " => array('change' => 105, 'baserank' => 121, 'refrank' => 226), + "d u" => array('change' => 300, 'baserank' => 282, 'refrank' => null), "clu" => array('change' => 300, 'baserank' => 270, 'refrank' => null), + " ur" => array('change' => 300, 'baserank' => 229, 'refrank' => null), "ebu" => array('change' => 300, 'baserank' => 298, 'refrank' => null), + "n i" => array('change' => 300, 'baserank' => 158, 'refrank' => null), "he " => array('change' => 0, 'baserank' => 2, 'refrank' => 2), + " wh" => array('change' => 195, 'baserank' => 232, 'refrank' => 37), " ph" => array('change' => 300, 'baserank' => 220, 'refrank' => null), + ); + + $ranked = $this->x->_arr_rank($this->x->_trigram($str)); + $results = $this->x->detect($str); + + $count = count($ranked); + $sum = 0; + + //foreach ($this->x->_lang_db['english'] as $key => $value) { + foreach ($ranked as $key => $value) { + if (isset($ranked[$key]) && isset($this->x->_lang_db['english'][$key])) { + $difference = abs($this->x->_lang_db['english'][$key] - $ranked[$key]); + } else { + $difference = 300; + } + + $this->assertTrue(isset($true_differences[$key]), "'$key'"); + if (isset($true_differences[$key])) { + $this->assertEquals($true_differences[$key]['change'], $difference, "'$key'"); + } + $sum += $difference; + } + + $this->assertEquals(300, $count); + $this->assertEquals(59490, $sum); + + $this->assertEquals('english', key($results)); + $this->assertEquals(198, floor(current($results))); + next($results); + $this->assertEquals('italian', key($results)); + $this->assertEquals(228, floor(current($results))); + } + + function test_french () + { + $this->x->setPerlCompatible(); + $str = "Verifions que le détecteur de langues marche"; + + $trigrams = $this->x->_trigram($str); + $this->assertEquals(42, count($trigrams)); + // verified in Language::Guess + + $ranked = $this->x->_arr_rank($trigrams); + $this->assertEquals(0, $ranked['e l']); + + $correct_ranks = array( + ' de' => 1, + "éte" => 41, + "dét" => 12, + 'fio' => 18, + 'de ' => 11, + 'ons' => 28, + 'ect' => 14, + 'le ' => 24, + 'arc' => 8, + 'lan' => 23, + 'es ' => 16, + 'mar' => 25, + " dé" => 2, + 'ifi' => 21, + 'gue' => 19, + 'ur ' => 39, + 'rch' => 31, + 'ang' => 7, + 'que' => 29, + 'ngu' => 26, + 'e d' => 13, + 'rif' => 32, + ' ma' => 5, + 'tec' => 35, + 'ns ' => 27, + ' la' => 3, + ' le' => 4, + 'r d' => 30, + 'e l' => 0, + 'che' => 9, + 's m' => 33, + 'ue ' => 37, + 'ver' => 40, + 'teu' => 36, + 'eri' => 15, + 'cte' => 10, + 'ues' => 38, + 's q' => 34, + 'eur' => 17, + ' qu' => 6, + 'he ' => 20, + 'ion' => 22 + ); + + + $this->assertEquals(count($correct_ranks), count($ranked), "different number of trigrams found"); + + $distances = array( + ' de' => array('change' => 0, 'baserank' => 1, 'refrank' => 1), + 'éte' => array('change' => 300, 'baserank' => 41, 'refrank' => null), + 'dét' => array('change' => 300, 'baserank' => 12, 'refrank' => null), + 'fio' => array('change' => 300, 'baserank' => 18, 'refrank' => null), + 'de ' => array('change' => 9, 'baserank' => 11, 'refrank' => 2), + 'ons' => array('change' => 11, 'baserank' => 28, 'refrank' => 39), + 'ect' => array('change' => 300, 'baserank' => 14, 'refrank' => null), + 'le ' => array('change' => 19, 'baserank' => 24, 'refrank' => 5), + 'arc' => array('change' => 300, 'baserank' => 8, 'refrank' => null), + 'lan' => array('change' => 300, 'baserank' => 23, 'refrank' => null), + 'es ' => array('change' => 16, 'baserank' => 16, 'refrank' => 0), + 'mar' => array('change' => 300, 'baserank' => 25, 'refrank' => null), + ' dé' => array('change' => 59, 'baserank' => 2, 'refrank' => 61), + 'ifi' => array('change' => 300, 'baserank' => 21, 'refrank' => null), + 'gue' => array('change' => 300, 'baserank' => 19, 'refrank' => null), + 'ur ' => array('change' => 12, 'baserank' => 39, 'refrank' => 27), + 'rch' => array('change' => 300, 'baserank' => 31, 'refrank' => null), + 'ang' => array('change' => 300, 'baserank' => 7, 'refrank' => null), + 'que' => array('change' => 5, 'baserank' => 29, 'refrank' => 24), + 'ngu' => array('change' => 300, 'baserank' => 26, 'refrank' => null), + 'e d' => array('change' => 2, 'baserank' => 13, 'refrank' => 15), + 'rif' => array('change' => 300, 'baserank' => 32, 'refrank' => null), + ' ma' => array('change' => 89, 'baserank' => 5, 'refrank' => 94), + 'tec' => array('change' => 300, 'baserank' => 35, 'refrank' => null), + 'ns ' => array('change' => 6, 'baserank' => 27, 'refrank' => 21), + ' la' => array('change' => 6, 'baserank' => 3, 'refrank' => 9), + ' le' => array('change' => 1, 'baserank' => 4, 'refrank' => 3), + 'r d' => array('change' => 202, 'baserank' => 30, 'refrank' => 232), + 'e l' => array('change' => 14, 'baserank' => 0, 'refrank' => 14), + 'che' => array('change' => 300, 'baserank' => 9, 'refrank' => null), + 's m' => array('change' => 180, 'baserank' => 33, 'refrank' => 213), + 'ue ' => array('change' => 7, 'baserank' => 37, 'refrank' => 30), + 'ver' => array('change' => 117, 'baserank' => 40, 'refrank' => 157), + 'teu' => array('change' => 300, 'baserank' => 36, 'refrank' => null), + 'eri' => array('change' => 300, 'baserank' => 15, 'refrank' => null), + 'cte' => array('change' => 300, 'baserank' => 10, 'refrank' => null), + 'ues' => array('change' => 237, 'baserank' => 38, 'refrank' => 275), + 's q' => array('change' => 300, 'baserank' => 34, 'refrank' => null), + 'eur' => array('change' => 56, 'baserank' => 17, 'refrank' => 73), + ' qu' => array('change' => 31, 'baserank' => 6, 'refrank' => 37), + 'he ' => array('change' => 300, 'baserank' => 20, 'refrank' => null), + 'ion' => array('change' => 12, 'baserank' => 22, 'refrank' => 10), + ); + + + + $french_ranks = $this->x->_lang_db['french']; + + $sumchange = 0; + foreach ($ranked as $key => $value) { + if (isset($french_ranks[$key])) { + $difference = abs($french_ranks[$key] - $ranked[$key]); + } else { + $difference = 300; + } + $this->assertTrue(isset($distances[$key]), $key); + if (isset($distances[$key])) { + $this->assertEquals($distances[$key]['baserank'], $ranked[$key], "baserank for $key"); + if ($distances[$key]['refrank'] === null) { + $this->assertArrayNotHasKey($key, $french_ranks); + } else { + $this->assertEquals($distances[$key]['refrank'], $french_ranks[$key], "refrank for $key"); + } + $this->assertEquals($distances[$key]['change'], $difference, "difference for $key"); + } + + $sumchange += $difference; + } + + $actual_result = $this->x->_distance($french_ranks, $ranked); + $this->assertEquals($sumchange, $actual_result); + $this->assertEquals(7091, $actual_result); + $this->assertEquals(168, floor($sumchange/count($trigrams))); + + $final_result = $this->x->detect($str); + $this->assertEquals(168, floor($final_result['french'])); + $this->assertEquals(211, $final_result['spanish']); + } + + function test_russian () + { + $str = 'авай проверить узнает ли наш угадатель руÑÑки Ñзык'; + + $this->x->setPerlCompatible(); + $trigrams = $this->x->_trigram($str); + $ranked = $this->x->_arr_rank($trigrams); + + $correct_ranks = array( + ' ру' => array('change' => 300, 'baserank' => 3, 'refrank' => null), + 'ай ' => array('change' => 300, 'baserank' => 10, 'refrank' => null), + 'ада' => array('change' => 300, 'baserank' => 8, 'refrank' => null), + ' пр' => array('change' => 1, 'baserank' => 2, 'refrank' => 1), + ' Ñз' => array('change' => 300, 'baserank' => 6, 'refrank' => null), + 'ить' => array('change' => 300, 'baserank' => 24, 'refrank' => null), + ' на' => array('change' => 1, 'baserank' => 1, 'refrank' => 0), + 'зна' => array('change' => 153, 'baserank' => 20, 'refrank' => 173), + 'вай' => array('change' => 300, 'baserank' => 13, 'refrank' => null), + 'ш у' => array('change' => 300, 'baserank' => 44, 'refrank' => null), + 'ль ' => array('change' => 300, 'baserank' => 28, 'refrank' => null), + ' ли' => array('change' => 300, 'baserank' => 0, 'refrank' => null), + 'ÑÑк' => array('change' => 300, 'baserank' => 37, 'refrank' => null), + 'Ñ‚ÑŒ ' => array('change' => 31, 'baserank' => 40, 'refrank' => 9), + 'ава' => array('change' => 300, 'baserank' => 7, 'refrank' => null), + 'про' => array('change' => 18, 'baserank' => 32, 'refrank' => 14), + 'гад' => array('change' => 300, 'baserank' => 15, 'refrank' => null), + 'уÑÑ' => array('change' => 300, 'baserank' => 43, 'refrank' => null), + 'ык ' => array('change' => 300, 'baserank' => 45, 'refrank' => null), + 'ель' => array('change' => 64, 'baserank' => 17, 'refrank' => 81), + 'Ñзы' => array('change' => 300, 'baserank' => 47, 'refrank' => null), + ' уг' => array('change' => 300, 'baserank' => 4, 'refrank' => null), + 'ате' => array('change' => 152, 'baserank' => 11, 'refrank' => 163), + 'и н' => array('change' => 63, 'baserank' => 22, 'refrank' => 85), + 'и Ñ' => array('change' => 300, 'baserank' => 23, 'refrank' => null), + 'ает' => array('change' => 152, 'baserank' => 9, 'refrank' => 161), + 'узн' => array('change' => 300, 'baserank' => 42, 'refrank' => null), + 'ери' => array('change' => 300, 'baserank' => 18, 'refrank' => null), + 'ли ' => array('change' => 23, 'baserank' => 27, 'refrank' => 4), + 'Ñ‚ л' => array('change' => 300, 'baserank' => 38, 'refrank' => null), + ' уз' => array('change' => 300, 'baserank' => 5, 'refrank' => null), + 'дат' => array('change' => 203, 'baserank' => 16, 'refrank' => 219), + 'зык' => array('change' => 300, 'baserank' => 21, 'refrank' => null), + 'ров' => array('change' => 59, 'baserank' => 34, 'refrank' => 93), + 'рит' => array('change' => 300, 'baserank' => 33, 'refrank' => null), + 'ÑŒ Ñ€' => array('change' => 300, 'baserank' => 46, 'refrank' => null), + 'ет ' => array('change' => 19, 'baserank' => 19, 'refrank' => 38), + 'ки ' => array('change' => 116, 'baserank' => 26, 'refrank' => 142), + 'руÑ' => array('change' => 300, 'baserank' => 35, 'refrank' => null), + 'тел' => array('change' => 16, 'baserank' => 39, 'refrank' => 23), + 'нае' => array('change' => 300, 'baserank' => 29, 'refrank' => null), + 'й п' => array('change' => 300, 'baserank' => 25, 'refrank' => null), + 'наш' => array('change' => 300, 'baserank' => 30, 'refrank' => null), + 'уга' => array('change' => 300, 'baserank' => 41, 'refrank' => null), + 'ове' => array('change' => 214, 'baserank' => 31, 'refrank' => 245), + 'Ñки' => array('change' => 112, 'baserank' => 36, 'refrank' => 148), + 'вер' => array('change' => 31, 'baserank' => 14, 'refrank' => 45), + 'аш ' => array('change' => 300, 'baserank' => 12, 'refrank' => null), + ); + + $this->assertEquals(48, count($ranked)); + + + $russian = $this->x->_lang_db['russian']; + + $sumchange = 0; + foreach ($ranked as $key => $value) { + if (isset($russian[$key])) { + $difference = abs($russian[$key] - $ranked[$key]); + } else { + $difference = 300; + } + $this->assertTrue(isset($correct_ranks[$key], $key)); + if (isset($correct_ranks[$key])) { + $this->assertEquals($correct_ranks[$key]['baserank'], $ranked[$key], "baserank for $key"); + if ($correct_ranks[$key]['refrank'] === null) { + $this->assertArrayNotHasKey($key, $russian); + } else { + $this->assertEquals($correct_ranks[$key]['refrank'], $russian[$key], "refrank for $key"); + } + $this->assertEquals($correct_ranks[$key]['change'], $difference, "difference for $key"); + } + + $sumchange += $difference; + } + + $actual_result = $this->x->_distance($russian, $ranked); + $this->assertEquals($sumchange, $actual_result); + $this->assertEquals(10428, $actual_result); + $this->assertEquals(217, floor($sumchange/count($trigrams))); + + $final_result = $this->x->detect($str); + $this->assertEquals(217,floor($final_result['russian'])); + } + + function test_ranker () + { + $str = 'is it s i'; + + $result = $this->x->_arr_rank($this->x->_trigram($str)); + + $this->assertEquals(0, $result['s i']); + } + + + function test_count () + { + $langs = $this->x->getLanguages(); + + $count = $this->x->getLanguageCount(); + + $this->assertEquals(count($langs), $count); + + foreach ($langs as $lang) { + $this->assertTrue($this->x->languageExists($lang), $lang); + } + } + + function testLanguageExistsNameMode2() + { + $this->x->setNameMode(2); + $this->assertTrue($this->x->languageExists('en')); + $this->assertFalse($this->x->languageExists('english')); + } + + function testLanguageExistsArrayNameMode2() + { + $this->x->setNameMode(2); + $this->assertTrue($this->x->languageExists(array('en', 'de'))); + $this->assertFalse($this->x->languageExists(array('en', 'doesnotexist'))); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Unsupported parameter type passed to languageExists() + */ + function testLanguageExistsUnsupportedType() + { + $this->x->languageExists(1.23); + } + + function testGetLanguages() + { + $langs = $this->x->getLanguages(); + $this->assertContains('english', $langs); + $this->assertContains('swedish', $langs); + } + + function testGetLanguagesNameMode2() + { + $this->x->setNameMode(2); + $langs = $this->x->getLanguages(); + $this->assertContains('en', $langs); + $this->assertContains('sv', $langs); + } + + function testDetect() + { + $scores = $this->x->detect('Das ist ein kleiner Text für euch alle'); + $this->assertInternalType('array', $scores); + $this->assertGreaterThan(5, count($scores)); + + list($key, $value) = each($scores); + $this->assertEquals('german', $key, 'text is german'); + } + + function testDetectNameMode2() + { + $this->x->setNameMode(2); + $scores = $this->x->detect('Das ist ein kleiner Text für euch alle'); + list($key, $value) = each($scores); + $this->assertEquals('de', $key, 'text is german'); + } + + function testDetectNameMode2Limit() + { + $this->x->setNameMode(2); + $scores = $this->x->detect('Das ist ein kleiner Text für euch alle', 1); + list($key, $value) = each($scores); + $this->assertEquals('de', $key, 'text is german'); + } + + function testDetectSimple() + { + $lang = $this->x->detectSimple('Das ist ein kleiner Text für euch alle'); + $this->assertInternalType('string', $lang); + $this->assertEquals('german', $lang, 'text is german'); + } + + function testDetectSimpleNameMode2() + { + $this->x->setNameMode(2); + $lang = $this->x->detectSimple('Das ist ein kleiner Text für euch alle'); + $this->assertInternalType('string', $lang); + $this->assertEquals('de', $lang, 'text is german'); + } + + function testDetectSimpleNoLanguages() + { + $this->x->omitLanguages('english', true); + $this->x->omitLanguages('english', false); + $this->assertNull( + $this->x->detectSimple('Das ist ein kleiner Text für euch alle') + ); + } + + function testLanguageSimilarity() + { + $this->x->setPerlCompatible(true); + $eng_dan = $this->x->languageSimilarity('english', 'danish'); + $nor_dan = $this->x->languageSimilarity('norwegian', 'danish'); + $swe_dan = $this->x->languageSimilarity('swedish', 'danish'); + + // remember, lower means more similar + $this->assertTrue($eng_dan > $nor_dan); // english is less similar to danish than norwegian is + $this->assertTrue($eng_dan > $swe_dan); // english is less similar to danish than swedish is + $this->assertTrue($nor_dan < $swe_dan); // norwegian is more similar to danish than swedish + + // test the range of the results + $this->assertTrue($eng_dan <= 300, $eng_dan); + $this->assertTrue($eng_dan >= 0, $eng_dan); + + // test it in perl compatible mode + $this->x->setPerlCompatible(false); + + $eng_dan = $this->x->languageSimilarity('english', 'danish'); + $nor_dan = $this->x->languageSimilarity('norwegian', 'danish'); + $swe_dan = $this->x->languageSimilarity('swedish', 'danish'); + + // now higher is more similar + $this->assertTrue($eng_dan < $nor_dan); + $this->assertTrue($eng_dan < $swe_dan); + $this->assertTrue($nor_dan > $swe_dan); + + $this->assertTrue($eng_dan <= 1, $eng_dan); + $this->assertTrue($eng_dan >= 0, $eng_dan); + + $this->x->setPerlCompatible(true); + + $eng_all = $this->x->languageSimilarity('english'); + $this->assertEquals($this->x->getLanguageCount() - 1, count($eng_all)); + $this->assertTrue(!isset($eng_all['english'])); + + $this->assertTrue($eng_all['italian'] < $eng_all['turkish']); + $this->assertTrue($eng_all['french'] < $eng_all['kyrgyz']); + + $all = $this->x->languageSimilarity(); + $this->assertTrue(!isset($all['english']['english'])); + $this->assertTrue($all['french']['spanish'] < $all['french']['mongolian']); + $this->assertTrue($all['spanish']['latin'] < $all['hindi']['finnish']); + $this->assertTrue($all['russian']['uzbek'] < $all['russian']['english']); + } + + + function testLanguageSimilarityNameMode2() + { + $this->x->setNameMode(2); + $this->x->setPerlCompatible(true); + $eng_dan = $this->x->languageSimilarity('en', 'dk'); + $nor_dan = $this->x->languageSimilarity('no', 'dk'); + + // remember, lower means more similar + $this->assertTrue($eng_dan > $nor_dan); // english is less similar to danish than norwegian is + } + + function testLanguageSimilarityUnknownLanguage() + { + $this->assertNull($this->x->languageSimilarity('doesnotexist')); + } + + function testLanguageSimilarityUnknownLanguage2() + { + $this->assertNull($this->x->languageSimilarity('english', 'doesnotexist')); + } + + function test_compatibility () + { + $str = "I am the very model of a modern major general."; + + + $this->x->setPerlCompatible(false); + $result = $this->x->detectConfidence($str); + + $this->assertTrue(!is_null($result)); + $this->assertTrue(is_array($result)); + extract($result); + $this->assertEquals('english', $language); + $this->assertTrue($similarity <= 1 && $similarity >= 0, $similarity); + $this->assertTrue($confidence <= 1 && $confidence >= 0, $confidence); + + $this->x->setPerlCompatible(true); + $result = $this->x->detectConfidence($str); + extract($result, EXTR_OVERWRITE); + + $this->assertEquals('english', $language); + + // technically the lowest possible score is 0 but it's extremely unlikely to hit that + $this->assertTrue($similarity <= 300 && $similarity >= 1, $similarity); + $this->assertTrue($confidence <= 1 && $confidence >= 0, $confidence); + + } + + function testDetectConfidenceNoText() + { + $this->assertNull($this->x->detectConfidence('')); + } + + function test_omit_error () + { + $str = 'On January 29, 1737, Thomas Paine was born in Thetford, England. His father, a corseter, had grand visions for his son, but by the age of 12, Thomas had failed out of school. The young Paine began apprenticing for his father, but again, he failed.'; + + $myobj = new Text_LanguageDetect; + + $result = $myobj->detectSimple($str); + $this->assertEquals('english', $result); + + // omit all languages and you should get an error + $myobj->omitLanguages($myobj->getLanguages()); + + $result = $myobj->detectSimple($str); + + $this->assertNull($result, gettype($result)); + } + + function test_cyrillic () + { + // tests whether the cyrillic lower-casing works + + $uppercased = 'РБ Ð’ Г Д Е Ж З И Й К Л Ðœ РО П' + . 'Р С Т У Ф Ð¥ Ц Ч Ш Щ Ъ Ы Ь Э Ю Я'; + + $lowercased = 'а б в г д е ж з и й к л м н о п' + . 'Ñ€ Ñ Ñ‚ у Ñ„ Ñ… ц ч ш щ ÑŠ Ñ‹ ÑŒ Ñ ÑŽ Ñ'; + + $this->assertEquals(strlen($uppercased), strlen($lowercased)); + + $i = 0; + $j = 0; + $new_u = ''; + while ($i < strlen($uppercased)) { + $u = Text_LanguageDetect::_next_char($uppercased, $i, true); + $l = Text_LanguageDetect::_next_char($lowercased, $j, true); + $this->assertEquals($u, $l); + + $new_u .= $u; + } + + $this->assertEquals($i, $j); + $this->assertEquals($i, strlen($lowercased)); + if (function_exists('mb_strtolower')) { + $this->assertEquals($new_u, mb_strtolower($uppercased, 'UTF-8')); + } + } + + function test_block_detection() + { + $exp_output = << 37 + [CJK Unified Ideographs] => 2 + [Hiragana] => 1 + [Latin-1 Supplement] => 4 +) +EOF; + $teststr = 'lsdkfj ゠葉 å¶ slskdfj s Ã…j;sdklf ÿjs;kdjÃ¥f î'; + $result = $this->x->detectUnicodeBlocks($teststr, false); + + ksort($result); + ob_start(); + print_r($result); + $str_result = ob_get_contents(); + ob_end_clean(); + $this->assertEquals(trim($exp_output), trim($str_result)); + + // test whether skipping the spaces reduces the basic latin count + $result2 = $this->x->detectUnicodeBlocks($teststr, true); + $this->assertTrue($result2['Basic Latin'] < $result['Basic Latin']); + + $result3 = $this->x->unicodeBlockName('и'); + $this->assertEquals('Cyrillic', $result3); + + $this->assertEquals('Basic Latin', $this->x->unicodeBlockName('A')); + + // see what happens when you try an unassigned range + $utf8 = $this->code2utf(0x0800); + + $this->assertEquals(false, $this->x->unicodeBlockName($utf8)); + + // try unicode vals in several different ranges + $unicode['Supplementary Private Use Area-A'] = 0xF0001; + $unicode['Supplementary Private Use Area-B'] = 0x100001; + $unicode['CJK Unified Ideographs Extension B'] = 0x20001; + $unicode['Ugaritic'] = 0x10381; + $unicode['Gothic'] = 0x10331; + $unicode['Low Surrogates'] = 0xDC01; + $unicode['CJK Unified Ideographs'] = 0x4E00; + $unicode['Glagolitic'] = 0x2C00; + $unicode['Latin Extended Additional'] = 0x1EFF; + $unicode['Devanagari'] = 0x0900; + $unicode['Hebrew'] = 0x0590; + $unicode['Latin Extended-B'] = 0x024F; + $unicode['Latin-1 Supplement'] = 0x00FF; + $unicode['Basic Latin'] = 0x007F; + + foreach ($unicode as $range => $codepoint) { + $result = $this->x->unicodeBlockName($this->code2utf($codepoint)); + $this->assertEquals($range, $result, $codepoint); + } + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Pass a single char only to this method + */ + function testUnicodeBlockNameParamString() + { + $this->x->unicodeBlockName('foo bar baz'); + } + + /** + * @expectedException Text_LanguageDetect_Exception + * @expectedExceptionMessage Input must be of type string or int + */ + function testUnicodeBlockNameUnsupportedParamType() + { + $this->x->unicodeBlockName(1.23); + } + + + // utility function + // found in http://www.php.net/manual/en/function.utf8-encode.php#49336 + function code2utf($num) + { + if ($num < 128) { + return chr($num); + + } elseif ($num < 2048) { + return chr(($num >> 6) + 192) . chr(($num & 63) + 128); + + } elseif ($num < 65536) { + return chr(($num >> 12) + 224) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); + + } elseif ($num < 2097152) { + return chr(($num >> 18) + 240) . chr((($num >> 12) & 63) + 128) . chr((($num >> 6) & 63) + 128) . chr(($num & 63) + 128); + } else { + return ''; + } + } + + function test_utf8len() + { + $str = 'Iñtërnâtiônàlizætiøn'; + $this->assertEquals(20, $this->x->utf8strlen($str), utf8_decode($str)); + + $str = '時期日'; + $this->assertEquals(3, $this->x->utf8strlen($str), utf8_decode($str)); + } + + function test_unicode() + { + // test whether it can get the right unicode values for utf8 chars + + $chars['ת'] = 0x5EA; + + $chars['ç'] = 0x00E7; + + $chars['a'] = 0x0061; + + $chars['Φ'] = 0x03A6; + + $chars['И'] = 0x0418; + + $chars['Ú°'] = 0x6B0; + + $chars['Ụ'] = 0x1EE4; + + $chars['놔'] = 0xB194; + + $chars['é®'] = 0x906E; + + $chars['怀'] = 0x6000; + + $chars['ฤ'] = 0x0E24; + + $chars['Я'] = 0x042F; + + $chars['ü'] = 0x00FC; + + $chars['Ä'] = 0x0110; + + $chars['×'] = 0x05D0; + + + foreach ($chars as $utf8 => $unicode) { + $this->assertEquals($unicode, $this->x->_utf8char2unicode($utf8), $utf8); + } + } + + function test_unicode_off() + { + + // see what happens when you turn the unicode setting off + + $myobj = new Text_LanguageDetect; + + $str = 'This is a delightful sample of English text'; + + $myobj->useUnicodeBlocks(true); + $result1 = $myobj->detectConfidence($str); + + $myobj->useUnicodeBlocks(false); + $result2 = $myobj->detectConfidence($str); + + $this->assertEquals($result1, $result2); + + // note this test doesn't tell if unicode narrowing was actually used or not + } + + + function test_detection() + { + + // WARNING: the below lines may make your terminal go ape! be warned + + + + + + + + + + + + + + + + + + + + + + + + // test strings from the test module used by perl's Language::Guess + + $testarr = array( + "english" => "This is a test of the language checker", + "french" => "Verifions que le détecteur de langues marche", + "polish" => "Sprawdźmy, czy odgadywacz jÄ™zyków pracuje", + "russian" => "Давай проверим узнает ли нашь угадыватель руÑÑкий Ñзык", + "spanish" => "La respuesta de los acreedores a la oferta argentina para salir del default no ha sido muy positiv", + "romanian" => "în acest sens aparÅ£inînd Adunării Generale a organizaÅ£iei, în ciuda faptului că mai multe dintre solicitările organizaÅ£iei privind organizarea scrutinului nu au fost soluÅ£ionate", + "albanian" => "kaluan ditën e fundit të fushatës në shtetet kryesore për të siguruar sa më shumë votues.", + "danish" => "PÃ¥ denne side bringer vi billeder fra de mange forskellige forberedelser til arrangementet, efterhÃ¥nden som vi fÃ¥r dem ", + "swedish" => "Vi säger att Frälsningen är en gÃ¥va till alla, fritt och för intet. Men som vi nämnt sÃ¥ finns det tvÃ¥ villkor som mÃ¥ste", + "norwegian" => "Nominasjonskomiteen i Akershus KrF har skviset ut Einar Holstad fra stortingslisten. Ytre Enebakk-mannen har plass p Stortinget s lenge Valgerd Svarstad Haugland sitter i", + "finnish" => "on julkishallinnon verkkopalveluiden yhteinen osoite. Kansalaisten arkielämää helpottavaa tietoa on koottu eri aihealueisiin", + "estonian" => "Ennetamaks reisil ebameeldivaid vahejuhtumeid vii end kurssi reisidokumentide ja viisade reeglitega ning muu praktilise informatsiooniga", + "hungarian" => "Hiába jön létre az önkéntes magyar haderÅ‘, hiába nem lesz többé bevonulás, változatlanul fennmarad a hadkötelezettség intézménye", + "uzbek" => "Ð¼Ð¸Ð»Ð¸Ñ†Ð¸Ñ Ð²Ð° уч Ñолиқ идораÑи ходимлари Ñраланган. Шаҳарда хавфÑизлик чоралари кучайтирилган.", + + + "czech" => "Francouzský ministr financí zmírnil výhrady vůÄi nízkým firemním daním v nových Älenských státech EU", + "dutch" => "Die kritiek was volgens hem bitter hard nodig, omdat Nederland binnen een paar jaar in een soort Belfast zou dreigen te nderen", + + "croatian" => "biće priliÄno izjednaÄena, sugeriÅ¡u najnovije ankete. Oba kandidata tvrde da su sposobni da dobiju rat protiv terorizma", + + "romanian" => "în acest sens aparÅ£inînd Adunării Generale a organizaÅ£iei, în ciuda faptului că mai multe dintre solicitările organizaÅ£iei ivind organizarea scrutinului nu au fost soluÅ£ionate", + + "turkish" => "yakın tarihin en çekiÅŸmeli baÅŸkanlık seçiminde oy verme iÅŸlemi sürerken, katılımda rekor bekleniyor.", + + "kyrgyz" => "көрбөгөндөй Ñлдик толкундоо болуп, Кокон шаарынын көчөлөрүндө бир нече миң киши нааразылык билдирди.", + + + "albanian" => "kaluan ditën e fundit të fushatës në shtetet kryesore për të siguruar sa më shumë votues.", + + + "azeri" => "Daxil olan xÉ™bÉ™rlÉ™rdÉ™ deyilir ki, 6 nÉ™fÉ™r BaÄŸdadın mÉ™rkÉ™zindÉ™ yerləşən TÉ™hsil Nazirliyinin binası yaxınlığında baÅŸ vermiÅŸ partlayış zamanı hÉ™lak olub.", + + + "macedonian" => "на јавното миÑлење покажуваат дека трката е толку теÑна, што Ñе очекува двајцата Ñоперници да ја прекршат традицијата и да Ñе појават и на Ñамиот изборен ден.", + + + + "kazakh" => "Сайлау нәтижеÑінде дауыÑтардың баÑым бөлігін ел премьер миниÑтрі Виктор Янукович пен оның қарÑылаÑÑ‹, Ð¾Ð¿Ð¿Ð¾Ð·Ð¸Ñ†Ð¸Ñ Ð¶ÐµÑ‚ÐµÐºÑˆÑ–ÑÑ– Виктор Ющенко алды.", + + + "bulgarian" => " е готов да даде гаранции, че нÑма да прави Ñдрено оръжие, ако му Ñе разреши мирна атомна програма", + + + "arabic" => " ملايين الناخبين الأمريكيين يدلون بأصواتهم وسط إقبال قياسي على انتخابات هي الأشد تناÙسا منذ عقود", + + ); + + + + + + + + + + + + + + + + + + + + + + + + + + // should be safe at this point + + + $languages = $this->x->getLanguages(); + foreach (array_keys($testarr) as $key) { + $this->assertTrue(in_array($key, $languages), "$key was not in known languages"); + } + + foreach ($testarr as $key=>$value) { + $this->assertEquals($key, $this->x->detectSimple($value)); + } + } + + + public function test_convertFromNameMode0() + { + $this->assertEquals( + 'english', + $this->x->_convertFromNameMode('english') + ); + } + + public function test_convertFromNameMode2String() + { + $this->x->setNameMode(2); + $this->assertEquals( + 'english', + $this->x->_convertFromNameMode('en') + ); + } + + public function test_convertFromNameMode3String() + { + $this->x->setNameMode(3); + $this->assertEquals( + 'english', + $this->x->_convertFromNameMode('eng') + ); + } + + public function test_convertFromNameMode2ArrayVal() + { + $this->x->setNameMode(2); + $this->assertEquals( + array('english', 'german'), + $this->x->_convertFromNameMode(array('en', 'de')) + ); + } + + public function test_convertFromNameMode2ArrayKey() + { + $this->x->setNameMode(2); + $this->assertEquals( + array('english' => 'foo', 'german' => 'test'), + $this->x->_convertFromNameMode( + array('en' => 'foo', 'de' => 'test'), + true + ) + ); + } + + public function test_convertFromNameMode3ArrayVal() + { + $this->x->setNameMode(3); + $this->assertEquals( + array('english', 'german'), + $this->x->_convertFromNameMode(array('eng', 'deu')) + ); + } + + public function test_convertFromNameMode3ArrayKey() + { + $this->x->setNameMode(3); + $this->assertEquals( + array('english' => 'foo', 'german' => 'test'), + $this->x->_convertFromNameMode( + array('eng' => 'foo', 'deu' => 'test'), + true + ) + ); + } + + public function test_convertToNameMode0() + { + $this->assertEquals( + 'english', + $this->x->_convertToNameMode('english') + ); + } + + public function test_convertToNameMode2String() + { + $this->x->setNameMode(2); + $this->assertEquals( + 'en', + $this->x->_convertToNameMode('english') + ); + } + + public function test_convertToNameMode3String() + { + $this->x->setNameMode(3); + $this->assertEquals( + 'eng', + $this->x->_convertToNameMode('english') + ); + } + + public function test_convertToNameMode2ArrayVal() + { + $this->x->setNameMode(2); + $this->assertEquals( + array('en', 'de'), + $this->x->_convertToNameMode(array('english', 'german')) + ); + } + + public function test_convertToNameMode2ArrayKey() + { + $this->x->setNameMode(2); + $this->assertEquals( + array('en' => 'foo', 'de' => 'test'), + $this->x->_convertToNameMode( + array('english' => 'foo', 'german' => 'test'), + true + ) + ); + } + + public function test_convertToNameMode3ArrayVal() + { + $this->x->setNameMode(3); + $this->assertEquals( + array('eng', 'deu'), + $this->x->_convertToNameMode(array('english', 'german')) + ); + } + + public function test_convertToNameMode3ArrayKey() + { + $this->x->setNameMode(3); + $this->assertEquals( + array('eng' => 'foo', 'deu' => 'test'), + $this->x->_convertToNameMode( + array('english' => 'foo', 'german' => 'test'), + true + ) + ); + } +} diff --git a/sources/library/langdet/tests/Text_LanguageDetect_ISO639Test.php b/sources/library/langdet/tests/Text_LanguageDetect_ISO639Test.php new file mode 100644 index 00000000..e01d715e --- /dev/null +++ b/sources/library/langdet/tests/Text_LanguageDetect_ISO639Test.php @@ -0,0 +1,72 @@ +assertEquals( + 'de', + Text_LanguageDetect_ISO639::nameToCode2('german') + ); + } + + public function testNameToCode2Fail() + { + $this->assertNull( + Text_LanguageDetect_ISO639::nameToCode2('doesnotexist') + ); + } + + public function testNameToCode3() + { + $this->assertEquals( + 'fra', + Text_LanguageDetect_ISO639::nameToCode3('french') + ); + } + + public function testNameToCode3Fail() + { + $this->assertNull( + Text_LanguageDetect_ISO639::nameToCode3('doesnotexist') + ); + } + + public function testCode2ToName() + { + $this->assertEquals( + 'english', + Text_LanguageDetect_ISO639::code2ToName('en') + ); + } + + public function testCode2ToNameFail() + { + $this->assertNull( + Text_LanguageDetect_ISO639::code2ToName('nx') + ); + } + + public function testCode3ToName() + { + $this->assertEquals( + 'romanian', + Text_LanguageDetect_ISO639::code3ToName('rom') + ); + } + + public function testCode3ToNameFail() + { + $this->assertNull( + Text_LanguageDetect_ISO639::code3ToName('nxx') + ); + } + +} + +?> \ No newline at end of file diff --git a/sources/library/markdown.php b/sources/library/markdown.php new file mode 100644 index 00000000..f548fc26 --- /dev/null +++ b/sources/library/markdown.php @@ -0,0 +1,2932 @@ + +# +# Original Markdown +# Copyright (c) 2004-2006 John Gruber +# +# + + +define( 'MARKDOWN_VERSION', "1.0.1o" ); # Sun 8 Jan 2012 +define( 'MARKDOWNEXTRA_VERSION', "1.2.5" ); # Sun 8 Jan 2012 + + +# +# Global default settings: +# + +# Change to ">" for HTML output +@define( 'MARKDOWN_EMPTY_ELEMENT_SUFFIX', " />"); + +# Define the width of a tab for code blocks. +@define( 'MARKDOWN_TAB_WIDTH', 4 ); + +# Optional title attribute for footnote links and backlinks. +@define( 'MARKDOWN_FN_LINK_TITLE', "" ); +@define( 'MARKDOWN_FN_BACKLINK_TITLE', "" ); + +# Optional class attribute for footnote links and backlinks. +@define( 'MARKDOWN_FN_LINK_CLASS', "" ); +@define( 'MARKDOWN_FN_BACKLINK_CLASS', "" ); + + +# +# WordPress settings: +# + +# Change to false to remove Markdown from posts and/or comments. +@define( 'MARKDOWN_WP_POSTS', true ); +@define( 'MARKDOWN_WP_COMMENTS', true ); + + + +### Standard Function Interface ### + +@define( 'MARKDOWN_PARSER_CLASS', 'MarkdownExtra_Parser' ); + +function Markdown($text) { +# +# Initialize the parser and return the result of its transform method. +# + # Setup static parser variable. + static $parser; + if (!isset($parser)) { + $parser_class = MARKDOWN_PARSER_CLASS; + $parser = new $parser_class; + } + + # Transform text using parser. + return $parser->transform($text); +} + + +### WordPress Plugin Interface ### + +/* +Plugin Name: Markdown Extra +Plugin URI: http://michelf.com/projects/php-markdown/ +Description: Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More... +Version: 1.2.5 +Author: Michel Fortin +Author URI: http://michelf.com/ +*/ + +if (isset($wp_version)) { + # More details about how it works here: + # + + # Post content and excerpts + # - Remove WordPress paragraph generator. + # - Run Markdown on excerpt, then remove all tags. + # - Add paragraph tag around the excerpt, but remove it for the excerpt rss. + if (MARKDOWN_WP_POSTS) { + remove_filter('the_content', 'wpautop'); + remove_filter('the_content_rss', 'wpautop'); + remove_filter('the_excerpt', 'wpautop'); + add_filter('the_content', 'mdwp_MarkdownPost', 6); + add_filter('the_content_rss', 'mdwp_MarkdownPost', 6); + add_filter('get_the_excerpt', 'mdwp_MarkdownPost', 6); + add_filter('get_the_excerpt', 'trim', 7); + add_filter('the_excerpt', 'mdwp_add_p'); + add_filter('the_excerpt_rss', 'mdwp_strip_p'); + + remove_filter('content_save_pre', 'balanceTags', 50); + remove_filter('excerpt_save_pre', 'balanceTags', 50); + add_filter('the_content', 'balanceTags', 50); + add_filter('get_the_excerpt', 'balanceTags', 9); + } + + # Add a footnote id prefix to posts when inside a loop. + function mdwp_MarkdownPost($text) { + static $parser; + if (!$parser) { + $parser_class = MARKDOWN_PARSER_CLASS; + $parser = new $parser_class; + } + if (is_single() || is_page() || is_feed()) { + $parser->fn_id_prefix = ""; + } else { + $parser->fn_id_prefix = get_the_ID() . "."; + } + return $parser->transform($text); + } + + # Comments + # - Remove WordPress paragraph generator. + # - Remove WordPress auto-link generator. + # - Scramble important tags before passing them to the kses filter. + # - Run Markdown on excerpt then remove paragraph tags. + if (MARKDOWN_WP_COMMENTS) { + remove_filter('comment_text', 'wpautop', 30); + remove_filter('comment_text', 'make_clickable'); + add_filter('pre_comment_content', 'Markdown', 6); + add_filter('pre_comment_content', 'mdwp_hide_tags', 8); + add_filter('pre_comment_content', 'mdwp_show_tags', 12); + add_filter('get_comment_text', 'Markdown', 6); + add_filter('get_comment_excerpt', 'Markdown', 6); + add_filter('get_comment_excerpt', 'mdwp_strip_p', 7); + + global $mdwp_hidden_tags, $mdwp_placeholders; + $mdwp_hidden_tags = explode(' ', + '

     
  1. '); + $mdwp_placeholders = explode(' ', str_rot13( + 'pEj07ZbbBZ U1kqgh4w4p pre2zmeN6K QTi31t9pre ol0MP1jzJR '. + 'ML5IjmbRol ulANi1NsGY J7zRLJqPul liA8ctl16T K9nhooUHli')); + } + + function mdwp_add_p($text) { + if (!preg_match('{^$|^<(p|ul|ol|dl|pre|blockquote)>}i', $text)) { + $text = '

    '.$text.'

    '; + $text = preg_replace('{\n{2,}}', "

    \n\n

    ", $text); + } + return $text; + } + + function mdwp_strip_p($t) { return preg_replace('{}i', '', $t); } + + function mdwp_hide_tags($text) { + global $mdwp_hidden_tags, $mdwp_placeholders; + return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text); + } + function mdwp_show_tags($text) { + global $mdwp_hidden_tags, $mdwp_placeholders; + return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text); + } +} + + +### bBlog Plugin Info ### + +function identify_modifier_markdown() { + return array( + 'name' => 'markdown', + 'type' => 'modifier', + 'nicename' => 'PHP Markdown Extra', + 'description' => 'A text-to-HTML conversion tool for web writers', + 'authors' => 'Michel Fortin and John Gruber', + 'licence' => 'GPL', + 'version' => MARKDOWNEXTRA_VERSION, + 'help' => 'Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More...', + ); +} + + +### Smarty Modifier Interface ### + +function smarty_modifier_markdown($text) { + return Markdown($text); +} + + +### Textile Compatibility Mode ### + +# Rename this file to "classTextile.php" and it can replace Textile everywhere. + +if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) { + # Try to include PHP SmartyPants. Should be in the same directory. + @include_once 'smartypants.php'; + # Fake Textile class. It calls Markdown instead. + class Textile { + function TextileThis($text, $lite='', $encode='') { + if ($lite == '' && $encode == '') $text = Markdown($text); + if (function_exists('SmartyPants')) $text = SmartyPants($text); + return $text; + } + # Fake restricted version: restrictions are not supported for now. + function TextileRestricted($text, $lite='', $noimage='') { + return $this->TextileThis($text, $lite); + } + # Workaround to ensure compatibility with TextPattern 4.0.3. + function blockLite($text) { return $text; } + } +} + + + +# +# Markdown Parser Class +# + +class Markdown_Parser { + + # Regex to match balanced [brackets]. + # Needed to insert a maximum bracked depth while converting to PHP. + var $nested_brackets_depth = 6; + var $nested_brackets_re; + + var $nested_url_parenthesis_depth = 4; + var $nested_url_parenthesis_re; + + # Table of hash values for escaped characters: + var $escape_chars = '\`*_{}[]()>#+-.!'; + var $escape_chars_re; + + # Change to ">" for HTML output. + var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX; + var $tab_width = MARKDOWN_TAB_WIDTH; + + # Change to `true` to disallow markup or entities. + var $no_markup = false; + var $no_entities = false; + + # Predefined urls and titles for reference links and images. + var $predef_urls = array(); + var $predef_titles = array(); + + + function Markdown_Parser() { + # + # Constructor function. Initialize appropriate member variables. + # + $this->_initDetab(); + $this->prepareItalicsAndBold(); + + $this->nested_brackets_re = + str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth). + str_repeat('\])*', $this->nested_brackets_depth); + + $this->nested_url_parenthesis_re = + str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth). + str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth); + + $this->escape_chars_re = '['.preg_quote($this->escape_chars).']'; + + # Sort document, block, and span gamut in ascendent priority order. + asort($this->document_gamut); + asort($this->block_gamut); + asort($this->span_gamut); + } + + + # Internal hashes used during transformation. + var $urls = array(); + var $titles = array(); + var $html_hashes = array(); + + # Status flag to avoid invalid nesting. + var $in_anchor = false; + + + function setup() { + # + # Called before the transformation process starts to setup parser + # states. + # + # Clear global hashes. + $this->urls = $this->predef_urls; + $this->titles = $this->predef_titles; + $this->html_hashes = array(); + + $in_anchor = false; + } + + function teardown() { + # + # Called after the transformation process to clear any variable + # which may be taking up memory unnecessarly. + # + $this->urls = array(); + $this->titles = array(); + $this->html_hashes = array(); + } + + + function transform($text) { + # + # Main function. Performs some preprocessing on the input text + # and pass it through the document gamut. + # + $this->setup(); + + # Remove UTF-8 BOM and marker character in input, if present. + $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text); + + # Standardize line endings: + # DOS to Unix and Mac to Unix + $text = preg_replace('{\r\n?}', "\n", $text); + + # Make sure $text ends with a couple of newlines: + $text .= "\n\n"; + + # Convert all tabs to spaces. + $text = $this->detab($text); + + # Turn block-level HTML blocks into hash entries + $text = $this->hashHTMLBlocks($text); + + # Strip any lines consisting only of spaces and tabs. + # This makes subsequent regexen easier to write, because we can + # match consecutive blank lines with /\n+/ instead of something + # contorted like /[ ]*\n+/ . + $text = preg_replace('/^[ ]+$/m', '', $text); + + # Run document gamut methods. + foreach ($this->document_gamut as $method => $priority) { + $text = $this->$method($text); + } + + $this->teardown(); + + return $text . "\n"; + } + + var $document_gamut = array( + # Strip link definitions, store in hashes. + "stripLinkDefinitions" => 20, + + "runBasicBlockGamut" => 30, + ); + + + function stripLinkDefinitions($text) { + # + # Strips link definitions from text, stores the URLs and titles in + # hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: ^[id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1 + [ ]* + \n? # maybe *one* newline + [ ]* + (?: + <(.+?)> # url = $2 + | + (\S+?) # url = $3 + ) + [ ]* + \n? # maybe one newline + [ ]* + (?: + (?<=\s) # lookbehind for whitespace + ["(] + (.*?) # title = $4 + [")] + [ ]* + )? # title is optional + (?:\n+|\Z) + }xm', + array(&$this, '_stripLinkDefinitions_callback'), + $text); + return $text; + } + function _stripLinkDefinitions_callback($matches) { + $link_id = strtolower($matches[1]); + $url = $matches[2] == '' ? $matches[3] : $matches[2]; + $this->urls[$link_id] = $url; + $this->titles[$link_id] =& $matches[4]; + return ''; # String that will replace the block + } + + + function hashHTMLBlocks($text) { + if ($this->no_markup) return $text; + + $less_than_tab = $this->tab_width - 1; + + # Hashify HTML blocks: + # We only want to do this for block-level HTML tags, such as headers, + # lists, and tables. That's because we still want to wrap

    s around + # "paragraphs" that are wrapped in non-block-level tags, such as anchors, + # phrase emphasis, and spans. The list of tags we're looking for is + # hard-coded: + # + # * List "a" is made of tags which can be both inline or block-level. + # These will be treated block-level when the start tag is alone on + # its line, otherwise they're not matched here and will be taken as + # inline later. + # * List "b" is made of tags which are always block-level; + # + $block_tags_a_re = 'ins|del'; + $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'. + 'script|noscript|form|fieldset|iframe|math'; + + # Regular expression for the content of a block tag. + $nested_tags_level = 4; + $attr = ' + (?> # optional tag attributes + \s # starts with whitespace + (?> + [^>"/]+ # text outside quotes + | + /+(?!>) # slash not followed by ">" + | + "[^"]*" # text inside double quotes (tolerate ">") + | + \'[^\']*\' # text inside single quotes (tolerate ">") + )* + )? + '; + $content = + str_repeat(' + (?> + [^<]+ # content without tag + | + <\2 # nested opening tag + '.$attr.' # attributes + (?> + /> + | + >', $nested_tags_level). # end of opening tag + '.*?'. # last level nested tag content + str_repeat(' + # closing nested tag + ) + | + <(?!/\2\s*> # other tags with a different name + ) + )*', + $nested_tags_level); + $content2 = str_replace('\2', '\3', $content); + + # First, look for nested blocks, e.g.: + #

    + #
    + # tags for inner block must be indented. + #
    + #
    + # + # The outermost tags must start at the left margin for this to match, and + # the inner nested divs must be indented. + # We need to do this before the next, more liberal match, because the next + # match will start at the first `
    ` and stop at the first `
    `. + $text = preg_replace_callback('{(?> + (?> + (?<=\n\n) # Starting after a blank line + | # or + \A\n? # the beginning of the doc + ) + ( # save in $1 + + # Match from `\n` to `\n`, handling nested tags + # in between. + + [ ]{0,'.$less_than_tab.'} + <('.$block_tags_b_re.')# start tag = $2 + '.$attr.'> # attributes followed by > and \n + '.$content.' # content, support nesting + # the matching end tag + [ ]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + + | # Special version for tags of group a. + + [ ]{0,'.$less_than_tab.'} + <('.$block_tags_a_re.')# start tag = $3 + '.$attr.'>[ ]*\n # attributes followed by > + '.$content2.' # content, support nesting + # the matching end tag + [ ]* # trailing spaces/tabs + (?=\n+|\Z) # followed by a newline or end of document + + | # Special case just for
    . It was easier to make a special + # case than to make the other regex more complicated. + + [ ]{0,'.$less_than_tab.'} + <(hr) # start tag = $2 + '.$attr.' # attributes + /?> # the matching end tag + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + | # Special case for standalone HTML comments: + + [ ]{0,'.$less_than_tab.'} + (?s: + + ) + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + | # PHP and ASP-style processor instructions ( + ) + [ ]* + (?=\n{2,}|\Z) # followed by a blank line or end of document + + ) + )}Sxmi', + array(&$this, '_hashHTMLBlocks_callback'), + $text); + + return $text; + } + function _hashHTMLBlocks_callback($matches) { + $text = $matches[1]; + $key = $this->hashBlock($text); + return "\n\n$key\n\n"; + } + + + function hashPart($text, $boundary = 'X') { + # + # Called whenever a tag must be hashed when a function insert an atomic + # element in the text stream. Passing $text to through this function gives + # a unique text-token which will be reverted back when calling unhash. + # + # The $boundary argument specify what character should be used to surround + # the token. By convension, "B" is used for block elements that needs not + # to be wrapped into paragraph tags at the end, ":" is used for elements + # that are word separators and "X" is used in the general case. + # + # Swap back any tag hash found in $text so we do not have to `unhash` + # multiple times at the end. + $text = $this->unhash($text); + + # Then hash the block. + static $i = 0; + $key = "$boundary\x1A" . ++$i . $boundary; + $this->html_hashes[$key] = $text; + return $key; # String that will replace the tag. + } + + + function hashBlock($text) { + # + # Shortcut function for hashPart with block-level boundaries. + # + return $this->hashPart($text, 'B'); + } + + + var $block_gamut = array( + # + # These are all the transformations that form block-level + # tags like paragraphs, headers, and list items. + # + "doHeaders" => 10, + "doHorizontalRules" => 20, + + "doLists" => 40, + "doCodeBlocks" => 50, + "doBlockQuotes" => 60, + ); + + function runBlockGamut($text) { + # + # Run block gamut tranformations. + # + # We need to escape raw HTML in Markdown source before doing anything + # else. This need to be done for each block, and not only at the + # begining in the Markdown function since hashed blocks can be part of + # list items and could have been indented. Indented blocks would have + # been seen as a code block in a previous pass of hashHTMLBlocks. + $text = $this->hashHTMLBlocks($text); + + return $this->runBasicBlockGamut($text); + } + + function runBasicBlockGamut($text) { + # + # Run block gamut tranformations, without hashing HTML blocks. This is + # useful when HTML blocks are known to be already hashed, like in the first + # whole-document pass. + # + foreach ($this->block_gamut as $method => $priority) { + $text = $this->$method($text); + } + + # Finally form paragraph and restore hashed blocks. + $text = $this->formParagraphs($text); + + return $text; + } + + + function doHorizontalRules($text) { + # Do Horizontal Rules: + return preg_replace( + '{ + ^[ ]{0,3} # Leading space + ([-*_]) # $1: First marker + (?> # Repeated marker group + [ ]{0,2} # Zero, one, or two spaces. + \1 # Marker character + ){2,} # Group repeated at least twice + [ ]* # Tailing spaces + $ # End of line. + }mx', + "\n".$this->hashBlock("empty_element_suffix")."\n", + $text); + } + + + var $span_gamut = array( + # + # These are all the transformations that occur *within* block-level + # tags like paragraphs, headers, and list items. + # + # Process character escapes, code spans, and inline HTML + # in one shot. + "parseSpan" => -30, + + # Process anchor and image tags. Images must come first, + # because ![foo][f] looks like an anchor. + "doImages" => 10, + "doAnchors" => 20, + + # Make links out of things like `` + # Must come after doAnchors, because you can use < and > + # delimiters in inline links like [this](). + "doAutoLinks" => 30, + "encodeAmpsAndAngles" => 40, + + "doItalicsAndBold" => 50, + "doHardBreaks" => 60, + ); + + function runSpanGamut($text) { + # + # Run span gamut tranformations. + # + foreach ($this->span_gamut as $method => $priority) { + $text = $this->$method($text); + } + + return $text; + } + + + function doHardBreaks($text) { + # Do hard breaks: + return preg_replace_callback('/ {2,}\n/', + array(&$this, '_doHardBreaks_callback'), $text); + } + function _doHardBreaks_callback($matches) { + return $this->hashPart("empty_element_suffix\n"); + } + + + function doAnchors($text) { + # + # Turn Markdown link shortcuts into XHTML tags. + # + if ($this->in_anchor) return $text; + $this->in_anchor = true; + + # + # First, handle reference-style links: [link text] [id] + # + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ('.$this->nested_brackets_re.') # link text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + ) + }xs', + array(&$this, '_doAnchors_reference_callback'), $text); + + # + # Next, inline-style links: [link text](url "optional title") + # + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ('.$this->nested_brackets_re.') # link text = $2 + \] + \( # literal paren + [ \n]* + (?: + <(.+?)> # href = $3 + | + ('.$this->nested_url_parenthesis_re.') # href = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # Title = $7 + \6 # matching quote + [ \n]* # ignore any spaces/tabs between closing quote and ) + )? # title is optional + \) + ) + }xs', + array(&$this, '_doAnchors_inline_callback'), $text); + + # + # Last, handle reference-style shortcuts: [link text] + # These must come last in case you've also got [link text][1] + # or [link text](/foo) + # + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + \[ + ([^\[\]]+) # link text = $2; can\'t contain [ or ] + \] + ) + }xs', + array(&$this, '_doAnchors_reference_callback'), $text); + + $this->in_anchor = false; + return $text; + } + function _doAnchors_reference_callback($matches) { + $whole_match = $matches[1]; + $link_text = $matches[2]; + $link_id =& $matches[3]; + + if ($link_id == "") { + # for shortcut links like [this][] or [this]. + $link_id = $link_text; + } + + # lower-case and turn embedded newlines into spaces + $link_id = strtolower($link_id); + $link_id = preg_replace('{[ ]?\n}', ' ', $link_id); + + if (isset($this->urls[$link_id])) { + $url = $this->urls[$link_id]; + $url = $this->encodeAttribute($url); + + $result = "titles[$link_id] ) ) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + $result = $this->hashPart($result); + } + else { + $result = $whole_match; + } + return $result; + } + function _doAnchors_inline_callback($matches) { + $whole_match = $matches[1]; + $link_text = $this->runSpanGamut($matches[2]); + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + + $url = $this->encodeAttribute($url); + + $result = "encodeAttribute($title); + $result .= " title=\"$title\""; + } + + $link_text = $this->runSpanGamut($link_text); + $result .= ">$link_text"; + + return $this->hashPart($result); + } + + + function doImages($text) { + # + # Turn Markdown image shortcuts into tags. + # + # + # First, handle reference-style labeled images: ![alt text][id] + # + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + ('.$this->nested_brackets_re.') # alt text = $2 + \] + + [ ]? # one optional space + (?:\n[ ]*)? # one optional newline followed by spaces + + \[ + (.*?) # id = $3 + \] + + ) + }xs', + array(&$this, '_doImages_reference_callback'), $text); + + # + # Next, handle inline images: ![alt text](url "optional title") + # Don't forget: encode * and _ + # + $text = preg_replace_callback('{ + ( # wrap whole match in $1 + !\[ + ('.$this->nested_brackets_re.') # alt text = $2 + \] + \s? # One optional whitespace character + \( # literal paren + [ \n]* + (?: + <(\S*)> # src url = $3 + | + ('.$this->nested_url_parenthesis_re.') # src url = $4 + ) + [ \n]* + ( # $5 + ([\'"]) # quote char = $6 + (.*?) # title = $7 + \6 # matching quote + [ \n]* + )? # title is optional + \) + ) + }xs', + array(&$this, '_doImages_inline_callback'), $text); + + return $text; + } + function _doImages_reference_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $link_id = strtolower($matches[3]); + + if ($link_id == "") { + $link_id = strtolower($alt_text); # for shortcut links like ![this][]. + } + + $alt_text = $this->encodeAttribute($alt_text); + if (isset($this->urls[$link_id])) { + $url = $this->encodeAttribute($this->urls[$link_id]); + $result = "\"$alt_text\"";titles[$link_id])) { + $title = $this->titles[$link_id]; + $title = $this->encodeAttribute($title); + $result .= " title=\"$title\""; + } + $result .= $this->empty_element_suffix; + $result = $this->hashPart($result); + } + else { + # If there's no such link ID, leave intact: + $result = $whole_match; + } + + return $result; + } + function _doImages_inline_callback($matches) { + $whole_match = $matches[1]; + $alt_text = $matches[2]; + $url = $matches[3] == '' ? $matches[4] : $matches[3]; + $title =& $matches[7]; + + $alt_text = $this->encodeAttribute($alt_text); + $url = $this->encodeAttribute($url); + $result = "\"$alt_text\"";encodeAttribute($title); + $result .= " title=\"$title\""; # $title already quoted + } + $result .= $this->empty_element_suffix; + + return $this->hashPart($result); + } + + + function doHeaders($text) { + # Setext-style headers: + # Header 1 + # ======== + # + # Header 2 + # -------- + # + $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx', + array(&$this, '_doHeaders_callback_setext'), $text); + + # atx-style headers: + # # Header 1 + # ## Header 2 + # ## Header 2 with closing hashes ## + # ... + # ###### Header 6 + # + $text = preg_replace_callback('{ + ^(\#{1,6}) # $1 = string of #\'s + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #\'s (not counted) + \n+ + }xm', + array(&$this, '_doHeaders_callback_atx'), $text); + + return $text; + } + function _doHeaders_callback_setext($matches) { + # Terrible hack to check we haven't found an empty list item. + if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1])) + return $matches[0]; + + $level = $matches[2]{0} == '=' ? 1 : 2; + $block = "".$this->runSpanGamut($matches[1]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + function _doHeaders_callback_atx($matches) { + $level = strlen($matches[1]); + $block = "".$this->runSpanGamut($matches[2]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + + function doLists($text) { + # + # Form HTML ordered (numbered) and unordered (bulleted) lists. + # + $less_than_tab = $this->tab_width - 1; + + # Re-usable patterns to match list item bullets and number markers: + $marker_ul_re = '[*+-]'; + $marker_ol_re = '\d+[\.]'; + $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; + + $markers_relist = array( + $marker_ul_re => $marker_ol_re, + $marker_ol_re => $marker_ul_re, + ); + + foreach ($markers_relist as $marker_re => $other_marker_re) { + # Re-usable pattern to match any entirel ul or ol list: + $whole_list_re = ' + ( # $1 = whole list + ( # $2 + ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces + ('.$marker_re.') # $4 = first list item marker + [ ]+ + ) + (?s:.+?) + ( # $5 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another list item marker + [ ]* + '.$marker_re.'[ ]+ + ) + | + (?= # Lookahead for another kind of list + \n + \3 # Must have the same indentation + '.$other_marker_re.'[ ]+ + ) + ) + ) + '; // mx + + # We use a different prefix before nested lists than top-level lists. + # See extended comment in _ProcessListItems(). + + if ($this->list_level) { + $text = preg_replace_callback('{ + ^ + '.$whole_list_re.' + }mx', + array(&$this, '_doLists_callback'), $text); + } + else { + $text = preg_replace_callback('{ + (?:(?<=\n)\n|\A\n?) # Must eat the newline + '.$whole_list_re.' + }mx', + array(&$this, '_doLists_callback'), $text); + } + } + + return $text; + } + function _doLists_callback($matches) { + # Re-usable patterns to match list item bullets and number markers: + $marker_ul_re = '[*+-]'; + $marker_ol_re = '\d+[\.]'; + $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)"; + + $list = $matches[1]; + $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol"; + + $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re ); + + $list .= "\n"; + $result = $this->processListItems($list, $marker_any_re); + + $result = $this->hashBlock("<$list_type>\n" . $result . ""); + return "\n". $result ."\n\n"; + } + + var $list_level = 0; + + function processListItems($list_str, $marker_any_re) { + # + # Process the contents of a single ordered or unordered list, splitting it + # into individual list items. + # + # The $this->list_level global keeps track of when we're inside a list. + # Each time we enter a list, we increment it; when we leave a list, + # we decrement. If it's zero, we're not in a list anymore. + # + # We do this because when we're not inside a list, we want to treat + # something like this: + # + # I recommend upgrading to version + # 8. Oops, now this line is treated + # as a sub-list. + # + # As a single paragraph, despite the fact that the second line starts + # with a digit-period-space sequence. + # + # Whereas when we're inside a list (or sub-list), that line will be + # treated as the start of a sub-list. What a kludge, huh? This is + # an aspect of Markdown's syntax that's hard to parse perfectly + # without resorting to mind-reading. Perhaps the solution is to + # change the syntax rules such that sub-lists must start with a + # starting cardinal number; e.g. "1." or "a.". + + $this->list_level++; + + # trim trailing blank lines: + $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); + + $list_str = preg_replace_callback('{ + (\n)? # leading line = $1 + (^[ ]*) # leading whitespace = $2 + ('.$marker_any_re.' # list marker and space = $3 + (?:[ ]+|(?=\n)) # space only required if item is not empty + ) + ((?s:.*?)) # list item text = $4 + (?:(\n+(?=\n))|\n) # tailing blank line = $5 + (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n)))) + }xm', + array(&$this, '_processListItems_callback'), $list_str); + + $this->list_level--; + return $list_str; + } + function _processListItems_callback($matches) { + $item = $matches[4]; + $leading_line =& $matches[1]; + $leading_space =& $matches[2]; + $marker_space = $matches[3]; + $tailing_blank_line =& $matches[5]; + + if ($leading_line || $tailing_blank_line || + preg_match('/\n{2,}/', $item)) + { + # Replace marker with the appropriate whitespace indentation + $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item; + $item = $this->runBlockGamut($this->outdent($item)."\n"); + } + else { + # Recursion for sub-lists: + $item = $this->doLists($this->outdent($item)); + $item = preg_replace('/\n+$/', '', $item); + $item = $this->runSpanGamut($item); + } + + return "
  2. " . $item . "
  3. \n"; + } + + + function doCodeBlocks($text) { + # + # Process Markdown `
    ` blocks.
    +	#
    +		$text = preg_replace_callback('{
    +				(?:\n\n|\A\n?)
    +				(	            # $1 = the code block -- one or more lines, starting with a space/tab
    +				  (?>
    +					[ ]{'.$this->tab_width.'}  # Lines must start with a tab or a tab-width of spaces
    +					.*\n+
    +				  )+
    +				)
    +				((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z)	# Lookahead for non-space at line-start, or end of doc
    +			}xm',
    +			array(&$this, '_doCodeBlocks_callback'), $text);
    +
    +		return $text;
    +	}
    +	function _doCodeBlocks_callback($matches) {
    +		$codeblock = $matches[1];
    +
    +		$codeblock = $this->outdent($codeblock);
    +		$codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
    +
    +		# trim leading newlines and trailing newlines
    +		$codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
    +
    +		$codeblock = "
    $codeblock\n
    "; + return "\n\n".$this->hashBlock($codeblock)."\n\n"; + } + + + function makeCodeSpan($code) { + # + # Create a code span markup for $code. Called from handleSpanToken. + # + $code = htmlspecialchars(trim($code), ENT_NOQUOTES); + return $this->hashPart("$code"); + } + + + var $em_relist = array( + '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(?em_relist as $em => $em_re) { + foreach ($this->strong_relist as $strong => $strong_re) { + # Construct list of allowed token expressions. + $token_relist = array(); + if (isset($this->em_strong_relist["$em$strong"])) { + $token_relist[] = $this->em_strong_relist["$em$strong"]; + } + $token_relist[] = $em_re; + $token_relist[] = $strong_re; + + # Construct master expression from list. + $token_re = '{('. implode('|', $token_relist) .')}'; + $this->em_strong_prepared_relist["$em$strong"] = $token_re; + } + } + } + + function doItalicsAndBold($text) { + $token_stack = array(''); + $text_stack = array(''); + $em = ''; + $strong = ''; + $tree_char_em = false; + + while (1) { + # + # Get prepared regular expression for seraching emphasis tokens + # in current context. + # + $token_re = $this->em_strong_prepared_relist["$em$strong"]; + + # + # Each loop iteration search for the next emphasis token. + # Each token is then passed to handleSpanToken. + # + $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); + $text_stack[0] .= $parts[0]; + $token =& $parts[1]; + $text =& $parts[2]; + + if (empty($token)) { + # Reached end of text span: empty stack without emitting. + # any more emphasis. + while ($token_stack[0]) { + $text_stack[1] .= array_shift($token_stack); + $text_stack[0] .= array_shift($text_stack); + } + break; + } + + $token_len = strlen($token); + if ($tree_char_em) { + # Reached closing marker while inside a three-char emphasis. + if ($token_len == 3) { + # Three-char closing marker, close em and strong. + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $em = ''; + $strong = ''; + } else { + # Other closing marker: close one em or strong and + # change current token state to match the other + $token_stack[0] = str_repeat($token{0}, 3-$token_len); + $tag = $token_len == 2 ? "strong" : "em"; + $span = $text_stack[0]; + $span = $this->runSpanGamut($span); + $span = "<$tag>$span"; + $text_stack[0] = $this->hashPart($span); + $$tag = ''; # $$tag stands for $em or $strong + } + $tree_char_em = false; + } else if ($token_len == 3) { + if ($em) { + # Reached closing marker for both em and strong. + # Closing strong marker: + for ($i = 0; $i < 2; ++$i) { + $shifted_token = array_shift($token_stack); + $tag = strlen($shifted_token) == 2 ? "strong" : "em"; + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "<$tag>$span"; + $text_stack[0] .= $this->hashPart($span); + $$tag = ''; # $$tag stands for $em or $strong + } + } else { + # Reached opening three-char emphasis marker. Push on token + # stack; will be handled by the special condition above. + $em = $token{0}; + $strong = "$em$em"; + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $tree_char_em = true; + } + } else if ($token_len == 2) { + if ($strong) { + # Unwind any dangling emphasis marker: + if (strlen($token_stack[0]) == 1) { + $text_stack[1] .= array_shift($token_stack); + $text_stack[0] .= array_shift($text_stack); + } + # Closing strong marker: + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $strong = ''; + } else { + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $strong = $token; + } + } else { + # Here $token_len == 1 + if ($em) { + if (strlen($token_stack[0]) == 1) { + # Closing emphasis marker: + array_shift($token_stack); + $span = array_shift($text_stack); + $span = $this->runSpanGamut($span); + $span = "$span"; + $text_stack[0] .= $this->hashPart($span); + $em = ''; + } else { + $text_stack[0] .= $token; + } + } else { + array_unshift($token_stack, $token); + array_unshift($text_stack, ''); + $em = $token; + } + } + } + return $text_stack[0]; + } + + + function doBlockQuotes($text) { + $text = preg_replace_callback('/ + ( # Wrap whole match in $1 + (?> + ^[ ]*>[ ]? # ">" at the start of a line + .+\n # rest of the first line + (.+\n)* # subsequent consecutive lines + \n* # blanks + )+ + ) + /xm', + array(&$this, '_doBlockQuotes_callback'), $text); + + return $text; + } + function _doBlockQuotes_callback($matches) { + $bq = $matches[1]; + # trim one level of quoting - trim whitespace-only lines + $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq); + $bq = $this->runBlockGamut($bq); # recurse + + $bq = preg_replace('/^/m', " ", $bq); + # These leading spaces cause problem with
     content, 
    +		# so we need to fix that:
    +		$bq = preg_replace_callback('{(\s*
    .+?
    )}sx', + array(&$this, '_doBlockQuotes_callback2'), $bq); + + return "\n". $this->hashBlock("
    \n$bq\n
    ")."\n\n"; + } + function _doBlockQuotes_callback2($matches) { + $pre = $matches[1]; + $pre = preg_replace('/^ /m', '', $pre); + return $pre; + } + + + function formParagraphs($text) { + # + # Params: + # $text - string to process with html

    tags + # + # Strip leading and trailing lines: + $text = preg_replace('/\A\n+|\n+\z/', '', $text); + + $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); + + # + # Wrap

    tags and unhashify HTML blocks + # + foreach ($grafs as $key => $value) { + if (!preg_match('/^B\x1A[0-9]+B$/', $value)) { + # Is a paragraph. + $value = $this->runSpanGamut($value); + $value = preg_replace('/^([ ]*)/', "

    ", $value); + $value .= "

    "; + $grafs[$key] = $this->unhash($value); + } + else { + # Is a block. + # Modify elements of @grafs in-place... + $graf = $value; + $block = $this->html_hashes[$graf]; + $graf = $block; +// if (preg_match('{ +// \A +// ( # $1 =
    tag +//
    ]* +// \b +// markdown\s*=\s* ([\'"]) # $2 = attr quote char +// 1 +// \2 +// [^>]* +// > +// ) +// ( # $3 = contents +// .* +// ) +// (
    ) # $4 = closing tag +// \z +// }xs', $block, $matches)) +// { +// list(, $div_open, , $div_content, $div_close) = $matches; +// +// # We can't call Markdown(), because that resets the hash; +// # that initialization code should be pulled into its own sub, though. +// $div_content = $this->hashHTMLBlocks($div_content); +// +// # Run document gamut methods on the content. +// foreach ($this->document_gamut as $method => $priority) { +// $div_content = $this->$method($div_content); +// } +// +// $div_open = preg_replace( +// '{\smarkdown\s*=\s*([\'"]).+?\1}', '', $div_open); +// +// $graf = $div_open . "\n" . $div_content . "\n" . $div_close; +// } + $grafs[$key] = $graf; + } + } + + return implode("\n\n", $grafs); + } + + + function encodeAttribute($text) { + # + # Encode text for a double-quoted HTML attribute. This function + # is *not* suitable for attributes enclosed in single quotes. + # + $text = $this->encodeAmpsAndAngles($text); + $text = str_replace('"', '"', $text); + return $text; + } + + + function encodeAmpsAndAngles($text) { + # + # Smart processing for ampersands and angle brackets that need to + # be encoded. Valid character entities are left alone unless the + # no-entities mode is set. + # + if ($this->no_entities) { + $text = str_replace('&', '&', $text); + } else { + # Ampersand-encoding based entirely on Nat Irons's Amputator + # MT plugin: + $text = preg_replace('/&(?!#?[xX]?(?:[0-9a-fA-F]+|\w+);)/', + '&', $text);; + } + # Encode remaining <'s + $text = str_replace('<', '<', $text); + + return $text; + } + + + function doAutoLinks($text) { + $text = preg_replace_callback('{<((https?|ftp|dict):[^\'">\s]+)>}i', + array(&$this, '_doAutoLinks_url_callback'), $text); + + # Email addresses: + $text = preg_replace_callback('{ + < + (?:mailto:)? + ( + (?: + [-!#$%&\'*+/=?^_`.{|}~\w\x80-\xFF]+ + | + ".*?" + ) + \@ + (?: + [-a-z0-9\x80-\xFF]+(\.[-a-z0-9\x80-\xFF]+)*\.[a-z]+ + | + \[[\d.a-fA-F:]+\] # IPv4 & IPv6 + ) + ) + > + }xi', + array(&$this, '_doAutoLinks_email_callback'), $text); + + return $text; + } + function _doAutoLinks_url_callback($matches) { + $url = $this->encodeAttribute($matches[1]); + $link = "$url"; + return $this->hashPart($link); + } + function _doAutoLinks_email_callback($matches) { + $address = $matches[1]; + $link = $this->encodeEmailAddress($address); + return $this->hashPart($link); + } + + + function encodeEmailAddress($addr) { + # + # Input: an email address, e.g. "foo@example.com" + # + # Output: the email address as a mailto link, with each character + # of the address encoded as either a decimal or hex entity, in + # the hopes of foiling most address harvesting spam bots. E.g.: + # + #

    foo@exampl + # e.com

    + # + # Based by a filter by Matthew Wickline, posted to BBEdit-Talk. + # With some optimizations by Milian Wolff. + # + $addr = "mailto:" . $addr; + $chars = preg_split('/(? $char) { + $ord = ord($char); + # Ignore non-ascii chars. + if ($ord < 128) { + $r = ($seed * (1 + $key)) % 100; # Pseudo-random function. + # roughly 10% raw, 45% hex, 45% dec + # '@' *must* be encoded. I insist. + if ($r > 90 && $char != '@') /* do nothing */; + else if ($r < 45) $chars[$key] = '&#x'.dechex($ord).';'; + else $chars[$key] = '&#'.$ord.';'; + } + } + + $addr = implode('', $chars); + $text = implode('', array_slice($chars, 7)); # text without `mailto:` + $addr = "$text"; + + return $addr; + } + + + function parseSpan($str) { + # + # Take the string $str and parse it into tokens, hashing embeded HTML, + # escaped characters and handling code spans. + # + $output = ''; + + $span_re = '{ + ( + \\\\'.$this->escape_chars_re.' + | + (?no_markup ? '' : ' + | + # comment + | + <\?.*?\?> | <%.*?%> # processing instruction + | + <[/!$]?[-a-zA-Z0-9:_]+ # regular tags + (?> + \s + (?>[^"\'>]+|"[^"]*"|\'[^\']*\')* + )? + > + ').' + ) + }xs'; + + while (1) { + # + # Each loop iteration seach for either the next tag, the next + # openning code span marker, or the next escaped character. + # Each token is then passed to handleSpanToken. + # + $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE); + + # Create token from text preceding tag. + if ($parts[0] != "") { + $output .= $parts[0]; + } + + # Check if we reach the end. + if (isset($parts[1])) { + $output .= $this->handleSpanToken($parts[1], $parts[2]); + $str = $parts[2]; + } + else { + break; + } + } + + return $output; + } + + + function handleSpanToken($token, &$str) { + # + # Handle $token provided by parseSpan by determining its nature and + # returning the corresponding value that should replace it. + # + switch ($token{0}) { + case "\\": + return $this->hashPart("&#". ord($token{1}). ";"); + case "`": + # Search for end marker in remaining text. + if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm', + $str, $matches)) + { + $str = $matches[2]; + $codespan = $this->makeCodeSpan($matches[1]); + return $this->hashPart($codespan); + } + return $token; // return as text since no ending marker found. + default: + return $this->hashPart($token); + } + } + + + function outdent($text) { + # + # Remove one level of line-leading tabs or spaces + # + return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text); + } + + + # String length function for detab. `_initDetab` will create a function to + # hanlde UTF-8 if the default function does not exist. + var $utf8_strlen = 'mb_strlen'; + + function detab($text) { + # + # Replace tabs with the appropriate amount of space. + # + # For each line we separate the line in blocks delemited by + # tab characters. Then we reconstruct every line by adding the + # appropriate number of space between each blocks. + + $text = preg_replace_callback('/^.*\t.*$/m', + array(&$this, '_detab_callback'), $text); + + return $text; + } + function _detab_callback($matches) { + $line = $matches[0]; + $strlen = $this->utf8_strlen; # strlen function for UTF-8. + + # Split in blocks. + $blocks = explode("\t", $line); + # Add each blocks to the line. + $line = $blocks[0]; + unset($blocks[0]); # Do not add first block twice. + foreach ($blocks as $block) { + # Calculate amount of space, insert spaces, insert block. + $amount = $this->tab_width - + $strlen($line, 'UTF-8') % $this->tab_width; + $line .= str_repeat(" ", $amount) . $block; + } + return $line; + } + function _initDetab() { + # + # Check for the availability of the function in the `utf8_strlen` property + # (initially `mb_strlen`). If the function is not available, create a + # function that will loosely count the number of UTF-8 characters with a + # regular expression. + # + if (function_exists($this->utf8_strlen)) return; + $this->utf8_strlen = create_function('$text', 'return preg_match_all( + "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/", + $text, $m);'); + } + + + function unhash($text) { + # + # Swap back in all the tags hashed by _HashHTMLBlocks. + # + return preg_replace_callback('/(.)\x1A[0-9]+\1/', + array(&$this, '_unhash_callback'), $text); + } + function _unhash_callback($matches) { + return $this->html_hashes[$matches[0]]; + } + +} + + +# +# Markdown Extra Parser Class +# + +class MarkdownExtra_Parser extends Markdown_Parser { + + # Prefix for footnote ids. + var $fn_id_prefix = ""; + + # Optional title attribute for footnote links and backlinks. + var $fn_link_title = MARKDOWN_FN_LINK_TITLE; + var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE; + + # Optional class attribute for footnote links and backlinks. + var $fn_link_class = MARKDOWN_FN_LINK_CLASS; + var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS; + + # Predefined abbreviations. + var $predef_abbr = array(); + + + function MarkdownExtra_Parser() { + # + # Constructor function. Initialize the parser object. + # + # Add extra escapable characters before parent constructor + # initialize the table. + $this->escape_chars .= ':|'; + + # Insert extra document, block, and span transformations. + # Parent constructor will do the sorting. + $this->document_gamut += array( + "doFencedCodeBlocks" => 5, + "stripFootnotes" => 15, + "stripAbbreviations" => 25, + "appendFootnotes" => 50, + ); + $this->block_gamut += array( + "doFencedCodeBlocks" => 5, + "doTables" => 15, + "doDefLists" => 45, + ); + $this->span_gamut += array( + "doFootnotes" => 5, + "doAbbreviations" => 70, + ); + + parent::Markdown_Parser(); + } + + + # Extra variables used during extra transformations. + var $footnotes = array(); + var $footnotes_ordered = array(); + var $abbr_desciptions = array(); + var $abbr_word_re = ''; + + # Give the current footnote number. + var $footnote_counter = 1; + + + function setup() { + # + # Setting up Extra-specific variables. + # + parent::setup(); + + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + $this->footnote_counter = 1; + + foreach ($this->predef_abbr as $abbr_word => $abbr_desc) { + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + } + } + + function teardown() { + # + # Clearing Extra-specific variables. + # + $this->footnotes = array(); + $this->footnotes_ordered = array(); + $this->abbr_desciptions = array(); + $this->abbr_word_re = ''; + + parent::teardown(); + } + + + ### HTML Block Parser ### + + # Tags that are always treated as block tags: + var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend'; + + # Tags treated as block tags only if the opening tag is alone on it's line: + var $context_block_tags_re = 'script|noscript|math|ins|del'; + + # Tags where markdown="1" default to span mode: + var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address'; + + # Tags which must not have their contents modified, no matter where + # they appear: + var $clean_tags_re = 'script|math'; + + # Tags that do not need to be closed. + var $auto_close_tags_re = 'hr|img'; + + + function hashHTMLBlocks($text) { + # + # Hashify HTML Blocks and "clean tags". + # + # We only want to do this for block-level HTML tags, such as headers, + # lists, and tables. That's because we still want to wrap

    s around + # "paragraphs" that are wrapped in non-block-level tags, such as anchors, + # phrase emphasis, and spans. The list of tags we're looking for is + # hard-coded. + # + # This works by calling _HashHTMLBlocks_InMarkdown, which then calls + # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1" + # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back + # _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag. + # These two functions are calling each other. It's recursive! + # + # + # Call the HTML-in-Markdown hasher. + # + list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text); + + return $text; + } + function _hashHTMLBlocks_inMarkdown($text, $indent = 0, + $enclosing_tag_re = '', $span = false) + { + # + # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags. + # + # * $indent is the number of space to be ignored when checking for code + # blocks. This is important because if we don't take the indent into + # account, something like this (which looks right) won't work as expected: + # + #

    + #
    + # Hello World. <-- Is this a Markdown code block or text? + #
    <-- Is this a Markdown code block or a real tag? + #
    + # + # If you don't like this, just don't indent the tag on which + # you apply the markdown="1" attribute. + # + # * If $enclosing_tag_re is not empty, stops at the first unmatched closing + # tag with that name. Nested tags supported. + # + # * If $span is true, text inside must treated as span. So any double + # newline will be replaced by a single newline so that it does not create + # paragraphs. + # + # Returns an array of that form: ( processed text , remaining text ) + # + if ($text === '') return array('', ''); + + # Regex to check for the presense of newlines around a block tag. + $newline_before_re = '/(?:^\n?|\n\n)*$/'; + $newline_after_re = + '{ + ^ # Start of text following the tag. + (?>[ ]*)? # Optional comment. + [ ]*\n # Must be followed by newline. + }xs'; + + # Regex to match any tag. + $block_tag_re = + '{ + ( # $2: Capture hole tag. + # Tag name. + '.$this->block_tags_re.' | + '.$this->context_block_tags_re.' | + '.$this->clean_tags_re.' | + (?!\s)'.$enclosing_tag_re.' + ) + (?: + (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name. + (?> + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + )? + > # End of tag. + | + # HTML Comment + | + <\?.*?\?> | <%.*?%> # Processing instruction + | + # CData Block + | + # Code span marker + `+ + '. ( !$span ? ' # If not in span. + | + # Indented code block + (?: ^[ ]*\n | ^ | \n[ ]*\n ) + [ ]{'.($indent+4).'}[^\n]* \n + (?> + (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n + )* + | + # Fenced code block marker + (?> ^ | \n ) + [ ]{0,'.($indent).'}~~~+[ ]*\n + ' : '' ). ' # End (if not is span). + ) + }xs'; + + + $depth = 0; # Current depth inside the tag tree. + $parsed = ""; # Parsed text that will be returned. + + # + # Loop through every tag until we find the closing tag of the parent + # or loop until reaching the end of text if no parent tag specified. + # + do { + # + # Split the text using the first $tag_match pattern found. + # Text before pattern will be first in the array, text after + # pattern will be at the end, and between will be any catches made + # by the pattern. + # + $parts = preg_split($block_tag_re, $text, 2, + PREG_SPLIT_DELIM_CAPTURE); + + # If in Markdown span mode, add a empty-string span-level hash + # after each newline to prevent triggering any block element. + if ($span) { + $void = $this->hashPart("", ':'); + $newline = "$void\n"; + $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void; + } + + $parsed .= $parts[0]; # Text before current tag. + + # If end of $text has been reached. Stop loop. + if (count($parts) < 3) { + $text = ""; + break; + } + + $tag = $parts[1]; # Tag to handle. + $text = $parts[2]; # Remaining text after current tag. + $tag_re = preg_quote($tag); # For use in a regular expression. + + # + # Check for: Code span marker + # + if ($tag{0} == "`") { + # Find corresponding end marker. + $tag_re = preg_quote($tag); + if (preg_match('{^(?>.+?|\n(?!\n))*?(?.*\n)+?[ ]{0,'.($indent).'}'.$tag_re.'[ ]*\n}', $text, + $matches)) + { + # End marker found: pass text unchanged until marker. + $parsed .= $tag . $matches[0]; + $text = substr($text, strlen($matches[0])); + } + else { + # No end marker: just skip it. + $parsed .= $tag; + } + } + # + # Check for: Indented code block. + # + else if ($tag{0} == "\n" || $tag{0} == " ") { + # Indented code block: pass it unchanged, will be handled + # later. + $parsed .= $tag; + } + # + # Check for: Opening Block level tag or + # Opening Context Block tag (like ins and del) + # used as a block tag (tag is alone on it's line). + # + else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) || + ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) && + preg_match($newline_before_re, $parsed) && + preg_match($newline_after_re, $text) ) + ) + { + # Need to parse tag and following text using the HTML parser. + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true); + + # Make sure it stays outside of any paragraph by adding newlines. + $parsed .= "\n\n$block_text\n\n"; + } + # + # Check for: Clean tag (like script, math) + # HTML Comments, processing instructions. + # + else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + # Need to parse tag and following text using the HTML parser. + # (don't check for markdown attribute) + list($block_text, $text) = + $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false); + + $parsed .= $block_text; + } + # + # Check for: Tag with same name as enclosing tag. + # + else if ($enclosing_tag_re !== '' && + # Same name as enclosing tag. + preg_match('{^= 0); + + return array($parsed, $text); + } + function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) { + # + # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags. + # + # * Calls $hash_method to convert any blocks. + # * Stops when the first opening tag closes. + # * $md_attr indicate if the use of the `markdown="1"` attribute is allowed. + # (it is not inside clean tags) + # + # Returns an array of that form: ( processed text , remaining text ) + # + if ($text === '') return array('', ''); + + # Regex to match `markdown` attribute inside of a tag. + $markdown_attr_re = ' + { + \s* # Eat whitespace before the `markdown` attribute + markdown + \s*=\s* + (?> + (["\']) # $1: quote delimiter + (.*?) # $2: attribute value + \1 # matching delimiter + | + ([^\s>]*) # $3: unquoted attribute value + ) + () # $4: make $3 always defined (avoid warnings) + }xs'; + + # Regex to match any tag. + $tag_re = '{ + ( # $2: Capture hole tag. + + ".*?" | # Double quotes (can contain `>`) + \'.*?\' | # Single quotes (can contain `>`) + .+? # Anything but quotes and `>`. + )*? + )? + > # End of tag. + | + # HTML Comment + | + <\?.*?\?> | <%.*?%> # Processing instruction + | + # CData Block + ) + }xs'; + + $original_text = $text; # Save original text in case of faliure. + + $depth = 0; # Current depth inside the tag tree. + $block_text = ""; # Temporary text holder for current text. + $parsed = ""; # Parsed text that will be returned. + + # + # Get the name of the starting tag. + # (This pattern makes $base_tag_name_re safe without quoting.) + # + if (preg_match('/^<([\w:$]*)\b/', $text, $matches)) + $base_tag_name_re = $matches[1]; + + # + # Loop through every tag until we find the corresponding closing tag. + # + do { + # + # Split the text using the first $tag_match pattern found. + # Text before pattern will be first in the array, text after + # pattern will be at the end, and between will be any catches made + # by the pattern. + # + $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE); + + if (count($parts) < 3) { + # + # End of $text reached with unbalenced tag(s). + # In that case, we return original text unchanged and pass the + # first character as filtered to prevent an infinite loop in the + # parent function. + # + return array($original_text{0}, substr($original_text, 1)); + } + + $block_text .= $parts[0]; # Text before current tag. + $tag = $parts[1]; # Tag to handle. + $text = $parts[2]; # Remaining text after current tag. + + # + # Check for: Auto-close tag (like
    ) + # Comments and Processing Instructions. + # + if (preg_match('{^auto_close_tags_re.')\b}', $tag) || + $tag{1} == '!' || $tag{1} == '?') + { + # Just add the tag to the block as if it was text. + $block_text .= $tag; + } + else { + # + # Increase/decrease nested tag count. Only do so if + # the tag's name match base tag's. + # + if (preg_match('{^mode = $attr_m[2] . $attr_m[3]; + $span_mode = $this->mode == 'span' || $this->mode != 'block' && + preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag); + + # Calculate indent before tag. + if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) { + $strlen = $this->utf8_strlen; + $indent = $strlen($matches[1], 'UTF-8'); + } else { + $indent = 0; + } + + # End preceding block with this tag. + $block_text .= $tag; + $parsed .= $this->$hash_method($block_text); + + # Get enclosing tag name for the ParseMarkdown function. + # (This pattern makes $tag_name_re safe without quoting.) + preg_match('/^<([\w:$]*)\b/', $tag, $matches); + $tag_name_re = $matches[1]; + + # Parse the content using the HTML-in-Markdown parser. + list ($block_text, $text) + = $this->_hashHTMLBlocks_inMarkdown($text, $indent, + $tag_name_re, $span_mode); + + # Outdent markdown text. + if ($indent > 0) { + $block_text = preg_replace("/^[ ]{1,$indent}/m", "", + $block_text); + } + + # Append tag content to parsed text. + if (!$span_mode) $parsed .= "\n\n$block_text\n\n"; + else $parsed .= "$block_text"; + + # Start over a new block. + $block_text = ""; + } + else $block_text .= $tag; + } + + } while ($depth > 0); + + # + # Hash last block text that wasn't processed inside the loop. + # + $parsed .= $this->$hash_method($block_text); + + return array($parsed, $text); + } + + + function hashClean($text) { + # + # Called whenever a tag must be hashed when a function insert a "clean" tag + # in $text, it pass through this function and is automaticaly escaped, + # blocking invalid nested overlap. + # + return $this->hashPart($text, 'C'); + } + + + function doHeaders($text) { + # + # Redefined to add id attribute support. + # + # Setext-style headers: + # Header 1 {#header1} + # ======== + # + # Header 2 {#header2} + # -------- + # + $text = preg_replace_callback( + '{ + (^.+?) # $1: Header text + (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute + [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer + }mx', + array(&$this, '_doHeaders_callback_setext'), $text); + + # atx-style headers: + # # Header 1 {#header1} + # ## Header 2 {#header2} + # ## Header 2 with closing hashes ## {#header3} + # ... + # ###### Header 6 {#header2} + # + $text = preg_replace_callback('{ + ^(\#{1,6}) # $1 = string of #\'s + [ ]* + (.+?) # $2 = Header text + [ ]* + \#* # optional closing #\'s (not counted) + (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute + [ ]* + \n+ + }xm', + array(&$this, '_doHeaders_callback_atx'), $text); + + return $text; + } + function _doHeaders_attr($attr) { + if (empty($attr)) return ""; + return " id=\"$attr\""; + } + function _doHeaders_callback_setext($matches) { + if ($matches[3] == '-' && preg_match('{^- }', $matches[1])) + return $matches[0]; + $level = $matches[3]{0} == '=' ? 1 : 2; + $attr = $this->_doHeaders_attr($id =& $matches[2]); + $block = "".$this->runSpanGamut($matches[1]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + function _doHeaders_callback_atx($matches) { + $level = strlen($matches[1]); + $attr = $this->_doHeaders_attr($id =& $matches[3]); + $block = "".$this->runSpanGamut($matches[2]).""; + return "\n" . $this->hashBlock($block) . "\n\n"; + } + + + function doTables($text) { + # + # Form HTML tables. + # + $less_than_tab = $this->tab_width - 1; + # + # Find tables with leading pipe. + # + # | Header 1 | Header 2 + # | -------- | -------- + # | Cell 1 | Cell 2 + # | Cell 3 | Cell 4 + # + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + [|] # Optional leading pipe (present) + (.+) \n # $1: Header row (at least one pipe) + + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?> + [ ]* # Allowed whitespace. + [|] .* \n # Row content. + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array(&$this, '_doTable_leadingPipe_callback'), $text); + + # + # Find tables without leading pipe. + # + # Header 1 | Header 2 + # -------- | -------- + # Cell 1 | Cell 2 + # Cell 3 | Cell 4 + # + $text = preg_replace_callback(' + { + ^ # Start of a line + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + (\S.*[|].*) \n # $1: Header row (at least one pipe) + + [ ]{0,'.$less_than_tab.'} # Allowed whitespace. + ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline + + ( # $3: Cells + (?> + .* [|] .* \n # Row content + )* + ) + (?=\n|\Z) # Stop at final double newline. + }xm', + array(&$this, '_DoTable_callback'), $text); + + return $text; + } + function _doTable_leadingPipe_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + # Remove leading pipe for each row. + $content = preg_replace('/^ *[|]/m', '', $content); + + return $this->_doTable_callback(array($matches[0], $head, $underline, $content)); + } + function _doTable_callback($matches) { + $head = $matches[1]; + $underline = $matches[2]; + $content = $matches[3]; + + # Remove any tailing pipes for each line. + $head = preg_replace('/[|] *$/m', '', $head); + $underline = preg_replace('/[|] *$/m', '', $underline); + $content = preg_replace('/[|] *$/m', '', $content); + + # Reading alignement from header underline. + $separators = preg_split('/ *[|] */', $underline); + foreach ($separators as $n => $s) { + if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"'; + else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"'; + else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"'; + else $attr[$n] = ''; + } + + # Parsing span elements, including code spans, character escapes, + # and inline HTML tags, so that pipes inside those gets ignored. + $head = $this->parseSpan($head); + $headers = preg_split('/ *[|] */', $head); + $col_count = count($headers); + + # Write column headers. + $text = "\n"; + $text .= "\n"; + $text .= "\n"; + foreach ($headers as $n => $header) + $text .= " ".$this->runSpanGamut(trim($header))."\n"; + $text .= "\n"; + $text .= "\n"; + + # Split content by row. + $rows = explode("\n", trim($content, "\n")); + + $text .= "\n"; + foreach ($rows as $row) { + # Parsing span elements, including code spans, character escapes, + # and inline HTML tags, so that pipes inside those gets ignored. + $row = $this->parseSpan($row); + + # Split row by cell. + $row_cells = preg_split('/ *[|] */', $row, $col_count); + $row_cells = array_pad($row_cells, $col_count, ''); + + $text .= "\n"; + foreach ($row_cells as $n => $cell) + $text .= " ".$this->runSpanGamut(trim($cell))."\n"; + $text .= "\n"; + } + $text .= "\n"; + $text .= "
    "; + + return $this->hashBlock($text) . "\n"; + } + + + function doDefLists($text) { + # + # Form HTML definition lists. + # + $less_than_tab = $this->tab_width - 1; + + # Re-usable pattern to match any entire dl list: + $whole_list_re = '(?> + ( # $1 = whole list + ( # $2 + [ ]{0,'.$less_than_tab.'} + ((?>.*\S.*\n)+) # $3 = defined term + \n? + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + (?s:.+?) + ( # $4 + \z + | + \n{2,} + (?=\S) + (?! # Negative lookahead for another term + [ ]{0,'.$less_than_tab.'} + (?: \S.*\n )+? # defined term + \n? + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + (?! # Negative lookahead for another definition + [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition + ) + ) + ) + )'; // mx + + $text = preg_replace_callback('{ + (?>\A\n?|(?<=\n\n)) + '.$whole_list_re.' + }mx', + array(&$this, '_doDefLists_callback'), $text); + + return $text; + } + function _doDefLists_callback($matches) { + # Re-usable patterns to match list item bullets and number markers: + $list = $matches[1]; + + # Turn double returns into triple returns, so that we can make a + # paragraph for the last item in a list, if necessary: + $result = trim($this->processDefListItems($list)); + $result = "
    \n" . $result . "\n
    "; + return $this->hashBlock($result) . "\n\n"; + } + + + function processDefListItems($list_str) { + # + # Process the contents of a single definition list, splitting it + # into individual term and definition list items. + # + $less_than_tab = $this->tab_width - 1; + + # trim trailing blank lines: + $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str); + + # Process definition terms. + $list_str = preg_replace_callback('{ + (?>\A\n?|\n\n+) # leading line + ( # definition terms = $1 + [ ]{0,'.$less_than_tab.'} # leading whitespace + (?![:][ ]|[ ]) # negative lookahead for a definition + # mark (colon) or more whitespace. + (?> \S.* \n)+? # actual term (not whitespace). + ) + (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed + # with a definition mark. + }xm', + array(&$this, '_processDefListItems_callback_dt'), $list_str); + + # Process actual definitions. + $list_str = preg_replace_callback('{ + \n(\n+)? # leading line = $1 + ( # marker space = $2 + [ ]{0,'.$less_than_tab.'} # whitespace before colon + [:][ ]+ # definition mark (colon) + ) + ((?s:.+?)) # definition text = $3 + (?= \n+ # stop at next definition mark, + (?: # next term or end of text + [ ]{0,'.$less_than_tab.'} [:][ ] | +
    | \z + ) + ) + }xm', + array(&$this, '_processDefListItems_callback_dd'), $list_str); + + return $list_str; + } + function _processDefListItems_callback_dt($matches) { + $terms = explode("\n", trim($matches[1])); + $text = ''; + foreach ($terms as $term) { + $term = $this->runSpanGamut(trim($term)); + $text .= "\n
    " . $term . "
    "; + } + return $text . "\n"; + } + function _processDefListItems_callback_dd($matches) { + $leading_line = $matches[1]; + $marker_space = $matches[2]; + $def = $matches[3]; + + if ($leading_line || preg_match('/\n{2,}/', $def)) { + # Replace marker with the appropriate whitespace indentation + $def = str_repeat(' ', strlen($marker_space)) . $def; + $def = $this->runBlockGamut($this->outdent($def . "\n\n")); + $def = "\n". $def ."\n"; + } + else { + $def = rtrim($def); + $def = $this->runSpanGamut($this->outdent($def)); + } + + return "\n
    " . $def . "
    \n"; + } + + + function doFencedCodeBlocks($text) { + # + # Adding the fenced code block syntax to regular Markdown: + # + # ~~~ + # Code block + # ~~~ + # + $less_than_tab = $this->tab_width; + + $text = preg_replace_callback('{ + (?:\n|\A) + # 1: Opening marker + ( + ~{3,} # Marker: three tilde or more. + ) + [ ]* \n # Whitespace and newline following marker. + + # 2: Content + ( + (?> + (?!\1 [ ]* \n) # Not a closing marker. + .*\n+ + )+ + ) + + # Closing marker. + \1 [ ]* \n + }xm', + array(&$this, '_doFencedCodeBlocks_callback'), $text); + + return $text; + } + function _doFencedCodeBlocks_callback($matches) { + $codeblock = $matches[2]; + $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES); + $codeblock = preg_replace_callback('/^\n+/', + array(&$this, '_doFencedCodeBlocks_newlines'), $codeblock); + $codeblock = "
    $codeblock
    "; + return "\n\n".$this->hashBlock($codeblock)."\n\n"; + } + function _doFencedCodeBlocks_newlines($matches) { + return str_repeat("empty_element_suffix", + strlen($matches[0])); + } + + + # + # Redefining emphasis markers so that emphasis by underscore does not + # work in the middle of a word. + # + var $em_relist = array( + '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? tags + # + # Strip leading and trailing lines: + $text = preg_replace('/\A\n+|\n+\z/', '', $text); + + $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY); + + # + # Wrap

    tags and unhashify HTML blocks + # + foreach ($grafs as $key => $value) { + $value = trim($this->runSpanGamut($value)); + + # Check if this should be enclosed in a paragraph. + # Clean tag hashes & block tag hashes are left alone. + $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value); + + if ($is_p) { + $value = "

    $value

    "; + } + $grafs[$key] = $value; + } + + # Join grafs in one text, then unhash HTML tags. + $text = implode("\n\n", $grafs); + + # Finish by removing any tag hashes still present in $text. + $text = $this->unhash($text); + + return $text; + } + + + ### Footnotes + + function stripFootnotes($text) { + # + # Strips link definitions from text, stores the URLs and titles in + # hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: [^id]: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1 + [ ]* + \n? # maybe *one* newline + ( # text = $2 (no blank lines allowed) + (?: + .+ # actual text + | + \n # newlines but + (?!\[\^.+?\]:\s)# negative lookahead for footnote marker. + (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed + # by non-indented content + )* + ) + }xm', + array(&$this, '_stripFootnotes_callback'), + $text); + return $text; + } + function _stripFootnotes_callback($matches) { + $note_id = $this->fn_id_prefix . $matches[1]; + $this->footnotes[$note_id] = $this->outdent($matches[2]); + return ''; # String that will replace the block + } + + + function doFootnotes($text) { + # + # Replace footnote references in $text [^id] with a special text-token + # which will be replaced by the actual footnote marker in appendFootnotes. + # + if (!$this->in_anchor) { + $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text); + } + return $text; + } + + + function appendFootnotes($text) { + # + # Append footnote list to text. + # + $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array(&$this, '_appendFootnotes_callback'), $text); + + if (!empty($this->footnotes_ordered)) { + $text .= "\n\n"; + $text .= "
    \n"; + $text .= "empty_element_suffix ."\n"; + $text .= "
      \n\n"; + + $attr = " rev=\"footnote\""; + if ($this->fn_backlink_class != "") { + $class = $this->fn_backlink_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_backlink_title != "") { + $title = $this->fn_backlink_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + $num = 0; + + while (!empty($this->footnotes_ordered)) { + $footnote = reset($this->footnotes_ordered); + $note_id = key($this->footnotes_ordered); + unset($this->footnotes_ordered[$note_id]); + + $footnote .= "\n"; # Need to append newline before parsing. + $footnote = $this->runBlockGamut("$footnote\n"); + $footnote = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}', + array(&$this, '_appendFootnotes_callback'), $footnote); + + $attr = str_replace("%%", ++$num, $attr); + $note_id = $this->encodeAttribute($note_id); + + # Add backlink to last paragraph; create new paragraph if needed. + $backlink = ""; + if (preg_match('{

      $}', $footnote)) { + $footnote = substr($footnote, 0, -4) . " $backlink

      "; + } else { + $footnote .= "\n\n

      $backlink

      "; + } + + $text .= "
    1. \n"; + $text .= $footnote . "\n"; + $text .= "
    2. \n\n"; + } + + $text .= "
    \n"; + $text .= "
    "; + } + return $text; + } + function _appendFootnotes_callback($matches) { + $node_id = $this->fn_id_prefix . $matches[1]; + + # Create footnote marker only if it has a corresponding footnote *and* + # the footnote hasn't been used by another marker. + if (isset($this->footnotes[$node_id])) { + # Transfert footnote content to the ordered list. + $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id]; + unset($this->footnotes[$node_id]); + + $num = $this->footnote_counter++; + $attr = " rel=\"footnote\""; + if ($this->fn_link_class != "") { + $class = $this->fn_link_class; + $class = $this->encodeAttribute($class); + $attr .= " class=\"$class\""; + } + if ($this->fn_link_title != "") { + $title = $this->fn_link_title; + $title = $this->encodeAttribute($title); + $attr .= " title=\"$title\""; + } + + $attr = str_replace("%%", $num, $attr); + $node_id = $this->encodeAttribute($node_id); + + return + "". + "$num". + ""; + } + + return "[^".$matches[1]."]"; + } + + + ### Abbreviations ### + + function stripAbbreviations($text) { + # + # Strips abbreviations from text, stores titles in hash references. + # + $less_than_tab = $this->tab_width - 1; + + # Link defs are in the form: [id]*: url "optional title" + $text = preg_replace_callback('{ + ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1 + (.*) # text = $2 (no blank lines allowed) + }xm', + array(&$this, '_stripAbbreviations_callback'), + $text); + return $text; + } + function _stripAbbreviations_callback($matches) { + $abbr_word = $matches[1]; + $abbr_desc = $matches[2]; + if ($this->abbr_word_re) + $this->abbr_word_re .= '|'; + $this->abbr_word_re .= preg_quote($abbr_word); + $this->abbr_desciptions[$abbr_word] = trim($abbr_desc); + return ''; # String that will replace the block + } + + + function doAbbreviations($text) { + # + # Find defined abbreviations in text and wrap them in elements. + # + if ($this->abbr_word_re) { + // cannot use the /x modifier because abbr_word_re may + // contain significant spaces: + $text = preg_replace_callback('{'. + '(?abbr_word_re.')'. + '(?![\w\x1A])'. + '}', + array(&$this, '_doAbbreviations_callback'), $text); + } + return $text; + } + function _doAbbreviations_callback($matches) { + $abbr = $matches[0]; + if (isset($this->abbr_desciptions[$abbr])) { + $desc = $this->abbr_desciptions[$abbr]; + if (empty($desc)) { + return $this->hashPart("$abbr"); + } else { + $desc = $this->encodeAttribute($desc); + return $this->hashPart("$abbr"); + } + } else { + return $matches[0]; + } + } + +} + + +/* + +PHP Markdown Extra +================== + +Description +----------- + +This is a PHP port of the original Markdown formatter written in Perl +by John Gruber. This special "Extra" version of PHP Markdown features +further enhancements to the syntax for making additional constructs +such as tables and definition list. + +Markdown is a text-to-HTML filter; it translates an easy-to-read / +easy-to-write structured text format into HTML. Markdown's text format +is most similar to that of plain text email, and supports features such +as headers, *emphasis*, code blocks, blockquotes, and links. + +Markdown's syntax is designed not as a generic markup language, but +specifically to serve as a front-end to (X)HTML. You can use span-level +HTML tags anywhere in a Markdown document, and you can use block level +HTML tags (like
    and as well). + +For more information about Markdown's syntax, see: + + + + +Bugs +---- + +To file bug reports please send email to: + + + +Please include with your report: (1) the example input; (2) the output you +expected; (3) the output Markdown actually produced. + + +Version History +--------------- + +See the readme file for detailed release notes for this version. + + +Copyright and License +--------------------- + +PHP Markdown & Extra +Copyright (c) 2004-2009 Michel Fortin + +All rights reserved. + +Based on Markdown +Copyright (c) 2003-2006 John Gruber + +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 "Markdown" nor the names of its contributors may + be used to endorse or promote products derived from this software + without specific prior written permission. + +This software is provided by the copyright holders and contributors "as +is" and any express or implied warranties, including, but not limited +to, the implied warranties of merchantability and fitness for a +particular purpose are disclaimed. In no event shall the copyright owner +or contributors be liable for any direct, indirect, incidental, special, +exemplary, or consequential damages (including, but not limited to, +procurement of substitute goods or services; loss of use, data, or +profits; or business interruption) however caused and on any theory of +liability, whether in contract, strict liability, or tort (including +negligence or otherwise) arising in any way out of the use of this +software, even if advised of the possibility of such damage. + +*/ +?> \ No newline at end of file diff --git a/sources/library/markdownify/LICENSE_LGPL.txt b/sources/library/markdownify/LICENSE_LGPL.txt new file mode 100644 index 00000000..5ab7695a --- /dev/null +++ b/sources/library/markdownify/LICENSE_LGPL.txt @@ -0,0 +1,504 @@ + 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/sources/library/markdownify/TODO b/sources/library/markdownify/TODO new file mode 100644 index 00000000..06ec8508 --- /dev/null +++ b/sources/library/markdownify/TODO @@ -0,0 +1,29 @@ +Markdownify +=========== +* handle non-markdownifiable lists (i.e. `
    • asdf
    `) +* organize methods better (i.e. flushlinebreaks & setlinebreaks close to each other) +* take a look at function names etc. +* is the new (in rev. 93) lastclosedtag property needed? +* word wrapping (some work is done but it's still very buggy) + + +Markdownify Extra +================= + +* handle table alignment with KEEP_HTML=false +* handle tables without headings when KEEP_HTML=false is set +* handle Markdown inside non-markdownable tags + + +Implementation Thoughts +======================= +* non-markdownifiable lists and markdown inside non-markdownable tags as well as the current + table implementation could be rewritten by using a rollback mechanism. + + example: + +
    • asdf
    • asdf
    + + we come to `
    # close table + }sxi'; + } + /** + * handle header tags (

    -

    ) + * + * @param int $level 1-6 + * @return void + */ + function handleHeader($level) { + static $id = null; + if ($this->parser->isStartTag) { + if (isset($this->parser->tagAttributes['id'])) { + $id = $this->parser->tagAttributes['id']; + } + } else { + if (!is_null($id)) { + $this->out(' {#'.$id.'}'); + $id = null; + } + } + parent::handleHeader($level); + } + /** + * handle tags + * + * @param void + * @return void + */ + function handleTag_abbr() { + if ($this->parser->isStartTag) { + $this->stack(); + $this->buffer(); + } else { + $tag = $this->unstack(); + $tag['text'] = $this->unbuffer(); + $add = true; + foreach ($this->stack['abbr'] as $stacked) { + if ($stacked['text'] == $tag['text']) { + /** TODO: differing abbr definitions, i.e. different titles for same text **/ + $add = false; + break; + } + } + $this->out($tag['text']); + if ($add) { + array_push($this->stack['abbr'], $tag); + } + } + } + /** + * flush stacked abbr tags + * + * @param void + * @return void + */ + function flushStacked_abbr() { + $out = array(); + foreach ($this->stack['abbr'] as $k => $tag) { + if (!isset($tag['unstacked'])) { + array_push($out, ' *['.$tag['text'].']: '.$tag['title']); + $tag['unstacked'] = true; + $this->stack['abbr'][$k] = $tag; + } + } + if (!empty($out)) { + $this->out("\n\n".implode("\n", $out)); + } + } + /** + * handle tags + * + * @param void + * @return void + */ + function handleTag_table() { + if ($this->parser->isStartTag) { + # check if upcoming table can be converted + if ($this->keepHTML) { + if (preg_match($this->tableLookaheadHeader, $this->parser->html, $matches)) { + # header seems good, now check body + # get align & number of cols + preg_match_all('##si', $matches[0], $cols); + $regEx = ''; + $i = 1; + $aligns = array(); + foreach ($cols[2] as $align) { + $align = strtolower($align); + array_push($aligns, $align); + if (empty($align)) { + $align = 'left'; # default value + } + $td = '\s+align=("|\')'.$align.'\\'.$i; + $i++; + if ($align == 'left') { + # look for empty align or left + $td = '(?:'.$td.')?'; + } + $td = ''; + $regEx .= $td.$this->tdSubstitute; + } + $regEx = sprintf($this->tableLookaheadBody, $regEx); + if (preg_match($regEx, $this->parser->html, $matches, null, strlen($matches[0]))) { + # this is a markdownable table tag! + $this->table = array( + 'rows' => array(), + 'col_widths' => array(), + 'aligns' => $aligns, + ); + $this->row = 0; + } else { + # non markdownable table + $this->handleTagToText(); + } + } else { + # non markdownable table + $this->handleTagToText(); + } + } else { + $this->table = array( + 'rows' => array(), + 'col_widths' => array(), + 'aligns' => array(), + ); + $this->row = 0; + } + } else { + # finally build the table in Markdown Extra syntax + $separator = array(); + # seperator with correct align identifikators + foreach($this->table['aligns'] as $col => $align) { + if (!$this->keepHTML && !isset($this->table['col_widths'][$col])) { + break; + } + $left = ' '; + $right = ' '; + switch ($align) { + case 'left': + $left = ':'; + break; + case 'center': + $right = ':'; + $left = ':'; + case 'right': + $right = ':'; + break; + } + array_push($separator, $left.str_repeat('-', $this->table['col_widths'][$col]).$right); + } + $separator = '|'.implode('|', $separator).'|'; + + $rows = array(); + # add padding + array_walk_recursive($this->table['rows'], array(&$this, 'alignTdContent')); + $header = array_shift($this->table['rows']); + array_push($rows, '| '.implode(' | ', $header).' |'); + array_push($rows, $separator); + foreach ($this->table['rows'] as $row) { + array_push($rows, '| '.implode(' | ', $row).' |'); + } + $this->out(implode("\n".$this->indent, $rows)); + $this->table = array(); + $this->setLineBreaks(2); + } + } + /** + * properly pad content so it is aligned as whished + * should be used with array_walk_recursive on $this->table['rows'] + * + * @param string &$content + * @param int $col + * @return void + */ + function alignTdContent(&$content, $col) { + switch ($this->table['aligns'][$col]) { + default: + case 'left': + $content .= str_repeat(' ', $this->table['col_widths'][$col] - $this->strlen($content)); + break; + case 'right': + $content = str_repeat(' ', $this->table['col_widths'][$col] - $this->strlen($content)).$content; + break; + case 'center': + $paddingNeeded = $this->table['col_widths'][$col] - $this->strlen($content); + $left = floor($paddingNeeded / 2); + $right = $paddingNeeded - $left; + $content = str_repeat(' ', $left).$content.str_repeat(' ', $right); + break; + } + } + /** + * handle tags + * + * @param void + * @return void + */ + function handleTag_tr() { + if ($this->parser->isStartTag) { + $this->col = -1; + } else { + $this->row++; + } + } + /** + * handle <\/tr>/g, ''); + + 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/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/color_picker.js b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/color_picker.js new file mode 100644 index 00000000..cc891c17 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/color_picker.js @@ -0,0 +1,345 @@ +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':'Alice Blue','#FAEBD7':'Antique White','#00FFFF':'Aqua','#7FFFD4':'Aquamarine','#F0FFFF':'Azure','#F5F5DC':'Beige', + '#FFE4C4':'Bisque','#000000':'Black','#FFEBCD':'Blanched Almond','#0000FF':'Blue','#8A2BE2':'Blue Violet','#A52A2A':'Brown', + '#DEB887':'Burly Wood','#5F9EA0':'Cadet Blue','#7FFF00':'Chartreuse','#D2691E':'Chocolate','#FF7F50':'Coral','#6495ED':'Cornflower Blue', + '#FFF8DC':'Cornsilk','#DC143C':'Crimson','#00FFFF':'Cyan','#00008B':'Dark Blue','#008B8B':'Dark Cyan','#B8860B':'Dark Golden Rod', + '#A9A9A9':'Dark Gray','#A9A9A9':'Dark Grey','#006400':'Dark Green','#BDB76B':'Dark Khaki','#8B008B':'Dark Magenta','#556B2F':'Dark Olive Green', + '#FF8C00':'Darkorange','#9932CC':'Dark Orchid','#8B0000':'Dark Red','#E9967A':'Dark Salmon','#8FBC8F':'Dark Sea Green','#483D8B':'Dark Slate Blue', + '#2F4F4F':'Dark Slate Gray','#2F4F4F':'Dark Slate Grey','#00CED1':'Dark Turquoise','#9400D3':'Dark Violet','#FF1493':'Deep Pink','#00BFFF':'Deep Sky Blue', + '#696969':'Dim Gray','#696969':'Dim Grey','#1E90FF':'Dodger Blue','#B22222':'Fire Brick','#FFFAF0':'Floral White','#228B22':'Forest Green', + '#FF00FF':'Fuchsia','#DCDCDC':'Gainsboro','#F8F8FF':'Ghost White','#FFD700':'Gold','#DAA520':'Golden Rod','#808080':'Gray','#808080':'Grey', + '#008000':'Green','#ADFF2F':'Green Yellow','#F0FFF0':'Honey Dew','#FF69B4':'Hot Pink','#CD5C5C':'Indian Red','#4B0082':'Indigo','#FFFFF0':'Ivory', + '#F0E68C':'Khaki','#E6E6FA':'Lavender','#FFF0F5':'Lavender Blush','#7CFC00':'Lawn Green','#FFFACD':'Lemon Chiffon','#ADD8E6':'Light Blue', + '#F08080':'Light Coral','#E0FFFF':'Light Cyan','#FAFAD2':'Light Golden Rod Yellow','#D3D3D3':'Light Gray','#D3D3D3':'Light Grey','#90EE90':'Light Green', + '#FFB6C1':'Light Pink','#FFA07A':'Light Salmon','#20B2AA':'Light Sea Green','#87CEFA':'Light Sky Blue','#778899':'Light Slate Gray','#778899':'Light Slate Grey', + '#B0C4DE':'Light Steel Blue','#FFFFE0':'Light Yellow','#00FF00':'Lime','#32CD32':'Lime Green','#FAF0E6':'Linen','#FF00FF':'Magenta','#800000':'Maroon', + '#66CDAA':'Medium Aqua Marine','#0000CD':'Medium Blue','#BA55D3':'Medium Orchid','#9370D8':'Medium Purple','#3CB371':'Medium Sea Green','#7B68EE':'Medium Slate Blue', + '#00FA9A':'Medium Spring Green','#48D1CC':'Medium Turquoise','#C71585':'Medium Violet Red','#191970':'Midnight Blue','#F5FFFA':'Mint Cream','#FFE4E1':'Misty Rose','#FFE4B5':'Moccasin', + '#FFDEAD':'Navajo White','#000080':'Navy','#FDF5E6':'Old Lace','#808000':'Olive','#6B8E23':'Olive Drab','#FFA500':'Orange','#FF4500':'Orange Red','#DA70D6':'Orchid', + '#EEE8AA':'Pale Golden Rod','#98FB98':'Pale Green','#AFEEEE':'Pale Turquoise','#D87093':'Pale Violet Red','#FFEFD5':'Papaya Whip','#FFDAB9':'Peach Puff', + '#CD853F':'Peru','#FFC0CB':'Pink','#DDA0DD':'Plum','#B0E0E6':'Powder Blue','#800080':'Purple','#FF0000':'Red','#BC8F8F':'Rosy Brown','#4169E1':'Royal Blue', + '#8B4513':'Saddle Brown','#FA8072':'Salmon','#F4A460':'Sandy Brown','#2E8B57':'Sea Green','#FFF5EE':'Sea Shell','#A0522D':'Sienna','#C0C0C0':'Silver', + '#87CEEB':'Sky Blue','#6A5ACD':'Slate Blue','#708090':'Slate Gray','#708090':'Slate Grey','#FFFAFA':'Snow','#00FF7F':'Spring Green', + '#4682B4':'Steel Blue','#D2B48C':'Tan','#008080':'Teal','#D8BFD8':'Thistle','#FF6347':'Tomato','#40E0D0':'Turquoise','#EE82EE':'Violet', + '#F5DEB3':'Wheat','#FFFFFF':'White','#F5F5F5':'White Smoke','#FFFF00':'Yellow','#9ACD32':'Yellow Green' +}; + +var namedLookup = {}; + +function init() { + var inputColor = convertRGBToHex(tinyMCEPopup.getWindowArg('input_color')), key, value; + + tinyMCEPopup.resizeToInnerSize(); + + generatePicker(); + generateWebColors(); + generateNamedColors(); + + if (inputColor) { + changeFinalColor(inputColor); + + col = convertHexToRGB(inputColor); + + if (col) + updateLight(col.r, col.g, col.b); + } + + for (key in named) { + value = named[key]; + namedLookup[value.replace(/\s+/, '').toLowerCase()] = key.replace(/#/, '').toLowerCase(); + } +} + +function toHexColor(color) { + var matches, red, green, blue, toInt = parseInt; + + function hex(value) { + value = parseInt(value).toString(16); + + return value.length > 1 ? value : '0' + value; // Padd with leading zero + }; + + color = tinymce.trim(color); + color = color.replace(/^[#]/, '').toLowerCase(); // remove leading '#' + color = namedLookup[color] || color; + + matches = /^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/.exec(color); + + if (matches) { + red = toInt(matches[1]); + green = toInt(matches[2]); + blue = toInt(matches[3]); + } else { + matches = /^([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/.exec(color); + + if (matches) { + red = toInt(matches[1], 16); + green = toInt(matches[2], 16); + blue = toInt(matches[3], 16); + } else { + matches = /^([0-9a-f])([0-9a-f])([0-9a-f])$/.exec(color); + + if (matches) { + red = toInt(matches[1] + matches[1], 16); + green = toInt(matches[2] + matches[2], 16); + blue = toInt(matches[3] + matches[3], 16); + } else { + return ''; + } + } + } + + return '#' + hex(red) + hex(green) + hex(blue); +} + +function insertAction() { + var color = document.getElementById("color").value, f = tinyMCEPopup.getWindowArg('func'); + + var hexColor = toHexColor(color); + + if (hexColor === '') { + var text = tinyMCEPopup.editor.getLang('advanced_dlg.invalid_color_value'); + tinyMCEPopup.alert(text + ': ' + color); + } + else { + tinyMCEPopup.restoreSelection(); + + if (f) + f(hexColor); + + tinyMCEPopup.close(); + } +} + +function showColor(color, name) { + if (name) + document.getElementById("colorname").innerHTML = name; + + document.getElementById("preview").style.backgroundColor = color; + document.getElementById("color").value = color.toUpperCase(); +} + +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; + + // TODO: VoiceOver doesn't seem to support legend as a label referenced by labelledby. + h += '
    tags + * + * @param void + * @return void + */ + function handleTag_td() { + if ($this->parser->isStartTag) { + $this->col++; + if (!isset($this->table['col_widths'][$this->col])) { + $this->table['col_widths'][$this->col] = 0; + } + $this->buffer(); + } else { + $buffer = trim($this->unbuffer()); + $this->table['col_widths'][$this->col] = max($this->table['col_widths'][$this->col], $this->strlen($buffer)); + $this->table['rows'][$this->row][$this->col] = $buffer; + } + } + /** + * handle tags + * + * @param void + * @return void + */ + function handleTag_th() { + if (!$this->keepHTML && !isset($this->table['rows'][1]) && !isset($this->table['aligns'][$this->col+1])) { + if (isset($this->parser->tagAttributes['align'])) { + $this->table['aligns'][$this->col+1] = $this->parser->tagAttributes['align']; + } else { + $this->table['aligns'][$this->col+1] = ''; + } + } + $this->handleTag_td(); + } + /** + * handle
    tags + * + * @param void + * @return void + */ + function handleTag_dl() { + if (!$this->parser->isStartTag) { + $this->setLineBreaks(2); + } + } + /** + * handle
    tags + * + * @param void + * @return void + **/ + function handleTag_dt() { + if (!$this->parser->isStartTag) { + $this->setLineBreaks(1); + } + } + /** + * handle
    tags + * + * @param void + * @return void + */ + function handleTag_dd() { + if ($this->parser->isStartTag) { + if (substr(ltrim($this->parser->html), 0, 3) == '

    ') { + # next comes a paragraph, so we'll need an extra line + $this->out("\n".$this->indent); + } elseif (substr($this->output, -2) == "\n\n") { + $this->output = substr($this->output, 0, -1); + } + $this->out(': '); + $this->indent(' ', false); + } else { + # lookahead for next dt + if (substr(ltrim($this->parser->html), 0, 4) == '

    ') { + $this->setLineBreaks(2); + } else { + $this->setLineBreaks(1); + } + $this->indent(' '); + } + } + /** + * handle tags (custom footnote references, see markdownify_extra::parseString()) + * + * @param void + * @return void + */ + function handleTag_fnref() { + $this->out('[^'.$this->parser->tagAttributes['target'].']'); + } + /** + * handle tags (custom footnotes, see markdownify_extra::parseString() + * and markdownify_extra::_makeFootnotes()) + * + * @param void + * @return void + */ + function handleTag_fn() { + if ($this->parser->isStartTag) { + $this->out('[^'.$this->parser->tagAttributes['name'].']:'); + $this->setLineBreaks(1); + } else { + $this->setLineBreaks(2); + } + $this->indent(' '); + } + /** + * handle tag (custom footnotes, see markdownify_extra::parseString() + * and markdownify_extra::_makeFootnotes()) + * + * @param void + * @return void + */ + function handleTag_footnotes() { + if (!$this->parser->isStartTag) { + $this->setLineBreaks(2); + } + } + /** + * parse a HTML string, clean up footnotes prior + * + * @param string $HTML input + * @return string Markdown formatted output + */ + function parseString($html) { + /** TODO: custom markdown-extra options, e.g. titles & classes **/ + # ... + # => + $html = preg_replace('@\s*\s*\d+\s*\s*@Us', '', $html); + #
    + #
    + #
      + # + #
    1. ...
    2. + # ... + # + #
    + #
    + # => + # + # ... + # ... + # + $html = preg_replace_callback('#
    \s*
    \s*
      \s*(.+)\s*
    \s*
    #Us', array(&$this, '_makeFootnotes'), $html); + return parent::parseString($html); + } + /** + * replace HTML representation of footnotes with something more easily parsable + * + * @note this is a callback to be used in parseString() + * + * @param array $matches + * @return string + */ + function _makeFootnotes($matches) { + #
  4. + # ... + #

    + #
  5. + # => ... + # remove footnote link + $fns = preg_replace('@\s*( \s*)?]*>↩\s*@s', '', $matches[1]); + # remove empty paragraph + $fns = preg_replace('@

    \s*

    @s', '', $fns); + #
  6. ...
  7. -> ... + $fns = str_replace('
  8. '; + return preg_replace('#
  9. \s*(?=(?:))#s', '
    $1', $fns); + } +} \ No newline at end of file diff --git a/sources/library/markdownify/parsehtml/parsehtml.php b/sources/library/markdownify/parsehtml/parsehtml.php new file mode 100644 index 00000000..1a8ecacd --- /dev/null +++ b/sources/library/markdownify/parsehtml/parsehtml.php @@ -0,0 +1,618 @@ + etc.) + * + * @var array + */ + var $emptyTags = array( + 'br', + 'hr', + 'input', + 'img', + 'area', + 'link', + 'meta', + 'param', + ); + /** + * tags with preformatted text + * whitespaces wont be touched in them + * + * @var array + */ + var $preformattedTags = array( + 'script', + 'style', + 'pre', + 'code', + ); + /** + * supress HTML tags inside preformatted tags (see above) + * + * @var bool + */ + var $noTagsInCode = false; + /** + * html to be parsed + * + * @var string + */ + var $html = ''; + /** + * node type: + * + * - tag (see isStartTag) + * - text (includes cdata) + * - comment + * - doctype + * - pi (processing instruction) + * + * @var string + */ + var $nodeType = ''; + /** + * current node content, i.e. either a + * simple string (text node), or something like + * + * + * @var string + */ + var $node = ''; + /** + * wether current node is an opening tag () or not () + * set to NULL if current node is not a tag + * NOTE: empty tags (
    ) set this to true as well! + * + * @var bool | null + */ + var $isStartTag = null; + /** + * wether current node is an empty tag (
    ) or not () + * + * @var bool | null + */ + var $isEmptyTag = null; + /** + * tag name + * + * @var string | null + */ + var $tagName = ''; + /** + * attributes of current tag + * + * @var array (attribName=>value) | null + */ + var $tagAttributes = null; + /** + * wether the current tag is a block element + * + * @var bool | null + */ + var $isBlockElement = null; + + /** + * keep whitespace + * + * @var int + */ + var $keepWhitespace = 0; + /** + * list of open tags + * count this to get current depth + * + * @var array + */ + var $openTags = array(); + /** + * list of block elements + * + * @var array + * TODO: what shall we do with and ?! + */ + var $blockElements = array ( + # tag name => is block + # block elements + 'address' => true, + 'blockquote' => true, + 'center' => true, + 'del' => true, + 'dir' => true, + 'div' => true, + 'dl' => true, + 'fieldset' => true, + 'form' => true, + 'h1' => true, + 'h2' => true, + 'h3' => true, + 'h4' => true, + 'h5' => true, + 'h6' => true, + 'hr' => true, + 'ins' => true, + 'isindex' => true, + 'menu' => true, + 'noframes' => true, + 'noscript' => true, + 'ol' => true, + 'p' => true, + 'pre' => true, + 'table' => true, + 'ul' => true, + # set table elements and list items to block as well + 'thead' => true, + 'tbody' => true, + 'tfoot' => true, + 'td' => true, + 'tr' => true, + 'th' => true, + 'li' => true, + 'dd' => true, + 'dt' => true, + # header items and html / body as well + 'html' => true, + 'body' => true, + 'head' => true, + 'meta' => true, + 'link' => true, + 'style' => true, + 'title' => true, + # unfancy media tags, when indented should be rendered as block + 'map' => true, + 'object' => true, + 'param' => true, + 'embed' => true, + 'area' => true, + # inline elements + 'a' => false, + 'abbr' => false, + 'acronym' => false, + 'applet' => false, + 'b' => false, + 'basefont' => false, + 'bdo' => false, + 'big' => false, + 'br' => false, + 'button' => false, + 'cite' => false, + 'code' => false, + 'del' => false, + 'dfn' => false, + 'em' => false, + 'font' => false, + 'i' => false, + 'img' => false, + 'ins' => false, + 'input' => false, + 'iframe' => false, + 'kbd' => false, + 'label' => false, + 'q' => false, + 'samp' => false, + 'script' => false, + 'select' => false, + 'small' => false, + 'span' => false, + 'strong' => false, + 'sub' => false, + 'sup' => false, + 'textarea' => false, + 'tt' => false, + 'var' => false, + ); + /** + * get next node, set $this->html prior! + * + * @param void + * @return bool + */ + function nextNode() { + if (empty($this->html)) { + # we are done with parsing the html string + return false; + } + static $skipWhitespace = true; + if ($this->isStartTag && !$this->isEmptyTag) { + array_push($this->openTags, $this->tagName); + if (in_array($this->tagName, $this->preformattedTags)) { + # dont truncate whitespaces for or
     contents
    +        $this->keepWhitespace++;
    +      }
    +    }
    +
    +    if ($this->html[0] == '<') {
    +      $token = substr($this->html, 0, 9);
    +      if (substr($token, 0, 2) == 'html, '>');
    +        $this->setNode('pi', $pos + 1);
    +        return true;
    +      }
    +      if (substr($token, 0, 4) == '');
    +        if ($pos === false) {
    +          # could not find a closing -->, use next gt instead
    +          # this is firefox' behaviour
    +          $pos = strpos($this->html, '>') + 1;
    +        } else {
    +          $pos += 3;
    +        }
    +        $this->setNode('comment', $pos);
    +
    +        $skipWhitespace = true;
    +        return true;
    +      }
    +      if ($token == 'setNode('doctype', strpos($this->html, '>')+1);
    +
    +        $skipWhitespace = true;
    +        return true;
    +      }
    +      if ($token == 'html = substr($this->html, 9);
    +
    +        $this->setNode('text', strpos($this->html, ']]>')+3);
    +
    +        # remove trailing ]]> and trim
    +        $this->node = substr($this->node, 0, -3);
    +        $this->handleWhitespaces();
    +
    +        $skipWhitespace = true;
    +        return true;
    +      }
    +      if ($this->parseTag()) {
    +        # seems to be a tag
    +        # handle whitespaces
    +        if ($this->isBlockElement) {
    +          $skipWhitespace = true;
    +        } else {
    +          $skipWhitespace = false;
    +        }
    +        return true;
    +      }
    +    }
    +    if ($this->keepWhitespace) {
    +      $skipWhitespace = false;
    +    }
    +    # when we get here it seems to be a text node
    +    $pos = strpos($this->html, '<');
    +    if ($pos === false) {
    +      $pos = strlen($this->html);
    +    }
    +    $this->setNode('text', $pos);
    +    $this->handleWhitespaces();
    +    if ($skipWhitespace && $this->node == ' ') {
    +      return $this->nextNode();
    +    }
    +    $skipWhitespace = false;
    +    return true;
    +  }
    +  /**
    +   * parse tag, set tag name and attributes, see if it's a closing tag and so forth...
    +   *
    +   * @param void
    +   * @return bool
    +   */
    +  function parseTag() {
    +    static $a_ord, $z_ord, $special_ords;
    +    if (!isset($a_ord)) {
    +      $a_ord = ord('a');
    +      $z_ord = ord('z');
    +      $special_ords = array(
    +        ord(':'), // for xml:lang
    +        ord('-'), // for http-equiv
    +      );
    +    }
    +
    +    $tagName = '';
    +
    +    $pos = 1;
    +    $isStartTag = $this->html[$pos] != '/';
    +    if (!$isStartTag) {
    +      $pos++;
    +    }
    +    # get tagName
    +    while (isset($this->html[$pos])) {
    +      $pos_ord = ord(strtolower($this->html[$pos]));
    +      if (($pos_ord >= $a_ord && $pos_ord <= $z_ord) || (!empty($tagName) && is_numeric($this->html[$pos]))) {
    +        $tagName .= $this->html[$pos];
    +        $pos++;
    +      } else {
    +        $pos--;
    +        break;
    +      }
    +    }
    +
    +    $tagName = strtolower($tagName);
    +    if (empty($tagName) || !isset($this->blockElements[$tagName])) {
    +      # something went wrong => invalid tag
    +      $this->invalidTag();
    +      return false;
    +    }
    +    if ($this->noTagsInCode && end($this->openTags) == 'code' && !($tagName == 'code' && !$isStartTag)) {
    +      # we supress all HTML tags inside code tags
    +      $this->invalidTag();
    +      return false;
    +    }
    +
    +    # get tag attributes
    +    /** TODO: in html 4 attributes do not need to be quoted **/
    +    $isEmptyTag = false;
    +    $attributes = array();
    +    $currAttrib = '';
    +    while (isset($this->html[$pos+1])) {
    +      $pos++;
    +      # close tag
    +      if ($this->html[$pos] == '>' || $this->html[$pos].$this->html[$pos+1] == '/>') {
    +        if ($this->html[$pos] == '/') {
    +          $isEmptyTag = true;
    +          $pos++;
    +        }
    +        break;
    +      }
    +
    +      $pos_ord = ord(strtolower($this->html[$pos]));
    +      if ( ($pos_ord >= $a_ord && $pos_ord <= $z_ord) || in_array($pos_ord, $special_ords)) {
    +        # attribute name
    +        $currAttrib .= $this->html[$pos];
    +      } elseif (in_array($this->html[$pos], array(' ', "\t", "\n"))) {
    +        # drop whitespace
    +      } elseif (in_array($this->html[$pos].$this->html[$pos+1], array('="', "='"))) {
    +        # get attribute value
    +        $pos++;
    +        $await = $this->html[$pos]; # single or double quote
    +        $pos++;
    +        $value = '';
    +        while (isset($this->html[$pos]) && $this->html[$pos] != $await) {
    +          $value .= $this->html[$pos];
    +          $pos++;
    +        }
    +        $attributes[$currAttrib] = $value;
    +        $currAttrib = '';
    +      } else {
    +        $this->invalidTag();
    +        return false;
    +      }
    +    }
    +    if ($this->html[$pos] != '>') {
    +      $this->invalidTag();
    +      return false;
    +    }
    +
    +    if (!empty($currAttrib)) {
    +      # html 4 allows something like 
    ' + + ''; + + for (i=0; i' + + ''; + if (tinyMCEPopup.editor.forcedHighContrastMode) { + h += ''; + } + h += ''; + h += ''; + if ((i+1) % 18 == 0) + h += ''; + } + + h += '
    '; + + el.innerHTML = h; + el.className = 'generated'; + + paintCanvas(el); + enableKeyboardNavigation(el.firstChild); +} + +function paintCanvas(el) { + tinyMCEPopup.getWin().tinymce.each(tinyMCEPopup.dom.select('canvas.mceColorSwatch', el), function(canvas) { + var context; + if (canvas.getContext && (context = canvas.getContext("2d"))) { + context.fillStyle = canvas.getAttribute('data-color'); + context.fillRect(0, 0, 10, 10); + } + }); +} +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 += ''; + if (tinyMCEPopup.editor.forcedHighContrastMode) { + h += ''; + } + h += ''; + h += ''; + i++; + } + + el.innerHTML = h; + el.className = 'generated'; + + paintCanvas(el); + enableKeyboardNavigation(el); +} + +function enableKeyboardNavigation(el) { + tinyMCEPopup.editor.windowManager.createInstance('tinymce.ui.KeyboardNavigation', { + root: el, + items: tinyMCEPopup.dom.select('a', el) + }, tinyMCEPopup.dom); +} + +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, pos = tinyMCEPopup.dom.getPos(e.target); + + x = e.offsetX ? e.offsetX : (e.target ? e.clientX - pos.x : 0); + y = e.offsetY ? e.offsetY : (e.target ? e.clientY - pos.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', tinyMCEPopup.getParam('external_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 = typeof(l) === 'function' ? 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.replace(/ /g, '%20'), + 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); + tinyMCEPopup.editor.execCommand('mceRepaint'); + tinyMCEPopup.editor.focus(); + } else { + tinymce.each(args, function(value, name) { + if (value === "") { + delete args[name]; + } + }); + + ed.execCommand('mceInsertContent', false, tinyMCEPopup.editor.dom.createHTML('img', args), {skip_undo : 1}); + ed.undoManager.add(); + } + + tinyMCEPopup.close(); + }, + + updateStyle : function() { + var dom = tinyMCEPopup.dom, st = {}, v, f = document.forms[0]; + + if (tinyMCEPopup.editor.settings.inline_styles) { + tinymce.each(tinyMCEPopup.dom.parseStyle(this.styleVal), function(value, key) { + st[key] = value; + }); + + // 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), 'img'); + this.styleVal = dom.serializeStyle(st, 'img'); + } + }, + + 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/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/link.js b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/link.js new file mode 100644 index 00000000..53ff409e --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/link.js @@ -0,0 +1,153 @@ +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, href = f.href.value.replace(/ /g, '%20'); + + tinyMCEPopup.restoreSelection(); + e = ed.dom.getParent(ed.selection.getNode(), 'A'); + + // Remove element if there is no href + if (!f.href.value) { + if (e) { + b = ed.selection.getBookmark(); + ed.dom.remove(e, 1); + ed.selection.moveToBookmark(b); + tinyMCEPopup.execCommand("mceEndUndoLevel"); + tinyMCEPopup.close(); + return; + } + } + + // Create new anchor elements + if (e == null) { + ed.getDoc().execCommand("unlink", false, null); + tinyMCEPopup.execCommand("mceInsertLink", 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 : href, + title : f.linktitle.value, + target : f.target_list ? getSelectValue(f, "target_list") : null, + 'class' : f.class_list ? getSelectValue(f, "class_list") : null + }); + } + }); + } else { + ed.dom.setAttribs(e, { + href : href, + title : f.linktitle.value, + target : f.target_list ? getSelectValue(f, "target_list") : null, + 'class' : f.class_list ? getSelectValue(f, "class_list") : 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/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/source_editor.js b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/source_editor.js new file mode 100644 index 00000000..dd5e366f --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/js/source_editor.js @@ -0,0 +1,78 @@ +tinyMCEPopup.requireLangPack(); +tinyMCEPopup.onInit.add(onLoadInit); + +function saveContent() { + tinyMCEPopup.editor.setContent(document.getElementById('htmlSource').value, {source_view : true}); + 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({source_view : true}); + + if (tinyMCEPopup.editor.getParam("theme_advanced_source_editor_wrap", true)) { + turnWrapOn(); + 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 setWhiteSpaceCss(value) { + var el = document.getElementById('htmlSource'); + tinymce.DOM.setStyle(el, 'white-space', value); +} + +function turnWrapOff() { + if (tinymce.isWebKit) { + setWhiteSpaceCss('pre'); + } else { + setWrap('off'); + } +} + +function turnWrapOn() { + if (tinymce.isWebKit) { + setWhiteSpaceCss('pre-wrap'); + } else { + setWrap('soft'); + } +} + +function toggleWordWrap(elm) { + if (elm.checked) { + turnWrapOn(); + } else { + turnWrapOff(); + } +} + +function resizeInputs() { + var vp = tinyMCEPopup.dom.getViewPort(window), el; + + el = document.getElementById('htmlSource'); + + if (el) { + el.style.width = (vp.w - 20) + 'px'; + el.style.height = (vp.h - 65) + 'px'; + } +} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en.js b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en.js new file mode 100644 index 00000000..6e584818 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en.js @@ -0,0 +1 @@ +tinyMCE.addI18n('en.advanced',{"underline_desc":"Underline (Ctrl+U)","italic_desc":"Italic (Ctrl+I)","bold_desc":"Bold (Ctrl+B)",dd:"Definition Description",dt:"Definition Term ",samp:"Code Sample",code:"Code",blockquote:"Block Quote",h6:"Heading 6",h5:"Heading 5",h4:"Heading 4",h3:"Heading 3",h2:"Heading 2",h1:"Heading 1",pre:"Preformatted",address:"Address",div:"DIV",paragraph:"Paragraph",block:"Format",fontdefault:"Font Family","font_size":"Font Size","style_select":"Styles","anchor_delta_height":"","anchor_delta_width":"","charmap_delta_height":"","charmap_delta_width":"","colorpicker_delta_height":"","colorpicker_delta_width":"","link_delta_height":"","link_delta_width":"","image_delta_height":"","image_delta_width":"","more_colors":"More Colors...","toolbar_focus":"Jump to tool buttons - Alt+Q, Jump to editor - Alt-Z, Jump to element path - Alt-X",newdocument:"Are you sure you want clear all contents?",path:"Path","clipboard_msg":"Copy/Cut/Paste is not available in Mozilla and Firefox.\nDo you want more information about this issue?","blockquote_desc":"Block Quote","help_desc":"Help","newdocument_desc":"New Document","image_props_desc":"Image Properties","paste_desc":"Paste (Ctrl+V)","copy_desc":"Copy (Ctrl+C)","cut_desc":"Cut (Ctrl+X)","anchor_desc":"Insert/Edit Anchor","visualaid_desc":"show/Hide Guidelines/Invisible Elements","charmap_desc":"Insert Special Character","backcolor_desc":"Select Background Color","forecolor_desc":"Select Text Color","custom1_desc":"Your Custom Description Here","removeformat_desc":"Remove Formatting","hr_desc":"Insert Horizontal Line","sup_desc":"Superscript","sub_desc":"Subscript","code_desc":"Edit HTML Source","cleanup_desc":"Cleanup Messy Code","image_desc":"Insert/Edit Image","unlink_desc":"Unlink","link_desc":"Insert/Edit Link","redo_desc":"Redo (Ctrl+Y)","undo_desc":"Undo (Ctrl+Z)","indent_desc":"Increase Indent","outdent_desc":"Decrease Indent","numlist_desc":"Insert/Remove Numbered List","bullist_desc":"Insert/Remove Bulleted List","justifyfull_desc":"Align Full","justifyright_desc":"Align Right","justifycenter_desc":"Align Center","justifyleft_desc":"Align Left","striketrough_desc":"Strikethrough","help_shortcut":"Press ALT-F10 for toolbar. Press ALT-0 for help","rich_text_area":"Rich Text Area","shortcuts_desc":"Accessability Help",toolbar:"Toolbar"}); \ No newline at end of file diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en_dlg.js b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en_dlg.js new file mode 100644 index 00000000..50cd87e3 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/langs/en_dlg.js @@ -0,0 +1 @@ +tinyMCE.addI18n('en.advanced_dlg', {"link_list":"Link List","link_is_external":"The URL you entered seems to be an external link. Do you want to add the required http:// prefix?","link_is_email":"The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?","link_titlefield":"Title","link_target_blank":"Open Link in a New Window","link_target_same":"Open Link in the Same Window","link_target":"Target","link_url":"Link URL","link_title":"Insert/Edit Link","image_align_right":"Right","image_align_left":"Left","image_align_textbottom":"Text Bottom","image_align_texttop":"Text Top","image_align_bottom":"Bottom","image_align_middle":"Middle","image_align_top":"Top","image_align_baseline":"Baseline","image_align":"Alignment","image_hspace":"Horizontal Space","image_vspace":"Vertical Space","image_dimensions":"Dimensions","image_alt":"Image Description","image_list":"Image List","image_border":"Border","image_src":"Image URL","image_title":"Insert/Edit Image","charmap_title":"Select Special Character", "charmap_usage":"Use left and right arrows to navigate.","colorpicker_name":"Name:","colorpicker_color":"Color:","colorpicker_named_title":"Named Colors","colorpicker_named_tab":"Named","colorpicker_palette_title":"Palette Colors","colorpicker_palette_tab":"Palette","colorpicker_picker_title":"Color Picker","colorpicker_picker_tab":"Picker","colorpicker_title":"Select a Color","code_wordwrap":"Word Wrap","code_title":"HTML Source Editor","anchor_name":"Anchor Name","anchor_title":"Insert/Edit Anchor","about_loaded":"Loaded Plugins","about_version":"Version","about_author":"Author","about_plugin":"Plugin","about_plugins":"Plugins","about_license":"License","about_help":"Help","about_general":"About","about_title":"About TinyMCE","anchor_invalid":"Please specify a valid anchor name.","accessibility_help":"Accessibility Help","accessibility_usage_title":"General Usage","invalid_color_value":"Invalid color value","":""}); diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/link.htm b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/link.htm new file mode 100644 index 00000000..5d9dea9b --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/link.htm @@ -0,0 +1,57 @@ + + + + {#advanced_dlg.link_title} + + + + + + + +
    + + +
    +
    + + + + + + + + + + + + + + + + + + + + + +
    + + + + +
     
    +
    +
    + +
    + + +
    +
    + + diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/shortcuts.htm b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/shortcuts.htm new file mode 100644 index 00000000..20ec2f5a --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/shortcuts.htm @@ -0,0 +1,47 @@ + + + + {#advanced_dlg.accessibility_help} + + + + +

    {#advanced_dlg.accessibility_usage_title}

    +

    Toolbars

    +

    Press ALT-F10 to move focus to the toolbars. Navigate through the buttons using the arrow keys. + Press enter to activate a button and return focus to the editor. + Press escape to return focus to the editor without performing any actions.

    + +

    Status Bar

    +

    To access the editor status bar, press ALT-F11. Use the left and right arrow keys to navigate between elements in the path. + Press enter or space to select an element. Press escape to return focus to the editor without changing the selection.

    + +

    Context Menu

    +

    Press shift-F10 to activate the context menu. Use the up and down arrow keys to move between menu items. To open sub-menus press the right arrow key. + To close submenus press the left arrow key. Press escape to close the context menu.

    + +

    Keyboard Shortcuts

    + + + + + + + + + + + + + + + + + + + + + +
    KeystrokeFunction
    Control-BBold
    Control-IItalic
    Control-ZUndo
    Control-YRedo
    + + diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/content.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/content.css new file mode 100644 index 00000000..52a1d67e --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/content.css @@ -0,0 +1,51 @@ +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;} +body.mceBrowserDefaults {background:transparent; color:inherit; font-size:inherit; font-family:inherit;} +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 {display:inline-block; -webkit-user-select:all; -webkit-user-modify:read-only; -moz-user-select:all; -moz-user-modify:read-only; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat center center} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table, img, hr, .mceItemAnchor {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 {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; +} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} +*[contentEditable]:focus {outline:0} + +.mceItemMedia {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)} +.mceItemVideo {background-image:url(../../img/video.gif)} +.mceItemAudio {background-image:url(../../img/video.gif)} +.mceItemEmbeddedAudio {background-image:url(../../img/video.gif)} +.mceItemIframe {background-image:url(../../img/iframe.gif)} +.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;} +.mceHideBrInPre pre br {display: none} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/dialog.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/dialog.css new file mode 100644 index 00000000..f0122265 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/dialog.css @@ -0,0 +1,117 @@ +/* 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;} +.nowrap {white-space: nowrap} + +/* 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; +float:left; +} + +#insert {background:url(img/buttons.png) 0 -52px} +#cancel {background:url(img/buttons.png) 0 0; float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +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;} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/buttons.png b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/buttons.png new file mode 100644 index 00000000..1e53560e Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/buttons.png differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/items.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/items.gif new file mode 100644 index 00000000..d2f93671 Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/items.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif new file mode 100644 index 00000000..85e31dfb Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_arrow.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_check.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_check.gif new file mode 100644 index 00000000..adfdddcc Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/menu_check.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/progress.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/progress.gif new file mode 100644 index 00000000..5bb90fd6 Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/progress.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/tabs.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/tabs.gif new file mode 100644 index 00000000..06812cb4 Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/img/tabs.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css new file mode 100644 index 00000000..5f1f9644 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/default/ui.css @@ -0,0 +1,213 @@ +/* Reset */ +.defaultSkin table, .defaultSkin tbody, .defaultSkin a, .defaultSkin img, .defaultSkin tr, .defaultSkin div, .defaultSkin td, .defaultSkin iframe, .defaultSkin span, .defaultSkin *, .defaultSkin .mceText {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000; vertical-align:baseline; width:auto; border-collapse:separate; text-align:left} +.defaultSkin a:hover, .defaultSkin a:link, .defaultSkin a:visited, .defaultSkin a:active {text-decoration:none; font-weight:normal; cursor:default; color:#000} +.defaultSkin table td {vertical-align:middle} + +/* Containers */ +.defaultSkin table {direction:ltr; background:#FFF} +.defaultSkin iframe {display:block; background:#FFF} +.defaultSkin .mceToolbar {height:26px} +.defaultSkin .mceLeft {text-align:left} +.defaultSkin .mceRight {text-align:right} + +/* External */ +.defaultSkin .mceExternalToolbar {position:absolute; border:2px solid #CCC; border-bottom:0; display:none;} +.defaultSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.defaultSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px; background:url(../../img/icons.gif) -820px 0} + +/* Layout */ +.defaultSkin table.mceLayout {border:0; border-left:1px solid #CCC; border-right:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceFirst td {border-top:1px solid #CCC} +.defaultSkin table.mceLayout tr.mceLast td {border-bottom:1px solid #CCC} +.defaultSkin table.mceToolbar, .defaultSkin tr.mceFirst .mceToolbar tr td, .defaultSkin tr.mceLast .mceToolbar tr td {border:0; margin:0; padding:0;} +.defaultSkin td.mceToolbar {padding-top:1px; vertical-align:top} +.defaultSkin .mceIframeContainer { /*border-top:1px solid #CCC; border-bottom:1px solid #CCC */ border: none;} +.defaultSkin .mceStatusbar {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:9pt; line-height:16px; overflow:visible; color:#000; display:block; height:20px} +.defaultSkin .mceStatusbar div {float:left; margin:2px} +.defaultSkin .mceStatusbar a.mceResize {display:block; float:right; background:url(../../img/icons.gif) -800px 0; width:20px; height:20px; cursor:se-resize; outline:0} +.defaultSkin .mceStatusbar a:hover {text-decoration:underline} +.defaultSkin table.mceToolbar {margin-left:3px} +.defaultSkin span.mceIcon, .defaultSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} +.defaultSkin td.mceCenter {text-align:center;} +.defaultSkin td.mceCenter table {margin:0 auto; text-align:left;} +.defaultSkin td.mceRight table {margin:0 0 0 auto;} + +/* Button */ +.defaultSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px; margin-right:10px} +.defaultSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSkin a.mceButtonActive, .defaultSkin a.mceButtonSelected {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceButtonDisabled .mceIcon {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.defaultSkin .mceButtonLabeled {width:auto} +.defaultSkin .mceButtonLabeled span.mceIcon {float:left} +.defaultSkin span.mceButtonLabel {display:block; font-size:10px; padding:4px 6px 0 22px; font-family:Tahoma,Verdana,Arial,Helvetica} +.defaultSkin .mceButtonDisabled .mceButtonLabel {color:#888} + +/* Separator */ +.defaultSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:2px 2px 0 4px} + +/* ListBox */ +.defaultSkin .mceListBox, .defaultSkin .mceListBox a {display:block} +.defaultSkin .mceListBox .mceText {padding-left:4px; width:70px; text-align:left; border:1px solid #CCC; border-right:0; background:#FFF; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; height:20px; line-height:20px; overflow:hidden} +.defaultSkin .mceListBox .mceOpen {width:9px; height:20px; background:url(../../img/icons.gif) -741px 0; margin-right:2px; border:1px solid #CCC;} +.defaultSkin table.mceListBoxEnabled:hover .mceText, .defaultSkin .mceListBoxHover .mceText, .defaultSkin .mceListBoxSelected .mceText {border:1px solid #A2ABC0; border-right:0; background:#FFF} +.defaultSkin table.mceListBoxEnabled:hover .mceOpen, .defaultSkin .mceListBoxHover .mceOpen, .defaultSkin .mceListBoxSelected .mceOpen {background-color:#FFF; border:1px solid #A2ABC0} +.defaultSkin .mceListBoxDisabled a.mceText {color:gray; background-color:transparent;} +.defaultSkin .mceListBoxMenu {overflow:auto; overflow-x:hidden} +.defaultSkin .mceOldBoxModel .mceListBox .mceText {height:22px} +.defaultSkin .mceOldBoxModel .mceListBox .mceOpen {width:11px; height:22px;} +.defaultSkin select.mceNativeListBox {font-family:'MS Sans Serif',sans-serif,Verdana,Arial; font-size:7pt; background:#F0F0EE; border:1px solid gray; margin-right:2px;} + +/* SplitButton */ +.defaultSkin .mceSplitButton {width:32px; height:20px; direction:ltr} +.defaultSkin .mceSplitButton a, .defaultSkin .mceSplitButton span {height:20px; display:block} +.defaultSkin .mceSplitButton a.mceAction {width:20px; border:1px solid #F0F0EE; border-right:0;} +.defaultSkin .mceSplitButton span.mceAction {width:20px; background-image:url(../../img/icons.gif);} +.defaultSkin .mceSplitButton a.mceOpen {width:9px; background:url(../../img/icons.gif) -741px 0; border:1px solid #F0F0EE;} +.defaultSkin .mceSplitButton span.mceOpen {display:none} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceAction, .defaultSkin .mceSplitButtonHover a.mceAction, .defaultSkin .mceSplitButtonSelected a.mceAction {border:1px solid #0A246A; border-right:0; background-color:#B2BBD0} +.defaultSkin table.mceSplitButtonEnabled:hover a.mceOpen, .defaultSkin .mceSplitButtonHover a.mceOpen, .defaultSkin .mceSplitButtonSelected a.mceOpen {background-color:#B2BBD0; border:1px solid #0A246A;} +.defaultSkin .mceSplitButtonDisabled .mceAction, .defaultSkin .mceSplitButtonDisabled a.mceOpen {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} +.defaultSkin .mceSplitButtonActive a.mceAction {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSkin .mceSplitButtonActive a.mceOpen {border-left:0;} + +/* ColorSplitButton */ +.defaultSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid gray} +.defaultSkin .mceColorSplitMenu td {padding:2px} +.defaultSkin .mceColorSplitMenu a {display:block; width:9px; height:9px; overflow:hidden; border:1px solid #808080} +.defaultSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.defaultSkin .mceColorSplitMenu a.mceMoreColors {width:100%; height:auto; text-align:center; font-family:Tahoma,Verdana,Arial,Helvetica; font-size:11px; line-height:20px; border:1px solid #FFF} +.defaultSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid #0A246A; background-color:#B6BDD2} +.defaultSkin a.mceMoreColors:hover {border:1px solid #0A246A} +.defaultSkin .mceColorPreview {margin-left:2px; width:16px; height:4px; overflow:hidden; background:#9a9b9a} +.defaultSkin .mce_forecolor span.mceAction, .defaultSkin .mce_backcolor span.mceAction {overflow:hidden; height:16px} + +/* Menu */ +.defaultSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid #D4D0C8} +.defaultSkin .mceNoIcons span.mceIcon {width:0;} +.defaultSkin .mceNoIcons a .mceText {padding-left:10px} +.defaultSkin .mceMenu table {background:#FFF} +.defaultSkin .mceMenu a, .defaultSkin .mceMenu span, .defaultSkin .mceMenu {display:block} +.defaultSkin .mceMenu td {height:20px} +.defaultSkin .mceMenu a {position:relative;padding:3px 0 4px 0} +.defaultSkin .mceMenu .mceText {position:relative; display:block; font-family:Tahoma,Verdana,Arial,Helvetica; color:#000; cursor:default; margin:0; padding:0 25px 0 25px; display:block} +.defaultSkin .mceMenu span.mceText, .defaultSkin .mceMenu .mcePreview {font-size:11px} +.defaultSkin .mceMenu pre.mceText {font-family:Monospace} +.defaultSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:22px;} +.defaultSkin .mceMenu .mceMenuItemEnabled a:hover, .defaultSkin .mceMenu .mceMenuItemActive {background-color:#dbecf3} +.defaultSkin td.mceMenuItemSeparator {background:#DDD; height:1px} +.defaultSkin .mceMenuItemTitle a {border:0; background:#EEE; border-bottom:1px solid #DDD} +.defaultSkin .mceMenuItemTitle span.mceText {color:#000; font-weight:bold; padding-left:4px} +.defaultSkin .mceMenuItemDisabled .mceText {color:#888} +.defaultSkin .mceMenuItemSelected .mceIcon {background:url(img/menu_check.gif)} +.defaultSkin .mceNoIcons .mceMenuItemSelected a {background:url(img/menu_arrow.gif) no-repeat -6px center} +.defaultSkin .mceMenu span.mceMenuLine {display:none} +.defaultSkin .mceMenuItemSub a {background:url(img/menu_arrow.gif) no-repeat top right;} + +/* Progress,Resize */ +.defaultSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=50)'; filter:alpha(opacity=50); background:#FFF} +.defaultSkin .mceProgress {position:absolute; left:0; top:0; z-index:1001; background:url(img/progress.gif) no-repeat; width:32px; height:32px; margin:-16px 0 0 -16px} + +/* Formats */ +.defaultSkin .mce_formatPreview a {font-size:10px} +.defaultSkin .mce_p span.mceText {} +.defaultSkin .mce_address span.mceText {font-style:italic} +.defaultSkin .mce_pre span.mceText {font-family:monospace} +.defaultSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.defaultSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.defaultSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.defaultSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.defaultSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.defaultSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} + +/* Theme */ +.defaultSkin span.mce_bold {background-position:0 0} +.defaultSkin span.mce_italic {background-position:-60px 0} +.defaultSkin span.mce_underline {background-position:-140px 0} +.defaultSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSkin span.mce_undo {background-position:-160px 0} +.defaultSkin span.mce_redo {background-position:-100px 0} +.defaultSkin span.mce_cleanup {background-position:-40px 0} +.defaultSkin span.mce_bullist {background-position:-20px 0} +.defaultSkin span.mce_numlist {background-position:-80px 0} +.defaultSkin span.mce_justifyleft {background-position:-460px 0} +.defaultSkin span.mce_justifyright {background-position:-480px 0} +.defaultSkin span.mce_justifycenter {background-position:-420px 0} +.defaultSkin span.mce_justifyfull {background-position:-440px 0} +.defaultSkin span.mce_anchor {background-position:-200px 0} +.defaultSkin span.mce_indent {background-position:-400px 0} +.defaultSkin span.mce_outdent {background-position:-540px 0} +.defaultSkin span.mce_link {background-position:-500px 0} +.defaultSkin span.mce_unlink {background-position:-640px 0} +.defaultSkin span.mce_sub {background-position:-600px 0} +.defaultSkin span.mce_sup {background-position:-620px 0} +.defaultSkin span.mce_removeformat {background-position:-580px 0} +.defaultSkin span.mce_newdocument {background-position:-520px 0} +.defaultSkin span.mce_image {background-position:-380px 0} +.defaultSkin span.mce_help {background-position:-340px 0} +.defaultSkin span.mce_code {background-position:-260px 0} +.defaultSkin span.mce_hr {background-position:-360px 0} +.defaultSkin span.mce_visualaid {background-position:-660px 0} +.defaultSkin span.mce_charmap {background-position:-240px 0} +.defaultSkin span.mce_paste {background-position:-560px 0} +.defaultSkin span.mce_copy {background-position:-700px 0} +.defaultSkin span.mce_cut {background-position:-680px 0} +.defaultSkin span.mce_blockquote {background-position:-220px 0} +.defaultSkin .mce_forecolor span.mceAction {background-position:-720px 0} +.defaultSkin .mce_backcolor span.mceAction {background-position:-760px 0} +.defaultSkin span.mce_forecolorpicker {background-position:-720px 0} +.defaultSkin span.mce_backcolorpicker {background-position:-760px 0} + +/* Plugins */ +.defaultSkin span.mce_advhr {background-position:-0px -20px} +.defaultSkin span.mce_ltr {background-position:-20px -20px} +.defaultSkin span.mce_rtl {background-position:-40px -20px} +.defaultSkin span.mce_emotions {background-position:-60px -20px} +.defaultSkin span.mce_fullpage {background-position:-80px -20px} +.defaultSkin span.mce_fullscreen {background-position:-100px -20px} +.defaultSkin span.mce_iespell {background-position:-120px -20px} +.defaultSkin span.mce_insertdate {background-position:-140px -20px} +.defaultSkin span.mce_inserttime {background-position:-160px -20px} +.defaultSkin span.mce_absolute {background-position:-180px -20px} +.defaultSkin span.mce_backward {background-position:-200px -20px} +.defaultSkin span.mce_forward {background-position:-220px -20px} +.defaultSkin span.mce_insert_layer {background-position:-240px -20px} +.defaultSkin span.mce_insertlayer {background-position:-260px -20px} +.defaultSkin span.mce_movebackward {background-position:-280px -20px} +.defaultSkin span.mce_moveforward {background-position:-300px -20px} +.defaultSkin span.mce_media {background-position:-320px -20px} +.defaultSkin span.mce_nonbreaking {background-position:-340px -20px} +.defaultSkin span.mce_pastetext {background-position:-360px -20px} +.defaultSkin span.mce_pasteword {background-position:-380px -20px} +.defaultSkin span.mce_selectall {background-position:-400px -20px} +.defaultSkin span.mce_preview {background-position:-420px -20px} +.defaultSkin span.mce_print {background-position:-440px -20px} +.defaultSkin span.mce_cancel {background-position:-460px -20px} +.defaultSkin span.mce_save {background-position:-480px -20px} +.defaultSkin span.mce_replace {background-position:-500px -20px} +.defaultSkin span.mce_search {background-position:-520px -20px} +.defaultSkin span.mce_styleprops {background-position:-560px -20px} +.defaultSkin span.mce_table {background-position:-580px -20px} +.defaultSkin span.mce_cell_props {background-position:-600px -20px} +.defaultSkin span.mce_delete_table {background-position:-620px -20px} +.defaultSkin span.mce_delete_col {background-position:-640px -20px} +.defaultSkin span.mce_delete_row {background-position:-660px -20px} +.defaultSkin span.mce_col_after {background-position:-680px -20px} +.defaultSkin span.mce_col_before {background-position:-700px -20px} +.defaultSkin span.mce_row_after {background-position:-720px -20px} +.defaultSkin span.mce_row_before {background-position:-740px -20px} +.defaultSkin span.mce_merge_cells {background-position:-760px -20px} +.defaultSkin span.mce_table_props {background-position:-980px -20px} +.defaultSkin span.mce_row_props {background-position:-780px -20px} +.defaultSkin span.mce_split_cells {background-position:-800px -20px} +.defaultSkin span.mce_template {background-position:-820px -20px} +.defaultSkin span.mce_visualchars {background-position:-840px -20px} +.defaultSkin span.mce_abbr {background-position:-860px -20px} +.defaultSkin span.mce_acronym {background-position:-880px -20px} +.defaultSkin span.mce_attribs {background-position:-900px -20px} +.defaultSkin span.mce_cite {background-position:-920px -20px} +.defaultSkin span.mce_del {background-position:-940px -20px} +.defaultSkin span.mce_ins {background-position:-960px -20px} +.defaultSkin span.mce_pagebreak {background-position:0 -40px} +.defaultSkin span.mce_restoredraft {background-position:-20px -40px} +.defaultSkin span.mce_spellchecker {background-position:-540px -20px} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/content.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/content.css new file mode 100644 index 00000000..fe09e214 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/content.css @@ -0,0 +1,25 @@ +body, td, pre { margin:8px;} +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 {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table, img, hr, .mceItemAnchor {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 {border-bottom:1px dashed #CCC; cursor:help} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} +*[contentEditable]:focus {outline:0} +.mceHideBrInPre pre br {display: none} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/dialog.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/dialog.css new file mode 100644 index 00000000..6d9fc8dd --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/dialog.css @@ -0,0 +1,106 @@ +/* Generic */ +body { +font-family:Verdana, Arial, Helvetica, sans-serif; font-size:11px; +background:#F0F0EE; +color: black; +padding:0; +margin:8px 8px 0 8px; +} + +html {background:#F0F0EE; color:#000;} +td {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +textarea {resize:none;outline:none;} +a:link, a:visited {color:black;background-color:transparent;} +a:hover {color:#2B6FB6;background-color:transparent;} +.nowrap {white-space: nowrap} + +/* 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;background-color:transparent;} +input.invalid {border:1px solid #EE0000;background-color:transparent;} +input {background:#FFF; border:1px solid #CCC;color:black;} +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 { +font-weight:bold; +width:94px; height:23px; +cursor:pointer; +padding-bottom:2px; +float:left; +} + +#cancel {float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +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;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; border: 1px solid black; border-bottom:0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block; cursor:pointer;} +.tabs li.current {font-weight: bold; margin-right:2px;} +.tabs span {float:left; display:block; padding:0px 10px 0 0;} +.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; 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 {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px} +#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline} +#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap} +#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 .panel_wrapper div.current {height:175px;} +#colorpicker #namedcolors {width:150px;} +#colorpicker #namedcolors a {display:block; float:left; width:10px; height:10px; margin:1px 1px 0 0; overflow:hidden;} +#colorpicker #colornamecontainer {margin-top:5px;} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/ui.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/ui.css new file mode 100644 index 00000000..effbbe15 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/highcontrast/ui.css @@ -0,0 +1,106 @@ +/* Reset */ +.highcontrastSkin table, .highcontrastSkin tbody, .highcontrastSkin a, .highcontrastSkin img, .highcontrastSkin tr, .highcontrastSkin div, .highcontrastSkin td, .highcontrastSkin iframe, .highcontrastSkin span, .highcontrastSkin *, .highcontrastSkin .mceText {border:0; margin:0; padding:0; vertical-align:baseline; border-collapse:separate;} +.highcontrastSkin a:hover, .highcontrastSkin a:link, .highcontrastSkin a:visited, .highcontrastSkin a:active {text-decoration:none; font-weight:normal; cursor:default;} +.highcontrastSkin table td {vertical-align:middle} + +.highcontrastSkin .mceIconOnly {display: block !important;} + +/* External */ +.highcontrastSkin .mceExternalToolbar {position:absolute; border:1px solid; border-bottom:0; display:none; background-color: white;} +.highcontrastSkin .mceExternalToolbar td.mceToolbar {padding-right:13px;} +.highcontrastSkin .mceExternalClose {position:absolute; top:3px; right:3px; width:7px; height:7px;} + +/* Layout */ +.highcontrastSkin table.mceLayout {border: 1px solid;} +.highcontrastSkin .mceIframeContainer {border-top:1px solid; border-bottom:1px solid} +.highcontrastSkin .mceStatusbar a:hover {text-decoration:underline} +.highcontrastSkin .mceStatusbar {display:block; line-height:1.5em; overflow:visible;} +.highcontrastSkin .mceStatusbar div {float:left} +.highcontrastSkin .mceStatusbar a.mceResize {display:block; float:right; width:20px; height:20px; cursor:se-resize; outline:0} + +.highcontrastSkin .mceToolbar td { display: inline-block; float: left;} +.highcontrastSkin .mceToolbar tr { display: block;} +.highcontrastSkin .mceToolbar table { display: block; } + +/* Button */ + +.highcontrastSkin .mceButton { display:block; margin: 2px; padding: 5px 10px;border: 1px solid; border-radius: 3px; -moz-border-radius: 3px; -webkit-border-radius: 3px; -ms-border-radius: 3px; height: 2em;} +.highcontrastSkin .mceButton .mceVoiceLabel { height: 100%; vertical-align: center; line-height: 2em} +.highcontrastSkin .mceButtonDisabled .mceVoiceLabel { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);} +.highcontrastSkin .mceButtonActive, .highcontrastSkin .mceButton:focus, .highcontrastSkin .mceButton:active { border: 5px solid; padding: 1px 6px;-webkit-focus-ring-color:none;outline:none;} + +/* Separator */ +.highcontrastSkin .mceSeparator {display:block; width:16px; height:26px;} + +/* ListBox */ +.highcontrastSkin .mceListBox { display: block; margin:2px;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceListBox .mceText {padding: 5px 6px; line-height: 2em; width: 15ex; overflow: hidden;} +.highcontrastSkin .mceListBoxDisabled .mceText { opacity:0.6; -ms-filter:'alpha(opacity=60)'; filter:alpha(opacity=60);} +.highcontrastSkin .mceListBox a.mceText { padding: 5px 10px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;} +.highcontrastSkin .mceListBox a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-left: 0; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;} +.highcontrastSkin .mceListBox:focus a.mceText, .highcontrastSkin .mceListBox:active a.mceText { border-width: 5px; padding: 1px 10px 1px 6px;} +.highcontrastSkin .mceListBox:focus a.mceOpen, .highcontrastSkin .mceListBox:active a.mceOpen { border-width: 5px; padding: 1px 0px 1px 4px;} + +.highcontrastSkin .mceListBoxMenu {overflow-y:auto} + +/* SplitButton */ +.highcontrastSkin .mceSplitButtonDisabled .mceAction {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} + +.highcontrastSkin .mceSplitButton { border-collapse: collapse; margin: 2px; height: 2em; line-height: 2em;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceSplitButton td { display: table-cell; float: none; margin: 0; padding: 0; height: 2em;} +.highcontrastSkin .mceSplitButton tr { display: table-row; } +.highcontrastSkin table.mceSplitButton { display: table; } +.highcontrastSkin .mceSplitButton a.mceAction { padding: 5px 10px; display: block; height: 2em; line-height: 2em; overflow: hidden; border: 1px solid; border-right: 0; border-radius: 3px 0px 0px 3px; -moz-border-radius: 3px 0px 0px 3px; -webkit-border-radius: 3px 0px 0px 3px; -ms-border-radius: 3px 0px 0px 3px;} +.highcontrastSkin .mceSplitButton a.mceOpen { padding: 5px 4px; display: block; height: 2em; line-height: 2em; border: 1px solid; border-radius: 0px 3px 3px 0px; -moz-border-radius: 0px 3px 3px 0px; -webkit-border-radius: 0px 3px 3px 0px; -ms-border-radius: 0px 3px 3px 0px;} +.highcontrastSkin .mceSplitButton .mceVoiceLabel { height: 2em; vertical-align: center; line-height: 2em; } +.highcontrastSkin .mceSplitButton:focus a.mceAction, .highcontrastSkin .mceSplitButton:active a.mceAction { border-width: 5px; border-right-width: 1px; padding: 1px 10px 1px 6px;-webkit-focus-ring-color:none;outline:none;} +.highcontrastSkin .mceSplitButton:focus a.mceOpen, .highcontrastSkin .mceSplitButton:active a.mceOpen { border-width: 5px; border-left-width: 1px; padding: 1px 0px 1px 4px;-webkit-focus-ring-color:none;outline:none;} + +/* Menu */ +.highcontrastSkin .mceNoIcons span.mceIcon {width:0;} +.highcontrastSkin .mceMenu {position:absolute; left:0; top:0; z-index:1000; border:1px solid; direction:ltr} +.highcontrastSkin .mceMenu table {background:white; color: black} +.highcontrastSkin .mceNoIcons a .mceText {padding-left:10px} +.highcontrastSkin .mceMenu a, .highcontrastSkin .mceMenu span, .highcontrastSkin .mceMenu {display:block;background:white; color: black} +.highcontrastSkin .mceMenu td {height:2em} +.highcontrastSkin .mceMenu a {position:relative;padding:3px 0 4px 0; display: block;} +.highcontrastSkin .mceMenu .mceText {position:relative; display:block; cursor:default; margin:0; padding:0 25px 0 25px;} +.highcontrastSkin .mceMenu pre.mceText {font-family:Monospace} +.highcontrastSkin .mceMenu .mceIcon {position:absolute; top:0; left:0; width:26px;} +.highcontrastSkin td.mceMenuItemSeparator {border-top:1px solid; height:1px} +.highcontrastSkin .mceMenuItemTitle a {border:0; border-bottom:1px solid} +.highcontrastSkin .mceMenuItemTitle span.mceText {font-weight:bold; padding-left:4px} +.highcontrastSkin .mceNoIcons .mceMenuItemSelected span.mceText:before {content: "\2713\A0";} +.highcontrastSkin .mceMenu span.mceMenuLine {display:none} +.highcontrastSkin .mceMenuItemSub a .mceText:after {content: "\A0\25B8"} +.highcontrastSkin .mceMenuItem td, .highcontrastSkin .mceMenuItem th {line-height: normal} + +/* ColorSplitButton */ +.highcontrastSkin div.mceColorSplitMenu table {background:#FFF; border:1px solid; color: #000} +.highcontrastSkin .mceColorSplitMenu td {padding:2px} +.highcontrastSkin .mceColorSplitMenu a {display:block; width:16px; height:16px; overflow:hidden; color:#000; margin: 0; padding: 0;} +.highcontrastSkin .mceColorSplitMenu td.mceMoreColors {padding:1px 3px 1px 1px} +.highcontrastSkin .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} +.highcontrastSkin .mceColorSplitMenu a.mceMoreColors:hover {border:1px solid; background-color:#B6BDD2} +.highcontrastSkin a.mceMoreColors:hover {border:1px solid #0A246A; color: #000;} +.highcontrastSkin .mceColorPreview {display:none;} +.highcontrastSkin .mce_forecolor span.mceAction, .highcontrastSkin .mce_backcolor span.mceAction {height:17px;overflow:hidden} + +/* Progress,Resize */ +.highcontrastSkin .mceBlocker {position:absolute; left:0; top:0; z-index:1000; opacity:0.5; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=50); background:#FFF} +.highcontrastSkin .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} + +/* Rtl */ +.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0} +.mceRtl .mceMenuItem .mceText {text-align: right} + +/* Formats */ +.highcontrastSkin .mce_p span.mceText {} +.highcontrastSkin .mce_address span.mceText {font-style:italic} +.highcontrastSkin .mce_pre span.mceText {font-family:monospace} +.highcontrastSkin .mce_h1 span.mceText {font-weight:bolder; font-size: 2em} +.highcontrastSkin .mce_h2 span.mceText {font-weight:bolder; font-size: 1.5em} +.highcontrastSkin .mce_h3 span.mceText {font-weight:bolder; font-size: 1.17em} +.highcontrastSkin .mce_h4 span.mceText {font-weight:bolder; font-size: 1em} +.highcontrastSkin .mce_h5 span.mceText {font-weight:bolder; font-size: .83em} +.highcontrastSkin .mce_h6 span.mceText {font-weight:bolder; font-size: .75em} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/content.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/content.css new file mode 100644 index 00000000..3537c8bc --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/content.css @@ -0,0 +1,49 @@ +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 {display:inline-block; width:11px !important; height:11px !important; background:url(../default/img/items.gif) no-repeat 0 0;} +span.mceItemNbsp {background: #DDD} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +img {border:0;} +table, img, hr, .mceItemAnchor {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 {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; +} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} +*[contentEditable]:focus {outline:0} + +.mceItemMedia {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)} +.mceItemVideo {background-image:url(../../img/video.gif)} +.mceItemAudio {background-image:url(../../img/video.gif)} +.mceItemIframe {background-image:url(../../img/iframe.gif)} +.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;} +.mceHideBrInPre pre br {display: none} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/dialog.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/dialog.css new file mode 100644 index 00000000..a54db98d --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/dialog.css @@ -0,0 +1,118 @@ +/* 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;} +.nowrap {white-space: nowrap} + +/* Forms */ +fieldset {margin:0; padding:4px; border:1px solid #919B9C; font-family:Verdana, Arial; font-size:10px;} +legend {color:#2B6FB6; font-weight:bold;} +label.msg {display:none;} +label.invalid {color:#EE0000; display:inline;} +input.invalid {border:1px solid #EE0000;} +input {background:#FFF; border:1px solid #CCC;} +input, select, textarea {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} +input, select, textarea {border:1px solid #808080;} +input.radio {border:1px none #000000; background:transparent; vertical-align:middle;} +input.checkbox {border:1px none #000000; background:transparent; vertical-align:middle;} +.input_noborder {border:0;} + +/* Buttons */ +#insert, #cancel, input.button, .updateButton { +border:0; margin:0; padding:0; +font-weight:bold; +width:94px; height:26px; +background:url(../default/img/buttons.png) 0 -26px; +cursor:pointer; +padding-bottom:2px; +float:left; +} + +#insert {background:url(../default/img/buttons.png) 0 -52px} +#cancel {background:url(../default/img/buttons.png) 0 0; float:right} + +/* Browse */ +a.pickcolor, a.browse {text-decoration:none} +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(../default/img/tabs.gif) repeat-x 0 -72px;} +.tabs ul {margin:0; padding:0; list-style:none;} +.tabs li {float:left; background:url(../default/img/tabs.gif) no-repeat 0 0; margin:0 2px 0 0; padding:0 0 0 10px; line-height:17px; height:18px; display:block;} +.tabs li.current {background:url(../default/img/tabs.gif) no-repeat 0 -18px; margin-right:2px;} +.tabs span {float:left; display:block; background:url(../default/img/tabs.gif) no-repeat right -36px; padding:0px 10px 0 0;} +.tabs .current span {background:url(../default/img/tabs.gif) no-repeat right -54px;} +.tabs a {text-decoration:none; font-family:Verdana, Arial; font-size:10px;} +.tabs a:link, .tabs a:visited, .tabs a:hover {color:black;} + +/* Panels */ +.panel_wrapper div.panel {display:none;} +.panel_wrapper div.current {display:block; width:100%; height:300px; overflow:visible;} +.panel_wrapper {border:1px solid #919B9C; border-top:0px; padding:10px; padding-top:5px; clear:both; background:white;} + +/* Columns */ +.column {float:left;} +.properties {width:100%;} +.properties .column1 {} +.properties .column2 {text-align:left;} + +/* Titles */ +h1, h2, h3, h4 {color:#2B6FB6; margin:0; padding:0; padding-top:5px;} +h3 {font-size:14px;} +.title {font-size:12px; font-weight:bold; color:#2B6FB6;} + +/* Dialog specific */ +#link .panel_wrapper, #link div.current {height:125px;} +#image .panel_wrapper, #image div.current {height:200px;} +#plugintable thead {font-weight:bold; background:#DDD;} +#plugintable, #about #plugintable td {border:1px solid #919B9C;} +#plugintable {width:96%; margin-top:10px;} +#pluginscontainer {height:290px; overflow:auto;} +#colorpicker #preview {display:inline-block; padding-left:40px; height:14px; border:1px solid black; margin-left:5px; margin-right: 5px} +#colorpicker #previewblock {position: relative; top: -3px; padding-left:5px; padding-top: 0px; display:inline} +#colorpicker #preview_wrapper { text-align:center; padding-top:4px; white-space: nowrap} +#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 .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;} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png new file mode 100644 index 00000000..13a5cb03 Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg.png differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png new file mode 100644 index 00000000..7fc57f2b Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_black.png differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png new file mode 100644 index 00000000..c0dcc6ca Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/img/button_bg_silver.png differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui.css new file mode 100644 index 00000000..a3102237 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui.css @@ -0,0 +1,222 @@ +/* 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:transparent} +.o2k7Skin iframe {display:block;} +.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 td.mceToolbar{background:#E5EFFD} +.o2k7Skin .mceStatusbar {background:#E5EFFD; 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; outline:0} +.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 {padding-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; margin-left:3px} +.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; direction:ltr} +.o2k7Skin .mceSplitButton {background:url(img/button_bg.png)} +.o2k7Skin .mceSplitButton a.mceAction {width:22px} +.o2k7Skin .mceSplitButton span.mceAction {width:22px; background-image:url(../../img/icons.gif)} +.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; direction:ltr} +.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;} +.o2k7Skin .mceMenuItem td, .o2k7Skin .mceMenuItem th {line-height: normal} + +/* 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} + +/* Rtl */ +.mceRtl .mceListBox .mceText {text-align: right; padding: 0 4px 0 0} +.mceRtl .mceMenuItem .mceText {text-align: right} + +/* 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 span.mce_restoredraft {background-position:-20px -40px} +.o2k7Skin span.mce_spellchecker {background-position:-540px -20px} +.o2k7Skin span.mce_visualblocks {background-position: -40px -40px} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui_black.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui_black.css new file mode 100644 index 00000000..50c9b76a --- /dev/null +++ b/sources/library/tinymce/jscripts/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 td.mceToolbar, .o2k7SkinBlack td.mceStatusbar, .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/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/skins/o2k7/ui_silver.css new file mode 100644 index 00000000..960a8e47 --- /dev/null +++ b/sources/library/tinymce/jscripts/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 td.mceToolbar, .o2k7SkinSilver td.mceStatusbar, .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/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/source_editor.htm b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/source_editor.htm new file mode 100644 index 00000000..3c6d6580 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/advanced/source_editor.htm @@ -0,0 +1,25 @@ + + + {#advanced_dlg.code_title} + + + + +
    +
    + +
    + +
    + +
    + + + +
    + + +
    +
    + + diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template.js b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template.js new file mode 100644 index 00000000..4b3209cc --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template.js @@ -0,0 +1 @@ +(function(){var a=tinymce.DOM;tinymce.ThemeManager.requireLangPack("simple");tinymce.create("tinymce.themes.SimpleTheme",{init:function(c,d){var e=this,b=["Bold","Italic","Underline","Strikethrough","InsertUnorderedList","InsertOrderedList"],f=c.settings;e.editor=c;c.contentCSS.push(d+"/skins/"+f.skin+"/content.css");c.onInit.add(function(){c.onNodeChange.add(function(h,g){tinymce.each(b,function(i){g.get(i.toLowerCase()).setActive(h.queryCommandState(i))})})});a.loadCSS((f.editor_css?c.documentBaseURI.toAbsolute(f.editor_css):"")||d+"/skins/"+f.skin+"/ui.css")},renderUI:function(h){var e=this,i=h.targetNode,b,c,d=e.editor,f=d.controlManager,g;i=a.insertAfter(a.create("span",{id:d.id+"_container","class":"mceEditor "+d.settings.skin+"SimpleSkin"}),i);i=g=a.add(i,"table",{cellPadding:0,cellSpacing:0,"class":"mceLayout"});i=c=a.add(i,"tbody");i=a.add(c,"tr");i=b=a.add(a.add(i,"td"),"div",{"class":"mceIframeContainer"});i=a.add(a.add(c,"tr",{"class":"last"}),"td",{"class":"mceToolbar mceLast",align:"center"});c=e.toolbar=f.createToolbar("tools1");c.add(f.createButton("bold",{title:"simple.bold_desc",cmd:"Bold"}));c.add(f.createButton("italic",{title:"simple.italic_desc",cmd:"Italic"}));c.add(f.createButton("underline",{title:"simple.underline_desc",cmd:"Underline"}));c.add(f.createButton("strikethrough",{title:"simple.striketrough_desc",cmd:"Strikethrough"}));c.add(f.createSeparator());c.add(f.createButton("undo",{title:"simple.undo_desc",cmd:"Undo"}));c.add(f.createButton("redo",{title:"simple.redo_desc",cmd:"Redo"}));c.add(f.createSeparator());c.add(f.createButton("cleanup",{title:"simple.cleanup_desc",cmd:"mceCleanup"}));c.add(f.createSeparator());c.add(f.createButton("insertunorderedlist",{title:"simple.bullist_desc",cmd:"InsertUnorderedList"}));c.add(f.createButton("insertorderedlist",{title:"simple.numlist_desc",cmd:"InsertOrderedList"}));c.renderTo(i);return{iframeContainer:b,editorContainer:d.id+"_container",sizeContainer:g,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/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template_src.js b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template_src.js new file mode 100644 index 00000000..01ce87c5 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/editor_template_src.js @@ -0,0 +1,84 @@ +/** + * editor_template_src.js + * + * Copyright 2009, Moxiecode Systems AB + * Released under LGPL License. + * + * License: http://tinymce.moxiecode.com/license + * Contributing: http://tinymce.moxiecode.com/contributing + */ + +(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.contentCSS.push(url + "/skins/" + s.skin + "/content.css"); + + ed.onInit.add(function() { + ed.onNodeChange.add(function(ed, cm) { + tinymce.each(states, function(c) { + cm.get(c.toLowerCase()).setActive(ed.queryCommandState(c)); + }); + }); + }); + + 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/sources/library/tinymce/jscripts/tiny_mce/themes/simple/img/icons.gif b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/img/icons.gif new file mode 100644 index 00000000..6fcbcb5d Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/img/icons.gif differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/langs/en.js b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/langs/en.js new file mode 100644 index 00000000..088ed0fc --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/langs/en.js @@ -0,0 +1 @@ +tinyMCE.addI18n('en.simple',{"cleanup_desc":"Cleanup Messy Code","redo_desc":"Redo (Ctrl+Y)","undo_desc":"Undo (Ctrl+Z)","numlist_desc":"Insert/Remove Numbered List","bullist_desc":"Insert/Remove Bulleted List","striketrough_desc":"Strikethrough","underline_desc":"Underline (Ctrl+U)","italic_desc":"Italic (Ctrl+I)","bold_desc":"Bold (Ctrl+B)"}); \ No newline at end of file diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/content.css b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/content.css new file mode 100644 index 00000000..2506c807 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/content.css @@ -0,0 +1,25 @@ +body, td, pre { + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 10px; +} + +body { + background-color: #FFFFFF; +} + +.mceVisualAid { + border: 1px dashed #BBBBBB; +} + +/* MSIE specific */ + +* html body { + scrollbar-3dlight-color: #F0F0EE; + scrollbar-arrow-color: #676662; + scrollbar-base-color: #F0F0EE; + scrollbar-darkshadow-color: #DDDDDD; + scrollbar-face-color: #E0E0DD; + scrollbar-highlight-color: #F0F0EE; + scrollbar-shadow-color: #F0F0EE; + scrollbar-track-color: #F5F5F5; +} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/ui.css b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/ui.css new file mode 100644 index 00000000..076fe84e --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/default/ui.css @@ -0,0 +1,32 @@ +/* Reset */ +.defaultSimpleSkin table, .defaultSimpleSkin tbody, .defaultSimpleSkin a, .defaultSimpleSkin img, .defaultSimpleSkin tr, .defaultSimpleSkin div, .defaultSimpleSkin td, .defaultSimpleSkin iframe, .defaultSimpleSkin span, .defaultSimpleSkin * {border:0; margin:0; padding:0; background:transparent; white-space:nowrap; text-decoration:none; font-weight:normal; cursor:default; color:#000} + +/* Containers */ +.defaultSimpleSkin {position:relative} +.defaultSimpleSkin table.mceLayout {background:#F0F0EE; border:1px solid #CCC;} +.defaultSimpleSkin iframe {display:block; background:#FFF; border-bottom:1px solid #CCC;} +.defaultSimpleSkin .mceToolbar {height:24px;} + +/* Layout */ +.defaultSimpleSkin span.mceIcon, .defaultSimpleSkin img.mceIcon {display:block; width:20px; height:20px} +.defaultSimpleSkin .mceIcon {background:url(../../img/icons.gif) no-repeat 20px 20px} + +/* Button */ +.defaultSimpleSkin .mceButton {display:block; border:1px solid #F0F0EE; width:20px; height:20px} +.defaultSimpleSkin a.mceButtonEnabled:hover {border:1px solid #0A246A; background-color:#B2BBD0} +.defaultSimpleSkin a.mceButtonActive {border:1px solid #0A246A; background-color:#C2CBE0} +.defaultSimpleSkin .mceButtonDisabled span {opacity:0.3; -ms-filter:'alpha(opacity=30)'; filter:alpha(opacity=30)} + +/* Separator */ +.defaultSimpleSkin .mceSeparator {display:block; background:url(../../img/icons.gif) -180px 0; width:2px; height:20px; margin:0 2px 0 4px} + +/* Theme */ +.defaultSimpleSkin span.mce_bold {background-position:0 0} +.defaultSimpleSkin span.mce_italic {background-position:-60px 0} +.defaultSimpleSkin span.mce_underline {background-position:-140px 0} +.defaultSimpleSkin span.mce_strikethrough {background-position:-120px 0} +.defaultSimpleSkin span.mce_undo {background-position:-160px 0} +.defaultSimpleSkin span.mce_redo {background-position:-100px 0} +.defaultSimpleSkin span.mce_cleanup {background-position:-40px 0} +.defaultSimpleSkin span.mce_insertunorderedlist {background-position:-20px 0} +.defaultSimpleSkin span.mce_insertorderedlist {background-position:-80px 0} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/content.css b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/content.css new file mode 100644 index 00000000..595809fa --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/content.css @@ -0,0 +1,17 @@ +body, td, pre {font-family:Verdana, Arial, Helvetica, sans-serif; font-size:10px;} + +body {background: #FFF;} +.mceVisualAid {border: 1px dashed #BBB;} + +/* IE */ + +* html body { +scrollbar-3dlight-color: #F0F0EE; +scrollbar-arrow-color: #676662; +scrollbar-base-color: #F0F0EE; +scrollbar-darkshadow-color: #DDDDDD; +scrollbar-face-color: #E0E0DD; +scrollbar-highlight-color: #F0F0EE; +scrollbar-shadow-color: #F0F0EE; +scrollbar-track-color: #F5F5F5; +} diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png new file mode 100644 index 00000000..527e3495 Binary files /dev/null and b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/img/button_bg.png differ diff --git a/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/ui.css b/sources/library/tinymce/jscripts/tiny_mce/themes/simple/skins/o2k7/ui.css new file mode 100644 index 00000000..cf6c35d1 --- /dev/null +++ b/sources/library/tinymce/jscripts/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/sources/library/tinymce/jscripts/tiny_mce/tiny_mce.js b/sources/library/tinymce/jscripts/tiny_mce/tiny_mce.js new file mode 100644 index 00000000..f52fd836 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/tiny_mce.js @@ -0,0 +1 @@ +(function(e){var a=/^\s*|\s*$/g,b,d="B".replace(/A(.)|B/,"$1")==="$1";var c={majorVersion:"3",minorVersion:"5.0.1",releaseDate:"2012-05-10",_init:function(){var s=this,q=document,o=navigator,g=o.userAgent,m,f,l,k,j,r;s.isOpera=e.opera&&opera.buildNumber;s.isWebKit=/WebKit/.test(g);s.isIE=!s.isWebKit&&!s.isOpera&&(/MSIE/gi).test(g)&&(/Explorer/gi).test(o.appName);s.isIE6=s.isIE&&/MSIE [56]/.test(g);s.isIE7=s.isIE&&/MSIE [7]/.test(g);s.isIE8=s.isIE&&/MSIE [8]/.test(g);s.isIE9=s.isIE&&/MSIE [9]/.test(g);s.isGecko=!s.isWebKit&&/Gecko/.test(g);s.isMac=g.indexOf("Mac")!=-1;s.isAir=/adobeair/i.test(g);s.isIDevice=/(iPad|iPhone)/.test(g);s.isIOS5=s.isIDevice&&g.match(/AppleWebKit\/(\d*)/)[1]>=534;if(e.tinyMCEPreInit){s.suffix=tinyMCEPreInit.suffix;s.baseURL=tinyMCEPreInit.base;s.query=tinyMCEPreInit.query;return}s.suffix="";f=q.getElementsByTagName("base");for(m=0;m0?b:[f.scope]);if(e===false){break}}a.inDispatch=false;return e}});(function(){var a=tinymce.each;tinymce.create("tinymce.util.URI",{URI:function(e,g){var f=this,i,d,c,h;e=tinymce.trim(e);g=f.settings=g||{};if(/^([\w\-]+):([^\/]{2})/i.test(e)||/^\s*#/.test(e)){f.source=e;return}if(e.indexOf("/")===0&&e.indexOf("//")!==0){e=(g.base_uri?g.base_uri.protocol||"http":"http")+"://mce_host"+e}if(!/^[\w\-]*:?\/\//.test(e)){h=g.base_uri?g.base_uri.path:new tinymce.util.URI(location.href).directory;e=((g.base_uri&&g.base_uri.protocol)||"http")+"://mce_host"+f.toAbsPath(h,e)}e=e.replace(/@@/g,"(mce_at)");e=/^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/.exec(e);a(["source","protocol","authority","userInfo","user","password","host","port","relative","path","directory","file","query","anchor"],function(b,j){var k=e[j];if(k){k=k.replace(/\(mce_at\)/g,"@@")}f[b]=k});c=g.base_uri;if(c){if(!f.protocol){f.protocol=c.protocol}if(!f.userInfo){f.userInfo=c.userInfo}if(!f.port&&f.host==="mce_host"){f.port=c.port}if(!f.host||f.host==="mce_host"){f.host=c.host}f.source=""}},setPath:function(c){var b=this;c=/^(.*?)\/?(\w+)?$/.exec(c);b.path=c[0];b.directory=c[1];b.file=c[2];b.source="";b.getURI()},toRelative:function(b){var d=this,f;if(b==="./"){return b}b=new tinymce.util.URI(b,{base_uri:d});if((b.host!="mce_host"&&d.host!=b.host&&b.host)||d.port!=b.port||d.protocol!=b.protocol){return b.getURI()}var c=d.getURI(),e=b.getURI();if(c==e||(c.charAt(c.length-1)=="/"&&c.substr(0,c.length-1)==e)){return c}f=d.toRelPath(d.path,b.path);if(b.query){f+="?"+b.query}if(b.anchor){f+="#"+b.anchor}return f},toAbsolute:function(b,c){b=new tinymce.util.URI(b,{base_uri:this});return b.getURI(this.host==b.host&&this.protocol==b.protocol?c:0)},toRelPath:function(g,h){var c,f=0,d="",e,b;g=g.substring(0,g.lastIndexOf("/"));g=g.split("/");c=h.split("/");if(g.length>=c.length){for(e=0,b=g.length;e=c.length||g[e]!=c[e]){f=e+1;break}}}if(g.length=g.length||g[e]!=c[e]){f=e+1;break}}}if(f===1){return h}for(e=0,b=g.length-(f-1);e=0;c--){if(f[c].length===0||f[c]==="."){continue}if(f[c]===".."){b++;continue}if(b>0){b--;continue}h.push(f[c])}c=e.length-b;if(c<=0){g=h.reverse().join("/")}else{g=e.slice(0,c).join("/")+"/"+h.reverse().join("/")}if(g.indexOf("/")!==0){g="/"+g}if(d&&g.lastIndexOf("/")!==g.length-1){g+=d}return g},getURI:function(d){var c,b=this;if(!b.source||d){c="";if(!d){if(b.protocol){c+=b.protocol+"://"}if(b.userInfo){c+=b.userInfo+"@"}if(b.host){c+=b.host}if(b.port){c+=":"+b.port}}if(b.path){c+=b.path}if(b.query){c+="?"+b.query}if(b.anchor){c+="#"+b.anchor}b.source=c}return b.source}})})();(function(){var a=tinymce.each;tinymce.create("static tinymce.util.Cookie",{getHash:function(d){var b=this.get(d),c;if(b){a(b.split("&"),function(e){e=e.split("=");c=c||{};c[unescape(e[0])]=unescape(e[1])})}return c},setHash:function(j,b,g,f,i,c){var h="";a(b,function(e,d){h+=(!h?"":"&")+escape(d)+"="+escape(e)});this.set(j,h,g,f,i,c)},get:function(i){var h=document.cookie,g,f=i+"=",d;if(!h){return}d=h.indexOf("; "+f);if(d==-1){d=h.indexOf(f);if(d!==0){return null}}else{d+=2}g=h.indexOf(";",d);if(g==-1){g=h.length}return unescape(h.substring(d+f.length,g))},set:function(i,b,g,f,h,c){document.cookie=i+"="+escape(b)+((g)?"; expires="+g.toGMTString():"")+((f)?"; path="+escape(f):"")+((h)?"; domain="+h:"")+((c)?"; secure":"")},remove:function(e,b){var c=new Date();c.setTime(c.getTime()-1000);this.set(e,"",c,b,c)}})})();(function(){function serialize(o,quote){var i,v,t,name;quote=quote||'"';if(o==null){return"null"}t=typeof o;if(t=="string"){v="\bb\tt\nn\ff\rr\"\"''\\\\";return quote+o.replace(/([\u0080-\uFFFF\x00-\x1f\"\'\\])/g,function(a,b){if(quote==='"'&&a==="'"){return a}i=v.indexOf(b);if(i+1){return"\\"+v.charAt(i+1)}a=b.charCodeAt().toString(16);return"\\u"+"0000".substring(a.length)+a})+quote}if(t=="object"){if(o.hasOwnProperty&&o instanceof Array){for(i=0,v="[";i0?",":"")+serialize(o[i],quote)}return v+"]"}v="{";for(name in o){if(o.hasOwnProperty(name)){v+=typeof o[name]!="function"?(v.length>1?","+quote:quote)+name+quote+":"+serialize(o[name],quote):""}}return v+"}"}return""+o}tinymce.util.JSON={serialize:serialize,parse:function(s){try{return eval("("+s+")")}catch(ex){}}}})();tinymce.create("static tinymce.util.XHR",{send:function(g){var a,e,b=window,h=0;function f(){if(!g.async||a.readyState==4||h++>10000){if(g.success&&h<10000&&a.status==200){g.success.call(g.success_scope,""+a.responseText,a,g)}else{if(g.error){g.error.call(g.error_scope,h>10000?"TIMED_OUT":"GENERAL",a,g)}}a=null}else{b.setTimeout(f,10)}}g.scope=g.scope||this;g.success_scope=g.success_scope||g.scope;g.error_scope=g.error_scope||g.scope;g.async=g.async===false?false:true;g.data=g.data||"";function d(i){a=0;try{a=new ActiveXObject(i)}catch(c){}return a}a=b.XMLHttpRequest?new XMLHttpRequest():d("Microsoft.XMLHTTP")||d("Msxml2.XMLHTTP");if(a){if(a.overrideMimeType){a.overrideMimeType(g.content_type)}a.open(g.type||(g.data?"POST":"GET"),g.url,g.async);if(g.content_type){a.setRequestHeader("Content-Type",g.content_type)}a.setRequestHeader("X-Requested-With","XMLHttpRequest");a.send(g.data);if(!g.async){return f()}e=b.setTimeout(f,10)}}});(function(){var c=tinymce.extend,b=tinymce.util.JSON,a=tinymce.util.XHR;tinymce.create("tinymce.util.JSONRequest",{JSONRequest:function(d){this.settings=c({},d);this.count=0},send:function(f){var e=f.error,d=f.success;f=c(this.settings,f);f.success=function(h,g){h=b.parse(h);if(typeof(h)=="undefined"){h={error:"JSON Parse error."}}if(h.error){e.call(f.error_scope||f.scope,h.error,g)}else{d.call(f.success_scope||f.scope,h.result)}};f.error=function(h,g){if(e){e.call(f.error_scope||f.scope,h,g)}};f.data=b.serialize({id:f.id||"c"+(this.count++),method:f.method,params:f.params});f.content_type="application/json";a.send(f)},"static":{sendRPC:function(d){return new tinymce.util.JSONRequest().send(d)}}})}());(function(a){a.VK={BACKSPACE:8,DELETE:46,DOWN:40,ENTER:13,LEFT:37,RIGHT:39,SPACEBAR:32,TAB:9,UP:38,modifierPressed:function(b){return b.shiftKey||b.ctrlKey||b.altKey}}})(tinymce);tinymce.util.Quirks=function(d){var l=tinymce.VK,r=l.BACKSPACE,s=l.DELETE,o=d.dom,z=d.selection,q=d.settings;function c(D,C){try{d.getDoc().execCommand(D,false,C)}catch(B){}}function h(){function B(E){var C,G,D,F;C=z.getRng();G=o.getParent(C.startContainer,o.isBlock);if(E){G=o.getNext(G,o.isBlock)}if(G){D=G.firstChild;while(D&&D.nodeType==3&&D.nodeValue.length===0){D=D.nextSibling}if(D&&D.nodeName==="SPAN"){F=D.cloneNode(false)}}d.getDoc().execCommand(E?"ForwardDelete":"Delete",false,null);G=o.getParent(C.startContainer,o.isBlock);tinymce.each(o.select("span.Apple-style-span,font.Apple-style-span",G),function(H){var I=z.getBookmark();if(F){o.replace(F.cloneNode(false),H,true)}else{o.remove(H,true)}z.moveToBookmark(I)})}d.onKeyDown.add(function(C,E){var D;D=E.keyCode==s;if(!E.isDefaultPrevented()&&(D||E.keyCode==r)&&!l.modifierPressed(E)){E.preventDefault();B(D)}});d.addCommand("Delete",function(){B()})}function A(){function C(E,H){var D,G,F=H?"start":"end";D=E[F+"Container"];G=E[F+"Offset"];if(D.nodeType==1&&D.hasChildNodes()){D=D.childNodes[Math.min(H?G:(G>0?G-1:0),D.childNodes.length-1)]}return D}function B(G,K){var F,J,E,H,I=K?"start":"end",D;F=G[I+"Container"];J=G[I+"Offset"];E=o.getRoot();if(F.nodeType==1){D=J>=F.childNodes.length;F=C(G,K);if(F.nodeType==3){J=K&&!D?0:F.nodeValue.length}}if(F.nodeType==3&&((K&&J>0)||(!K&&J7){return}c("RespectVisibilityInDesign",true);o.addClass(d.getBody(),"mceHideBrInPre");d.parser.addNodeFilter("pre",function(C,E){var F=C.length,H,D,I,G;while(F--){H=C[F].getAll("br");D=H.length;while(D--){I=H[D];G=I.prev;if(G&&G.type===3&&G.value.charAt(G.value-1)!="\n"){G.value+="\n"}else{I.parent.insert(new tinymce.html.Node("#text",3),I,true).value="\n"}}}});d.serializer.addNodeFilter("pre",function(C,E){var F=C.length,H,D,I,G;while(F--){H=C[F].getAll("br");D=H.length;while(D--){I=H[D];G=I.prev;if(G&&G.type==3){G.value=G.value.replace(/\r?\n$/,"")}}}})}function f(){o.bind(d.getBody(),"mouseup",function(D){var C,B=z.getNode();if(B.nodeName=="IMG"){if(C=o.getStyle(B,"width")){o.setAttrib(B,"width",C.replace(/[^0-9%]+/g,""));o.setStyle(B,"width","")}if(C=o.getStyle(B,"height")){o.setAttrib(B,"height",C.replace(/[^0-9%]+/g,""));o.setStyle(B,"height","")}}})}function p(){d.onKeyDown.add(function(H,I){var G,B,C,E,F,J,D;G=I.keyCode==s;if(!I.isDefaultPrevented()&&(G||I.keyCode==r)&&!l.modifierPressed(I)){B=z.getRng();C=B.startContainer;E=B.startOffset;D=B.collapsed;if(C.nodeType==3&&C.nodeValue.length>0&&((E===0&&!D)||(D&&E===(G?0:1)))){nonEmptyElements=H.schema.getNonEmptyElements();I.preventDefault();F=o.create("br",{id:"__tmp"});C.parentNode.insertBefore(F,C);H.getDoc().execCommand(G?"ForwardDelete":"Delete",false,null);C=z.getRng().startContainer;J=C.previousSibling;if(J&&J.nodeType==1&&!o.isBlock(J)&&o.isEmpty(J)&&!nonEmptyElements[J.nodeName.toLowerCase()]){o.remove(J)}o.remove("__tmp")}}})}function e(){d.onKeyDown.add(function(F,G){var D,C,H,B,E;if(G.isDefaultPrevented()||G.keyCode!=l.BACKSPACE){return}D=z.getRng();C=D.startContainer;H=D.startOffset;B=o.getRoot();E=C;if(!D.collapsed||H!==0){return}while(E&&E.parentNode&&E.parentNode.firstChild==E&&E.parentNode!=B){E=E.parentNode}if(E.tagName==="BLOCKQUOTE"){F.formatter.toggle("blockquote",null,E);D.setStart(C,0);D.setEnd(C,0);z.setRng(D);z.collapse(false)}})}function k(){function B(){d._refreshContentEditable();c("StyleWithCSS",false);c("enableInlineTableEditing",false);if(!q.object_resizing){c("enableObjectResizing",false)}}if(!q.readonly){d.onBeforeExecCommand.add(B);d.onMouseDown.add(B)}}function n(){function B(C,D){tinymce.each(o.select("a"),function(G){var E=G.parentNode,F=o.getRoot();if(E.lastChild===G){while(E&&!o.isBlock(E)){if(E.parentNode.lastChild!==E||E===F){return}E=E.parentNode}o.add(E,"br",{"data-mce-bogus":1})}})}d.onExecCommand.add(function(C,D){if(D==="CreateLink"){B(C)}});d.onSetContent.add(z.onSetContent.add(B))}function a(){function B(D,C){if(!D||!C.initial){d.execCommand("mceRepaint")}}d.onUndo.add(B);d.onRedo.add(B);d.onSetContent.add(B)}function j(){d.onKeyDown.add(function(B,C){if(!C.isDefaultPrevented()&&C.keyCode==8&&z.getNode().nodeName=="IMG"){C.preventDefault();B.undoManager.beforeChange();o.remove(z.getNode());B.undoManager.add()}})}u();e();A();if(tinymce.isWebKit){p();h();t();v();if(tinymce.isIDevice){i()}}if(tinymce.isIE){m();y();g();f();j()}if(tinymce.isGecko){m();b();x();k();n();a()}};(function(j){var a,g,d,k=/[&<>\"\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,b=/[<>&\u007E-\uD7FF\uE000-\uFFEF]|[\uD800-\uDBFF][\uDC00-\uDFFF]/g,f=/[<>&\"\']/g,c=/&(#x|#)?([\w]+);/g,i={128:"\u20AC",130:"\u201A",131:"\u0192",132:"\u201E",133:"\u2026",134:"\u2020",135:"\u2021",136:"\u02C6",137:"\u2030",138:"\u0160",139:"\u2039",140:"\u0152",142:"\u017D",145:"\u2018",146:"\u2019",147:"\u201C",148:"\u201D",149:"\u2022",150:"\u2013",151:"\u2014",152:"\u02DC",153:"\u2122",154:"\u0161",155:"\u203A",156:"\u0153",158:"\u017E",159:"\u0178"};g={'"':""","'":"'","<":"<",">":">","&":"&"};d={"<":"<",">":">","&":"&",""":'"',"'":"'"};function h(l){var m;m=document.createElement("div");m.innerHTML=l;return m.textContent||m.innerText||l}function e(m,p){var n,o,l,q={};if(m){m=m.split(",");p=p||10;for(n=0;n1){return"&#"+(((n.charCodeAt(0)-55296)*1024)+(n.charCodeAt(1)-56320)+65536)+";"}return g[n]||"&#"+n.charCodeAt(0)+";"})},encodeNamed:function(n,l,m){m=m||a;return n.replace(l?k:b,function(o){return g[o]||m[o]||o})},getEncodeFunc:function(l,o){var p=j.html.Entities;o=e(o)||a;function m(r,q){return r.replace(q?k:b,function(s){return g[s]||o[s]||"&#"+s.charCodeAt(0)+";"||s})}function n(r,q){return p.encodeNamed(r,q,o)}l=j.makeMap(l.replace(/\+/g,","));if(l.named&&l.numeric){return m}if(l.named){if(o){return n}return p.encodeNamed}if(l.numeric){return p.encodeNumeric}return p.encodeRaw},decode:function(l){return l.replace(c,function(n,m,o){if(m){o=parseInt(o,m.length===2?16:10);if(o>65535){o-=65536;return String.fromCharCode(55296+(o>>10),56320+(o&1023))}else{return i[o]||String.fromCharCode(o)}}return d[n]||a[n]||h(n)})}}})(tinymce);tinymce.html.Styles=function(d,f){var k=/rgb\s*\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*\)/gi,h=/(?:url(?:(?:\(\s*\"([^\"]+)\"\s*\))|(?:\(\s*\'([^\']+)\'\s*\))|(?:\(\s*([^)\s]+)\s*\))))|(?:\'([^\']+)\')|(?:\"([^\"]+)\")/gi,b=/\s*([^:]+):\s*([^;]+);?/g,l=/\s+$/,m=/rgb/,e,g,a={},j;d=d||{};j="\\\" \\' \\; \\: ; : \uFEFF".split(" ");for(g=0;g1?r:"0"+r}return"#"+o(q)+o(p)+o(i)}return{toHex:function(i){return i.replace(k,c)},parse:function(s){var z={},q,n,x,r,v=d.url_converter,y=d.url_converter_scope||this;function p(D,G){var F,C,B,E;F=z[D+"-top"+G];if(!F){return}C=z[D+"-right"+G];if(F!=C){return}B=z[D+"-bottom"+G];if(C!=B){return}E=z[D+"-left"+G];if(B!=E){return}z[D+G]=E;delete z[D+"-top"+G];delete z[D+"-right"+G];delete z[D+"-bottom"+G];delete z[D+"-left"+G]}function u(C){var D=z[C],B;if(!D||D.indexOf(" ")<0){return}D=D.split(" ");B=D.length;while(B--){if(D[B]!==D[0]){return false}}z[C]=D[0];return true}function A(D,C,B,E){if(!u(C)){return}if(!u(B)){return}if(!u(E)){return}z[D]=z[C]+" "+z[B]+" "+z[E];delete z[C];delete z[B];delete z[E]}function t(B){r=true;return a[B]}function i(C,B){if(r){C=C.replace(/\uFEFF[0-9]/g,function(D){return a[D]})}if(!B){C=C.replace(/\\([\'\";:])/g,"$1")}return C}function o(C,B,F,E,G,D){G=G||D;if(G){G=i(G);return"'"+G.replace(/\'/g,"\\'")+"'"}B=i(B||F||E);if(v){B=v.call(y,B,"style")}return"url('"+B.replace(/\'/g,"\\'")+"')"}if(s){s=s.replace(/\\[\"\';:\uFEFF]/g,t).replace(/\"[^\"]+\"|\'[^\']+\'/g,function(B){return B.replace(/[;:]/g,t)});while(q=b.exec(s)){n=q[1].replace(l,"").toLowerCase();x=q[2].replace(l,"");if(n&&x.length>0){if(n==="font-weight"&&x==="700"){x="bold"}else{if(n==="color"||n==="background-color"){x=x.toLowerCase()}}x=x.replace(k,c);x=x.replace(h,o);z[n]=r?i(x,true):x}b.lastIndex=q.index+q[0].length}p("border","");p("border","-width");p("border","-color");p("border","-style");p("padding","");p("margin","");A("border","border-width","border-style","border-color");if(z.border==="medium none"){delete z.border}}return z},serialize:function(p,r){var o="",n,q;function i(t){var x,u,s,v;x=f.styles[t];if(x){for(u=0,s=x.length;u0){o+=(o.length>0?" ":"")+t+": "+v+";"}}}}if(r&&f&&f.styles){i("*");i(r)}else{for(n in p){q=p[n];if(q!==e&&q.length>0){o+=(o.length>0?" ":"")+n+": "+q+";"}}}return o}}};(function(f){var a={},e=f.makeMap,g=f.each;function d(j,i){return j.split(i||",")}function h(m,l){var j,k={};function i(n){return n.replace(/[A-Z]+/g,function(o){return i(m[o])})}for(j in m){if(m.hasOwnProperty(j)){m[j]=i(m[j])}}i(l).replace(/#/g,"#text").replace(/(\w+)\[([^\]]+)\]\[([^\]]*)\]/g,function(q,o,n,p){n=d(n,"|");k[o]={attributes:e(n),attributesOrder:n,children:e(p,"|",{"#comment":{}})}});return k}function b(){var i=a.html5;if(!i){i=a.html5=h({A:"id|accesskey|class|dir|draggable|item|hidden|itemprop|role|spellcheck|style|subject|title",B:"#|a|abbr|area|audio|b|bdo|br|button|canvas|cite|code|command|datalist|del|dfn|em|embed|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|meta|meter|noscript|object|output|progress|q|ruby|samp|script|select|small|span|strong|sub|sup|svg|textarea|time|var|video",C:"#|a|abbr|area|address|article|aside|audio|b|bdo|blockquote|br|button|canvas|cite|code|command|datalist|del|details|dfn|dialog|div|dl|em|embed|fieldset|figure|footer|form|h1|h2|h3|h4|h5|h6|header|hgroup|hr|i|iframe|img|input|ins|kbd|keygen|label|link|map|mark|menu|meta|meter|nav|noscript|ol|object|output|p|pre|progress|q|ruby|samp|script|section|select|small|span|strong|style|sub|sup|svg|table|textarea|time|ul|var|video"},"html[A|manifest][body|head]head[A][base|command|link|meta|noscript|script|style|title]title[A][#]base[A|href|target][]link[A|href|rel|media|type|sizes][]meta[A|http-equiv|name|content|charset][]style[A|type|media|scoped][#]script[A|charset|type|src|defer|async][#]noscript[A][C]body[A][C]section[A][C]nav[A][C]article[A][C]aside[A][C]h1[A][B]h2[A][B]h3[A][B]h4[A][B]h5[A][B]h6[A][B]hgroup[A][h1|h2|h3|h4|h5|h6]header[A][C]footer[A][C]address[A][C]p[A][B]br[A][]pre[A][B]dialog[A][dd|dt]blockquote[A|cite][C]ol[A|start|reversed][li]ul[A][li]li[A|value][C]dl[A][dd|dt]dt[A][B]dd[A][C]a[A|href|target|ping|rel|media|type][C]em[A][B]strong[A][B]small[A][B]cite[A][B]q[A|cite][B]dfn[A][B]abbr[A][B]code[A][B]var[A][B]samp[A][B]kbd[A][B]sub[A][B]sup[A][B]i[A][B]b[A][B]mark[A][B]progress[A|value|max][B]meter[A|value|min|max|low|high|optimum][B]time[A|datetime][B]ruby[A][B|rt|rp]rt[A][B]rp[A][B]bdo[A][B]span[A][B]ins[A|cite|datetime][B]del[A|cite|datetime][B]figure[A][C|legend|figcaption]figcaption[A][C]img[A|alt|src|height|width|usemap|ismap][]iframe[A|name|src|height|width|sandbox|seamless][]embed[A|src|height|width|type][]object[A|data|type|height|width|usemap|name|form|classid][param]param[A|name|value][]details[A|open][C|legend]command[A|type|label|icon|disabled|checked|radiogroup][]menu[A|type|label][C|li]legend[A][C|B]div[A][C]source[A|src|type|media][]audio[A|src|autobuffer|autoplay|loop|controls][source]video[A|src|autobuffer|autoplay|loop|controls|width|height|poster][source]hr[A][]form[A|accept-charset|action|autocomplete|enctype|method|name|novalidate|target][C]fieldset[A|disabled|form|name][C|legend]label[A|form|for][B]input[A|type|accept|alt|autocomplete|checked|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|height|list|max|maxlength|min|multiple|pattern|placeholder|readonly|required|size|src|step|width|files|value][]button[A|autofocus|disabled|form|formaction|formenctype|formmethod|formnovalidate|formtarget|name|value|type][B]select[A|autofocus|disabled|form|multiple|name|size][option|optgroup]datalist[A][B|option]optgroup[A|disabled|label][option]option[A|disabled|selected|label|value][]textarea[A|autofocus|disabled|form|maxlength|name|placeholder|readonly|required|rows|cols|wrap][]keygen[A|autofocus|challenge|disabled|form|keytype|name][]output[A|for|form|name][B]canvas[A|width|height][]map[A|name][B|C]area[A|shape|coords|href|alt|target|media|rel|ping|type][]mathml[A][]svg[A][]table[A|summary][caption|colgroup|thead|tfoot|tbody|tr]caption[A][C]colgroup[A|span][col]col[A|span][]thead[A][tr]tfoot[A][tr]tbody[A][tr]tr[A][th|td]th[A|headers|rowspan|colspan|scope][B]td[A|headers|rowspan|colspan][C]")}return i}function c(){var i=a.html4;if(!i){i=a.html4=h({Z:"H|K|N|O|P",Y:"X|form|R|Q",ZG:"E|span|width|align|char|charoff|valign",X:"p|T|div|U|W|isindex|fieldset|table",ZF:"E|align|char|charoff|valign",W:"pre|hr|blockquote|address|center|noframes",ZE:"abbr|axis|headers|scope|rowspan|colspan|align|char|charoff|valign|nowrap|bgcolor|width|height",ZD:"[E][S]",U:"ul|ol|dl|menu|dir",ZC:"p|Y|div|U|W|table|br|span|bdo|object|applet|img|map|K|N|Q",T:"h1|h2|h3|h4|h5|h6",ZB:"X|S|Q",S:"R|P",ZA:"a|G|J|M|O|P",R:"a|H|K|N|O",Q:"noscript|P",P:"ins|del|script",O:"input|select|textarea|label|button",N:"M|L",M:"em|strong|dfn|code|q|samp|kbd|var|cite|abbr|acronym",L:"sub|sup",K:"J|I",J:"tt|i|b|u|s|strike",I:"big|small|font|basefont",H:"G|F",G:"br|span|bdo",F:"object|applet|img|map|iframe",E:"A|B|C",D:"accesskey|tabindex|onfocus|onblur",C:"onclick|ondblclick|onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|onkeydown|onkeyup",B:"lang|xml:lang|dir",A:"id|class|style|title"},"script[id|charset|type|language|src|defer|xml:space][]style[B|id|type|media|title|xml:space][]object[E|declare|classid|codebase|data|type|codetype|archive|standby|width|height|usemap|name|tabindex|align|border|hspace|vspace][#|param|Y]param[id|name|value|valuetype|type][]p[E|align][#|S]a[E|D|charset|type|name|href|hreflang|rel|rev|shape|coords|target][#|Z]br[A|clear][]span[E][#|S]bdo[A|C|B][#|S]applet[A|codebase|archive|code|object|alt|name|width|height|align|hspace|vspace][#|param|Y]h1[E|align][#|S]img[E|src|alt|name|longdesc|width|height|usemap|ismap|align|border|hspace|vspace][]map[B|C|A|name][X|form|Q|area]h2[E|align][#|S]iframe[A|longdesc|name|src|frameborder|marginwidth|marginheight|scrolling|align|width|height][#|Y]h3[E|align][#|S]tt[E][#|S]i[E][#|S]b[E][#|S]u[E][#|S]s[E][#|S]strike[E][#|S]big[E][#|S]small[E][#|S]font[A|B|size|color|face][#|S]basefont[id|size|color|face][]em[E][#|S]strong[E][#|S]dfn[E][#|S]code[E][#|S]q[E|cite][#|S]samp[E][#|S]kbd[E][#|S]var[E][#|S]cite[E][#|S]abbr[E][#|S]acronym[E][#|S]sub[E][#|S]sup[E][#|S]input[E|D|type|name|value|checked|disabled|readonly|size|maxlength|src|alt|usemap|onselect|onchange|accept|align][]select[E|name|size|multiple|disabled|tabindex|onfocus|onblur|onchange][optgroup|option]optgroup[E|disabled|label][option]option[E|selected|disabled|label|value][]textarea[E|D|name|rows|cols|disabled|readonly|onselect|onchange][]label[E|for|accesskey|onfocus|onblur][#|S]button[E|D|name|value|type|disabled][#|p|T|div|U|W|table|G|object|applet|img|map|K|N|Q]h4[E|align][#|S]ins[E|cite|datetime][#|Y]h5[E|align][#|S]del[E|cite|datetime][#|Y]h6[E|align][#|S]div[E|align][#|Y]ul[E|type|compact][li]li[E|type|value][#|Y]ol[E|type|compact|start][li]dl[E|compact][dt|dd]dt[E][#|S]dd[E][#|Y]menu[E|compact][li]dir[E|compact][li]pre[E|width|xml:space][#|ZA]hr[E|align|noshade|size|width][]blockquote[E|cite][#|Y]address[E][#|S|p]center[E][#|Y]noframes[E][#|Y]isindex[A|B|prompt][]fieldset[E][#|legend|Y]legend[E|accesskey|align][#|S]table[E|summary|width|border|frame|rules|cellspacing|cellpadding|align|bgcolor][caption|col|colgroup|thead|tfoot|tbody|tr]caption[E|align][#|S]col[ZG][]colgroup[ZG][col]thead[ZF][tr]tr[ZF|bgcolor][th|td]th[E|ZE][#|Y]form[E|action|method|name|enctype|onsubmit|onreset|accept|accept-charset|target][#|X|R|Q]noscript[E][#|Y]td[E|ZE][#|Y]tfoot[ZF][tr]tbody[ZF][tr]area[E|D|shape|coords|href|nohref|alt|target][]base[id|href|target][]body[E|onload|onunload|background|bgcolor|text|link|vlink|alink][#|Y]")}return i}f.html.Schema=function(A){var u=this,s={},k={},j=[],D,y;var o,q,z,r,v,n,p={};function m(F,E,H){var G=A[F];if(!G){G=a[F];if(!G){G=e(E," ",e(E.toUpperCase()," "));G=f.extend(G,H);a[F]=G}}else{G=e(G,",",e(G.toUpperCase()," "))}return G}A=A||{};y=A.schema=="html5"?b():c();if(A.verify_html===false){A.valid_elements="*[*]"}if(A.valid_styles){D={};g(A.valid_styles,function(F,E){D[E]=f.explode(F)})}o=m("whitespace_elements","pre script style textarea");q=m("self_closing_elements","colgroup dd dt li options p td tfoot th thead tr");z=m("short_ended_elements","area base basefont br col frame hr img input isindex link meta param embed source");r=m("boolean_attributes","checked compact declare defer disabled ismap multiple nohref noresize noshade nowrap readonly selected autoplay loop controls");n=m("non_empty_elements","td th iframe video audio object",z);v=m("block_elements","h1 h2 h3 h4 h5 h6 hr p div address pre form table tbody thead tfoot th tr td li ol ul caption blockquote center dl dt dd dir fieldset noscript menu isindex samp header footer article section hgroup aside nav figure");function i(E){return new RegExp("^"+E.replace(/([?+*])/g,".$1")+"$")}function C(L){var K,G,Z,V,aa,F,I,U,X,Q,Y,ac,O,J,W,E,S,H,ab,ad,P,T,N=/^([#+\-])?([^\[\/]+)(?:\/([^\[]+))?(?:\[([^\]]+)\])?$/,R=/^([!\-])?(\w+::\w+|[^=:<]+)?(?:([=:<])(.*))?$/,M=/[*?+]/;if(L){L=d(L);if(s["@"]){S=s["@"].attributes;H=s["@"].attributesOrder}for(K=0,G=L.length;K=0){for(U=A.length-1;U>=V;U--){T=A[U];if(T.valid){n.end(T.name)}}A.length=V}}function p(U,T,Y,X,W){var Z,V;T=T.toLowerCase();Y=T in H?T:j(Y||X||W||"");if(v&&!z&&T.indexOf("data-")!==0){Z=P[T];if(!Z&&F){V=F.length;while(V--){Z=F[V];if(Z.pattern.test(T)){break}}if(V===-1){Z=null}}if(!Z){return}if(Z.validValues&&!(Y in Z.validValues)){return}}N.map[T]=Y;N.push({name:T,value:Y})}l=new RegExp("<(?:(?:!--([\\w\\W]*?)-->)|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)|(?:!DOCTYPE([\\w\\W]*?)>)|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)|(?:\\/([^>]+)>)|(?:([A-Za-z0-9\\-\\:]+)((?:\\s+[^\"'>]+(?:(?:\"[^\"]*\")|(?:'[^']*')|[^>]*))*|\\/|\\s+)>))","g");D=/([\w:\-]+)(?:\s*=\s*(?:(?:\"((?:\\.|[^\"])*)\")|(?:\'((?:\\.|[^\'])*)\')|([^>\s]+)))?/g;K={script:/<\/script[^>]*>/gi,style:/<\/style[^>]*>/gi,noscript:/<\/noscript[^>]*>/gi};M=e.getShortEndedElements();J=e.getSelfClosingElements();H=e.getBoolAttrs();v=c.validate;s=c.remove_internals;y=c.fix_self_closing;q=a.isIE;o=/^:/;while(g=l.exec(E)){if(G0&&A[A.length-1].name===I){u(I)}if(!v||(m=e.getElementRule(I))){k=true;if(v){P=m.attributes;F=m.attributePatterns}if(R=g[8]){z=R.indexOf("data-mce-type")!==-1;if(z&&s){k=false}N=[];N.map={};R.replace(D,p)}else{N=[];N.map={}}if(v&&!z){S=m.attributesRequired;L=m.attributesDefault;f=m.attributesForced;if(f){Q=f.length;while(Q--){t=f[Q];r=t.name;h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}if(L){Q=L.length;while(Q--){t=L[Q];r=t.name;if(!(r in N.map)){h=t.value;if(h==="{$uid}"){h="mce_"+x++}N.map[r]=h;N.push({name:r,value:h})}}}if(S){Q=S.length;while(Q--){if(S[Q] in N.map){break}}if(Q===-1){k=false}}if(N.map["data-mce-bogus"]){k=false}}if(k){n.start(I,N,O)}}else{k=false}if(B=K[I]){B.lastIndex=G=g.index+g[0].length;if(g=B.exec(E)){if(k){C=E.substr(G,g.index-G)}G=g.index+g[0].length}else{C=E.substr(G);G=E.length}if(k&&C.length>0){n.text(C,true)}if(k){n.end(I)}l.lastIndex=G;continue}if(!O){if(!R||R.indexOf("/")!=R.length-1){A.push({name:I,valid:k})}else{if(k){n.end(I)}}}}else{if(I=g[1]){n.comment(I)}else{if(I=g[2]){n.cdata(I)}else{if(I=g[3]){n.doctype(I)}else{if(I=g[4]){n.pi(I,g[5])}}}}}}G=g.index+g[0].length}if(G=0;Q--){I=A[Q];if(I.valid){n.end(I.name)}}}}})(tinymce);(function(d){var c=/^[ \t\r\n]*$/,e={"#text":3,"#comment":8,"#cdata":4,"#pi":7,"#doctype":10,"#document-fragment":11};function a(k,l,j){var i,h,f=j?"lastChild":"firstChild",g=j?"prev":"next";if(k[f]){return k[f]}if(k!==l){i=k[g];if(i){return i}for(h=k.parent;h&&h!==l;h=h.parent){i=h[g];if(i){return i}}}}function b(f,g){this.name=f;this.type=g;if(g===1){this.attributes=[];this.attributes.map={}}}d.extend(b.prototype,{replace:function(g){var f=this;if(g.parent){g.remove()}f.insert(g,f);f.remove();return f},attr:function(h,l){var f=this,g,j,k;if(typeof h!=="string"){for(j in h){f.attr(j,h[j])}return f}if(g=f.attributes){if(l!==k){if(l===null){if(h in g.map){delete g.map[h];j=g.length;while(j--){if(g[j].name===h){g=g.splice(j,1);return f}}}return f}if(h in g.map){j=g.length;while(j--){if(g[j].name===h){g[j].value=l;break}}}else{g.push({name:h,value:l})}g.map[h]=l;return f}else{return g.map[h]}}},clone:function(){var g=this,n=new b(g.name,g.type),h,f,m,j,k;if(m=g.attributes){k=[];k.map={};for(h=0,f=m.length;h1){v.reverse();z=n=f.filterNode(v[0].clone());for(t=0;t0){P.value=l;P=P.prev}else{N=P.prev;P.remove();P=N}}}n=new b.html.SaxParser({validate:z,fix_self_closing:!z,cdata:function(l){B.append(J("#cdata",4)).value=l},text:function(O,l){var N;if(!K){O=O.replace(k," ");if(B.lastChild&&o[B.lastChild.name]){O=O.replace(E,"")}}if(O.length!==0){N=J("#text",3);N.raw=!!l;B.append(N).value=O}},comment:function(l){B.append(J("#comment",8)).value=l},pi:function(l,N){B.append(J(l,7)).value=N;H(B)},doctype:function(N){var l;l=B.append(J("#doctype",10));l.value=N;H(B)},start:function(l,V,O){var T,Q,P,N,R,W,U,S;P=z?h.getElementRule(l):{};if(P){T=J(P.outputName||l,1);T.attributes=V;T.shortEnded=O;B.append(T);S=p[B.name];if(S&&p[T.name]&&!S[T.name]){L.push(T)}Q=d.length;while(Q--){R=d[Q].name;if(R in V.map){F=c[R];if(F){F.push(T)}else{c[R]=[T]}}}if(o[l]){H(T)}if(!O){B=T}if(!K&&s[l]){K=true}}},end:function(l){var R,O,Q,N,P;O=z?h.getElementRule(l):{};if(O){if(o[l]){if(!K){R=B.firstChild;if(R&&R.type===3){Q=R.value.replace(E,"");if(Q.length>0){R.value=Q;R=R.next}else{N=R.next;R.remove();R=N}while(R&&R.type===3){Q=R.value;N=R.next;if(Q.length===0||y.test(Q)){R.remove();R=N}R=N}}R=B.lastChild;if(R&&R.type===3){Q=R.value.replace(t,"");if(Q.length>0){R.value=Q;R=R.prev}else{N=R.prev;R.remove();R=N}while(R&&R.type===3){Q=R.value;N=R.prev;if(Q.length===0||y.test(Q)){R.remove();R=N}R=N}}}R=B.prev;if(R&&R.type===3){Q=R.value.replace(E,"");if(Q.length>0){R.value=Q}else{R.remove()}}}if(K&&s[l]){K=false}if(O.removeEmpty||O.paddEmpty){if(B.isEmpty(u)){if(O.paddEmpty){B.empty().append(new a("#text","3")).value="\u00a0"}else{if(!B.attributes.map.name){P=B.parent;B.empty().remove();B=P;return}}}}B=B.parent}}},h);I=B=new a(m.context||g.root_name,11);n.parse(v);if(z&&L.length){if(!m.context){j(L)}else{m.invalid=true}}if(q&&I.name=="body"){G()}if(!m.invalid){for(M in i){F=e[M];A=i[M];x=A.length;while(x--){if(!A[x].parent){A.splice(x,1)}}for(D=0,C=F.length;D0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}c.push("<",m);if(k){for(n=0,j=k.length;n0){o=c[c.length-1];if(o.length>0&&o!=="\n"){c.push("\n")}}},end:function(h){var i;c.push("");if(a&&d[h]&&c.length>0){i=c[c.length-1];if(i.length>0&&i!=="\n"){c.push("\n")}}},text:function(i,h){if(i.length>0){c[c.length]=h?i:f(i)}},cdata:function(h){c.push("")},comment:function(h){c.push("")},pi:function(h,i){if(i){c.push("")}else{c.push("")}if(a){c.push("\n")}},doctype:function(h){c.push("",a?"\n":"")},reset:function(){c.length=0},getContent:function(){return c.join("").replace(/\n$/,"")}}};(function(a){a.html.Serializer=function(c,d){var b=this,e=new a.html.Writer(c);c=c||{};c.validate="validate" in c?c.validate:true;b.schema=d=d||new a.html.Schema();b.writer=e;b.serialize=function(h){var g,i;i=c.validate;g={3:function(k,j){e.text(k.value,k.raw)},8:function(j){e.comment(j.value)},7:function(j){e.pi(j.name,j.value)},10:function(j){e.doctype(j.value)},4:function(j){e.cdata(j.value)},11:function(j){if((j=j.firstChild)){do{f(j)}while(j=j.next)}}};e.reset();function f(k){var t=g[k.type],j,o,s,r,p,u,n,m,q;if(!t){j=k.name;o=k.shortEnded;s=k.attributes;if(i&&s&&s.length>1){u=[];u.map={};q=d.getElementRule(k.name);for(n=0,m=q.attributesOrder.length;n=8;k.boxModel=!e.isIE||o.compatMode=="CSS1Compat"||k.stdMode;k.hasOuterHTML="outerHTML" in o.createElement("a");k.settings=l=e.extend({keep_values:false,hex_colors:1},l);k.schema=l.schema;k.styles=new e.html.Styles({url_converter:l.url_converter,url_converter_scope:l.url_converter_scope},l.schema);if(e.isIE6){try{o.execCommand("BackgroundImageCache",false,true)}catch(m){k.cssFlicker=true}}k.fixDoc(o);k.events=l.ownEvents?new e.dom.EventUtils(l.proxy):e.dom.Event;e.addUnload(k.destroy,k);n=l.schema?l.schema.getBlockElements():{};k.isBlock=function(q){var p=q.nodeType;if(p){return !!(p===1&&n[q.nodeName])}return !!n[q]}},fixDoc:function(k){var j=this.settings,i;if(b&&j.schema){("abbr article aside audio canvas details figcaption figure footer header hgroup mark menu meter nav output progress section summary time video").replace(/\w+/g,function(l){k.createElement(l)});for(i in j.schema.getCustomElements()){k.createElement(i)}}},clone:function(k,i){var j=this,m,l;if(!b||k.nodeType!==1||i){return k.cloneNode(i)}l=j.doc;if(!i){m=l.createElement(k.nodeName);g(j.getAttribs(k),function(n){j.setAttrib(m,n.nodeName,j.getAttrib(k,n.nodeName))});return m}return m.firstChild},getRoot:function(){var i=this,j=i.settings;return(j&&i.get(j.root_element))||i.doc.body},getViewPort:function(j){var k,i;j=!j?this.win:j;k=j.document;i=this.boxModel?k.documentElement:k.body;return{x:j.pageXOffset||i.scrollLeft,y:j.pageYOffset||i.scrollTop,w:j.innerWidth||i.clientWidth,h:j.innerHeight||i.clientHeight}},getRect:function(l){var k,i=this,j;l=i.get(l);k=i.getPos(l);j=i.getSize(l);return{x:k.x,y:k.y,w:j.w,h:j.h}},getSize:function(l){var j=this,i,k;l=j.get(l);i=j.getStyle(l,"width");k=j.getStyle(l,"height");if(i.indexOf("px")===-1){i=0}if(k.indexOf("px")===-1){k=0}return{w:parseInt(i,10)||l.offsetWidth||l.clientWidth,h:parseInt(k,10)||l.offsetHeight||l.clientHeight}},getParent:function(k,j,i){return this.getParents(k,j,i,false)},getParents:function(s,m,k,q){var j=this,i,l=j.settings,p=[];s=j.get(s);q=q===undefined;if(l.strict_root){k=k||j.getRoot()}if(d(m,"string")){i=m;if(m==="*"){m=function(o){return o.nodeType==1}}else{m=function(o){return j.is(o,i)}}}while(s){if(s==k||!s.nodeType||s.nodeType===9){break}if(!m||m(s)){if(q){p.push(s)}else{return s}}s=s.parentNode}return q?p:null},get:function(i){var j;if(i&&this.doc&&typeof(i)=="string"){j=i;i=this.doc.getElementById(i);if(i&&i.id!==j){return this.doc.getElementsByName(j)[1]}}return i},getNext:function(j,i){return this._findSib(j,i,"nextSibling")},getPrev:function(j,i){return this._findSib(j,i,"previousSibling")},select:function(k,j){var i=this;return e.dom.Sizzle(k,i.get(j)||i.get(i.settings.root_element)||i.doc,[])},is:function(l,j){var k;if(l.length===undefined){if(j==="*"){return l.nodeType==1}if(c.test(j)){j=j.toLowerCase().split(/,/);l=l.nodeName.toLowerCase();for(k=j.length-1;k>=0;k--){if(j[k]==l){return true}}return false}}return e.dom.Sizzle.matches(j,l.nodeType?[l]:l).length>0},add:function(l,o,i,k,m){var j=this;return this.run(l,function(r){var q,n;q=d(o,"string")?j.doc.createElement(o):o;j.setAttribs(q,i);if(k){if(k.nodeType){q.appendChild(k)}else{j.setHTML(q,k)}}return !m?r.appendChild(q):q})},create:function(k,i,j){return this.add(this.doc.createElement(k),k,i,j,1)},createHTML:function(q,i,m){var p="",l=this,j;p+="<"+q;for(j in i){if(i.hasOwnProperty(j)){p+=" "+j+'="'+l.encode(i[j])+'"'}}if(typeof(m)!="undefined"){return p+">"+m+""}return p+" />"},remove:function(i,j){return this.run(i,function(l){var m,k=l.parentNode;if(!k){return null}if(j){while(m=l.firstChild){if(!e.isIE||m.nodeType!==3||m.nodeValue){k.insertBefore(m,l)}else{l.removeChild(m)}}}return k.removeChild(l)})},setStyle:function(l,i,j){var k=this;return k.run(l,function(o){var n,m;n=o.style;i=i.replace(/-(\D)/g,function(q,p){return p.toUpperCase()});if(k.pixelStyles.test(i)&&(e.is(j,"number")||/^[\-0-9\.]+$/.test(j))){j+="px"}switch(i){case"opacity":if(b){n.filter=j===""?"":"alpha(opacity="+(j*100)+")";if(!l.currentStyle||!l.currentStyle.hasLayout){n.display="inline-block"}}n[i]=n["-moz-opacity"]=n["-khtml-opacity"]=j||"";break;case"float":b?n.styleFloat=j:n.cssFloat=j;break;default:n[i]=j||""}if(k.settings.update_styles){k.setAttrib(o,"data-mce-style")}})},getStyle:function(l,i,k){l=this.get(l);if(!l){return}if(this.doc.defaultView&&k){i=i.replace(/[A-Z]/g,function(m){return"-"+m});try{return this.doc.defaultView.getComputedStyle(l,null).getPropertyValue(i)}catch(j){return null}}i=i.replace(/-(\D)/g,function(n,m){return m.toUpperCase()});if(i=="float"){i=b?"styleFloat":"cssFloat"}if(l.currentStyle&&k){return l.currentStyle[i]}return l.style?l.style[i]:undefined},setStyles:function(l,m){var j=this,k=j.settings,i;i=k.update_styles;k.update_styles=0;g(m,function(o,p){j.setStyle(l,p,o)});k.update_styles=i;if(k.update_styles){j.setAttrib(l,k.cssText)}},removeAllAttribs:function(i){return this.run(i,function(l){var k,j=l.attributes;for(k=j.length-1;k>=0;k--){l.removeAttributeNode(j.item(k))}})},setAttrib:function(k,l,i){var j=this;if(!k||!l){return}if(j.settings.strict){l=l.toLowerCase()}return this.run(k,function(p){var o=j.settings;var m=p.getAttribute(l);if(i!==null){switch(l){case"style":if(!d(i,"string")){g(i,function(q,r){j.setStyle(p,r,q)});return}if(o.keep_values){if(i&&!j._isRes(i)){p.setAttribute("data-mce-style",i,2)}else{p.removeAttribute("data-mce-style",2)}}p.style.cssText=i;break;case"class":p.className=i||"";break;case"src":case"href":if(o.keep_values){if(o.url_converter){i=o.url_converter.call(o.url_converter_scope||j,i,l,p)}j.setAttrib(p,"data-mce-"+l,i,2)}break;case"shape":p.setAttribute("data-mce-style",i);break}}if(d(i)&&i!==null&&i.length!==0){p.setAttribute(l,""+i,2)}else{p.removeAttribute(l,2)}if(tinyMCE.activeEditor&&m!=i){var n=tinyMCE.activeEditor;n.onSetAttrib.dispatch(n,p,l,i)}})},setAttribs:function(j,k){var i=this;return this.run(j,function(l){g(k,function(m,o){i.setAttrib(l,o,m)})})},getAttrib:function(m,o,k){var i,j=this,l;m=j.get(m);if(!m||m.nodeType!==1){return k===l?false:k}if(!d(k)){k=""}if(/^(src|href|style|coords|shape)$/.test(o)){i=m.getAttribute("data-mce-"+o);if(i){return i}}if(b&&j.props[o]){i=m[j.props[o]];i=i&&i.nodeValue?i.nodeValue:i}if(!i){i=m.getAttribute(o,2)}if(/^(checked|compact|declare|defer|disabled|ismap|multiple|nohref|noshade|nowrap|readonly|selected)$/.test(o)){if(m[j.props[o]]===true&&i===""){return o}return i?o:""}if(m.nodeName==="FORM"&&m.getAttributeNode(o)){return m.getAttributeNode(o).nodeValue}if(o==="style"){i=i||m.style.cssText;if(i){i=j.serializeStyle(j.parseStyle(i),m.nodeName);if(j.settings.keep_values&&!j._isRes(i)){m.setAttribute("data-mce-style",i)}}}if(f&&o==="class"&&i){i=i.replace(/(apple|webkit)\-[a-z\-]+/gi,"")}if(b){switch(o){case"rowspan":case"colspan":if(i===1){i=""}break;case"size":if(i==="+0"||i===20||i===0){i=""}break;case"width":case"height":case"vspace":case"checked":case"disabled":case"readonly":if(i===0){i=""}break;case"hspace":if(i===-1){i=""}break;case"maxlength":case"tabindex":if(i===32768||i===2147483647||i==="32768"){i=""}break;case"multiple":case"compact":case"noshade":case"nowrap":if(i===65535){return o}return k;case"shape":i=i.toLowerCase();break;default:if(o.indexOf("on")===0&&i){i=e._replace(/^function\s+\w+\(\)\s+\{\s+(.*)\s+\}$/,"$1",""+i)}}}return(i!==l&&i!==null&&i!=="")?""+i:k},getPos:function(q,l){var j=this,i=0,p=0,m,o=j.doc,k;q=j.get(q);l=l||o.body;if(q){if(q.getBoundingClientRect){q=q.getBoundingClientRect();m=j.boxModel?o.documentElement:o.body;i=q.left+(o.documentElement.scrollLeft||o.body.scrollLeft)-m.clientTop;p=q.top+(o.documentElement.scrollTop||o.body.scrollTop)-m.clientLeft;return{x:i,y:p}}k=q;while(k&&k!=l&&k.nodeType){i+=k.offsetLeft||0;p+=k.offsetTop||0;k=k.offsetParent}k=q.parentNode;while(k&&k!=l&&k.nodeType){i-=k.scrollLeft||0;p-=k.scrollTop||0;k=k.parentNode}}return{x:i,y:p}},parseStyle:function(i){return this.styles.parse(i)},serializeStyle:function(j,i){return this.styles.serialize(j,i)},loadCSS:function(i){var k=this,l=k.doc,j;if(!i){i=""}j=l.getElementsByTagName("head")[0];g(i.split(","),function(m){var n;if(k.files[m]){return}k.files[m]=true;n=k.create("link",{rel:"stylesheet",href:e._addVer(m)});if(b&&l.documentMode&&l.recalc){n.onload=function(){if(l.recalc){l.recalc()}n.onload=null}}j.appendChild(n)})},addClass:function(i,j){return this.run(i,function(k){var l;if(!j){return 0}if(this.hasClass(k,j)){return k.className}l=this.removeClass(k,j);return k.className=(l!=""?(l+" "):"")+j})},removeClass:function(k,l){var i=this,j;return i.run(k,function(n){var m;if(i.hasClass(n,l)){if(!j){j=new RegExp("(^|\\s+)"+l+"(\\s+|$)","g")}m=n.className.replace(j," ");m=e.trim(m!=" "?m:"");n.className=m;if(!m){n.removeAttribute("class");n.removeAttribute("className")}return m}return n.className})},hasClass:function(j,i){j=this.get(j);if(!j||!i){return false}return(" "+j.className+" ").indexOf(" "+i+" ")!==-1},show:function(i){return this.setStyle(i,"display","block")},hide:function(i){return this.setStyle(i,"display","none")},isHidden:function(i){i=this.get(i);return !i||i.style.display=="none"||this.getStyle(i,"display")=="none"},uniqueId:function(i){return(!i?"mce_":i)+(this.counter++)},setHTML:function(k,j){var i=this;return i.run(k,function(m){if(b){while(m.firstChild){m.removeChild(m.firstChild)}try{m.innerHTML="
    "+j;m.removeChild(m.firstChild)}catch(l){m=i.create("div");m.innerHTML="
    "+j;g(m.childNodes,function(o,n){if(n){m.appendChild(o)}})}}else{m.innerHTML=j}return j})},getOuterHTML:function(k){var j,i=this;k=i.get(k);if(!k){return null}if(k.nodeType===1&&i.hasOuterHTML){return k.outerHTML}j=(k.ownerDocument||i.doc).createElement("body");j.appendChild(k.cloneNode(true));return j.innerHTML},setOuterHTML:function(l,j,m){var i=this;function k(p,o,r){var s,q;q=r.createElement("body");q.innerHTML=o;s=q.lastChild;while(s){i.insertAfter(s.cloneNode(true),p);s=s.previousSibling}i.remove(p)}return this.run(l,function(o){o=i.get(o);if(o.nodeType==1){m=m||o.ownerDocument||i.doc;if(b){try{if(b&&o.nodeType==1){o.outerHTML=j}else{k(o,j,m)}}catch(n){k(o,j,m)}}else{k(o,j,m)}}})},decode:h.decode,encode:h.encodeAllRaw,insertAfter:function(i,j){j=this.get(j);return this.run(i,function(l){var k,m;k=j.parentNode;m=j.nextSibling;if(m){k.insertBefore(l,m)}else{k.appendChild(l)}return l})},replace:function(m,l,i){var j=this;if(d(l,"array")){m=m.cloneNode(true)}return j.run(l,function(k){if(i){g(e.grep(k.childNodes),function(n){m.appendChild(n)})}return k.parentNode.replaceChild(m,k)})},rename:function(l,i){var k=this,j;if(l.nodeName!=i.toUpperCase()){j=k.create(i);g(k.getAttribs(l),function(m){k.setAttrib(j,m.nodeName,k.getAttrib(l,m.nodeName))});k.replace(j,l,1)}return j||l},findCommonAncestor:function(k,i){var l=k,j;while(l){j=i;while(j&&l!=j){j=j.parentNode}if(l==j){break}l=l.parentNode}if(!l&&k.ownerDocument){return k.ownerDocument.documentElement}return l},toHex:function(i){var k=/^\s*rgb\s*?\(\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?,\s*?([0-9]+)\s*?\)\s*$/i.exec(i);function j(l){l=parseInt(l,10).toString(16);return l.length>1?l:"0"+l}if(k){i="#"+j(k[1])+j(k[2])+j(k[3]);return i}return i},getClasses:function(){var n=this,j=[],m,o={},p=n.settings.class_filter,l;if(n.classes){return n.classes}function q(i){g(i.imports,function(s){q(s)});g(i.cssRules||i.rules,function(s){switch(s.type||1){case 1:if(s.selectorText){g(s.selectorText.split(","),function(r){r=r.replace(/^\s*|\s*$|^\s\./g,"");if(/\.mce/.test(r)||!/\.[\w\-]+$/.test(r)){return}l=r;r=e._replace(/.*\.([a-z0-9_\-]+).*/i,"$1",r);if(p&&!(r=p(r,l))){return}if(!o[r]){j.push({"class":r});o[r]=1}})}break;case 3:q(s.styleSheet);break}})}try{g(n.doc.styleSheets,q)}catch(k){}if(j.length>0){n.classes=j}return j},run:function(l,k,j){var i=this,m;if(i.doc&&typeof(l)==="string"){l=i.get(l)}if(!l){return false}j=j||this;if(!l.nodeType&&(l.length||l.length===0)){m=[];g(l,function(o,n){if(o){if(typeof(o)=="string"){o=i.doc.getElementById(o)}m.push(k.call(j,o,n))}});return m}return k.call(j,l)},getAttribs:function(j){var i;j=this.get(j);if(!j){return[]}if(b){i=[];if(j.nodeName=="OBJECT"){return j.attributes}if(j.nodeName==="OPTION"&&this.getAttrib(j,"selected")){i.push({specified:1,nodeName:"selected"})}j.cloneNode(false).outerHTML.replace(/<\/?[\w:\-]+ ?|=[\"][^\"]+\"|=\'[^\']+\'|=[\w\-]+|>/gi,"").replace(/[\w:\-]+/gi,function(k){i.push({specified:1,nodeName:k})});return i}return j.attributes},isEmpty:function(m,k){var r=this,o,n,q,j,l,p=0;m=m.firstChild;if(m){j=new e.dom.TreeWalker(m,m.parentNode);k=k||r.schema?r.schema.getNonEmptyElements():null;do{q=m.nodeType;if(q===1){if(m.getAttribute("data-mce-bogus")){continue}l=m.nodeName.toLowerCase();if(k&&k[l]){if(l==="br"){p++;continue}return false}n=r.getAttribs(m);o=m.attributes.length;while(o--){l=m.attributes[o].nodeName;if(l==="name"||l==="data-mce-bookmark"){return false}}}if(q==8){return false}if((q===3&&!a.test(m.nodeValue))){return false}}while(m=j.next())}return p<=1},destroy:function(j){var i=this;i.win=i.doc=i.root=i.events=i.frag=null;if(!j){e.removeUnload(i.destroy)}},createRng:function(){var i=this.doc;return i.createRange?i.createRange():new e.dom.Range(this)},nodeIndex:function(m,n){var i=0,k,l,j;if(m){for(k=m.nodeType,m=m.previousSibling,l=m;m;m=m.previousSibling){j=m.nodeType;if(n&&j==3){if(j==k||!m.nodeValue.length){continue}}i++;k=j}}return i},split:function(m,l,p){var q=this,i=q.createRng(),n,k,o;function j(v){var t,s=v.childNodes,u=v.nodeType;function x(A){var z=A.previousSibling&&A.previousSibling.nodeName=="SPAN";var y=A.nextSibling&&A.nextSibling.nodeName=="SPAN";return z&&y}if(u==1&&v.getAttribute("data-mce-type")=="bookmark"){return}for(t=s.length-1;t>=0;t--){j(s[t])}if(u!=9){if(u==3&&v.nodeValue.length>0){var r=e.trim(v.nodeValue).length;if(!q.isBlock(v.parentNode)||r>0||r===0&&x(v)){return}}else{if(u==1){s=v.childNodes;if(s.length==1&&s[0]&&s[0].nodeType==1&&s[0].getAttribute("data-mce-type")=="bookmark"){v.parentNode.insertBefore(s[0],v)}if(s.length||/^(br|hr|input|img)$/i.test(v.nodeName)){return}}}q.remove(v)}return v}if(m&&l){i.setStart(m.parentNode,q.nodeIndex(m));i.setEnd(l.parentNode,q.nodeIndex(l));n=i.extractContents();i=q.createRng();i.setStart(l.parentNode,q.nodeIndex(l)+1);i.setEnd(m.parentNode,q.nodeIndex(m)+1);k=i.extractContents();o=m.parentNode;o.insertBefore(j(n),m);if(p){o.replaceChild(p,l)}else{o.insertBefore(l,m)}o.insertBefore(j(k),m);q.remove(m);return p||l}},bind:function(l,i,k,j){return this.events.add(l,i,k,j||this)},unbind:function(k,i,j){return this.events.remove(k,i,j)},fire:function(k,j,i){return this.events.fire(k,j,i)},getContentEditable:function(j){var i;if(j.nodeType!=1){return null}i=j.getAttribute("data-mce-contenteditable");if(i&&i!=="inherit"){return i}return j.contentEditable!=="inherit"?j.contentEditable:null},_findSib:function(l,i,j){var k=this,m=i;if(l){if(d(m,"string")){m=function(n){return k.is(n,i)}}for(l=l[j];l;l=l[j]){if(m(l)){return l}}}return null},_isRes:function(i){return/^(top|left|bottom|right|width|height)/i.test(i)||/;\s*(top|left|bottom|right|width|height)/i.test(i)}});e.DOM=new e.dom.DOMUtils(document,{process_html:0})})(tinymce);(function(a){function b(c){var O=this,e=c.doc,T=0,F=1,j=2,E=true,S=false,V="startOffset",h="startContainer",Q="endContainer",A="endOffset",k=tinymce.extend,n=c.nodeIndex;k(O,{startContainer:e,startOffset:0,endContainer:e,endOffset:0,collapsed:E,commonAncestorContainer:e,START_TO_START:0,START_TO_END:1,END_TO_END:2,END_TO_START:3,setStart:q,setEnd:s,setStartBefore:g,setStartAfter:J,setEndBefore:K,setEndAfter:u,collapse:B,selectNode:y,selectNodeContents:G,compareBoundaryPoints:v,deleteContents:p,extractContents:I,cloneContents:d,insertNode:D,surroundContents:N,cloneRange:L});function x(){return e.createDocumentFragment()}function q(W,t){C(E,W,t)}function s(W,t){C(S,W,t)}function g(t){q(t.parentNode,n(t))}function J(t){q(t.parentNode,n(t)+1)}function K(t){s(t.parentNode,n(t))}function u(t){s(t.parentNode,n(t)+1)}function B(t){if(t){O[Q]=O[h];O[A]=O[V]}else{O[h]=O[Q];O[V]=O[A]}O.collapsed=E}function y(t){g(t);u(t)}function G(t){q(t,0);s(t,t.nodeType===1?t.childNodes.length:t.nodeValue.length)}function v(Z,t){var ac=O[h],X=O[V],ab=O[Q],W=O[A],aa=t.startContainer,ae=t.startOffset,Y=t.endContainer,ad=t.endOffset;if(Z===0){return H(ac,X,aa,ae)}if(Z===1){return H(ab,W,aa,ae)}if(Z===2){return H(ab,W,Y,ad)}if(Z===3){return H(ac,X,Y,ad)}}function p(){l(j)}function I(){return l(T)}function d(){return l(F)}function D(Z){var W=this[h],t=this[V],Y,X;if((W.nodeType===3||W.nodeType===4)&&W.nodeValue){if(!t){W.parentNode.insertBefore(Z,W)}else{if(t>=W.nodeValue.length){c.insertAfter(Z,W)}else{Y=W.splitText(t);W.parentNode.insertBefore(Z,Y)}}}else{if(W.childNodes.length>0){X=W.childNodes[t]}if(X){W.insertBefore(Z,X)}else{W.appendChild(Z)}}}function N(W){var t=O.extractContents();O.insertNode(W);W.appendChild(t);O.selectNode(W)}function L(){return k(new b(c),{startContainer:O[h],startOffset:O[V],endContainer:O[Q],endOffset:O[A],collapsed:O.collapsed,commonAncestorContainer:O.commonAncestorContainer})}function P(t,W){var X;if(t.nodeType==3){return t}if(W<0){return t}X=t.firstChild;while(X&&W>0){--W;X=X.nextSibling}if(X){return X}return t}function m(){return(O[h]==O[Q]&&O[V]==O[A])}function H(Y,aa,W,Z){var ab,X,t,ac,ae,ad;if(Y==W){if(aa==Z){return 0}if(aa0){O.collapse(W)}}else{O.collapse(W)}O.collapsed=m();O.commonAncestorContainer=c.findCommonAncestor(O[h],O[Q])}function l(ac){var ab,Y=0,ae=0,W,aa,X,Z,t,ad;if(O[h]==O[Q]){return f(ac)}for(ab=O[Q],W=ab.parentNode;W;ab=W,W=W.parentNode){if(W==O[h]){return r(ab,ac)}++Y}for(ab=O[h],W=ab.parentNode;W;ab=W,W=W.parentNode){if(W==O[Q]){return U(ab,ac)}++ae}aa=ae-Y;X=O[h];while(aa>0){X=X.parentNode;aa--}Z=O[Q];while(aa<0){Z=Z.parentNode;aa++}for(t=X.parentNode,ad=Z.parentNode;t!=ad;t=t.parentNode,ad=ad.parentNode){X=t;Z=ad}return o(X,Z,ac)}function f(ab){var ad,ae,t,X,Y,ac,Z,W,aa;if(ab!=j){ad=x()}if(O[V]==O[A]){return ad}if(O[h].nodeType==3){ae=O[h].nodeValue;t=ae.substring(O[V],O[A]);if(ab!=F){X=O[h];W=O[V];aa=O[A]-O[V];if(W===0&&aa>=X.nodeValue.length-1){X.parentNode.removeChild(X)}else{X.deleteData(W,aa)}O.collapse(E)}if(ab==j){return}if(t.length>0){ad.appendChild(e.createTextNode(t))}return ad}X=P(O[h],O[V]);Y=O[A]-O[V];while(X&&Y>0){ac=X.nextSibling;Z=z(X,ab);if(ad){ad.appendChild(Z)}--Y;X=ac}if(ab!=F){O.collapse(E)}return ad}function r(ac,Z){var ab,aa,W,t,Y,X;if(Z!=j){ab=x()}aa=i(ac,Z);if(ab){ab.appendChild(aa)}W=n(ac);t=W-O[V];if(t<=0){if(Z!=F){O.setEndBefore(ac);O.collapse(S)}return ab}aa=ac.previousSibling;while(t>0){Y=aa.previousSibling;X=z(aa,Z);if(ab){ab.insertBefore(X,ab.firstChild)}--t;aa=Y}if(Z!=F){O.setEndBefore(ac);O.collapse(S)}return ab}function U(aa,Z){var ac,W,ab,t,Y,X;if(Z!=j){ac=x()}ab=R(aa,Z);if(ac){ac.appendChild(ab)}W=n(aa);++W;t=O[A]-W;ab=aa.nextSibling;while(ab&&t>0){Y=ab.nextSibling;X=z(ab,Z);if(ac){ac.appendChild(X)}--t;ab=Y}if(Z!=F){O.setStartAfter(aa);O.collapse(E)}return ac}function o(aa,t,ad){var X,af,Z,ab,ac,W,ae,Y;if(ad!=j){af=x()}X=R(aa,ad);if(af){af.appendChild(X)}Z=aa.parentNode;ab=n(aa);ac=n(t);++ab;W=ac-ab;ae=aa.nextSibling;while(W>0){Y=ae.nextSibling;X=z(ae,ad);if(af){af.appendChild(X)}ae=Y;--W}X=i(t,ad);if(af){af.appendChild(X)}if(ad!=F){O.setStartAfter(aa);O.collapse(E)}return af}function i(ab,ac){var X=P(O[Q],O[A]-1),ad,aa,Z,t,W,Y=X!=O[Q];if(X==ab){return M(X,Y,S,ac)}ad=X.parentNode;aa=M(ad,S,S,ac);while(ad){while(X){Z=X.previousSibling;t=M(X,Y,S,ac);if(ac!=j){aa.insertBefore(t,aa.firstChild)}Y=E;X=Z}if(ad==ab){return aa}X=ad.previousSibling;ad=ad.parentNode;W=M(ad,S,S,ac);if(ac!=j){W.appendChild(aa)}aa=W}}function R(ab,ac){var Y=P(O[h],O[V]),Z=Y!=O[h],ad,aa,X,t,W;if(Y==ab){return M(Y,Z,E,ac)}ad=Y.parentNode;aa=M(ad,S,E,ac);while(ad){while(Y){X=Y.nextSibling;t=M(Y,Z,E,ac);if(ac!=j){aa.appendChild(t)}Z=E;Y=X}if(ad==ab){return aa}Y=ad.nextSibling;ad=ad.parentNode;W=M(ad,S,E,ac);if(ac!=j){W.appendChild(aa)}aa=W}}function M(t,Z,ac,ad){var Y,X,aa,W,ab;if(Z){return z(t,ad)}if(t.nodeType==3){Y=t.nodeValue;if(ac){W=O[V];X=Y.substring(W);aa=Y.substring(0,W)}else{W=O[A];X=Y.substring(0,W);aa=Y.substring(W)}if(ad!=F){t.nodeValue=aa}if(ad==j){return}ab=c.clone(t,S);ab.nodeValue=X;return ab}if(ad==j){return}return c.clone(t,S)}function z(W,t){if(t!=j){return t==F?c.clone(W,E):W}W.parentNode.removeChild(W)}}a.Range=b})(tinymce.dom);(function(){function a(d){var b=this,h=d.dom,c=true,f=false;function e(i,j){var k,t=0,q,n,m,l,o,r,p=-1,s;k=i.duplicate();k.collapse(j);s=k.parentElement();if(s.ownerDocument!==d.dom.doc){return}while(s.contentEditable==="false"){s=s.parentNode}if(!s.hasChildNodes()){return{node:s,inside:1}}m=s.children;q=m.length-1;while(t<=q){r=Math.floor((t+q)/2);l=m[r];k.moveToElementText(l);p=k.compareEndPoints(j?"StartToStart":"EndToEnd",i);if(p>0){q=r-1}else{if(p<0){t=r+1}else{return{node:l}}}}if(p<0){if(!l){k.moveToElementText(s);k.collapse(true);l=s;n=true}else{k.collapse(false)}o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",1)===0||s!=k.parentElement()){break}o++}}else{k.collapse(true);o=0;while(k.compareEndPoints(j?"StartToStart":"StartToEnd",i)!==0){if(k.move("character",-1)===0||s!=k.parentElement()){break}o++}}return{node:l,position:p,offset:o,inside:n}}function g(){var i=d.getRng(),r=h.createRng(),l,k,p,q,m,j;l=i.item?i.item(0):i.parentElement();if(l.ownerDocument!=h.doc){return r}k=d.isCollapsed();if(i.item){r.setStart(l.parentNode,h.nodeIndex(l));r.setEnd(r.startContainer,r.startOffset+1);return r}function o(A){var u=e(i,A),s,y,z=0,x,v,t;s=u.node;y=u.offset;if(u.inside&&!s.hasChildNodes()){r[A?"setStart":"setEnd"](s,0);return}if(y===v){r[A?"setStartBefore":"setEndAfter"](s);return}if(u.position<0){x=u.inside?s.firstChild:s.nextSibling;if(!x){r[A?"setStartAfter":"setEndAfter"](s);return}if(!y){if(x.nodeType==3){r[A?"setStart":"setEnd"](x,0)}else{r[A?"setStartBefore":"setEndBefore"](x)}return}while(x){t=x.nodeValue;z+=t.length;if(z>=y){s=x;z-=y;z=t.length-z;break}x=x.nextSibling}}else{x=s.previousSibling;if(!x){return r[A?"setStartBefore":"setEndBefore"](s)}if(!y){if(s.nodeType==3){r[A?"setStart":"setEnd"](x,s.nodeValue.length)}else{r[A?"setStartAfter":"setEndAfter"](x)}return}while(x){z+=x.nodeValue.length;if(z>=y){s=x;z-=y;break}x=x.previousSibling}}r[A?"setStart":"setEnd"](s,z)}try{o(true);if(!k){o()}}catch(n){if(n.number==-2147024809){m=b.getBookmark(2);p=i.duplicate();p.collapse(true);l=p.parentElement();if(!k){p=i.duplicate();p.collapse(false);q=p.parentElement();q.innerHTML=q.innerHTML}l.innerHTML=l.innerHTML;b.moveToBookmark(m);i=d.getRng();o(true);if(!k){o()}}else{throw n}}return r}this.getBookmark=function(m){var j=d.getRng(),o,i,l={};function n(u){var t,p,s,r,q=[];t=u.parentNode;p=h.getRoot().parentNode;while(t!=p&&t.nodeType!==9){s=t.children;r=s.length;while(r--){if(u===s[r]){q.push(r);break}}u=t;t=t.parentNode}return q}function k(q){var p;p=e(j,q);if(p){return{position:p.position,offset:p.offset,indexes:n(p.node),inside:p.inside}}}if(m===2){if(!j.item){l.start=k(true);if(!d.isCollapsed()){l.end=k()}}else{l.start={ctrl:true,indexes:n(j.item(0))}}}return l};this.moveToBookmark=function(k){var j,i=h.doc.body;function m(o){var r,q,n,p;r=h.getRoot();for(q=o.length-1;q>=0;q--){p=r.children;n=o[q];if(n<=p.length-1){r=p[n]}}return r}function l(r){var n=k[r?"start":"end"],q,p,o;if(n){q=n.position>0;p=i.createTextRange();p.moveToElementText(m(n.indexes));offset=n.offset;if(offset!==o){p.collapse(n.inside||q);p.moveStart("character",q?-offset:offset)}else{p.collapse(r)}j.setEndPoint(r?"StartToStart":"EndToStart",p);if(r){j.collapse(true)}}}if(k.start){if(k.start.ctrl){j=i.createControlRange();j.addElement(m(k.start.indexes));j.select()}else{j=i.createTextRange();l(true);l();j.select()}}};this.addRange=function(i){var n,l,k,p,s,q,r=d.dom.doc,m=r.body;function j(z){var u,y,t,x,v;t=h.create("a");u=z?k:s;y=z?p:q;x=n.duplicate();if(u==r||u==r.documentElement){u=m;y=0}if(u.nodeType==3){u.parentNode.insertBefore(t,u);x.moveToElementText(t);x.moveStart("character",y);h.remove(t);n.setEndPoint(z?"StartToStart":"EndToEnd",x)}else{v=u.childNodes;if(v.length){if(y>=v.length){h.insertAfter(t,v[v.length-1])}else{u.insertBefore(t,v[y])}x.moveToElementText(t)}else{if(u.canHaveHTML){u.innerHTML="\uFEFF";t=u.firstChild;x.moveToElementText(t);x.collapse(f)}}n.setEndPoint(z?"StartToStart":"EndToEnd",x);h.remove(t)}}k=i.startContainer;p=i.startOffset;s=i.endContainer;q=i.endOffset;n=m.createTextRange();if(k==s&&k.nodeType==1){if(p==q&&!k.hasChildNodes()){if(k.canHaveHTML){k.innerHTML="\uFEFF\uFEFF";n.moveToElementText(k.lastChild);n.select();h.doc.selection.clear();k.innerHTML="";return}else{p=h.nodeIndex(k);k=k.parentNode}}if(p==q-1){try{l=m.createControlRange();l.addElement(k.childNodes[p]);l.select();return}catch(o){}}}j(true);j();n.select()};this.getRangeAt=g}tinymce.dom.TridentSelection=a})();(function(){var n=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,i="sizcache",o=0,r=Object.prototype.toString,h=false,g=true,q=/\\/g,u=/\r\n/g,x=/\W/;[0,0].sort(function(){g=false;return 0});var d=function(C,e,F,G){F=F||[];e=e||document;var I=e;if(e.nodeType!==1&&e.nodeType!==9){return[]}if(!C||typeof C!=="string"){return F}var z,K,N,y,J,M,L,E,B=true,A=d.isXML(e),D=[],H=C;do{n.exec("");z=n.exec(H);if(z){H=z[3];D.push(z[1]);if(z[2]){y=z[3];break}}}while(z);if(D.length>1&&j.exec(C)){if(D.length===2&&k.relative[D[0]]){K=s(D[0]+D[1],e,G)}else{K=k.relative[D[0]]?[e]:d(D.shift(),e);while(D.length){C=D.shift();if(k.relative[C]){C+=D.shift()}K=s(C,K,G)}}}else{if(!G&&D.length>1&&e.nodeType===9&&!A&&k.match.ID.test(D[0])&&!k.match.ID.test(D[D.length-1])){J=d.find(D.shift(),e,A);e=J.expr?d.filter(J.expr,J.set)[0]:J.set[0]}if(e){J=G?{expr:D.pop(),set:l(G)}:d.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&e.parentNode?e.parentNode:e,A);K=J.expr?d.filter(J.expr,J.set):J.set;if(D.length>0){N=l(K)}else{B=false}while(D.length){M=D.pop();L=M;if(!k.relative[M]){M=""}else{L=D.pop()}if(L==null){L=e}k.relative[M](N,L,A)}}else{N=D=[]}}if(!N){N=K}if(!N){d.error(M||C)}if(r.call(N)==="[object Array]"){if(!B){F.push.apply(F,N)}else{if(e&&e.nodeType===1){for(E=0;N[E]!=null;E++){if(N[E]&&(N[E]===true||N[E].nodeType===1&&d.contains(e,N[E]))){F.push(K[E])}}}else{for(E=0;N[E]!=null;E++){if(N[E]&&N[E].nodeType===1){F.push(K[E])}}}}}else{l(N,F)}if(y){d(y,I,F,G);d.uniqueSort(F)}return F};d.uniqueSort=function(y){if(p){h=g;y.sort(p);if(h){for(var e=1;e0};d.find=function(E,e,F){var D,z,B,A,C,y;if(!E){return[]}for(z=0,B=k.order.length;z":function(D,y){var C,B=typeof y==="string",z=0,e=D.length;if(B&&!x.test(y)){y=y.toLowerCase();for(;z=0)){if(!z){e.push(C)}}else{if(z){y[B]=false}}}}return false},ID:function(e){return e[1].replace(q,"")},TAG:function(y,e){return y[1].replace(q,"").toLowerCase()},CHILD:function(e){if(e[1]==="nth"){if(!e[2]){d.error(e[0])}e[2]=e[2].replace(/^\+|\s*/g,"");var y=/(-?)(\d*)(?:n([+\-]?\d*))?/.exec(e[2]==="even"&&"2n"||e[2]==="odd"&&"2n+1"||!/\D/.test(e[2])&&"0n+"+e[2]||e[2]);e[2]=(y[1]+(y[2]||1))-0;e[3]=y[3]-0}else{if(e[2]){d.error(e[0])}}e[0]=o++;return e},ATTR:function(B,y,z,e,C,D){var A=B[1]=B[1].replace(q,"");if(!D&&k.attrMap[A]){B[1]=k.attrMap[A]}B[4]=(B[4]||B[5]||"").replace(q,"");if(B[2]==="~="){B[4]=" "+B[4]+" "}return B},PSEUDO:function(B,y,z,e,C){if(B[1]==="not"){if((n.exec(B[3])||"").length>1||/^\w/.test(B[3])){B[3]=d(B[3],null,null,y)}else{var A=d.filter(B[3],y,z,true^C);if(!z){e.push.apply(e,A)}return false}}else{if(k.match.POS.test(B[0])||k.match.CHILD.test(B[0])){return true}}return B},POS:function(e){e.unshift(true);return e}},filters:{enabled:function(e){return e.disabled===false&&e.type!=="hidden"},disabled:function(e){return e.disabled===true},checked:function(e){return e.checked===true},selected:function(e){if(e.parentNode){e.parentNode.selectedIndex}return e.selected===true},parent:function(e){return !!e.firstChild},empty:function(e){return !e.firstChild},has:function(z,y,e){return !!d(e[3],z).length},header:function(e){return(/h\d/i).test(e.nodeName)},text:function(z){var e=z.getAttribute("type"),y=z.type;return z.nodeName.toLowerCase()==="input"&&"text"===y&&(e===y||e===null)},radio:function(e){return e.nodeName.toLowerCase()==="input"&&"radio"===e.type},checkbox:function(e){return e.nodeName.toLowerCase()==="input"&&"checkbox"===e.type},file:function(e){return e.nodeName.toLowerCase()==="input"&&"file"===e.type},password:function(e){return e.nodeName.toLowerCase()==="input"&&"password"===e.type},submit:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"submit"===y.type},image:function(e){return e.nodeName.toLowerCase()==="input"&&"image"===e.type},reset:function(y){var e=y.nodeName.toLowerCase();return(e==="input"||e==="button")&&"reset"===y.type},button:function(y){var e=y.nodeName.toLowerCase();return e==="input"&&"button"===y.type||e==="button"},input:function(e){return(/input|select|textarea|button/i).test(e.nodeName)},focus:function(e){return e===e.ownerDocument.activeElement}},setFilters:{first:function(y,e){return e===0},last:function(z,y,e,A){return y===A.length-1},even:function(y,e){return e%2===0},odd:function(y,e){return e%2===1},lt:function(z,y,e){return ye[3]-0},nth:function(z,y,e){return e[3]-0===y},eq:function(z,y,e){return e[3]-0===y}},filter:{PSEUDO:function(z,E,D,F){var e=E[1],y=k.filters[e];if(y){return y(z,D,E,F)}else{if(e==="contains"){return(z.textContent||z.innerText||b([z])||"").indexOf(E[3])>=0}else{if(e==="not"){var A=E[3];for(var C=0,B=A.length;C=0)}}},ID:function(y,e){return y.nodeType===1&&y.getAttribute("id")===e},TAG:function(y,e){return(e==="*"&&y.nodeType===1)||!!y.nodeName&&y.nodeName.toLowerCase()===e},CLASS:function(y,e){return(" "+(y.className||y.getAttribute("class"))+" ").indexOf(e)>-1},ATTR:function(C,A){var z=A[1],e=d.attr?d.attr(C,z):k.attrHandle[z]?k.attrHandle[z](C):C[z]!=null?C[z]:C.getAttribute(z),D=e+"",B=A[2],y=A[4];return e==null?B==="!=":!B&&d.attr?e!=null:B==="="?D===y:B==="*="?D.indexOf(y)>=0:B==="~="?(" "+D+" ").indexOf(y)>=0:!y?D&&e!==false:B==="!="?D!==y:B==="^="?D.indexOf(y)===0:B==="$="?D.substr(D.length-y.length)===y:B==="|="?D===y||D.substr(0,y.length+1)===y+"-":false},POS:function(B,y,z,C){var e=y[2],A=k.setFilters[e];if(A){return A(B,z,y,C)}}}};var j=k.match.POS,c=function(y,e){return"\\"+(e-0+1)};for(var f in k.match){k.match[f]=new RegExp(k.match[f].source+(/(?![^\[]*\])(?![^\(]*\))/.source));k.leftMatch[f]=new RegExp(/(^(?:.|\r|\n)*?)/.source+k.match[f].source.replace(/\\(\d+)/g,c))}k.match.globalPOS=j;var l=function(y,e){y=Array.prototype.slice.call(y,0);if(e){e.push.apply(e,y);return e}return y};try{Array.prototype.slice.call(document.documentElement.childNodes,0)[0].nodeType}catch(v){l=function(B,A){var z=0,y=A||[];if(r.call(B)==="[object Array]"){Array.prototype.push.apply(y,B)}else{if(typeof B.length==="number"){for(var e=B.length;z";e.insertBefore(y,e.firstChild);if(document.getElementById(z)){k.find.ID=function(B,C,D){if(typeof C.getElementById!=="undefined"&&!D){var A=C.getElementById(B[1]);return A?A.id===B[1]||typeof A.getAttributeNode!=="undefined"&&A.getAttributeNode("id").nodeValue===B[1]?[A]:undefined:[]}};k.filter.ID=function(C,A){var B=typeof C.getAttributeNode!=="undefined"&&C.getAttributeNode("id");return C.nodeType===1&&B&&B.nodeValue===A}}e.removeChild(y);e=y=null})();(function(){var e=document.createElement("div");e.appendChild(document.createComment(""));if(e.getElementsByTagName("*").length>0){k.find.TAG=function(y,C){var B=C.getElementsByTagName(y[1]);if(y[1]==="*"){var A=[];for(var z=0;B[z];z++){if(B[z].nodeType===1){A.push(B[z])}}B=A}return B}}e.innerHTML="";if(e.firstChild&&typeof e.firstChild.getAttribute!=="undefined"&&e.firstChild.getAttribute("href")!=="#"){k.attrHandle.href=function(y){return y.getAttribute("href",2)}}e=null})();if(document.querySelectorAll){(function(){var e=d,A=document.createElement("div"),z="__sizzle__";A.innerHTML="

    ";if(A.querySelectorAll&&A.querySelectorAll(".TEST").length===0){return}d=function(L,C,G,K){C=C||document;if(!K&&!d.isXML(C)){var J=/^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(L);if(J&&(C.nodeType===1||C.nodeType===9)){if(J[1]){return l(C.getElementsByTagName(L),G)}else{if(J[2]&&k.find.CLASS&&C.getElementsByClassName){return l(C.getElementsByClassName(J[2]),G)}}}if(C.nodeType===9){if(L==="body"&&C.body){return l([C.body],G)}else{if(J&&J[3]){var F=C.getElementById(J[3]);if(F&&F.parentNode){if(F.id===J[3]){return l([F],G)}}else{return l([],G)}}}try{return l(C.querySelectorAll(L),G)}catch(H){}}else{if(C.nodeType===1&&C.nodeName.toLowerCase()!=="object"){var D=C,E=C.getAttribute("id"),B=E||z,N=C.parentNode,M=/^\s*[+~]/.test(L);if(!E){C.setAttribute("id",B)}else{B=B.replace(/'/g,"\\$&")}if(M&&N){C=C.parentNode}try{if(!M||N){return l(C.querySelectorAll("[id='"+B+"'] "+L),G)}}catch(I){}finally{if(!E){D.removeAttribute("id")}}}}}return e(L,C,G,K)};for(var y in e){d[y]=e[y]}A=null})()}(function(){var e=document.documentElement,z=e.matchesSelector||e.mozMatchesSelector||e.webkitMatchesSelector||e.msMatchesSelector;if(z){var B=!z.call(document.createElement("div"),"div"),y=false;try{z.call(document.documentElement,"[test!='']:sizzle")}catch(A){y=true}d.matchesSelector=function(D,F){F=F.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!d.isXML(D)){try{if(y||!k.match.PSEUDO.test(F)&&!/!=/.test(F)){var C=z.call(D,F);if(C||!B||D.document&&D.document.nodeType!==11){return C}}}catch(E){}}return d(F,null,null,[D]).length>0}}})();(function(){var e=document.createElement("div");e.innerHTML="
    ";if(!e.getElementsByClassName||e.getElementsByClassName("e").length===0){return}e.lastChild.className="e";if(e.getElementsByClassName("e").length===1){return}k.order.splice(1,0,"CLASS");k.find.CLASS=function(y,z,A){if(typeof z.getElementsByClassName!=="undefined"&&!A){return z.getElementsByClassName(y[1])}};e=null})();function a(y,D,C,G,E,F){for(var A=0,z=G.length;A0){B=e;break}}}e=e[y]}G[A]=B}}}if(document.documentElement.contains){d.contains=function(y,e){return y!==e&&(y.contains?y.contains(e):true)}}else{if(document.documentElement.compareDocumentPosition){d.contains=function(y,e){return !!(y.compareDocumentPosition(e)&16)}}else{d.contains=function(){return false}}}d.isXML=function(e){var y=(e?e.ownerDocument||e:0).documentElement;return y?y.nodeName!=="HTML":false};var s=function(z,e,D){var C,E=[],B="",F=e.nodeType?[e]:e;while((C=k.match.PSEUDO.exec(z))){B+=C[0];z=z.replace(k.match.PSEUDO,"")}z=k.relative[z]?z+"*":z;for(var A=0,y=F.length;A"+(i.item?i.item(0).outerHTML:i.htmlText);m.removeChild(m.firstChild)}else{m.innerHTML=i.toString()}}if(/^\s/.test(m.innerHTML)){j=" "}if(/\s+$/.test(m.innerHTML)){l=" "}h.getInner=true;h.content=g.isCollapsed()?"":j+g.serializer.serialize(m,h)+l;g.onGetContent.dispatch(g,h);return h.content},setContent:function(h,j){var o=this,g=o.getRng(),k,l=o.win.document,n,m;j=j||{format:"html"};j.set=true;h=j.content=h;if(!j.no_events){o.onBeforeSetContent.dispatch(o,j)}h=j.content;if(g.insertNode){h+='_';if(g.startContainer==l&&g.endContainer==l){l.body.innerHTML=h}else{g.deleteContents();if(l.body.childNodes.length===0){l.body.innerHTML=h}else{if(g.createContextualFragment){g.insertNode(g.createContextualFragment(h))}else{n=l.createDocumentFragment();m=l.createElement("div");n.appendChild(m);m.outerHTML=h;g.insertNode(n)}}}k=o.dom.get("__caret");g=l.createRange();g.setStartBefore(k);g.setEndBefore(k);o.setRng(g);o.dom.remove("__caret");try{o.setRng(g)}catch(i){}}else{if(g.item){l.execCommand("Delete",false,null);g=o.getRng()}if(/^\s+/.test(h)){g.pasteHTML('_'+h);o.dom.remove("__mce_tmp")}else{g.pasteHTML(h)}}if(!j.no_events){o.onSetContent.dispatch(o,j)}},getStart:function(){var h=this.getRng(),i,g,k,j;if(h.duplicate||h.item){if(h.item){return h.item(0)}k=h.duplicate();k.collapse(1);i=k.parentElement();g=j=h.parentElement();while(j=j.parentNode){if(j==i){i=g;break}}return i}else{i=h.startContainer;if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[Math.min(i.childNodes.length-1,h.startOffset)]}if(i&&i.nodeType==3){return i.parentNode}return i}},getEnd:function(){var h=this,i=h.getRng(),j,g;if(i.duplicate||i.item){if(i.item){return i.item(0)}i=i.duplicate();i.collapse(0);j=i.parentElement();if(j&&j.nodeName=="BODY"){return j.lastChild||j}return j}else{j=i.endContainer;g=i.endOffset;if(j.nodeType==1&&j.hasChildNodes()){j=j.childNodes[g>0?g-1:g]}if(j&&j.nodeType==3){return j.parentNode}return j}},getBookmark:function(s,v){var y=this,n=y.dom,h,k,j,o,i,p,q,m="\uFEFF",x;function g(z,A){var t=0;e(n.select(z),function(C,B){if(C==A){t=B}});return t}function u(t){function z(E){var A,D,C,B=E?"start":"end";A=t[B+"Container"];D=t[B+"Offset"];if(A.nodeType==1&&A.nodeName=="TR"){C=A.childNodes;A=C[Math.min(E?D:D-1,C.length-1)];if(A){D=E?0:A.childNodes.length;t["set"+(E?"Start":"End")](A,D)}}}z(true);z();return t}function l(){var z=y.getRng(true),t=n.getRoot(),A={};function B(E,J){var D=E[J?"startContainer":"endContainer"],I=E[J?"startOffset":"endOffset"],C=[],F,H,G=0;if(D.nodeType==3){if(v){for(F=D.previousSibling;F&&F.nodeType==3;F=F.previousSibling){I+=F.nodeValue.length}}C.push(I)}else{H=D.childNodes;if(I>=H.length&&H.length){G=1;I=Math.max(0,H.length-1)}C.push(y.dom.nodeIndex(H[I],v)+G)}for(;D&&D!=t;D=D.parentNode){C.push(y.dom.nodeIndex(D,v))}return C}A.start=B(z,true);if(!y.isCollapsed()){A.end=B(z)}return A}if(s==2){if(y.tridentSel){return y.tridentSel.getBookmark(s)}return l()}if(s){return{rng:y.getRng()}}h=y.getRng();j=n.uniqueId();o=tinyMCE.activeEditor.selection.isCollapsed();x="overflow:hidden;line-height:0px";if(h.duplicate||h.item){if(!h.item){k=h.duplicate();try{h.collapse();h.pasteHTML(''+m+"");if(!o){k.collapse(false);h.moveToElementText(k.parentElement());if(h.compareEndPoints("StartToEnd",k)===0){k.move("character",-1)}k.pasteHTML(''+m+"")}}catch(r){return null}}else{p=h.item(0);i=p.nodeName;return{name:i,index:g(i,p)}}}else{p=y.getNode();i=p.nodeName;if(i=="IMG"){return{name:i,index:g(i,p)}}k=u(h.cloneRange());if(!o){k.collapse(false);k.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_end",style:x},m))}h=u(h);h.collapse(true);h.insertNode(n.create("span",{"data-mce-type":"bookmark",id:j+"_start",style:x},m))}y.moveToBookmark({id:j,keep:1});return{id:j}},moveToBookmark:function(o){var s=this,m=s.dom,j,i,g,r,k,u,p,q;function h(A){var t=o[A?"start":"end"],x,y,z,v;if(t){z=t[0];for(y=r,x=t.length-1;x>=1;x--){v=y.childNodes;if(t[x]>v.length-1){return}y=v[t[x]]}if(y.nodeType===3){z=Math.min(t[0],y.nodeValue.length)}if(y.nodeType===1){z=Math.min(t[0],y.childNodes.length)}if(A){g.setStart(y,z)}else{g.setEnd(y,z)}}return true}function l(B){var v=m.get(o.id+"_"+B),A,t,y,z,x=o.keep;if(v){A=v.parentNode;if(B=="start"){if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}k=u=A;p=q=t}else{if(!x){t=m.nodeIndex(v)}else{A=v.firstChild;t=1}u=A;q=t}if(!x){z=v.previousSibling;y=v.nextSibling;e(d.grep(v.childNodes),function(C){if(C.nodeType==3){C.nodeValue=C.nodeValue.replace(/\uFEFF/g,"")}});while(v=m.get(o.id+"_"+B)){m.remove(v,1)}if(z&&y&&z.nodeType==y.nodeType&&z.nodeType==3&&!d.isOpera){t=z.nodeValue.length;z.appendData(y.nodeValue);m.remove(y);if(B=="start"){k=u=z;p=q=t}else{u=z;q=t}}}}}function n(t){if(m.isBlock(t)&&!t.innerHTML&&!b){t.innerHTML='
    '}return t}if(o){if(o.start){g=m.createRng();r=m.getRoot();if(s.tridentSel){return s.tridentSel.moveToBookmark(o)}if(h(true)&&h()){s.setRng(g)}}else{if(o.id){l("start");l("end");if(k){g=m.createRng();g.setStart(n(k),p);g.setEnd(n(u),q);s.setRng(g)}}else{if(o.name){s.select(m.select(o.name)[o.index])}else{if(o.rng){s.setRng(o.rng)}}}}}},select:function(l,k){var j=this,m=j.dom,h=m.createRng(),g;function i(n,p){var o=new a(n,n);do{if(n.nodeType==3&&d.trim(n.nodeValue).length!==0){if(p){h.setStart(n,0)}else{h.setEnd(n,n.nodeValue.length)}return}if(n.nodeName=="BR"){if(p){h.setStartBefore(n)}else{h.setEndBefore(n)}return}}while(n=(p?o.next():o.prev()))}if(l){g=m.nodeIndex(l);h.setStart(l.parentNode,g);h.setEnd(l.parentNode,g+1);if(k){i(l,1);i(l)}j.setRng(h)}return l},isCollapsed:function(){var g=this,i=g.getRng(),h=g.getSel();if(!i||i.item){return false}if(i.compareEndPoints){return i.compareEndPoints("StartToEnd",i)===0}return !h||i.collapsed},collapse:function(g){var i=this,h=i.getRng(),j;if(h.item){j=h.item(0);h=i.win.document.body.createTextRange();h.moveToElementText(j)}h.collapse(!!g);i.setRng(h)},getSel:function(){var h=this,g=this.win;return g.getSelection?g.getSelection():g.document.selection},getRng:function(m){var h=this,j,g,l,k=h.win.document;if(m&&h.tridentSel){return h.tridentSel.getRangeAt(0)}try{if(j=h.getSel()){g=j.rangeCount>0?j.getRangeAt(0):(j.createRange?j.createRange():k.createRange())}}catch(i){}if(d.isIE&&g&&g.setStart&&k.selection.createRange().item){l=k.selection.createRange().item(0);g=k.createRange();g.setStartBefore(l);g.setEndAfter(l)}if(!g){g=k.createRange?k.createRange():k.body.createTextRange()}if(g.setStart&&g.startContainer.nodeType===9&&g.collapsed){l=h.dom.getRoot();g.setStart(l,0);g.setEnd(l,0)}if(h.selectedRange&&h.explicitRange){if(g.compareBoundaryPoints(g.START_TO_START,h.selectedRange)===0&&g.compareBoundaryPoints(g.END_TO_END,h.selectedRange)===0){g=h.explicitRange}else{h.selectedRange=null;h.explicitRange=null}}return g},setRng:function(k,g){var j,i=this;if(!i.tridentSel){j=i.getSel();if(j){i.explicitRange=k;try{j.removeAllRanges()}catch(h){}j.addRange(k);if(g===false&&j.extend){j.collapse(k.endContainer,k.endOffset);j.extend(k.startContainer,k.startOffset)}i.selectedRange=j.rangeCount>0?j.getRangeAt(0):null}}else{if(k.cloneRange){try{i.tridentSel.addRange(k);return}catch(h){}}try{k.select()}catch(h){}}},setNode:function(h){var g=this;g.setContent(g.dom.getOuterHTML(h));return h},getNode:function(){var i=this,h=i.getRng(),j=i.getSel(),m,l=h.startContainer,g=h.endContainer;function k(q,o){var p=q;while(q&&q.nodeType===3&&q.length===0){q=o?q.nextSibling:q.previousSibling}return q||p}if(!h){return i.dom.getRoot()}if(h.setStart){m=h.commonAncestorContainer;if(!h.collapsed){if(h.startContainer==h.endContainer){if(h.endOffset-h.startOffset<2){if(h.startContainer.hasChildNodes()){m=h.startContainer.childNodes[h.startOffset]}}}if(l.nodeType===3&&g.nodeType===3){if(l.length===h.startOffset){l=k(l.nextSibling,true)}else{l=l.parentNode}if(h.endOffset===0){g=k(g.previousSibling,false)}else{g=g.parentNode}if(l&&l===g){return l}}}if(m&&m.nodeType==3){return m.parentNode}return m}return h.item?h.item(0):h.parentElement()},getSelectedBlocks:function(p,h){var o=this,k=o.dom,m,l,i,j=[];m=k.getParent(p||o.getStart(),k.isBlock);l=k.getParent(h||o.getEnd(),k.isBlock);if(m){j.push(m)}if(m&&l&&m!=l){i=m;var g=new a(m,k.getRoot());while((i=g.next())&&i!=l){if(k.isBlock(i)){j.push(i)}}}if(l&&m!=l){j.push(l)}return j},isForward:function(){var i=this.dom,g=this.getSel(),j,h;if(!g||g.anchorNode==null||g.focusNode==null){return true}j=i.createRng();j.setStart(g.anchorNode,g.anchorOffset);j.collapse(true);h=i.createRng();h.setStart(g.focusNode,g.focusOffset);h.collapse(true);return j.compareBoundaryPoints(j.START_TO_START,h)<=0},normalize:function(){var h=this,g,m,l,j,i;function k(p){var o,r,n,s=h.dom,u=s.getRoot(),q,t,v;function y(z,A){var B=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(z=B[A?"prev":"next"]()){if(z.nodeName==="BR"){return true}}}function x(B,z){var C,A;z=z||o;C=new a(z,s.getParent(z.parentNode,s.isBlock)||u);while(q=C[B?"prev":"next"]()){if(q.nodeType===3&&q.nodeValue.length>0){o=q;r=B?q.nodeValue.length:0;m=true;return}if(s.isBlock(q)||t[q.nodeName.toLowerCase()]){return}A=q}if(l&&A){o=A;m=true;r=0}}o=g[(p?"start":"end")+"Container"];r=g[(p?"start":"end")+"Offset"];t=s.schema.getNonEmptyElements();if(o.nodeType===9){o=s.getRoot();r=0}if(o===u){if(p){q=o.childNodes[r>0?r-1:0];if(q){v=q.nodeName.toLowerCase();if(t[q.nodeName]||q.nodeName=="TABLE"){return}}}if(o.hasChildNodes()){o=o.childNodes[Math.min(!p&&r>0?r-1:r,o.childNodes.length-1)];r=0;if(o.hasChildNodes()&&!/TABLE/.test(o.nodeName)){q=o;n=new a(o,u);do{if(q.nodeType===3&&q.nodeValue.length>0){r=p?0:q.nodeValue.length;o=q;m=true;break}if(t[q.nodeName.toLowerCase()]){r=s.nodeIndex(q);o=q.parentNode;if(q.nodeName=="IMG"&&!p){r++}m=true;break}}while(q=(p?n.next():n.prev()))}}}if(l){if(o.nodeType===3&&r===0){x(true)}if(o.nodeType===1){q=o.childNodes[r];if(q&&q.nodeName==="BR"&&!y(q)&&!y(q,true)){x(true,o.childNodes[r])}}}if(p&&!l&&o.nodeType===3&&r===o.nodeValue.length){x(false)}if(m){g["set"+(p?"Start":"End")](o,r)}}if(d.isIE){return}g=h.getRng();l=g.collapsed;k(true);if(!l){k()}if(m){if(l){g.collapse(true)}h.setRng(g,h.isForward())}},destroy:function(h){var g=this;g.win=null;if(!h){d.removeUnload(g.destroy)}},_fixIESelection:function(){var h=this.dom,n=h.doc,i=n.body,k,o,g;function j(p,s){var q=i.createTextRange();try{q.moveToPoint(p,s)}catch(r){q=null}return q}function m(q){var p;if(q.button){p=j(q.x,q.y);if(p){if(p.compareEndPoints("StartToStart",o)>0){p.setEndPoint("StartToStart",o)}else{p.setEndPoint("EndToEnd",o)}p.select()}}else{l()}}function l(){var p=n.selection.createRange();if(o&&!p.item&&p.compareEndPoints("StartToEnd",p)===0){o.select()}h.unbind(n,"mouseup",l);h.unbind(n,"mousemove",m);o=k=0}n.documentElement.unselectable=true;h.bind(n,["mousedown","contextmenu"],function(p){if(p.target.nodeName==="HTML"){if(k){l()}g=n.documentElement;if(g.scrollHeight>g.clientHeight){return}k=1;o=j(p.x,p.y);if(o){h.bind(n,"mouseup",l);h.bind(n,"mousemove",m);h.win.focus();o.select()}}})}})})(tinymce);(function(a){a.dom.Serializer=function(e,i,f){var h,b,d=a.isIE,g=a.each,c;if(!e.apply_source_formatting){e.indent=false}i=i||a.DOM;f=f||new a.html.Schema(e);e.entity_encoding=e.entity_encoding||"named";e.remove_trailing_brs="remove_trailing_brs" in e?e.remove_trailing_brs:true;h=new a.util.Dispatcher(self);b=new a.util.Dispatcher(self);c=new a.html.DomParser(e,f);c.addAttributeFilter("src,href,style",function(k,j){var o=k.length,l,q,n="data-mce-"+j,p=e.url_converter,r=e.url_converter_scope,m;while(o--){l=k[o];q=l.attributes.map[n];if(q!==m){l.attr(j,q.length>0?q:null);l.attr(n,null)}else{q=l.attributes.map[j];if(j==="style"){q=i.serializeStyle(i.parseStyle(q),l.name)}else{if(p){q=p.call(r,q,j,l.name)}}l.attr(j,q.length>0?q:null)}}});c.addAttributeFilter("class",function(j,k){var l=j.length,m,n;while(l--){m=j[l];n=m.attr("class").replace(/(?:^|\s)mce(Item\w+|Selected)(?!\S)/g,"");m.attr("class",n.length>0?n:null)}});c.addAttributeFilter("data-mce-type",function(j,l,k){var m=j.length,n;while(m--){n=j[m];if(n.attributes.map["data-mce-type"]==="bookmark"&&!k.cleanup){n.remove()}}});c.addAttributeFilter("data-mce-expando",function(j,l,k){var m=j.length;while(m--){j[m].attr(l,null)}});c.addNodeFilter("script,style",function(k,l){var m=k.length,n,o;function j(p){return p.replace(/()/g,"\n").replace(/^[\r\n]*|[\r\n]*$/g,"").replace(/^\s*(()?|\s*\/\/\s*\]\]>(-->)?|\/\/\s*(-->)?|\]\]>|\/\*\s*-->\s*\*\/|\s*-->\s*)\s*$/g,"")}while(m--){n=k[m];o=n.firstChild?n.firstChild.value:"";if(l==="script"){n.attr("type",(n.attr("type")||"text/javascript").replace(/^mce\-/,""));if(o.length>0){n.firstChild.value="// "}}else{if(o.length>0){n.firstChild.value=""}}}});c.addNodeFilter("#comment",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.value.indexOf("[CDATA[")===0){m.name="#cdata";m.type=4;m.value=m.value.replace(/^\[CDATA\[|\]\]$/g,"")}else{if(m.value.indexOf("mce:protected ")===0){m.name="#text";m.type=3;m.raw=true;m.value=unescape(m.value).substr(14)}}}});c.addNodeFilter("xml:namespace,input",function(j,k){var l=j.length,m;while(l--){m=j[l];if(m.type===7){m.remove()}else{if(m.type===1){if(k==="input"&&!("type" in m.attributes.map)){m.attr("type","text")}}}}});if(e.fix_list_elements){c.addNodeFilter("ul,ol",function(k,l){var m=k.length,n,j;while(m--){n=k[m];j=n.parent;if(j.name==="ul"||j.name==="ol"){if(n.prev&&n.prev.name==="li"){n.prev.append(n)}}}})}c.addAttributeFilter("data-mce-src,data-mce-href,data-mce-style",function(j,k){var l=j.length;while(l--){j[l].attr(k,null)}});return{schema:f,addNodeFilter:c.addNodeFilter,addAttributeFilter:c.addAttributeFilter,onPreProcess:h,onPostProcess:b,serialize:function(o,m){var l,p,k,j,n;if(d&&i.select("script,style,select,map").length>0){n=o.innerHTML;o=o.cloneNode(false);i.setHTML(o,n)}else{o=o.cloneNode(true)}l=o.ownerDocument.implementation;if(l.createHTMLDocument){p=l.createHTMLDocument("");g(o.nodeName=="BODY"?o.childNodes:[o],function(q){p.body.appendChild(p.importNode(q,true))});if(o.nodeName!="BODY"){o=p.body.firstChild}else{o=p.body}k=i.doc;i.doc=p}m=m||{};m.format=m.format||"html";if(!m.no_events){m.node=o;h.dispatch(self,m)}j=new a.html.Serializer(e,f);m.content=j.serialize(c.parse(a.trim(m.getInner?o.innerHTML:i.getOuterHTML(o)),m));if(!m.cleanup){m.content=m.content.replace(/\uFEFF|\u200B/g,"")}if(!m.no_events){b.dispatch(self,m)}if(k){i.doc=k}m.node=null;return m.content},addRules:function(j){f.addValidElements(j)},setRules:function(j){f.setValidElements(j)}}}})(tinymce);(function(a){a.dom.ScriptLoader=function(h){var c=0,k=1,i=2,l={},j=[],e={},d=[],g=0,f;function b(m,v){var x=this,q=a.DOM,s,o,r,n;function p(){q.remove(n);if(s){s.onreadystatechange=s.onload=s=null}v()}function u(){if(typeof(console)!=="undefined"&&console.log){console.log("Failed to load: "+m)}}n=q.uniqueId();if(a.isIE6){o=new a.util.URI(m);r=location;if(o.host==r.hostname&&o.port==r.port&&(o.protocol+":")==r.protocol&&o.protocol.toLowerCase()!="file"){a.util.XHR.send({url:a._addVer(o.getURI()),success:function(y){var t=q.create("script",{type:"text/javascript"});t.text=y;document.getElementsByTagName("head")[0].appendChild(t);q.remove(t);p()},error:u});return}}s=q.create("script",{id:n,type:"text/javascript",src:a._addVer(m)});if(!a.isIE){s.onload=p}s.onerror=u;if(!a.isOpera){s.onreadystatechange=function(){var t=s.readyState;if(t=="complete"||t=="loaded"){p()}}}(document.getElementsByTagName("head")[0]||document.body).appendChild(s)}this.isDone=function(m){return l[m]==i};this.markDone=function(m){l[m]=i};this.add=this.load=function(m,q,n){var o,p=l[m];if(p==f){j.push(m);l[m]=c}if(q){if(!e[m]){e[m]=[]}e[m].push({func:q,scope:n||this})}};this.loadQueue=function(n,m){this.loadScripts(j,n,m)};this.loadScripts=function(m,q,p){var o;function n(r){a.each(e[r],function(s){s.func.call(s.scope)});e[r]=f}d.push({func:q,scope:p||this});o=function(){var r=a.grep(m);m.length=0;a.each(r,function(s){if(l[s]==i){n(s);return}if(l[s]!=k){l[s]=k;g++;b(s,function(){l[s]=i;g--;n(s);o()})}});if(!g){a.each(d,function(s){s.func.call(s.scope)});d.length=0}};o()}};a.ScriptLoader=new a.dom.ScriptLoader()})(tinymce);(function(a){a.dom.RangeUtils=function(c){var b="\uFEFF";this.walk=function(d,s){var i=d.startContainer,l=d.startOffset,t=d.endContainer,m=d.endOffset,j,g,o,h,r,q,e;e=c.select("td.mceSelected,th.mceSelected");if(e.length>0){a.each(e,function(u){s([u])});return}function f(u){var v;v=u[0];if(v.nodeType===3&&v===i&&l>=v.nodeValue.length){u.splice(0,1)}v=u[u.length-1];if(m===0&&u.length>0&&v===t&&v.nodeType===3){u.splice(u.length-1,1)}return u}function p(x,v,u){var y=[];for(;x&&x!=u;x=x[v]){y.push(x)}return y}function n(v,u){do{if(v.parentNode==u){return v}v=v.parentNode}while(v)}function k(x,v,y){var u=y?"nextSibling":"previousSibling";for(h=x,r=h.parentNode;h&&h!=v;h=r){r=h.parentNode;q=p(h==x?h:h[u],u);if(q.length){if(!y){q.reverse()}s(f(q))}}}if(i.nodeType==1&&i.hasChildNodes()){i=i.childNodes[l]}if(t.nodeType==1&&t.hasChildNodes()){t=t.childNodes[Math.min(m-1,t.childNodes.length-1)]}if(i==t){return s(f([i]))}j=c.findCommonAncestor(i,t);for(h=i;h;h=h.parentNode){if(h===t){return k(i,j,true)}if(h===j){break}}for(h=t;h;h=h.parentNode){if(h===i){return k(t,j)}if(h===j){break}}g=n(i,j)||i;o=n(t,j)||t;k(i,g,true);q=p(g==i?g:g.nextSibling,"nextSibling",o==t?o.nextSibling:o);if(q.length){s(f(q))}k(t,o)};this.split=function(e){var h=e.startContainer,d=e.startOffset,i=e.endContainer,g=e.endOffset;function f(j,k){return j.splitText(k)}if(h==i&&h.nodeType==3){if(d>0&&dd){g=g-d;h=i=f(i,g).previousSibling;g=i.nodeValue.length;d=0}else{g=0}}}else{if(h.nodeType==3&&d>0&&d0&&g=l.length){q=0}}s=l[q];f.setAttrib(g,"tabindex","-1");f.setAttrib(s.id,"tabindex","0");f.get(s.id).focus();if(e.actOnFocus){e.onAction(s.id)}if(r){a.cancel(r)}};o=function(y){var u=37,t=39,x=38,z=40,q=27,s=14,r=13,v=32;switch(y.keyCode){case u:if(i){p.moveFocus(-1)}break;case t:if(i){p.moveFocus(1)}break;case x:if(n){p.moveFocus(-1)}break;case z:if(n){p.moveFocus(1)}break;case q:if(e.onCancel){e.onCancel();a.cancel(y)}break;case s:case r:case v:if(e.onAction){e.onAction(g);a.cancel(y)}break}};c(l,function(s,q){var r;if(!s.id){s.id=f.uniqueId("_mce_item_")}if(k){f.bind(s.id,"blur",h);r="-1"}else{r=(q===0?"0":"-1")}f.setAttrib(s.id,"tabindex",r);f.bind(f.get(s.id),"focus",j)});if(l[0]){g=l[0].id}f.setAttrib(m,"tabindex","-1");f.bind(f.get(m),"focus",d);f.bind(f.get(m),"keydown",o)}})})(tinymce);(function(c){var b=c.DOM,a=c.is;c.create("tinymce.ui.Control",{Control:function(f,e,d){this.id=f;this.settings=e=e||{};this.rendered=false;this.onRender=new c.util.Dispatcher(this);this.classPrefix="";this.scope=e.scope||this;this.disabled=0;this.active=0;this.editor=d},setAriaProperty:function(f,e){var d=b.get(this.id+"_aria")||b.get(this.id);if(d){b.setAttrib(d,"aria-"+f,!!e)}},focus:function(){b.get(this.id).focus()},setDisabled:function(d){if(d!=this.disabled){this.setAriaProperty("disabled",d);this.setState("Disabled",d);this.setState("Enabled",!d);this.disabled=d}},isDisabled:function(){return this.disabled},setActive:function(d){if(d!=this.active){this.setState("Active",d);this.active=d;this.setAriaProperty("pressed",d)}},isActive:function(){return this.active},setState:function(f,d){var e=b.get(this.id);f=this.classPrefix+f;if(d){b.addClass(e,f)}else{b.removeClass(e,f)}},isRendered:function(){return this.rendered},renderHTML:function(){},renderTo:function(d){b.setHTML(d,this.renderHTML())},postRender:function(){var e=this,d;if(a(e.disabled)){d=e.disabled;e.disabled=-1;e.setDisabled(d)}if(a(e.active)){d=e.active;e.active=-1;e.setActive(d)}},remove:function(){b.remove(this.id);this.destroy()},destroy:function(){c.dom.Event.clear(this.id)}})})(tinymce);tinymce.create("tinymce.ui.Container:tinymce.ui.Control",{Container:function(c,b,a){this.parent(c,b,a);this.controls=[];this.lookup={}},add:function(a){this.lookup[a.id]=a;this.controls.push(a);return a},get:function(a){return this.lookup[a]}});tinymce.create("tinymce.ui.Separator:tinymce.ui.Control",{Separator:function(b,a){this.parent(b,a);this.classPrefix="mceSeparator";this.setDisabled(true)},renderHTML:function(){return tinymce.DOM.createHTML("span",{"class":this.classPrefix,role:"separator","aria-orientation":"vertical",tabindex:"-1"})}});(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.MenuItem:tinymce.ui.Control",{MenuItem:function(g,f){this.parent(g,f);this.classPrefix="mceMenuItem"},setSelected:function(f){this.setState("Selected",f);this.setAriaProperty("checked",!!f);this.selected=f},isSelected:function(){return this.selected},postRender:function(){var f=this;f.parent();if(c(f.selected)){f.setSelected(f.selected)}}})})(tinymce);(function(d){var c=d.is,b=d.DOM,e=d.each,a=d.walk;d.create("tinymce.ui.Menu:tinymce.ui.MenuItem",{Menu:function(h,g){var f=this;f.parent(h,g);f.items={};f.collapsed=false;f.menuCount=0;f.onAddItem=new d.util.Dispatcher(this)},expand:function(g){var f=this;if(g){a(f,function(h){if(h.expand){h.expand()}},"items",f)}f.collapsed=false},collapse:function(g){var f=this;if(g){a(f,function(h){if(h.collapse){h.collapse()}},"items",f)}f.collapsed=true},isCollapsed:function(){return this.collapsed},add:function(f){if(!f.settings){f=new d.ui.MenuItem(f.id||b.uniqueId(),f)}this.onAddItem.dispatch(this,f);return this.items[f.id]=f},addSeparator:function(){return this.add({separator:true})},addMenu:function(f){if(!f.collapse){f=this.createMenu(f)}this.menuCount++;return this.add(f)},hasMenus:function(){return this.menuCount!==0},remove:function(f){delete this.items[f.id]},removeAll:function(){var f=this;a(f,function(g){if(g.removeAll){g.removeAll()}else{g.remove()}g.destroy()},"items",f);f.items={}},createMenu:function(g){var f=new d.ui.Menu(g.id||b.uniqueId(),g);f.onAddItem.add(this.onAddItem.dispatch,this.onAddItem);return f}})})(tinymce);(function(e){var d=e.is,c=e.DOM,f=e.each,a=e.dom.Event,b=e.dom.Element;e.create("tinymce.ui.DropMenu:tinymce.ui.Menu",{DropMenu:function(h,g){g=g||{};g.container=g.container||c.doc.body;g.offset_x=g.offset_x||0;g.offset_y=g.offset_y||0;g.vp_offset_x=g.vp_offset_x||0;g.vp_offset_y=g.vp_offset_y||0;if(d(g.icons)&&!g.icons){g["class"]+=" mceNoIcons"}this.parent(h,g);this.onShowMenu=new e.util.Dispatcher(this);this.onHideMenu=new e.util.Dispatcher(this);this.classPrefix="mceMenu"},createMenu:function(j){var h=this,i=h.settings,g;j.container=j.container||i.container;j.parent=h;j.constrain=j.constrain||i.constrain;j["class"]=j["class"]||i["class"];j.vp_offset_x=j.vp_offset_x||i.vp_offset_x;j.vp_offset_y=j.vp_offset_y||i.vp_offset_y;j.keyboard_focus=i.keyboard_focus;g=new e.ui.DropMenu(j.id||c.uniqueId(),j);g.onAddItem.add(h.onAddItem.dispatch,h.onAddItem);return g},focus:function(){var g=this;if(g.keyboardNav){g.keyboardNav.focus()}},update:function(){var i=this,j=i.settings,g=c.get("menu_"+i.id+"_tbl"),l=c.get("menu_"+i.id+"_co"),h,k;h=j.max_width?Math.min(g.offsetWidth,j.max_width):g.offsetWidth;k=j.max_height?Math.min(g.offsetHeight,j.max_height):g.offsetHeight;if(!c.boxModel){i.element.setStyles({width:h+2,height:k+2})}else{i.element.setStyles({width:h,height:k})}if(j.max_width){c.setStyle(l,"width",h)}if(j.max_height){c.setStyle(l,"height",k);if(g.clientHeightv){p=r?r-u:Math.max(0,(v-A.vp_offset_x)-u)}if((n+A.vp_offset_y+l)>q){n=Math.max(0,(q-A.vp_offset_y)-l)}}c.setStyles(o,{left:p,top:n});z.element.update();z.isMenuVisible=1;z.mouseClickFunc=a.add(o,"click",function(s){var h;s=s.target;if(s&&(s=c.getParent(s,"tr"))&&!c.hasClass(s,m+"ItemSub")){h=z.items[s.id];if(h.isDisabled()){return}k=z;while(k){if(k.hideMenu){k.hideMenu()}k=k.settings.parent}if(h.settings.onclick){h.settings.onclick(s)}return false}});if(z.hasMenus()){z.mouseOverFunc=a.add(o,"mouseover",function(x){var h,t,s;x=x.target;if(x&&(x=c.getParent(x,"tr"))){h=z.items[x.id];if(z.lastMenu){z.lastMenu.collapse(1)}if(h.isDisabled()){return}if(x&&c.hasClass(x,m+"ItemSub")){t=c.getRect(x);h.showMenu((t.x+t.w-i),t.y-i,t.x);z.lastMenu=h;c.addClass(c.get(h.id).firstChild,m+"ItemActive")}}})}a.add(o,"keydown",z._keyHandler,z);z.onShowMenu.dispatch(z);if(A.keyboard_focus){z._setupKeyboardNav()}},hideMenu:function(j){var g=this,i=c.get("menu_"+g.id),h;if(!g.isMenuVisible){return}if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(i,"mouseover",g.mouseOverFunc);a.remove(i,"click",g.mouseClickFunc);a.remove(i,"keydown",g._keyHandler);c.hide(i);g.isMenuVisible=0;if(!j){g.collapse(1)}if(g.element){g.element.hide()}if(h=c.get(g.id)){c.removeClass(h.firstChild,g.classPrefix+"ItemActive")}g.onHideMenu.dispatch(g)},add:function(i){var g=this,h;i=g.parent(i);if(g.isRendered&&(h=c.get("menu_"+g.id))){g._add(c.select("tbody",h)[0],i)}return i},collapse:function(g){this.parent(g);this.hideMenu(1)},remove:function(g){c.remove(g.id);this.destroy();return this.parent(g)},destroy:function(){var g=this,h=c.get("menu_"+g.id);if(g.keyboardNav){g.keyboardNav.destroy()}a.remove(h,"mouseover",g.mouseOverFunc);a.remove(c.select("a",h),"focus",g.mouseOverFunc);a.remove(h,"click",g.mouseClickFunc);a.remove(h,"keydown",g._keyHandler);if(g.element){g.element.remove()}c.remove(h)},renderNode:function(){var i=this,j=i.settings,l,h,k,g;g=c.create("div",{role:"listbox",id:"menu_"+i.id,"class":j["class"],style:"position:absolute;left:0;top:0;z-index:200000;outline:0"});if(i.settings.parent){c.setAttrib(g,"aria-parent","menu_"+i.settings.parent.id)}k=c.add(g,"div",{role:"presentation",id:"menu_"+i.id+"_co","class":i.classPrefix+(j["class"]?" "+j["class"]:"")});i.element=new b("menu_"+i.id,{blocker:1,container:j.container});if(j.menu_line){c.add(k,"span",{"class":i.classPrefix+"Line"})}l=c.add(k,"table",{role:"presentation",id:"menu_"+i.id+"_tbl",border:0,cellPadding:0,cellSpacing:0});h=c.add(l,"tbody");f(i.items,function(m){i._add(h,m)});i.rendered=true;return g},_setupKeyboardNav:function(){var i,h,g=this;i=c.get("menu_"+g.id);h=c.select("a[role=option]","menu_"+g.id);h.splice(0,0,i);g.keyboardNav=new e.ui.KeyboardNavigation({root:"menu_"+g.id,items:h,onCancel:function(){g.hideMenu()},enableUpDown:true});i.focus()},_keyHandler:function(g){var h=this,i;switch(g.keyCode){case 37:if(h.settings.parent){h.hideMenu();h.settings.parent.focus();a.cancel(g)}break;case 39:if(h.mouseOverFunc){h.mouseOverFunc(g)}break}},_add:function(j,h){var i,q=h.settings,p,l,k,m=this.classPrefix,g;if(q.separator){l=c.add(j,"tr",{id:h.id,"class":m+"ItemSeparator"});c.add(l,"td",{"class":m+"ItemSeparator"});if(i=l.previousSibling){c.addClass(i,"mceLast")}return}i=l=c.add(j,"tr",{id:h.id,"class":m+"Item "+m+"ItemEnabled"});i=k=c.add(i,q.titleItem?"th":"td");i=p=c.add(i,"a",{id:h.id+"_aria",role:q.titleItem?"presentation":"option",href:"javascript:;",onclick:"return false;",onmousedown:"return false;"});if(q.parent){c.setAttrib(p,"aria-haspopup","true");c.setAttrib(p,"aria-owns","menu_"+h.id)}c.addClass(k,q["class"]);g=c.add(i,"span",{"class":"mceIcon"+(q.icon?" mce_"+q.icon:"")});if(q.icon_src){c.add(g,"img",{src:q.icon_src})}i=c.add(i,q.element||"span",{"class":"mceText",title:h.settings.title},h.settings.title);if(h.settings.style){if(typeof h.settings.style=="function"){h.settings.style=h.settings.style()}c.setAttrib(i,"style",h.settings.style)}if(j.childNodes.length==1){c.addClass(l,"mceFirst")}if((i=l.previousSibling)&&c.hasClass(i,m+"ItemSeparator")){c.addClass(l,"mceFirst")}if(h.collapse){c.addClass(l,m+"ItemSub")}if(i=l.previousSibling){c.removeClass(i,"mceLast")}c.addClass(l,"mceLast")}})})(tinymce);(function(b){var a=b.DOM;b.create("tinymce.ui.Button:tinymce.ui.Control",{Button:function(e,d,c){this.parent(e,d,c);this.classPrefix="mceButton"},renderHTML:function(){var f=this.classPrefix,e=this.settings,d,c;c=a.encode(e.label||"");d='';if(e.image&&!(this.editor&&this.editor.forcedHighContrastMode)){d+=''+a.encode(e.title)+''+c}else{d+=''+(c?''+c+"":"")}d+='";d+="";return d},postRender:function(){var d=this,e=d.settings,c;if(b.isIE&&d.editor){b.dom.Event.add(d.id,"mousedown",function(f){var g=d.editor.selection.getNode().nodeName;c=g==="IMG"?d.editor.selection.getBookmark():null})}b.dom.Event.add(d.id,"click",function(f){if(!d.isDisabled()){if(b.isIE&&d.editor&&c!==null){d.editor.selection.moveToBookmark(c)}return e.onclick.call(e.scope,f)}});b.dom.Event.add(d.id,"keyup",function(f){if(!d.isDisabled()&&f.keyCode==b.VK.SPACEBAR){return e.onclick.call(e.scope,f)}})}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.ListBox:tinymce.ui.Control",{ListBox:function(j,i,g){var h=this;h.parent(j,i,g);h.items=[];h.onChange=new a(h);h.onPostRender=new a(h);h.onAdd=new a(h);h.onRenderMenu=new e.util.Dispatcher(this);h.classPrefix="mceListBox";h.marked={}},select:function(h){var g=this,j,i;g.marked={};if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){var i=this,j,k,h;i.marked={};if(g!=i.selectedIndex){j=d.get(i.id+"_text");h=d.get(i.id+"_voiceDesc");k=i.items[g];if(k){i.selectedValue=k.value;i.selectedIndex=g;d.setHTML(j,d.encode(k.title));d.setHTML(h,i.settings.title+" - "+k.title);d.removeClass(j,"mceTitle");d.setAttrib(i.id,"aria-valuenow",k.title)}else{d.setHTML(j,d.encode(i.settings.title));d.setHTML(h,d.encode(i.settings.title));d.addClass(j,"mceTitle");i.selectedValue=i.selectedIndex=null;d.setAttrib(i.id,"aria-valuenow",i.settings.title)}j=0}},mark:function(g){this.marked[g]=true},add:function(j,g,i){var h=this;i=i||{};i=e.extend(i,{title:j,value:g});h.items.push(i);h.onAdd.dispatch(h,i)},getLength:function(){return this.items.length},renderHTML:function(){var j="",g=this,i=g.settings,k=g.classPrefix;j='';j+="";j+="";j+="";return j},showMenu:function(){var h=this,j,i=d.get(this.id),g;if(h.isDisabled()||h.items.length===0){return}if(h.menu&&h.menu.isMenuVisible){return h.hideMenu()}if(!h.isMenuRendered){h.renderMenu();h.isMenuRendered=true}j=d.getPos(i);g=h.menu;g.settings.offset_x=j.x;g.settings.offset_y=j.y;g.settings.keyboard_focus=!e.isOpera;f(h.items,function(k){if(g.items[k.id]){g.items[k.id].setSelected(0)}});f(h.items,function(k){if(g.items[k.id]&&h.marked[k.value]){g.items[k.id].setSelected(1)}if(k.value===h.selectedValue){g.items[k.id].setSelected(1)}});g.showMenu(0,i.clientHeight);b.add(d.doc,"mousedown",h.hideMenu,h);d.addClass(h.id,h.classPrefix+"Selected")},hideMenu:function(h){var g=this;if(g.menu&&g.menu.isMenuVisible){d.removeClass(g.id,g.classPrefix+"Selected");if(h&&h.type=="mousedown"&&(h.target.id==g.id+"_text"||h.target.id==g.id+"_open")){return}if(!h||!d.getParent(h.target,".mceMenu")){d.removeClass(g.id,g.classPrefix+"Selected");b.remove(d.doc,"mousedown",g.hideMenu,g);g.menu.hideMenu()}}},renderMenu:function(){var h=this,g;g=h.settings.control_manager.createDropMenu(h.id+"_menu",{menu_line:1,"class":h.classPrefix+"Menu mceNoIcons",max_width:250,max_height:150});g.onHideMenu.add(function(){h.hideMenu();h.focus()});g.add({title:h.settings.title,"class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}});f(h.items,function(i){if(i.value===c){g.add({title:i.title,role:"option","class":"mceMenuItemTitle",onclick:function(){if(h.settings.onselect("")!==false){h.select("")}}})}else{i.id=d.uniqueId();i.role="option";i.onclick=function(){if(h.settings.onselect(i.value)!==false){h.select(i.value)}};g.add(i)}});h.onRenderMenu.dispatch(h,g);h.menu=g},postRender:function(){var g=this,h=g.classPrefix;b.add(g.id,"click",g.showMenu,g);b.add(g.id,"keydown",function(i){if(i.keyCode==32){g.showMenu(i);b.cancel(i)}});b.add(g.id,"focus",function(){if(!g._focused){g.keyDownHandler=b.add(g.id,"keydown",function(i){if(i.keyCode==40){g.showMenu();b.cancel(i)}});g.keyPressHandler=b.add(g.id,"keypress",function(j){var i;if(j.keyCode==13){i=g.selectedValue;g.selectedValue=null;b.cancel(j);g.settings.onselect(i)}})}g._focused=1});b.add(g.id,"blur",function(){b.remove(g.id,"keydown",g.keyDownHandler);b.remove(g.id,"keypress",g.keyPressHandler);g._focused=0});if(e.isIE6||!d.boxModel){b.add(g.id,"mouseover",function(){if(!d.hasClass(g.id,h+"Disabled")){d.addClass(g.id,h+"Hover")}});b.add(g.id,"mouseout",function(){if(!d.hasClass(g.id,h+"Disabled")){d.removeClass(g.id,h+"Hover")}})}g.onPostRender.dispatch(g,d.get(g.id))},destroy:function(){this.parent();b.clear(this.id+"_text");b.clear(this.id+"_open")}})})(tinymce);(function(e){var d=e.DOM,b=e.dom.Event,f=e.each,a=e.util.Dispatcher,c;e.create("tinymce.ui.NativeListBox:tinymce.ui.ListBox",{NativeListBox:function(h,g){this.parent(h,g);this.classPrefix="mceNativeListBox"},setDisabled:function(g){d.get(this.id).disabled=g;this.setAriaProperty("disabled",g)},isDisabled:function(){return d.get(this.id).disabled},select:function(h){var g=this,j,i;if(h==c){return g.selectByIndex(-1)}if(h&&typeof(h)=="function"){i=h}else{i=function(k){return k==h}}if(h!=g.selectedValue){f(g.items,function(l,k){if(i(l.value)){j=1;g.selectByIndex(k);return false}});if(!j){g.selectByIndex(-1)}}},selectByIndex:function(g){d.get(this.id).selectedIndex=g+1;this.selectedValue=this.items[g]?this.items[g].value:null},add:function(k,h,g){var j,i=this;g=g||{};g.value=h;if(i.isRendered()){d.add(d.get(this.id),"option",g,k)}j={title:k,value:h,attribs:g};i.items.push(j);i.onAdd.dispatch(i,j)},getLength:function(){return this.items.length},renderHTML:function(){var i,g=this;i=d.createHTML("option",{value:""},"-- "+g.settings.title+" --");f(g.items,function(h){i+=d.createHTML("option",{value:h.value},h.title)});i=d.createHTML("select",{id:g.id,"class":"mceNativeListBox","aria-labelledby":g.id+"_aria"},i);i+=d.createHTML("span",{id:g.id+"_aria",style:"display: none"},g.settings.title);return i},postRender:function(){var h=this,i,j=true;h.rendered=true;function g(l){var k=h.items[l.target.selectedIndex-1];if(k&&(k=k.value)){h.onChange.dispatch(h,k);if(h.settings.onselect){h.settings.onselect(k)}}}b.add(h.id,"change",g);b.add(h.id,"keydown",function(l){var k;b.remove(h.id,"change",i);j=false;k=b.add(h.id,"blur",function(){if(j){return}j=true;b.add(h.id,"change",g);b.remove(h.id,"blur",k)});if(e.isWebKit&&(l.keyCode==37||l.keyCode==39)){return b.prevent(l)}if(l.keyCode==13||l.keyCode==32){g(l);return b.cancel(l)}});h.onPostRender.dispatch(h,d.get(h.id))}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.MenuButton:tinymce.ui.Button",{MenuButton:function(g,f,e){this.parent(g,f,e);this.onRenderMenu=new c.util.Dispatcher(this);f.menu_container=f.menu_container||b.doc.body},showMenu:function(){var g=this,j,i,h=b.get(g.id),f;if(g.isDisabled()){return}if(!g.isMenuRendered){g.renderMenu();g.isMenuRendered=true}if(g.isMenuVisible){return g.hideMenu()}j=b.getPos(g.settings.menu_container);i=b.getPos(h);f=g.menu;f.settings.offset_x=i.x;f.settings.offset_y=i.y;f.settings.vp_offset_x=i.x;f.settings.vp_offset_y=i.y;f.settings.keyboard_focus=g._focused;f.showMenu(0,h.firstChild.clientHeight);a.add(b.doc,"mousedown",g.hideMenu,g);g.setState("Selected",1);g.isMenuVisible=1},renderMenu:function(){var f=this,e;e=f.settings.control_manager.createDropMenu(f.id+"_menu",{menu_line:1,"class":this.classPrefix+"Menu",icons:f.settings.icons});e.onHideMenu.add(function(){f.hideMenu();f.focus()});f.onRenderMenu.dispatch(f,e);f.menu=e},hideMenu:function(g){var f=this;if(g&&g.type=="mousedown"&&b.getParent(g.target,function(h){return h.id===f.id||h.id===f.id+"_open"})){return}if(!g||!b.getParent(g.target,".mceMenu")){f.setState("Selected",0);a.remove(b.doc,"mousedown",f.hideMenu,f);if(f.menu){f.menu.hideMenu()}}f.isMenuVisible=0},postRender:function(){var e=this,f=e.settings;a.add(e.id,"click",function(){if(!e.isDisabled()){if(f.onclick){f.onclick(e.value)}e.showMenu()}})}})})(tinymce);(function(c){var b=c.DOM,a=c.dom.Event,d=c.each;c.create("tinymce.ui.SplitButton:tinymce.ui.MenuButton",{SplitButton:function(g,f,e){this.parent(g,f,e);this.classPrefix="mceSplitButton"},renderHTML:function(){var i,f=this,g=f.settings,e;i="";if(g.image){e=b.createHTML("img ",{src:g.image,role:"presentation","class":"mceAction "+g["class"]})}else{e=b.createHTML("span",{"class":"mceAction "+g["class"]},"")}e+=b.createHTML("span",{"class":"mceVoiceLabel mceIconOnly",id:f.id+"_voice",style:"display:none;"},g.title);i+=""+b.createHTML("a",{role:"button",id:f.id+"_action",tabindex:"-1",href:"javascript:;","class":"mceAction "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"";e=b.createHTML("span",{"class":"mceOpen "+g["class"]},'');i+=""+b.createHTML("a",{role:"button",id:f.id+"_open",tabindex:"-1",href:"javascript:;","class":"mceOpen "+g["class"],onclick:"return false;",onmousedown:"return false;",title:g.title},e)+"";i+="";i=b.createHTML("table",{role:"presentation","class":"mceSplitButton mceSplitButtonEnabled "+g["class"],cellpadding:"0",cellspacing:"0",title:g.title},i);return b.createHTML("div",{id:f.id,role:"button",tabindex:"0","aria-labelledby":f.id+"_voice","aria-haspopup":"true"},i)},postRender:function(){var e=this,g=e.settings,f;if(g.onclick){f=function(h){if(!e.isDisabled()){g.onclick(e.value);a.cancel(h)}};a.add(e.id+"_action","click",f);a.add(e.id,["click","keydown"],function(h){var k=32,m=14,i=13,j=38,l=40;if((h.keyCode===32||h.keyCode===13||h.keyCode===14)&&!h.altKey&&!h.ctrlKey&&!h.metaKey){f();a.cancel(h)}else{if(h.type==="click"||h.keyCode===l){e.showMenu();a.cancel(h)}}})}a.add(e.id+"_open","click",function(h){e.showMenu();a.cancel(h)});a.add([e.id,e.id+"_open"],"focus",function(){e._focused=1});a.add([e.id,e.id+"_open"],"blur",function(){e._focused=0});if(c.isIE6||!b.boxModel){a.add(e.id,"mouseover",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.addClass(e.id,"mceSplitButtonHover")}});a.add(e.id,"mouseout",function(){if(!b.hasClass(e.id,"mceSplitButtonDisabled")){b.removeClass(e.id,"mceSplitButtonHover")}})}},destroy:function(){this.parent();a.clear(this.id+"_action");a.clear(this.id+"_open");a.clear(this.id)}})})(tinymce);(function(d){var c=d.DOM,a=d.dom.Event,b=d.is,e=d.each;d.create("tinymce.ui.ColorSplitButton:tinymce.ui.SplitButton",{ColorSplitButton:function(i,h,f){var g=this;g.parent(i,h,f);g.settings=h=d.extend({colors:"000000,993300,333300,003300,003366,000080,333399,333333,800000,FF6600,808000,008000,008080,0000FF,666699,808080,FF0000,FF9900,99CC00,339966,33CCCC,3366FF,800080,999999,FF00FF,FFCC00,FFFF00,00FF00,00FFFF,00CCFF,993366,C0C0C0,FF99CC,FFCC99,FFFF99,CCFFCC,CCFFFF,99CCFF,CC99FF,FFFFFF",grid_width:8,default_color:"#888888"},g.settings);g.onShowMenu=new d.util.Dispatcher(g);g.onHideMenu=new d.util.Dispatcher(g);g.value=h.default_color},showMenu:function(){var f=this,g,j,i,h;if(f.isDisabled()){return}if(!f.isMenuRendered){f.renderMenu();f.isMenuRendered=true}if(f.isMenuVisible){return f.hideMenu()}i=c.get(f.id);c.show(f.id+"_menu");c.addClass(i,"mceSplitButtonSelected");h=c.getPos(i);c.setStyles(f.id+"_menu",{left:h.x,top:h.y+i.firstChild.clientHeight,zIndex:200000});i=0;a.add(c.doc,"mousedown",f.hideMenu,f);f.onShowMenu.dispatch(f);if(f._focused){f._keyHandler=a.add(f.id+"_menu","keydown",function(k){if(k.keyCode==27){f.hideMenu()}});c.select("a",f.id+"_menu")[0].focus()}f.isMenuVisible=1},hideMenu:function(g){var f=this;if(f.isMenuVisible){if(g&&g.type=="mousedown"&&c.getParent(g.target,function(h){return h.id===f.id+"_open"})){return}if(!g||!c.getParent(g.target,".mceSplitButtonMenu")){c.removeClass(f.id,"mceSplitButtonSelected");a.remove(c.doc,"mousedown",f.hideMenu,f);a.remove(f.id+"_menu","keydown",f._keyHandler);c.hide(f.id+"_menu")}f.isMenuVisible=0;f.onHideMenu.dispatch()}},renderMenu:function(){var p=this,h,k=0,q=p.settings,g,j,l,o,f;o=c.add(q.menu_container,"div",{role:"listbox",id:p.id+"_menu","class":q.menu_class+" "+q["class"],style:"position:absolute;left:0;top:-1000px;"});h=c.add(o,"div",{"class":q["class"]+" mceSplitButtonMenu"});c.add(h,"span",{"class":"mceMenuLine"});g=c.add(h,"table",{role:"presentation","class":"mceColorSplitMenu"});j=c.add(g,"tbody");k=0;e(b(q.colors,"array")?q.colors:q.colors.split(","),function(m){m=m.replace(/^#/,"");if(!k--){l=c.add(j,"tr");k=q.grid_width-1}g=c.add(l,"td");var i={href:"javascript:;",style:{backgroundColor:"#"+m},title:p.editor.getLang("colors."+m,m),"data-mce-color":"#"+m};if(!d.isIE){i.role="option"}g=c.add(g,"a",i);if(p.editor.forcedHighContrastMode){g=c.add(g,"canvas",{width:16,height:16,"aria-hidden":"true"});if(g.getContext&&(f=g.getContext("2d"))){f.fillStyle="#"+m;f.fillRect(0,0,16,16)}else{c.remove(g)}}});if(q.more_colors_func){g=c.add(j,"tr");g=c.add(g,"td",{colspan:q.grid_width,"class":"mceMoreColors"});g=c.add(g,"a",{role:"option",id:p.id+"_more",href:"javascript:;",onclick:"return false;","class":"mceMoreColors"},q.more_colors_title);a.add(g,"click",function(i){q.more_colors_func.call(q.more_colors_scope||this);return a.cancel(i)})}c.addClass(h,"mceColorSplitMenu");new d.ui.KeyboardNavigation({root:p.id+"_menu",items:c.select("a",p.id+"_menu"),onCancel:function(){p.hideMenu();p.focus()}});a.add(p.id+"_menu","mousedown",function(i){return a.cancel(i)});a.add(p.id+"_menu","click",function(i){var m;i=c.getParent(i.target,"a",j);if(i&&i.nodeName.toLowerCase()=="a"&&(m=i.getAttribute("data-mce-color"))){p.setColor(m)}return false});return o},setColor:function(f){this.displayColor(f);this.hideMenu();this.settings.onselect(f)},displayColor:function(g){var f=this;c.setStyle(f.id+"_preview","backgroundColor",g);f.value=g},postRender:function(){var f=this,g=f.id;f.parent();c.add(g+"_action","div",{id:g+"_preview","class":"mceColorPreview"});c.setStyle(f.id+"_preview","backgroundColor",f.value)},destroy:function(){this.parent();a.clear(this.id+"_menu");a.clear(this.id+"_more");c.remove(this.id+"_menu")}})})(tinymce);(function(b){var d=b.DOM,c=b.each,a=b.dom.Event;b.create("tinymce.ui.ToolbarGroup:tinymce.ui.Container",{renderHTML:function(){var f=this,i=[],e=f.controls,j=b.each,g=f.settings;i.push('
    ');i.push("");i.push('");j(e,function(h){i.push(h.renderHTML())});i.push("");i.push("
    ");return i.join("")},focus:function(){var e=this;d.get(e.id).focus()},postRender:function(){var f=this,e=[];c(f.controls,function(g){c(g.controls,function(h){if(h.id){e.push(h)}})});f.keyNav=new b.ui.KeyboardNavigation({root:f.id,items:e,onCancel:function(){if(b.isWebKit){d.get(f.editor.id+"_ifr").focus()}f.editor.focus()},excludeFromTabOrder:!f.settings.tab_focus_toolbar})},destroy:function(){var e=this;e.parent();e.keyNav.destroy();a.clear(e.id)}})})(tinymce);(function(a){var c=a.DOM,b=a.each;a.create("tinymce.ui.Toolbar:tinymce.ui.Container",{renderHTML:function(){var m=this,f="",j,k,n=m.settings,e,d,g,l;l=m.controls;for(e=0;e"))}if(d&&k.ListBox){if(d.Button||d.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarEnd"},c.createHTML("span",null,""))}}if(c.stdMode){f+=''+k.renderHTML()+""}else{f+=""+k.renderHTML()+""}if(g&&k.ListBox){if(g.Button||g.SplitButton){f+=c.createHTML("td",{"class":"mceToolbarStart"},c.createHTML("span",null,""))}}}j="mceToolbarEnd";if(k.Button){j+=" mceToolbarEndButton"}else{if(k.SplitButton){j+=" mceToolbarEndSplitButton"}else{if(k.ListBox){j+=" mceToolbarEndListBox"}}}f+=c.createHTML("td",{"class":j},c.createHTML("span",null,""));return c.createHTML("table",{id:m.id,"class":"mceToolbar"+(n["class"]?" "+n["class"]:""),cellpadding:"0",cellspacing:"0",align:m.settings.align||"",role:"presentation",tabindex:"-1"},""+f+"")}})})(tinymce);(function(b){var a=b.util.Dispatcher,c=b.each;b.create("tinymce.AddOnManager",{AddOnManager:function(){var d=this;d.items=[];d.urls={};d.lookup={};d.onAdd=new a(d)},get:function(d){if(this.lookup[d]){return this.lookup[d].instance}else{return undefined}},dependencies:function(e){var d;if(this.lookup[e]){d=this.lookup[e].dependencies}return d||[]},requireLangPack:function(e){var d=b.settings;if(d&&d.language&&d.language_load!==false){b.ScriptLoader.add(this.urls[e]+"/langs/"+d.language+".js")}},add:function(f,e,d){this.items.push(e);this.lookup[f]={instance:e,dependencies:d};this.onAdd.dispatch(this,f,e);return e},createUrl:function(d,e){if(typeof e==="object"){return e}else{return{prefix:d.prefix,resource:e,suffix:d.suffix}}},addComponents:function(f,d){var e=this.urls[f];b.each(d,function(g){b.ScriptLoader.add(e+"/"+g)})},load:function(j,f,d,h){var g=this,e=f;function i(){var k=g.dependencies(j);b.each(k,function(m){var l=g.createUrl(f,m);g.load(l.resource,l,undefined,undefined)});if(d){if(h){d.call(h)}else{d.call(b.ScriptLoader)}}}if(g.urls[j]){return}if(typeof f==="object"){e=f.prefix+f.resource+f.suffix}if(e.indexOf("/")!==0&&e.indexOf("://")==-1){e=b.baseURL+"/"+e}g.urls[j]=e.substring(0,e.lastIndexOf("/"));if(g.lookup[j]){i()}else{b.ScriptLoader.add(e,i,h)}}});b.PluginManager=new b.AddOnManager();b.ThemeManager=new b.AddOnManager()}(tinymce));(function(j){var g=j.each,d=j.extend,k=j.DOM,i=j.dom.Event,f=j.ThemeManager,b=j.PluginManager,e=j.explode,h=j.util.Dispatcher,a,c=0;j.documentBaseURL=window.location.href.replace(/[\?#].*$/,"").replace(/[\/\\][^\/]+$/,"");if(!/[\/\\]$/.test(j.documentBaseURL)){j.documentBaseURL+="/"}j.baseURL=new j.util.URI(j.documentBaseURL).toAbsolute(j.baseURL);j.baseURI=new j.util.URI(j.baseURL);j.onBeforeUnload=new h(j);i.add(window,"beforeunload",function(l){j.onBeforeUnload.dispatch(j,l)});j.onAddEditor=new h(j);j.onRemoveEditor=new h(j);j.EditorManager=d(j,{editors:[],i18n:{},activeEditor:null,init:function(x){var v=this,o,n=j.ScriptLoader,u,l=[],r;function q(t){var s=t.id;if(!s){s=t.name;if(s&&!k.get(s)){s=t.name}else{s=k.uniqueId()}t.setAttribute("id",s)}return s}function m(z,A,t){var y=z[A];if(!y){return}if(j.is(y,"string")){t=y.replace(/\.\w+$/,"");t=t?j.resolve(t):0;y=j.resolve(y)}return y.apply(t||this,Array.prototype.slice.call(arguments,2))}function p(t,s){return s.constructor===RegExp?s.test(t.className):k.hasClass(t,s)}x=d({theme:"simple",language:"en"},x);v.settings=x;i.bind(window,"ready",function(){var s,t;m(x,"onpageload");switch(x.mode){case"exact":s=x.elements||"";if(s.length>0){g(e(s),function(y){if(k.get(y)){r=new j.Editor(y,x);l.push(r);r.render(1)}else{g(document.forms,function(z){g(z.elements,function(A){if(A.name===y){y="mce_editor_"+c++;k.setAttrib(A,"id",y);r=new j.Editor(y,x);l.push(r);r.render(1)}})})}})}break;case"textareas":case"specific_textareas":g(k.select("textarea"),function(y){if(x.editor_deselector&&p(y,x.editor_deselector)){return}if(!x.editor_selector||p(y,x.editor_selector)){r=new j.Editor(q(y),x);l.push(r);r.render(1)}});break;default:if(x.types){g(x.types,function(y){g(k.select(y.selector),function(A){var z=new j.Editor(q(A),j.extend({},x,y));l.push(z);z.render(1)})})}else{if(x.selector){g(k.select(x.selector),function(z){var y=new j.Editor(q(z),x);l.push(y);y.render(1)})}}}if(x.oninit){s=t=0;g(l,function(y){t++;if(!y.initialized){y.onInit.add(function(){s++;if(s==t){m(x,"oninit")}})}else{s++}if(s==t){m(x,"oninit")}})}})},get:function(l){if(l===a){return this.editors}return this.editors[l]},getInstanceById:function(l){return this.get(l)},add:function(m){var l=this,n=l.editors;n[m.id]=m;n.push(m);l._setActive(m);l.onAddEditor.dispatch(l,m);return m},remove:function(n){var m=this,l,o=m.editors;if(!o[n.id]){return null}delete o[n.id];for(l=0;l':"",visual:n,font_size_style_values:"xx-small,x-small,small,medium,large,x-large,xx-large",font_size_legacy_values:"xx-small,small,medium,large,x-large,xx-large,300%",apply_source_formatting:n,directionality:"ltr",forced_root_block:"p",hidden_input:n,padd_empty_editor:n,render_ui:n,indentation:"30px",fix_table_elements:n,inline_styles:n,convert_fonts_to_spans:n,indent:"simple",indent_before:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure",indent_after:"p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,ul,li,area,table,thead,tfoot,tbody,tr,section,article,hgroup,aside,figure",validate:n,entity_encoding:"named",url_converter:m.convertURL,url_converter_scope:m,ie7_compat:n},o);m.id=m.editorId=p;m.isNotDirty=false;m.plugins={};m.documentBaseURI=new k.util.URI(o.document_base_url||k.documentBaseURL,{base_uri:tinyMCE.baseURI});m.baseURI=k.baseURI;m.contentCSS=[];m.setupEvents();m.execCommands={};m.queryStateCommands={};m.queryValueCommands={};m.execCallback("setup",m)},render:function(o){var p=this,q=p.settings,r=p.id,m=k.ScriptLoader;if(!j.domLoaded){j.add(window,"ready",function(){p.render()});return}tinyMCE.settings=q;if(!p.getElement()){return}if(k.isIDevice&&!k.isIOS5){return}if(!/TEXTAREA|INPUT/i.test(p.getElement().nodeName)&&q.hidden_input&&l.getParent(r,"form")){l.insertAfter(l.create("input",{type:"hidden",name:r}),r)}if(k.WindowManager){p.windowManager=new k.WindowManager(p)}if(q.encoding=="xml"){p.onGetContent.add(function(s,t){if(t.save){t.content=l.encode(t.content)}})}if(q.add_form_submit_trigger){p.onSubmit.addToTop(function(){if(p.initialized){p.save();p.isNotDirty=1}})}if(q.add_unload_trigger){p._beforeUnload=tinyMCE.onBeforeUnload.add(function(){if(p.initialized&&!p.destroyed&&!p.isHidden()){p.save({format:"raw",no_events:true})}})}k.addUnload(p.destroy,p);if(q.submit_patch){p.onBeforeRenderUI.add(function(){var s=p.getElement().form;if(!s){return}if(s._mceOldSubmit){return}if(!s.submit.nodeType&&!s.submit.length){p.formElement=s;s._mceOldSubmit=s.submit;s.submit=function(){k.triggerSave();p.isNotDirty=1;return p.formElement._mceOldSubmit(p.formElement)}}s=null})}function n(){if(q.language&&q.language_load!==false){m.add(k.baseURL+"/langs/"+q.language+".js")}if(q.theme&&q.theme.charAt(0)!="-"&&!h.urls[q.theme]){h.load(q.theme,"themes/"+q.theme+"/editor_template"+k.suffix+".js")}i(g(q.plugins),function(t){if(t&&!c.urls[t]){if(t.charAt(0)=="-"){t=t.substr(1,t.length);var s=c.dependencies(t);i(s,function(v){var u={prefix:"plugins/",resource:v,suffix:"/editor_plugin"+k.suffix+".js"};v=c.createUrl(u,v);c.load(v.resource,v)})}else{if(t=="safari"){return}c.load(t,{prefix:"plugins/",resource:t,suffix:"/editor_plugin"+k.suffix+".js"})}}});m.loadQueue(function(){if(!p.removed){p.init()}})}n()},init:function(){var q,F=this,G=F.settings,C,y,B=F.getElement(),p,m,D,v,A,E,x,r=[];k.add(F);G.aria_label=G.aria_label||l.getAttrib(B,"aria-label",F.getLang("aria.rich_text_area"));if(G.theme){G.theme=G.theme.replace(/-/,"");p=h.get(G.theme);F.theme=new p();if(F.theme.init){F.theme.init(F,h.urls[G.theme]||k.documentBaseURL.replace(/\/$/,""))}}function z(s){var t=c.get(s),o=c.urls[s]||k.documentBaseURL.replace(/\/$/,""),n;if(t&&k.inArray(r,s)===-1){i(c.dependencies(s),function(u){z(u)});n=new t(F,o);F.plugins[s]=n;if(n.init){n.init(F,o);r.push(s)}}}i(g(G.plugins.replace(/\-/g,"")),z);if(G.popup_css!==false){if(G.popup_css){G.popup_css=F.documentBaseURI.toAbsolute(G.popup_css)}else{G.popup_css=F.baseURI.toAbsolute("themes/"+G.theme+"/skins/"+G.skin+"/dialog.css")}}if(G.popup_css_add){G.popup_css+=","+F.documentBaseURI.toAbsolute(G.popup_css_add)}F.controlManager=new k.ControlManager(F);F.onExecCommand.add(function(n,o){if(!/^(FontName|FontSize)$/.test(o)){F.nodeChanged()}});F.onBeforeRenderUI.dispatch(F,F.controlManager);if(G.render_ui&&F.theme){C=G.width||B.style.width||B.offsetWidth;y=G.height||B.style.height||B.offsetHeight;F.orgDisplay=B.style.display;E=/^[0-9\.]+(|px)$/i;if(E.test(""+C)){C=Math.max(parseInt(C,10)+(p.deltaWidth||0),100)}if(E.test(""+y)){y=Math.max(parseInt(y,10)+(p.deltaHeight||0),100)}p=F.theme.renderUI({targetNode:B,width:C,height:y,deltaWidth:G.delta_width,deltaHeight:G.delta_height});F.editorContainer=p.editorContainer}if(G.content_css){i(g(G.content_css),function(n){F.contentCSS.push(F.documentBaseURI.toAbsolute(n))})}if(G.content_editable){B=q=p=null;return F.initContentBody()}if(document.domain&&location.hostname!=document.domain){k.relaxedDomain=document.domain}l.setStyles(p.sizeContainer||p.editorContainer,{width:C,height:y});y=(p.iframeHeight||y)+(typeof(y)=="number"?(p.deltaHeight||0):"");if(y<100){y=100}F.iframeHTML=G.doctype+'';if(G.document_base_url!=k.documentBaseURL){F.iframeHTML+=''}if(G.ie7_compat){F.iframeHTML+=''}else{F.iframeHTML+=''}F.iframeHTML+='';for(x=0;x'}F.contentCSS=[];v=G.body_id||"tinymce";if(v.indexOf("=")!=-1){v=F.getParam("body_id","","hash");v=v[F.id]||v}A=G.body_class||"";if(A.indexOf("=")!=-1){A=F.getParam("body_class","","hash");A=A[F.id]||""}F.iframeHTML+='
    ";if(k.relaxedDomain&&(b||(k.isOpera&&parseFloat(opera.version())<11))){D='javascript:(function(){document.open();document.domain="'+document.domain+'";var ed = window.parent.tinyMCE.get("'+F.id+'");document.write(ed.iframeHTML);document.close();ed.initContentBody();})()'}q=l.add(p.iframeContainer,"iframe",{id:F.id+"_ifr",src:D||'javascript:""',frameBorder:"0",allowTransparency:"true",title:G.aria_label,style:{width:"100%",height:y,display:"block"}});F.contentAreaContainer=p.iframeContainer;l.get(p.editorContainer).style.display=F.orgDisplay;l.get(F.id).style.display="none";l.setAttrib(F.id,"aria-hidden",true);if(!k.relaxedDomain||!D){F.initContentBody()}B=q=p=null},initContentBody:function(){var n=this,p=n.settings,q=l.get(n.id),r=n.getDoc(),o,m;if((!b||!k.relaxedDomain)&&!p.content_editable){r.open();r.write(n.iframeHTML);r.close();if(k.relaxedDomain){r.domain=k.relaxedDomain}}if(p.content_editable){l.addClass(q,"mceContentBody");n.contentDocument=r=p.content_document||document;n.contentWindow=p.content_window||window;n.bodyElement=q;p.content_document=p.content_window=null}m=n.getBody();m.disabled=true;if(!p.readonly){m.contentEditable=n.getParam("content_editable_state",true)}m.disabled=false;n.schema=new k.html.Schema(p);n.dom=new k.dom.DOMUtils(r,{keep_values:true,url_converter:n.convertURL,url_converter_scope:n,hex_colors:p.force_hex_style_colors,class_filter:p.class_filter,update_styles:true,root_element:p.content_editable?n.id:null,schema:n.schema});n.parser=new k.html.DomParser(p,n.schema);n.parser.addAttributeFilter("src,href,style",function(s,t){var u=s.length,x,z=n.dom,y,v;while(u--){x=s[u];y=x.attr(t);v="data-mce-"+t;if(!x.attributes.map[v]){if(t==="style"){x.attr(v,z.serializeStyle(z.parseStyle(y),x.name))}else{x.attr(v,n.convertURL(y,t,x.name))}}}});n.parser.addNodeFilter("script",function(s,t){var u=s.length,v;while(u--){v=s[u];v.attr("type","mce-"+(v.attr("type")||"text/javascript"))}});n.parser.addNodeFilter("#cdata",function(s,t){var u=s.length,v;while(u--){v=s[u];v.type=8;v.name="#comment";v.value="[CDATA["+v.value+"]]"}});n.parser.addNodeFilter("p,h1,h2,h3,h4,h5,h6,div",function(t,u){var v=t.length,x,s=n.schema.getNonEmptyElements();while(v--){x=t[v];if(x.isEmpty(s)){x.empty().append(new k.html.Node("br",1)).shortEnded=true}}});n.serializer=new k.dom.Serializer(p,n.dom,n.schema);n.selection=new k.dom.Selection(n.dom,n.getWin(),n.serializer);n.formatter=new k.Formatter(n);n.undoManager=new k.UndoManager(n);n.forceBlocks=new k.ForceBlocks(n);n.enterKey=new k.EnterKey(n);n.editorCommands=new k.EditorCommands(n);n.serializer.onPreProcess.add(function(s,t){return n.onPreProcess.dispatch(n,t,s)});n.serializer.onPostProcess.add(function(s,t){return n.onPostProcess.dispatch(n,t,s)});n.onPreInit.dispatch(n);if(!p.gecko_spellcheck){r.body.spellcheck=false}if(!p.readonly){n.bindNativeEvents()}n.controlManager.onPostRender.dispatch(n,n.controlManager);n.onPostRender.dispatch(n);n.quirks=k.util.Quirks(n);if(p.directionality){m.dir=p.directionality}if(p.nowrap){m.style.whiteSpace="nowrap"}if(p.protect){n.onBeforeSetContent.add(function(s,t){i(p.protect,function(u){t.content=t.content.replace(u,function(v){return""})})})}n.onSetContent.add(function(){n.addVisual(n.getBody())});if(p.padd_empty_editor){n.onPostProcess.add(function(s,t){t.content=t.content.replace(/^(]*>( | |\s|\u00a0|)<\/p>[\r\n]*|
    [\r\n]*)$/,"")})}n.load({initial:true,format:"html"});n.startContent=n.getContent({format:"raw"});n.initialized=true;n.onInit.dispatch(n);n.execCallback("setupcontent_callback",n.id,m,r);n.execCallback("init_instance_callback",n);n.focus(true);n.nodeChanged({initial:true});i(n.contentCSS,function(s){n.dom.loadCSS(s)});if(p.auto_focus){setTimeout(function(){var s=k.get(p.auto_focus);s.selection.select(s.getBody(),1);s.selection.collapse(1);s.getBody().focus();s.getWin().focus()},100)}q=r=m=null},focus:function(p){var o,u=this,t=u.selection,q=u.settings.content_editable,n,r,s=u.getDoc(),m;if(!p){n=t.getRng();if(n.item){r=n.item(0)}u._refreshContentEditable();if(!q){u.getWin().focus()}if(k.isGecko||q){m=u.getBody();if(m.setActive){m.setActive()}else{m.focus()}if(q){t.normalize()}}if(r&&r.ownerDocument==s){n=s.body.createControlRange();n.addElement(r);n.select()}}if(k.activeEditor!=u){if((o=k.activeEditor)!=null){o.onDeactivate.dispatch(o,u)}u.onActivate.dispatch(u,o)}k._setActive(u)},execCallback:function(q){var m=this,p=m.settings[q],o;if(!p){return}if(m.callbackLookup&&(o=m.callbackLookup[q])){p=o.func;o=o.scope}if(d(p,"string")){o=p.replace(/\.\w+$/,"");o=o?k.resolve(o):0;p=k.resolve(p);m.callbackLookup=m.callbackLookup||{};m.callbackLookup[q]={func:p,scope:o}}return p.apply(o||m,Array.prototype.slice.call(arguments,1))},translate:function(m){var o=this.settings.language||"en",n=k.i18n;if(!m){return""}return n[o+"."+m]||m.replace(/\{\#([^\}]+)\}/g,function(q,p){return n[o+"."+p]||"{#"+p+"}"})},getLang:function(o,m){return k.i18n[(this.settings.language||"en")+"."+o]||(d(m)?m:"{#"+o+"}")},getParam:function(t,q,m){var r=k.trim,p=d(this.settings[t])?this.settings[t]:q,s;if(m==="hash"){s={};if(d(p,"string")){i(p.indexOf("=")>0?p.split(/[;,](?![^=;,]*(?:[;,]|$))/):p.split(","),function(n){n=n.split("=");if(n.length>1){s[r(n[0])]=r(n[1])}else{s[r(n[0])]=r(n)}})}else{s=p}return s}return p},nodeChanged:function(q){var m=this,n=m.selection,p;if(m.initialized){q=q||{};p=n.getStart()||m.getBody();p=b&&p.ownerDocument!=m.getDoc()?m.getBody():p;q.parents=[];m.dom.getParent(p,function(o){if(o.nodeName=="BODY"){return true}q.parents.push(o)});m.onNodeChange.dispatch(m,q?q.controlManager||m.controlManager:m.controlManager,p,n.isCollapsed(),q)}},addButton:function(n,o){var m=this;m.buttons=m.buttons||{};m.buttons[n]=o},addCommand:function(m,o,n){this.execCommands[m]={func:o,scope:n||this}},addQueryStateHandler:function(m,o,n){this.queryStateCommands[m]={func:o,scope:n||this}},addQueryValueHandler:function(m,o,n){this.queryValueCommands[m]={func:o,scope:n||this}},addShortcut:function(o,q,m,p){var n=this,r;if(n.settings.custom_shortcuts===false){return false}n.shortcuts=n.shortcuts||{};if(d(m,"string")){r=m;m=function(){n.execCommand(r,false,null)}}if(d(m,"object")){r=m;m=function(){n.execCommand(r[0],r[1],r[2])}}i(g(o),function(s){var t={func:m,scope:p||this,desc:n.translate(q),alt:false,ctrl:false,shift:false};i(g(s,"+"),function(u){switch(u){case"alt":case"ctrl":case"shift":t[u]=true;break;default:t.charCode=u.charCodeAt(0);t.keyCode=u.toUpperCase().charCodeAt(0)}});n.shortcuts[(t.ctrl?"ctrl":"")+","+(t.alt?"alt":"")+","+(t.shift?"shift":"")+","+t.keyCode]=t});return true},execCommand:function(u,r,x,m){var p=this,q=0,v,n;if(!/^(mceAddUndoLevel|mceEndUndoLevel|mceBeginUndoLevel|mceRepaint|SelectAll)$/.test(u)&&(!m||!m.skip_focus)){p.focus()}m=f({},m);p.onBeforeExecCommand.dispatch(p,u,r,x,m);if(m.terminate){return false}if(p.execCallback("execcommand_callback",p.id,p.selection.getNode(),u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(v=p.execCommands[u]){n=v.func.call(v.scope,r,x);if(n!==true){p.onExecCommand.dispatch(p,u,r,x,m);return n}}i(p.plugins,function(o){if(o.execCommand&&o.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);q=1;return false}});if(q){return true}if(p.theme&&p.theme.execCommand&&p.theme.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}if(p.editorCommands.execCommand(u,r,x)){p.onExecCommand.dispatch(p,u,r,x,m);return true}p.getDoc().execCommand(u,r,x);p.onExecCommand.dispatch(p,u,r,x,m)},queryCommandState:function(q){var n=this,r,p;if(n._isHidden()){return}if(r=n.queryStateCommands[q]){p=r.func.call(r.scope);if(p!==true){return p}}r=n.editorCommands.queryCommandState(q);if(r!==-1){return r}try{return this.getDoc().queryCommandState(q)}catch(m){}},queryCommandValue:function(r){var n=this,q,p;if(n._isHidden()){return}if(q=n.queryValueCommands[r]){p=q.func.call(q.scope);if(p!==true){return p}}q=n.editorCommands.queryCommandValue(r);if(d(q)){return q}try{return this.getDoc().queryCommandValue(r)}catch(m){}},show:function(){var m=this;l.show(m.getContainer());l.hide(m.id);m.load()},hide:function(){var m=this,n=m.getDoc();if(b&&n){n.execCommand("SelectAll")}m.save();l.hide(m.getContainer());l.setStyle(m.id,"display",m.orgDisplay)},isHidden:function(){return !l.isHidden(this.id)},setProgressState:function(m,n,p){this.onSetProgressState.dispatch(this,m,n,p);return m},load:function(q){var m=this,p=m.getElement(),n;if(p){q=q||{};q.load=true;n=m.setContent(d(p.value)?p.value:p.innerHTML,q);q.element=p;if(!q.no_events){m.onLoadContent.dispatch(m,q)}q.element=p=null;return n}},save:function(r){var m=this,q=m.getElement(),n,p;if(!q||!m.initialized){return}r=r||{};r.save=true;r.element=q;n=r.content=m.getContent(r);if(!r.no_events){m.onSaveContent.dispatch(m,r)}n=r.content;if(!/TEXTAREA|INPUT/i.test(q.nodeName)){q.innerHTML=n;if(p=l.getParent(m.id,"form")){i(p.elements,function(o){if(o.name==m.id){o.value=n;return false}})}}else{q.value=n}r.element=q=null;return n},setContent:function(r,p){var o=this,n,m=o.getBody(),q;p=p||{};p.format=p.format||"html";p.set=true;p.content=r;if(!p.no_events){o.onBeforeSetContent.dispatch(o,p)}r=p.content;if(!k.isIE&&(r.length===0||/^\s+$/.test(r))){q=o.settings.forced_root_block;if(q){r="<"+q+'>
    "}else{r='
    '}m.innerHTML=r;o.selection.select(m,true);o.selection.collapse(true);return}if(p.format!=="raw"){r=new k.html.Serializer({},o.schema).serialize(o.parser.parse(r))}p.content=k.trim(r);o.dom.setHTML(m,p.content);if(!p.no_events){o.onSetContent.dispatch(o,p)}o.selection.normalize();return p.content},getContent:function(n){var m=this,o;n=n||{};n.format=n.format||"html";n.get=true;n.getInner=true;if(!n.no_events){m.onBeforeGetContent.dispatch(m,n)}if(n.format=="raw"){o=m.getBody().innerHTML}else{o=m.serializer.serialize(m.getBody(),n)}n.content=k.trim(o);if(!n.no_events){m.onGetContent.dispatch(m,n)}return n.content},isDirty:function(){var m=this;return k.trim(m.startContent)!=k.trim(m.getContent({format:"raw",no_events:1}))&&!m.isNotDirty},getContainer:function(){var m=this;if(!m.container){m.container=l.get(m.editorContainer||m.id+"_parent")}return m.container},getContentAreaContainer:function(){return this.contentAreaContainer},getElement:function(){return l.get(this.settings.content_element||this.id)},getWin:function(){var m=this,n;if(!m.contentWindow){n=l.get(m.id+"_ifr");if(n){m.contentWindow=n.contentWindow}}return m.contentWindow},getDoc:function(){var m=this,n;if(!m.contentDocument){n=m.getWin();if(n){m.contentDocument=n.document}}return m.contentDocument},getBody:function(){return this.bodyElement||this.getDoc().body},convertURL:function(o,n,q){var m=this,p=m.settings;if(p.urlconverter_callback){return m.execCallback("urlconverter_callback",o,q,true,n)}if(!p.convert_urls||(q&&q.nodeName=="LINK")||o.indexOf("file:")===0){return o}if(p.relative_urls){return m.documentBaseURI.toRelative(o)}o=m.documentBaseURI.toAbsolute(o,p.remove_script_host);return o},addVisual:function(q){var n=this,o=n.settings,p=n.dom,m;q=q||n.getBody();if(!d(n.hasVisual)){n.hasVisual=o.visual}i(p.select("table,a",q),function(s){var r;switch(s.nodeName){case"TABLE":m=o.visual_table_class||"mceItemTable";r=p.getAttrib(s,"border");if(!r||r=="0"){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}return;case"A":r=p.getAttrib(s,"name");m="mceItemAnchor";if(r){if(n.hasVisual){p.addClass(s,m)}else{p.removeClass(s,m)}}return}});n.onVisualAid.dispatch(n,q,n.hasVisual)},remove:function(){var m=this,n=m.getContainer();if(!m.removed){m.removed=1;m.hide();if(!m.settings.content_editable){j.clear(m.getWin());j.clear(m.getDoc())}j.clear(m.getBody());j.clear(m.formElement);j.unbind(n);m.execCallback("remove_instance_callback",m);m.onRemove.dispatch(m);m.onExecCommand.listeners=[];k.remove(m);l.remove(n)}},destroy:function(n){var m=this;if(m.destroyed){return}if(a){j.unbind(m.getDoc());j.unbind(m.getWin());j.unbind(m.getBody())}if(!n){k.removeUnload(m.destroy);tinyMCE.onBeforeUnload.remove(m._beforeUnload);if(m.theme&&m.theme.destroy){m.theme.destroy()}m.controlManager.destroy();m.selection.destroy();m.dom.destroy()}if(m.formElement){m.formElement.submit=m.formElement._mceOldSubmit;m.formElement._mceOldSubmit=null}m.contentAreaContainer=m.formElement=m.container=m.settings.content_element=m.bodyElement=m.contentDocument=m.contentWindow=null;if(m.selection){m.selection=m.selection.win=m.selection.dom=m.selection.dom.doc=null}m.destroyed=1},_refreshContentEditable:function(){var n=this,m,o;if(n._isHidden()){m=n.getBody();o=m.parentNode;o.removeChild(m);o.appendChild(m);m.focus()}},_isHidden:function(){var m;if(!a){return 0}m=this.selection.getSel();return(!m||!m.rangeCount||m.rangeCount===0)}})})(tinymce);(function(a){var b=a.each;a.Editor.prototype.setupEvents=function(){var c=this,d=c.settings;b(["onPreInit","onBeforeRenderUI","onPostRender","onLoad","onInit","onRemove","onActivate","onDeactivate","onClick","onEvent","onMouseUp","onMouseDown","onDblClick","onKeyDown","onKeyUp","onKeyPress","onContextMenu","onSubmit","onReset","onPaste","onPreProcess","onPostProcess","onBeforeSetContent","onBeforeGetContent","onSetContent","onGetContent","onLoadContent","onSaveContent","onNodeChange","onChange","onBeforeExecCommand","onExecCommand","onUndo","onRedo","onVisualAid","onSetProgressState","onSetAttrib"],function(e){c[e]=new a.util.Dispatcher(c)});if(d.cleanup_callback){c.onBeforeSetContent.add(function(e,f){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)});c.onPreProcess.add(function(e,f){if(f.set){e.execCallback("cleanup_callback","insert_to_editor_dom",f.node,f)}if(f.get){e.execCallback("cleanup_callback","get_from_editor_dom",f.node,f)}});c.onPostProcess.add(function(e,f){if(f.set){f.content=e.execCallback("cleanup_callback","insert_to_editor",f.content,f)}if(f.get){f.content=e.execCallback("cleanup_callback","get_from_editor",f.content,f)}})}if(d.save_callback){c.onGetContent.add(function(e,f){if(f.save){f.content=e.execCallback("save_callback",e.id,f.content,e.getBody())}})}if(d.handle_event_callback){c.onEvent.add(function(f,g,h){if(c.execCallback("handle_event_callback",g,f,h)===false){Event.cancel(g)}})}if(d.handle_node_change_callback){c.onNodeChange.add(function(f,e,g){f.execCallback("handle_node_change_callback",f.id,g,-1,-1,true,f.selection.isCollapsed())})}if(d.save_callback){c.onSaveContent.add(function(e,g){var f=e.execCallback("save_callback",e.id,g.content,e.getBody());if(f){g.content=f}})}if(d.onchange_callback){c.onChange.add(function(f,e){f.execCallback("onchange_callback",f,e)})}};a.Editor.prototype.bindNativeEvents=function(){var l=this,f,d=l.settings,e=l.dom,h;h={mouseup:"onMouseUp",mousedown:"onMouseDown",click:"onClick",keyup:"onKeyUp",keydown:"onKeyDown",keypress:"onKeyPress",submit:"onSubmit",reset:"onReset",contextmenu:"onContextMenu",dblclick:"onDblClick",paste:"onPaste"};function c(i,m){var n=i.type;if(l.removed){return}if(l.onEvent.dispatch(l,i,m)!==false){l[h[i.fakeType||i.type]].dispatch(l,i,m)}}function j(i){l.focus(true)}function k(){l.selection.normalize();l.nodeChanged()}b(h,function(m,n){var i=d.content_editable?l.getBody():l.getDoc();switch(n){case"contextmenu":e.bind(i,n,c);break;case"paste":e.bind(l.getBody(),n,c);break;case"submit":case"reset":e.bind(l.getElement().form||a.DOM.getParent(l.id,"form"),n,c);break;default:e.bind(i,n,c)}});e.bind(d.content_editable?l.getBody():(a.isGecko?l.getDoc():l.getWin()),"focus",function(i){l.focus(true)});if(d.content_editable&&a.isOpera){e.bind(l.getBody(),"click",j);e.bind(l.getBody(),"keydown",j)}l.onMouseUp.add(k);l.onKeyUp.add(function(i,n){var m=n.keyCode;if((m>=33&&m<=36)||(m>=37&&m<=40)||m==13||m==45||m==46||m==8||(a.isMac&&(m==91||m==93))||n.ctrlKey){k()}});l.onReset.add(function(){l.setContent(l.startContent,{format:"raw"})});function g(m,i){if(m.altKey||m.ctrlKey||m.metaKey){b(l.shortcuts,function(n){var o=a.isMac?m.metaKey:m.ctrlKey;if(n.ctrl!=o||n.alt!=m.altKey||n.shift!=m.shiftKey){return}if(m.keyCode==n.keyCode||(m.charCode&&m.charCode==n.charCode)){m.preventDefault();if(i){n.func.call(n.scope)}return true}})}}l.onKeyUp.add(function(i,m){g(m)});l.onKeyPress.add(function(i,m){g(m)});l.onKeyDown.add(function(i,m){g(m,true)});if(a.isOpera){l.onClick.add(function(i,m){m.preventDefault()})}}})(tinymce);(function(d){var e=d.each,b,a=true,c=false;d.EditorCommands=function(n){var m=n.dom,p=n.selection,j={state:{},exec:{},value:{}},k=n.settings,q=n.formatter,o;function r(z,y,x){var v;z=z.toLowerCase();if(v=j.exec[z]){v(z,y,x);return a}return c}function l(x){var v;x=x.toLowerCase();if(v=j.state[x]){return v(x)}return -1}function h(x){var v;x=x.toLowerCase();if(v=j.value[x]){return v(x)}return c}function u(v,x){x=x||"exec";e(v,function(z,y){e(y.toLowerCase().split(","),function(A){j[x][A]=z})})}d.extend(this,{execCommand:r,queryCommandState:l,queryCommandValue:h,addCommands:u});function f(y,x,v){if(x===b){x=c}if(v===b){v=null}return n.getDoc().execCommand(y,x,v)}function t(v){return q.match(v)}function s(v,x){q.toggle(v,x?{value:x}:b)}function i(v){o=p.getBookmark(v)}function g(){p.moveToBookmark(o)}u({"mceResetDesignMode,mceBeginUndoLevel":function(){},"mceEndUndoLevel,mceAddUndoLevel":function(){n.undoManager.add()},"Cut,Copy,Paste":function(z){var y=n.getDoc(),v;try{f(z)}catch(x){v=a}if(v||!y.queryCommandSupported(z)){if(d.isGecko){n.windowManager.confirm(n.getLang("clipboard_msg"),function(A){if(A){open("http://www.mozilla.org/editor/midasdemo/securityprefs.html","_blank")}})}else{n.windowManager.alert(n.getLang("clipboard_no_support"))}}},unlink:function(v){if(p.isCollapsed()){p.select(p.getNode())}f(v);p.collapse(c)},"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(v){var x=v.substring(7);e("left,center,right,full".split(","),function(y){if(x!=y){q.remove("align"+y)}});s("align"+x);r("mceRepaint")},"InsertUnorderedList,InsertOrderedList":function(y){var v,x;f(y);v=m.getParent(p.getNode(),"ol,ul");if(v){x=v.parentNode;if(/^(H[1-6]|P|ADDRESS|PRE)$/.test(x.nodeName)){i();m.split(x,v);g()}}},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){s(v)},"ForeColor,HiliteColor,FontName":function(y,x,v){s(y,v)},FontSize:function(z,y,x){var v,A;if(x>=1&&x<=7){A=d.explode(k.font_size_style_values);v=d.explode(k.font_size_classes);if(v){x=v[x-1]||x}else{x=A[x-1]||x}}s(z,x)},RemoveFormat:function(v){q.remove(v)},mceBlockQuote:function(v){s("blockquote")},FormatBlock:function(y,x,v){return s(v||"p")},mceCleanup:function(){var v=p.getBookmark();n.setContent(n.getContent({cleanup:a}),{cleanup:a});p.moveToBookmark(v)},mceRemoveNode:function(z,y,x){var v=x||p.getNode();if(v!=n.getBody()){i();n.dom.remove(v,a);g()}},mceSelectNodeDepth:function(z,y,x){var v=0;m.getParent(p.getNode(),function(A){if(A.nodeType==1&&v++==x){p.select(A);return c}},n.getBody())},mceSelectNode:function(y,x,v){p.select(v)},mceInsertContent:function(B,I,K){var y,J,E,z,F,G,D,C,L,x,A,M,v,H;y=n.parser;J=new d.html.Serializer({},n.schema);v='\uFEFF';G={content:K,format:"html"};p.onBeforeSetContent.dispatch(p,G);K=G.content;if(K.indexOf("{$caret}")==-1){K+="{$caret}"}K=K.replace(/\{\$caret\}/,v);if(!p.isCollapsed()){n.getDoc().execCommand("Delete",false,null)}E=p.getNode();G={context:E.nodeName.toLowerCase()};F=y.parse(K,G);A=F.lastChild;if(A.attr("id")=="mce_marker"){D=A;for(A=A.prev;A;A=A.walk(true)){if(A.type==3||!m.isBlock(A.name)){A.parent.insert(D,A,A.name==="br");break}}}if(!G.invalid){K=J.serialize(F);A=E.firstChild;M=E.lastChild;if(!A||(A===M&&A.nodeName==="BR")){m.setHTML(E,K)}else{p.setContent(K)}}else{p.setContent(v);E=n.selection.getNode();z=n.getBody();if(E.nodeType==9){E=A=z}else{A=E}while(A!==z){E=A;A=A.parentNode}K=E==z?z.innerHTML:m.getOuterHTML(E);K=J.serialize(y.parse(K.replace(//i,function(){return J.serialize(F)})));if(E==z){m.setHTML(z,K)}else{m.setOuterHTML(E,K)}}D=m.get("mce_marker");C=m.getRect(D);L=m.getViewPort(n.getWin());if((C.y+C.h>L.y+L.h||C.yL.x+L.w||C.x")},mceToggleVisualAid:function(){n.hasVisual=!n.hasVisual;n.addVisual()},mceReplaceContent:function(y,x,v){n.execCommand("mceInsertContent",false,v.replace(/\{\$selection\}/g,p.getContent({format:"text"})))},mceInsertLink:function(z,y,x){var v;if(typeof(x)=="string"){x={href:x}}v=m.getParent(p.getNode(),"a");x.href=x.href.replace(" ","%20");if(!v||!x.href){q.remove("link")}if(x.href){q.apply("link",x,v)}},selectAll:function(){var x=m.getRoot(),v=m.createRng();v.setStart(x,0);v.setEnd(x,x.childNodes.length);n.selection.setRng(v)}});u({"JustifyLeft,JustifyCenter,JustifyRight,JustifyFull":function(z){var x="align"+z.substring(7);var v=p.isCollapsed()?[m.getParent(p.getNode(),m.isBlock)]:p.getSelectedBlocks();var y=d.map(v,function(A){return !!q.matchNode(A,x)});return d.inArray(y,a)!==-1},"Bold,Italic,Underline,Strikethrough,Superscript,Subscript":function(v){return t(v)},mceBlockQuote:function(){return t("blockquote")},Outdent:function(){var v;if(k.inline_styles){if((v=m.getParent(p.getStart(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}if((v=m.getParent(p.getEnd(),m.isBlock))&&parseInt(v.style.paddingLeft)>0){return a}}return l("InsertUnorderedList")||l("InsertOrderedList")||(!k.inline_styles&&!!m.getParent(p.getNode(),"BLOCKQUOTE"))},"InsertUnorderedList,InsertOrderedList":function(v){return m.getParent(p.getNode(),v=="insertunorderedlist"?"UL":"OL")}},"state");u({"FontSize,FontName":function(y){var x=0,v;if(v=m.getParent(p.getNode(),"span")){if(y=="fontsize"){x=v.style.fontSize}else{x=v.style.fontFamily.replace(/, /g,",").replace(/[\'\"]/g,"").toLowerCase()}}return x}},"value");u({Undo:function(){n.undoManager.undo()},Redo:function(){n.undoManager.redo()}})}})(tinymce);(function(b){var a=b.util.Dispatcher;b.UndoManager=function(h){var l,i=0,e=[],g,k,j,f;function c(){return b.trim(h.getContent({format:"raw",no_events:1}).replace(/]+data-mce-bogus[^>]+>[\u200B\uFEFF]+<\/span>/g,""))}function d(){l.typing=false;l.add()}k=new a(l);j=new a(l);f=new a(l);k.add(function(m,n){if(m.hasUndo()){return h.onChange.dispatch(h,n,m)}});j.add(function(m,n){return h.onUndo.dispatch(h,n,m)});f.add(function(m,n){return h.onRedo.dispatch(h,n,m)});h.onInit.add(function(){l.add()});h.onBeforeExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.beforeChange()}});h.onExecCommand.add(function(m,p,o,q,n){if(p!="Undo"&&p!="Redo"&&p!="mceRepaint"&&(!n||!n.skip_undo)){l.add()}});h.onSaveContent.add(d);h.dom.bind(h.dom.getRoot(),"dragend",d);h.dom.bind(h.getDoc(),b.isGecko?"blur":"focusout",function(m){if(!h.removed&&l.typing){d()}});h.onKeyUp.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45||n==13||o.ctrlKey){d()}});h.onKeyDown.add(function(m,o){var n=o.keyCode;if((n>=33&&n<=36)||(n>=37&&n<=40)||n==45){if(l.typing){d()}return}if((n<16||n>20)&&n!=224&&n!=91&&!l.typing){l.beforeChange();l.typing=true;l.add()}});h.onMouseDown.add(function(m,n){if(l.typing){d()}});h.addShortcut("ctrl+z","undo_desc","Undo");h.addShortcut("ctrl+y","redo_desc","Redo");l={data:e,typing:false,onAdd:k,onUndo:j,onRedo:f,beforeChange:function(){g=h.selection.getBookmark(2,true)},add:function(p){var m,n=h.settings,o;p=p||{};p.content=c();o=e[i];if(o&&o.content==p.content){return null}if(e[i]){e[i].beforeBookmark=g}if(n.custom_undo_redo_levels){if(e.length>n.custom_undo_redo_levels){for(m=0;m0){n=e[--i];h.setContent(n.content,{format:"raw"});h.selection.moveToBookmark(n.beforeBookmark);l.onUndo.dispatch(l,n)}return n},redo:function(){var m;if(i0||this.typing},hasRedo:function(){return i0){g.moveEnd("character",q)}g.select()}catch(n){}}if(p){c.nodeChanged()}}if(b.forced_root_block){c.onKeyUp.add(f);c.onNodeChange.add(f)}};(function(c){var b=c.DOM,a=c.dom.Event,d=c.each,e=c.extend;c.create("tinymce.ControlManager",{ControlManager:function(f,j){var h=this,g;j=j||{};h.editor=f;h.controls={};h.onAdd=new c.util.Dispatcher(h);h.onPostRender=new c.util.Dispatcher(h);h.prefix=j.prefix||f.id+"_";h._cls={};h.onPostRender.add(function(){d(h.controls,function(i){i.postRender()})})},get:function(f){return this.controls[this.prefix+f]||this.controls[f]},setActive:function(h,f){var g=null;if(g=this.get(h)){g.setActive(f)}return g},setDisabled:function(h,f){var g=null;if(g=this.get(h)){g.setDisabled(f)}return g},add:function(g){var f=this;if(g){f.controls[g.id]=g;f.onAdd.dispatch(g,f)}return g},createControl:function(i){var h,g=this,f=g.editor;d(f.plugins,function(j){if(j.createControl){h=j.createControl(i,g);if(h){return false}}});switch(i){case"|":case"separator":return g.createSeparator()}if(!h&&f.buttons&&(h=f.buttons[i])){return g.createButton(i,h)}return g.add(h)},createDropMenu:function(f,n,h){var m=this,i=m.editor,j,g,k,l;n=e({"class":"mceDropDown",constrain:i.settings.constrain_menus},n);n["class"]=n["class"]+" "+i.getParam("skin")+"Skin";if(k=i.getParam("skin_variant")){n["class"]+=" "+i.getParam("skin")+"Skin"+k.substring(0,1).toUpperCase()+k.substring(1)}n["class"]+=i.settings.directionality=="rtl"?" mceRtl":"";f=m.prefix+f;l=h||m._cls.dropmenu||c.ui.DropMenu;j=m.controls[f]=new l(f,n);j.onAddItem.add(function(r,q){var p=q.settings;p.title=i.getLang(p.title,p.title);if(!p.onclick){p.onclick=function(o){if(p.cmd){i.execCommand(p.cmd,p.ui||false,p.value)}}}});i.onRemove.add(function(){j.destroy()});if(c.isIE){j.onShowMenu.add(function(){i.focus();g=i.selection.getBookmark(1)});j.onHideMenu.add(function(){if(g){i.selection.moveToBookmark(g);g=0}})}return m.add(j)},createListBox:function(f,n,h){var l=this,j=l.editor,i,k,m;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,scope:n.scope,control_manager:l},n);f=l.prefix+f;function g(o){return o.settings.use_accessible_selects&&!c.isGecko}if(j.settings.use_native_selects||g(j)){k=new c.ui.NativeListBox(f,n)}else{m=h||l._cls.listbox||c.ui.ListBox;k=new m(f,n,j)}l.controls[f]=k;if(c.isWebKit){k.onPostRender.add(function(p,o){a.add(o,"mousedown",function(){j.bookmark=j.selection.getBookmark(1)});a.add(o,"focus",function(){j.selection.moveToBookmark(j.bookmark);j.bookmark=null})})}if(k.hideMenu){j.onMouseDown.add(k.hideMenu,k)}return l.add(k)},createButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.label=g.translate(i.label);i.scope=i.scope||g;if(!i.onclick&&!i.menu_button){i.onclick=function(){g.execCommand(i.cmd,i.ui||false,i.value)}}i=e({title:i.title,"class":"mce_"+m,unavailable_prefix:g.getLang("unavailable",""),scope:i.scope,control_manager:h},i);m=h.prefix+m;if(i.menu_button){f=l||h._cls.menubutton||c.ui.MenuButton;k=new f(m,i,g);g.onMouseDown.add(k.hideMenu,k)}else{f=h._cls.button||c.ui.Button;k=new f(m,i,g)}return h.add(k)},createMenuButton:function(h,f,g){f=f||{};f.menu_button=1;return this.createButton(h,f,g)},createSplitButton:function(m,i,l){var h=this,g=h.editor,j,k,f;if(h.get(m)){return null}i.title=g.translate(i.title);i.scope=i.scope||g;if(!i.onclick){i.onclick=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}if(!i.onselect){i.onselect=function(n){g.execCommand(i.cmd,i.ui||false,n||i.value)}}i=e({title:i.title,"class":"mce_"+m,scope:i.scope,control_manager:h},i);m=h.prefix+m;f=l||h._cls.splitbutton||c.ui.SplitButton;k=h.add(new f(m,i,g));g.onMouseDown.add(k.hideMenu,k);return k},createColorSplitButton:function(f,n,h){var l=this,j=l.editor,i,k,m,g;if(l.get(f)){return null}n.title=j.translate(n.title);n.scope=n.scope||j;if(!n.onclick){n.onclick=function(o){if(c.isIE){g=j.selection.getBookmark(1)}j.execCommand(n.cmd,n.ui||false,o||n.value)}}if(!n.onselect){n.onselect=function(o){j.execCommand(n.cmd,n.ui||false,o||n.value)}}n=e({title:n.title,"class":"mce_"+f,menu_class:j.getParam("skin")+"Skin",scope:n.scope,more_colors_title:j.getLang("more_colors")},n);f=l.prefix+f;m=h||l._cls.colorsplitbutton||c.ui.ColorSplitButton;k=new m(f,n,j);j.onMouseDown.add(k.hideMenu,k);j.onRemove.add(function(){k.destroy()});if(c.isIE){k.onShowMenu.add(function(){j.focus();g=j.selection.getBookmark(1)});k.onHideMenu.add(function(){if(g){j.selection.moveToBookmark(g);g=0}})}return l.add(k)},createToolbar:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||g._cls.toolbar||c.ui.Toolbar;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createToolbarGroup:function(k,h,j){var i,g=this,f;k=g.prefix+k;f=j||this._cls.toolbarGroup||c.ui.ToolbarGroup;i=new f(k,h,g.editor);if(g.get(k)){return null}return g.add(i)},createSeparator:function(g){var f=g||this._cls.separator||c.ui.Separator;return new f()},setControlType:function(g,f){return this._cls[g.toLowerCase()]=f},destroy:function(){d(this.controls,function(f){f.destroy()});this.controls=null}})})(tinymce);(function(d){var a=d.util.Dispatcher,e=d.each,c=d.isIE,b=d.isOpera;d.create("tinymce.WindowManager",{WindowManager:function(f){var g=this;g.editor=f;g.onOpen=new a(g);g.onClose=new a(g);g.params={};g.features={}},open:function(z,h){var v=this,k="",n,m,i=v.editor.settings.dialog_type=="modal",q,o,j,g=d.DOM.getViewPort(),r;z=z||{};h=h||{};o=b?g.w:screen.width;j=b?g.h:screen.height;z.name=z.name||"mc_"+new Date().getTime();z.width=parseInt(z.width||320);z.height=parseInt(z.height||240);z.resizable=true;z.left=z.left||parseInt(o/2)-(z.width/2);z.top=z.top||parseInt(j/2)-(z.height/2);h.inline=false;h.mce_width=z.width;h.mce_height=z.height;h.mce_auto_focus=z.auto_focus;if(i){if(c){z.center=true;z.help=false;z.dialogWidth=z.width+"px";z.dialogHeight=z.height+"px";z.scroll=z.scrollbars||false}}e(z,function(p,f){if(d.is(p,"boolean")){p=p?"yes":"no"}if(!/^(name|url)$/.test(f)){if(c&&i){k+=(k?";":"")+f+":"+p}else{k+=(k?",":"")+f+"="+p}}});v.features=z;v.params=h;v.onOpen.dispatch(v,z,h);r=z.url||z.file;r=d._addVer(r);try{if(c&&i){q=1;window.showModalDialog(r,window,k)}else{q=window.open(r,z.name,k)}}catch(l){}if(!q){alert(v.editor.getLang("popup_blocked"))}},close:function(f){f.close();this.onClose.dispatch(this)},createInstance:function(i,h,g,m,l,k){var j=d.resolve(i);return new j(h,g,m,l,k)},confirm:function(h,f,i,g){g=g||window;f.call(i||this,g.confirm(this._decode(this.editor.getLang(h,h))))},alert:function(h,f,j,g){var i=this;g=g||window;g.alert(i._decode(i.editor.getLang(h,h)));if(f){f.call(j||i)}},resizeBy:function(f,g,h){h.resizeBy(f,g)},_decode:function(f){return d.DOM.decode(f).replace(/\\n/g,"\n")}})}(tinymce));(function(a){a.Formatter=function(Y){var O={},R=a.each,c=Y.dom,r=Y.selection,t=a.dom.TreeWalker,M=new a.dom.RangeUtils(c),d=Y.schema.isValidChild,H=c.isBlock,m=Y.settings.forced_root_block,s=c.nodeIndex,G=a.isGecko?"\u200B":"\uFEFF",e=/^(src|href|style)$/,V=false,C=true,D,x=c.getContentEditable;function A(Z){return Z instanceof Array}function n(aa,Z){return c.getParents(aa,Z,c.getRoot())}function b(Z){return Z.nodeType===1&&Z.id==="_mce_caret"}function j(){l({alignleft:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"left"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"left"}}],aligncenter:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"center"},defaultBlock:"div"},{selector:"img",collapsed:false,styles:{display:"block",marginLeft:"auto",marginRight:"auto"}},{selector:"table",collapsed:false,styles:{marginLeft:"auto",marginRight:"auto"}}],alignright:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"right"},defaultBlock:"div"},{selector:"img,table",collapsed:false,styles:{"float":"right"}}],alignfull:[{selector:"figure,p,h1,h2,h3,h4,h5,h6,td,th,div,ul,ol,li",styles:{textAlign:"justify"},defaultBlock:"div"}],bold:[{inline:"strong",remove:"all"},{inline:"span",styles:{fontWeight:"bold"}},{inline:"b",remove:"all"}],italic:[{inline:"em",remove:"all"},{inline:"span",styles:{fontStyle:"italic"}},{inline:"i",remove:"all"}],underline:[{inline:"span",styles:{textDecoration:"underline"},exact:true},{inline:"u",remove:"all"}],strikethrough:[{inline:"span",styles:{textDecoration:"line-through"},exact:true},{inline:"strike",remove:"all"}],forecolor:{inline:"span",styles:{color:"%value"},wrap_links:false},hilitecolor:{inline:"span",styles:{backgroundColor:"%value"},wrap_links:false},fontname:{inline:"span",styles:{fontFamily:"%value"}},fontsize:{inline:"span",styles:{fontSize:"%value"}},fontsize_class:{inline:"span",attributes:{"class":"%value"}},blockquote:{block:"blockquote",wrapper:1,remove:"all"},subscript:{inline:"sub"},superscript:{inline:"sup"},link:{inline:"a",selector:"a",remove:"all",split:true,deep:true,onmatch:function(Z){return true},onformat:function(ab,Z,aa){R(aa,function(ad,ac){c.setAttrib(ab,ac,ad)})}},removeformat:[{selector:"b,strong,em,i,font,u,strike",remove:"all",split:true,expand:false,block_expand:true,deep:true},{selector:"span",attributes:["style","class"],remove:"empty",split:true,expand:false,deep:true},{selector:"*",attributes:["style","class"],split:false,expand:false,deep:true}]});R("p h1 h2 h3 h4 h5 h6 div address pre div code dt dd samp".split(/\s/),function(Z){l(Z,{block:Z,remove:"all"})});l(Y.settings.formats)}function U(){Y.addShortcut("ctrl+b","bold_desc","Bold");Y.addShortcut("ctrl+i","italic_desc","Italic");Y.addShortcut("ctrl+u","underline_desc","Underline");for(var Z=1;Z<=6;Z++){Y.addShortcut("ctrl+"+Z,"",["FormatBlock",false,"h"+Z])}Y.addShortcut("ctrl+7","",["FormatBlock",false,"p"]);Y.addShortcut("ctrl+8","",["FormatBlock",false,"div"]);Y.addShortcut("ctrl+9","",["FormatBlock",false,"address"])}function T(Z){return Z?O[Z]:O}function l(Z,aa){if(Z){if(typeof(Z)!=="string"){R(Z,function(ac,ab){l(ab,ac)})}else{aa=aa.length?aa:[aa];R(aa,function(ab){if(ab.deep===D){ab.deep=!ab.selector}if(ab.split===D){ab.split=!ab.selector||ab.inline}if(ab.remove===D&&ab.selector&&!ab.inline){ab.remove="none"}if(ab.selector&&ab.inline){ab.mixed=true;ab.block_expand=true}if(typeof(ab.classes)==="string"){ab.classes=ab.classes.split(/\s+/)}});O[Z]=aa}}}var i=function(aa){var Z;Y.dom.getParent(aa,function(ab){Z=Y.dom.getStyle(ab,"text-decoration");return Z&&Z!=="none"});return Z};var K=function(Z){var aa;if(Z.nodeType===1&&Z.parentNode&&Z.parentNode.nodeType===1){aa=i(Z.parentNode);if(Y.dom.getStyle(Z,"color")&&aa){Y.dom.setStyle(Z,"text-decoration",aa)}else{if(Y.dom.getStyle(Z,"textdecoration")===aa){Y.dom.setStyle(Z,"text-decoration",null)}}}};function W(ac,aj,ae){var af=T(ac),ak=af[0],ai,aa,ah,ag=r.isCollapsed();function Z(ao,an){an=an||ak;if(ao){if(an.onformat){an.onformat(ao,an,aj,ae)}R(an.styles,function(aq,ap){c.setStyle(ao,ap,q(aq,aj))});R(an.attributes,function(aq,ap){c.setAttrib(ao,ap,q(aq,aj))});R(an.classes,function(ap){ap=q(ap,aj);if(!c.hasClass(ao,ap)){c.addClass(ao,ap)}})}}function ad(){function ap(aw,au){var av=new t(au);for(ae=av.current();ae;ae=av.prev()){if(ae.childNodes.length>1||ae==aw||ae.tagName=="BR"){return ae}}}var ao=Y.selection.getRng();var at=ao.startContainer;var an=ao.endContainer;if(at!=an&&ao.endOffset===0){var ar=ap(at,an);var aq=ar.nodeType==3?ar.length:ar.childNodes.length;ao.setEnd(ar,aq)}return ao}function ab(aq,aw,au,at,ao){var an=[],ap=-1,av,ay=-1,ar=-1,ax;R(aq.childNodes,function(aA,az){if(aA.nodeName==="UL"||aA.nodeName==="OL"){ap=az;av=aA;return false}});R(aq.childNodes,function(aA,az){if(aA.nodeName==="SPAN"&&c.getAttrib(aA,"data-mce-type")=="bookmark"){if(aA.id==aw.id+"_start"){ay=az}else{if(aA.id==aw.id+"_end"){ar=az}}}});if(ap<=0||(ayap)){R(a.grep(aq.childNodes),ao);return 0}else{ax=c.clone(au,V);R(a.grep(aq.childNodes),function(aA,az){if((ayap&&az>ap)){an.push(aA);aA.parentNode.removeChild(aA)}});if(ayap){aq.insertBefore(ax,av.nextSibling)}}at.push(ax);R(an,function(az){ax.appendChild(az)});return ax}}function al(ao,aq,au){var an=[],at,ap,ar=true;at=ak.inline||ak.block;ap=c.create(at);Z(ap);M.walk(ao,function(av){var aw;function ax(ay){var aD,aB,az,aA,aC;aC=ar;aD=ay.nodeName.toLowerCase();aB=ay.parentNode.nodeName.toLowerCase();if(ay.nodeType===1&&x(ay)){aC=ar;ar=x(ay)==="true";aA=true}if(g(aD,"br")){aw=0;if(ak.block){c.remove(ay)}return}if(ak.wrapper&&y(ay,ac,aj)){aw=0;return}if(ar&&!aA&&ak.block&&!ak.wrapper&&I(aD)){ay=c.rename(ay,at);Z(ay);an.push(ay);aw=0;return}if(ak.selector){R(af,function(aE){if("collapsed" in aE&&aE.collapsed!==ag){return}if(c.is(ay,aE.selector)&&!b(ay)){Z(ay,aE);az=true}});if(!ak.inline||az){aw=0;return}}if(ar&&!aA&&d(at,aD)&&d(aB,at)&&!(!au&&ay.nodeType===3&&ay.nodeValue.length===1&&ay.nodeValue.charCodeAt(0)===65279)&&!b(ay)){if(!aw){aw=c.clone(ap,V);ay.parentNode.insertBefore(aw,ay);an.push(aw)}aw.appendChild(ay)}else{if(aD=="li"&&aq){aw=ab(ay,aq,ap,an,ax)}else{aw=0;R(a.grep(ay.childNodes),ax);if(aA){ar=aC}aw=0}}}R(av,ax)});if(ak.wrap_links===false){R(an,function(av){function aw(aA){var az,ay,ax;if(aA.nodeName==="A"){ay=c.clone(ap,V);an.push(ay);ax=a.grep(aA.childNodes);for(az=0;az1||!H(ax))&&av===0){c.remove(ax,1);return}if(ak.inline||ak.wrapper){if(!ak.exact&&av===1){ax=aw(ax)}R(af,function(az){R(c.select(az.inline,ax),function(aB){var aA;if(az.wrap_links===false){aA=aB.parentNode;do{if(aA.nodeName==="A"){return}}while(aA=aA.parentNode)}X(az,aj,aB,az.exact?aB:null)})});if(y(ax.parentNode,ac,aj)){c.remove(ax,1);ax=0;return C}if(ak.merge_with_parents){c.getParent(ax.parentNode,function(az){if(y(az,ac,aj)){c.remove(ax,1);ax=0;return C}})}if(ax&&ak.merge_siblings!==false){ax=u(E(ax),ax);ax=u(ax,E(ax,C))}}})}if(ak){if(ae){if(ae.nodeType){aa=c.createRng();aa.setStartBefore(ae);aa.setEndAfter(ae);al(p(aa,af),null,true)}else{al(ae,null,true)}}else{if(!ag||!ak.inline||c.select("td.mceSelected,th.mceSelected").length){var am=Y.selection.getNode();if(!m&&af[0].defaultBlock&&!c.getParent(am,c.isBlock)){W(af[0].defaultBlock)}Y.selection.setRng(ad());ai=r.getBookmark();al(p(r.getRng(C),af),ai);if(ak.styles&&(ak.styles.color||ak.styles.textDecoration)){a.walk(am,K,"childNodes");K(am)}r.moveToBookmark(ai);P(r.getRng(C));Y.nodeChanged()}else{S("apply",ac,aj)}}}}function B(ab,ak,ad){var ae=T(ab),am=ae[0],ai,ah,aa,aj=true;function ac(at){var ar,aq,ap,ao,av,au;if(at.nodeType===1&&x(at)){av=aj;aj=x(at)==="true";au=true}ar=a.grep(at.childNodes);if(aj&&!au){for(aq=0,ap=ae.length;aq=0;aa--){Z=af[aa].selector;if(!Z){return C}for(ae=ab.length-1;ae>=0;ae--){if(c.is(ab[ae],Z)){return C}}}}return V}a.extend(this,{get:T,register:l,apply:W,remove:B,toggle:F,match:k,matchAll:v,matchNode:y,canApply:z});j();U();function h(Z,aa){if(g(Z,aa.inline)){return C}if(g(Z,aa.block)){return C}if(aa.selector){return c.is(Z,aa.selector)}}function g(aa,Z){aa=aa||"";Z=Z||"";aa=""+(aa.nodeName||aa);Z=""+(Z.nodeName||Z);return aa.toLowerCase()==Z.toLowerCase()}function N(aa,Z){var ab=c.getStyle(aa,Z);if(Z=="color"||Z=="backgroundColor"){ab=c.toHex(ab)}if(Z=="fontWeight"&&ab==700){ab="bold"}return""+ab}function q(Z,aa){if(typeof(Z)!="string"){Z=Z(aa)}else{if(aa){Z=Z.replace(/%(\w+)/g,function(ac,ab){return aa[ab]||ac})}}return Z}function f(Z){return Z&&Z.nodeType===3&&/^([\t \r\n]+|)$/.test(Z.nodeValue)}function Q(ab,aa,Z){var ac=c.create(aa,Z);ab.parentNode.insertBefore(ac,ab);ac.appendChild(ab);return ac}function p(Z,ak,ac){var an,al,af,aj,ab=Z.startContainer,ag=Z.startOffset,ap=Z.endContainer,ai=Z.endOffset;function am(ax){var ar,av,aw,au,at,aq;ar=av=ax?ab:ap;at=ax?"previousSibling":"nextSibling";aq=c.getRoot();if(ar.nodeType==3&&!f(ar)){if(ax?ag>0:aial?al:ag];if(ab.nodeType==3){ag=0}}if(ap.nodeType==1&&ap.hasChildNodes()){al=ap.childNodes.length-1;ap=ap.childNodes[ai>al?al:ai-1];if(ap.nodeType==3){ai=ap.nodeValue.length}}function ao(ar){var aq=ar;while(aq){if(aq.nodeType===1&&x(aq)){return x(aq)==="false"?aq:ar}aq=aq.parentNode}return ar}function ah(ar,aw,ay){var av,at,ax,aq;function au(aA,aC){var aD,az,aB=aA.nodeValue;if(typeof(aC)=="undefined"){aC=ay?aB.length:0}if(ay){aD=aB.lastIndexOf(" ",aC);az=aB.lastIndexOf("\u00a0",aC);aD=aD>az?aD:az;if(aD!==-1&&!ac){aD++}}else{aD=aB.indexOf(" ",aC);az=aB.indexOf("\u00a0",aC);aD=aD!==-1&&(az===-1||aD0&&af.node.nodeType===3&&af.node.nodeValue.charAt(af.offset-1)===" "){if(af.offset>1){ap=af.node;ap.splitText(af.offset-1)}}}}if(ak[0].inline||ak[0].block_expand){if(!ak[0].inline||(ab.nodeType!=3||ag===0)){ab=am(true)}if(!ak[0].inline||(ap.nodeType!=3||ai===ap.nodeValue.length)){ap=am()}}if(ak[0].selector&&ak[0].expand!==V&&!ak[0].inline){ab=ad(ab,"previousSibling");ap=ad(ap,"nextSibling")}if(ak[0].block||ak[0].selector){ab=aa(ab,"previousSibling");ap=aa(ap,"nextSibling");if(ak[0].block){if(!H(ab)){ab=am(true)}if(!H(ap)){ap=am()}}}if(ab.nodeType==1){ag=s(ab);ab=ab.parentNode}if(ap.nodeType==1){ai=s(ap)+1;ap=ap.parentNode}return{startContainer:ab,startOffset:ag,endContainer:ap,endOffset:ai}}function X(af,ae,ac,Z){var ab,aa,ad;if(!h(ac,af)){return V}if(af.remove!="all"){R(af.styles,function(ah,ag){ah=q(ah,ae);if(typeof(ag)==="number"){ag=ah;Z=0}if(!Z||g(N(Z,ag),ah)){c.setStyle(ac,ag,"")}ad=1});if(ad&&c.getAttrib(ac,"style")==""){ac.removeAttribute("style");ac.removeAttribute("data-mce-style")}R(af.attributes,function(ai,ag){var ah;ai=q(ai,ae);if(typeof(ag)==="number"){ag=ai;Z=0}if(!Z||g(c.getAttrib(Z,ag),ai)){if(ag=="class"){ai=c.getAttrib(ac,ag);if(ai){ah="";R(ai.split(/\s+/),function(aj){if(/mce\w+/.test(aj)){ah+=(ah?" ":"")+aj}});if(ah){c.setAttrib(ac,ag,ah);return}}}if(ag=="class"){ac.removeAttribute("className")}if(e.test(ag)){ac.removeAttribute("data-mce-"+ag)}ac.removeAttribute(ag)}});R(af.classes,function(ag){ag=q(ag,ae);if(!Z||c.hasClass(Z,ag)){c.removeClass(ac,ag)}});aa=c.getAttribs(ac);for(ab=0;abab?ab:ad]}if(Z.nodeType===3&&ae&&ad>=Z.nodeValue.length){Z=new t(Z,Y.getBody()).next()||Z}if(Z.nodeType===3&&!ae&&ad===0){Z=new t(Z,Y.getBody()).prev()||Z}return Z}function S(ai,Z,ag){var aj="_mce_caret",aa=Y.settings.caret_debug;function ab(am){var al=c.create("span",{id:aj,"data-mce-bogus":true,style:aa?"color:red":""});if(am){al.appendChild(Y.getDoc().createTextNode(G))}return al}function ah(am,al){while(am){if((am.nodeType===3&&am.nodeValue!==G)||am.childNodes.length>1){return false}if(al&&am.nodeType===1){al.push(am)}am=am.firstChild}return true}function ae(al){while(al){if(al.id===aj){return al}al=al.parentNode}}function ad(al){var am;if(al){am=new t(al,al);for(al=am.current();al;al=am.next()){if(al.nodeType===3){return al}}}}function ac(an,am){var ao,al;if(!an){an=ae(r.getStart());if(!an){while(an=c.get(aj)){ac(an,false)}}}else{al=r.getRng(true);if(ah(an)){if(am!==false){al.setStartBefore(an);al.setEndBefore(an)}c.remove(an)}else{ao=ad(an);if(ao.nodeValue.charAt(0)===G){ao=ao.deleteData(0,1)}c.remove(an,1)}r.setRng(al)}}function af(){var an,al,ar,aq,ao,am,ap;an=r.getRng(true);aq=an.startOffset;am=an.startContainer;ap=am.nodeValue;al=ae(r.getStart());if(al){ar=ad(al)}if(ap&&aq>0&&aq=0;ap--){an.appendChild(c.clone(au[ap],false));an=an.firstChild}an.appendChild(c.doc.createTextNode(G));an=an.firstChild;c.insertAfter(at,av);r.setCursorLocation(an,1)}}if(!self._hasCaretEvents){Y.onBeforeGetContent.addToTop(function(){var al=[],am;if(ah(ae(r.getStart()),al)){am=al.length;while(am--){c.setAttrib(al[am],"data-mce-bogus","1")}}});a.each("onMouseUp onKeyUp".split(" "),function(al){Y[al].addToTop(function(){ac()})});Y.onKeyDown.addToTop(function(al,an){var am=an.keyCode;if(am==8||am==37||am==39){ac(ae(r.getStart()))}});r.onSetContent.add(function(){c.getParent(r.getStart(),function(al){if(al.id!==aj&&c.getAttrib(al,"data-mce-bogus")&&!c.isEmpty(al)){c.setAttrib(al,"data-mce-bogus",null)}})});self._hasCaretEvents=true}if(ai=="apply"){af()}else{ak()}}function P(aa){var Z=aa.startContainer,ag=aa.startOffset,ac,af,ae,ab,ad;if(Z.nodeType==3&&ag>=Z.nodeValue.length){ag=s(Z);Z=Z.parentNode;ac=true}if(Z.nodeType==1){ab=Z.childNodes;Z=ab[Math.min(ag,ab.length-1)];af=new t(Z,c.getParent(Z,c.isBlock));if(ag>ab.length-1||ac){af.next()}for(ae=af.current();ae;ae=af.next()){if(ae.nodeType==3&&!f(ae)){ad=c.create("a",null,G);ae.parentNode.insertBefore(ad,ae);aa.setStart(ae,0);r.setRng(aa);c.remove(ad);return}}}}}})(tinymce);tinymce.onAddEditor.add(function(e,a){var d,h,g,c=a.settings;function b(j,i){e.each(i,function(l,k){if(l){g.setStyle(j,k,l)}});g.rename(j,"span")}function f(i,j){g=i.dom;if(c.convert_fonts_to_spans){e.each(g.select("font,u,strike",j.node),function(k){d[k.nodeName.toLowerCase()](a.dom,k)})}}if(c.inline_styles){h=e.explode(c.font_size_legacy_values);d={font:function(j,i){b(i,{backgroundColor:i.style.backgroundColor,color:i.color,fontFamily:i.face,fontSize:h[parseInt(i.size,10)-1]})},u:function(j,i){b(i,{textDecoration:"underline"})},strike:function(j,i){b(i,{textDecoration:"line-through"})}};a.onPreProcess.add(f);a.onSetContent.add(f);a.onInit.add(function(){a.selection.onSetContent.add(f)})}});(function(b){var a=b.dom.TreeWalker;b.EnterKey=function(e){var h=e.dom,d=e.selection,c=e.settings,g=e.undoManager;function f(y){var u=d.getRng(true),C,i,x,t,o,H,n,j,l,s,E,v,z;function B(I){return I&&h.isBlock(I)&&!/^(TD|TH|CAPTION)$/.test(I.nodeName)&&!/^(fixed|absolute)/i.test(I.style.position)&&h.getContentEditable(I)!=="true"}function m(J){var O,M,I,P,N,L=J,K;I=h.createRng();if(J.hasChildNodes()){O=new a(J,J);while(M=O.current()){if(M.nodeType==3){I.setStart(M,0);I.setEnd(M,0);break}if(/^(BR|IMG)$/.test(M.nodeName)){I.setStartBefore(M);I.setEndBefore(M);break}L=M;M=O.next()}if(!M){I.setStart(L,0);I.setEnd(L,0)}}else{if(J.nodeName=="BR"){if(J.nextSibling&&h.isBlock(J.nextSibling)){if(!H||H<9){K=h.create("br");J.parentNode.insertBefore(K,J)}I.setStartBefore(J);I.setEndBefore(J)}else{I.setStartAfter(J);I.setEndAfter(J)}}else{I.setStart(J,0);I.setEnd(J,0)}}d.setRng(I);h.remove(K);N=h.getViewPort(e.getWin());P=h.getPos(J).y;if(PN.y+N.h){e.getWin().scrollTo(0,P"}return M}function p(L){var K,J,I;if(x.nodeType==3&&(L?t>0:t=x.nodeValue.length){if(!b.isIE&&!A()){J=h.create("br");u.insertNode(J);u.setStartAfter(J);u.setEndAfter(J);I=true}}J=h.create("br");u.insertNode(J);if(b.isIE&&s=="PRE"&&(!H||H<8)){J.parentNode.insertBefore(h.doc.createTextNode("\r"),J)}if(!I){u.setStartAfter(J);u.setEndAfter(J)}else{u.setStartBefore(J);u.setEndBefore(J)}d.setRng(u);g.add()}function r(I){do{if(I.nodeType===3){I.nodeValue=I.nodeValue.replace(/^[\r\n]+/,"")}I=I.firstChild}while(I)}function F(K){var I=h.getRoot(),J,L;J=K;while(J!==I&&h.getContentEditable(J)!=="false"){if(h.getContentEditable(J)==="true"){L=J}J=J.parentNode}return J!==I?L:I}if(!u.collapsed){e.execCommand("Delete");return}if(y.isDefaultPrevented()){return}x=u.startContainer;t=u.startOffset;v=c.forced_root_block;v=v?v.toUpperCase():"";H=h.doc.documentMode;if(x.nodeType==1&&x.hasChildNodes()){z=t>x.childNodes.length-1;x=x.childNodes[Math.min(t,x.childNodes.length-1)]||x;t=0}i=F(x);if(!i){return}g.beforeChange();if(!h.isBlock(i)&&i!=h.getRoot()){if(!v||y.shiftKey){G()}return}if((v&&!y.shiftKey)||(!v&&y.shiftKey)){x=k(x,t)}o=h.getParent(x,h.isBlock);l=o?h.getParent(o.parentNode,h.isBlock):null;s=o?o.nodeName.toUpperCase():"";E=l?l.nodeName.toUpperCase():"";if(s=="LI"&&h.isEmpty(o)){if(/^(UL|OL|LI)$/.test(l.parentNode.nodeName)){return false}D();return}if(s=="PRE"&&c.br_in_pre!==false){if(!y.shiftKey){G();return}}else{if((!v&&!y.shiftKey&&s!="LI")||(v&&y.shiftKey)){G();return}}v=v||"P";if(p()){if(/^(H[1-6]|PRE)$/.test(s)&&E!="HGROUP"){n=q(v)}else{n=q()}if(c.end_container_on_empty_block&&B(l)&&h.isEmpty(o)){n=h.split(l,o)}else{h.insertAfter(n,o)}}else{if(p(true)){n=o.parentNode.insertBefore(q(),o)}else{C=u.cloneRange();C.setEndAfter(o);j=C.extractContents();r(j);n=j.firstChild;h.insertAfter(j,o)}}h.setAttrib(n,"id","");m(n);g.add()}e.onKeyDown.add(function(j,i){if(i.keyCode==13){if(f(i)!==false){i.preventDefault()}}})}})(tinymce); \ No newline at end of file diff --git a/sources/library/tinymce/jscripts/tiny_mce/tiny_mce_popup.js b/sources/library/tinymce/jscripts/tiny_mce/tiny_mce_popup.js new file mode 100644 index 00000000..4d9ffc03 --- /dev/null +++ b/sources/library/tinymce/jscripts/tiny_mce/tiny_mce_popup.js @@ -0,0 +1,5 @@ + +// Uncomment and change this document.domain value if you are loading the script cross subdomains +// document.domain = 'moxiecode.com'; + +var tinymce=null,tinyMCEPopup,tinyMCE;tinyMCEPopup={init:function(){var b=this,a,c;a=b.getWin();tinymce=a.tinymce;tinyMCE=a.tinyMCE;b.editor=tinymce.EditorManager.activeEditor;b.params=b.editor.windowManager.params;b.features=b.editor.windowManager.features;b.dom=b.editor.windowManager.createInstance("tinymce.dom.DOMUtils",document,{ownEvents:true,proxy:tinyMCEPopup._eventProxy});b.dom.bind(window,"ready",b._onDOMLoaded,b);if(b.features.popup_css!==false){b.dom.loadCSS(b.features.popup_css||b.editor.settings.popup_css)}b.listeners=[];b.onInit={add:function(e,d){b.listeners.push({func:e,scope:d})}};b.isWindow=!b.getWindowArg("mce_inline");b.id=b.getWindowArg("mce_window_id");b.editor.windowManager.onOpen.dispatch(b.editor.windowManager,window)},getWin:function(){return(!window.frameElement&&window.dialogArguments)||opener||parent||top},getWindowArg:function(c,b){var a=this.params[c];return tinymce.is(a)?a:b},getParam:function(b,a){return this.editor.getParam(b,a)},getLang:function(b,a){return this.editor.getLang(b,a)},execCommand:function(d,c,e,b){b=b||{};b.skip_focus=1;this.restoreSelection();return this.editor.execCommand(d,c,e,b)},resizeToInnerSize:function(){var a=this;setTimeout(function(){var b=a.dom.getViewPort(window);a.editor.windowManager.resizeBy(a.getWindowArg("mce_width")-b.w,a.getWindowArg("mce_height")-b.h,a.id||window)},10)},executeOnLoad:function(s){this.onInit.add(function(){eval(s)})},storeSelection:function(){this.editor.windowManager.bookmark=tinyMCEPopup.editor.selection.getBookmark(1)},restoreSelection:function(){var a=tinyMCEPopup;if(!a.isWindow&&tinymce.isIE){a.editor.selection.moveToBookmark(a.editor.windowManager.bookmark)}},requireLangPack:function(){var b=this,a=b.getWindowArg("plugin_url")||b.getWindowArg("theme_url");if(a&&b.editor.settings.language&&b.features.translate_i18n!==false&&b.editor.settings.language_load!==false){a+="/langs/"+b.editor.settings.language+"_dlg.js";if(!tinymce.ScriptLoader.isDone(a)){document.write('\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'channel', + '$uid' => (($a->profile['profile_uid']) ? $a->profile['profile_uid'] : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '0', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$nouveau' => '0', + '$wall' => '1', + '$fh' => '0', + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$search' => '', + '$order' => '', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), + '$file' => '', + '$cats' => (($category) ? $category : ''), + '$tags' => (($hashtags) ? $hashtags : ''), + '$mid' => $mid, + '$verb' => '', + '$dend' => $datequery, + '$dbegin' => $datequery2 + )); + + + } + + $update_unseen = ''; + + if($page_mode === 'list') { + + /** + * in "list mode", only mark the parent item and any like activities as "seen". + * We won't distinguish between comment likes and post likes. The important thing + * is that the number of unseen comments will be accurate. The SQL to separate the + * comment likes could also get somewhat hairy. + */ + + if($parents_str) { + $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; + $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; + } + } + else { + if($parents_str) { + $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; + } + } + + if($is_owner && $update_unseen) { + $r = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 and item_wall = 1 AND uid = %d $update_unseen", + intval(local_channel()) + ); + } + + + if($_COOKIE['jsAvailable'] == 1) { + $o .= conversation($a,$items,'channel',$update,$page_mode); + } else { + $o .= conversation($a,$items,'channel',$update,'traditional'); + } + + if((! $update) || ($_COOKIE['jsAvailable'] != 1)) { + $o .= alt_pager($a,count($items)); + if ($mid && $items[0]['title']) + $a->page['title'] = $items[0]['title'] . " - " . $a->page['title']; + } + + if($mid) + $o .= '
    '; + + return $o; +} diff --git a/sources/mod/chanview.php b/sources/mod/chanview.php new file mode 100644 index 00000000..0cbcb2e5 --- /dev/null +++ b/sources/mod/chanview.php @@ -0,0 +1,104 @@ +get_observer(); + $xchan = null; + + $r = null; + + if($_REQUEST['hash']) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($_REQUEST['hash']) + ); + } + if($_REQUEST['address']) { + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + } + elseif(local_channel() && intval($_REQUEST['cid'])) { + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_channel()), + intval($_REQUEST['cid']) + ); + } + elseif($_REQUEST['url']) { + + // if somebody re-installed they will have more than one xchan, use the most recent name date as this is + // the most useful consistently ascending table item we have. + + $r = q("select * from xchan where xchan_url = '%s' order by xchan_name_date desc limit 1", + dbesc($_REQUEST['url']) + ); + } + if($r) { + $a->poi = $r[0]; + } + + + // Here, let's see if we have an xchan. If we don't, how we proceed is determined by what + // info we do have. If it's a URL, we can offer to visit it directly. If it's a webbie or + // address, we can and should try to import it. If it's just a hash, we can't continue, but we + // probably wouldn't have a hash if we don't already have an xchan for this channel. + + if(! $a->poi) { + logger('mod_chanview: fallback'); + // This is hackish - construct a zot address from the url + if($_REQUEST['url']) { + if(preg_match('/https?\:\/\/(.*?)(\/channel\/|\/profile\/)(.*?)$/ism',$_REQUEST['url'],$matches)) { + $_REQUEST['address'] = $matches[3] . '@' . $matches[1]; + } + logger('mod_chanview: constructed address ' . print_r($matches,true)); + } + + if($_REQUEST['address']) { + $ret = zot_finger($_REQUEST['address'],null); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) + import_xchan($j); + $r = q("select * from xchan where xchan_addr = '%s' limit 1", + dbesc($_REQUEST['address']) + ); + if($r) + $a->poi = $r[0]; + } + + } + } + + if(! $a->poi) { +// We don't know who this is, and we can't figure it out from the URL +// On the plus side, there's a good chance we know somebody else at that +// hub so sending them there with a Zid will probably work anyway. + $url = ($_REQUEST['url']); + if($observer) + $url = zid($url); + } + + if ($a->poi) { + $url = $a->poi['xchan_url']; + if($observer) + $url = zid($url); + } + // let somebody over-ride the iframed viewport presentation + // or let's just declare this a failed experiment. + +// if((! local_channel()) || (get_pconfig(local_channel(),'system','chanview_full'))) + + goaway($url); + +// $o = replace_macros(get_markup_template('chanview.tpl'),array( +// '$url' => $url, +// '$full' => t('toggle full screen mode') +// )); + +// return $o; + +} diff --git a/sources/mod/chat.php b/sources/mod/chat.php new file mode 100644 index 00000000..c54d2931 --- /dev/null +++ b/sources/mod/chat.php @@ -0,0 +1,235 @@ + 1) + $which = argv(1); + if(! $which) { + if(local_channel()) { + $channel = $a->get_channel(); + if($channel && $channel['channel_address']) + $which = $channel['channel_address']; + } + } + if(! $which) { + notice( t('You must be logged in to see this page.') . EOL ); + return; + } + + $profile = 0; + $channel = $a->get_channel(); + + if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + } + + $a->page['htmlhead'] .= '' . "\r\n" ; + + // Run profile_load() here to make sure the theme is set before + // we start loading content + + profile_load($a,$which,$profile); + +} + +function chat_post(&$a) { + + if($_POST['room_name']) + $room = strip_tags(trim($_POST['room_name'])); + + if((! $room) || (! local_channel())) + return; + + $channel = $a->get_channel(); + + + if($_POST['action'] === 'drop') { + logger('delete chatroom'); + chatroom_destroy($channel,array('cr_name' => $room)); + goaway(z_root() . '/chat/' . $channel['channel_address']); + } + + + $arr = array('name' => $room); + $arr['allow_gid'] = perms2str($_REQUEST['group_allow']); + $arr['allow_cid'] = perms2str($_REQUEST['contact_allow']); + $arr['deny_gid'] = perms2str($_REQUEST['group_deny']); + $arr['deny_cid'] = perms2str($_REQUEST['contact_deny']); + + chatroom_create($channel,$arr); + + $x = q("select cr_id from chatroom where cr_name = '%s' and cr_uid = %d limit 1", + dbesc($room), + intval(local_channel()) + ); + + if($x) + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/' . $x[0]['cr_id']); + + // that failed. Try again perhaps? + + goaway(z_root() . '/chat/' . $channel['channel_address'] . '/new'); + + +} + + +function chat_content(&$a) { + + if(local_channel()) + $channel = $a->get_channel(); + + $ob = $a->get_observer(); + $observer = get_observer_hash(); + if(! $observer) { + notice( t('Permission denied.') . EOL); + return; + } + + if(! perm_is_allowed($a->profile['profile_uid'],$observer,'chat')) { + notice( t('Permission denied.') . EOL); + return; + } + + if((argc() > 3) && intval(argv(2)) && (argv(3) === 'leave')) { + chatroom_leave($observer,argv(2),$_SERVER['REMOTE_ADDR']); + goaway(z_root() . '/channel/' . argv(1)); + } + + + if((argc() > 3) && intval(argv(2)) && (argv(3) === 'status')) { + $ret = array('success' => false); + $room_id = intval(argv(2)); + if(! $room_id || ! $observer) + return; + + $r = q("select * from chatroom where cr_id = %d limit 1", + intval($room_id) + ); + if(! $r) { + json_return_and_die($ret); + } + require_once('include/security.php'); + $sql_extra = permissions_sql($r[0]['cr_uid']); + + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($r[0]['cr_uid']) + ); + if(! $x) { + json_return_and_die($ret); + } + $y = q("select count(*) as total from chatpresence where cp_room = %d", + intval($room_id) + ); + if($y) { + $ret['success'] = true; + $ret['chatroom'] = $r[0]['cr_name']; + $ret['inroom'] = $y[0]['total']; + } + + // figure out how to present a timestamp of the last activity, since we don't know the observer's timezone. + + $z = q("select created from chat where chat_room = %d order by created desc limit 1", + intval($room_id) + ); + if($z) { + $ret['last'] = $z[0]['created']; + } + json_return_and_die($ret); + } + + + if(argc() > 2 && intval(argv(2))) { + + $room_id = intval(argv(2)); + $bookmark_link = get_bookmark_link($ob); + + $x = chatroom_enter($observer,$room_id,'online',$_SERVER['REMOTE_ADDR']); + if(! $x) + return; + $x = q("select * from chatroom where cr_id = %d and cr_uid = %d $sql_extra limit 1", + intval($room_id), + intval($a->profile['profile_uid']) + ); + if($x) { + $private = ((($x[0]['allow_cid']) || ($x[0]['allow_gid']) || ($x[0]['deny_cid']) || ($x[0]['deny_gid'])) ? true : false); + $room_name = $x[0]['cr_name']; + if($bookmark_link) + $bookmark_link .= '&url=' . z_root() . '/chat/' . argv(1) . '/' . argv(2) . '&title=' . urlencode($x[0]['cr_name']) . (($private) ? '&private=1' : '') . '&ischat=1'; + } + else { + notice( t('Room not found') . EOL); + return; + } + + $o = replace_macros(get_markup_template('chat.tpl'),array( + '$is_owner' => ((local_channel() && local_channel() == $x[0]['cr_uid']) ? true : false), + '$room_name' => $room_name, + '$room_id' => $room_id, + '$baseurl' => z_root(), + '$nickname' => argv(1), + '$submit' => t('Submit'), + '$leave' => t('Leave Room'), + '$drop' => t('Delete This Room'), + '$away' => t('I am away right now'), + '$online' => t('I am online'), + '$bookmark_link' => $bookmark_link, + '$bookmark' => t('Bookmark this room') + + )); + return $o; + } + + + + + + if(local_channel() && argc() > 2 && argv(2) === 'new') { + + + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + require_once('include/acl_selectors.php'); + + $o = replace_macros(get_markup_template('chatroom_new.tpl'),array( + '$header' => t('New Chatroom'), + '$name' => array('room_name',t('Chatroom Name'),'', ''), + '$permissions' => t('Permissions'), + '$acl' => populate_acl($channel_acl,false), + '$submit' => t('Submit') + )); + return $o; + } + + + + require_once('include/conversation.php'); + + $o = profile_tabs($a,((local_channel() && local_channel() == $a->profile['profile_uid']) ? true : false),$a->profile['channel_address']); + + require_once('include/widgets.php'); + + $o .= replace_macros(get_markup_template('chatrooms.tpl'), array( + '$header' => sprintf( t('%1$s\'s Chatrooms'), $a->profile['name']), + '$baseurl' => z_root(), + '$nickname' => $channel['channel_address'], + '$rooms' => widget_chatroom_list(array()), + '$newroom' => t('New Chatroom'), + '$is_owner' => ((local_channel() && local_channel() == $a->profile['profile_uid']) ? 1 : 0) + )); + + return $o; + +} diff --git a/sources/mod/chatsvc.php b/sources/mod/chatsvc.php new file mode 100644 index 00000000..44225e6d --- /dev/null +++ b/sources/mod/chatsvc.php @@ -0,0 +1,159 @@ + false); + + $a->data['chat']['room_id'] = intval($_REQUEST['room_id']); + $x = q("select cr_uid from chatroom where cr_id = %d and cr_id != 0 limit 1", + intval($a->data['chat']['room_id']) + ); + if(! $x) + json_return_and_die($ret); + + $a->data['chat']['uid'] = $x[0]['cr_uid']; + + if(! perm_is_allowed($a->data['chat']['uid'],get_observer_hash(),'chat')) { + json_return_and_die($ret); + } + +} + +function chatsvc_post(&$a) { + + $ret = array('success' => false); + + $room_id = $a->data['chat']['room_id']; + $text = escape_tags($_REQUEST['chat_text']); + if(! $text) + return; + + $sql_extra = permissions_sql($a->data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval($a->data['chat']['uid']), + intval($a->data['chat']['room_id']) + ); + if(! $r) + json_return_and_die($ret); + + $arr = array( + 'chat_room' => $a->data['chat']['room_id'], + 'chat_xchan' => get_observer_hash(), + 'chat_text' => $text + ); + + call_hooks('chat_post',$arr); + + $x = q("insert into chat ( chat_room, chat_xchan, created, chat_text ) + values( %d, '%s', '%s', '%s' )", + intval($a->data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc($arr['chat_text']) + ); + + $ret['success'] = true; + json_return_and_die($ret); +} + +function chatsvc_content(&$a) { + + $status = strip_tags($_REQUEST['status']); + $room_id = intval($a->data['chat']['room_id']); + $stopped = ((x($_REQUEST,'stopped') && intval($_REQUEST['stopped'])) ? true : false); + + if($status && $room_id) { + + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval($a->data['chat']['uid']) + ); + + $r = q("update chatpresence set cp_status = '%s', cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", + dbesc($status), + dbesc(datetime_convert()), + intval($room_id), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + goaway(z_root() . '/chat/' . $x[0]['channel_address'] . '/' . $room_id); + } + + if(! $stopped) { + + $lastseen = intval($_REQUEST['last']); + + $ret = array('success' => false); + + $sql_extra = permissions_sql($a->data['chat']['uid']); + + $r = q("select * from chatroom where cr_uid = %d and cr_id = %d $sql_extra", + intval($a->data['chat']['uid']), + intval($a->data['chat']['room_id']) + ); + if(! $r) + json_return_and_die($ret); + + $inroom = array(); + + $r = q("select * from chatpresence left join xchan on xchan_hash = cp_xchan where cp_room = %d order by xchan_name", + intval($a->data['chat']['room_id']) + ); + if($r) { + foreach($r as $rr) { + switch($rr['cp_status']) { + case 'away': + $status = t('Away'); + break; + case 'online': + default: + $status = t('Online'); + break; + } + + $inroom[] = array('img' => zid($rr['xchan_photo_m']), 'img_type' => $rr['xchan_photo_mimetype'],'name' => $rr['xchan_name'], status => $status); + } + } + + $chats = array(); + + $r = q("select * from chat left join xchan on chat_xchan = xchan_hash where chat_room = %d and chat_id > %d order by created", + intval($a->data['chat']['room_id']), + intval($lastseen) + ); + if($r) { + foreach($r as $rr) { + $chats[] = array( + 'id' => $rr['chat_id'], + 'img' => zid($rr['xchan_photo_m']), + 'img_type' => $rr['xchan_photo_mimetype'], + 'name' => $rr['xchan_name'], + 'isotime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'c'), + 'localtime' => datetime_convert('UTC', date_default_timezone_get(), $rr['created'], 'r'), + 'text' => smilies(bbcode($rr['chat_text'])) + ); + } + } + } + + $r = q("update chatpresence set cp_last = '%s' where cp_room = %d and cp_xchan = '%s' and cp_client = '%s'", + dbesc(datetime_convert()), + intval($a->data['chat']['room_id']), + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + + $ret['success'] = true; + if(! $stopped) { + $ret['inroom'] = $inroom; + $ret['chats'] = $chats; + } + json_return_and_die($ret); + +} + diff --git a/sources/mod/cloud.php b/sources/mod/cloud.php new file mode 100644 index 00000000..7f6dc096 --- /dev/null +++ b/sources/mod/cloud.php @@ -0,0 +1,120 @@ + 1) + $which = argv(1); + + $profile = 0; + + $a->page['htmlhead'] .= '' . "\r\n"; + + if ($which) + profile_load($a, $which, $profile); + + $auth = new RedDAV\RedBasicAuth(); + + $ob_hash = get_observer_hash(); + + if ($ob_hash) { + if (local_channel()) { + $channel = $a->get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if($channel['channel_timezone']) + $auth->setTimezone($channel['channel_timezone']); + } + $auth->observer = $ob_hash; + } + + if ($_GET['davguest']) + $_SESSION['davguest'] = true; + + $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['QUERY_STRING']); + + $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['REQUEST_URI']); + + $rootDirectory = new RedDAV\RedDirectory('/', $auth); + + // A SabreDAV server-object + $server = new DAV\Server($rootDirectory); + // prevent overwriting changes each other with a lock backend + $lockBackend = new DAV\Locks\Backend\File('store/[data]/locks'); + $lockPlugin = new DAV\Locks\Plugin($lockBackend); + + $server->addPlugin($lockPlugin); + + // The next section of code allows us to bypass prompting for http-auth if a + // FILE is being accessed anonymously and permissions allow this. This way + // one can create hotlinks to public media files in their cloud and anonymous + // viewers won't get asked to login. + // If a DIRECTORY is accessed or there are permission issues accessing the + // file and we aren't previously authenticated via zot, prompt for HTTP-auth. + // This will be the default case for mounting a DAV directory. + // In order to avoid prompting for passwords for viewing a DIRECTORY, add + // the URL query parameter 'davguest=1'. + + $isapublic_file = false; + $davguest = ((x($_SESSION, 'davguest')) ? true : false); + + if ((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) { + try { + $x = RedFileData('/' . $a->cmd, $auth); + if($x instanceof RedDAV\RedFile) + $isapublic_file = true; + } + catch (Exception $e) { + $isapublic_file = false; + } + } + + if ((! $auth->observer) && (! $isapublic_file) && (! $davguest)) { + logger('mod_cloud: auth exception'); + http_status_exit(401, 'Permission denied.'); + } + + require_once('include/RedDAV/RedBrowser.php'); + // provide a directory view for the cloud in Hubzilla + $browser = new RedDAV\RedBrowser($auth); + $auth->setBrowserPlugin($browser); + + $server->addPlugin($browser); + + // Experimental QuotaPlugin +// require_once('include/RedDAV/QuotaPlugin.php'); +// $server->addPlugin(new RedDAV\QuotaPlugin($auth)); + + // All we need to do now, is to fire up the server + $server->exec(); + + killme(); +} diff --git a/sources/mod/common.php b/sources/mod/common.php new file mode 100644 index 00000000..e19a9d3a --- /dev/null +++ b/sources/mod/common.php @@ -0,0 +1,67 @@ + 1 && intval(argv(1))) + $channel_id = intval(argv(1)); + else { + notice( t('No channel.') . EOL ); + $a->error = 404; + return; + } + + $x = q("select channel_address from channel where channel_id = %d limit 1", + intval($channel_id) + ); + + if($x) + profile_load($a,$x[0]['channel_address'],0); + +} + +function common_content(&$a) { + + $o = ''; + + if(! $a->profile['profile_uid']) + return; + + $observer_hash = get_observer_hash(); + + + if(! perm_is_allowed($a->profile['profile_uid'],$observer_hash,'view_contacts')) { + notice( t('Permission denied.') . EOL); + return; + } + + $o .= '

    ' . t('Common connections') . '

    '; + + $t = count_common_friends($a->profile['profile_uid'],$observer_hash); + + if(! $t) { + notice( t('No connections in common.') . EOL); + return $o; + } + + $r = common_friends($a->profile['profile_uid'],$observer_hash); + + if($r) { + + $tpl = get_markup_template('common_friends.tpl'); + + foreach($r as $rr) { + $o .= replace_macros($tpl,array( + '$url' => $rr['xchan_url'], + '$name' => $rr['xchan_name'], + '$photo' => $rr['xchan_photo_m'], + '$tags' => '' + )); + } + + $o .= cleardiv(); + } + + return $o; +} diff --git a/sources/mod/connect.php b/sources/mod/connect.php new file mode 100644 index 00000000..c36aef43 --- /dev/null +++ b/sources/mod/connect.php @@ -0,0 +1,125 @@ + 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $r = q("select * from channel where channel_address = '%s' limit 1", + dbesc($which) + ); + + if($r) + $a->data['channel'] = $r[0]; + + profile_load($a,$which,''); +} + +function connect_post(&$a) { + + if(! array_key_exists('channel', $a->data)) + return; + + $edit = ((local_channel() && (local_channel() == $a->data['channel']['channel_id'])) ? true : false); + + if($edit) { + $has_premium = (($a->data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? 1 : 0); + $premium = (($_POST['premium']) ? intval($_POST['premium']) : 0); + $text = escape_tags($_POST['text']); + + if($has_premium != $premium) { + $r = q("update channel set channel_pageflags = ( channel_pageflags %s %d ) where channel_id = %d", + db_getfunc('^'), + intval(PAGE_PREMIUM), + intval(local_channel()) + ); + proc_run('php','include/notifier.php','refresh_all',$a->data['channel']['channel_id']); + } + set_pconfig($a->data['channel']['channel_id'],'system','selltext',$text); + // reload the page completely to get fresh data + goaway(z_root() . '/' . $a->query_string); + + } + + $url = ''; + $observer = $a->get_observer(); + if(($observer) && ($_POST['submit'] === t('Continue'))) { + if($observer['xchan_follow']) + $url = sprintf($observer['xchan_follow'],urlencode($a->data['channel']['channel_address'] . '@' . $a->get_hostname())); + if(! $url) { + $r = q("select * from hubloc where hubloc_hash = '%s' order by hubloc_id desc limit 1", + dbesc($observer['xchan_hash']) + ); + if($r) + $url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode($a->data['channel']['channel_address'] . '@' . $a->get_hostname()); + } + } + if($url) + goaway($url . '&confirm=1'); + else + notice('Unable to connect to your home hub location.'); + +} + + + +function connect_content(&$a) { + + $edit = ((local_channel() && (local_channel() == $a->data['channel']['channel_id'])) ? true : false); + + $text = get_pconfig($a->data['channel']['channel_id'],'system','selltext'); + + if($edit) { + + $o = replace_macros(get_markup_template('sellpage_edit.tpl'),array( + '$header' => t('Premium Channel Setup'), + '$address' => $a->data['channel']['channel_address'], + '$premium' => array('premium', t('Enable premium channel connection restrictions'),(($a->data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? '1' : ''),''), + '$lbl_about' => t('Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc.'), + '$text' => $text, + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$lbl2' => t('Potential connections will then see the following text before proceeding:'), + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => t('Submit'), + + + )); + return $o; + } + else { + if(! $text) + $text = t('(No specific instructions have been provided by the channel owner.)'); + + $submit = replace_macros(get_markup_template('sellpage_submit.tpl'), array( + '$continue' => t('Continue'), + '$address' => $a->data['channel']['channel_address'] + )); + + $o = replace_macros(get_markup_template('sellpage_view.tpl'),array( + '$header' => t('Restricted or Premium Channel'), + '$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'), + '$text' => prepare_text($text), + + '$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'), + '$submit' => $submit, + + )); + + $arr = array('channel' => $a->data['channel'],'observer' => $a->get_observer(), 'sellpage' => $o, 'submit' => $submit); + call_hooks('connect_premium', $arr); + $o = $arr['sellpage']; + + } + + return $o; +} \ No newline at end of file diff --git a/sources/mod/connections.php b/sources/mod/connections.php new file mode 100644 index 00000000..2f1a1fdf --- /dev/null +++ b/sources/mod/connections.php @@ -0,0 +1,416 @@ +get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); + +} + +function connections_post(&$a) { + + if(! local_channel()) + return; + + $contact_id = intval(argv(1)); + if(! $contact_id) + return; + + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($contact_id), + intval(local_channel()) + ); + + if(! $orig_record) { + notice( t('Could not access contact record.') . EOL); + goaway(z_root() . '/connections'); + return; // NOTREACHED + } + + call_hooks('contact_edit_post', $_POST); + + $profile_id = $_POST['profile_assign']; + if($profile_id) { + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND `uid` = %d LIMIT 1", + dbesc($profile_id), + intval(local_channel()) + ); + if(! count($r)) { + notice( t('Could not locate selected profile.') . EOL); + return; + } + } + + $hidden = intval($_POST['hidden']); + + $priority = intval($_POST['poll']); + if($priority > 5 || $priority < 0) + $priority = 0; + + $closeness = intval($_POST['closeness']); + if($closeness < 0) + $closeness = 99; + + $abook_my_perms = 0; + + foreach($_POST as $k => $v) { + if(strpos($k,'perms_') === 0) { + $abook_my_perms += $v; + } + } + + $new_friend = false; + + if(($_REQUEST['pending']) && intval($orig_record[0]['abook_pending'])) { + $new_friend = true; + } + + $r = q("UPDATE abook SET abook_profile = '%s', abook_my_perms = %d , abook_closeness = %d, abook_pending = %d + where abook_id = %d AND abook_channel = %d", + dbesc($profile_id), + intval($abook_my_perms), + intval($closeness), + intval(1 - intval($new_friend)), + intval($contact_id), + intval(local_channel()) + ); + + if($r) + info( t('Connection updated.') . EOL); + else + notice( t('Failed to update connection record.') . EOL); + + if((x($a->data,'abook')) && $a->data['abook']['abook_my_perms'] != $abook_my_perms + && (! intval($a->data['abook']['abook_self']))) { + proc_run('php', 'include/notifier.php', 'permission_update', $contact_id); + } + + if($new_friend) { + $channel = $a->get_channel(); + $default_group = $channel['channel_default_group']; + if($default_group) { + require_once('include/group.php'); + $g = group_rec_byhash(local_channel(),$default_group); + if($g) + group_add_member(local_channel(),'',$a->data['abook_xchan'],$g['id']); + } + + + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + // TODO + + // pull in a bit of content if there is any to pull in + proc_run('php','include/onepoll.php',$contact_id); + + } + + // Refresh the structure in memory with the new data + + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_channel()), + intval($contact_id) + ); + if($r) { + $a->data['abook'] = $r[0]; + } + + if($new_friend) { + $arr = array('channel_id' => local_channel(), 'abook' => $a->data['abook']); + call_hooks('accept_follow', $arr); + } + + connections_clone($a); + + return; + +} + +function connections_clone(&$a) { + + if(! array_key_exists('abook',$a->data)) + return; + $clone = $a->data['abook']; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone))); +} + + +function connections_content(&$a) { + + $sort_type = 0; + $o = ''; + + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return login(); + } + + $blocked = false; + $hidden = false; + $ignored = false; + $archived = false; + $unblocked = false; + $pending = false; + $unconnected = false; + $all = false; + + if(! $_REQUEST['aj']) + $_SESSION['return_url'] = $a->query_string; + + $search_flags = ''; + $head = ''; + + if(argc() == 2) { + switch(argv(1)) { + case 'blocked': + $search_flags = " and abook_blocked = 1 "; + $head = t('Blocked'); + $blocked = true; + break; + case 'ignored': + $search_flags = " and abook_ignored = 1 "; + $head = t('Ignored'); + $ignored = true; + break; + case 'hidden': + $search_flags = " and abook_hidden = 1 "; + $head = t('Hidden'); + $hidden = true; + break; + case 'archived': + $search_flags = " and abook_archived = 1 "; + $head = t('Archived'); + $archived = true; + break; + case 'pending': + $search_flags = " and abook_pending = 1 "; + $head = t('New'); + $pending = true; + nav_set_selected('intros'); + break; + case 'ifpending': + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval(local_channel()) + ); + if($r && $r[0]['total']) { + $search_flags = " and abook_pending = 1 "; + $head = t('New'); + $pending = true; + nav_set_selected('intros'); + $a->argv[1] = 'pending'; + } + else { + $head = t('All'); + $search_flags = ''; + $all = true; + $a->argc = 1; + unset($a->argv[1]); + } + nav_set_selected('intros'); + break; +// case 'unconnected': +// $search_flags = " and abook_unconnected = 1 "; +// $head = t('Unconnected'); +// $unconnected = true; +// break; + + case 'all': + $head = t('All'); + default: + $search_flags = ''; + $all = true; + break; + + } + + $sql_extra = $search_flags; + if(argv(1) === 'pending') + $sql_extra .= " and abook_ignored = 0 "; + + } + else { + $sql_extra = " and abook_blocked = 0 "; + $unblocked = true; + } + + $search = ((x($_REQUEST,'search')) ? notags(trim($_REQUEST['search'])) : ''); + + $tabs = array( + array( + 'label' => t('Suggestions'), + 'url' => z_root() . '/suggest', + 'sel' => '', + 'title' => t('Suggest new connections'), + ), + array( + 'label' => t('New Connections'), + 'url' => z_root() . '/connections/pending', + 'sel' => ($pending) ? 'active' : '', + 'title' => t('Show pending (new) connections'), + ), + array( + 'label' => t('All Connections'), + 'url' => z_root() . '/connections/all', + 'sel' => ($all) ? 'active' : '', + 'title' => t('Show all connections'), + ), + array( + 'label' => t('Unblocked'), + 'url' => z_root() . '/connections', + 'sel' => (($unblocked) && (! $search) && (! $nets)) ? 'active' : '', + 'title' => t('Only show unblocked connections'), + ), + + array( + 'label' => t('Blocked'), + 'url' => z_root() . '/connections/blocked', + 'sel' => ($blocked) ? 'active' : '', + 'title' => t('Only show blocked connections'), + ), + + array( + 'label' => t('Ignored'), + 'url' => z_root() . '/connections/ignored', + 'sel' => ($ignored) ? 'active' : '', + 'title' => t('Only show ignored connections'), + ), + + array( + 'label' => t('Archived'), + 'url' => z_root() . '/connections/archived', + 'sel' => ($archived) ? 'active' : '', + 'title' => t('Only show archived connections'), + ), + + array( + 'label' => t('Hidden'), + 'url' => z_root() . '/connections/hidden', + 'sel' => ($hidden) ? 'active' : '', + 'title' => t('Only show hidden connections'), + ), + +// array( +// 'label' => t('Unconnected'), +// 'url' => z_root() . '/connections/unconnected', +// 'sel' => ($unconnected) ? 'active' : '', +// 'title' => t('Only show one-way connections'), +// ), + + + ); + + $tab_tpl = get_markup_template('common_tabs.tpl'); + $t = replace_macros($tab_tpl, array('$tabs'=>$tabs)); + + $searching = false; + if($search) { + $search_hdr = $search; + $search_txt = dbesc(protect_sprintf(preg_quote($search))); + $searching = true; + } + $sql_extra .= (($searching) ? protect_sprintf(" AND xchan_name like '%$search_txt%' ") : ""); + + if($_REQUEST['gid']) { + $sql_extra .= " and xchan_hash in ( select xchan from group_member where gid = " . intval($_REQUEST['gid']) . " and uid = " . intval(local_channel()) . " ) "; + } + + $r = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash + where abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ", + intval(local_channel()) + ); + if($r) { + $a->set_pager_total($r[0]['total']); + $total = $r[0]['total']; + } + + $r = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash + WHERE abook_channel = %d and abook_self = 0 and xchan_deleted = 0 and xchan_orphan = 0 $sql_extra $sql_extra2 ORDER BY xchan_name LIMIT %d OFFSET %d ", + intval(local_channel()), + intval($a->pager['itemspage']), + intval($a->pager['start']) + ); + + $contacts = array(); + + if(count($r)) { + + foreach($r as $rr) { + if($rr['xchan_url']) { + $contacts[] = array( + 'img_hover' => sprintf( t('%1$s [%2$s]'),$rr['xchan_name'],$rr['xchan_url']), + 'edit_hover' => t('Edit connection'), + 'id' => $rr['abook_id'], + 'alt_text' => $alt_text, + 'dir_icon' => $dir_icon, + 'thumb' => $rr['xchan_photo_m'], + 'name' => $rr['xchan_name'], + 'username' => $rr['xchan_name'], + 'classes' => (intval($rr['abook_archived']) ? 'archived' : ''), + 'link' => z_root() . '/connedit/' . $rr['abook_id'], + 'edit' => t('Edit'), + 'url' => chanlink_url($rr['xchan_url']), + 'network' => network_to_name($rr['network']), + ); + } + } + } + + + if($_REQUEST['aj']) { + if($contacts) { + $o = replace_macros(get_markup_template('contactsajax.tpl'),array( + '$contacts' => $contacts, + '$edit' => t('Edit'), + )); + } + else { + $o = '
    '; + } + echo $o; + killme(); + } + else { + $o .= ""; + $o .= replace_macros(get_markup_template('connections.tpl'),array( + '$header' => t('Connections') . (($head) ? ' - ' . $head : ''), + '$tabs' => $t, + '$total' => $total, + '$search' => $search_hdr, + '$desc' => t('Search your connections'), + '$finding' => (($searching) ? t('Finding: ') . "'" . $search . "'" : ""), + '$submit' => t('Find'), + '$edit' => t('Edit'), + '$cmd' => $a->cmd, + '$contacts' => $contacts, + '$paginate' => paginate($a), + + )); + } + + if(! $contacts) + $o .= '
    '; + + return $o; +} diff --git a/sources/mod/connedit.php b/sources/mod/connedit.php new file mode 100644 index 00000000..866f8361 --- /dev/null +++ b/sources/mod/connedit.php @@ -0,0 +1,704 @@ += 2) && intval(argv(1))) { + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_channel()), + intval(argv(1)) + ); + if($r) { + $a->poi = $r[0]; + } + } + + $channel = $a->get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); + +} + +/* @brief Evaluate posted values and set changes + * + */ + +function connedit_post(&$a) { + + if(! local_channel()) + return; + + $contact_id = intval(argv(1)); + if(! $contact_id) + return; + + $channel = $a->get_channel(); + + // TODO if configured for hassle-free permissions, we'll post the form with ajax as soon as the + // connection enable is toggled to a special autopost url and set permissions immediately, leaving + // the other form elements alone pending a manual submit of the form. The downside is that there + // will be a window of opportunity when the permissions have been set but before you've had a chance + // to review and possibly restrict them. The upside is we won't have to warn you that your connection + // can't do anything until you save the bloody form. + + $autopost = (((argc() > 2) && (argv(2) === 'auto')) ? true : false); + + $orig_record = q("SELECT * FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($contact_id), + intval(local_channel()) + ); + + if(! $orig_record) { + notice( t('Could not access contact record.') . EOL); + goaway($a->get_baseurl(true) . '/connections'); + return; // NOTREACHED + } + + call_hooks('contact_edit_post', $_POST); + + if(intval($orig_record[0]['abook_self'])) { + $autoperms = intval($_POST['autoperms']); + $is_self = true; + } + else { + $autoperms = null; + $is_self = false; + } + + + $profile_id = $_POST['profile_assign']; + if($profile_id) { + $r = q("SELECT profile_guid FROM profile WHERE profile_guid = '%s' AND `uid` = %d LIMIT 1", + dbesc($profile_id), + intval(local_channel()) + ); + if(! count($r)) { + notice( t('Could not locate selected profile.') . EOL); + return; + } + } + + $abook_incl = escape_tags($_POST['abook_incl']); + $abook_excl = escape_tags($_POST['abook_excl']); + + $hidden = intval($_POST['hidden']); + + $priority = intval($_POST['poll']); + if($priority > 5 || $priority < 0) + $priority = 0; + + $closeness = intval($_POST['closeness']); + if($closeness < 0) + $closeness = 99; + + $rating = intval($_POST['rating']); + if($rating < (-10)) + $rating = (-10); + if($rating > 10) + $rating = 10; + + $rating_text = trim(escape_tags($_REQUEST['rating_text'])); + + $abook_my_perms = 0; + + foreach($_POST as $k => $v) { + if(strpos($k,'perms_') === 0) { + $abook_my_perms += $v; + } + } + + $new_friend = false; + + if(! $is_self) { + + $signed = $orig_record[0]['abook_xchan'] . '.' . $rating . '.' . $rating_text; + + $sig = base64url_encode(rsa_sign($signed,$channel['channel_prvkey'])); + + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($orig_record[0]['abook_xchan']) + ); + + if($z) { + $record = $z[0]['xlink_id']; + $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s' + where xlink_id = %d", + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()), + intval($record) + ); + } + else { + $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", + dbesc($channel['channel_hash']), + dbesc($orig_record[0]['abook_xchan']), + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()) + ); + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($orig_record[0]['abook_xchan']) + ); + if($z) + $record = $z[0]['xlink_id']; + } + if($record) { + proc_run('php','include/ratenotif.php','rating',$record); + } + } + + if(($_REQUEST['pending']) && intval($orig_record[0]['abook_pending'])) { + $new_friend = true; + if(! $abook_my_perms) { + + $abook_my_perms = get_channel_default_perms(local_channel()); + + $role = get_pconfig(local_channel(),'system','permissions_role'); + if($role) { + $x = get_role_perms($role); + if($x['perms_accept']) + $abook_my_perms = $x['perms_accept']; + } + } + } + + $abook_pending = $new_friend ? 0 : $orig_record[0]['abook_pending']; + + $r = q("UPDATE abook SET abook_profile = '%s', abook_my_perms = %d , abook_closeness = %d, abook_pending = %d, + abook_incl = '%s', abook_excl = '%s' + where abook_id = %d AND abook_channel = %d", + dbesc($profile_id), + intval($abook_my_perms), + intval($closeness), + intval($abook_pending), + dbesc($abook_incl), + dbesc($abook_excl), + intval($contact_id), + intval(local_channel()) + ); + + if($orig_record[0]['abook_profile'] != $profile_id) { + //Update profile photo permissions + + logger('A new profile was assigned - updating profile photos'); + require_once('mod/profile_photo.php'); + profile_photo_set_profile_perms($profile_id); + + } + + + if($r) + info( t('Connection updated.') . EOL); + else + notice( t('Failed to update connection record.') . EOL); + + if($a->poi && $a->poi['abook_my_perms'] != $abook_my_perms + && (! intval($a->poi['abook_self']))) { + proc_run('php', 'include/notifier.php', 'permission_update', $contact_id); + } + + if($new_friend) { + $default_group = $channel['channel_default_group']; + if($default_group) { + require_once('include/group.php'); + $g = group_rec_byhash(local_channel(),$default_group); + if($g) + group_add_member(local_channel(),'',$a->poi['abook_xchan'],$g['id']); + } + + // Check if settings permit ("post new friend activity" is allowed, and + // friends in general or this friend in particular aren't hidden) + // and send out a new friend activity + + $pr = q("select * from profile where uid = %d and is_default = 1 and hide_friends = 0", + intval($channel['channel_id']) + ); + if(($pr) && (! intval($orig_record[0]['abook_hidden'])) && (intval(get_pconfig($channel['channel_id'],'system','post_newfriend')))) { + $xarr = array(); + $xarr['verb'] = ACTIVITY_FRIEND; + $xarr['item_wall'] = 1; + $xarr['item_origin'] = 1; + $xarr['item_thread_top'] = 1; + $xarr['owner_xchan'] = $xarr['author_xchan'] = $channel['channel_hash']; + $xarr['allow_cid'] = $channel['channel_allow_cid']; + $xarr['allow_gid'] = $channel['channel_allow_gid']; + $xarr['deny_cid'] = $channel['channel_deny_cid']; + $xarr['deny_gid'] = $channel['channel_deny_gid']; + $xarr['item_private'] = (($xarr['allow_cid']||$xarr['allow_gid']||$xarr['deny_cid']||$xarr['deny_gid']) ? 1 : 0); + $obj = array( + 'type' => ACTIVITY_OBJ_PERSON, + 'title' => $a->poi['xchan_name'], + 'id' => $a->poi['xchan_hash'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $a->poi['xchan_url']), + array('rel' => 'photo', 'type' => $a->poi['xchan_photo_mimetype'], 'href' => $a->poi['xchan_photo_l']) + ), + ); + $xarr['object'] = json_encode($obj); + $xarr['obj_type'] = ACTIVITY_OBJ_PERSON; + + $xarr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t('is now connected to') . ' ' . '[zrl=' . $a->poi['xchan_url'] . ']' . $a->poi['xchan_name'] . '[/zrl]'; + + $xarr['body'] .= "\n\n\n" . '[zrl=' . $a->poi['xchan_url'] . '][zmg=80x80]' . $a->poi['xchan_photo_m'] . '[/zmg][/zrl]'; + + post_activity_item($xarr); + + } + + + // pull in a bit of content if there is any to pull in + proc_run('php','include/onepoll.php',$contact_id); + + } + + // Refresh the structure in memory with the new data + + $r = q("SELECT abook.*, xchan.* + FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_channel = %d and abook_id = %d LIMIT 1", + intval(local_channel()), + intval($contact_id) + ); + if($r) { + $a->poi = $r[0]; + } + + if($new_friend) { + $arr = array('channel_id' => local_channel(), 'abook' => $a->poi); + call_hooks('accept_follow', $arr); + } + + if(! is_null($autoperms)) + set_pconfig(local_channel(),'system','autoperms',(($autoperms) ? $abook_my_perms : 0)); + + connedit_clone($a); + + return; + +} + +/* @brief Clone connection + * + * + */ + +function connedit_clone(&$a) { + + if(! $a->poi) + return; + $clone = $a->poi; + + unset($clone['abook_id']); + unset($clone['abook_account']); + unset($clone['abook_channel']); + + build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone))); +} + +/* @brief Generate content of connection edit page + * + * + */ + +function connedit_content(&$a) { + + $sort_type = 0; + $o = ''; + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return login(); + } + + $channel = $a->get_channel(); + $my_perms = get_channel_default_perms(local_channel()); + $role = get_pconfig(local_channel(),'system','permissions_role'); + if($role) { + $x = get_role_perms($role); + if($x['perms_accept']) + $my_perms = $x['perms_accept']; + } + + if($my_perms) { + $o .= "\n"; + } + + if(argc() == 3) { + + $contact_id = intval(argv(1)); + if(! $contact_id) + return; + + $cmd = argv(2); + + $orig_record = q("SELECT abook.*, xchan.* FROM abook left join xchan on abook_xchan = xchan_hash + WHERE abook_id = %d AND abook_channel = %d AND abook_self = 0 LIMIT 1", + intval($contact_id), + intval(local_channel()) + ); + + if(! count($orig_record)) { + notice( t('Could not access address book record.') . EOL); + goaway($a->get_baseurl(true) . '/connections'); + } + + if($cmd === 'update') { + + // pull feed and consume it, which should subscribe to the hub. + proc_run('php',"include/poller.php","$contact_id"); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + + } + + if($cmd === 'refresh') { + if(! zot_refresh($orig_record[0],get_app()->get_channel())) + notice( t('Refresh failed - channel is currently unavailable.') ); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'block') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_BLOCKED)) { + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'ignore') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_IGNORED)) { + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'archive') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_ARCHIVED)) { + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + if($cmd === 'hide') { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_HIDDEN)) { + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + // We'll prevent somebody from unapproving an already approved contact. + // Though maybe somebody will want this eventually (??) + + if($cmd === 'approve') { + if(intval($orig_record[0]['abook_pending'])) { + if(abook_toggle_flag($orig_record[0],ABOOK_FLAG_PENDING)) { + connedit_clone($a); + } + else + notice(t('Unable to set address book parameters.') . EOL); + } + goaway($a->get_baseurl(true) . '/connedit/' . $contact_id); + } + + + if($cmd === 'drop') { + + require_once('include/Contact.php'); + +// FIXME +// We need to send either a purge or a refresh packet to the other side (the channel being unfriended). +// The issue is that the abook DB record _may_ get destroyed when we call contact_remove. As the notifier runs +// in the background there could be a race condition preventing this packet from being sent in all cases. +// PLACEHOLDER + + contact_remove(local_channel(), $orig_record[0]['abook_id']); + build_sync_packet(0 /* use the current local_channel */, + array('abook' => array(array( + 'abook_xchan' => $orig_record[0]['abook_xchan'], + 'entry_deleted' => true)) + ) + ); + + info( t('Connection has been removed.') . EOL ); + if(x($_SESSION,'return_url')) + goaway($a->get_baseurl(true) . '/' . $_SESSION['return_url']); + goaway($a->get_baseurl(true) . '/contacts'); + + } + } + + if($a->poi) { + + $contact_id = $a->poi['abook_id']; + $contact = $a->poi; + + $buttons = array( + + 'view' => array( + 'label' => t('View Profile'), + 'url' => chanlink_cid($contact['abook_id']), + 'sel' => '', + 'title' => sprintf( t('View %s\'s profile'), $contact['xchan_name']), + ), + + 'refresh' => array( + 'label' => t('Refresh Permissions'), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/refresh', + 'sel' => '', + 'title' => t('Fetch updated permissions'), + ), + + 'recent' => array( + 'label' => t('Recent Activity'), + 'url' => $a->get_baseurl(true) . '/network/?f=&cid=' . $contact['abook_id'], + 'sel' => '', + 'title' => t('View recent posts and comments'), + ), + + 'block' => array( + 'label' => (intval($contact['abook_blocked']) ? t('Unblock') : t('Block')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/block', + 'sel' => (intval($contact['abook_blocked']) ? 'active' : ''), + 'title' => t('Block (or Unblock) all communications with this connection'), + 'info' => (intval($contact['abook_blocked']) ? t('This connection is blocked!') : ''), + ), + + 'ignore' => array( + 'label' => (intval($contact['abook_ignored']) ? t('Unignore') : t('Ignore')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/ignore', + 'sel' => (intval($contact['abook_ignored']) ? 'active' : ''), + 'title' => t('Ignore (or Unignore) all inbound communications from this connection'), + 'info' => (intval($contact['abook_ignored']) ? t('This connection is ignored!') : ''), + ), + + 'archive' => array( + 'label' => (intval($contact['abook_archived']) ? t('Unarchive') : t('Archive')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/archive', + 'sel' => (intval($contact['abook_archived']) ? 'active' : ''), + 'title' => t('Archive (or Unarchive) this connection - mark channel dead but keep content'), + 'info' => (intval($contact['abook_archived']) ? t('This connection is archived!') : ''), + ), + + 'hide' => array( + 'label' => (intval($contact['abook_hidden']) ? t('Unhide') : t('Hide')), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/hide', + 'sel' => (intval($contact['abook_hidden']) ? 'active' : ''), + 'title' => t('Hide or Unhide this connection from your other connections'), + 'info' => (intval($contact['abook_hidden']) ? t('This connection is hidden!') : ''), + ), + + 'delete' => array( + 'label' => t('Delete'), + 'url' => $a->get_baseurl(true) . '/connedit/' . $contact['abook_id'] . '/drop', + 'sel' => '', + 'title' => t('Delete this connection'), + ), + + ); + + $self = false; + + if(intval($contact['abook_self'])) + $self = true; + + require_once('include/contact_selectors.php'); + + $tpl = get_markup_template("abook_edit.tpl"); + + if(feature_enabled(local_channel(),'affinity')) { + + $labels = array( + t('Me'), + t('Family'), + t('Friends'), + t('Acquaintances'), + t('All') + ); + call_hooks('affinity_labels',$labels); + $label_str = ''; + + if($labels) { + foreach($labels as $l) { + if($label_str) { + $label_str .= ", '|'"; + $label_str .= ", '" . $l . "'"; + } + else + $label_str .= "'" . $l . "'"; + } + } + + $slider_tpl = get_markup_template('contact_slider.tpl'); + $slide = replace_macros($slider_tpl,array( + '$min' => 1, + '$val' => (($contact['abook_closeness']) ? $contact['abook_closeness'] : 99), + '$labels' => $label_str, + )); + } + + $rating_val = 0; + $rating_text = ''; + + $xl = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", + dbesc($channel['channel_hash']), + dbesc($contact['xchan_hash']) + ); + + if($xl) { + $rating_val = intval($xl[0]['xlink_rating']); + $rating_text = $xl[0]['xlink_rating_text']; + } + + $poco_rating = get_config('system','poco_rating_enable'); + + // if unset default to enabled + if($poco_rating === false) + $poco_rating = true; + + if($poco_rating) { + $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( + '$min' => -10, + '$val' => $rating_val + )); + } + else { + $rating = false; + } + + + $perms = array(); + $channel = $a->get_channel(); + + $global_perms = get_perms(); + $existing = get_all_perms(local_channel(),$contact['abook_xchan']); + + $unapproved = array('pending', t('Approve this connection'), '', t('Accept connection to allow communication'), array(t('No'),('Yes'))); + + $multiprofs = ((feature_enabled(local_channel(),'multi_profiles')) ? true : false); + + if($slide && !$multiprofs) + $affinity = t('Set Affinity'); + + if(!$slide && $multiprofs) + $affinity = t('Set Profile'); + + if($slide && $multiprofs) + $affinity = t('Set Affinity & Profile'); + + foreach($global_perms as $k => $v) { + $thisperm = (($contact['abook_my_perms'] & $v[1]) ? "1" : ''); + $checkinherited = ((($channel[$v[0]]) && ($channel[$v[0]] != PERMS_SPECIFIC)) ? "1" : ''); + + // For auto permissions (when $self is true) we don't want to look at existing + // permissions because they are enabled for the channel owner + if((! $self) && ($existing[$k])) + $thisperm = "1"; + + $perms[] = array('perms_' . $k, $v[3], (($contact['abook_their_perms'] & $v[1]) ? "1" : ""),$thisperm, $v[1], (($channel[$v[0]] == PERMS_SPECIFIC) ? '' : '1'), $v[4], $checkinherited); + } + + $o .= replace_macros($tpl,array( + + '$header' => (($self) ? t('Connection Default Permissions') : sprintf( t('Connection: %s'),$contact['xchan_name'])), + '$autoperms' => array('autoperms',t('Apply these permissions automatically'), ((get_pconfig(local_channel(),'system','autoperms')) ? 1 : 0), 'Connection requests will be approved without your interaction', array(t('No'),('Yes'))), + '$addr' => $contact['xchan_addr'], + '$addr_text' => t('This connection\'s address is'), + '$notself' => (($self) ? '' : '1'), + '$self' => (($self) ? '1' : ''), + '$autolbl' => t('The permissions indicated on this page will be applied to all new connections.'), + '$buttons' => (($self) ? '' : $buttons), + '$lbl_slider' => t('Slide to adjust your degree of friendship'), + '$lbl_rating' => t('Rating'), + '$lbl_rating_label' => t('Slide to adjust your rating'), + '$lbl_rating_txt' => t('Optionally explain your rating'), + '$connfilter' => feature_enabled(local_channel(),'connfilter'), + '$connfilter_label' => t('Custom Filter'), + '$incl' => array('abook_incl',t('Only import posts with this text'), $contact['abook_incl'],t('words one per line or #tags or /patterns/, leave blank to import all posts')), + '$excl' => array('abook_excl',t('Do not import posts with this text'), $contact['abook_excl'],t('words one per line or #tags or /patterns/, leave blank to import all posts')), + '$rating_text' => array('rating_text', t('Optionally explain your rating'),$rating_text,''), + '$rating_info' => t('This information is public!'), + '$rating' => $rating, + '$rating_val' => $rating_val, + '$slide' => $slide, + '$affinity' => $affinity, + '$pending_label' => t('Connection Pending Approval'), + '$pending_modal_title' => t('Connection Request'), + '$pending_modal_body' => sprintf(t('(%s) would like to connect with you. Please approve this connection to allow communication.'), $contact['xchan_addr']), + '$pending_modal_approve' => t('Approve'), + '$pending_modal_dismiss' => t('Approve Later'), + '$is_pending' => (intval($contact['abook_pending']) ? 1 : ''), + '$unapproved' => $unapproved, + '$inherited' => t('inherited'), + '$submit' => t('Submit'), + '$lbl_vis2' => sprintf( t('Please choose the profile you would like to display to %s when viewing your profile securely.'), $contact['xchan_name']), + '$close' => $contact['abook_closeness'], + '$them' => t('Their Settings'), + '$me' => t('My Settings'), + '$perms' => $perms, + '$permlbl' => t('Individual Permissions'), + '$permnote' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can not change those settings here.'), + '$permnote_self' => t('Some permissions may be inherited from your channel\'s privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes.'), + '$lastupdtext' => t('Last update:'), + '$last_update' => relative_date($contact['abook_connected']), + '$profile_select' => contact_profile_assign($contact['abook_profile']), + '$multiprofs' => $multiprofs, + '$contact_id' => $contact['abook_id'], + '$name' => $contact['xchan_name'], + + )); + + $arr = array('contact' => $contact,'output' => $o); + + call_hooks('contact_edit', $arr); + + return $arr['output']; + + } + + +} diff --git a/sources/mod/contactgroup.php b/sources/mod/contactgroup.php new file mode 100644 index 00000000..61ca3705 --- /dev/null +++ b/sources/mod/contactgroup.php @@ -0,0 +1,49 @@ + 2) && (intval(argv(1))) && (argv(2))) { + $r = q("SELECT abook_xchan from abook where abook_xchan = '%s' and abook_channel = %d and abook_self = 0 limit 1", + dbesc(base64url_decode(argv(2))), + intval(local_channel()) + ); + if($r) + $change = $r[0]['abook_xchan']; + } + + if((argc() > 1) && (intval(argv(1)))) { + + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if(! $r) { + killme(); + } + + $group = $r[0]; + $members = group_get_members($group['id']); + $preselected = array(); + if(count($members)) { + foreach($members as $member) + $preselected[] = $member['xchan_hash']; + } + + if($change) { + if(in_array($change,$preselected)) { + group_rmv_member(local_channel(),$group['name'],$change); + } + else { + group_add_member(local_channel(),$group['name'],$change); + } + } + } + + killme(); +} \ No newline at end of file diff --git a/sources/mod/dav.php b/sources/mod/dav.php new file mode 100644 index 00000000..d4695a54 --- /dev/null +++ b/sources/mod/dav.php @@ -0,0 +1,142 @@ + 1) + $which = argv(1); + + $profile = 0; + + $a->page['htmlhead'] .= '' . "\r\n"; + + if ($which) + profile_load($a, $which, $profile); + + $auth = new RedDAV\RedBasicAuth(); + + $ob_hash = get_observer_hash(); + + if ($ob_hash) { + if (local_channel()) { + $channel = $a->get_channel(); + $auth->setCurrentUser($channel['channel_address']); + $auth->channel_id = $channel['channel_id']; + $auth->channel_hash = $channel['channel_hash']; + $auth->channel_account_id = $channel['channel_account_id']; + if($channel['channel_timezone']) + $auth->setTimezone($channel['channel_timezone']); + } + $auth->observer = $ob_hash; + } + + if ($_GET['davguest']) + $_SESSION['davguest'] = true; + + $_SERVER['QUERY_STRING'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = strip_zids($_SERVER['QUERY_STRING']); + $_SERVER['QUERY_STRING'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['QUERY_STRING']); + + $_SERVER['REQUEST_URI'] = str_replace(array('?f=', '&f='), array('', ''), $_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = strip_zids($_SERVER['REQUEST_URI']); + $_SERVER['REQUEST_URI'] = preg_replace('/[\?&]davguest=(.*?)([\?&]|$)/ism', '', $_SERVER['REQUEST_URI']); + + $rootDirectory = new RedDAV\RedDirectory('/', $auth); + + // A SabreDAV server-object + $server = new DAV\Server($rootDirectory); + // prevent overwriting changes each other with a lock backend + $lockBackend = new DAV\Locks\Backend\File('store/[data]/locks'); + $lockPlugin = new DAV\Locks\Plugin($lockBackend); + + $server->addPlugin($lockPlugin); + + // The next section of code allows us to bypass prompting for http-auth if a + // FILE is being accessed anonymously and permissions allow this. This way + // one can create hotlinks to public media files in their cloud and anonymous + // viewers won't get asked to login. + // If a DIRECTORY is accessed or there are permission issues accessing the + // file and we aren't previously authenticated via zot, prompt for HTTP-auth. + // This will be the default case for mounting a DAV directory. + // In order to avoid prompting for passwords for viewing a DIRECTORY, add + // the URL query parameter 'davguest=1'. + + $isapublic_file = false; + $davguest = ((x($_SESSION, 'davguest')) ? true : false); + + if ((! $auth->observer) && ($_SERVER['REQUEST_METHOD'] === 'GET')) { + try { + $x = RedFileData('/' . $a->cmd, $auth); + if($x instanceof RedDAV\RedFile) + $isapublic_file = true; + } + catch (Exception $e) { + $isapublic_file = false; + } + } + + if ((! $auth->observer) && (! $isapublic_file) && (! $davguest)) { + try { + $auth->Authenticate($server, t('$Projectname channel')); + } + catch (Exception $e) { + logger('mod_cloud: auth exception' . $e->getMessage()); + http_status_exit($e->getHTTPCode(), $e->getMessage()); + } + } + + require_once('include/RedDAV/RedBrowser.php'); + // provide a directory view for the cloud in Hubzilla + $browser = new RedDAV\RedBrowser($auth); + $auth->setBrowserPlugin($browser); + + // Experimental QuotaPlugin +// require_once('include/RedDAV/QuotaPlugin.php'); +// $server->addPlugin(new RedDAV\QuotaPlugin($auth)); + + // All we need to do now, is to fire up the server + $server->exec(); + + killme(); +} diff --git a/sources/mod/directory.php b/sources/mod/directory.php new file mode 100644 index 00000000..3c230e17 --- /dev/null +++ b/sources/mod/directory.php @@ -0,0 +1,414 @@ +set_pager_itemspage(60); + + if(x($_GET,'ignore')) { + q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ", + intval(local_channel()), + dbesc($_GET['ignore']) + ); + goaway(z_root() . '/directory?suggest=1'); + } + + $observer = get_observer_hash(); + $global_changed = false; + $safe_changed = false; + $pubforums_changed = false; + + if(array_key_exists('global',$_REQUEST)) { + $globaldir = intval($_REQUEST['global']); + $global_changed = true; + } + if($global_changed) { + $_SESSION['globaldir'] = $globaldir; + if($observer) + set_xconfig($observer,'directory','globaldir',$globaldir); + } + + if(array_key_exists('safe',$_REQUEST)) { + $safemode = intval($_REQUEST['safe']); + $safe_changed = true; + } + if($safe_changed) { + $_SESSION['safemode'] = $safemode; + if($observer) + set_xconfig($observer,'directory','safemode',$safemode); + } + + + if(array_key_exists('pubforums',$_REQUEST)) { + $pubforums = intval($_REQUEST['pubforums']); + $pubforums_changed = true; + } + if($pubforums_changed) { + $_SESSION['pubforums'] = $pubforums; + if($observer) + set_xconfig($observer,'directory','pubforums',$pubforums); + } +} + +function directory_content(&$a) { + + if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) { + notice( t('Public access denied.') . EOL); + return; + } + + $observer = get_observer_hash(); + + $globaldir = get_directory_setting($observer, 'globaldir'); + // override your personal global search pref if we're doing a navbar search of the directory + if(intval($_REQUEST['navsearch'])) + $globaldir = 1; + + $safe_mode = get_directory_setting($observer, 'safemode'); + + $pubforums = get_directory_setting($observer, 'pubforums'); + + $o = ''; + nav_set_selected('directory'); + + if(x($_POST,'search')) + $search = notags(trim($_POST['search'])); + else + $search = ((x($_GET,'search')) ? notags(trim(rawurldecode($_GET['search']))) : ''); + + + if(strpos($search,'=') && local_channel() && get_pconfig(local_channel(),'feature','expert')) + $advanced = $search; + + + $keywords = (($_GET['keywords']) ? $_GET['keywords'] : ''); + + // Suggest channels if no search terms or keywords are given + $suggest = (local_channel() && x($_REQUEST,'suggest')) ? $_REQUEST['suggest'] : ''; + + if($suggest) { + + $r = suggestion_query(local_channel(),get_observer_hash()); + + // Remember in which order the suggestions were + $addresses = array(); + $common = array(); + $index = 0; + foreach($r as $rr) { + $common[$rr['xchan_addr']] = $rr['total']; + $addresses[$rr['xchan_addr']] = $index++; + } + + // Build query to get info about suggested people + $advanced = ''; + foreach(array_keys($addresses) as $address) { + $advanced .= "address=\"$address\" "; + } + // Remove last space in the advanced query + $advanced = rtrim($advanced); + + } + + $tpl = get_markup_template('directory_header.tpl'); + + $dirmode = intval(get_config('system','directory_mode')); + + if(($dirmode == DIRECTORY_MODE_PRIMARY) || ($dirmode == DIRECTORY_MODE_STANDALONE)) { + $url = z_root() . '/dirsearch'; + } + if(! $url) { + $directory = find_upstream_directory($dirmode); + $url = $directory['url'] . '/dirsearch'; + } + + $token = get_config('system','realm_token'); + + + logger('mod_directory: URL = ' . $url, LOGGER_DEBUG); + + $contacts = array(); + + if(local_channel()) { + $x = q("select abook_xchan from abook where abook_channel = %d", + intval(local_channel()) + ); + if($x) { + foreach($x as $xx) + $contacts[] = $xx['abook_xchan']; + } + } + + if($url) { + // We might want to make the tagadelic count (&kw=) configurable or turn it off completely. + + $numtags = get_config('system','directorytags'); + + $kw = ((intval($numtags)) ? $numtags : 50); + $query = $url . '?f=&kw=' . $kw . (($safe_mode != 1) ? '&safe=' . $safe_mode : ''); + + if($token) + $query .= '&t=' . $token; + + if(! $globaldir) + $query .= '&hub=' . get_app()->get_hostname(); + + if($search) + $query .= '&name=' . urlencode($search) . '&keywords=' . urlencode($search); + if(strpos($search,'@')) + $query .= '&address=' . urlencode($search); + if($keywords) + $query .= '&keywords=' . urlencode($keywords); + if($advanced) + $query .= '&query=' . urlencode($advanced); + if(! is_null($pubforums)) + $query .= '&pubforums=' . intval($pubforums); + + $directory_sort_order = get_config('system','directory_sort_order'); + if(! $directory_sort_order) + $directory_sort_order = 'date'; + + $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : $directory_sort_order); + + if($sort_order) + $query .= '&order=' . urlencode($sort_order); + + if($a->pager['page'] != 1) + $query .= '&p=' . $a->pager['page']; + + logger('mod_directory: query: ' . $query); + + $x = z_fetch_url($query); + logger('directory: return from upstream: ' . print_r($x,true), LOGGER_DATA); + + if($x['success']) { + $t = 0; + $j = json_decode($x['body'],true); + if($j) { + + if($j['results']) { + + $entries = array(); + + $photo = 'thumb'; + + foreach($j['results'] as $rr) { + + $profile_link = chanlink_url($rr['url']); + + $pdesc = (($rr['description']) ? $rr['description'] . '
    ' : ''); + $connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : ''); + + // Checking status is disabled ATM until someone checks the performance impact more carefully + //$online = remote_online_status($rr['address']); + $online = ''; + + if(in_array($rr['hash'],$contacts)) + $connect_link = ''; + + $location = ''; + if(strlen($rr['locale'])) + $location .= $rr['locale']; + if(strlen($rr['region'])) { + if(strlen($rr['locale'])) + $location .= ', '; + $location .= $rr['region']; + } + if(strlen($rr['country'])) { + if(strlen($location)) + $location .= ', '; + $location .= $rr['country']; + } + + $age = ''; + if(strlen($rr['birthday'])) { + if(($years = age($rr['birthday'],'UTC','')) != 0) + $age = $years; + } + + $page_type = ''; + + if($rr['total_ratings']) + $total_ratings = sprintf( tt("%d rating", "%d ratings", $rr['total_ratings']), $rr['total_ratings']); + else + $total_ratings = ''; + + $profile = $rr; + + if ((x($profile,'locale') == 1) + || (x($profile,'region') == 1) + || (x($profile,'postcode') == 1) + || (x($profile,'country') == 1)) + + $gender = ((x($profile,'gender') == 1) ? t('Gender: ') . $profile['gender']: False); + + $marital = ((x($profile,'marital') == 1) ? t('Status: ') . $profile['marital']: False); + + $homepage = ((x($profile,'homepage') == 1) ? t('Homepage: ') : False); + $homepageurl = ((x($profile,'homepage') == 1) ? $profile['homepage'] : ''); + + $hometown = ((x($profile,'hometown') == 1) ? $profile['hometown'] : False); + + $about = ((x($profile,'about') == 1) ? bbcode($profile['about']) : False); + + $keywords = ((x($profile,'keywords')) ? $profile['keywords'] : ''); + + $out = ''; + + if($keywords) { + $keywords = str_replace(',',' ', $keywords); + $keywords = str_replace(' ',' ', $keywords); + $karr = explode(' ', $keywords); + + if($karr) { + if(local_channel()) { + $r = q("select keywords from profile where uid = %d and is_default = 1 limit 1", + intval(local_channel()) + ); + if($r) { + $keywords = str_replace(',',' ', $r[0]['keywords']); + $keywords = str_replace(' ',' ', $keywords); + $marr = explode(' ', $keywords); + } + } + foreach($karr as $k) { + if(strlen($out)) + $out .= ', '; + if($marr && in_arrayi($k,$marr)) + $out .= '' . $k . ''; + else + $out .= $k; + } + } + + } + + $entry = array( + 'id' => ++$t, + 'profile_link' => $profile_link, + 'public_forum' => $rr['public_forum'], + 'photo' => $rr['photo'], + 'hash' => $rr['hash'], + 'alttext' => $rr['name'] . ((local_channel() || remote_channel()) ? ' ' . $rr['address'] : ''), + 'name' => $rr['name'], + 'age' => $age, + 'age_label' => t('Age:'), + 'profile' => $profile, + 'address' => $rr['address'], + 'nickname' => substr($rr['address'],0,strpos($rr['address'],'@')), + 'location' => $location, + 'location_label' => t('Location:'), + 'gender' => $gender, + 'total_ratings' => $total_ratings, + 'viewrate' => true, + 'canrate' => ((local_channel()) ? true : false), + 'pdesc' => $pdesc, + 'pdesc_label' => t('Description:'), + 'marital' => $marital, + 'homepage' => $homepage, + 'homepageurl' => linkify($homepageurl), + 'hometown' => $hometown, + 'hometown_label' => t('Hometown:'), + 'about' => $about, + 'about_label' => t('About:'), + 'conn_label' => t('Connect'), + 'forum_label' => t('Public Forum:'), + 'connect' => $connect_link, + 'online' => $online, + 'kw' => (($out) ? t('Keywords: ') : ''), + 'keywords' => $out, + 'ignlink' => $suggest ? $a->get_baseurl() . '/directory?ignore=' . $rr['hash'] : '', + 'ignore_label' => t('Don\'t suggest'), + 'common_friends' => (($common[$rr['address']]) ? intval($common[$rr['address']]) : ''), + 'common_label' => t('Common connections:'), + 'common_count' => intval($common[$rr['address']]), + 'safe' => $safe_mode + ); + + $arr = array('contact' => $rr, 'entry' => $entry); + + call_hooks('directory_item', $arr); + + unset($profile); + unset($location); + + if(! $arr['entry']) { + continue; + } + + if($sort_order == '' && $suggest) { + $entries[$addresses[$rr['address']]] = $arr['entry']; // Use the same indexes as originally to get the best suggestion first + } + + else { + $entries[] = $arr['entry']; + } + } + + ksort($entries); // Sort array by key so that foreach-constructs work as expected + + if($j['keywords']) { + $a->data['directory_keywords'] = $j['keywords']; + } + + logger('mod_directory: entries: ' . print_r($entries,true), LOGGER_DATA); + + + if($_REQUEST['aj']) { + if($entries) { + $o = replace_macros(get_markup_template('directajax.tpl'),array( + '$entries' => $entries + )); + } + else { + $o = '
    '; + } + echo $o; + killme(); + } + else { + $maxheight = 94; + + $dirtitle = (($globaldir) ? t('Global Directory') : t('Local Directory')); + + $o .= ""; + $o .= replace_macros($tpl, array( + '$search' => $search, + '$desc' => t('Find'), + '$finddsc' => t('Finding:'), + '$safetxt' => htmlspecialchars($search,ENT_QUOTES,'UTF-8'), + '$entries' => $entries, + '$dirlbl' => $suggest ? t('Channel Suggestions') : $dirtitle, + '$submit' => t('Find'), + '$next' => alt_pager($a,$j['records'], t('next page'), t('previous page')), + '$sort' => t('Sort options'), + '$normal' => t('Alphabetic'), + '$reverse' => t('Reverse Alphabetic'), + '$date' => t('Newest to Oldest'), + '$reversedate' => t('Oldest to Newest'), + '$suggest' => $suggest ? '&suggest=1' : '' + )); + + + } + + } + else { + if($_REQUEST['aj']) { + $o = '
    '; + echo $o; + killme(); + } + if($a->pager['page'] == 1 && $j['records'] == 0 && strpos($search,'@')) { + goaway(z_root() . '/chanview/?f=&address=' . $search); + } + info( t("No entries (some entries may be hidden).") . EOL); + } + } + } + } + return $o; +} + diff --git a/sources/mod/dirsearch.php b/sources/mod/dirsearch.php new file mode 100644 index 00000000..132ed252 --- /dev/null +++ b/sources/mod/dirsearch.php @@ -0,0 +1,446 @@ +set_pager_itemspage(60); + +} + +function dirsearch_content(&$a) { + + $ret = array('success' => false); + +// logger('request: ' . print_r($_REQUEST,true)); + + + $dirmode = intval(get_config('system','directory_mode')); + + if($dirmode == DIRECTORY_MODE_NORMAL) { + $ret['message'] = t('This site is not a directory server'); + json_return_and_die($ret); + } + + $access_token = $_REQUEST['t']; + + $token = get_config('system','realm_token'); + if($token && $access_token != $token) { + $result['message'] = t('This directory server requires an access token'); + return; + } + + + if(argc() > 1 && argv(1) === 'sites') { + $ret = list_public_sites(); + json_return_and_die($ret); + } + + $sql_extra = ''; + + + $tables = array('name','address','locale','region','postcode','country','gender','marital','sexual','keywords'); + + if($_REQUEST['query']) { + $advanced = dir_parse_query($_REQUEST['query']); + if($advanced) { + foreach($advanced as $adv) { + if(in_array($adv['field'],$tables)) { + if($adv['field'] === 'name') + $sql_extra .= dir_query_build($adv['logic'],'xchan_name',$adv['value']); + elseif($adv['field'] === 'address') + $sql_extra .= dir_query_build($adv['logic'],'xchan_addr',$adv['value']); + else + $sql_extra .= dir_query_build($adv['logic'],'xprof_' . $adv['field'],$adv['value']); + } + } + } + } + + $hash = ((x($_REQUEST['hash'])) ? $_REQUEST['hash'] : ''); + + $name = ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''); + $hub = ((x($_REQUEST,'hub')) ? $_REQUEST['hub'] : ''); + $address = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); + $locale = ((x($_REQUEST,'locale')) ? $_REQUEST['locale'] : ''); + $region = ((x($_REQUEST,'region')) ? $_REQUEST['region'] : ''); + $postcode = ((x($_REQUEST,'postcode')) ? $_REQUEST['postcode'] : ''); + $country = ((x($_REQUEST,'country')) ? $_REQUEST['country'] : ''); + $gender = ((x($_REQUEST,'gender')) ? $_REQUEST['gender'] : ''); + $marital = ((x($_REQUEST,'marital')) ? $_REQUEST['marital'] : ''); + $sexual = ((x($_REQUEST,'sexual')) ? $_REQUEST['sexual'] : ''); + $keywords = ((x($_REQUEST,'keywords')) ? $_REQUEST['keywords'] : ''); + $agege = ((x($_REQUEST,'agege')) ? intval($_REQUEST['agege']) : 0 ); + $agele = ((x($_REQUEST,'agele')) ? intval($_REQUEST['agele']) : 0 ); + $kw = ((x($_REQUEST,'kw')) ? intval($_REQUEST['kw']) : 0 ); + $forums = ((array_key_exists('pubforums',$_REQUEST)) ? intval($_REQUEST['pubforums']) : 0); + + + + // by default use a safe search + $safe = ((x($_REQUEST,'safe'))); // ? intval($_REQUEST['safe']) : 1 ); + if ($safe === false) + $safe = 1; + + if(array_key_exists('sync',$_REQUEST)) { + if($_REQUEST['sync']) + $sync = datetime_convert('UTC','UTC',$_REQUEST['sync']); + else + $sync = datetime_convert('UTC','UTC','2010-01-01 01:01:00'); + } + else + $sync = false; + + + if($hub) + $hub_query = " and xchan_hash in (select hubloc_hash from hubloc where hubloc_host = '" . protect_sprintf(dbesc($hub)) . "') "; + else + $hub_query = ''; + + $sort_order = ((x($_REQUEST,'order')) ? $_REQUEST['order'] : ''); + + $joiner = ' OR '; + if($_REQUEST['and']) + $joiner = ' AND '; + + if($name) + $sql_extra .= dir_query_build($joiner,'xchan_name',$name); + if($address) + $sql_extra .= dir_query_build($joiner,'xchan_addr',$address); + if($city) + $sql_extra .= dir_query_build($joiner,'xprof_locale',$city); + if($region) + $sql_extra .= dir_query_build($joiner,'xprof_region',$region); + if($post) + $sql_extra .= dir_query_build($joiner,'xprof_postcode',$post); + if($country) + $sql_extra .= dir_query_build($joiner,'xprof_country',$country); + if($gender) + $sql_extra .= dir_query_build($joiner,'xprof_gender',$gender); + if($marital) + $sql_extra .= dir_query_build($joiner,'xprof_marital',$marital); + if($sexual) + $sql_extra .= dir_query_build($joiner,'xprof_sexual',$sexual); + if($keywords) + $sql_extra .= dir_query_build($joiner,'xprof_keywords',$keywords); + + if($forums) + $safesql .= dir_flag_build(' AND ','xchan_flags',XCHAN_FLAGS_PUBFORUM, $forums); + + // we only support an age range currently. You must set both agege + // (greater than or equal) and agele (less than or equal) + + if($agele && $agege) { + $sql_extra .= " $joiner ( xprof_age <= " . intval($agele) . " "; + $sql_extra .= " AND xprof_age >= " . intval($agege) . ") "; + } + + + if($hash) { + $sql_extra = " AND xchan_hash like '" . dbesc($hash) . protect_sprintf('%') . "' "; + } + + + $perpage = (($_REQUEST['n']) ? $_REQUEST['n'] : 60); + $page = (($_REQUEST['p']) ? intval($_REQUEST['p'] - 1) : 0); + $startrec = (($page+1) * $perpage) - $perpage; + $limit = (($_REQUEST['limit']) ? intval($_REQUEST['limit']) : 0); + $return_total = ((x($_REQUEST,'return_total')) ? intval($_REQUEST['return_total']) : 0); + + // mtime is not currently working + + $mtime = ((x($_REQUEST,'mtime')) ? datetime_convert('UTC','UTC',$_REQUEST['mtime']) : ''); + + // ok a separate tag table won't work. + // merge them into xprof + + $ret['success'] = true; + + // If &limit=n, return at most n entries + // If &return_total=1, we count matching entries and return that as 'total_items' for use in pagination. + // By default we return one page (default 80 items maximum) and do not count total entries + + $logic = ((strlen($sql_extra)) ? 'false' : 'true'); + + if($hash) + $logic = 'true'; + + if($dirmode == DIRECTORY_MODE_STANDALONE) { + $sql_extra .= " and xchan_addr like '%%" . get_app()->get_hostname() . "' "; + } + + $safesql = (($safe > 0) ? " and xchan_censored = 0 and xchan_selfcensored = 0 " : ''); + if($safe < 0) + $safesql = " and ( xchan_censored = 1 OR xchan_selfcensored = 1 ) "; + + if($limit) + $qlimit = " LIMIT $limit "; + else { + $qlimit = " LIMIT " . intval($perpage) . " OFFSET " . intval($startrec); + if($return_total) { + $r = q("SELECT COUNT(xchan_hash) AS `total` FROM xchan left join xprof on xchan_hash = xprof_hash where $logic $sql_extra and xchan_network = 'zot' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 $safesql "); + if($r) { + $ret['total_items'] = $r[0]['total']; + } + } + } + + + if($sort_order == 'normal') { + $order = " order by xchan_name asc "; + + // Start the alphabetic search at 'A' + // This will make a handful of channels whose names begin with + // punctuation un-searchable in this mode + + $safesql .= " and ascii(substring(xchan_name FROM 1 FOR 1)) > 64 "; + } + elseif($sort_order == 'reverse') + $order = " order by xchan_name desc "; + elseif($sort_order == 'reversedate') + $order = " order by xchan_name_date asc "; + else + $order = " order by xchan_name_date desc "; + + if($sync) { + $spkt = array('transactions' => array()); + $r = q("select * from updates where ud_date >= '%s' and ud_guid != '' order by ud_date desc", + dbesc($sync) + ); + if($r) { + foreach($r as $rr) { + $flags = array(); + if($rr['ud_flags'] & UPDATE_FLAGS_DELETED) + $flags[] = 'deleted'; + if($rr['ud_flags'] & UPDATE_FLAGS_FORCED) + $flags[] = 'forced'; + + $spkt['transactions'][] = array( + 'hash' => $rr['ud_hash'], + 'address' => $rr['ud_addr'], + 'transaction_id' => $rr['ud_guid'], + 'timestamp' => $rr['ud_date'], + 'flags' => $flags + ); + } + } + $r = q("select * from xlink where xlink_static = 1 and xlink_updated >= '%s' ", + dbesc($sync) + ); + if($r) { + $spkt['ratings'] = array(); + foreach($r as $rr) { + $spkt['ratings'][] = array( + 'type' => 'rating', + 'encoding' => 'zot', + 'channel' => $rr['xlink_xchan'], + 'target' => $rr['xlink_link'], + 'rating' => intval($rr['xlink_rating']), + 'rating_text' => $rr['xlink_rating_text'], + 'signature' => $rr['xlink_sig'], + 'edited' => $rr['xlink_updated'] + ); + } + } + json_return_and_die($spkt); + } + else { + $r = q("SELECT xchan.*, xprof.* from xchan left join xprof on xchan_hash = xprof_hash + where ( $logic $sql_extra ) $hub_query and xchan_network = 'zot' and xchan_hidden = 0 and xchan_orphan = 0 and xchan_deleted = 0 + $safesql $order $qlimit " + ); + $ret['page'] = $page + 1; + $ret['records'] = count($r); + } + + + if($r) { + + $entries = array(); + + foreach($r as $rr) { + + $entry = array(); + + $pc = q("select count(xlink_rating) as total_ratings from xlink where xlink_link = '%s' and xlink_rating != 0 and xlink_static = 1 group by xlink_rating", + dbesc($rr['xchan_hash']) + ); + + if($pc) + $entry['total_ratings'] = intval($pc[0]['total_ratings']); + else + $entry['total_ratings'] = 0; + + $entry['name'] = $rr['xchan_name']; + $entry['hash'] = $rr['xchan_hash']; + + $entry['public_forum'] = (intval($rr['xchan_pubforum']) ? true : false); + + $entry['url'] = $rr['xchan_url']; + $entry['photo_l'] = $rr['xchan_photo_l']; + $entry['photo'] = $rr['xchan_photo_m']; + $entry['address'] = $rr['xchan_addr']; + $entry['description'] = $rr['xprof_desc']; + $entry['locale'] = $rr['xprof_locale']; + $entry['region'] = $rr['xprof_region']; + $entry['postcode'] = $rr['xprof_postcode']; + $entry['country'] = $rr['xprof_country']; + $entry['birthday'] = $rr['xprof_dob']; + $entry['age'] = $rr['xprof_age']; + $entry['gender'] = $rr['xprof_gender']; + $entry['marital'] = $rr['xprof_marital']; + $entry['sexual'] = $rr['xprof_sexual']; + $entry['about'] = $rr['xprof_about']; + $entry['homepage'] = $rr['xprof_homepage']; + $entry['hometown'] = $rr['xprof_hometown']; + $entry['keywords'] = $rr['xprof_keywords']; + + $entries[] = $entry; + + } + + $ret['results'] = $entries; + if($kw) { + $k = dir_tagadelic($kw); + if($k) { + $ret['keywords'] = array(); + foreach($k as $kv) { + $ret['keywords'][] = array('term' => $kv[0],'weight' => $kv[1], 'normalise' => $kv[2]); + } + } + } + } + + json_return_and_die($ret); +} + +function dir_query_build($joiner,$field,$s) { + $ret = ''; + if(trim($s)) + $ret .= dbesc($joiner) . " " . dbesc($field) . " like '" . protect_sprintf( '%' . dbesc($s) . '%' ) . "' "; + return $ret; +} + +function dir_flag_build($joiner,$field,$bit,$s) { + return dbesc($joiner) . " ( " . dbesc($field) . " & " . intval($bit) . " ) " . ((intval($s)) ? '>' : '=' ) . " 0 "; +} + + +function dir_parse_query($s) { + + $ret = array(); + $curr = array(); + $all = explode(' ',$s); + $quoted_string = false; + + if($all) { + foreach($all as $q) { + if($quoted_string === false) { + if($q === 'and') { + $curr['logic'] = 'and'; + continue; + } + if($q === 'or') { + $curr['logic'] = 'or'; + continue; + } + if($q === 'not') { + $curr['logic'] .= ' not'; + continue; + } + if(strpos($q,'=')) { + if(! isset($curr['logic'])) + $curr['logic'] = 'or'; + $curr['field'] = trim(substr($q,0,strpos($q,'='))); + $curr['value'] = trim(substr($q,strpos($q,'=')+1)); + if($curr['value'][0] == '"' && $curr['value'][strlen($curr['value'])-1] != '"') { + $quoted_string = true; + $curr['value'] = substr($curr['value'],1); + continue; + } + elseif($curr['value'][0] == '"' && $curr['value'][strlen($curr['value'])-1] == '"') { + $curr['value'] = substr($curr['value'],1,strlen($curr['value'])-2); + $ret[] = $curr; + $curr = array(); + continue; + } + else { + $ret[] = $curr; + $curr = array(); + continue; + } + } + } + else { + if($q[strlen($q)-1] == '"') { + $curr['value'] .= ' ' . str_replace('"','',trim($q)); + $ret[] = $curr; + $curr = array(); + $quoted_string = false; + } + else + $curr['value'] .= ' ' . trim(q); + } + } + } + logger('dir_parse_query:' . print_r($ret,true),LOGGER_DATA); + return $ret; +} + + + + + + + +function list_public_sites() { + + $rand = db_getfunc('rand'); + $realm = get_directory_realm(); + if($realm == DIRECTORY_REALM) { + $r = q("select * from site where site_access != 0 and site_register !=0 and ( site_realm = '%s' or site_realm = '') order by $rand", + dbesc($realm) + ); + } + else { + $r = q("select * from site where site_access != 0 and site_register !=0 and site_realm = '%s' order by $rand", + dbesc($realm) + ); + } + + $ret = array('success' => false); + + if($r) { + $ret['success'] = true; + $ret['sites'] = array(); + $insecure = array(); + + foreach($r as $rr) { + + if($rr['site_access'] == ACCESS_FREE) + $access = 'free'; + elseif($rr['site_access'] == ACCESS_PAID) + $access = 'paid'; + elseif($rr['site_access'] == ACCESS_TIERED) + $access = 'tiered'; + else + $access = 'private'; + + if($rr['site_register'] == REGISTER_OPEN) + $register = 'open'; + elseif($rr['site_register'] == REGISTER_APPROVE) + $register = 'approve'; + else + $register = 'closed'; + + if(strpos($rr['site_url'],'https://') !== false) + $ret['sites'][] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location']); + else + $insecure[] = array('url' => $rr['site_url'], 'access' => $access, 'register' => $register, 'sellpage' => $rr['site_sellpage'], 'location' => $rr['site_location']); + } + if($insecure) { + $ret['sites'] = array_merge($ret['sites'],$insecure); + } + } + return $ret; +} diff --git a/sources/mod/display.php b/sources/mod/display.php new file mode 100644 index 00000000..b2d9ba34 --- /dev/null +++ b/sources/mod/display.php @@ -0,0 +1,289 @@ +page['htmlhead'] .= replace_macros(get_markup_template('display-head.tpl'), array()); + + if(argc() > 1 && argv(1) !== 'load') + $item_hash = argv(1); + + + if($_REQUEST['mid']) + $item_hash = $_REQUEST['mid']; + + + if(! $item_hash) { + $a->error = 404; + notice( t('Item not found.') . EOL); + return; + } + + $observer_is_owner = false; + + + if(local_channel() && (! $update)) { + + $channel = $a->get_channel(); + + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + + 'acl' => populate_acl($channel_acl), + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'return_path' => 'channel/' . $channel['channel_address'], + 'expanded' => true + ); + + $o = '
    '; + $o .= status_editor($a,$x); + $o .= '
    '; + + } + + // This page can be viewed by anybody so the query could be complicated + // First we'll see if there is a copy of the item which is owned by us - if we're logged in locally. + // If that fails (or we aren't logged in locally), + // query an item in which the observer (if logged in remotely) has cid or gid rights + // and if that fails, look for a copy of the post that has no privacy restrictions. + // If we find the post, but we don't find a copy that we're allowed to look at, this fact needs to be reported. + + // find a copy of the item somewhere + + $target_item = null; + + $r = q("select id, uid, mid, parent_mid, item_type, item_deleted from item where mid like '%s' limit 1", + dbesc($item_hash . '%') + ); + + if($r) { + $target_item = $r[0]; + } + + $r = null; + + if($target_item['item_type'] == ITEM_TYPE_WEBPAGE) { + $x = q("select * from channel where channel_id = %d limit 1", + intval($target_item['uid']) + ); + $y = q("select * from item_id where uid = %d and service = 'WEBPAGE' and iid = %d limit 1", + intval($target_item['uid']), + intval($target_item['id']) + ); + if($x && $y) { + goaway(z_root() . '/page/' . $x[0]['channel_address'] . '/' . $y[0]['sid']); + } + else { + notice( t('Page not found.') . EOL); + return ''; + } + } + + + $simple_update = (($update) ? " AND item_unseen = 1 " : ''); + + if($update && $_SESSION['loadtime']) + $simple_update .= " and item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' "; + if($load) + $simple_update = ''; + + + + if((! $update) && (! $load)) { + + + $o .= '
    ' . "\r\n"; + $o .= "\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'display', + '$uid' => '0', + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '99', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), + '$search' => '', + '$order' => '', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$dend' => '', + '$dbegin' => '', + '$verb' => '', + '$mid' => $item_hash + )); + + + } + + $observer_hash = get_observer_hash(); + $item_normal = item_normal(); + + $sql_extra = public_permissions_sql($observer_hash); + + if(($update && $load) || ($_COOKIE['jsAvailable'] != 1)) { + + $updateable = false; + + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($a->pager['itemspage']),intval($a->pager['start'])); + + if($load || ($_COOKIE['jsAvailable'] != 1)) { + $r = null; + + require_once('include/identity.php'); + $sys = get_sys_channel(); + $sysid = $sys['channel_id']; + + if(local_channel()) { + $r = q("SELECT * from item + WHERE uid = %d + and mid = '%s' + $item_normal + limit 1", + intval(local_channel()), + dbesc($target_item['parent_mid']) + ); + if($r) { + $updateable = true; + + } + + } + if($r === null) { + + // in case somebody turned off public access to sys channel content using permissions + // make that content unsearchable by ensuring the owner_xchan can't match + + if(! perm_is_allowed($sysid,$observer_hash,'view_stream')) + $sysid = 0; + + + $r = q("SELECT * from item + WHERE mid = '%s' + AND (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' + AND `item`.`deny_gid` = '' AND item_private = 0 ) + and owner_xchan in ( " . stream_perms_xchans(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) + OR uid = %d ) + $sql_extra ) + $item_normal + limit 1", + dbesc($target_item['parent_mid']), + intval($sysid) + ); + + } + } + else { + $r = array(); + } + } + + if($r) { + + $parents_str = ids_to_querystr($r,'id'); + if($parents_str) { + + $items = q("SELECT `item`.*, `item`.`id` AS `item_id` + FROM `item` + WHERE parent in ( %s ) $item_normal ", + dbesc($parents_str) + ); + + xchan_query($items); + $items = fetch_post_tags($items,true); + $items = conv_sort($items,'created'); + } + } else { + $items = array(); + } + + + if ($_COOKIE['jsAvailable'] == 1) { + $o .= conversation($a, $items, 'display', $update, 'client'); + } else { + $o .= conversation($a, $items, 'display', $update, 'traditional'); + if ($items[0]['title']) + $a->page['title'] = $items[0]['title'] . " - " . $a->page['title']; + + } + + if($updateable) { + $x = q("UPDATE item SET item_unseen = 0 where item_unseen = 1 AND uid = %d and parent = %d ", + intval(local_channel()), + intval($r[0]['parent']) + ); + } + + $o .= '
    '; + + return $o; + + +/* + elseif((! $update) && (! { + + $r = q("SELECT `id`, item_flags FROM `item` WHERE `id` = '%s' OR `mid` = '%s' LIMIT 1", + dbesc($item_hash), + dbesc($item_hash) + ); + if($r) { + if(intval($r[0]['item_deleted'])) { + notice( t('Item has been removed.') . EOL ); + } + else { + notice( t('Permission denied.') . EOL ); + } + } + else { + notice( t('Item not found.') . EOL ); + } + + } +*/ + return $o; +} + diff --git a/sources/mod/editblock.php b/sources/mod/editblock.php new file mode 100644 index 00000000..b4d954ef --- /dev/null +++ b/sources/mod/editblock.php @@ -0,0 +1,189 @@ + 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $a->is_sys = true; + } + } + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($a,$which); + +} + + + +function editblock_content(&$a) { + + if(! $a->profile) { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $which = argv(1); + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = $a->get_observer(); + + $channel = $a->get_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if(! $owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = (($uid && $uid == $owner) ? true : false); + + $o = ''; + + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! ($post_id && $owner)) { + notice( t('Item not found') . EOL); + return; + } + + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); + if($itm) { + $item_id = q("select * from item_id where service = 'BUILDBLOCK' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if($item_id) + $block_title = $item_id[0]['sid']; + } + else { + notice( t('Item not found') . EOL); + return; + } + + $plaintext = true; + + $mimeselect = ''; + $mimetype = $itm[0]['mimetype']; + + if($mimetype != 'text/bbcode') + $plaintext = true; + + if(get_config('system','page_mimetype')) + $mimeselect = ''; + else + $mimeselect = mimetype_select($itm[0]['uid'],$mimetype); + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to everybody'), + '$geotag' => '', + '$nickname' => $channel['channel_address'], + '$confirmdelete' => t('Delete block?') + )); + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + $rp = 'blocks/' . $channel['channel_address']; + + $editor = replace_macros($tpl,array( + '$return_path' => $rp, + '$action' => 'item', + '$webpage' => ITEM_TYPE_BLOCK, + '$share' => t('Edit'), + '$bold' => t('Bold'), + '$italic' => t('Italic'), + '$underline' => t('Underline'), + '$quote' => t('Quote'), + '$code' => t('Code'), + '$writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_storage'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$mimeselect' => $mimeselect, + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $channel['channel_location'], + '$visitor' => false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Title (optional)'), + '$pagetitle' => $block_title, + '$category' => '', + '$placeholdercategory' => t('Categories (optional, comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', + '$bang' => '', + '$profile_uid' => (intval($channel['channel_id'])), + '$preview' => t('Preview'), + '$jotplugins' => $jotplugins, + '$sourceapp' => $itm[0]['app'], + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + )); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Block'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$id' => $itm[0]['id'], + '$editor' => $editor + )); + + return $o; + +} + + diff --git a/sources/mod/editlayout.php b/sources/mod/editlayout.php new file mode 100644 index 00000000..6ea7f410 --- /dev/null +++ b/sources/mod/editlayout.php @@ -0,0 +1,187 @@ + 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $a->is_sys = true; + } + } + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($a,$which); + +} + +function editlayout_content(&$a) { + + if(! $a->profile) { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $which = argv(1); + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = $a->get_observer(); + + $channel = $a->get_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if(! $owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = (($uid && $uid == $owner) ? true : false); + + $o = ''; + + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + + // Now we've got a post and an owner, let's find out if we're allowed to edit it + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s LIMIT 1", + intval($post_id), + intval($owner) + ); + + $item_id = q("select * from item_id where service = 'PDL' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if($item_id) + $layout_title = $item_id[0]['sid']; + + $plaintext = true; + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to everybody'), + '$geotag' => $geotag, + '$nickname' => $channel['channel_address'], + '$confirmdelete' => t('Delete layout?') + )); + + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + + // FIXME A return path with $_SESSION doesn't always work for observer - it may WSoD + // instead of loading a sensible page. So, send folk to the webpage list. + + $rp = 'layouts/' . $which; + + $editor = replace_macros($tpl,array( + '$return_path' => $rp, + '$action' => 'item', + '$webpage' => ITEM_TYPE_PDL, + '$share' => t('Edit'), + '$bold' => t('Bold'), + '$italic' => t('Italic'), + '$underline' => t('Underline'), + '$quote' => t('Quote'), + '$code' => t('Code'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $channel['channel_location'], + '$visitor' => false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Layout Description (Optional)'), + '$pagetitle' => $layout_title, + '$placeholdpagetitle' => t('Layout Name'), + '$category' => '', + '$placeholdercategory' => t('Categories (optional, comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', + '$bang' => '', + '$profile_uid' => (intval($owner)), + '$jotplugins' => $jotplugins, + '$sourceapp' => t($a->sourcename), + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + )); + + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Layout'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$id' => $itm[0]['id'], + '$editor' => $editor + )); + + return $o; + +} + + diff --git a/sources/mod/editpost.php b/sources/mod/editpost.php new file mode 100644 index 00000000..daca7c15 --- /dev/null +++ b/sources/mod/editpost.php @@ -0,0 +1,172 @@ + 1) ? intval(argv(1)) : 0); + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + + $itm = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d and author_xchan = '%s' LIMIT 1", + intval($post_id), + intval(local_channel()), + dbesc(get_observer_hash()) + ); + + if(! count($itm)) { + notice( t('Item is not editable') . EOL); + return; + } + + if($itm[0]['resource_type'] === 'event' && $itm[0]['resource_id']) { + goaway(z_root() . '/events/event/' . $itm[0]['resource_id']); + } + + + + $plaintext = true; +// if(feature_enabled(local_channel(),'richtext')) +// $plaintext = false; + + $channel = $a->get_channel(); + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to everybody'), + '$geotag' => $geotag, + '$nickname' => $channel['channel_address'], + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM'), + '$confirmdelete' => t('Delete item?'), + )); + + if(intval($itm[0]['item_obscured'])) { + $key = get_config('system','prvkey'); + if($itm[0]['title']) + $itm[0]['title'] = crypto_unencapsulate(json_decode_plus($itm[0]['title']),$key); + if($itm[0]['body']) + $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key); + } + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + $channel = $a->get_channel(); + + //$tpl = replace_macros($tpl,array('$jotplugins' => $jotplugins)); + + $voting = feature_enabled(local_channel(),'consensus_tools'); + + $category = ''; + $catsenabled = ((feature_enabled(local_channel(),'categories')) ? 'categories' : ''); + + if ($catsenabled){ + $itm = fetch_post_tags($itm); + + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); + + foreach ($cats as $cat) { + if (strlen($category)) + $category .= ', '; + $category .= $cat['term']; + } + + } + + if($itm[0]['attach']) { + $j = json_decode($itm[0]['attach'],true); + if($j) { + foreach($j as $jj) { + $itm[0]['body'] .= "\n" . '[attachment]' . basename($jj['href']) . ',' . $jj['revision'] . '[/attachment]' . "\n"; + } + } + } + + $cipher = get_pconfig(get_app()->profile['profile_uid'],'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + + $editor = replace_macros($tpl,array( + '$return_path' => $_SESSION['return_url'], + '$action' => 'item', + '$share' => t('Edit'), + '$bold' => t('Bold'), + '$italic' => t('Italic'), + '$underline' => t('Underline'), + '$quote' => t('Quote'), + '$code' => t('Code'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => t('Clear browser location'), + '$voting' => t('Toggle voting'), + '$feature_voting' => $voting, + '$consensus' => intval($itm[0]['item_consensus']), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$parent' => (($itm[0]['parent'] != $itm[0]['id']) ? $itm[0]['parent'] : ''), + '$baseurl' => $a->get_baseurl(), + '$defloc' => $channel['channel_location'], + '$visitor' => false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Title (optional)'), + '$category' => $category, + '$placeholdercategory' => t('Categories (optional, comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + '$lockstate' => $lockstate, + '$acl' => '', + '$bang' => '', + '$profile_uid' => local_channel(), + '$preview' => t('Preview'), + '$jotplugins' => $jotplugins, + '$sourceapp' => t($a->sourcename), + '$catsenabled' => $catsenabled, + '$defexpire' => datetime_convert('UTC', date_default_timezone_get(),$itm[0]['expires']), + '$feature_expire' => ((feature_enabled(get_app()->profile['profile_uid'],'content_expire') && (! $webpage)) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(get_app()->profile['profile_uid'],'content_encrypt') && (! $webpage)) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + '$expiryModalOK' => t('OK'), + '$expiryModalCANCEL' => t('Cancel'), + )); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit post'), + '$editor' => $editor + )); + + return $o; + +} + + diff --git a/sources/mod/editwebpage.php b/sources/mod/editwebpage.php new file mode 100644 index 00000000..974e8cc3 --- /dev/null +++ b/sources/mod/editwebpage.php @@ -0,0 +1,231 @@ + 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $a->is_sys = true; + } + } + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($a,$which); + +} + + +function editwebpage_content(&$a) { + + if(! $a->profile) { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $which = argv(1); + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = $a->get_observer(); + + $channel = $a->get_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if(! $owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner,$ob_hash,'write_pages')) { + notice( t('Permission denied.') . EOL); + return; + } + + $is_owner = (($uid && $uid == $owner) ? true : false); + + $o = ''; + + // Figure out which post we're editing + $post_id = ((argc() > 2) ? intval(argv(2)) : 0); + + + if(! $post_id) { + notice( t('Item not found') . EOL); + return; + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + // We've already figured out which item we want and whose copy we need, + // so we don't need anything fancy here + + $sql_extra = item_permissions_sql($owner); + + $itm = q("SELECT * FROM `item` WHERE `id` = %d and uid = %s $sql_extra LIMIT 1", + intval($post_id), + intval($owner) + ); + + if(! $itm) { + notice( t('Permission denied.') . EOL); + return; + } + + if(intval($itm[0]['item_obscured'])) { + $key = get_config('system','prvkey'); + if($itm[0]['title']) + $itm[0]['title'] = crypto_unencapsulate(json_decode_plus($itm[0]['title']),$key); + if($itm[0]['body']) + $itm[0]['body'] = crypto_unencapsulate(json_decode_plus($itm[0]['body']),$key); + } + + $item_id = q("select * from item_id where service = 'WEBPAGE' and iid = %d limit 1", + intval($itm[0]['id']) + ); + if($item_id) + $page_title = $item_id[0]['sid']; + + $plaintext = true; + + $mimetype = $itm[0]['mimetype']; + + if($mimetype === 'application/x-php') { + if((! $uid) || ($uid != $itm[0]['uid'])) { + notice( t('Permission denied.') . EOL); + return; + } + } + + $mimeselect = ''; + + if($mimetype != 'text/bbcode') + $plaintext = true; + + if(get_config('system','page_mimetype')) + $mimeselect = ''; + else + $mimeselect = mimetype_select($itm[0]['uid'],$mimetype); + + $layout = get_config('system','page_layout'); + if($layout) + $layoutselect = ''; + else + $layoutselect = layout_select($itm[0]['uid'],$itm[0]['layout_mid']); + + $a->page['htmlhead'] .= replace_macros(get_markup_template('jot-header.tpl'), array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$ispublic' => ' ', // t('Visible to everybody'), + '$geotag' => $geotag, + '$nickname' => $channel['channel_address'], + '$confirmdelete' => t('Delete webpage?') + )); + + $tpl = get_markup_template("jot.tpl"); + + $jotplugins = ''; + $jotnets = ''; + + call_hooks('jot_tool', $jotplugins); + call_hooks('jot_networks', $jotnets); + + // FIXME A return path with $_SESSION doesn't always work for observer - it may WSoD + // instead of loading a sensible page. So, send folk to the webpage list. + + $rp = 'webpages/' . $which; + + $editor = replace_macros($tpl,array( + '$return_path' => $rp, + '$webpage' => ITEM_TYPE_WEBPAGE, + '$placeholdpagetitle' => t('Page link title'), + '$pagetitle' => $page_title, + '$writefiles' => perm_is_allowed($owner, get_observer_hash(), 'write_storage'), + '$action' => 'item', + '$share' => t('Edit'), + '$bold' => t('Bold'), + '$italic' => t('Italic'), + '$underline' => t('Underline'), + '$quote' => t('Quote'), + '$code' => t('Code'), + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$weblink' => t('Insert web link'), + '$youtube' => t('Insert YouTube video'), + '$video' => t('Insert Vorbis [.ogg] video'), + '$audio' => t('Insert Vorbis [.ogg] audio'), + '$setloc' => t('Set your location'), + '$noloc' => ((get_pconfig($uid, 'system', 'use_browser_location')) ? t('Clear browser location') : ''), + '$wait' => t('Please wait'), + '$permset' => t('Permission settings'), + '$ptyp' => $itm[0]['type'], + '$content' => undo_post_tagging($itm[0]['body']), + '$post_id' => $post_id, + '$baseurl' => $a->get_baseurl(), + '$defloc' => $itm[0]['location'], + '$visitor' => ($is_owner) ? true : false, + '$acl' => populate_acl($itm[0],false), + '$showacl' => ($is_owner) ? true : false, + '$public' => t('Public post'), + '$jotnets' => $jotnets, + '$mimeselect' => $mimeselect, + '$layoutselect' => $layoutselect, + '$title' => htmlspecialchars($itm[0]['title'],ENT_COMPAT,'UTF-8'), + '$placeholdertitle' => t('Title (optional)'), + '$category' => '', + '$placeholdercategory' => t('Categories (optional, comma-separated list)'), + '$emtitle' => t('Example: bob@example.com, mary@example.com'), + 'lockstate' => (((strlen($itm[0]['allow_cid'])) || (strlen($itm[0]['allow_gid'])) || (strlen($itm[0]['deny_cid'])) || (strlen($itm[0]['deny_gid']))) ? 'lock' : 'unlock'), + '$bang' => '', + '$profile_uid' => (intval($owner)), + '$preview' => t('Preview'), + '$jotplugins' => $jotplugins, + '$sourceapp' => $a->sourcename, + '$defexpire' => '', + '$feature_expire' => false, + '$expires' => t('Set expiration date'), + + )); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit Webpage'), + '$delete' => ((($itm[0]['author_xchan'] === $ob_hash) || ($itm[0]['owner_xchan'] === $ob_hash)) ? t('Delete') : false), + '$editor' => $editor, + '$id' => $itm[0]['id'] + )); + + return $o; + +} + + diff --git a/sources/mod/events.php b/sources/mod/events.php new file mode 100755 index 00000000..15fed9df --- /dev/null +++ b/sources/mod/events.php @@ -0,0 +1,710 @@ +get_baseurl() . "/events/" . $action . "?summary=$summary&description=$desc&location=$location&start=$start_text&finish=$finish_text&adjust=$adjust&nofinish=$nofinish&type=$type"; + if(strcmp($finish,$start) < 0 && !$nofinish) { + notice( t('Event can not end before it has started.') . EOL); + if(intval($_REQUEST['preview'])) { + echo( t('Unable to generate preview.')); + killme(); + } + goaway($onerror_url); + } + + if((! $summary) || (! $start)) { + notice( t('Event title and start time are required.') . EOL); + if(intval($_REQUEST['preview'])) { + echo( t('Unable to generate preview.')); + killme(); + } + goaway($onerror_url); + } + + $share = ((intval($_POST['share'])) ? intval($_POST['share']) : 0); + + $channel = $a->get_channel(); + + if($event_id) { + $x = q("select * from event where id = %d and uid = %d limit 1", + intval($event_id), + intval(local_channel()) + ); + if(! $x) { + notice( t('Event not found.') . EOL); + if(intval($_REQUEST['preview'])) { + echo( t('Unable to generate preview.')); + killme(); + } + return; + } + if($x[0]['allow_cid'] === '<' . $channel['channel_hash'] . '>' + && $x[0]['allow_gid'] === '' && $x[0]['deny_cid'] === '' && $x[0]['deny_gid'] === '') { + $share = false; + } + else { + $share = true; + $str_group_allow = $x[0]['allow_gid']; + $str_contact_allow = $x[0]['allow_cid']; + $str_group_deny = $x[0]['deny_gid']; + $str_contact_deny = $x[0]['deny_cid']; + + if(strlen($str_group_allow) || strlen($str_contact_allow) + || strlen($str_group_deny) || strlen($str_contact_deny)) { + $private_event = true; + } + } + } + else { + if($share) { + $str_group_allow = perms2str($_POST['group_allow']); + $str_contact_allow = perms2str($_POST['contact_allow']); + $str_group_deny = perms2str($_POST['group_deny']); + $str_contact_deny = perms2str($_POST['contact_deny']); + + if(strlen($str_group_allow) || strlen($str_contact_allow) + || strlen($str_group_deny) || strlen($str_contact_deny)) { + $private_event = true; + } + } + else { + $str_contact_allow = '<' . $channel['channel_hash'] . '>'; + $str_group_allow = $str_contact_deny = $str_group_deny = ''; + $private_event = true; + } + } + + $post_tags = array(); + $channel = $a->get_channel(); + + if(strlen($categories)) { + $cats = explode(',',$categories); + foreach($cats as $cat) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($cat), + 'url' => $channel['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) + ); + } + } + + $datarray = array(); + $datarray['start'] = $start; + $datarray['finish'] = $finish; + $datarray['summary'] = $summary; + $datarray['description'] = $desc; + $datarray['location'] = $location; + $datarray['type'] = $type; + $datarray['adjust'] = $adjust; + $datarray['nofinish'] = $nofinish; + $datarray['uid'] = local_channel(); + $datarray['account'] = get_account_id(); + $datarray['event_xchan'] = $channel['channel_hash']; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['private'] = (($private_event) ? 1 : 0); + $datarray['id'] = $event_id; + $datarray['created'] = $created; + $datarray['edited'] = $edited; + + if(intval($_REQUEST['preview'])) { + $html = format_event_html($datarray); + echo $html; + killme(); + } + + $event = event_store_event($datarray); + + + if($post_tags) + $datarray['term'] = $post_tags; + + $item_id = event_store_item($datarray,$event); + + if($share) + proc_run('php',"include/notifier.php","event","$item_id"); + +} + + + +function events_content(&$a) { + + if(argc() > 2 && argv(1) == 'ical') { + $event_id = argv(2); + + require_once('include/security.php'); + $sql_extra = permissions_sql(local_channel()); + + $r = q("select * from event where event_hash = '%s' $sql_extra limit 1", + dbesc($event_id) + ); + if($r) { + header('Content-type: text/calendar'); + header('content-disposition: attachment; filename="' . t('event') . '-' . $event_id . '.ics"' ); + echo ical_wrapper($r); + killme(); + } + else { + notice( t('Event not found.') . EOL ); + return; + } + } + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + nav_set_selected('all_events'); + + if((argc() > 2) && (argv(1) === 'ignore') && intval(argv(2))) { + $r = q("update event set ignore = 1 where id = %d and uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + } + + if((argc() > 2) && (argv(1) === 'unignore') && intval(argv(2))) { + $r = q("update event set ignore = 0 where id = %d and uid = %d", + intval(argv(2)), + intval(local_channel()) + ); + } + + + $plaintext = true; + +// if(feature_enabled(local_channel(),'richtext')) +// $plaintext = false; + + + + $htpl = get_markup_template('event_head.tpl'); + $a->page['htmlhead'] .= replace_macros($htpl,array( + '$baseurl' => $a->get_baseurl(), + '$editselect' => (($plaintext) ? 'none' : 'textareas') + )); + + $o =""; + // tabs + + $channel = $a->get_channel(); + + $tabs = profile_tabs($a, True, $channel['channel_address']); + + + + $mode = 'view'; + $y = 0; + $m = 0; + $ignored = ((x($_REQUEST,'ignored')) ? " and ignored = " . intval($_REQUEST['ignored']) . " " : ''); + + if(argc() > 1) { + if(argc() > 2 && argv(1) == 'event') { + $mode = 'edit'; + $event_id = argv(2); + } + if(argc() > 2 && argv(1) === 'add') { + $mode = 'add'; + $item_id = intval(argv(2)); + } + if(argc() > 2 && argv(1) === 'drop') { + $mode = 'drop'; + $event_id = argv(2); + } + if(argv(1) === 'new') { + $mode = 'new'; + $event_id = ''; + } + if(argc() > 2 && intval(argv(1)) && intval(argv(2))) { + $mode = 'view'; + $y = intval(argv(1)); + $m = intval(argv(2)); + } + } + + if($mode === 'add') { + event_addtocal($item_id,local_channel()); + killme(); + } + + + + + + if($mode == 'view') { + + + $thisyear = datetime_convert('UTC',date_default_timezone_get(),'now','Y'); + $thismonth = datetime_convert('UTC',date_default_timezone_get(),'now','m'); + if(! $y) + $y = intval($thisyear); + if(! $m) + $m = intval($thismonth); + + $export = false; + if(argc() === 4 && argv(3) === 'export') + $export = true; + + + // Put some limits on dates. The PHP date functions don't seem to do so well before 1900. + // An upper limit was chosen to keep search engines from exploring links millions of years in the future. + + if($y < 1901) + $y = 1900; + if($y > 2099) + $y = 2100; + + $nextyear = $y; + $nextmonth = $m + 1; + if($nextmonth > 12) { + $nextmonth = 1; + $nextyear ++; + } + + $prevyear = $y; + if($m > 1) + $prevmonth = $m - 1; + else { + $prevmonth = 12; + $prevyear --; + } + + $dim = get_dim($y,$m); + $start = sprintf('%d-%d-%d %d:%d:%d',$y,$m,1,0,0,0); + $finish = sprintf('%d-%d-%d %d:%d:%d',$y,$m,$dim,23,59,59); + + + if (argv(1) === 'json'){ + if (x($_GET,'start')) $start = date("Y-m-d h:i:s", $_GET['start']); + if (x($_GET,'end')) $finish = date("Y-m-d h:i:s", $_GET['end']); + } + + $start = datetime_convert('UTC','UTC',$start); + $finish = datetime_convert('UTC','UTC',$finish); + + $adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start); + $adjust_finish = datetime_convert('UTC', date_default_timezone_get(), $finish); + + if (x($_GET,'id')){ + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + from event left join item on resource_id = event_hash where resource_type = 'event' and event.uid = %d and event.id = %d limit 1", + intval(local_channel()), + intval($_GET['id']) + ); + } elseif($export) { + $r = q("SELECT * from event where uid = %d + AND (( `adjust` = 0 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' ) + OR ( `adjust` = 1 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' )) ", + intval(local_channel()), + dbesc($start), + dbesc($finish), + dbesc($adjust_start), + dbesc($adjust_finish) + ); + } + else { + // fixed an issue with "nofinish" events not showing up in the calendar. + // There's still an issue if the finish date crosses the end of month. + // Noting this for now - it will need to be fixed here and in Friendica. + // Ultimately the finish date shouldn't be involved in the query. + + $r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan + from event left join item on event_hash = resource_id + where resource_type = 'event' and event.uid = %d $ignored + AND (( `adjust` = 0 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' ) + OR ( `adjust` = 1 AND ( `finish` >= '%s' or nofinish = 1 ) AND `start` <= '%s' )) ", + intval(local_channel()), + dbesc($start), + dbesc($finish), + dbesc($adjust_start), + dbesc($adjust_finish) + ); + } + + + $links = array(); + + if($r && ! $export) { + xchan_query($r); + $r = fetch_post_tags($r,true); + + $r = sort_by_date($r); + } + + if($r) { + foreach($r as $rr) { + $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j')); + if(! x($links,$j)) + $links[$j] = $a->get_baseurl() . '/' . $a->cmd . '#link-' . $j; + } + } + + $events=array(); + + $last_date = ''; + $fmt = t('l, F j'); + + if($r) { + + foreach($r as $rr) { + + $j = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'j') : datetime_convert('UTC','UTC',$rr['start'],'j')); + $d = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], $fmt) : datetime_convert('UTC','UTC',$rr['start'],$fmt)); + $d = day_translate($d); + + $start = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['start'], 'c') : datetime_convert('UTC','UTC',$rr['start'],'c')); + if ($rr['nofinish']){ + $end = null; + } else { + $end = (($rr['adjust']) ? datetime_convert('UTC',date_default_timezone_get(),$rr['finish'], 'c') : datetime_convert('UTC','UTC',$rr['finish'],'c')); + } + + + $is_first = ($d !== $last_date); + + $last_date = $d; + + $edit = (intval($rr['item_wall']) ? array($a->get_baseurl().'/events/event/'.$rr['event_hash'],t('Edit event'),'','') : null); + + $drop = array($a->get_baseurl().'/events/drop/'.$rr['event_hash'],t('Delete event'),'',''); + + $title = strip_tags(html_entity_decode(bbcode($rr['summary']),ENT_QUOTES,'UTF-8')); + if(! $title) { + list($title, $_trash) = explode("$rr['id'], + 'hash' => $rr['event_hash'], + 'start'=> $start, + 'end' => $end, + 'drop' => $drop, + 'allDay' => false, + 'title' => $title, + + 'j' => $j, + 'd' => $d, + 'edit' => $edit, + 'is_first'=>$is_first, + 'item'=>$rr, + 'html'=>$html, + 'plink' => array($rr['plink'],t('Link to Source'),'',''), + ); + + + } + } + + if($export) { + header('Content-type: text/calendar'); + header('content-disposition: attachment; filename="' . t('calendar') . '-' . $channel['channel_address'] . '.ics"' ); + echo ical_wrapper($r); + killme(); + } + + if ($a->argv[1] === 'json'){ + echo json_encode($events); killme(); + } + + // links: array('href', 'text', 'extra css classes', 'title') + if (x($_GET,'id')){ + $tpl = get_markup_template("event.tpl"); + } + else { + $tpl = get_markup_template("events-js.tpl"); + } + + $o = replace_macros($tpl, array( + '$baseurl' => $a->get_baseurl(), + '$tabs' => $tabs, + '$title' => t('Events'), + '$new_event'=> array($a->get_baseurl().'/events/new',t('Create New Event'),'',''), + '$previus' => array($a->get_baseurl()."/events/$prevyear/$prevmonth",t('Previous'),'',''), + '$next' => array($a->get_baseurl()."/events/$nextyear/$nextmonth",t('Next'),'',''), + '$export' => array($a->get_baseurl()."/events/$y/$m/export",t('Export'),'',''), + '$calendar' => cal($y,$m,$links, ' eventcal'), + '$events' => $events, + '$upload' => t('Import'), + '$submit' => t('Submit') + )); + + if (x($_GET,'id')){ echo $o; killme(); } + + return $o; + + } + + if($mode === 'drop' && $event_id) { + $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", + dbesc($event_id), + intval(local_channel()) + ); + if($r) { + $r = q("delete from event where event_hash = '%s' and uid = %d limit 1", + dbesc($event_id), + intval(local_channel()) + ); + if($r) { + $r = q("update item set resource_type = '', resource_id = '' where resource_type = 'event' and resource_id = '%s' and uid = %d", + dbesc($event_id), + intval(local_channel()) + ); + info( t('Event removed') . EOL); + } + else { + notice( t('Failed to remove event' ) . EOL); + } + goaway(z_root() . '/events'); + } + } + + if($mode === 'edit' && $event_id) { + $r = q("SELECT * FROM `event` WHERE event_hash = '%s' AND `uid` = %d LIMIT 1", + dbesc($event_id), + intval(local_channel()) + ); + if(count($r)) + $orig_event = $r[0]; + } + + $channel = $a->get_channel(); + + // Passed parameters overrides anything found in the DB + if($mode === 'edit' || $mode === 'new') { + if(!x($orig_event)) $orig_event = array(); + // In case of an error the browser is redirected back here, with these parameters filled in with the previous values + if(x($_REQUEST,'nofinish')) $orig_event['nofinish'] = $_REQUEST['nofinish']; + if(x($_REQUEST,'adjust')) $orig_event['adjust'] = $_REQUEST['adjust']; + if(x($_REQUEST,'summary')) $orig_event['summary'] = $_REQUEST['summary']; + if(x($_REQUEST,'description')) $orig_event['description'] = $_REQUEST['description']; + if(x($_REQUEST,'location')) $orig_event['location'] = $_REQUEST['location']; + if(x($_REQUEST,'start')) $orig_event['start'] = $_REQUEST['start']; + if(x($_REQUEST,'finish')) $orig_event['finish'] = $_REQUEST['finish']; + if(x($_REQUEST,'type')) $orig_event['type'] = $_REQUEST['type']; + + $n_checked = ((x($orig_event) && $orig_event['nofinish']) ? ' checked="checked" ' : ''); + $a_checked = ((x($orig_event) && $orig_event['adjust']) ? ' checked="checked" ' : ''); + $t_orig = ((x($orig_event)) ? $orig_event['summary'] : ''); + $d_orig = ((x($orig_event)) ? $orig_event['description'] : ''); + $l_orig = ((x($orig_event)) ? $orig_event['location'] : ''); + $eid = ((x($orig_event)) ? $orig_event['id'] : 0); + $event_xchan = ((x($orig_event)) ? $orig_event['event_xchan'] : $channel['channel_hash']); + $mid = ((x($orig_event)) ? $orig_event['mid'] : ''); + + if(! x($orig_event)) + $sh_checked = ''; + else + $sh_checked = ((($orig_event['allow_cid'] === '<' . $channel['channel_hash'] . '>' || (! $orig_event['allow_cid'])) && (! $orig_event['allow_gid']) && (! $orig_event['deny_cid']) && (! $orig_event['deny_gid'])) ? '' : ' checked="checked" ' ); + + if($orig_event['event_xchan']) + $sh_checked .= ' disabled="disabled" '; + + $sdt = ((x($orig_event)) ? $orig_event['start'] : 'now'); + $fdt = ((x($orig_event)) ? $orig_event['finish'] : 'now'); + + $tz = date_default_timezone_get(); + if(x($orig_event)) + $tz = (($orig_event['adjust']) ? date_default_timezone_get() : 'UTC'); + + $syear = datetime_convert('UTC', $tz, $sdt, 'Y'); + $smonth = datetime_convert('UTC', $tz, $sdt, 'm'); + $sday = datetime_convert('UTC', $tz, $sdt, 'd'); + + + $shour = ((x($orig_event)) ? datetime_convert('UTC', $tz, $sdt, 'H') : 0); + $sminute = ((x($orig_event)) ? datetime_convert('UTC', $tz, $sdt, 'i') : 0); + $stext = datetime_convert('UTC',$tz,$sdt); + $stext = substr($stext,0,14) . "00:00"; + + $fyear = datetime_convert('UTC', $tz, $fdt, 'Y'); + $fmonth = datetime_convert('UTC', $tz, $fdt, 'm'); + $fday = datetime_convert('UTC', $tz, $fdt, 'd'); + + $fhour = ((x($orig_event)) ? datetime_convert('UTC', $tz, $fdt, 'H') : 0); + $fminute = ((x($orig_event)) ? datetime_convert('UTC', $tz, $fdt, 'i') : 0); + $ftext = datetime_convert('UTC',$tz,$fdt); + $ftext = substr($ftext,0,14) . "00:00"; + $type = ((x($orig_event)) ? $orig_event['type'] : 'event'); + + $f = get_config('system','event_input_format'); + if(! $f) + $f = 'ymd'; + + $catsenabled = feature_enabled(local_channel(),'categories'); + + $category = ''; + + if($catsenabled && x($orig_event)){ + $itm = q("select * from item where resource_type = 'event' and resource_id = '%s' and uid = %d limit 1", + dbesc($orig_event['event_hash']), + intval(local_channel()) + ); + $itm = fetch_post_tags($itm); + if($itm) { + $cats = get_terms_oftype($itm[0]['term'], TERM_CATEGORY); + foreach ($cats as $cat) { + if(strlen($category)) + $category .= ', '; + $category .= $cat['term']; + } + } + } + + require_once('include/acl_selectors.php'); + + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $tpl = get_markup_template('event_form.tpl'); + + $o .= replace_macros($tpl,array( + '$post' => $a->get_baseurl() . '/events', + '$eid' => $eid, + '$type' => $type, + '$xchan' => $event_xchan, + '$mid' => $mid, + '$event_hash' => $event_id, + + '$title' => t('Event details'), + '$desc' => t('Starting date and Title are required.'), + '$catsenabled' => $catsenabled, + '$placeholdercategory' => t('Categories (comma-separated list)'), + '$category' => $category, + '$s_text' => t('Event Starts:'), + '$stext' => $stext, + '$ftext' => $ftext, + '$required' => '*', + '$ModalCANCEL' => t('Cancel'), + '$ModalOK' => t('OK'), + '$s_dsel' => datetimesel($f,new DateTime(),DateTime::createFromFormat('Y',$syear+5),DateTime::createFromFormat('Y-m-d H:i',"$syear-$smonth-$sday $shour:$sminute"),'start_text',true,true,'','',true), + '$n_text' => t('Finish date/time is not known or not relevant'), + '$n_checked' => $n_checked, + '$f_text' => t('Event Finishes:'), + '$f_dsel' => datetimesel($f,new DateTime(),DateTime::createFromFormat('Y',$fyear+5),DateTime::createFromFormat('Y-m-d H:i',"$fyear-$fmonth-$fday $fhour:$fminute"),'finish_text',true,true,'start_text'), + '$adjust' => array('adjust', t('Adjust for viewer timezone'), $a_checked, t('Important for events that happen in a particular place. Not practical for global holidays.'),), + '$a_text' => t('Adjust for viewer timezone'), + '$d_text' => t('Description:'), + '$d_orig' => $d_orig, + '$l_text' => t('Location:'), + '$l_orig' => $l_orig, + '$t_text' => t('Title:'), + '$t_orig' => $t_orig, + '$sh_text' => t('Share this event'), + '$sh_checked' => $sh_checked, + '$preview' => t('Preview'), + '$permissions' => t('Permissions'), + '$acl' => (($orig_event['event_xchan']) ? '' : populate_acl(((x($orig_event)) ? $orig_event : $perm_defaults),false)), + '$submit' => t('Submit') + + )); + + return $o; + } +} diff --git a/sources/mod/fbrowser.php b/sources/mod/fbrowser.php new file mode 100644 index 00000000..90b554ed --- /dev/null +++ b/sources/mod/fbrowser.php @@ -0,0 +1,128 @@ + + */ + +require_once('include/photo/photo_driver.php'); + +/** + * @param App $a + */ +function fbrowser_content($a){ + + if (!local_channel()) + killme(); + + if ($a->argc==1) + killme(); + + //echo "
    "; var_dump($a->argv); killme();	
    +	
    +	switch($a->argv[1]){
    +		case "image":
    +			$path = array( array($a->get_baseurl()."/fbrowser/image/", t("Photos")));
    +			$albums = false;
    +			$sql_extra = "";
    +			$sql_extra2 = " ORDER BY created DESC LIMIT 0, 10";
    +			
    +			if ($a->argc==2){
    +				$albums = q("SELECT distinct(`album`) AS `album` FROM `photo` WHERE `uid` = %d ",
    +					intval(local_channel())
    +				);
    +				// anon functions only from 5.3.0... meglio tardi che mai..
    +				function folder1($el){return array(bin2hex($el['album']),$el['album']);}	
    +				$albums = array_map( "folder1" , $albums);
    +				
    +			}
    +			
    +			$album = "";
    +			if ($a->argc==3){
    +				$album = hex2bin($a->argv[2]);
    +				$sql_extra = sprintf("AND `album` = '%s' ",dbesc($album));
    +				$sql_extra2 = "";
    +				$path[]=array($a->get_baseurl()."/fbrowser/image/".$a->argv[2]."/", $album);
    +			}
    +				
    +			$r = q("SELECT `resource_id`, `id`, `filename`, type, min(`scale`) AS `hiq`,max(`scale`) AS `loq`, `description`  
    +					FROM `photo` WHERE `uid` = %d $sql_extra
    +					GROUP BY `resource_id` $sql_extra2",
    +				intval(local_channel())					
    +			);
    +			
    +			function files1($rr){ 
    +				global $a;
    +				$ph = photo_factory('');
    +				$types = $ph->supportedTypes();
    +				$ext = $types[$rr['type']];
    +
    +				if($a->get_template_engine() === 'internal') {
    +					$filename_e = template_escape($rr['filename']);
    +				}
    +				else {
    +					$filename_e = $rr['filename'];
    +				}
    +
    +				return array( 
    +					$a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['hiq'] . '.' .$ext, 
    +					$filename_e, 
    +					$a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['loq'] . '.'. $ext
    +				);
    +			}
    +			$files = array_map("files1", $r);
    +			
    +			$tpl = get_markup_template("filebrowser.tpl");
    +			echo replace_macros($tpl, array(
    +				'$type' => 'image',
    +				'$baseurl' => $a->get_baseurl(),
    +				'$path' => $path,
    +				'$folders' => $albums,
    +				'$files' =>$files,
    +				'$cancel' => t('Cancel'),
    +			));
    +				
    +				
    +			break;
    +		case "file":
    +			if ($a->argc==2){
    +				$files = q("SELECT id, filename, filetype FROM `attach` WHERE `uid` = %d ",
    +					intval(local_channel())
    +				);
    +				
    +				function files2($rr){ global $a; 
    +					list($m1,$m2) = explode("/",$rr['filetype']);
    +					$filetype = ( (file_exists("images/icons/$m1.png"))?$m1:"zip");
    +
    +					if($a->get_template_engine() === 'internal') {
    +						$filename_e = template_escape($rr['filename']);
    +					}
    +					else {
    +						$filename_e = $rr['filename'];
    +					}
    +
    +					return array( $a->get_baseurl() . '/attach/' . $rr['id'], $filename_e, $a->get_baseurl() . '/images/icons/16/' . $filetype . '.png'); 
    +				}
    +				$files = array_map("files2", $files);
    +				//echo "
    "; var_dump($files); killme();
    +			
    +							
    +				$tpl = get_markup_template("filebrowser.tpl");
    +				echo replace_macros($tpl, array(
    +					'$type' => 'file',
    +					'$baseurl' => $a->get_baseurl(),
    +					'$path' => array( array($a->get_baseurl()."/fbrowser/image/", t("Files")) ),
    +					'$folders' => false,
    +					'$files' =>$files,
    +					'$cancel' => t('Cancel'),
    +				));
    +				
    +			}
    +		
    +			break;
    +	}
    +	
    +
    +	killme();
    +	
    +}
    diff --git a/sources/mod/feed.php b/sources/mod/feed.php
    new file mode 100644
    index 00000000..3b622fc1
    --- /dev/null
    +++ b/sources/mod/feed.php
    @@ -0,0 +1,39 @@
    + 1) {
    +		$r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1",
    +			dbesc(argv(1))
    +		);
    +		if(!($r && count($r)))
    +			killme();
    +
    +		$channel = $r[0];
    +
    +		if((intval(get_config('system','block_public'))) && (! get_account_id()))
    +			killme();
    + 
    +		logger('mod_feed: public feed request from ' . $_SERVER['REMOTE_ADDR'] . ' for ' . $channel['channel_address']);
    +		echo get_public_feed($channel,$params);
    +		killme();
    +	}
    +
    +}
    +
    +
    diff --git a/sources/mod/filer.php b/sources/mod/filer.php
    new file mode 100644
    index 00000000..8d69503b
    --- /dev/null
    +++ b/sources/mod/filer.php
    @@ -0,0 +1,55 @@
    +argc > 1) ? intval($a->argv[1]) : 0);
    +
    +	logger('filer: tag ' . $term . ' item ' . $item_id);
    +
    +	if($item_id && strlen($term)){
    +		// file item
    +		store_item_tag(local_channel(),$item_id,TERM_OBJ_POST,TERM_FILE,$term,'');
    +
    +		// protect the entire conversation from periodic expiration
    +
    +		$r = q("select parent from item where id = %d and uid = %d limit 1",
    +			intval($item_id),
    +			intval(local_channel())
    +		);
    +		if($r) {
    +			$x = q("update item set item_retained = 1 where id = %d and uid = %d",
    +				intval($r[0]['parent']),
    +				intval(local_channel())
    +			);
    +		}
    +	} 
    +	else {
    +		$filetags = array();
    +		$r = q("select distinct(term) from term where uid = %d and type = %d order by term asc",
    +			intval(local_channel()),
    +			intval(TERM_FILE)
    +		);
    +		if(count($r)) {
    +			foreach($r as $rr)
    +				$filetags[] = $rr['term'];
    +		}
    +		$tpl = get_markup_template("filer_dialog.tpl");
    +		$o = replace_macros($tpl, array(
    +			'$field' => array('term', t("Save to Folder:"), '', '', $filetags, t('- select -')),
    +			'$submit' => t('Save'),
    +		));
    +		
    +		echo $o;
    +	}
    +	killme();
    +}
    diff --git a/sources/mod/filerm.php b/sources/mod/filerm.php
    new file mode 100644
    index 00000000..bd8ce7cf
    --- /dev/null
    +++ b/sources/mod/filerm.php
    @@ -0,0 +1,33 @@
    +argc > 1) ? intval($a->argv[1]) : 0);
    +
    +	logger('filerm: tag ' . $term . ' item ' . $item_id);
    +
    +	if($item_id && strlen($term)) {
    +		$r = q("delete from term where uid = %d and type = %d and oid = %d and term = '%s'",
    +			intval(local_channel()),
    +			intval(($category) ? TERM_CATEGORY : TERM_FILE),
    +			intval($item_id),
    +			dbesc($term)
    +		);
    +	}
    +
    +	if(x($_SESSION,'return_url'))
    +		goaway($a->get_baseurl() . '/' . $_SESSION['return_url']);
    +	
    +	killme();
    +}
    diff --git a/sources/mod/filestorage.php b/sources/mod/filestorage.php
    new file mode 100644
    index 00000000..9787c038
    --- /dev/null
    +++ b/sources/mod/filestorage.php
    @@ -0,0 +1,167 @@
    +get_channel();
    +	$cloudPath = get_parent_cloudpath($channel_id, $channel['channel_address'], $resource);
    +
    +	//get the object before permissions change so we can catch eventual former allowed members
    +	$object = get_file_activity_object($channel_id, $resource, $cloudPath);
    +
    +	attach_change_permissions($channel_id, $resource, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny, $recurse);
    +
    +	file_activity($channel_id, $object, $str_contact_allow, $str_group_allow, $str_contact_deny, $str_group_deny, 'post', $notify);
    +
    +	goaway($cloudPath);
    +}
    +
    +function filestorage_content(&$a) {
    +
    +	if(argc() > 1)
    +		$which = argv(1);
    +	else {
    +		notice( t('Requested profile is not available.') . EOL );
    +		$a->error = 404;
    +		return;
    +	}
    +
    +	$r = q("select * from channel where channel_address = '%s'",
    +		dbesc($which)
    +	);
    +	if($r) {
    +		$channel = $r[0];
    +		$owner = intval($r[0]['channel_id']);
    +	}
    +
    +	$observer = $a->get_observer();
    +	$ob_hash = (($observer) ? $observer['xchan_hash'] : '');
    +
    +	$perms = get_all_perms($owner, $ob_hash);
    +
    +	if(! $perms['view_storage']) {
    +		notice( t('Permission denied.') . EOL);
    +		return;
    +	}
    +
    +	// Since we have ACL'd files in the wild, but don't have ACL here yet, we
    +	// need to return for anyone other than the owner, despite the perms check for now.
    +
    +	$is_owner = (((local_channel()) && ($owner  == local_channel())) ? true : false);
    +	if(! $is_owner) {
    +		info( t('Permission Denied.') . EOL );
    +		return;
    +	}
    +
    +	if(argc() > 3 && argv(3) === 'delete') {
    +		if(! $perms['write_storage']) {
    +			notice( t('Permission denied.') . EOL);
    +			return;
    +		}
    +
    +		$file = intval(argv(2));
    +		$r = q("SELECT hash FROM attach WHERE id = %d AND uid = %d LIMIT 1",
    +			dbesc($file),
    +			intval($owner)
    +		);
    +		if(! $r) {
    +			notice( t('File not found.') . EOL);
    +			goaway(z_root() . '/cloud/' . $which);
    +		}
    +
    +		$f = $r[0];
    +		$channel = $a->get_channel();
    +
    +		$parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
    +
    +		attach_delete($owner, $f['hash']);
    +
    +		goaway($parentpath);
    +	}
    +
    +	if(argc() > 3 && argv(3) === 'edit') {
    +		require_once('include/acl_selectors.php');
    +		if(! $perms['write_storage']) {
    +			notice( t('Permission denied.') . EOL);
    +			return;
    +		}
    +		$file = intval(argv(2));
    +
    +		$r = q("select id, uid, folder, filename, revision, flags, is_dir, os_storage, hash, allow_cid, allow_gid, deny_cid, deny_gid from attach where id = %d and uid = %d limit 1",
    +			intval($file),
    +			intval($owner)
    +		);
    +
    +		$f = $r[0];
    +		$channel = $a->get_channel();
    +
    +		$cloudpath = get_cloudpath($f) . (intval($f['is_dir']) ? '?f=&davguest=1' : '');
    +		$parentpath = get_parent_cloudpath($channel['channel_id'], $channel['channel_address'], $f['hash']);
    +
    +		$aclselect_e = populate_acl($f, false);
    +		$is_a_dir = (intval($f['is_dir']) ? true : false);
    +
    +		$lockstate = (($f['allow_cid'] || $f['allow_gid'] || $f['deny_cid'] || $f['deny_gid']) ? 'lock' : 'unlock'); 
    +
    +		// Encode path that is used for link so it's a valid URL
    +		// Keep slashes as slashes, otherwise mod_rewrite doesn't work correctly
    +		$encoded_path = str_replace('%2F', '/', rawurlencode($cloudpath));
    +
    +		$o = replace_macros(get_markup_template('attach_edit.tpl'), array(
    +			'$header' => t('Edit file permissions'),
    +			'$file' => $f,
    +			'$cloudpath' => z_root() . '/' . $encoded_path,
    +			'$parentpath' => $parentpath,
    +			'$uid' => $channel['channel_id'],
    +			'$channelnick' => $channel['channel_address'],
    +			'$permissions' => t('Permissions'),
    +			'$aclselect' => $aclselect_e,
    +			'$lockstate' => $lockstate,
    +			'$permset' => t('Set/edit permissions'),
    +			'$recurse' => array('recurse', t('Include all files and sub folders'), 0, '', array(t('No'), t('Yes'))),
    +			'$backlink' => t('Return to file list'),
    +			'$isadir' => $is_a_dir,
    +			'$cpdesc' => t('Copy/paste this code to attach file to a post'),
    +			'$cpldesc' => t('Copy/paste this URL to link file from a web page'),
    +			'$submit' => t('Submit'),
    +			'$attach_btn_title' => t('Share this file'),
    +			'$link_btn_title' => t('Show URL to this file'),
    +			'$notify' => array('notify', t('Notify your contacts about this file'), 0, '', array(t('No'), t('Yes')))
    +		));
    +
    +		echo $o;
    +		killme();
    +	}
    +
    +	goaway(z_root() . '/cloud/' . $which);
    +}
    diff --git a/sources/mod/follow.php b/sources/mod/follow.php
    new file mode 100644
    index 00000000..3ad2cb3b
    --- /dev/null
    +++ b/sources/mod/follow.php
    @@ -0,0 +1,54 @@
    +get_channel(),true,$confirm);
    +	
    +	if($result['success'] == false) {
    +		if($result['message'])
    +			notice($result['message']);
    +		goaway($return_url);
    +	}
    +
    +	info( t('Channel added.') . EOL);
    +
    +	$clone = array();
    +	foreach($result['abook'] as $k => $v) {
    +		if(strpos($k,'abook_') === 0) {
    +			$clone[$k] = $v;
    +		}
    +	}
    +	unset($clone['abook_id']);
    +	unset($clone['abook_account']);
    +	unset($clone['abook_channel']);
    +
    +	build_sync_packet(0 /* use the current local_channel */, array('abook' => array($clone)));
    +
    +
    +	// If we can view their stream, pull in some posts
    +
    +	if(($result['abook']['abook_their_perms'] & PERMS_R_STREAM) || ($result['abook']['xchan_network'] === 'rss'))
    +		proc_run('php','include/onepoll.php',$result['abook']['abook_id']);
    +
    +	goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?f=&follow=1');
    +
    +}
    +
    +function follow_content(&$a) {
    +
    +	if(! local_channel()) {
    +		return login();
    +	}
    +}
    \ No newline at end of file
    diff --git a/sources/mod/fsuggest.php b/sources/mod/fsuggest.php
    new file mode 100644
    index 00000000..ec87af6a
    --- /dev/null
    +++ b/sources/mod/fsuggest.php
    @@ -0,0 +1,112 @@
    +argc != 2)
    +		return;
    +
    +	$contact_id = intval($a->argv[1]);
    +
    +	$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
    +		intval($contact_id),
    +		intval(local_channel())
    +	);
    +	if(! count($r)) {
    +		notice( t('Contact not found.') . EOL);
    +		return;
    +	}
    +	$contact = $r[0];
    +
    +	$new_contact = intval($_POST['suggest']);
    +
    +	$hash = random_string();
    +
    +	$note = escape_tags(trim($_POST['note']));
    +
    +	if($new_contact) {
    +		$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
    +			intval($new_contact),
    +			intval(local_channel())
    +		);
    +		if(count($r)) {
    +
    +			$x = q("INSERT INTO `fsuggest` ( `uid`,`cid`,`name`,`url`,`request`,`photo`,`note`,`created`)
    +				VALUES ( %d, %d, '%s','%s','%s','%s','%s','%s')",
    +				intval(local_channel()),
    +				intval($contact_id),
    +				dbesc($r[0]['name']), 
    +				dbesc($r[0]['url']), 
    +				dbesc($r[0]['request']), 
    +				dbesc($r[0]['photo']), 
    +				dbesc($hash), 
    +				dbesc(datetime_convert())
    +			);
    +			$r = q("SELECT `id` FROM `fsuggest` WHERE `note` = '%s' AND `uid` = %d LIMIT 1",
    +				dbesc($hash),
    +				intval(local_channel())
    +			);
    +			if(count($r)) {
    +				$fsuggest_id = $r[0]['id'];
    +				q("UPDATE `fsuggest` SET `note` = '%s' WHERE `id` = %d AND `uid` = %d",
    +					dbesc($note),
    +					intval($fsuggest_id),
    +					intval(local_channel())
    +				);
    +				proc_run('php', 'include/notifier.php', 'suggest' , $fsuggest_id);
    +			}
    +
    +			info( t('Friend suggestion sent.') . EOL);
    +		}
    +
    +	}
    +
    +
    +}
    +
    +
    +
    +function fsuggest_content(&$a) {
    +
    +	require_once('include/acl_selectors.php');
    +
    +	if(! local_channel()) {
    +		notice( t('Permission denied.') . EOL);
    +		return;
    +	}
    +
    +	if($a->argc != 2)
    +		return;
    +
    +	$contact_id = intval($a->argv[1]);
    +
    +	$r = q("SELECT * FROM `contact` WHERE `id` = %d AND `uid` = %d LIMIT 1",
    +		intval($contact_id),
    +		intval(local_channel())
    +	);
    +	if(! count($r)) {
    +		notice( t('Contact not found.') . EOL);
    +		return;
    +	}
    +	$contact = $r[0];
    +
    +	$o = '

    ' . t('Suggest Friends') . '

    '; + + $o .= '
    ' . sprintf( t('Suggest a friend for %s'), $contact['name']) . '
    '; + + $o .= '
    '; + +// FIXME contact_selector deprecated, removed +// $o .= contact_selector('suggest','suggest-select', false, +// array('size' => 4, 'exclude' => $contact_id, 'networks' => 'DFRN_ONLY', 'single' => true)); + + + $o .= '
    '; + $o .= '
    '; + + return $o; +} \ No newline at end of file diff --git a/sources/mod/group.php b/sources/mod/group.php new file mode 100644 index 00000000..ce963366 --- /dev/null +++ b/sources/mod/group.php @@ -0,0 +1,238 @@ +get_baseurl() . '/group/' . $r); + } + else + notice( t('Could not create collection.') . EOL ); + goaway($a->get_baseurl() . '/group'); + + } + if((argc() == 2) && (intval(argv(1)))) { + check_form_security_token_redirectOnErr('/group', 'group_edit'); + + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if(! $r) { + notice( t('Collection not found.') . EOL ); + goaway($a->get_baseurl() . '/connections'); + + } + $group = $r[0]; + $groupname = notags(trim($_POST['groupname'])); + $public = intval($_POST['public']); + + if((strlen($groupname)) && (($groupname != $group['name']) || ($public != $group['visible']))) { + $r = q("UPDATE `groups` SET `name` = '%s', visible = %d WHERE `uid` = %d AND `id` = %d", + dbesc($groupname), + intval($public), + intval(local_channel()), + intval($group['id']) + ); + if($r) + info( t('Collection updated.') . EOL ); + } + + goaway(z_root() . '/group/' . argv(1) . '/' . argv(2)); + } + return; +} + +function group_content(&$a) { + $change = false; + + logger('mod_group: ' . $a->cmd,LOGGER_DEBUG); + + if(! local_channel()) { + notice( t('Permission denied') . EOL); + return; + } + + // Switch to text mode interface if we have more than 'n' contacts or group members + + $switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit'); + if($switchtotext === false) + $switchtotext = get_config('system','groupedit_image_limit'); + if($switchtotext === false) + $switchtotext = 400; + + $tpl = get_markup_template('group_edit.tpl'); + $context = array('$submit' => t('Submit')); + + if((argc() == 2) && (argv(1) === 'new')) { + + return replace_macros($tpl, $context + array( + '$title' => t('Create a collection of channels.'), + '$gname' => array('groupname',t('Collection Name: '), '', ''), + '$gid' => 'new', + '$public' => array('public',t('Members are visible to other channels'), false, ''), + '$form_security_token' => get_form_security_token("group_edit"), + )); + + + } + + if((argc() == 3) && (argv(1) === 'drop')) { + check_form_security_token_redirectOnErr('/group', 'group_drop', 't'); + + if(intval(argv(2))) { + $r = q("SELECT `name` FROM `groups` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval(argv(2)), + intval(local_channel()) + ); + if($r) + $result = group_rmv(local_channel(),$r[0]['name']); + if($result) + info( t('Collection removed.') . EOL); + else + notice( t('Unable to remove collection.') . EOL); + } + goaway($a->get_baseurl() . '/group'); + // NOTREACHED + } + + + if((argc() > 2) && intval(argv(1)) && argv(2)) { + + check_form_security_token_ForbiddenOnErr('group_member_change', 't'); + + $r = q("SELECT abook_xchan from abook left join xchan on abook_xchan = xchan_hash where abook_xchan = '%s' and abook_channel = %d and xchan_deleted = 0 and abook_blocked = 0 and abook_pending = 0 limit 1", + dbesc(base64url_decode(argv(2))), + intval(local_channel()) + ); + if(count($r)) + $change = base64url_decode(argv(2)); + + } + + if((argc() > 1) && (intval(argv(1)))) { + + require_once('include/acl_selectors.php'); + $r = q("SELECT * FROM `groups` WHERE `id` = %d AND `uid` = %d AND `deleted` = 0 LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if(! $r) { + notice( t('Collection not found.') . EOL ); + goaway($a->get_baseurl() . '/connections'); + } + $group = $r[0]; + + + $members = group_get_members($group['id']); + + $preselected = array(); + if(count($members)) { + foreach($members as $member) + if(! in_array($member['xchan_hash'],$preselected)) + $preselected[] = $member['xchan_hash']; + } + + if($change) { + + if(in_array($change,$preselected)) { + group_rmv_member(local_channel(),$group['name'],$change); + } + else { + group_add_member(local_channel(),$group['name'],$change); + } + + $members = group_get_members($group['id']); + + $preselected = array(); + if(count($members)) { + foreach($members as $member) + $preselected[] = $member['xchan_hash']; + } + } + + $drop_tpl = get_markup_template('group_drop.tpl'); + $drop_txt = replace_macros($drop_tpl, array( + '$id' => $group['id'], + '$delete' => t('Delete'), + '$form_security_token' => get_form_security_token("group_drop"), + )); + + + $context = $context + array( + '$title' => t('Collection Editor'), + '$gname' => array('groupname',t('Collection Name: '),$group['name'], ''), + '$gid' => $group['id'], + '$drop' => $drop_txt, + '$public' => array('public',t('Members are visible to other channels'), $group['visible'], ''), + '$form_security_token' => get_form_security_token('group_edit'), + ); + + } + + if(! isset($group)) + return; + + $groupeditor = array( + 'label_members' => t('Members'), + 'members' => array(), + 'label_contacts' => t('All Connected Channels'), + 'contacts' => array(), + ); + + $sec_token = addslashes(get_form_security_token('group_member_change')); + $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); + foreach($members as $member) { + if($member['xchan_url']) { + $member['archived'] = (intval($member['abook_archived']) ? true : false); + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; + $groupeditor['members'][] = micropro($member,true,'mpgroup', $textmode); + } + else + group_rmv_member(local_channel(),$group['name'],$member['xchan_hash']); + } + + $r = q("SELECT abook.*, xchan.* FROM `abook` left join xchan on abook_xchan = xchan_hash WHERE `abook_channel` = %d AND abook_blocked = 0 and abook_pending = 0 and xchan_deleted = 0 order by xchan_name asc", + intval(local_channel()) + ); + + if(count($r)) { + $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); + foreach($r as $member) { + if(! in_array($member['xchan_hash'],$preselected)) { + $member['archived'] = (intval($member['abook_archived']) ? true : false); + $member['click'] = 'groupChangeMember(' . $group['id'] . ',\'' . base64url_encode($member['xchan_hash']) . '\',\'' . $sec_token . '\'); return false;'; + $groupeditor['contacts'][] = micropro($member,true,'mpall', $textmode); + } + } + } + + $context['$groupeditor'] = $groupeditor; + $context['$desc'] = t('Click on a channel to add or remove.'); + + if($change) { + $tpl = get_markup_template('groupeditor.tpl'); + echo replace_macros($tpl, $context); + killme(); + } + + return replace_macros($tpl, $context); + +} + diff --git a/sources/mod/hcard.php b/sources/mod/hcard.php new file mode 100644 index 00000000..014a63b3 --- /dev/null +++ b/sources/mod/hcard.php @@ -0,0 +1,54 @@ + 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $profile = ''; + $channel = $a->get_channel(); + + if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", + intval($profile), + intval(local_channel()) + ); + if(! $r) + $profile = ''; + $profile = $r[0]['profile_guid']; + } + + $a->page['htmlhead'] .= '' . "\r\n" ; + + if(! $profile) { + $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", + dbesc(argv(1)) + ); + if($x) { + $a->profile = $x[0]; + } + } + + profile_load($a,$which,$profile); + + +} + + +function hcard_content(&$a) { + + require_once('include/widgets.php'); + return widget_profile(array()); + + + +} + + diff --git a/sources/mod/help.php b/sources/mod/help.php new file mode 100644 index 00000000..809313a3 --- /dev/null +++ b/sources/mod/help.php @@ -0,0 +1,269 @@ +language; + if(! isset($lang)) + $lang = 'en'; + $b = basename($s); + $d = dirname($s); + + $c = find_doc_file("$d/$lang/$b"); + if($c) + return $c; + $c = find_doc_file($s); + if($c) + return $c; + return ''; +} + +function find_doc_file($s) { + + // If the file was edited more recently than we've stored a copy in the database, use the file. + // The stored database item will be searchable, the file won't be. + + $r = q("select item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and + sid = '%s' and item_type = %d limit 1", + dbesc($s), + intval(ITEM_TYPE_DOC) + ); + + if($r) { + if(file_exists($s) && (filemtime($s) > datetime_convert('UTC','UTC',$r[0]['edited'],'U'))) + return file_get_contents($s); + return($r[0]['body']); + } + if(file_exists($s)) + return file_get_contents($s); + return ''; +} + +function search_doc_files($s) { + + $a = get_app(); + + $itemspage = get_pconfig(local_channel(),'system','itemspage'); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($a->pager['itemspage']), intval($a->pager['start'])); + + // If the file was edited more recently than we've stored a copy in the database, use the file. + // The stored database item will be searchable, the file won't be. + + $regexop = db_getfunc('REGEXP'); + + $r = q("select item_id.sid, item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and + body $regexop '%s' and item_type = %d $pager_sql", + dbesc($s), + intval(ITEM_TYPE_DOC) + ); + + $r = fetch_post_tags($r,true); + require_once('include/html2plain.php'); + + for($x = 0; $x < count($r); $x ++) { + + $r[$x]['text'] = html2plain(prepare_text($r[$x]['body'],$r[$x]['mimetype'], true)); + + $r[$x]['rank'] = 0; + if($r[$x]['term']) { + foreach($r[$x]['term'] as $t) { + if(stristr($t['term'],$s)) { + $r[$x]['rank'] ++; + } + } + } + if(stristr($r[$x]['sid'],$s)) + $r[$x]['rank'] ++; + $r[$x]['rank'] += substr_count(strtolower($r[$x]['text']),strtolower($s)); + } + usort($r,'doc_rank_sort'); + return $r; +} + + +function doc_rank_sort($a,$b) { + if($a['rank'] == $b['rank']) + return 0; + return (($a['rank'] < $b['rank']) ? 1 : (-1)); +} + + + + + +function store_doc_file($s) { + + if(is_dir($s)) + return; + + $item = array(); + $sys = get_sys_channel(); + + $item['aid'] = 0; + $item['uid'] = $sys['channel_id']; + + + if(strpos($s,'.md')) + $item['mimetype'] = 'text/markdown'; + elseif(strpos($s,'.html')) + $item['mimetype'] = 'text/html'; + else + $item['mimetype'] = 'text/bbcode'; + + + $item['body'] = file_get_contents($s); + $item['plink'] = z_root() . '/' . str_replace('doc','help',$s); + $item['owner_xchan'] = $item['author_xchan'] = $sys['channel_hash']; + $item['item_type'] = ITEM_TYPE_DOC; + + $r = q("select item.* from item left join item_id on item.id = item_id.iid where service = 'docfile' and + sid = '%s' and item_type = %d limit 1", + dbesc($s), + intval(ITEM_TYPE_DOC) + ); + + if($r) { + $item['id'] = $r[0]['id']; + $item['mid'] = $item['parent_mid'] = $r[0]['mid']; + $x = item_store_update($item); + } + else { + $item['mid'] = $item['parent_mid'] = item_message_id(); + $x = item_store($item); + } + + if($x['success']) { + update_remote_id($sys,$x['item_id'],ITEM_TYPE_DOC,$s,'docfile',0,$item['mid']); + } + + +} + + +function help_content(&$a) { + nav_set_selected('help'); + + if($_REQUEST['search']) { + $r = search_doc_files($_REQUEST['search']); + if($r) { + $o .= '
      '; + foreach($r as $rr) { + $dirname = dirname($rr['sid']); + $fname = basename($rr['sid']); + $fname = substr($fname,0,strrpos($fname,'.')); + $path = trim(substr($dirname,4),'/'); + + $o .= '
    • ' . ucwords(str_replace('_',' ',notags($fname))) . '
      ' . + str_replace('$Projectname',PLATFORM_NAME,substr($rr['text'],0,200)) . '...

    • '; + + } + $o .= '
    '; + } + return $o; + } + + + global $lang; + + $doctype = 'markdown'; + + $text = ''; + + if(argc() > 1) { + $path = ''; + for($x = 1; $x < argc(); $x ++) { + if(strlen($path)) + $path .= '/'; + $path .= argv($x); + } + $title = basename($path); + + $text = load_doc_file('doc/' . $path . '.md'); + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); + + if(! $text) { + $text = load_doc_file('doc/' . $path . '.bb'); + if($text) + $doctype = 'bbcode'; + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('_',' ',notags($title))); + } + if(! $text) { + $text = load_doc_file('doc/' . $path . '.html'); + if($text) + $doctype = 'html'; + $a->page['title'] = t('Help:') . ' ' . ucwords(str_replace('-',' ',notags($title))); + } + } + + if(! $text) { + $text = load_doc_file('doc/Site.md'); + $a->page['title'] = t('Help'); + } + if(! $text) { + $doctype = 'bbcode'; + $text = load_doc_file('doc/main.bb'); + $a->page['title'] = t('Help'); + } + + if(! strlen($text)) { + header($_SERVER["SERVER_PROTOCOL"] . ' 404 ' . t('Not Found')); + $tpl = get_markup_template("404.tpl"); + return replace_macros($tpl, array( + '$message' => t('Page not found.' ) + )); + } + + if($doctype === 'html') + $content = $text; + if($doctype === 'markdown') { + require_once('library/markdown.php'); + # escape #include tags + $text = preg_replace('/#include/ism', '%%include', $text); + $content = Markdown($text); + $content = preg_replace('/%%include/ism', '#include', $content); + } + if($doctype === 'bbcode') { + require_once('include/bbcode.php'); + $content = bbcode($text); + } + + $content = preg_replace_callback("/#include (.*?)\;/ism", 'preg_callback_help_include', $content); + + return replace_macros(get_markup_template("help.tpl"), array( + '$title' => t('$Projectname Documentation'), + '$content' => translate_projectname($content) + )); + +} + + +function preg_callback_help_include($matches) { + + if($matches[1]) { + $include = str_replace($matches[0],load_doc_file($matches[1]),$matches[0]); + if(preg_match('/\.bb$/', $matches[1]) || preg_match('/\.txt$/', $matches[1])) { + require_once('include/bbcode.php'); + $include = bbcode($include); + } elseif(preg_match('/\.md$/', $matches[1])) { + require_once('library/markdown.php'); + $include = Markdown($include); + } + return $include; + } + +} + diff --git a/sources/mod/home.php b/sources/mod/home.php new file mode 100644 index 00000000..242b2dce --- /dev/null +++ b/sources/mod/home.php @@ -0,0 +1,81 @@ + 1 && argv(1) === 'splash') ? true : false); + + $channel = $a->get_channel(); + if(local_channel() && $channel && $channel['xchan_url'] && ! $splash) { + $dest = $channel['channel_startpage']; + if(! $dest) + $dest = get_pconfig(local_channel(),'system','startpage'); + if(! $dest) + $dest = get_config('system','startpage'); + if(! $dest) + $dest = z_root() . '/network'; + + goaway($dest); + } + + if(get_account_id() && ! $splash) { + goaway(z_root() . '/new_channel'); + } + +} + + +function home_content(&$a, $update = 0, $load = false) { + + $o = ''; + + + if(x($_SESSION,'theme')) + unset($_SESSION['theme']); + if(x($_SESSION,'mobile_theme')) + unset($_SESSION['mobile_theme']); + + $splash = ((argc() > 1 && argv(1) === 'splash') ? true : false); + + call_hooks('home_content',$o); + if($o) + return $o; + + $frontpage = get_config('system','frontpage'); + if($frontpage) { + if(strpos($frontpage,'include:') !== false) { + $file = trim(str_replace('include:' , '', $frontpage)); + if(file_exists($file)) { + $a->page['template'] = 'full'; + $a->page['title'] = t('$Projectname'); + $o .= file_get_contents($file); + return $o; + } + } + if(intval(get_config('system','mirror_frontpage'))) { + $o = '' . t('$Projectname') . ''; + echo $o; + killme(); + } + goaway(z_root() . '/' . $frontpage); + } + + + $sitename = get_config('system','sitename'); + if($sitename) + $o .= '

    ' . sprintf( t("Welcome to %s") ,$sitename) . '

    '; + + $loginbox = get_config('system','login_on_homepage'); + if(intval($loginbox) || $loginbox === false) + $o .= login(($a->config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1); + + return $o; + +} diff --git a/sources/mod/hostxrd.php b/sources/mod/hostxrd.php new file mode 100644 index 00000000..ef86f2dd --- /dev/null +++ b/sources/mod/hostxrd.php @@ -0,0 +1,16 @@ + $a->get_hostname(), + '$zroot' => z_root() + )); + $arr = array('xrd' => $x); + call_hooks('hostxrd',$arr); + echo $arr['xrd']; + killme(); +} diff --git a/sources/mod/id.php b/sources/mod/id.php new file mode 100644 index 00000000..bd4c1fa8 --- /dev/null +++ b/sources/mod/id.php @@ -0,0 +1,310 @@ + t('First Name'), + 'namePerson/last' => t('Last Name'), + 'namePerson/friendly' => t('Nickname'), + 'namePerson' => t('Full Name'), + 'contact/internet/email' => t('Email'), + 'contact/email' => t('Email'), + 'media/image/aspect11' => t('Profile Photo'), + 'media/image' => t('Profile Photo'), + 'media/image/default' => t('Profile Photo'), + 'media/image/16x16' => t('Profile Photo 16px'), + 'media/image/32x32' => t('Profile Photo 32px'), + 'media/image/48x48' => t('Profile Photo 48px'), + 'media/image/64x64' => t('Profile Photo 64px'), + 'media/image/80x80' => t('Profile Photo 80px'), + 'media/image/128x128' => t('Profile Photo 128px'), + 'timezone' => t('Timezone'), + 'contact/web/default' => t('Homepage URL'), + 'language/pref' => t('Language'), + 'birthDate/birthYear' => t('Birth Year'), + 'birthDate/birthMonth' => t('Birth Month'), + 'birthDate/birthday' => t('Birth Day'), + 'birthDate' => t('Birthdate'), + 'gender' => t('Gender'), +); + + +/** + * @brief Entrypoint for the OpenID implementation. + * + * @param App &$a + */ +function id_init(&$a) { + + logger('id: ' . print_r($_REQUEST, true)); + + if(argc() > 1) { + $which = argv(1); + } else { + $a->error = 404; + return; + } + + $profile = ''; + $channel = $a->get_channel(); + profile_load($a,$which,$profile); + + $op = new MysqlProvider; + $op->server(); +} + +/** + * @brief Returns user data needed for OpenID. + * + * If no $handle is provided we will use local_channel() by default. + * + * @param string $handle (default null) + * @return boolean|array + */ +function getUserData($handle = null) { + if (! local_channel()) { + notice( t('Permission denied.') . EOL); + get_app()->page['content'] = login(); + + return false; + } + +// logger('handle: ' . $handle); + + if ($handle) { + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_address = '%s' limit 1", + dbesc($handle) + ); + } else { + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d", + intval(local_channel()) + ); + } + + if (! r) + return false; + + $x = q("select * from account where account_id = %d limit 1", + intval($r[0]['channel_account_id']) + ); + if ($x) + $r[0]['email'] = $x[0]['account_email']; + + $p = q("select * from profile where is_default = 1 and uid = %d limit 1", + intval($r[0]['channel_account_id']) + ); + + $gender = ''; + if ($p[0]['gender'] == t('Male')) + $gender = 'M'; + if ($p[0]['gender'] == t('Female')) + $gender = 'F'; + + $r[0]['firstName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],0,strpos($r[0]['channel_name'],' ')) : $r[0]['channel_name']); + $r[0]['lastName'] = ((strpos($r[0]['channel_name'],' ')) ? substr($r[0]['channel_name'],strpos($r[0]['channel_name'],' ')+1) : ''); + $r[0]['namePerson'] = $r[0]['channel_name']; + $r[0]['pphoto'] = $r[0]['xchan_photo_l']; + $r[0]['pphoto16'] = z_root() . '/photo/profile/16/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto32'] = z_root() . '/photo/profile/32/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto48'] = z_root() . '/photo/profile/48/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto64'] = z_root() . '/photo/profile/64/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto80'] = z_root() . '/photo/profile/80/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['pphoto128'] = z_root() . '/photo/profile/128/' . $r[0]['channel_id'] . '.jpg'; + $r[0]['timezone'] = $r[0]['channel_timezone']; + $r[0]['url'] = $r[0]['xchan_url']; + $r[0]['language'] = (($x[0]['account_language']) ? $x[0]['account_language'] : 'en'); + $r[0]['birthyear'] = ((intval(substr($p[0]['dob'],0,4))) ? intval(substr($p[0]['dob'],0,4)) : ''); + $r[0]['birthmonth'] = ((intval(substr($p[0]['dob'],5,2))) ? intval(substr($p[0]['dob'],5,2)) : ''); + $r[0]['birthday'] = ((intval(substr($p[0]['dob'],8,2))) ? intval(substr($p[0]['dob'],8,2)) : ''); + $r[0]['birthdate'] = (($r[0]['birthyear'] && $r[0]['birthmonth'] && $r[0]['birthday']) ? $p[0]['dob'] : ''); + $r[0]['gender'] = $gender; + + return $r[0]; + +/* +* if(isset($_POST['login'],$_POST['password'])) { +* $login = mysql_real_escape_string($_POST['login']); +* $password = sha1($_POST['password']); +* $q = mysql_query("SELECT * FROM Users WHERE login = '$login' AND password = '$password'"); +* if($data = mysql_fetch_assoc($q)) { +* return $data; +* } +* if($handle) { +* echo 'Wrong login/password.'; +* } +* } +* if($handle) { +* ?> +*
    +* +* Login:
    +* Password:
    +* +*
    +* 'firstName', + 'namePerson/last' => 'lastName', + 'namePerson/friendly' => 'channel_address', + 'namePerson' => 'namePerson', + 'contact/internet/email' => 'email', + 'contact/email' => 'email', + 'media/image/aspect11' => 'pphoto', + 'media/image' => 'pphoto', + 'media/image/default' => 'pphoto', + 'media/image/16x16' => 'pphoto16', + 'media/image/32x32' => 'pphoto32', + 'media/image/48x48' => 'pphoto48', + 'media/image/64x64' => 'pphoto64', + 'media/image/80x80' => 'pphoto80', + 'media/image/128x128' => 'pphoto128', + 'timezone' => 'timezone', + 'contact/web/default' => 'url', + 'language/pref' => 'language', + 'birthDate/birthYear' => 'birthyear', + 'birthDate/birthMonth' => 'birthmonth', + 'birthDate/birthday' => 'birthday', + 'birthDate' => 'birthdate', + 'gender' => 'gender', + ); + + function setup($identity, $realm, $assoc_handle, $attributes) { + global $attrMap; + +// logger('identity: ' . $identity); +// logger('realm: ' . $realm); +// logger('assoc_handle: ' . $assoc_handle); +// logger('attributes: ' . print_r($attributes,true)); + + $data = getUserData($assoc_handle); + + +/** @FIXME this needs to be a template with localised strings */ + + $o .= '
    ' + . '' + . '' + . '' + . "$realm wishes to authenticate you."; + if($attributes['required'] || $attributes['optional']) { + $o .= " It also requests following information (required fields marked with *):" + . '
      '; + + foreach($attributes['required'] as $attr) { + if(isset($this->attrMap[$attr])) { + $o .= '
    • ' + . ' ' + . $this->attrMap[$attr] . ' *
    • '; + } + } + + foreach($attributes['optional'] as $attr) { + if(isset($this->attrMap[$attr])) { + $o .= '
    • ' + . ' ' + . $this->attrMap[$attr] . '
    • '; + } + } + $o .= '
    '; + } + $o .= '
    ' + . ' ' + . ' ' + . ' ' + . '
    '; + + get_app()->page['content'] .= $o; + } + + function checkid($realm, &$attributes) { + + logger('checkid: ' . $realm); + logger('checkid attrs: ' . print_r($attributes,true)); + + if(isset($_POST['cancel'])) { + $this->cancel(); + } + + $data = getUserData(); + if(! $data) { + return false; + } + + $q = get_pconfig(local_channel(), 'openid', $realm); + + $attrs = array(); + if($q) { + $attrs = $q; + } elseif(isset($_POST['attributes'])) { + $attrs = array_keys($_POST['attributes']); + } elseif(!isset($_POST['once']) && !isset($_POST['always'])) { + return false; + } + + $attributes = array(); + foreach($attrs as $attr) { + if(isset($this->attrFieldMap[$attr])) { + $attributes[$attr] = $data[$this->attrFieldMap[$attr]]; + } + } + + if(isset($_POST['always'])) { + set_pconfig(local_channel(),'openid',$realm,array_keys($attributes)); + } + + return z_root() . '/id/' . $data['channel_address']; + } + + function assoc_handle() { + logger('assoc_handle'); + $channel = get_app()->get_channel(); + + return z_root() . '/channel/' . $channel['channel_address']; + } + + function setAssoc($handle, $data) { + logger('setAssoc'); + $channel = channelx_by_nick(basename($handle)); + if($channel) + set_pconfig($channel['channel_id'],'openid','associate',$data); + } + + function getAssoc($handle) { + logger('getAssoc: ' . $handle); + + $channel = channelx_by_nick(basename($handle)); + if($channel) + return get_pconfig($channel['channel_id'], 'openid', 'associate'); + + return false; + } + + function delAssoc($handle) { + logger('delAssoc'); + $channel = channelx_by_nick(basename($handle)); + if($channel) + return del_pconfig($channel['channel_id'], 'openid', 'associate'); + } +} diff --git a/sources/mod/impel.php b/sources/mod/impel.php new file mode 100644 index 00000000..da713843 --- /dev/null +++ b/sources/mod/impel.php @@ -0,0 +1,201 @@ + false); + + if(! local_channel()) + json_return_and_die($ret); + + logger('impel: ' . print_r($_REQUEST,true), LOGGER_DATA); + + $elm = $_REQUEST['element']; + $x = base64url_decode($elm); + if(! $x) + json_return_and_die($ret); + + $j = json_decode($x,true); + if(! $j) + json_return_and_die($ret); + + $channel = $a->get_channel(); + + $arr = array(); + $is_menu = false; + + // a portable menu has its links rewritten with the local baseurl + $portable_menu = false; + + switch($j['type']) { + case 'webpage': + $arr['item_type'] = ITEM_TYPE_WEBPAGE; + $namespace = 'WEBPAGE'; + $installed_type = t('webpage'); + break; + case 'block': + $arr['item_type'] = ITEM_TYPE_BLOCK; + $namespace = 'BUILDBLOCK'; + $installed_type = t('block'); + break; + case 'layout': + $arr['item_type'] = ITEM_TYPE_PDL; + $namespace = 'PDL'; + $installed_type = t('layout'); + break; + case 'portable-menu': + $portable_menu = true; + // fall through + case 'menu': + $is_menu = true; + $installed_type = t('menu'); + break; + default: + logger('mod_impel: unrecognised element type' . print_r($j,true)); + break; + } + + if($is_menu) { + $m = array(); + $m['menu_channel_id'] = local_channel(); + $m['menu_name'] = $j['pagetitle']; + $m['menu_desc'] = $j['desc']; + if($j['created']) + $m['menu_created'] = datetime_convert($j['created']); + if($j['edited']) + $m['menu_edited'] = datetime_convert($j['edited']); + + $m['menu_flags'] = 0; + if($j['flags']) { + if(in_array('bookmark',$j['flags'])) + $m['menu_flags'] |= MENU_BOOKMARK; + if(in_array('system',$j['flags'])) + $m['menu_flags'] |= MENU_SYSTEM; + + } + + $menu_id = menu_create($m); + + if($menu_id) { + if(is_array($j['items'])) { + foreach($j['items'] as $it) { + $mitem = array(); + + $mitem['mitem_link'] = str_replace('[baseurl]',z_root(),$it['link']); + $mitem['mitem_desc'] = escape_tags($it['desc']); + $mitem['mitem_order'] = intval($it['order']); + if(is_array($it['flags'])) { + $mitem['mitem_flags'] = 0; + if(in_array('zid',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_ZID; + if(in_array('new-window',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_NEWWIN; + if(in_array('chatroom',$it['flags'])) + $mitem['mitem_flags'] |= MENU_ITEM_CHATROOM; + } + menu_add_item($menu_id,local_channel(),$mitem); + } + if($j['edited']) { + $x = q("update menu set menu_edited = '%s' where menu_id = %d and menu_channel_id = %d", + dbesc(datetime_convert('UTC','UTC',$j['edited'])), + intval($menu_id), + intval(local_channel()) + ); + } + } + $ret['success'] = true; + } + $x = $ret; + } + else { + $arr['uid'] = local_channel(); + $arr['aid'] = $channel['channel_account_id']; + $arr['title'] = $j['title']; + $arr['body'] = $j['body']; + $arr['term'] = $j['term']; + $arr['layout_mid'] = $j['layout_mid']; + $arr['created'] = datetime_convert('UTC','UTC', $j['created']); + $arr['edited'] = datetime_convert('UTC','UTC',$j['edited']); + $arr['owner_xchan'] = get_observer_hash(); + $arr['author_xchan'] = (($j['author_xchan']) ? $j['author_xchan'] : get_observer_hash()); + $arr['mimetype'] = (($j['mimetype']) ? $j['mimetype'] : 'text/bbcode'); + + if(! $j['mid']) + $j['mid'] = item_message_id(); + + $arr['mid'] = $arr['parent_mid'] = $j['mid']; + + + if($j['pagetitle']) { + require_once('library/urlify/URLify.php'); + $pagetitle = strtolower(URLify::transliterate($j['pagetitle'])); + } + + + + // Verify ability to use html or php!!! + + $execflag = false; + + if($arr['mimetype'] === 'application/x-php') { + $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", + intval(local_channel()) + ); + + if($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) { + $execflag = true; + } + } + + $remote_id = 0; + + $z = q("select * from item_id where sid = '%s' and service = '%s' and uid = %d limit 1", + dbesc($pagetitle), + dbesc($namespace), + intval(local_channel()) + ); + + $i = q("select id, edited, item_deleted from item where mid = '%s' and uid = %d limit 1", + dbesc($arr['mid']), + intval(local_channel()) + ); + + if($z && $i) { + $remote_id = $z[0]['id']; + $arr['id'] = $i[0]['id']; + // don't update if it has the same timestamp as the original + if($arr['edited'] > $i[0]['edited']) + $x = item_store_update($arr,$execflag); + } + else { + if(($i) && (intval($i[0]['item_deleted']))) { + // was partially deleted already, finish it off + q("delete from item where mid = '%s' and uid = %d", + dbesc($arr['mid']), + intval(local_channel()) + ); + } + $x = item_store($arr,$execflag); + } + + if($x['success']) { + $item_id = $x['item_id']; + update_remote_id($channel,$item_id,$arr['item_type'],$pagetitle,$namespace,$remote_id,$arr['mid']); + } + } + + if($x['success']) { + $ret['success'] = true; + info( sprintf( t('%s element installed'), $installed_type)); + } + else { + notice( sprintf( t('%s element installation failed'), $installed_type)); + } + +//??? should perhaps return ret? + json_return_and_die(true); + +} diff --git a/sources/mod/import.php b/sources/mod/import.php new file mode 100644 index 00000000..deee0c6e --- /dev/null +++ b/sources/mod/import.php @@ -0,0 +1,653 @@ + $max_identities) { + notice( sprintf( t('Your service plan only allows %d channels.'), $max_identities) . EOL); + return; + } + } + + + $data = null; + $seize = ((x($_REQUEST,'make_primary')) ? intval($_REQUEST['make_primary']) : 0); + $import_posts = ((x($_REQUEST,'import_posts')) ? intval($_REQUEST['import_posts']) : 0); + $src = $_FILES['filename']['tmp_name']; + $filename = basename($_FILES['filename']['name']); + $filesize = intval($_FILES['filename']['size']); + $filetype = $_FILES['filename']['type']; + + $completed = ((array_key_exists('import_step',$_SESSION)) ? intval($_SESSION['import_step']) : 0); + if($completed) + logger('saved import step: ' . $_SESSION['import_step']); + + if($src) { + + // This is OS specific and could also fail if your tmpdir isn't very large + // mostly used for Diaspora which exports gzipped files. + + if(strpos($filename,'.gz')){ + @rename($src,$src . '.gz'); + @system('gunzip ' . escapeshellarg($src . '.gz')); + } + + if($filesize) { + $data = @file_get_contents($src); + } + unlink($src); + } + + if(! $src) { + $old_address = ((x($_REQUEST,'old_address')) ? $_REQUEST['old_address'] : ''); + if(! $old_address) { + logger('mod_import: nothing to import.'); + notice( t('Nothing to import.') . EOL); + return; + } + + $email = ((x($_REQUEST,'email')) ? $_REQUEST['email'] : ''); + $password = ((x($_REQUEST,'password')) ? $_REQUEST['password'] : ''); + + $channelname = substr($old_address,0,strpos($old_address,'@')); + $servername = substr($old_address,strpos($old_address,'@')+1); + + $scheme = 'https://'; + $api_path = '/api/red/channel/export/basic?f=&channel=' . $channelname; + if($import_posts) + $api_path .= '&posts=1'; + $binary = false; + $redirects = 0; + $opts = array('http_auth' => $email . ':' . $password); + $url = $scheme . $servername . $api_path; + $ret = z_fetch_url($url, $binary, $redirects, $opts); + if(! $ret['success']) + $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); + if($ret['success']) + $data = $ret['body']; + else + notice( t('Unable to download data from old server') . EOL); + + } + + if(! $data) { + logger('mod_import: empty file.'); + notice( t('Imported file is empty.') . EOL); + return; + } + + $data = json_decode($data,true); + +// logger('import: data: ' . print_r($data,true)); +// print_r($data); + + + if(array_key_exists('user',$data) && array_key_exists('version',$data)) { + require_once('include/Import/import_diaspora.php'); + import_diaspora($data); + return; + } + + if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { + $v1 = substr($data['compatibility']['database'],-4); + $v2 = substr(DB_UPDATE_VERSION,-4); + if($v2 > $v1) { + $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); + notice($t); + } + } + + // import channel + + if(array_key_exists('channel',$data)) { + $channel = $data['channel']; + + if($completed < 1) { + + if(! array_key_exists('channel_system',$channel)) { + $channel['channel_system'] = (($channel['channel_pageflags'] & 0x1000) ? 1 : 0); + $channel['channel_removed'] = (($channel['channel_pageflags'] & 0x8000) ? 1 : 0); + } + + $r = q("select * from channel where (channel_guid = '%s' or channel_hash = '%s' or channel_address = '%s' ) limit 1", + dbesc($channel['channel_guid']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address']) + ); + + // We should probably also verify the hash + + if($r) { + if($r[0]['channel_guid'] === $channel['channel_guid'] || $r[0]['channel_hash'] === $channel['channel_hash']) { + logger('mod_import: duplicate channel. ', print_r($channel,true)); + notice( t('Cannot create a duplicate channel identifier on this system. Import failed.') . EOL); + return; + } + else { + // try at most ten times to generate a unique address. + $x = 0; + $found_unique = false; + do { + $tmp = $channel['channel_address'] . mt_rand(1000,9999); + $r = q("select * from channel where channel_address = '%s' limit 1", + dbesc($tmp) + ); + if(! $r) { + $channel['channel_address'] = $tmp; + $found_unique = true; + break; + } + $x ++; + } while ($x < 10); + if(! $found_unique) { + logger('mod_import: duplicate channel. randomisation failed.', print_r($channel,true)); + notice( t('Unable to create a unique channel address. Import failed.') . EOL); + return; + } + } + } + + unset($channel['channel_id']); + $channel['channel_account_id'] = get_account_id(); + $channel['channel_primary'] = (($seize) ? 1 : 0); + + dbesc_array($channel); + + $r = dbq("INSERT INTO channel (`" + . implode("`, `", array_keys($channel)) + . "`) VALUES ('" + . implode("', '", array_values($channel)) + . "')" ); + + if(! $r) { + logger('mod_import: channel clone failed. ', print_r($channel,true)); + notice( t('Channel clone failed. Import failed.') . EOL); + return; + } + + $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", + intval(get_account_id()), + $channel['channel_guid'] // Already dbesc'd + ); + if(! $r) { + logger('mod_import: channel not found. ', print_r($channel,true)); + notice( t('Cloned channel not found. Import failed.') . EOL); + return; + } + // reset + $channel = $r[0]; + + set_default_login_identity(get_account_id(),$channel['channel_id'],false); + logger('import step 1'); + $_SESSION['import_step'] = 1; + ref_session_write(session_id(), serialize($_SESSION)); + } + } + else { + $r = q("select * from channel where channel_account_id = %d and channel_guid = '%s' limit 1", + intval(get_account_id()), + dbesc($channel['channel_guid']) + ); + if($r) + $channel = $r[0]; + else { + logger('mod_import: channel not found. ', print_r($channel,true)); + notice( t('Cloned channel not found. Import failed.') . EOL); + return; + } + } + + if($completed < 2) { + + $configs = $data['config']; + if($configs) { + foreach($configs as $config) { + unset($config['id']); + $config['uid'] = $channel['channel_id']; + dbesc_array($config); + $r = dbq("INSERT INTO pconfig (`" + . implode("`, `", array_keys($config)) + . "`) VALUES ('" + . implode("', '", array_values($config)) + . "')" ); + } + } + logger('import step 2'); + $_SESSION['import_step'] = 2; + ref_session_write(session_id(), serialize($_SESSION)); + } + + + + if($completed < 3) { + + if($data['photo']) { + require_once('include/photo/photo_driver.php'); + import_channel_photo(base64url_decode($data['photo']['data']),$data['photo']['type'],get_account_id(),$channel['channel_id']); + } + + $profiles = $data['profile']; + if($profiles) { + foreach($profiles as $profile) { + unset($profile['id']); + $profile['aid'] = get_account_id(); + $profile['uid'] = $channel['channel_id']; + + // we are going to reset all profile photos to the original + // somebody will have to fix this later and put all the applicable photos into the export + + $profile['photo'] = z_root() . '/photo/profile/l/' . $channel['channel_id']; + $profile['thumb'] = z_root() . '/photo/profile/m/' . $channel['channel_id']; + + + dbesc_array($profile); + $r = dbq("INSERT INTO profile (`" + . implode("`, `", array_keys($profile)) + . "`) VALUES ('" + . implode("', '", array_values($profile)) + . "')" ); + } + } + logger('import step 3'); + $_SESSION['import_step'] = 3; + ref_session_write(session_id(), serialize($_SESSION)); + } + + + if($completed < 4) { + $hublocs = $data['hubloc']; + if($hublocs) { + foreach($hublocs as $hubloc) { + + if(! array_key_exists('hubloc_primary',$hublocs)) { + $hubloc['hubloc_primary'] = (($hubloc['hubloc_flags'] & 0x0001) ? 1 : 0); + $hubloc['hubloc_orphancheck'] = (($hubloc['hubloc_flags'] & 0x0004) ? 1 : 0); + $hubloc['hubloc_error'] = (($hubloc['hubloc_status'] & 0x0003) ? 1 : 0); + $hubloc['hubloc_deleted'] = (($hubloc['hubloc_flags'] & 0x1000) ? 1 : 0); + } + + $arr = array( + 'guid' => $hubloc['hubloc_guid'], + 'guid_sig' => $hubloc['guid_sig'], + 'url' => $hubloc['hubloc_url'], + 'url_sig' => $hubloc['hubloc_url_sig'] + ); + if(($hubloc['hubloc_hash'] === $channel['channel_hash']) && intval($hubloc['hubloc_primary']) && ($seize)) + $hubloc['hubloc_primary'] = 0; + + if(! zot_gethub($arr)) { + unset($hubloc['hubloc_id']); + dbesc_array($hubloc); + + $r = dbq("INSERT INTO hubloc (`" + . implode("`, `", array_keys($hubloc)) + . "`) VALUES ('" + . implode("', '", array_values($hubloc)) + . "')" ); + } + } + } + logger('import step 4'); + $_SESSION['import_step'] = 4; + ref_session_write(session_id(), serialize($_SESSION)); + } + + if($completed < 5) { + // create new hubloc for the new channel at this site + + $r = q("insert into hubloc ( hubloc_guid, hubloc_guid_sig, hubloc_hash, hubloc_addr, hubloc_network, hubloc_primary, + hubloc_url, hubloc_url_sig, hubloc_host, hubloc_callback, hubloc_sitekey ) + values ( '%s', '%s', '%s', '%s', '%s', %d, '%s', '%s', '%s', '%s', '%s' )", + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_hash']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + dbesc('zot'), + intval(($seize) ? 1 : 0), + dbesc(z_root()), + dbesc(base64url_encode(rsa_sign(z_root(),$channel['channel_prvkey']))), + dbesc(get_app()->get_hostname()), + dbesc(z_root() . '/post'), + dbesc(get_config('system','pubkey')) + ); + + // reset the original primary hubloc if it is being seized + + if($seize) { + $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' and hubloc_url != '%s' ", + dbesc($channel['channel_hash']), + dbesc(z_root()) + ); + } + logger('import step 5'); + $_SESSION['import_step'] = 5; + ref_session_write(session_id(), serialize($_SESSION)); + } + + + if($completed < 6) { + + // import xchans and contact photos + + if($seize) { + + // replace any existing xchan we may have on this site if we're seizing control + + $r = q("delete from xchan where xchan_hash = '%s'", + dbesc($channel['channel_hash']) + ); + + $r = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_l, xchan_photo_m, xchan_photo_s, xchan_addr, xchan_url, xchan_follow, xchan_connurl, xchan_name, xchan_network, xchan_photo_date, xchan_name_date, xchan_hidden, xchan_orphan, xchan_censored, xchan_selfcensored, xchan_system, xchan_pubforum, xchan_deleted ) values ('%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, %d, %d, %d, %d, %d )", + dbesc($channel['channel_hash']), + dbesc($channel['channel_guid']), + dbesc($channel['channel_guid_sig']), + dbesc($channel['channel_pubkey']), + dbesc($a->get_baseurl() . "/photo/profile/l/" . $channel['channel_id']), + dbesc($a->get_baseurl() . "/photo/profile/m/" . $channel['channel_id']), + dbesc($a->get_baseurl() . "/photo/profile/s/" . $channel['channel_id']), + dbesc($channel['channel_address'] . '@' . get_app()->get_hostname()), + dbesc(z_root() . '/channel/' . $channel['channel_address']), + dbesc(z_root() . '/follow?f=&url=%s'), + dbesc(z_root() . '/poco/' . $channel['channel_address']), + dbesc($channel['channel_name']), + dbesc('zot'), + dbesc(datetime_convert()), + dbesc(datetime_convert()), + 0,0,0,0,0,0,0 + ); + } + logger('import step 6'); + $_SESSION['import_step'] = 6; + ref_session_write(session_id(), serialize($_SESSION)); + } + + if($completed < 7) { + + $xchans = $data['xchan']; + if($xchans) { + foreach($xchans as $xchan) { + if(! array_key_exists('xchan_hidden',$xchan)) { + $xchan['xchan_hidden'] = (($xchan['xchan_flags'] & 0x0001) ? 1 : 0); + $xchan['xchan_orphan'] = (($xchan['xchan_flags'] & 0x0002) ? 1 : 0); + $xchan['xchan_censored'] = (($xchan['xchan_flags'] & 0x0004) ? 1 : 0); + $xchan['xchan_selfcensored'] = (($xchan['xchan_flags'] & 0x0008) ? 1 : 0); + $xchan['xchan_system'] = (($xchan['xchan_flags'] & 0x0010) ? 1 : 0); + $xchan['xchan_pubforum'] = (($xchan['xchan_flags'] & 0x0020) ? 1 : 0); + $xchan['xchan_deleted'] = (($xchan['xchan_flags'] & 0x1000) ? 1 : 0); + } + + $r = q("select xchan_hash from xchan where xchan_hash = '%s' limit 1", + dbesc($xchan['xchan_hash']) + ); + if($r) + continue; + + dbesc_array($xchan); + + $r = dbq("INSERT INTO xchan (`" + . implode("`, `", array_keys($xchan)) + . "`) VALUES ('" + . implode("', '", array_values($xchan)) + . "')" ); + + + require_once('include/photo/photo_driver.php'); + $photos = import_profile_photo($xchan['xchan_photo_l'],$xchan['xchan_hash']); + if($photos[4]) + $photodate = NULL_DATE; + else + $photodate = $xchan['xchan_photo_date']; + + $r = q("update xchan set xchan_photo_l = '%s', xchan_photo_m = '%s', xchan_photo_s = '%s', xchan_photo_mimetype = '%s', xchan_photo_date = '%s' + where xchan_hash = '%s'", + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($photodate), + dbesc($xchan['xchan_hash']) + ); + + } + } + logger('import step 7'); + $_SESSION['import_step'] = 7; + ref_session_write(session_id(), serialize($_SESSION)); + } + + + +// FIXME - ensure we have an xchan if somebody is trying to pull a fast one + + if($completed < 8) { + $friends = 0; + $feeds = 0; + + // import contacts + $abooks = $data['abook']; + if($abooks) { + foreach($abooks as $abook) { + + unset($abook['abook_id']); + unset($abook['abook_rating']); + unset($abook['abook_rating_text']); + $abook['abook_account'] = get_account_id(); + $abook['abook_channel'] = $channel['channel_id']; + if(! array_key_exists('abook_blocked',$abook)) { + $abook['abook_blocked'] = (($abook['abook_flags'] & 0x0001 ) ? 1 : 0); + $abook['abook_ignored'] = (($abook['abook_flags'] & 0x0002 ) ? 1 : 0); + $abook['abook_hidden'] = (($abook['abook_flags'] & 0x0004 ) ? 1 : 0); + $abook['abook_archived'] = (($abook['abook_flags'] & 0x0008 ) ? 1 : 0); + $abook['abook_pending'] = (($abook['abook_flags'] & 0x0010 ) ? 1 : 0); + $abook['abook_unconnected'] = (($abook['abook_flags'] & 0x0020 ) ? 1 : 0); + $abook['abook_self'] = (($abook['abook_flags'] & 0x0080 ) ? 1 : 0); + $abook['abook_feed'] = (($abook['abook_flags'] & 0x0100 ) ? 1 : 0); + } + + if($abook['abook_self']) { + $role = get_pconfig($channel['channel_id'],'system','permissions_role'); + if(($role === 'forum') || ($abook['abook_my_perms'] & PERMS_W_TAGWALL)) { + q("update xchan set xchan_pubforum = 1 where xchan_hash = '%s' ", + dbesc($abook['abook_xchan']) + ); + } + } + else { + if($max_friends !== false && $friends > $max_friends) + continue; + if($max_feeds !== false && intval($abook['abook_feed']) && ($feeds > $max_feeds)) + continue; + } + + dbesc_array($abook); + $r = dbq("INSERT INTO abook (`" + . implode("`, `", array_keys($abook)) + . "`) VALUES ('" + . implode("', '", array_values($abook)) + . "')" ); + + $friends ++; + if(intval($abook['abook_feed'])) + $feeds ++; + } + } + logger('import step 8'); + $_SESSION['import_step'] = 8; + ref_session_write(session_id(), serialize($_SESSION)); + } + + + + if($completed < 9) { + $groups = $data['group']; + if($groups) { + $saved = array(); + foreach($groups as $group) { + $saved[$group['hash']] = array('old' => $group['id']); + unset($group['id']); + $group['uid'] = $channel['channel_id']; + dbesc_array($group); + $r = dbq("INSERT INTO groups (`" + . implode("`, `", array_keys($group)) + . "`) VALUES ('" + . implode("', '", array_values($group)) + . "')" ); + } + $r = q("select * from `groups` where uid = %d", + intval($channel['channel_id']) + ); + if($r) { + foreach($r as $rr) { + $saved[$rr['hash']]['new'] = $rr['id']; + } + } + } + + + $group_members = $data['group_member']; + if($group_members) { + foreach($group_members as $group_member) { + unset($group_member['id']); + $group_member['uid'] = $channel['channel_id']; + foreach($saved as $x) { + if($x['old'] == $group_member['gid']) + $group_member['gid'] = $x['new']; + } + dbesc_array($group_member); + $r = dbq("INSERT INTO group_member (`" + . implode("`, `", array_keys($group_member)) + . "`) VALUES ('" + . implode("', '", array_values($group_member)) + . "')" ); + } + } + logger('import step 9'); + $_SESSION['import_step'] = 9; + ref_session_write(session_id(), serialize($_SESSION)); + } + + $saved_notification_flags = notifications_off($channel['channel_id']); + + if($import_posts && array_key_exists('item',$data) && $data['item']) { + + foreach($data['item'] as $i) { + $item = get_item_elements($i); + + $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", + dbesc($item['mid']), + intval($channel['channel_id']) + ); + if($r) { + if($item['edited'] > $r[0]['edited']) { + $item['id'] = $r[0]['id']; + $item['uid'] = $channel['channel_id']; + item_store_update($item); + continue; + } + } + else { + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item_result = item_store($item); + } + + } + + } + + notifications_on($channel['channel_id'],$saved_notification_flags); + + if(array_key_exists('item_id',$data) && $data['item_id']) { + foreach($data['item_id'] as $i) { + $r = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($i['mid']), + intval($channel['channel_id']) + ); + if(! $r) + continue; + $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", + dbesc($i['service']), + dbesc($i['sid']), + intval($r[0]['id']), + intval($channel['channel_id']) + ); + if(! $z) { + q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", + intval($r[0]['id']), + intval($channel['channel_id']), + dbesc($i['sid']), + dbesc($i['service']) + ); + } + } + } + + + +// FIXME - ensure we have a self entry if somebody is trying to pull a fast one + + // send out refresh requests + // notify old server that it may no longer be primary. + + proc_run('php','include/notifier.php','location',$channel['channel_id']); + + // This will indirectly perform a refresh_all *and* update the directory + + proc_run('php', 'include/directory.php', $channel['channel_id']); + + + notice( t('Import completed.') . EOL); + + change_channel($channel['channel_id']); + + unset($_SESSION['import_step']); + goaway(z_root() . '/network' ); + +} + + +function import_content(&$a) { + + if(! get_account_id()) { + notice( t('You must be logged in to use this feature.')); + return ''; + } + + $o = replace_macros(get_markup_template('channel_import.tpl'),array( + '$title' => t('Import Channel'), + '$desc' => t('Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file.'), + '$label_filename' => t('File to Upload'), + '$choice' => t('Or provide the old server/hub details'), + '$label_old_address' => t('Your old identity address (xyz@example.com)'), + '$label_old_email' => t('Your old login email address'), + '$label_old_pass' => t('Your old login password'), + '$common' => t('For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media.'), + '$label_import_primary' => t('Make this hub my primary location'), + '$label_import_posts' => t('Import existing posts if possible (experimental - limited by available memory'), + '$pleasewait' => t('This process may take several minutes to complete. Please submit the form only once and leave this page open until finished.'), + '$email' => '', + '$pass' => '', + '$submit' => t('Submit') + )); + + return $o; + +} diff --git a/sources/mod/import_items.php b/sources/mod/import_items.php new file mode 100644 index 00000000..1e54c0de --- /dev/null +++ b/sources/mod/import_items.php @@ -0,0 +1,172 @@ + $email . ':' . $password); + $url = $scheme . $servername . $api_path; + $ret = z_fetch_url($url, $binary, $redirects, $opts); + if(! $ret['success']) + $ret = z_fetch_url('http://' . $servername . $api_path, $binary, $redirects, $opts); + if($ret['success']) + $data = $ret['body']; + else + notice( t('Unable to download data from old server') . EOL); + + } + + if(! $data) { + logger('mod_import: empty file.'); + notice( t('Imported file is empty.') . EOL); + return; + } + + $data = json_decode($data,true); + +// logger('import: data: ' . print_r($data,true)); +// print_r($data); + + + if(array_key_exists('compatibility',$data) && array_key_exists('database',$data['compatibility'])) { + $v1 = substr($data['compatibility']['database'],-4); + $v2 = substr(DB_UPDATE_VERSION,-4); + if($v2 > $v1) { + $t = sprintf( t('Warning: Database versions differ by %1$d updates.'), $v2 - $v1 ); + notice($t); + } + } + + $channel = $a->get_channel(); + + $saved_notification_flags = notifications_off($channel['channel_id']); + + if(array_key_exists('item',$data) && $data['item']) { + + foreach($data['item'] as $i) { + $item = get_item_elements($i); + + $r = q("select id, edited from item where mid = '%s' and uid = %d limit 1", + dbesc($item['mid']), + intval($channel['channel_id']) + ); + if($r) { + if($item['edited'] > $r[0]['edited']) { + $item['id'] = $r[0]['id']; + $item['uid'] = $channel['channel_id']; + item_store_update($item); + continue; + } + } + else { + $item['aid'] = $channel['channel_account_id']; + $item['uid'] = $channel['channel_id']; + $item_result = item_store($item); + } + + } + + } + + notifications_on($channel['channel_id'],$saved_notification_flags); + + if(array_key_exists('item_id',$data) && $data['item_id']) { + foreach($data['item_id'] as $i) { + $r = q("select id from item where mid = '%s' and uid = %d limit 1", + dbesc($i['mid']), + intval($channel['channel_id']) + ); + if(! $r) + continue; + $z = q("select * from item_id where service = '%s' and sid = '%s' and iid = %d and uid = %d limit 1", + dbesc($i['service']), + dbesc($i['sid']), + intval($r[0]['id']), + intval($channel['channel_id']) + ); + if(! $z) { + q("insert into item_id (iid,uid,sid,service) values(%d,%d,'%s','%s')", + intval($r[0]['id']), + intval($channel['channel_id']), + dbesc($i['sid']), + dbesc($i['service']) + ); + } + } + } + + info( t('Import completed') . EOL); + return; +} + + + + +function import_items_content(&$a) { + + + + + if(! local_channel()) { + notice( t('Permission denied') . EOL); + return login(); + } + + $o = replace_macros(get_markup_template('item_import.tpl'),array( + '$title' => t('Import Items'), + '$desc' => t('Use this form to import existing posts and content from an export file.'), + '$label_filename' => t('File to Upload'), + '$submit' => t('Submit') + )); + + return $o; + +} + + diff --git a/sources/mod/invite.php b/sources/mod/invite.php new file mode 100644 index 00000000..1fdfbacc --- /dev/null +++ b/sources/mod/invite.php @@ -0,0 +1,146 @@ + $max_invites) { + notice( t('Total invitation limit exceeded.') . EOL); + return; + }; + + + $recips = ((x($_POST,'recipients')) ? explode("\n",$_POST['recipients']) : array()); + $message = ((x($_POST,'message')) ? notags(trim($_POST['message'])) : ''); + + $total = 0; + + if(get_config('system','invitation_only')) { + $invonly = true; + $x = get_pconfig(local_channel(),'system','invites_remaining'); + if((! $x) && (! is_site_admin())) + return; + } + + foreach($recips as $recip) { + + $recip = trim($recip); + if(! $recip) + continue; + + if(! valid_email($recip)) { + notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL); + continue; + } + + if($invonly && ($x || is_site_admin())) { + $code = autoname(8) . srand(1000,9999); + $nmessage = str_replace('$invite_code',$code,$message); + + $r = q("INSERT INTO `register` (`hash`,`created`) VALUES ('%s', '%s') ", + dbesc($code), + dbesc(datetime_convert()) + ); + + if(! is_site_admin()) { + $x --; + if($x >= 0) + set_pconfig(local_channel(),'system','invites_remaining',$x); + else + return; + } + } + else + $nmessage = $message; + + $account = $a->get_account(); + + + $res = mail($recip, sprintf( t('Please join us on Red'), $a->config['sitename']), + $nmessage, + "From: " . $account['account_email'] . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); + + if($res) { + $total ++; + $current_invites ++; + set_pconfig(local_channel(),'system','sent_invites',$current_invites); + if($current_invites > $max_invites) { + notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL); + return; + } + } + else { + notice( sprintf( t('%s : Message delivery failed.'), $recip) . EOL); + } + + } + notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL); + return; +} + + +function invite_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + $tpl = get_markup_template('invite.tpl'); + $invonly = false; + + if(get_config('system','invitation_only')) { + $invonly = true; + $x = get_pconfig(local_channel(),'system','invites_remaining'); + if((! $x) && (! is_site_admin())) { + notice( t('You have no more invitations available') . EOL); + return ''; + } + } + + + $ob = $a->get_observer(); + if(! $ob) + return $o; + + $channel = $a->get_channel(); + + $o = replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("send_invite"), + '$invite' => t('Send invitations'), + '$addr_text' => t('Enter email addresses, one per line:'), + '$msg_text' => t('Your message:'), + '$default_message' => t('Please join my community on $Projectname.') . "\r\n" . "\r\n" + . $linktxt + . (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code: ') . $invite_code . "\r\n" . "\r\n" : '') + . t('1. Register at any $Projectname location (they are all inter-connected)') + . "\r\n" . "\r\n" . z_root() . '/register' + . "\r\n" . "\r\n" . t('2. Enter my $Projectname network address into the site searchbar.') + . "\r\n" . "\r\n" . $ob['xchan_addr'] . ' (' . t('or visit ') . z_root() . '/channel/' . $channel['channel_address'] . ')' + . "\r\n" . "\r\n" + . t('3. Click [Connect]') + . "\r\n" . "\r\n" , + '$submit' => t('Submit') + )); + + return $o; +} \ No newline at end of file diff --git a/sources/mod/item.php b/sources/mod/item.php new file mode 100644 index 00000000..ff6a834e --- /dev/null +++ b/sources/mod/item.php @@ -0,0 +1,1203 @@ + 1); + echo json_encode($json); + killme(); + } + + call_hooks('post_local_start', $_REQUEST); + +// logger('postvars ' . print_r($_REQUEST,true), LOGGER_DATA); + + $api_source = ((x($_REQUEST,'api_source') && $_REQUEST['api_source']) ? true : false); + + $consensus = intval($_REQUEST['consensus']); + + // 'origin' (if non-zero) indicates that this network is where the message originated, + // for the purpose of relaying comments to other conversation members. + // If using the API from a device (leaf node) you must set origin to 1 (default) or leave unset. + // If the API is used from another network with its own distribution + // and deliveries, you may wish to set origin to 0 or false and allow the other + // network to relay comments. + + // If you are unsure, it is prudent (and important) to leave it unset. + + $origin = (($api_source && array_key_exists('origin',$_REQUEST)) ? intval($_REQUEST['origin']) : 1); + + // To represent message-ids on other networks - this will create an item_id record + + $namespace = (($api_source && array_key_exists('namespace',$_REQUEST)) ? strip_tags($_REQUEST['namespace']) : ''); + $remote_id = (($api_source && array_key_exists('remote_id',$_REQUEST)) ? strip_tags($_REQUEST['remote_id']) : ''); + + $owner_hash = null; + + $message_id = ((x($_REQUEST,'message_id') && $api_source) ? strip_tags($_REQUEST['message_id']) : ''); + $created = ((x($_REQUEST,'created')) ? datetime_convert('UTC','UTC',$_REQUEST['created']) : datetime_convert()); + $post_id = ((x($_REQUEST,'post_id')) ? intval($_REQUEST['post_id']) : 0); + $app = ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''); + $return_path = ((x($_REQUEST,'return')) ? $_REQUEST['return'] : ''); + $preview = ((x($_REQUEST,'preview')) ? intval($_REQUEST['preview']) : 0); + $categories = ((x($_REQUEST,'category')) ? escape_tags($_REQUEST['category']) : ''); + $webpage = ((x($_REQUEST,'webpage')) ? intval($_REQUEST['webpage']) : 0); + $pagetitle = ((x($_REQUEST,'pagetitle')) ? escape_tags(urlencode($_REQUEST['pagetitle'])) : ''); + $layout_mid = ((x($_REQUEST,'layout_mid')) ? escape_tags($_REQUEST['layout_mid']): ''); + $plink = ((x($_REQUEST,'permalink')) ? escape_tags($_REQUEST['permalink']) : ''); + $obj_type = ((x($_REQUEST,'obj_type')) ? escape_tags($_REQUEST['obj_type']) : ACTIVITY_OBJ_NOTE); + + // allow API to bulk load a bunch of imported items with sending out a bunch of posts. + $nopush = ((x($_REQUEST,'nopush')) ? intval($_REQUEST['nopush']) : 0); + + /* + * Check service class limits + */ + if ($uid && !(x($_REQUEST,'parent')) && !(x($_REQUEST,'post_id'))) { + $ret = item_check_service_class($uid,(($_REQUEST['webpage'] == ITEM_TYPE_WEBPAGE) ? true : false)); + if (!$ret['success']) { + notice( t($ret['message']) . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + + if($pagetitle) { + require_once('library/urlify/URLify.php'); + $pagetitle = strtolower(URLify::transliterate($pagetitle)); + } + + + $item_flags = $item_restrict = 0; + + $route = ''; + $parent_item = null; + $parent_contact = null; + $thr_parent = ''; + $parid = 0; + $r = false; + + if($parent || $parent_mid) { + + if(! x($_REQUEST,'type')) + $_REQUEST['type'] = 'net-comment'; + + if($obj_type == ACTIVITY_OBJ_POST) + $obj_type = ACTIVITY_OBJ_COMMENT; + + if($parent) { + $r = q("SELECT * FROM `item` WHERE `id` = %d LIMIT 1", + intval($parent) + ); + } + elseif($parent_mid && $uid) { + // This is coming from an API source, and we are logged in + $r = q("SELECT * FROM `item` WHERE `mid` = '%s' AND `uid` = %d LIMIT 1", + dbesc($parent_mid), + intval($uid) + ); + } + // if this isn't the real parent of the conversation, find it + if($r !== false && count($r)) { + $parid = $r[0]['parent']; + $parent_mid = $r[0]['mid']; + if($r[0]['id'] != $r[0]['parent']) { + $r = q("SELECT * FROM `item` WHERE `id` = `parent` AND `parent` = %d LIMIT 1", + intval($parid) + ); + } + } + + if(($r === false) || (! count($r))) { + notice( t('Unable to locate original post.') . EOL); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + + // can_comment_on_post() needs info from the following xchan_query + xchan_query($r); + + $parent_item = $r[0]; + $parent = $r[0]['id']; + + // multi-level threading - preserve the info but re-parent to our single level threading + + $thr_parent = $parent_mid; + + $route = $parent_item['route']; + + } + + if(! $observer) + $observer = $a->get_observer(); + + if($parent) { + logger('mod_item: item_post parent=' . $parent); + $can_comment = false; + if((array_key_exists('owner',$parent_item)) && intval($parent_item['owner']['abook_self'])) + $can_comment = perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_comments'); + else + $can_comment = can_comment_on_post($observer['xchan_hash'],$parent_item); + + if(! $can_comment) { + notice( t('Permission denied.') . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + else { + if(! perm_is_allowed($profile_uid,$observer['xchan_hash'],'post_wall')) { + notice( t('Permission denied.') . EOL) ; + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + + + // is this an edited post? + + $orig_post = null; + + if($namespace && $remote_id) { + // It wasn't an internally generated post - see if we've got an item matching this remote service id + $i = q("select iid from item_id where service = '%s' and sid = '%s' limit 1", + dbesc($namespace), + dbesc($remote_id) + ); + if($i) + $post_id = $i[0]['iid']; + } + + if($post_id) { + $i = q("SELECT * FROM `item` WHERE `uid` = %d AND `id` = %d LIMIT 1", + intval($profile_uid), + intval($post_id) + ); + if(! count($i)) + killme(); + $orig_post = $i[0]; + } + + + if(! $channel) { + if($uid && $uid == $profile_uid) { + $channel = $a->get_channel(); + } + else { + // posting as yourself but not necessarily to a channel you control + $r = q("select * from channel left join account on channel_account_id = account_id where channel_id = %d LIMIT 1", + intval($profile_uid) + ); + if($r) + $channel = $r[0]; + } + } + + + if(! $channel) { + logger("mod_item: no channel."); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + + $owner_xchan = null; + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($channel['channel_hash']) + ); + if($r && count($r)) { + $owner_xchan = $r[0]; + } + else { + logger("mod_item: no owner."); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + + $walltowall = false; + $walltowall_comment = false; + + if($remote_xchan) + $observer = $remote_observer; + + if($observer) { + logger('mod_item: post accepted from ' . $observer['xchan_name'] . ' for ' . $owner_xchan['xchan_name'], LOGGER_DEBUG); + + // wall-to-wall detection. + // For top-level posts, if the author and owner are different it's a wall-to-wall + // For comments, We need to additionally look at the parent and see if it's a wall post that originated locally. + + if($observer['xchan_name'] != $owner_xchan['xchan_name']) { + if(($parent_item) && ($parent_item['item_wall'] && $parent_item['item_origin'])) { + $walltowall_comment = true; + $walltowall = true; + } + if(! $parent) { + $walltowall = true; + } + } + } + + + $public_policy = ((x($_REQUEST,'public_policy')) ? escape_tags($_REQUEST['public_policy']) : map_scope($channel['channel_r_stream'],true)); + if($webpage) + $public_policy = ''; + if($public_policy) + $private = 1; + + if($orig_post) { + $private = 0; + // webpages are allowed to change ACLs after the fact. Normal conversation items aren't. + if($webpage) { + $str_group_allow = perms2str($_REQUEST['group_allow']); + $str_contact_allow = perms2str($_REQUEST['contact_allow']); + $str_group_deny = perms2str($_REQUEST['group_deny']); + $str_contact_deny = perms2str($_REQUEST['contact_deny']); + } + else { + $str_group_allow = $orig_post['allow_gid']; + $str_contact_allow = $orig_post['allow_cid']; + $str_group_deny = $orig_post['deny_gid']; + $str_contact_deny = $orig_post['deny_cid']; + $public_policy = $orig_post['public_policy']; + $private = $orig_post['item_private']; + } + + if((strlen($str_group_allow)) + || strlen($str_contact_allow) + || strlen($str_group_deny) + || strlen($str_contact_deny) + || strlen($public_policy) + || $private) { + $private = 1; + } + + $location = $orig_post['location']; + $coord = $orig_post['coord']; + $verb = $orig_post['verb']; + $app = $orig_post['app']; + $title = escape_tags(trim($_REQUEST['title'])); + $body = trim($_REQUEST['body']); + $item_flags = $orig_post['item_flags']; + + $item_origin = $orig_post['item_origin']; + $item_unseen = $orig_post['item_unseen']; + $item_starred = $orig_post['item_starred']; + $item_uplink = $orig_post['item_uplink']; + $item_consensus = $orig_post['item_consensus']; + $item_wall = $orig_post['item_wall']; + $item_thread_top = $orig_post['item_thread_top']; + $item_notshown = $orig_post['item_notshown']; + $item_nsfw = $orig_post['item_nsfw']; + $item_relay = $orig_post['item_relay']; + $item_mentionsme = $orig_post['item_mentionsme']; + $item_nocomment = $orig_post['item_nocomment']; + $item_obscured = $orig_post['item_obscured']; + $item_verified = $orig_post['item_verified']; + $item_retained = $orig_post['item_retained']; + $item_rss = $orig_post['item_rss']; + $item_deleted = $orig_post['item_deleted']; + $item_type = $orig_post['item_type']; + $item_hidden = $orig_post['item_hidden']; + $item_unpublished = $orig_post['item_unpublished']; + $item_delayed = $orig_post['item_delayed']; + $item_pending_remove = $orig_post['item_pending_remove']; + $item_blocked = $orig_post['item_blocked']; + + + + $postopts = $orig_post['postopts']; + $created = $orig_post['created']; + $mid = $orig_post['mid']; + $parent_mid = $orig_post['parent_mid']; + $plink = $orig_post['plink']; + + } + else { + + // if coming from the API and no privacy settings are set, + // use the user default permissions - as they won't have + // been supplied via a form. + + if(($api_source) + && (! array_key_exists('contact_allow',$_REQUEST)) + && (! array_key_exists('group_allow',$_REQUEST)) + && (! array_key_exists('contact_deny',$_REQUEST)) + && (! array_key_exists('group_deny',$_REQUEST))) { + $str_group_allow = $channel['channel_allow_gid']; + $str_contact_allow = $channel['channel_allow_cid']; + $str_group_deny = $channel['channel_deny_gid']; + $str_contact_deny = $channel['channel_deny_cid']; + } + elseif($walltowall) { + + // use the channel owner's default permissions + + $str_group_allow = $channel['channel_allow_gid']; + $str_contact_allow = $channel['channel_allow_cid']; + $str_group_deny = $channel['channel_deny_gid']; + $str_contact_deny = $channel['channel_deny_cid']; + } + else { + + // use the posted permissions + + $str_group_allow = perms2str($_REQUEST['group_allow']); + $str_contact_allow = perms2str($_REQUEST['contact_allow']); + $str_group_deny = perms2str($_REQUEST['group_deny']); + $str_contact_deny = perms2str($_REQUEST['contact_deny']); + } + + + $location = notags(trim($_REQUEST['location'])); + $coord = notags(trim($_REQUEST['coord'])); + $verb = notags(trim($_REQUEST['verb'])); + $title = escape_tags(trim($_REQUEST['title'])); + $body = trim($_REQUEST['body']); + $body .= trim($_REQUEST['attachment']); + $postopts = ''; + + $private = ( + ( strlen($str_group_allow) + || strlen($str_contact_allow) + || strlen($str_group_deny) + || strlen($str_contact_deny) + || strlen($public_policy) + ) ? 1 : 0); + + // If this is a comment, set the permissions from the parent. + + if($parent_item) { + $private = 0; + + if(($parent_item['item_private']) + || strlen($parent_item['allow_cid']) + || strlen($parent_item['allow_gid']) + || strlen($parent_item['deny_cid']) + || strlen($parent_item['deny_gid']) + || strlen($parent_item['public_policy'])) { + $private = (($parent_item['item_private']) ? $parent_item['item_private'] : 1); + } + + $public_policy = $parent_item['public_policy']; + $str_contact_allow = $parent_item['allow_cid']; + $str_group_allow = $parent_item['allow_gid']; + $str_contact_deny = $parent_item['deny_cid']; + $str_group_deny = $parent_item['deny_gid']; + $owner_hash = $parent_item['owner_xchan']; + } + + if(! strlen($body)) { + if($preview) + killme(); + info( t('Empty post discarded.') . EOL ); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + + + $expires = NULL_DATE; + + if(feature_enabled($profile_uid,'content_expire')) { + if(x($_REQUEST,'expire')) { + $expires = datetime_convert(date_default_timezone_get(),'UTC', $_REQUEST['expire']); + if($expires <= datetime_convert()) + $expires = NULL_DATE; + } + } + + $mimetype = notags(trim($_REQUEST['mimetype'])); + if(! $mimetype) + $mimetype = 'text/bbcode'; + + if($preview) { + $body = z_input_filter($profile_uid,$body,$mimetype); + } + + + // Verify ability to use html or php!!! + + $execflag = false; + + if($mimetype === 'application/x-php') { + $z = q("select account_id, account_roles, channel_pageflags from account left join channel on channel_account_id = account_id where channel_id = %d limit 1", + intval($profile_uid) + ); + if($z && (($z[0]['account_roles'] & ACCOUNT_ROLE_ALLOWCODE) || ($z[0]['channel_pageflags'] & PAGE_ALLOWCODE))) { + if($uid && (get_account_id() == $z[0]['account_id'])) { + $execflag = true; + } + else { + notice( t('Executable content type not permitted to this channel.') . EOL); + if(x($_REQUEST,'return')) + goaway($a->get_baseurl() . "/" . $return_path ); + killme(); + } + } + } + + + if($mimetype === 'text/bbcode') { + + require_once('include/text.php'); + if($uid && $uid == $profile_uid && feature_enabled($uid,'markdown')) { + require_once('include/bb2diaspora.php'); + $body = escape_tags($body); + $body = preg_replace_callback('/\[share(.*?)\]/ism','share_shield',$body); + $body = diaspora2bb($body,true); + $body = preg_replace_callback('/\[share(.*?)\]/ism','share_unshield',$body); + } + + // BBCODE alert: the following functions assume bbcode input + // and will require alternatives for alternative content-types (text/html, text/markdown, text/plain, etc.) + // we may need virtual or template classes to implement the possible alternatives + + // Work around doubled linefeeds in Tinymce 3.5b2 + // First figure out if it's a status post that would've been + // created using tinymce. Otherwise leave it alone. + + $plaintext = true; + +// $plaintext = ((feature_enabled($profile_uid,'richtext')) ? false : true); +// if((! $parent) && (! $api_source) && (! $plaintext)) { +// $body = fix_mce_lf($body); +// } + + + + // If we're sending a private top-level message with a single @-taggable channel as a recipient, @-tag it, if our pconfig is set. + + + if((! $parent) && (get_pconfig($profile_uid,'system','tagifonlyrecip')) && (substr_count($str_contact_allow,'<') == 1) && ($str_group_allow == '') && ($str_contact_deny == '') && ($str_group_deny == '')) { + $x = q("select abook_id, abook_their_perms from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc(str_replace(array('<','>'),array('',''),$str_contact_allow)), + intval($profile_uid) + ); + if($x && ($x[0]['abook_their_perms'] & PERMS_W_TAGWALL)) + $body .= "\n\n@group+" . $x[0]['abook_id'] . "\n"; + } + + /** + * fix naked links by passing through a callback to see if this is a red site + * (already known to us) which will get a zrl, otherwise link with url, add bookmark tag to both. + * First protect any url inside certain bbcode tags so we don't double link it. + */ + + + $body = preg_replace_callback('/\[code(.*?)\[\/(code)\]/ism','red_escape_codeblock',$body); + $body = preg_replace_callback('/\[url(.*?)\[\/(url)\]/ism','red_escape_codeblock',$body); + $body = preg_replace_callback('/\[zrl(.*?)\[\/(zrl)\]/ism','red_escape_codeblock',$body); + + $body = preg_replace_callback("/([^\]\='".'"'."\/]|^|\#\^)(https?\:\/\/[a-zA-Z0-9\:\/\-\?\&\;\.\=\@\_\~\#\%\$\!\+\,]+)/ism", 'red_zrl_callback', $body); + + $body = preg_replace_callback('/\[\$b64zrl(.*?)\[\/(zrl)\]/ism','red_unescape_codeblock',$body); + $body = preg_replace_callback('/\[\$b64url(.*?)\[\/(url)\]/ism','red_unescape_codeblock',$body); + $body = preg_replace_callback('/\[\$b64code(.*?)\[\/(code)\]/ism','red_unescape_codeblock',$body); + + + // fix any img tags that should be zmg + + $body = preg_replace_callback('/\[img(.*?)\](.*?)\[\/img\]/ism','red_zrlify_img_callback',$body); + + + + + + $body = bb_translate_video($body); + + /** + * Fold multi-line [code] sequences + */ + + $body = preg_replace('/\[\/code\]\s*\[code\]/ism',"\n",$body); + + $body = scale_external_images($body,false); + + + // Look for tags and linkify them + $results = linkify_tags($a, $body, ($uid) ? $uid : $profile_uid); + + if($results) { + + // Set permissions based on tag replacements + set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private); + + $post_tags = array(); + foreach($results as $result) { + $success = $result['success']; + if($success['replaced']) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + } + } + + + /** + * + * When a photo was uploaded into the message using the (profile wall) ajax + * uploader, The permissions are initially set to disallow anybody but the + * owner from seeing it. This is because the permissions may not yet have been + * set for the post. If it's private, the photo permissions should be set + * appropriately. But we didn't know the final permissions on the post until + * now. So now we'll look for links of uploaded photos and attachments that are in the + * post and set them to the same permissions as the post itself. + * + * If the post was end-to-end encrypted we can't find images and attachments in the body, + * use our media_str input instead which only contains these elements - but only do this + * when encrypted content exists because the photo/attachment may have been removed from + * the post and we should keep it private. If it's encrypted we have no way of knowing + * so we'll set the permissions regardless and realise that the media may not be + * referenced in the post. + * + * What is preventing us from being able to upload photos into comments is dealing with + * the photo and attachment permissions, since we don't always know who was in the + * distribution for the top level post. + * + * We might be able to provide this functionality with a lot of fiddling: + * - if the top level post is public (make the photo public) + * - if the top level post was written by us or a wall post that belongs to us (match the top level post) + * - if the top level post has privacy mentions, add those to the permissions. + * - otherwise disallow the photo *or* make the photo public. This is the part that gets messy. + */ + + if(! $preview) { + fix_attached_photo_permissions($profile_uid,$owner_xchan['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + + fix_attached_file_permissions($channel,$observer['xchan_hash'],((strpos($body,'[/crypt]')) ? $_POST['media_str'] : $body),$str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny); + + } + + + $attachments = ''; + $match = false; + + if(preg_match_all('/(\[attachment\](.*?)\[\/attachment\])/',$body,$match)) { + $attachments = array(); + foreach($match[2] as $mtch) { + $attach_link = ''; + $hash = substr($mtch,0,strpos($mtch,',')); + $rev = intval(substr($mtch,strpos($mtch,','))); + $r = attach_by_hash_nodata($hash,$rev); + if($r['success']) { + $attachments[] = array( + 'href' => $a->get_baseurl() . '/attach/' . $r['data']['hash'], + 'length' => $r['data']['filesize'], + 'type' => $r['data']['filetype'], + 'title' => urlencode($r['data']['filename']), + 'revision' => $r['data']['revision'] + ); + } + $ext = substr($r['data']['filename'],strrpos($r['data']['filename'],'.')); + if(strpos($r['data']['filetype'],'audio/') !== false) + $attach_link = '[audio]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/audio]'; + elseif(strpos($r['data']['filetype'],'video/') !== false) + $attach_link = '[video]' . z_root() . '/attach/' . $r['data']['hash'] . '/' . $r['data']['revision'] . (($ext) ? $ext : '') . '[/video]'; + $body = str_replace($match[1],$attach_link,$body); + } + } + + } + +// BBCODE end alert + + if(strlen($categories)) { + $cats = explode(',',$categories); + foreach($cats as $cat) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => TERM_CATEGORY, + 'otype' => TERM_OBJ_POST, + 'term' => trim($cat), + 'url' => $owner_xchan['xchan_url'] . '?f=&cat=' . urlencode(trim($cat)) + ); + } + } + + + $item_unseen = ((local_channel() != $profile_uid) ? 1 : 0); + $item_wall = (($post_type === 'wall' || $post_type === 'wall-comment') ? 1 : 0); + $item_origin = (($origin) ? 1 : 0); + + + // determine if this is a wall post + + if($parent) { + $item_wall = $parent_item['item_wall']; + } + else { + if(! $webpage) { + $item_wall = 1; + } + } + + + if($moderated) + $item_blocked = ITEM_MODERATED; + + + if(! strlen($verb)) + $verb = ACTIVITY_POST ; + + $notify_type = (($parent) ? 'comment-new' : 'wall-new' ); + + if(! $mid) { + $mid = (($message_id) ? $message_id : item_message_id()); + } + if(! $parent_mid) { + $parent_mid = $mid; + } + + if($parent_item) + $parent_mid = $parent_item['mid']; + + // Fallback so that we alway have a thr_parent + + if(!$thr_parent) + $thr_parent = $mid; + + $datarray = array(); + + $item_thead_top = ((! $parent) ? 1 : 0); + + + if ((! $plink) && ($item_thread_top)) { + $plink = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $mid; + } + + $datarray['aid'] = $channel['channel_account_id']; + $datarray['uid'] = $profile_uid; + + $datarray['owner_xchan'] = (($owner_hash) ? $owner_hash : $owner_xchan['xchan_hash']); + $datarray['author_xchan'] = $observer['xchan_hash']; + $datarray['created'] = $created; + $datarray['edited'] = (($orig_post) ? datetime_convert() : $created); + $datarray['expires'] = $expires; + $datarray['commented'] = (($orig_post) ? datetime_convert() : $created); + $datarray['received'] = (($orig_post) ? datetime_convert() : $created); + $datarray['changed'] = (($orig_post) ? datetime_convert() : $created); + $datarray['mid'] = $mid; + $datarray['parent_mid'] = $parent_mid; + $datarray['mimetype'] = $mimetype; + $datarray['title'] = $title; + $datarray['body'] = $body; + $datarray['app'] = $app; + $datarray['location'] = $location; + $datarray['coord'] = $coord; + $datarray['verb'] = $verb; + $datarray['obj_type'] = $obj_type; + $datarray['allow_cid'] = $str_contact_allow; + $datarray['allow_gid'] = $str_group_allow; + $datarray['deny_cid'] = $str_contact_deny; + $datarray['deny_gid'] = $str_group_deny; + $datarray['item_private'] = $private; + $datarray['item_wall'] = $item_wall; + $datarray['attach'] = $attachments; + $datarray['thr_parent'] = $thr_parent; + $datarray['postopts'] = $postopts; + $datarray['item_unseen'] = $item_unseen; + $datarray['item_wall'] = $item_wall; + $datarray['item_origin'] = $item_origin; + $datarray['item_type'] = $webpage; + $datarray['item_thread_top'] = $item_thread_top; + $datarray['item_unseen'] = $item_unseen; + $datarray['item_starred'] = $item_starred; + $datarray['item_uplink'] = $item_uplink; + $datarray['item_consensus'] = $item_consensus; + $datarray['item_notshown'] = $item_notshown; + $datarray['item_nsfw'] = $item_nsfw; + $datarray['item_relay'] = $item_relay; + $datarray['item_mentionsme'] = $item_mentionsme; + $datarray['item_nocomment'] = $item_nocomment; + $datarray['item_obscured'] = $item_obscured; + $datarray['item_verified'] = $item_verified; + $datarray['item_retained'] = $item_retained; + $datarray['item_rss'] = $item_rss; + $datarray['item_deleted'] = $item_deleted; + $datarray['item_hidden'] = $item_hidden; + $datarray['item_unpublished'] = $item_unpublished; + $datarray['item_delayed'] = $item_delayed; + $datarray['item_pending_remove'] = $item_pending_remove; + $datarray['item_blocked'] = $item_blocked; + + $datarray['layout_mid'] = $layout_mid; + $datarray['public_policy'] = $public_policy; + $datarray['comment_policy'] = map_scope($channel['channel_w_comment']); + $datarray['term'] = $post_tags; + $datarray['plink'] = $plink; + $datarray['route'] = $route; + + // preview mode - prepare the body for display and send it via json + + if($preview) { + require_once('include/conversation.php'); + + $datarray['owner'] = $owner_xchan; + $datarray['author'] = $observer; + $datarray['attach'] = json_encode($datarray['attach']); + $o = conversation($a,array($datarray),'search',false,'preview'); +// logger('preview: ' . $o, LOGGER_DEBUG); + echo json_encode(array('preview' => $o)); + killme(); + } + if($orig_post) + $datarray['edit'] = true; + + call_hooks('post_local',$datarray); + + if(x($datarray,'cancel')) { + logger('mod_item: post cancelled by plugin.'); + if($return_path) { + goaway($a->get_baseurl() . "/" . $return_path); + } + + $json = array('cancel' => 1); + if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload'])) + $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload']; + + echo json_encode($json); + killme(); + } + + + if(mb_strlen($datarray['title']) > 255) + $datarray['title'] = mb_substr($datarray['title'],0,255); + + if(array_key_exists('item_private',$datarray) && $datarray['item_private']) { + + $datarray['body'] = trim(z_input_filter($datarray['uid'],$datarray['body'],$datarray['mimetype'])); + + if($uid) { + if($channel['channel_hash'] === $datarray['author_xchan']) { + $datarray['sig'] = base64url_encode(rsa_sign($datarray['body'],$channel['channel_prvkey'])); + $datarray['item_verified'] = 1; + } + } + } + + if($orig_post) { + $datarray['id'] = $post_id; + + item_store_update($datarray,$execflag); + + update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid); + + if(! $nopush) + proc_run('php', "include/notifier.php", 'edit_post', $post_id); + + if((x($_REQUEST,'return')) && strlen($return_path)) { + logger('return: ' . $return_path); + goaway($a->get_baseurl() . "/" . $return_path ); + } + killme(); + } + else + $post_id = 0; + + $post = item_store($datarray,$execflag); + + $post_id = $post['item_id']; + + if($post_id) { + logger('mod_item: saved item ' . $post_id); + + if($parent) { + + // only send comment notification if this is a wall-to-wall comment, + // otherwise it will happen during delivery + + if(($datarray['owner_xchan'] != $datarray['author_xchan']) && (intval($parent_item['item_wall']))) { + notification(array( + 'type' => NOTIFY_COMMENT, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], + 'verb' => ACTIVITY_POST, + 'otype' => 'item', + 'parent' => $parent, + 'parent_mid' => $parent_item['mid'] + )); + + } + } + else { + $parent = $post_id; + + if($datarray['owner_xchan'] != $datarray['author_xchan']) { + notification(array( + 'type' => NOTIFY_WALL, + 'from_xchan' => $datarray['author_xchan'], + 'to_xchan' => $datarray['owner_xchan'], + 'item' => $datarray, + 'link' => $a->get_baseurl() . '/display/' . $datarray['mid'], + 'verb' => ACTIVITY_POST, + 'otype' => 'item' + )); + } + + if($uid && $uid == $profile_uid && (is_item_normal($datarray))) { + q("update channel set channel_lastpost = '%s' where channel_id = %d", + dbesc(datetime_convert()), + intval($uid) + ); + } + } + + // photo comments turn the corresponding item visible to the profile wall + // This way we don't see every picture in your new photo album posted to your wall at once. + // They will show up as people comment on them. + + if(intval($parent_item['item_hidden'])) { + $r = q("UPDATE item SET item_hidden = 0 WHERE id = %d", + intval($parent_item['id']) + ); + } + } + else { + logger('mod_item: unable to retrieve post that was just stored.'); + notice( t('System error. Post not saved.') . EOL); + goaway($a->get_baseurl() . "/" . $return_path ); + // NOTREACHED + } + + if($parent) { + // Store the comment signature information in case we need to relay to Diaspora + $ditem = $datarray; + $ditem['author'] = $observer; + store_diaspora_comment_sig($ditem,$channel,$parent_item, $post_id, (($walltowall_comment) ? 1 : 0)); + } + + update_remote_id($channel,$post_id,$webpage,$pagetitle,$namespace,$remote_id,$mid); + + $datarray['id'] = $post_id; + $datarray['llink'] = $a->get_baseurl() . '/display/' . $channel['channel_address'] . '/' . $post_id; + + call_hooks('post_local_end', $datarray); + + if(! $nopush) + proc_run('php', 'include/notifier.php', $notify_type, $post_id); + + logger('post_complete'); + + // figure out how to return, depending on from whence we came + + if($api_source) + return $post; + + if($return_path) { + goaway($a->get_baseurl() . "/" . $return_path); + } + + $json = array('success' => 1); + if(x($_REQUEST,'jsreload') && strlen($_REQUEST['jsreload'])) + $json['reload'] = $a->get_baseurl() . '/' . $_REQUEST['jsreload']; + + logger('post_json: ' . print_r($json,true), LOGGER_DEBUG); + + echo json_encode($json); + killme(); + // NOTREACHED +} + + + + + +function item_content(&$a) { + + if((! local_channel()) && (! remote_channel())) + return; + + require_once('include/security.php'); + + if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { + + require_once('include/items.php'); + $i = q("select id, uid, author_xchan, owner_xchan, source_xchan, item_type from item where id = %d limit 1", + intval(argv(2)) + ); + + if($i) { + $can_delete = false; + $local_delete = false; + if(local_channel() && local_channel() == $i[0]['uid']) + $local_delete = true; + + $sys = get_sys_channel(); + if(is_site_admin() && $sys['channel_id'] == $i[0]['uid']) + $can_delete = true; + + $ob_hash = get_observer_hash(); + if($ob_hash && ($ob_hash === $i[0]['author_xchan'] || $ob_hash === $i[0]['owner_xchan'] || $ob_hash === $i[0]['source_xchan'])) + $can_delete = true; + + if(! ($can_delete || $local_delete)) { + notice( t('Permission denied.') . EOL); + return; + } + + // if this is a different page type or it's just a local delete + // but not by the item author or owner, do a simple deletion + + if(intval($i[0]['item_type']) || ($local_delete && (! $can_delete))) { + drop_item($i[0]['id']); + } + else { + // complex deletion that needs to propagate and be performed in phases + drop_item($i[0]['id'],true,DROPITEM_PHASE1); + tag_deliver($i[0]['uid'],$i[0]['id']); + } + } + } +} + + +function fix_attached_photo_permissions($uid,$xchan_hash,$body, + $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { + + if(get_pconfig($uid,'system','force_public_uploads')) { + $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + } + + $match = null; + // match img and zmg image links + if(preg_match_all("/\[[zi]mg(.*?)\](.*?)\[\/[zi]mg\]/",$body,$match)) { + $images = $match[2]; + if($images) { + foreach($images as $image) { + if(! stristr($image,get_app()->get_baseurl() . '/photo/')) + continue; + $image_uri = substr($image,strrpos($image,'/') + 1); + if(strpos($image_uri,'-') !== false) + $image_uri = substr($image_uri,0, strpos($image_uri,'-')); + if(strpos($image_uri,'.') !== false) + $image_uri = substr($image_uri,0, strpos($image_uri,'.')); + if(! strlen($image_uri)) + continue; + $srch = '<' . $xchan_hash . '>'; + + $r = q("select folder from attach where hash = '%s' and uid = %d limit 1", + dbesc($image_uri), + intval($uid) + ); + if($r && $r[0]['folder']) { + $f = q("select * from attach where hash = '%s' and is_dir = 1 and uid = %d limit 1", + dbesc($r[0]['folder']), + intval($uid) + ); + if(($f) && (($f[0]['allow_cid']) || ($f[0]['allow_gid']) || ($f[0]['deny_cid']) || ($f[0]['deny_gid']))) { + $str_contact_allow = $f[0]['allow_cid']; + $str_group_allow = $f[0]['allow_gid']; + $str_contact_deny = $f[0]['deny_cid']; + $str_group_deny = $f[0]['deny_gid']; + } + } + + $r = q("SELECT id FROM photo + WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = '' + AND resource_id = '%s' AND uid = %d LIMIT 1", + dbesc($srch), + dbesc($image_uri), + intval($uid) + ); + + if($r) { + $r = q("UPDATE photo SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' + WHERE resource_id = '%s' AND uid = %d ", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + dbesc($image_uri), + intval($uid) + ); + + // also update the linked item (which is probably invisible) + + $r = q("select id from item + WHERE allow_cid = '%s' AND allow_gid = '' AND deny_cid = '' AND deny_gid = '' + AND resource_id = '%s' and resource_type = 'photo' AND uid = %d LIMIT 1", + dbesc($srch), + dbesc($image_uri), + intval($uid) + ); + if($r) { + $private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); + + $r = q("UPDATE item SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d + WHERE id = %d AND uid = %d", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval($private), + intval($r[0]['id']), + intval($uid) + ); + } + $r = q("select id from attach where hash = '%s' and uid = %d limit 1", + dbesc($image_uri), + intval($uid) + ); + if($r) { + q("update attach SET allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' + WHERE id = %d AND uid = %d", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval($r[0]['id']), + intval($uid) + ); + } + } + } + } + } +} + + +function fix_attached_file_permissions($channel,$observer_hash,$body, + $str_contact_allow,$str_group_allow,$str_contact_deny,$str_group_deny) { + + if(get_pconfig($channel['channel_id'],'system','force_public_uploads')) { + $str_contact_allow = $str_group_allow = $str_contact_deny = $str_group_deny = ''; + } + + $match = false; + + if(preg_match_all("/\[attachment\](.*?)\[\/attachment\]/",$body,$match)) { + $attaches = $match[1]; + if($attaches) { + foreach($attaches as $attach) { + $hash = substr($attach,0,strpos($attach,',')); + $rev = intval(substr($attach,strpos($attach,','))); + attach_store($channel,$observer_hash,$options = 'update', array( + 'hash' => $hash, + 'revision' => $rev, + 'allow_cid' => $str_contact_allow, + 'allow_gid' => $str_group_allow, + 'deny_cid' => $str_contact_deny, + 'deny_gid' => $str_group_deny + )); + } + } + } +} + +function item_check_service_class($channel_id,$iswebpage) { + $ret = array('success' => false, 'message' => ''); + + if ($iswebpage) { + $r = q("select count(i.id) as total from item i + right join channel c on (i.author_xchan=c.channel_hash and i.uid=c.channel_id ) + and i.parent=i.id and i.item_type = %d and i.item_deleted = 0 and i.uid= %d ", + intval(ITEM_TYPE_WEBPAGE), + intval($channel_id) + ); + } + else { + $r = q("select count(id) as total from item where parent = id and item_wall = 1 and uid = %d " . item_normal(), + intval($channel_id) + ); + } + + if(! $r) { + $ret['message'] = t('Unable to obtain post information from database.'); + return $ret; + } + + if (!$iswebpage) { + $max = service_class_fetch($channel_id,'total_items'); + if(! service_class_allows($channel_id,'total_items',$r[0]['total'])) { + $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f top level posts.'),$max); + return $result; + } + } + else { + $max = service_class_fetch($channel_id,'total_pages'); + if(! service_class_allows($channel_id,'total_pages',$r[0]['total'])) { + $result['message'] .= upgrade_message() . sprintf( t('You have reached your limit of %1$.0f webpages.'),$max); + return $result; + } + } + + $ret['success'] = true; + return $ret; +} + diff --git a/sources/mod/lang.php b/sources/mod/lang.php new file mode 100644 index 00000000..fba5f9c7 --- /dev/null +++ b/sources/mod/lang.php @@ -0,0 +1,6 @@ + 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $a->is_sys = true; + } + } + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($a,$which); + +} + + +function layouts_content(&$a) { + + if(! $a->profile) { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $which = argv(1); + + $_SESSION['return_url'] = $a->query_string; + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = $a->get_observer(); + + $channel = $a->get_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if(! $owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + // Block design features from visitors + + if((! $uid) || ($uid != $owner)) { + notice( t('Permission denied.') . EOL); + return; + } + + // Get the observer, check their permissions + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + //This feature is not exposed in redbasic ui since it is not clear why one would want to + //download a json encoded pdl file - we dont have a possibility to import it. + //Use the buildin share/install feature instead. + if((argc() > 3) && (argv(2) === 'share') && (argv(3))) { + $r = q("select sid, service, mimetype, title, body from item_id + left join item on item.id = item_id.iid + where item_id.uid = %d and item.mid = '%s' and service = 'PDL' order by sid asc", + intval($owner), + dbesc(argv(3)) + ); + if($r) { + header('Content-type: application/x-hubzilla-layout'); + header('Content-disposition: attachment; filename="' . $r[0]['sid'] . '.pdl"'); + echo json_encode($r); + killme(); + } + } + + // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages + // Nickname is set to the observers xchan, and profile_uid to the owners. + // This lets you post pages at other people's channels. + + $x = array( + 'webpage' => ITEM_TYPE_PDL, + 'is_owner' => true, + 'nickname' => $a->profile['channel_address'], + 'bang' => '', + 'showacl' => false, + 'visitor' => false, + 'nopreview' => 1, + 'ptlabel' => t('Layout Name'), + 'profile_uid' => intval($owner), + 'expanded' => true, + 'placeholdertitle' => t('Layout Description (Optional)'), + 'novoting' => true + ); + + if($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; + if($_REQUEST['pagetitle']) + $x['pagetitle'] = $_REQUEST['pagetitle']; + + $editor = status_editor($a,$x); + + $r = q("select iid, sid, mid, title, body, mimetype, created, edited, item_type from item_id left join item on item_id.iid = item.id + where item_id.uid = %d and service = 'PDL' and item_type = %d order by item.created desc", + intval($owner), + intval(ITEM_TYPE_PDL) + ); + + $pages = null; + + if($r) { + $pages = array(); + foreach($r as $rr) { + $element_arr = array( + 'type' => 'layout', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'pagetitle' => $rr['sid'], + 'mid' => $rr['mid'] + ); + $pages[$rr['iid']][] = array( + 'url' => $rr['iid'], + 'title' => $rr['sid'], + 'descr' => $rr['title'], + 'mid' => $rr['mid'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]' + ); + } + } + + //Build the base URL for edit links + $url = z_root() . '/editlayout/' . $which; + + $o .= replace_macros(get_markup_template('layoutlist.tpl'), array( + '$title' => t('Layouts'), + '$create' => t('Create'), + '$help' => array('text' => t('Help'), 'url' => 'help/comanche', 'title' => t('Comanche page description language help')), + '$editor' => $editor, + '$baseurl' => $url, + '$name' => t('Layout Name'), + '$descr' => t('Layout Description'), + '$created' => t('Created'), + '$edited' => t('Edited'), + '$edit' => t('Edit'), + '$share' => t('Share'), + '$download' => t('Download PDL file'), + '$pages' => $pages, + '$channel' => $which, + '$view' => t('View'), + )); + + return $o; +} diff --git a/sources/mod/like.php b/sources/mod/like.php new file mode 100755 index 00000000..9077adbd --- /dev/null +++ b/sources/mod/like.php @@ -0,0 +1,507 @@ +get_observer(); + $interactive = $_REQUEST['interactive']; + if($interactive) { + $o .= '

    ' . t('Like/Dislike') . '

    '; + $o .= EOL . EOL; + + if(! $observer) { + $_SESSION['return_url'] = $a->query_string; + $o .= t('This action is restricted to members.') . EOL; + $o .= t('Please login with your $Projectname ID or register as a new $Projectname member to continue.') . EOL; + return $o; + } + } + + $verb = notags(trim($_GET['verb'])); + + if(! $verb) + $verb = 'like'; + + switch($verb) { + case 'like': + case 'unlike': + $activity = ACTIVITY_LIKE; + break; + case 'dislike': + case 'undislike': + $activity = ACTIVITY_DISLIKE; + break; + case 'agree': + case 'unagree': + $activity = ACTIVITY_AGREE; + break; + case 'disagree': + case 'undisagree': + $activity = ACTIVITY_DISAGREE; + break; + case 'abstain': + case 'unabstain': + $activity = ACTIVITY_ABSTAIN; + break; + case 'attendyes': + case 'unattendyes': + $activity = ACTIVITY_ATTEND; + break; + case 'attendno': + case 'unattendno': + $activity = ACTIVITY_ATTENDNO; + break; + case 'attendmaybe': + case 'unattendmaybe': + $activity = ACTIVITY_ATTENDMAYBE; + break; + default: + return; + break; + } + + $extended_like = false; + $object = $target = null; + $post_type = ''; + $objtype = ''; + + if(argc() == 3) { + + if(! $observer) + killme(); + + $extended_like = true; + $obj_type = argv(1); + $obj_id = argv(2); + $public = true; + + if($obj_type == 'profile') { + $r = q("select * from profile where profile_guid = '%s' limit 1", + dbesc(argv(2)) + ); + if(! $r) + killme(); + $owner_uid = $r[0]['uid']; + if($r[0]['is_default']) + $public = true; + if(! $public) { + $d = q("select abook_xchan from abook where abook_profile = '%s' and abook_channel = %d", + dbesc($r[0]['profile_guid']), + intval($owner_uid) + ); + if(! $d) { + // forgery - illegal + if($interactive) { + notice( t('Invalid request.') . EOL); + return $o; + } + killme(); + } + // $d now contains a list of those who can see this profile - only send the status notification + // to them. + $allow_cid = $allow_gid = $deny_cid = $deny_gid = ''; + foreach($d as $dd) { + $allow_gid .= '<' . $dd['abook_xchan'] . '>'; + } + } + $post_type = t('channel'); + $objtype = ACTIVITY_OBJ_PROFILE; + + + } + elseif($obj_type == 'thing') { + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' + and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(2)) + ); + + if(! $r) { + if($interactive) { + notice( t('Invalid request.') . EOL); + return $o; + } + killme(); + } + + $owner_uid = $r[0]['obj_channel']; + + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + if($allow_cid || $allow_gid || $deny_cid || $deny_gid) + $public = false; + + $post_type = t('thing'); + $objtype = ACTIVITY_OBJ_PROFILE; + $tgttype = ACTIVITY_OBJ_THING; + + $links = array(); + $links[] = array('rel' => 'alternate', 'type' => 'text/html', + 'href' => z_root() . '/thing/' . $r[0]['term_hash']); + if($r[0]['imgurl']) + $links[] = array('rel' => 'photo', 'href' => $r[0]['imgurl']); + + $target = json_encode(array( + 'type' => $tgttype, + 'title' => $r[0]['term'], + 'id' => z_root() . '/thing/' . $r[0]['term_hash'], + 'link' => $links + )); + + $plink = '[zrl=' . z_root() . '/thing/' . $r[0]['term_hash'] . ']' . $r[0]['term'] . '[/zrl]'; + + } + + if(! ($owner_uid && $r)) { + if($interactive) { + notice( t('Invalid request.') . EOL); + return $o; + } + killme(); + } + + // The resultant activity is going to be a wall-to-wall post, so make sure this is allowed + + $perms = get_all_perms($owner_uid,$observer['xchan_hash']); + + if(! ($perms['post_like'] && $perms['view_profile'])) { + if($interactive) { + notice( t('Permission denied.') . EOL); + return $o; + } + killme(); + } + + $ch = q("select * from channel left join xchan on channel_hash = xchan_hash where channel_id = %d limit 1", + intval($owner_uid) + ); + if(! $ch) { + if($interactive) { + notice( t('Channel unavailable.') . EOL); + return $o; + } + killme(); + } + + if(! $plink) + $plink = '[zrl=' . z_root() . '/profile/' . $ch[0]['channel_address'] . ']' . $post_type . '[/zrl]'; + + $links = array(); + $links[] = array('rel' => 'alternate', 'type' => 'text/html', + 'href' => z_root() . '/profile/' . $ch[0]['channel_address']); + $links[] = array('rel' => 'photo', 'type' => $ch[0]['xchan_photo_mimetype'], + 'href' => $ch[0]['xchan_photo_l']); + + $object = json_encode(array( + 'type' => ACTIVITY_OBJ_PROFILE, + 'title' => $ch[0]['channel_name'], + 'id' => $ch[0]['xchan_url'] . '/' . $ch[0]['xchan_hash'], + 'link' => $links + )); + + + // second like of the same thing is "undo" for the first like + + $z = q("select * from likes where channel_id = %d and liker = '%s' and verb = '%s' and target_type = '%s' and target_id = '%s' limit 1", + intval($ch[0]['channel_id']), + dbesc($observer['xchan_hash']), + dbesc($activity), + dbesc(($tgttype)?$tgttype:$objtype), + dbesc($obj_id) + ); + + if($z) { + q("delete from likes where id = %d limit 1", + intval($z[0]['id']) + ); + drop_item($z[0]['iid'],false); + if($interactive) { + notice( t('Previous action reversed.') . EOL); + return $o; + } + killme(); + } + } + else { + + // this is used to like an item or comment + + $item_id = ((argc() == 2) ? notags(trim(argv(1))) : 0); + + logger('like: verb ' . $verb . ' item ' . $item_id, LOGGER_DEBUG); + + // get the item. Allow linked photos (which are normally hidden) to be liked + + $r = q("SELECT * FROM item WHERE id = %d + and item_type = 0 and item_deleted = 0 and item_unpublished = 0 + and item_delayed = 0 and item_pending_remove = 0 and item_blocked = 0 LIMIT 1", + intval($item_id) + ); + + if(! $item_id || (! $r)) { + logger('like: no item ' . $item_id); + killme(); + } + + + $item = $r[0]; + $owner_uid = $item['uid']; + $owner_aid = $item['aid']; + + + $sys = get_sys_channel(); + + + // if this is a "discover" item, (item['uid'] is the sys channel), + // fallback to the item comment policy, which should've been + // respected when generating the conversation thread. + // Even if the activity is rejected by the item owner, it should still get attached + // to the local discover conversation on this site. + + if(($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) { + notice( t('Permission denied') . EOL); + killme(); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) + ); + if($r) + $thread_owner = $r[0]; + else + killme(); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if($r) + $item_author = $r[0]; + else + killme(); + + + $verbs = " '".dbesc($activity)."' "; + $multi_undo = 0; + + // event participation and consensus items are essentially radio toggles. If you make a subsequent choice, + // we need to eradicate your first choice. + + if($activity === ACTIVITY_ATTEND || $activity === ACTIVITY_ATTENDNO || $activity === ACTIVITY_ATTENDMAYBE) { + $verbs = " '" . dbesc(ACTIVITY_ATTEND) . "','" . dbesc(ACTIVITY_ATTENDNO) . "','" . dbesc(ACTIVITY_ATTENDMAYBE) . "' "; + $multi_undo = 1; + } + if($activity === ACTIVITY_AGREE || $activity === ACTIVITY_DISAGREE || $activity === ACTIVITY_ABSTAIN) { + $verbs = " '" . dbesc(ACTIVITY_AGREE) . "','" . dbesc(ACTIVITY_DISAGREE) . "','" . dbesc(ACTIVITY_ABSTAIN) . "' "; + $multi_undo = 1; + } + + $item_normal = item_normal(); + + $r = q("SELECT id, parent, uid, verb FROM item WHERE verb in ( $verbs ) $item_normal + AND author_xchan = '%s' AND ( parent = %d OR thr_parent = '%s') and uid = %d ", + dbesc($observer['xchan_hash']), + intval($item_id), + dbesc($item['mid']), + intval($owner_uid) + ); + + if($r) { + // already liked it. Drop that item. + require_once('include/items.php'); + foreach($r as $rr) { + drop_item($rr['id'],false,DROPITEM_PHASE1); + // set the changed timestamp on the parent so we'll see the update without a page reload + $z = q("update item set changed = '%s' where id = %d and uid = %d", + dbesc(datetime_convert()), + intval($rr['parent']), + intval($rr['uid']) + ); + // Prior activity was a duplicate of the one we're submitting, just undo it; + // don't fall through and create another + if(activity_match($rr['verb'],$activity)) + $multi_undo = false; + } + + if($interactive) + return; + + if(! $multi_undo) + killme(); + } + } + + $mid = item_message_id(); + + $arr = array(); + + if($extended_like) { + $arr['item_thread_top'] = 1; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + } + else { + $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); + if($item['obj_type'] === ACTIVITY_OBJ_EVENT) + $post_type = t('event'); + + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $body = $item['body']; + + $object = json_encode(array( + 'type' => $objtype, + 'id' => $item['mid'], + 'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']), + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item_author['xchan_name'], + 'address' => $item_author['xchan_addr'], + 'guid' => $item_author['xchan_guid'], + 'guid_sig' => $item_author['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), + array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), + ), + )); + + if(! intval($item['item_thread_top'])) + $post_type = 'comment'; + + $arr['item_origin'] = 1; + $arr['item_notshown'] = 1; + + if(intval($item['item_wall'])) + $arr['item_wall'] = 1; + + // if this was a linked photo and was hidden, unhide it. + + if(intval($item['item_hidden'])) { + $r = q("update item set item_hidden = 0 where id = %d", + intval($item['id']) + ); + } + + } + + if($verb === 'like') + $bodyverb = t('%1$s likes %2$s\'s %3$s'); + if($verb === 'dislike') + $bodyverb = t('%1$s doesn\'t like %2$s\'s %3$s'); + if($verb === 'agree') + $bodyverb = t('%1$s agrees with %2$s\'s %3$s'); + if($verb === 'disagree') + $bodyverb = t('%1$s doesn\'t agree with %2$s\'s %3$s'); + if($verb === 'abstain') + $bodyverb = t('%1$s abstains from a decision on %2$s\'s %3$s'); + if($verb === 'attendyes') + $bodyverb = t('%1$s is attending %2$s\'s %3$s'); + if($verb === 'attendno') + $bodyverb = t('%1$s is not attending %2$s\'s %3$s'); + if($verb === 'attendmaybe') + $bodyverb = t('%1$s may attend %2$s\'s %3$s'); + + if(! isset($bodyverb)) + killme(); + + + + if($extended_like) { + $ulink = '[zrl=' . $ch[0]['xchan_url'] . ']' . $ch[0]['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $private = (($public) ? 0 : 1); + } + else { + $arr['parent'] = $item['id']; + $arr['thr_parent'] = $item['mid']; + $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]'; + $allow_cid = $item['allow_cid']; + $allow_gid = $item['allow_gid']; + $deny_cid = $item['deny_cid']; + $deny_gid = $item['deny_gid']; + $private = $item['private']; + + } + + + $arr['mid'] = $mid; + $arr['aid'] = (($extended_like) ? $ch[0]['channel_account_id'] : $owner_aid); + $arr['uid'] = $owner_uid; + $arr['item_flags'] = $item_flags; + $arr['item_wall'] = $item_wall; + $arr['parent_mid'] = (($extended_like) ? $mid : $item['mid']); + $arr['owner_xchan'] = (($extended_like) ? $ch[0]['xchan_hash'] : $thread_owner['xchan_hash']); + $arr['author_xchan'] = $observer['xchan_hash']; + + + $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); + if($obj_type === 'thing' && $r[0]['imgurl']) { + $arr['body'] .= "\n\n[zmg=80x80]" . $r[0]['imgurl'] . '[/zmg]'; + } + + + $arr['verb'] = $activity; + $arr['obj_type'] = $objtype; + $arr['object'] = $object; + + if($target) { + $arr['tgt_type'] = $tgttype; + $arr['target'] = $target; + } + + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['item_private'] = $private; + + + $post = item_store($arr); + $post_id = $post['item_id']; + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + + if($extended_like) { + $r = q("insert into likes (channel_id,liker,likee,iid,verb,target_type,target_id,target) values (%d,'%s','%s',%d,'%s','%s','%s','%s')", + intval($ch[0]['channel_id']), + dbesc($observer['xchan_hash']), + dbesc($ch[0]['channel_hash']), + intval($post_id), + dbesc($activity), + dbesc(($tgttype)?$tgttype:$objtype), + dbesc($obj_id), + dbesc(json_encode(($target)?$target:$object)) + ); + }; + + + proc_run('php',"include/notifier.php","like","$post_id"); + + if($interactive) { + notice( t('Action completed.') . EOL); + $o .= t('Thank you.'); + return $o; + } + + killme(); +} + + diff --git a/sources/mod/lockview.php b/sources/mod/lockview.php new file mode 100644 index 00000000..84c16f65 --- /dev/null +++ b/sources/mod/lockview.php @@ -0,0 +1,95 @@ + 1) ? argv(1) : 0); + if (is_numeric($type)) { + $item_id = intval($type); + $type='item'; + } else { + $item_id = ((argc() > 2) ? intval(argv(2)) : 0); + } + + if(! $item_id) + killme(); + + if (!in_array($type, array('item','photo','event', 'menu_item'))) + killme(); + + //we have different naming in in menu_item table + $id = (($type == 'menu_item') ? 'mitem_id' : 'id'); + + $r = q("SELECT * FROM %s WHERE $id = %d LIMIT 1", + dbesc($type), + intval($item_id) + ); + + if(! $r) + killme(); + + $item = $r[0]; + + //we have different naming in in menu_item table + $uid = (($type == 'menu_item') ? $item['mitem_channel_id'] : $item['uid']); + + if($uid != local_channel()) { + echo '
  10. ' . t('Remote privacy information not available.') . '
  11. '; + killme(); + } + + if(($item['item_private'] == 1) && (! strlen($item['allow_cid'])) && (! strlen($item['allow_gid'])) + && (! strlen($item['deny_cid'])) && (! strlen($item['deny_gid']))) { + + // if the post is private, but public_policy is blank ("visible to the internet"), and there aren't any + // specific recipients, we're the recipient of a post with "bcc" or targeted recipients; so we'll just show it + // as unknown specific recipients. The sender will have the visibility list and will fall through to the + // next section. + + echo '
  12. ' . translate_scope((! $item['public_policy']) ? 'specific' : $item['public_policy']) . '
  13. '; + killme(); + } + + $allowed_users = expand_acl($item['allow_cid']); + $allowed_groups = expand_acl($item['allow_gid']); + $deny_users = expand_acl($item['deny_cid']); + $deny_groups = expand_acl($item['deny_gid']); + + $o = '
  14. ' . t('Visible to:') . '
  15. '; + $l = array(); + + stringify_array_elms($allowed_groups,true); + stringify_array_elms($allowed_users,true); + stringify_array_elms($deny_groups,true); + stringify_array_elms($deny_users,true); + + if(count($allowed_groups)) { + $r = q("SELECT name FROM `groups` WHERE hash IN ( " . implode(', ', $allowed_groups) . " )"); + if($r) + foreach($r as $rr) + $l[] = '
  16. ' . $rr['name'] . '
  17. '; + } + if(count($allowed_users)) { + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ',$allowed_users) . " )"); + if($r) + foreach($r as $rr) + $l[] = '
  18. ' . $rr['xchan_name'] . '
  19. '; + } + if(count($deny_groups)) { + $r = q("SELECT name FROM `groups` WHERE hash IN ( " . implode(', ', $deny_groups) . " )"); + if($r) + foreach($r as $rr) + $l[] = '
  20. ' . $rr['name'] . '
  21. '; + } + if(count($deny_users)) { + $r = q("SELECT xchan_name FROM xchan WHERE xchan_hash IN ( " . implode(', ', $deny_users) . " )"); + if($r) + foreach($r as $rr) + $l[] = '
  22. ' . $rr['xchan_name'] . '
  23. '; + } + + echo $o . implode($l); + killme(); + + +} diff --git a/sources/mod/locs.php b/sources/mod/locs.php new file mode 100644 index 00000000..3f8bd902 --- /dev/null +++ b/sources/mod/locs.php @@ -0,0 +1,106 @@ +get_channel(); + + if($_REQUEST['primary']) { + $hubloc_id = intval($_REQUEST['primary']); + if($hubloc_id) { + + $r = q("select hubloc_id from hubloc where hubloc_id = %d and hubloc_hash = '%s' limit 1", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + + if(! $r) { + notice( t('Location not found.') . EOL); + return; + } + + $r = q("update hubloc set hubloc_primary = 0 where hubloc_primary = 1 and hubloc_hash = '%s' ", + dbesc($channel['channel_hash']) + ); + $r = q("update hubloc set hubloc_primary = 1 where hubloc_id = %d and hubloc_hash = '%s'", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + + proc_run('php','include/notifier.php','location',$channel['channel_id']); + return; + } + } + + if($_REQUEST['drop']) { + $hubloc_id = intval($_REQUEST['drop']); + + if($hubloc_id) { + $r = q("select * from hubloc where hubloc_id = %d and hubloc_url != '%s' and hubloc_hash = '%s' limit 1", + intval($hubloc_id), + dbesc(z_root()), + dbesc($channel['channel_hash']) + ); + + if(! $r) { + notice( t('Location not found.') . EOL); + return; + } + if(intval($r[0]['hubloc_primary'])) { + notice( t('Primary location cannot be removed.') . EOL); + return; + } + + $r = q("update hubloc set hubloc_deleted = 1 where hubloc_id = %d and hubloc_hash = '%s'", + intval($hubloc_id), + dbesc($channel['channel_hash']) + ); + proc_run('php','include/notifier.php','location',$channel['channel_id']); + return; + } + } +} + + + +function locs_content(&$a) { + + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + $channel = $a->get_channel(); + + $r = q("select * from hubloc where hubloc_hash = '%s'", + dbesc($channel['channel_hash']) + ); + + if(! $r) { + notice( t('No locations found.') . EOL); + return; + } + + + for($x = 0; $x < count($r); $x ++) { + $r[$x]['primary'] = (intval($r[$x]['hubloc_primary']) ? true : false); + $r[$x]['deleted'] = (intval($r[$x]['hubloc_deleted']) ? true : false); + } + + + + $o = replace_macros(get_markup_template('locmanage.tpl'), array( + '$header' => t('Manage Channel Locations'), + '$loc' => t('Location (address)'), + '$mkprm' => t('Primary Location'), + '$drop' => t('Drop location'), + '$submit' => t('Submit'), + '$hubs' => $r + )); + + return $o; +} \ No newline at end of file diff --git a/sources/mod/login.php b/sources/mod/login.php new file mode 100644 index 00000000..12c7d339 --- /dev/null +++ b/sources/mod/login.php @@ -0,0 +1,7 @@ +config['system']['register_policy'] == REGISTER_CLOSED) ? false : true); +} diff --git a/sources/mod/lostpass.php b/sources/mod/lostpass.php new file mode 100644 index 00000000..3dbc2fe7 --- /dev/null +++ b/sources/mod/lostpass.php @@ -0,0 +1,132 @@ + get_config('system','sitename'), + '$siteurl' => $a->get_baseurl(), + '$username' => sprintf( t('Site Member (%s)'), $email), + '$email' => $email, + '$reset_link' => $a->get_baseurl() . '/lostpass?verify=' . $hash + )); + + $subject = email_header_encode(sprintf( t('Password reset requested at %s'),get_config('system','sitename')), 'UTF-8'); + + $res = mail($email, $subject , + $message, + 'From: Administrator@' . $_SERVER['SERVER_NAME'] . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); + + + goaway(z_root()); +} + + +function lostpass_content(&$a) { + + + if(x($_GET,'verify')) { + $verify = $_GET['verify']; + + $r = q("SELECT * FROM account WHERE account_reset = '%s' LIMIT 1", + dbesc($verify) + ); + if(! $r) { + notice( t("Request could not be verified. (You may have previously submitted it.) Password reset failed.") . EOL); + goaway(z_root()); + return; + } + + $aid = $r[0]['account_id']; + $email = $r[0]['account_email']; + + $new_password = autoname(6) . mt_rand(100,9999); + + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $new_password); + + $r = q("UPDATE account SET account_salt = '%s', account_password = '%s', account_reset = '', account_flags = (account_flags & ~%d) where account_id = %d", + dbesc($salt), + dbesc($password_encoded), + intval(ACCOUNT_UNVERIFIED), + intval($aid) + ); + + if($r) { + $tpl = get_markup_template('pwdreset.tpl'); + $o .= replace_macros($tpl,array( + '$lbl1' => t('Password Reset'), + '$lbl2' => t('Your password has been reset as requested.'), + '$lbl3' => t('Your new password is'), + '$lbl4' => t('Save or copy your new password - and then'), + '$lbl5' => '' . t('click here to login') . '.', + '$lbl6' => t('Your password may be changed from the Settings page after successful login.'), + '$newpass' => $new_password, + '$baseurl' => $a->get_baseurl() + + )); + + info("Your password has been reset." . EOL); + + $email_tpl = get_intltext_template("passchanged_eml.tpl"); + $message = replace_macros($email_tpl, array( + '$sitename' => $a->config['sitename'], + '$siteurl' => $a->get_baseurl(), + '$username' => sprintf( t('Site Member (%s)'), $email), + '$email' => $email, + '$new_password' => $new_password, + '$uid' => $newuid )); + + $subject = email_header_encode( sprintf( t('Your password has changed at %s'), get_config('system','sitename')), 'UTF-8'); + + $res = mail($email,$subject,$message, + 'From: ' . 'Administrator@' . $_SERVER['SERVER_NAME'] . "\n" + . 'Content-type: text/plain; charset=UTF-8' . "\n" + . 'Content-transfer-encoding: 8bit' ); + + return $o; + } + + } + else { + $tpl = get_markup_template('lostpass.tpl'); + + $o .= replace_macros($tpl,array( + '$title' => t('Forgot your Password?'), + '$desc' => t('Enter your email address and submit to have your password reset. Then check your email for further instructions.'), + '$name' => t('Email Address'), + '$submit' => t('Reset') + )); + + return $o; + } + +} diff --git a/sources/mod/magic.php b/sources/mod/magic.php new file mode 100644 index 00000000..2fee8724 --- /dev/null +++ b/sources/mod/magic.php @@ -0,0 +1,169 @@ + false, 'url' => '', 'message' => ''); + logger('mod_magic: invoked', LOGGER_DEBUG); + + logger('mod_magic: args: ' . print_r($_REQUEST,true),LOGGER_DATA); + + $addr = ((x($_REQUEST,'addr')) ? $_REQUEST['addr'] : ''); + $dest = ((x($_REQUEST,'dest')) ? $_REQUEST['dest'] : ''); + $test = ((x($_REQUEST,'test')) ? intval($_REQUEST['test']) : 0); + $rev = ((x($_REQUEST,'rev')) ? intval($_REQUEST['rev']) : 0); + $delegate = ((x($_REQUEST,'delegate')) ? $_REQUEST['delegate'] : ''); + + $parsed = parse_url($dest); + if(! $parsed) { + if($test) { + $ret['message'] .= 'could not parse ' . $dest . EOL; + return($ret); + } + goaway($dest); + } + + $basepath = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + + $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", + dbesc($basepath) + ); + + if(! $x) { + + /* + * We have no records for, or prior communications with this hub. + * If an address was supplied, let's finger them to create a hub record. + * Otherwise we'll use the special address '[system]' which will return + * either a system channel or the first available normal channel. We don't + * really care about what channel is returned - we need the hub information + * from that response so that we can create signed auth packets destined + * for that hub. + * + */ + + $ret = zot_finger((($addr) ? $addr : '[system]@' . $parsed['host']),null); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) + import_xchan($j); + + // Now try again + + $x = q("select * from hubloc where hubloc_url = '%s' order by hubloc_connected desc limit 1", + dbesc($basepath) + ); + } + } + + if(! $x) { + if($rev) + goaway($dest); + else { + logger('mod_magic: no channels found for requested hub.' . print_r($_REQUEST,true)); + if($test) { + $ret['message'] .= 'This site has no previous connections with ' . $basepath . EOL; + return $ret; + } + notice( t('Hub not found.') . EOL); + return; + } + } + + // This is ready-made for a plugin that provides a blacklist or "ask me" before blindly authenticating. + // By default, we'll proceed without asking. + + $arr = array( + 'channel_id' => local_channel(), + 'xchan' => $x[0], + 'destination' => $dest, + 'proceed' => true + ); + + call_hooks('magic_auth',$arr); + $dest = $arr['destination']; + if(! $arr['proceed']) { + if($test) { + $ret['message'] .= 'cancelled by plugin.' . EOL; + return $ret; + } + goaway($dest); + } + + if((get_observer_hash()) && ($x[0]['hubloc_url'] === z_root())) { + // We are already authenticated on this site and a registered observer. + // Just redirect. + if($test) { + $ret['success'] = true; + $ret['message'] .= 'Local site - you are already authenticated.' . EOL; + return $ret; + } + + $delegation_success = false; + if($delegate) { + $r = q("select * from channel left join hubloc on channel_hash = hubloc_hash where hubloc_addr = '%s' limit 1", + dbesc($delegate) + ); + if($r && intval($r[0]['channel_id'])) { + $allowed = perm_is_allowed($r[0]['channel_id'],get_observer_hash(),'delegate'); + if($allowed) { + $_SESSION['delegate_channel'] = $r[0]['channel_id']; + $_SESSION['delegate'] = get_observer_hash(); + $_SESSION['account_id'] = intval($r[0]['channel_account_id']); + change_channel($r[0]['channel_id']); + $delegation_success = true; + } + } + } + + + + // FIXME: check and honour local delegation + + + goaway($dest); + } + + if(local_channel()) { + $channel = $a->get_channel(); + + $token = random_string(); + $token_sig = base64url_encode(rsa_sign($token,$channel['channel_prvkey'])); + + $channel['token'] = $token; + $channel['token_sig'] = $token_sig; + $r = q("insert into verify ( type, channel, token, meta, created) values ('%s','%d','%s','%s','%s')", + dbesc('auth'), + intval($channel['channel_id']), + dbesc($token), + dbesc($x[0]['hubloc_url']), + dbesc(datetime_convert()) + ); + $target_url = $x[0]['hubloc_callback'] . '/?f=&auth=' . urlencode($channel['channel_address'] . '@' . $a->get_hostname()) + . '&sec=' . $token . '&dest=' . urlencode($dest) . '&version=' . ZOT_REVISION; + + if($delegate) + $target_url .= '&delegate=' . urlencode($delegate); + + logger('mod_magic: redirecting to: ' . $target_url, LOGGER_DEBUG); + + if($test) { + $ret['success'] = true; + $ret['url'] = $target_url; + $ret['message'] = 'token ' . $token . ' created for channel ' . $channel['channel_id'] . ' for url ' . $x[0]['hubloc_url'] . EOL; + return $ret; + } + + goaway($target_url); + + } + + if($test) { + $ret['message'] = 'Not authenticated or invalid arguments to mod_magic' . EOL; + return $ret; + } + + goaway($dest); + +} diff --git a/sources/mod/mail.php b/sources/mod/mail.php new file mode 100644 index 00000000..152db323 --- /dev/null +++ b/sources/mod/mail.php @@ -0,0 +1,368 @@ +get_channel(); + + $ret = zot_finger($rstr,$channel); + + if(! $ret['success']) { + notice( t('Unable to lookup recipient.') . EOL); + return; + } + $j = json_decode($ret['body'],true); + + logger('message_post: lookup: ' . $url . ' ' . print_r($j,true)); + + if(! ($j['success'] && $j['guid'])) { + notice( t('Unable to communicate with requested channel.')); + return; + } + + $x = import_xchan($j); + + if(! $x['success']) { + notice( t('Cannot verify requested channel.')); + return; + } + + $recipient = $x['hash']; + + $their_perms = 0; + + $global_perms = get_perms(); + + if($j['permissions']['data']) { + $permissions = crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']); + if($permissions) + $permissions = json_decode($permissions); + logger('decrypted permissions: ' . print_r($permissions,true), LOGGER_DATA); + } + else + $permissions = $j['permissions']; + + foreach($permissions as $k => $v) { + if($v) { + $their_perms = $their_perms | intval($global_perms[$k][1]); + } + } + + if(! ($their_perms & PERMS_W_MAIL)) { + notice( t('Selected channel has private message restrictions. Send failed.')); + // reported issue: let's still save the message and continue. We'll just tell them + // that nothing useful is likely to happen. They might have spent hours on it. + // return; + + } + } + +// if(feature_enabled(local_channel(),'richtext')) { +// $body = fix_mce_lf($body); +// } + + require_once('include/text.php'); + linkify_tags($a, $body, local_channel()); + + if(! $recipient) { + notice('No recipient found.'); + $a->argc = 2; + $a->argv[1] = 'new'; + return; + } + + // We have a local_channel, let send_message use the session channel and save a lookup + + $ret = send_message(0, $recipient, $body, $subject, $replyto, $expires); + + if(! $ret['success']) { + notice($ret['message']); + } + + goaway(z_root() . '/message'); + +} + +function mail_content(&$a) { + + $o = ''; + nav_set_selected('messages'); + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return login(); + } + + $channel = $a->get_channel(); + + head_set_icon($channel['xchan_photo_s']); + + $cipher = get_pconfig(local_channel(),'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + $tpl = get_markup_template('mail_head.tpl'); + $header = replace_macros($tpl, array( + '$messages' => t('Messages'), + '$tab_content' => $tab_content + )); + + if((argc() == 3) && (argv(1) === 'drop')) { + if(! intval(argv(2))) + return; + $cmd = argv(1); + + $r = private_messages_drop(local_channel(), argv(2)); + if($r) { + info( t('Message deleted.') . EOL ); + } + goaway($a->get_baseurl(true) . '/message' ); + } + + if((argc() == 3) && (argv(1) === 'recall')) { + if(! intval(argv(2))) + return; + $cmd = argv(1); + $r = q("update mail set mail_recalled = 1 where id = %d and channel_id = %d", + intval(argv(2)), + intval(local_channel()) + ); + proc_run('php','include/notifier.php','mail',intval(argv(2))); + + if($r) { + info( t('Message recalled.') . EOL ); + } + goaway($a->get_baseurl(true) . '/message' ); + + } + + if((argc() > 1) && (argv(1) === 'new')) { + + $o .= $header; + + $plaintext = true; + + $tpl = get_markup_template('msg-header.tpl'); + + $header = replace_macros($tpl, array( + '$baseurl' => $a->get_baseurl(true), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$nickname' => $channel['channel_address'], + '$linkurl' => t('Please enter a link URL:'), + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM') + )); + + $a->page['htmlhead'] .= $header; + + + $preselect = (isset($a->argv[2])?array($a->argv[2]):false); + $prename = $preurl = $preid = ''; + + if(x($_REQUEST,'hash')) { + $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash + where abook_channel = %d and abook_xchan = '%s' limit 1", + intval(local_channel()), + dbesc($_REQUEST['hash']) + ); + if($r) { + $prename = $r[0]['xchan_name']; + $preurl = $r[0]['xchan_url']; + $preid = $r[0]['abook_id']; + $preselect = array($preid); + } + } + + + if($preselect) { + $r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash + where abook_channel = %d and abook_id = %d limit 1", + intval(local_channel()), + intval(argv(2)) + ); + if($r) { + $prename = $r[0]['xchan_name']; + $preurl = $r[0]['xchan_url']; + $preid = $r[0]['abook_id']; + } + } + + $prefill = (($preselect) ? $prename : ''); + + if(! $prefill) { + if(array_key_exists('to',$_REQUEST)) + $prefill = $_REQUEST['to']; + } + + // the ugly select box + + $select = contact_select('messageto','message-to-select', $preselect, 4, true, false, false, 10); + + $tpl = get_markup_template('prv_message.tpl'); + $o .= replace_macros($tpl,array( + '$header' => t('Send Private Message'), + '$to' => t('To:'), + '$showinputs' => 'true', + '$prefill' => $prefill, + '$autocomp' => $autocomp, + '$preid' => $preid, + '$subject' => t('Subject:'), + '$subjtxt' => ((x($_REQUEST,'subject')) ? strip_tags($_REQUEST['subject']) : ''), + '$text' => ((x($_REQUEST,'body')) ? htmlspecialchars($_REQUEST['body'], ENT_COMPAT, 'UTF-8') : ''), + '$readonly' => '', + '$yourmessage' => t('Your message:'), + '$select' => $select, + '$parent' => '', + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$insert' => t('Insert web link'), + '$wait' => t('Please wait'), + '$submit' => t('Send'), + '$defexpire' => '', + '$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + + + )); + + return $o; + } + + + if((argc() > 1) && (intval(argv(1)))) { + + $o .= $header; + + $plaintext = true; + +// if( local_channel() && feature_enabled(local_channel(),'richtext') ) +// $plaintext = false; + + $messages = private_messages_fetch_conversation(local_channel(), argv(1), true); + + if(! $messages) { + info( t('Message not found.') . EOL); + return $o; + } + + if($messages[0]['to_xchan'] === $channel['channel_hash']) + $a->poi = $messages[0]['from']; + else + $a->poi = $messages[0]['to']; + +// require_once('include/Contact.php'); + +// $a->set_widget('mail_conversant',vcard_from_xchan($a->poi,$get_observer_hash,'mail')); + + + $tpl = get_markup_template('msg-header.tpl'); + + $a->page['htmlhead'] .= replace_macros($tpl, array( + '$nickname' => $channel['channel_address'], + '$baseurl' => $a->get_baseurl(true), + '$editselect' => (($plaintext) ? 'none' : '/(profile-jot-text|prvmail-text)/'), + '$linkurl' => t('Please enter a link URL:'), + '$expireswhen' => t('Expires YYYY-MM-DD HH:MM') + )); + + + $mails = array(); + $seen = 0; + $unknown = false; + + foreach($messages as $message) { + + $s = theme_attachments($message); + + $mails[] = array( + 'id' => $message['id'], + 'from_name' => $message['from']['xchan_name'], + 'from_url' => chanlink_hash($message['from_xchan']), + 'from_photo' => $message['from']['xchan_photo_m'], + 'to_name' => $message['to']['xchan_name'], + 'to_url' => chanlink_hash($message['to_xchan']), + 'to_photo' => $message['to']['xchan_photo_m'], + 'subject' => $message['title'], + 'body' => smilies(bbcode($message['body']) . $s), + 'delete' => t('Delete message'), + 'recall' => t('Recall message'), + 'can_recall' => (($channel['channel_hash'] == $message['from_xchan']) ? true : false), + 'is_recalled' => (intval($message['mail_recalled']) ? t('Message has been recalled.') : ''), + 'date' => datetime_convert('UTC',date_default_timezone_get(),$message['created'],'D, d M Y - g:i A'), + ); + + $seen = $message['seen']; + + } + + $recp = (($message['from_xchan'] === $channel['channel_hash']) ? 'to' : 'from'); + +// FIXME - move this HTML to template + + $select = $message[$recp]['xchan_name'] . ''; + $parent = ''; + + $tpl = get_markup_template('mail_display.tpl'); + $o = replace_macros($tpl, array( + '$prvmsg_header' => t('Private Conversation'), + '$thread_id' => $a->argv[1], + '$thread_subject' => $message['title'], + '$thread_seen' => $seen, + '$delete' => t('Delete conversation'), + '$canreply' => (($unknown) ? false : '1'), + '$unknown_text' => t("No secure communications available. You may be able to respond from the sender's profile page."), + '$mails' => $mails, + + // reply + '$header' => t('Send Reply'), + '$to' => t('To:'), + '$showinputs' => '', + '$subject' => t('Subject:'), + '$subjtxt' => $message['title'], + '$readonly' => ' readonly="readonly" style="background: #BBBBBB;" ', + '$yourmessage' => t('Your message:'), + '$text' => '', + '$select' => $select, + '$parent' => $parent, + '$upload' => t('Upload photo'), + '$attach' => t('Attach file'), + '$insert' => t('Insert web link'), + '$submit' => t('Submit'), + '$wait' => t('Please wait'), + '$defexpire' => '', + '$feature_expire' => ((feature_enabled(local_channel(),'content_expire')) ? true : false), + '$expires' => t('Set expiration date'), + '$feature_encrypt' => ((feature_enabled(local_channel(),'content_encrypt')) ? true : false), + '$encrypt' => t('Encrypt text'), + '$cipher' => $cipher, + + )); + + return $o; + } + +} diff --git a/sources/mod/manage.php b/sources/mod/manage.php new file mode 100644 index 00000000..b609ede4 --- /dev/null +++ b/sources/mod/manage.php @@ -0,0 +1,179 @@ + 1) ? intval(argv(1)) : 0); + + if((argc() > 2) && (argv(2) === 'default')) { + $r = q("select channel_id from channel where channel_id = %d and channel_account_id = %d limit 1", + intval($change_channel), + intval(get_account_id()) + ); + if($r) { + q("update account set account_default_channel = %d where account_id = %d", + intval($change_channel), + intval(get_account_id()) + ); + } + goaway(z_root() . '/manage'); + } + + if($change_channel) { + $r = change_channel($change_channel); + + if((argc() > 2) && !(argv(2) === 'default')) { + goaway(z_root() . '/' . implode('/',array_slice($a->argv,2))); // Go to whatever is after /manage/, but with the new channel + } + else { + if($r && $r['channel_startpage']) + goaway(z_root() . '/' . $r['channel_startpage']); // If nothing extra is specified, go to the default page + } + goaway(z_root()); + } + + $channels = null; + + if(local_channel()) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel.channel_hash = xchan.xchan_hash where channel.channel_account_id = %d and channel_removed = 0 order by channel_name ", + intval(get_account_id()) + ); + + $account = get_app()->get_account(); + + if($r && count($r)) { + $channels = $r; + for($x = 0; $x < count($channels); $x ++) { + $channels[$x]['link'] = 'manage/' . intval($channels[$x]['channel_id']); + $channels[$x]['default'] = (($channels[$x]['channel_id'] == $account['account_default_channel']) ? "1" : ''); + $channels[$x]['default_links'] = '1'; + + + $c = q("SELECT id, item_wall FROM item + WHERE item_unseen = 1 and uid = %d " . item_normal(), + intval($channels[$x]['channel_id']) + ); + + if($c) { + foreach ($c as $it) { + if(intval($it['item_wall'])) + $channels[$x]['home'] ++; + else + $channels[$x]['network'] ++; + } + } + + + $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval($channels[$x]['channel_id']) + ); + + if($intr) + $channels[$x]['intros'] = intval($intr[0]['total']); + + + $mails = q("SELECT count(id) as total from mail WHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ", + intval($channels[$x]['channel_id']), + dbesc($channels[$x]['channel_hash']) + ); + + if($mails) + $channels[$x]['mail'] = intval($mails[0]['total']); + + + $events = q("SELECT type, start, adjust FROM `event` + WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0 + ORDER BY `start` ASC ", + intval($channels[$x]['channel_id']), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + 7 days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); + + if($events) { + $channels[$x]['all_events'] = count($events); + + if($channels[$x]['all_events']) { + $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); + foreach($events as $e) { + $bd = false; + if($e['type'] === 'birthday') { + $channels[$x]['birthdays'] ++; + $bd = true; + } + else { + $channels[$x]['events'] ++; + } + if(datetime_convert('UTC', ((intval($e['adjust'])) ? date_default_timezone_get() : 'UTC'), $e['start'], 'Y-m-d') === $str_now) { + $channels[$x]['all_events_today'] ++; + if($bd) + $channels[$x]['birthdays_today'] ++; + else + $channels[$x]['events_today'] ++; + } + } + } + } + } + } + + $r = q("select count(channel_id) as total from channel where channel_account_id = %d and channel_removed = 0", + intval(get_account_id()) + ); + $limit = account_service_class_fetch(get_account_id(),'total_identities'); + if($limit !== false) { + $channel_usage_message = sprintf( t("You have created %1$.0f of %2$.0f allowed channels."), $r[0]['total'], $limit); + } + else { + $channel_usage_message = ''; + } + } + + $links = array( + array( 'new_channel', t('Create a new channel'), t('Create a new channel')) + ); + + $delegates = q("select * from abook left join xchan on abook_xchan = xchan_hash where + abook_channel = %d and (abook_their_perms & %d) > 0", + intval(local_channel()), + intval(PERMS_A_DELEGATE) + ); + + if($delegates) { + for($x = 0; $x < count($delegates); $x ++) { + $delegates[$x]['link'] = 'magic?f=&dest=' . urlencode($delegates[$x]['xchan_url']) + . '&delegate=' . urlencode($delegates[$x]['xchan_addr']); + } + } + else { + $delegates = null; + } + + + + $o = replace_macros(get_markup_template('channels.tpl'), array( + '$header' => t('Channel Manager'), + '$msg_selected' => t('Current Channel'), + '$selected' => local_channel(), + '$desc' => t('Switch to one of your channels by selecting it.'), + '$msg_default' => t('Default Channel'), + '$msg_make_default' => t('Make Default'), + '$links' => $links, + '$all_channels' => $channels, + '$mail_format' => t('%d new messages'), + '$intros_format' => t('%d new introductions'), + '$channel_usage_message' => $channel_usage_message, + '$delegate_header' => t('Delegated Channels'), + '$delegates' => $delegates, + + )); + + + return $o; + +} diff --git a/sources/mod/match.php b/sources/mod/match.php new file mode 100644 index 00000000..fd739ba2 --- /dev/null +++ b/sources/mod/match.php @@ -0,0 +1,78 @@ +get_baseurl() . '/' . $a->cmd; + + $o .= '

    ' . t('Profile Match') . '

    '; + + $r = q("SELECT `keywords` FROM `profile` WHERE `is_default` = 1 AND `uid` = %d LIMIT 1", + intval(local_channel()) + ); + if (! count($r)) + return; + + if (! $r[0]['keywords']) { + notice( t('No keywords to match. Please add keywords to your default profile.') . EOL); + return; + } + + $params = array(); + $tags = trim($r[0]['keywords']); + + if ($tags) { + $params['s'] = $tags; + if ($a->pager['page'] != 1) + $params['p'] = $a->pager['page']; + +// if(strlen(get_config('system','directory_submit_url'))) +// $x = post_url('http://dir.friendica.com/msearch', $params); +// else +// $x = post_url($a->get_baseurl() . '/msearch', $params); + + $j = json_decode($x); + + if ($j->total) { + $a->set_pager_total($j->total); + $a->set_pager_itemspage($j->items_page); + } + + if (count($j->results)) { + $tpl = get_markup_template('match.tpl'); + foreach ($j->results as $jj) { + $connlnk = $a->get_baseurl() . '/follow/?url=' . $jj->url; + $o .= replace_macros($tpl,array( + '$url' => zid($jj->url), + '$name' => $jj->name, + '$photo' => $jj->photo, + '$inttxt' => ' ' . t('is interested in:'), + '$conntxt' => t('Connect'), + '$connlnk' => $connlnk, + '$tags' => $jj->tags + )); + } + } else { + info( t('No matches') . EOL); + } + } + + $o .= cleardiv(); + $o .= paginate($a); + + return $o; +} diff --git a/sources/mod/menu.php b/sources/mod/menu.php new file mode 100644 index 00000000..7763c4ed --- /dev/null +++ b/sources/mod/menu.php @@ -0,0 +1,161 @@ +is_sys = true; + } + } +} + +function menu_post(&$a) { + + $uid = local_channel(); + + if(array_key_exists('sys', $_REQUEST) && $_REQUEST['sys'] && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + $a->is_sys = true; + } + + if(! $uid) + return; + + $_REQUEST['menu_channel_id'] = $uid; + + if($_REQUEST['menu_bookmark']) + $_REQUEST['menu_flags'] |= MENU_BOOKMARK; + if($_REQUEST['menu_system']) + $_REQUEST['menu_flags'] |= MENU_SYSTEM; + + $menu_id = ((argc() > 1) ? intval(argv(1)) : 0); + if($menu_id) { + $_REQUEST['menu_id'] = intval(argv(1)); + $r = menu_edit($_REQUEST); + if($r) { + //info( t('Menu updated.') . EOL); + goaway(z_root() . '/mitem/' . $menu_id . (($a->is_sys) ? '?f=&sys=1' : '')); + } + else + notice( t('Unable to update menu.'). EOL); + } + else { + $r = menu_create($_REQUEST); + if($r) { + //info( t('Menu created.') . EOL); + goaway(z_root() . '/mitem/' . $r . (($a->is_sys) ? '?f=&sys=1' : '')); + } + else + notice( t('Unable to create menu.'). EOL); + + } +} + + +function menu_content(&$a) { + + $uid = local_channel(); + + if ($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + } + + if(! $uid) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(argc() == 1) { + + + + // list menus + $x = menu_list($uid); + if($x) { + for($y = 0; $y < count($x); $y ++) { + $m = menu_fetch($x[$y]['menu_name'],$uid,get_observer_hash()); + if($m) + $x[$y]['element'] = '[element]' . base64url_encode(json_encode(menu_element($m))) . '[/element]'; + $x[$y]['bookmark'] = (($x[$y]['menu_flags'] & MENU_BOOKMARK) ? true : false); + } + } + + $create = replace_macros(get_markup_template('menuedit.tpl'), array( + '$menu_name' => array('menu_name', t('Menu Name'), '', t('Unique name (not visible on webpage) - required'), '*'), + '$menu_desc' => array('menu_desc', t('Menu Title'), '', t('Visible on webpage - leave empty for no title'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow Bookmarks'), 0 , t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), + '$submit' => t('Submit and proceed'), + '$sys' => $a->is_sys, + '$display' => 'none' + )); + + $o = replace_macros(get_markup_template('menulist.tpl'),array( + '$title' => t('Menus'), + '$create' => $create, + '$menus' => $x, + '$nametitle' => t('Menu Name'), + '$desctitle' => t('Menu Title'), + '$edit' => t('Edit'), + '$drop' => t('Drop'), + '$created' => t('Created'), + '$edited' => t('Edited'), + '$new' => t('New'), + '$bmark' => t('Bookmarks allowed'), + '$hintnew' => t('Create'), + '$hintdrop' => t('Delete this menu'), + '$hintcontent' => t('Edit menu contents'), + '$hintedit' => t('Edit this menu'), + '$sys' => $a->is_sys + )); + + return $o; + + } + + if(argc() > 1) { + if(intval(argv(1))) { + + if(argc() == 3 && argv(2) == 'drop') { + $r = menu_delete_id(intval(argv(1)),$uid); + if(!$r) + notice( t('Menu could not be deleted.'). EOL); + + goaway(z_root() . '/menu' . (($a->is_sys) ? '?f=&sys=1' : '')); + } + + $m = menu_fetch_id(intval(argv(1)),$uid); + + if(! $m) { + notice( t('Menu not found.') . EOL); + return ''; + } + + $o = replace_macros(get_markup_template('menuedit.tpl'), array( + '$header' => t('Edit Menu'), + '$sys' => $a->is_sys, + '$menu_id' => intval(argv(1)), + '$menu_edit_link' => 'mitem/' . intval(argv(1)) . (($a->is_sys) ? '?f=&sys=1' : ''), + '$hintedit' => t('Add or remove entries to this menu'), + '$editcontents' => t('Edit menu contents'), + '$menu_name' => array('menu_name', t('Menu name'), $m['menu_name'], t('Must be unique, only seen by you'), '*'), + '$menu_desc' => array('menu_desc', t('Menu title'), $m['menu_desc'], t('Menu title as seen by others'), ''), + '$menu_bookmark' => array('menu_bookmark', t('Allow bookmarks'), (($m['menu_flags'] & MENU_BOOKMARK) ? 1 : 0), t('Menu may be used to store saved bookmarks'), array(t('No'), t('Yes'))), + '$menu_system' => (($m['menu_flags'] & MENU_SYSTEM) ? 1 : 0), + '$submit' => t('Submit and proceed') + )); + + return $o; + + } + else { + notice( t('Not found.') . EOL); + return; + } + } + +} diff --git a/sources/mod/message.php b/sources/mod/message.php new file mode 100644 index 00000000..9cf4b698 --- /dev/null +++ b/sources/mod/message.php @@ -0,0 +1,81 @@ +get_channel(); + head_set_icon($channel['xchan_photo_s']); + + $cipher = get_pconfig(local_channel(),'system','default_cipher'); + if(! $cipher) + $cipher = 'aes256'; + + + $tpl = get_markup_template('mail_head.tpl'); + $header = replace_macros($tpl, array( + '$messages' => t('Messages'), + '$tab_content' => $tab_content + )); + + if((argc() == 3) && (argv(1) === 'dropconv')) { + if(! intval(argv(2))) + return; + $cmd = argv(1); + $r = private_messages_drop(local_channel(), argv(2), true); + if($r) + info( t('Conversation removed.') . EOL ); + goaway($a->get_baseurl(true) . '/message' ); + } + if(argc() == 1) { + + // list messages + + $o .= $header; + + // private_messages_list() can do other more complicated stuff, for now keep it simple + + $r = private_messages_list(local_channel(), '', $a->pager['start'], $a->pager['itemspage']); + + if(! $r) { + info( t('No messages.') . EOL); + return $o; + } + + $tpl = get_markup_template('mail_list.tpl'); + foreach($r as $rr) { + + $o .= replace_macros($tpl, array( + '$id' => $rr['id'], + '$from_name' => $rr['from']['xchan_name'], + '$from_url' => chanlink_hash($rr['from_xchan']), + '$from_photo' => $rr['from']['xchan_photo_s'], + '$to_name' => $rr['to']['xchan_name'], + '$to_url' => chanlink_hash($rr['to_xchan']), + '$to_photo' => $rr['to']['xchan_photo_s'], + '$subject' => (($rr['seen']) ? $rr['title'] : '' . $rr['title'] . ''), + '$delete' => t('Delete conversation'), + '$body' => smilies(bbcode($rr['body'])), + '$date' => datetime_convert('UTC',date_default_timezone_get(),$rr['created'], t('D, d M Y - g:i A')), + '$seen' => $rr['seen'] + )); + } + $o .= alt_pager($a,count($r)); + return $o; + } + + +} diff --git a/sources/mod/mitem.php b/sources/mod/mitem.php new file mode 100644 index 00000000..bc93165a --- /dev/null +++ b/sources/mod/mitem.php @@ -0,0 +1,240 @@ +is_sys = true; + } + + if(! $uid) + return; + + if(argc() < 2) + return; + + $m = menu_fetch_id(intval(argv(1)),$uid); + if(! $m) { + notice( t('Menu not found.') . EOL); + return ''; + } + $a->data['menu'] = $m; + +} + +function mitem_post(&$a) { + + $uid = local_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + } + + if(! $uid) { + return; + } + + if(! $a->data['menu']) + return; + + if(!$_REQUEST['mitem_desc'] || !$_REQUEST['mitem_link']) { + notice( t('Unable to create element.') . EOL); + return; + } + + $_REQUEST['mitem_channel_id'] = $uid; + $_REQUEST['menu_id'] = $a->data['menu']['menu_id']; + + $_REQUEST['mitem_flags'] = 0; + if($_REQUEST['usezid']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_ZID; + if($_REQUEST['newwin']) + $_REQUEST['mitem_flags'] |= MENU_ITEM_NEWWIN; + + + $mitem_id = ((argc() > 2) ? intval(argv(2)) : 0); + if($mitem_id) { + $_REQUEST['mitem_id'] = $mitem_id; + $r = menu_edit_item($_REQUEST['menu_id'],$uid,$_REQUEST); + if($r) { + //info( t('Menu element updated.') . EOL); + goaway(z_root() . '/mitem/' . $_REQUEST['menu_id'] . (($a->is_sys) ? '?f=&sys=1' : '')); + } + else + notice( t('Unable to update menu element.') . EOL); + + } + else { + $r = menu_add_item($_REQUEST['menu_id'],$uid,$_REQUEST); + if($r) { + //info( t('Menu element added.') . EOL); + if($_REQUEST['submit']) { + goaway(z_root() . '/menu' . (($a->is_sys) ? '?f=&sys=1' : '')); + } + if($_REQUEST['submit-more']) { + goaway(z_root() . '/mitem/' . $_REQUEST['menu_id'] . '?f=&display=block' . (($a->is_sys) ? '&sys=1' : '') ); + } + } + else + notice( t('Unable to add menu element.') . EOL); + + } + +} + + +function mitem_content(&$a) { + + $uid = local_channel(); + $channel = $a->get_channel(); + $observer = $a->get_observer(); + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + $uid = intval($sys['channel_id']); + $channel = $sys; + $ob_hash = $sys['xchan_hash']; + } + + if(! $uid) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(argc() < 2 || (! $a->data['menu'])) { + notice( t('Not found.') . EOL); + return ''; + } + + $m = menu_fetch($a->data['menu']['menu_name'],$uid,$ob_hash); + $a->data['menu_item'] = $m; + + $menu_list = menu_list($uid); + + foreach($menu_list as $menus) { + if($menus['menu_name'] != $m['menu']['menu_name']) + $menu_names[] = $menus['menu_name']; + } + + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $lockstate = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'); + + if(argc() == 2) { + $r = q("select * from menu_item where mitem_menu_id = %d and mitem_channel_id = %d order by mitem_order asc, mitem_desc asc", + intval($a->data['menu']['menu_id']), + intval($uid) + ); + + if($_GET['display']) { + $display = $_GET['display']; + } + else { + $display = (($r) ? 'none' : 'block'); + } + + $create = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$menu_id' => $a->data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($perm_defaults,false), + '$mitem_desc' => array('mitem_desc', t('Link Name'), '', 'Visible name of the link','*'), + '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), '', t('Enter URL of the link or select a menu name to create a submenu'), '*', 'list="menu-names"'), + '$usezid' => array('usezid', t('Use magic-auth if available'), true, '', array(t('No'), t('Yes'))), + '$newwin' => array('newwin', t('Open link in new window'), false,'', array(t('No'), t('Yes'))), + '$mitem_order' => array('mitem_order', t('Order in list'),'0',t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Submit and finish'), + '$submit_more' => t('Submit and continue'), + '$display' => $display, + '$lockstate' => $lockstate, + '$menu_names' => $menu_names, + '$sys' => $a->is_sys + )); + + $o .= replace_macros(get_markup_template('mitemlist.tpl'),array( + '$title' => t('Menu:'), + '$create' => $create, + '$nametitle' => t('Link Name'), + '$targettitle' => t('Link Target'), + '$menuname' => $a->data['menu']['menu_name'], + '$menudesc' => $a->data['menu']['menu_desc'], + '$edmenu' => t('Edit menu'), + '$menu_id' => $a->data['menu']['menu_id'], + '$mlist' => $r, + '$edit' => t('Edit element'), + '$drop' => t('Drop element'), + '$new' => t('New element'), + '$hintmenu' => t('Edit this menu container'), + '$hintnew' => t('Add menu element'), + '$hintdrop' => t('Delete this menu item'), + '$hintedit' => t('Edit this menu item'), + )); + + return $o; + } + + + if(argc() > 2) { + + if(intval(argv(2))) { + + $m = q("select * from menu_item where mitem_id = %d and mitem_channel_id = %d limit 1", + intval(argv(2)), + intval($uid) + ); + + if(! $m) { + notice( t('Menu item not found.') . EOL); + goaway(z_root() . '/menu'. (($a->is_sys) ? '?f=&sys=1' : '')); + } + + $mitem = $m[0]; + + $lockstate = (($mitem['allow_cid'] || $mitem['allow_gid'] || $mitem['deny_cid'] || $mitem['deny_gid']) ? 'lock' : 'unlock'); + + if(argc() == 4 && argv(3) == 'drop') { + $r = menu_del_item($mitem['mitem_menu_id'], $uid, intval(argv(2))); + if($r) + info( t('Menu item deleted.') . EOL); + else + notice( t('Menu item could not be deleted.'). EOL); + + goaway(z_root() . '/mitem/' . $mitem['mitem_menu_id'] . (($a->is_sys) ? '?f=&sys=1' : '')); + } + + // edit menu item + $o = replace_macros(get_markup_template('mitemedit.tpl'), array( + '$header' => t('Edit Menu Element'), + '$menu_id' => $a->data['menu']['menu_id'], + '$permissions' => t('Menu Item Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($mitem,false), + '$mitem_id' => intval(argv(2)), + '$mitem_desc' => array('mitem_desc', t('Link text'), $mitem['mitem_desc'], '','*'), + '$mitem_link' => array('mitem_link', t('Link or Submenu Target'), $mitem['mitem_link'], 'Enter URL of the link or select a menu name to create a submenu', '*', 'list="menu-names"'), + '$usezid' => array('usezid', t('Use magic-auth if available'), (($mitem['mitem_flags'] & MENU_ITEM_ZID) ? 1 : 0), '', array(t('No'), t('Yes'))), + '$newwin' => array('newwin', t('Open link in new window'), (($mitem['mitem_flags'] & MENU_ITEM_NEWWIN) ? 1 : 0),'', array(t('No'), t('Yes'))), + '$mitem_order' => array('mitem_order', t('Order in list'),$mitem['mitem_order'],t('Higher numbers will sink to bottom of listing')), + '$submit' => t('Submit'), + '$lockstate' => $lockstate, + '$menu_names' => $menu_names + )); + + return $o; + } + } +} diff --git a/sources/mod/mood.php b/sources/mod/mood.php new file mode 100755 index 00000000..92a4f391 --- /dev/null +++ b/sources/mod/mood.php @@ -0,0 +1,140 @@ +get_channel(); + $verb = notags(trim($_GET['verb'])); + + if(! $verb) + return; + + $verbs = get_mood_verbs(); + + if(! array_key_exists($verb,$verbs)) + return; + + $activity = ACTIVITY_MOOD . '#' . urlencode($verb); + + $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : 0); + + + logger('mood: verb ' . $verb, LOGGER_DEBUG); + + + if($parent) { + $r = q("select mid, owner_xchan, private, allow_cid, allow_gid, deny_cid, deny_gid + from item where id = %d and parent = %d and uid = %d limit 1", + intval($parent), + intval($parent), + intval($uid) + ); + if(count($r)) { + $parent_mid = $r[0]['mid']; + $private = $r[0]['item_private']; + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + } + } + else { + + $private = 0; + + $allow_cid = $channel['channel_allow_cid']; + $allow_gid = $channel['channel_allow_gid']; + $deny_cid = $channel['channel_deny_cid']; + $deny_gid = $channel['channel_deny_gid']; + } + + $poster = $a->get_observer(); + + $mid = item_message_id(); + + $action = sprintf( t('%1$s is %2$s','mood'), '[zrl=' . $poster['xchan_url'] . ']' . $poster['xchan_name'] . '[/zrl]' , $verbs[$verb]); + + $arr = array(); + + $arr['aid'] = get_account_id(); + $arr['uid'] = $uid; + $arr['mid'] = $mid; + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); + $arr['author_xchan'] = $poster['xchan_hash']; + $arr['owner_xchan'] = (($parent_mid) ? $r[0]['owner_xchan'] : $poster['xchan_hash']); + $arr['title'] = ''; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['item_private'] = $private; + $arr['verb'] = $activity; + $arr['body'] = $action; + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_unseen'] = 1; + if(! $parent_mid) + $item['item_thread_top'] = 1; + + if ((! $arr['plink']) && intval($arr['item_thread_top'])) { + $arr['plink'] = z_root() . '/channel/' . $channel['channel_address'] . '/?f=&mid=' . $arr['mid']; + } + + + $post = item_store($arr); + $item_id = $post['item_id']; + + if($item_id) { + proc_run('php',"include/notifier.php","activity", $item_id); + } + + call_hooks('post_local_end', $arr); + + if($_SESSION['return_url']) + goaway(z_root() . '/' . $_SESSION['return_url']); + + return; +} + + + +function mood_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + $parent = ((x($_GET,'parent')) ? intval($_GET['parent']) : '0'); + + + + $verbs = get_mood_verbs(); + + $shortlist = array(); + foreach($verbs as $k => $v) + if($v !== 'NOTRANSLATION') + $shortlist[] = array($k,$v); + + + $tpl = get_markup_template('mood_content.tpl'); + + $o = replace_macros($tpl,array( + '$title' => t('Mood'), + '$desc' => t('Set your current mood and tell your friends'), + '$verbs' => $shortlist, + '$parent' => $parent, + '$submit' => t('Submit'), + )); + + return $o; + +} diff --git a/sources/mod/msearch.php b/sources/mod/msearch.php new file mode 100644 index 00000000..b51c4e09 --- /dev/null +++ b/sources/mod/msearch.php @@ -0,0 +1,42 @@ + $rr['name'], + 'url' => $a->get_baseurl() . '/channel/' . $rr['nickname'], + 'photo' => $a->get_baseurl() . '/photo/avatar/' . $rr['uid'], + 'tags' => str_replace(array(',',' '),array(' ',' '),$rr['keywords']) + ); + } + + $output = array('total' => $total, 'items_page' => $perpage, 'page' => $page + 1, 'results' => $results); + + echo json_encode($output); + + killme(); + +} \ No newline at end of file diff --git a/sources/mod/network.php b/sources/mod/network.php new file mode 100644 index 00000000..d5e30568 --- /dev/null +++ b/sources/mod/network.php @@ -0,0 +1,511 @@ +get_channel(); + $a->profile_uid = local_channel(); + head_set_icon($channel['xchan_photo_s']); + +} + +function network_content(&$a, $update = 0, $load = false) { + + if(! local_channel()) { + $_SESSION['return_url'] = $a->query_string; + return login(false); + } + + if($load) + $_SESSION['loadtime'] = datetime_convert(); + + $arr = array('query' => $a->query_string); + + call_hooks('network_content_init', $arr); + + $channel = $a->get_channel(); + $item_normal = item_normal(); + + $datequery = $datequery2 = ''; + + $group = 0; + + $nouveau = false; + + $datequery = ((x($_GET,'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : ''); + $datequery2 = ((x($_GET,'dbegin') && is_a_date_arg($_GET['dbegin'])) ? notags($_GET['dbegin']) : ''); + $nouveau = ((x($_GET,'new')) ? intval($_GET['new']) : 0); + $gid = ((x($_GET,'gid')) ? intval($_GET['gid']) : 0); + $category = ((x($_REQUEST,'cat')) ? $_REQUEST['cat'] : ''); + $hashtags = ((x($_REQUEST,'tag')) ? $_REQUEST['tag'] : ''); + $verb = ((x($_REQUEST,'verb')) ? $_REQUEST['verb'] : ''); + + $search = (($_GET['search']) ? $_GET['search'] : ''); + if($search) { + if(strpos($search,'@') === 0) { + $r = q("select abook_id from abook left join xchan on abook_xchan = xchan_hash where xchan_name = '%s' and abook_channel = %d limit 1", + dbesc(substr($search,1)), + intval(local_channel()) + ); + if($r) { + $_GET['cid'] = $r[0]['abook_id']; + $search = $_GET['search'] = ''; + } + } + elseif(strpos($search,'#') === 0) { + $hashtags = substr($search,1); + $search = $_GET['search'] = ''; + } + } + + if($datequery) + $_GET['order'] = 'post'; + + + // filter by collection (e.g. group) + + if($gid) { + $r = q("SELECT * FROM groups WHERE id = %d AND uid = %d LIMIT 1", + intval($gid), + intval(local_channel()) + ); + if(! $r) { + if($update) + killme(); + notice( t('No such group') . EOL ); + goaway($a->get_baseurl(true) . '/network'); + // NOTREACHED + } + + $group = $gid; + $group_hash = $r[0]['hash']; + $def_acl = array('allow_gid' => '<' . $r[0]['hash'] . '>'); + } + + $o = ''; + + + // if no tabs are selected, defaults to comments + + $cid = ((x($_GET,'cid')) ? intval($_GET['cid']) : 0); + $star = ((x($_GET,'star')) ? intval($_GET['star']) : 0); + $order = ((x($_GET,'order')) ? notags($_GET['order']) : 'comment'); + $liked = ((x($_GET,'liked')) ? intval($_GET['liked']) : 0); + $conv = ((x($_GET,'conv')) ? intval($_GET['conv']) : 0); + $spam = ((x($_GET,'spam')) ? intval($_GET['spam']) : 0); + $cmin = ((x($_GET,'cmin')) ? intval($_GET['cmin']) : 0); + $cmax = ((x($_GET,'cmax')) ? intval($_GET['cmax']) : 99); + $firehose = ((x($_GET,'fh')) ? intval($_GET['fh']) : 0); + $file = ((x($_GET,'file')) ? $_GET['file'] : ''); + + + if(x($_GET,'search') || x($_GET,'file')) + $nouveau = true; + if($cid) { + $r = q("SELECT abook_xchan FROM abook WHERE abook_id = %d AND abook_channel = %d LIMIT 1", + intval($cid), + intval(local_channel()) + ); + if(! $r) { + if($update) { + killme(); + } + notice( t('No such channel') . EOL ); + goaway($a->get_baseurl(true) . '/network'); + // NOTREACHED + } + $def_acl = array('allow_cid' => '<' . $r[0]['abook_xchan'] . '>'); + } + + if(! $update) { + $tabs = network_tabs(); + $o .= $tabs; + + // search terms header + if($search) { + $o .= replace_macros(get_markup_template("section_title.tpl"),array( + '$title' => t('Search Results For:') . ' ' . htmlspecialchars($search, ENT_COMPAT,'UTF-8') + )); + } + + nav_set_selected('network'); + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($group || $cid || $channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl((($group || $cid) ? $def_acl : $channel_acl)), + 'bang' => (($group || $cid) ? '!' : ''), + 'visitor' => true, + 'profile_uid' => local_channel() + ); + + $status_editor = status_editor($a,$x); + $o .= $status_editor; + } + + + // We don't have to deal with ACL's on this page. You're looking at everything + // that belongs to you, hence you can see all of it. We will filter by group if + // desired. + + + $sql_options = (($star) + ? " and item_starred = 1 " + : ''); + + $sql_nets = ''; + + $sql_extra = " AND `item`.`parent` IN ( SELECT `parent` FROM `item` WHERE item_thread_top = 1 $sql_options ) "; + + if($group) { + $contact_str = ''; + $contacts = group_get_members($group); + if($contacts) { + foreach($contacts as $c) { + if($contact_str) + $contact_str .= ','; + $contact_str .= "'" . $c['xchan'] . "'"; + } + } + else { + $contact_str = ' 0 '; + info( t('Collection is empty')); + } + + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND (( author_xchan IN ( $contact_str ) OR owner_xchan in ( $contact_str )) or allow_gid like '" . protect_sprintf('%<' . dbesc($group_hash) . '>%') . "' ) and id = parent $item_normal ) "; + + $x = group_rec_byhash(local_channel(), $group_hash); + + if($x) { + $title = replace_macros(get_markup_template("section_title.tpl"),array( + '$title' => t('Collection: ') . $x['name'] + )); + } + + $o = $tabs; + $o .= $title; + $o .= $status_editor; + + } + + elseif($cid) { + + $r = q("SELECT abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1", + intval($cid), + intval(local_channel()) + ); + if($r) { + $sql_extra = " AND item.parent IN ( SELECT DISTINCT parent FROM item WHERE true $sql_options AND uid = " . intval(local_channel()) . " AND ( author_xchan = '" . dbesc($r[0]['abook_xchan']) . "' or owner_xchan = '" . dbesc($r[0]['abook_xchan']) . "' ) $item_normal ) "; + $title = replace_macros(get_markup_template("section_title.tpl"),array( + '$title' => t('Connection: ') . $r[0]['xchan_name'] + )); + $o = $tabs; + $o .= $title; + $o .= $status_editor; + } + else { + notice( t('Invalid connection.') . EOL); + goaway($a->get_baseurl(true) . '/network'); + } + } + + if(x($category)) { + $sql_extra .= protect_sprintf(term_query('item', $category, TERM_CATEGORY)); + } + if(x($hashtags)) { + $sql_extra .= protect_sprintf(term_query('item', $hashtags, TERM_HASHTAG)); + } + + if(! $update) { + // The special div is needed for liveUpdate to kick in for this page. + // We only launch liveUpdate if you aren't filtering in some incompatible + // way and also you aren't writing a comment (discovered in javascript). + + if($gid || $cid || $cmin || ($cmax != 99) || $star || $liked || $conv || $spam || $nouveau || $list) + $firehose = 0; + + $maxheight = get_pconfig(local_channel(),'system','network_divmore_height'); + if(! $maxheight) + $maxheight = 400; + + + $o .= '
    ' . "\r\n"; + $o .= "\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'network', + '$uid' => ((local_channel()) ? local_channel() : '0'), + '$gid' => (($gid) ? $gid : '0'), + '$cid' => (($cid) ? $cid : '0'), + '$cmin' => (($cmin) ? $cmin : '0'), + '$cmax' => (($cmax) ? $cmax : '0'), + '$star' => (($star) ? $star : '0'), + '$liked' => (($liked) ? $liked : '0'), + '$conv' => (($conv) ? $conv : '0'), + '$spam' => (($spam) ? $spam : '0'), + '$fh' => (($firehose) ? $firehose : '0'), + '$nouveau' => (($nouveau) ? $nouveau : '0'), + '$wall' => '0', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$search' => (($search) ? $search : ''), + '$order' => $order, + '$file' => $file, + '$cats' => $category, + '$tags' => $hashtags, + '$dend' => $datequery, + '$mid' => '', + '$verb' => $verb, + '$dbegin' => $datequery2 + )); + } + + $sql_extra3 = ''; + + if($datequery) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created <= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery)))); + } + if($datequery2) { + $sql_extra3 .= protect_sprintf(sprintf(" AND item.created >= '%s' ", dbesc(datetime_convert(date_default_timezone_get(),'',$datequery2)))); + } + + $sql_extra2 = (($nouveau) ? '' : " AND item.parent = item.id "); + $sql_extra3 = (($nouveau) ? '' : $sql_extra3); + + if(x($_GET,'search')) { + $search = escape_tags($_GET['search']); + if(strpos($search,'#') === 0) { + $sql_extra .= term_query('item',substr($search,1),TERM_HASHTAG); + } + else { + $sql_extra .= sprintf(" AND item.body like '%s' ", + dbesc(protect_sprintf('%' . $search . '%')) + ); + } + } + + if($verb) { + $sql_extra .= sprintf(" AND item.verb like '%s' ", + dbesc(protect_sprintf('%' . $verb . '%')) + ); + } + + if(strlen($file)) { + $sql_extra .= term_query('item',$file,TERM_FILE); + } + + if($conv) { + $sql_extra .= sprintf(" AND parent IN (SELECT distinct(parent) from item where ( author_xchan like '%s' or item_mentionsme = 1 )) ", + dbesc(protect_sprintf($channel['channel_hash'])) + ); + } + + if($update && ! $load) { + + // only setup pagination on initial page view + $pager_sql = ''; + + } + else { + $itemspage = get_pconfig(local_channel(),'system','itemspage'); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($a->pager['itemspage']), intval($a->pager['start'])); + } + + + if(($cmin != 0) || ($cmax != 99)) { + + // Not everybody who shows up in the network stream will be in your address book. + // By default those that aren't are assumed to have closeness = 99; but this isn't + // recorded anywhere. So if cmax is 99, we'll open the search up to anybody in + // the stream with a NULL address book entry. + + $sql_nets .= " AND "; + + if($cmax == 99) + $sql_nets .= " ( "; + + $sql_nets .= "( abook.abook_closeness >= " . intval($cmin) . " "; + $sql_nets .= " AND abook.abook_closeness <= " . intval($cmax) . " ) "; + + if($cmax == 99) + $sql_nets .= " OR abook.abook_closeness IS NULL ) "; + + + } + + $abook_uids = " and abook.abook_channel = " . local_channel() . " "; + + if($firehose && (! get_config('system','disable_discover_tab'))) { + require_once('include/identity.php'); + $sys = get_sys_channel(); + $uids = " and item.uid = " . intval($sys['channel_id']) . " "; + $a->data['firehose'] = intval($sys['channel_id']); + } + else { + $uids = " and item.uid = " . local_channel() . " "; + } + + if(get_pconfig(local_channel(),'system','network_list_mode')) + $page_mode = 'list'; + else + $page_mode = 'client'; + + $simple_update = (($update) ? " and item_unseen = 1 " : ''); + + // This fixes a very subtle bug so I'd better explain it. You wake up in the morning or return after a day + // or three and look at your matrix page - after opening up your browser. The first page loads just as it + // should. All of a sudden a few seconds later, page 2 will get inserted at the beginning of the page + // (before the page 1 content). The update code is actually doing just what it's supposed + // to, it's fetching posts that have the ITEM_UNSEEN bit set. But the reason that page 2 content is being + // returned in an UPDATE is because you hadn't gotten that far yet - you're still on page 1 and everything + // that we loaded for page 1 is now marked as seen. But the stuff on page 2 hasn't been. So... it's being + // treated as "new fresh" content because it is unseen. We need to distinguish it somehow from content + // which "arrived as you were reading page 1". We're going to do this + // by storing in your session the current UTC time whenever you LOAD a network page, and only UPDATE items + // which are both ITEM_UNSEEN and have "changed" since that time. Cross fingers... + + if($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; + if($load) + $simple_update = ''; + + if($nouveau && $load) { + // "New Item View" - show all items unthreaded in reverse created date order + + $items = q("SELECT item.*, item.id AS item_id, received FROM item + left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) + WHERE true $uids $item_normal + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $simple_update + $sql_extra $sql_nets + ORDER BY item.received DESC $pager_sql " + ); + + require_once('include/items.php'); + + xchan_query($items); + + $items = fetch_post_tags($items,true); + } + elseif($update) { + + // Normal conversation view + + if($order === 'post') + $ordering = "created"; + else + $ordering = "commented"; + + if($load) { + + // Fetch a page full of parent items for this page + + $r = q("SELECT distinct item.id AS item_id, $ordering FROM item + left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) + WHERE true $uids $item_normal + AND item.parent = item.id + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets + ORDER BY $ordering DESC $pager_sql " + ); + + } + else { + // this is an update + $r = q("SELECT item.parent AS item_id FROM item + left join abook on ( item.owner_xchan = abook.abook_xchan $abook_uids ) + WHERE true $uids $item_normal $simple_update + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets " + ); + $_SESSION['loadtime'] = datetime_convert(); + } + + // Then fetch all the children of the parents that are on this page + $parents_str = ''; + $update_unseen = ''; + + if($r) { + + $parents_str = ids_to_querystr($r,'item_id'); + + $items = q("SELECT item.*, item.id AS item_id FROM item + WHERE true $uids $item_normal + AND item.parent IN ( %s ) + $sql_extra ", + dbesc($parents_str) + ); + + xchan_query($items,true,(($firehose) ? local_channel() : 0)); + $items = fetch_post_tags($items,true); + $items = conv_sort($items,$ordering); + } + else { + $items = array(); + } + + if($page_mode === 'list') { + + /** + * in "list mode", only mark the parent item and any like activities as "seen". + * We won't distinguish between comment likes and post likes. The important thing + * is that the number of unseen comments will be accurate. The SQL to separate the + * comment likes could also get somewhat hairy. + */ + + if($parents_str) { + $update_unseen = " AND ( id IN ( " . dbesc($parents_str) . " )"; + $update_unseen .= " OR ( parent IN ( " . dbesc($parents_str) . " ) AND verb in ( '" . dbesc(ACTIVITY_LIKE) . "','" . dbesc(ACTIVITY_DISLIKE) . "' ))) "; + } + } + else { + if($parents_str) { + $update_unseen = " AND parent IN ( " . dbesc($parents_str) . " )"; + } + } + } + + if(($update_unseen) && (! $firehose)) + $r = q("UPDATE item SET item_unseen = 0 WHERE item_unseen = 1 AND uid = %d $update_unseen ", + intval(local_channel()) + ); + + $mode = (($nouveau) ? 'network-new' : 'network'); + + $o .= conversation($a,$items,$mode,$update,$page_mode); + + if(($items) && (! $update)) + $o .= alt_pager($a,count($items)); + + return $o; +} diff --git a/sources/mod/new_channel.php b/sources/mod/new_channel.php new file mode 100644 index 00000000..047048f0 --- /dev/null +++ b/sources/mod/new_channel.php @@ -0,0 +1,127 @@ + 1) ? argv(1) : ''); + + + if($cmd === 'autofill.json') { + require_once('library/urlify/URLify.php'); + $result = array('error' => false, 'message' => ''); + $n = trim($_REQUEST['name']); + + $x = strtolower(URLify::transliterate($n)); + + $test = array(); + + // first name + if(strpos($x,' ')) + $test[] = legal_webbie(substr($x,0,strpos($x,' '))); + if($test[0]) { + // first name plus first initial of last + $test[] = ((strpos($x,' ')) ? $test[0] . legal_webbie(trim(substr($x,strpos($x,' '),2))) : ''); + // first name plus random number + $test[] = $test[0] . mt_rand(1000,9999); + } + // fullname + $test[] = legal_webbie($x); + // fullname plus random number + $test[] = legal_webbie($x) . mt_rand(1000,9999); + + json_return_and_die(check_webbie($test)); + } + + if($cmd === 'checkaddr.json') { + require_once('library/urlify/URLify.php'); + $result = array('error' => false, 'message' => ''); + $n = trim($_REQUEST['nick']); + + $x = strtolower(URLify::transliterate($n)); + + $test = array(); + + $n = legal_webbie($x); + if(strlen($n)) { + $test[] = $n; + $test[] = $n . mt_rand(1000,9999); + } + + for($y = 0; $y < 100; $y ++) + $test[] = 'id' . mt_rand(1000,9999); + + json_return_and_die(check_webbie($test)); + } + + +} + + +function new_channel_post(&$a) { + + $arr = $_POST; + + if(($arr['account_id'] = get_account_id()) === false) { + notice( t('Permission denied.') . EOL ); + return; + } + + $result = create_identity($arr); + + if(! $result['success']) { + notice($result['message']); + return; + } + + $newuid = $result['channel']['channel_id']; + + change_channel($result['channel']['channel_id']); + + if(! strlen($next_page = get_config('system','workflow_channel_next'))) + $next_page = 'settings'; + + goaway(z_root() . '/' . $next_page); + +} + + + + + + + +function new_channel_content(&$a) { + + if(! get_account_id()) { + notice( t('Permission denied.') . EOL); + return; + } + + $name = ((x($_REQUEST,'name')) ? $_REQUEST['name'] : "" ); + $nickname = ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : "" ); + $privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "" ); + + $o = replace_macros(get_markup_template('new_channel.tpl'), array( + + '$title' => t('Add a Channel'), + '$desc' => t('A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows.'), + + '$label_name' => t('Channel Name'), + '$help_name' => t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group" '), + '$label_nick' => t('Choose a short nickname'), + '$nick_desc' => t('Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others.'), + '$label_import' => t('Or import an existing channel from another location'), + '$name' => $name, + '$help_role' => t('Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you'), + '$role' => array('permissions_role' , t('Channel Type'), ($privacy_role) ? $privacy_role : 'social', ''.t('Read more about roles').'',get_roles()), + '$nickname' => $nickname, + '$submit' => t('Create') + )); + + return $o; + +} + diff --git a/sources/mod/notes.php b/sources/mod/notes.php new file mode 100644 index 00000000..4bb97fc9 --- /dev/null +++ b/sources/mod/notes.php @@ -0,0 +1,24 @@ + true); + if($_REQUEST['note_text'] || $_REQUEST['note_text'] == '') { + $body = escape_tags($_REQUEST['note_text']); + set_pconfig(local_channel(),'notes','text',$body); + } + + // push updates to channel clones + + if((argc() > 1) && (argv(1) === 'sync')) { + require_once('include/zot.php'); + build_sync_packet(); + } + + logger('notes saved.', LOGGER_DEBUG); + json_return_and_die($ret); + +} diff --git a/sources/mod/notifications.php b/sources/mod/notifications.php new file mode 100644 index 00000000..f679fbb3 --- /dev/null +++ b/sources/mod/notifications.php @@ -0,0 +1,105 @@ +argc > 1) ? $a->argv[1] : 0); + + if($request_id === "all") + return; + + if($request_id) { + + $r = q("SELECT * FROM `intro` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($request_id), + intval(local_channel()) + ); + + if(count($r)) { + $intro_id = $r[0]['id']; + $contact_id = $r[0]['contact-id']; + } + else { + notice( t('Invalid request identifier.') . EOL); + return; + } + + // If it is a friend suggestion, the contact is not a new friend but an existing friend + // that should not be deleted. + + $fid = $r[0]['fid']; + + if($_POST['submit'] == t('Discard')) { + $r = q("DELETE FROM `intro` WHERE `id` = %d", + intval($intro_id) + ); + if(! $fid) { + + // The check for blocked and pending is in case the friendship was already approved + // and we just want to get rid of the now pointless notification + + $r = q("DELETE FROM `contact` WHERE `id` = %d AND `uid` = %d AND `self` = 0 AND `blocked` = 1 AND `pending` = 1", + intval($contact_id), + intval(local_channel()) + ); + } + goaway($a->get_baseurl(true) . '/notifications/intros'); + } + if($_POST['submit'] == t('Ignore')) { + $r = q("UPDATE `intro` SET `ignore` = 1 WHERE `id` = %d", + intval($intro_id)); + goaway($a->get_baseurl(true) . '/notifications/intros'); + } + } +} + + + + + +function notifications_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + nav_set_selected('notifications'); + + $o = ''; + + $notif_tpl = get_markup_template('notifications.tpl'); + + $not_tpl = get_markup_template('notify.tpl'); + require_once('include/bbcode.php'); + + $r = q("SELECT * from notify where uid = %d and seen = 0 order by date desc", + intval(local_channel()) + ); + + if (count($r) > 0) { + $notifications_available =1; + foreach ($r as $it) { + $notif_content .= replace_macros($not_tpl,array( + '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], + '$item_image' => $it['photo'], + '$item_text' => strip_tags(bbcode($it['msg'])), + '$item_when' => relative_date($it['date']) + )); + } + } else { + $notif_content .= t('No more system notifications.'); + } + + $o .= replace_macros($notif_tpl,array( + '$notif_header' => t('System Notifications'), + '$notif_link_mark_seen' => t('Mark all system notifications seen'), + '$notif_content' => $notif_content, + '$notifications_available' => $notifications_available, + )); + + return $o; +} diff --git a/sources/mod/notify.php b/sources/mod/notify.php new file mode 100644 index 00000000..4c9d1977 --- /dev/null +++ b/sources/mod/notify.php @@ -0,0 +1,64 @@ + 2 && argv(1) === 'view' && intval(argv(2))) { + $r = q("select * from notify where id = %d and uid = %d limit 1", + intval(argv(2)), + intval(local_channel()) + ); + if($r) { + q("update notify set seen = 1 where (( parent != '' and parent = '%s' and otype = '%s' ) or link = '%s' ) and uid = %d", + dbesc($r[0]['parent']), + dbesc($r[0]['otype']), + dbesc($r[0]['link']), + intval(local_channel()) + ); + goaway($r[0]['link']); + } + goaway($a->get_baseurl(true)); + } + + +} + + +function notify_content(&$a) { + if(! local_channel()) + return login(); + + $notif_tpl = get_markup_template('notifications.tpl'); + + $not_tpl = get_markup_template('notify.tpl'); + require_once('include/bbcode.php'); + + $r = q("SELECT * from notify where uid = %d and seen = 0 order by date desc", + intval(local_channel()) + ); + + if($r) { + foreach ($r as $it) { + $notif_content .= replace_macros($not_tpl,array( + '$item_link' => $a->get_baseurl(true).'/notify/view/'. $it['id'], + '$item_image' => $it['photo'], + '$item_text' => strip_tags(bbcode($it['msg'])), + '$item_when' => relative_date($it['date']) + )); + } + } + else { + $notif_content .= t('No more system notifications.'); + } + + $o .= replace_macros($notif_tpl,array( + '$notif_header' => t('System Notifications'), + '$tabs' => '', // $tabs, + '$notif_content' => $notif_content, + )); + + return $o; + +} \ No newline at end of file diff --git a/sources/mod/oembed.php b/sources/mod/oembed.php new file mode 100644 index 00000000..d4a4424f --- /dev/null +++ b/sources/mod/oembed.php @@ -0,0 +1,30 @@ +query_string, LOGGER_ALL); + + if(argc() > 1) { + if (argv(1) == 'b2h'){ + $url = array( "", trim(hex2bin($_REQUEST['url']))); + echo oembed_replacecb($url); + killme(); + } + + elseif (argv(1) == 'h2b'){ + $text = trim(hex2bin($_REQUEST['text'])); + echo oembed_html2bbcode($text); + killme(); + } + + else { + echo ""; + $src = base64url_decode(argv(1)); + $j = oembed_fetch_url($src); + echo $j->html; +// logger('mod-oembed ' . $h, LOGGER_ALL); + echo ""; + } + } + killme(); +} diff --git a/sources/mod/oexchange.php b/sources/mod/oexchange.php new file mode 100644 index 00000000..867cea6f --- /dev/null +++ b/sources/mod/oexchange.php @@ -0,0 +1,71 @@ + 1) && (argv(1) === 'xrd')) { + $tpl = get_markup_template('oexchange_xrd.tpl'); + + $o = replace_macros($tpl, array('$base' => $a->get_baseurl())); + echo $o; + killme(); + } +} + +function oexchange_content(&$a) { + + if(! local_channel()) { + if(remote_channel()) { + $observer = $a->get_observer(); + if($observer && $observer['xchan_url']) { + $parsed = @parse_url($observer['xchan_url']); + if(! $parsed) { + notice( t('Unable to find your hub.') . EOL); + return; + } + $url = $parsed['scheme'] . '://' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : ''); + $url .= '/oexchange'; + $result = z_post_url($url,$_REQUEST); + json_return_and_die($result); + } + } + + return login(false); + } + + if((argc() > 1) && argv(1) === 'done') { + info( t('Post successful.') . EOL); + return; + } + + $url = (((x($_REQUEST,'url')) && strlen($_REQUEST['url'])) + ? urlencode(notags(trim($_REQUEST['url']))) : ''); + $title = (((x($_REQUEST,'title')) && strlen($_REQUEST['title'])) + ? '&title=' . urlencode(notags(trim($_REQUEST['title']))) : ''); + $description = (((x($_REQUEST,'description')) && strlen($_REQUEST['description'])) + ? '&description=' . urlencode(notags(trim($_REQUEST['description']))) : ''); + $tags = (((x($_REQUEST,'tags')) && strlen($_REQUEST['tags'])) + ? '&tags=' . urlencode(notags(trim($_REQUEST['tags']))) : ''); + + $ret = z_fetch_url($a->get_baseurl() . '/urlinfo?f=&url=' . $url . $title . $description . $tags); + + if($ret['success']) + $s = $ret['body']; + + if(! strlen($s)) + return; + + $post = array(); + + $post['profile_uid'] = local_channel(); + $post['return'] = '/oexchange/done' ; + $post['body'] = $s; + $post['type'] = 'wall'; + + $_REQUEST = $post; + require_once('mod/item.php'); + item_post($a); + +} + + diff --git a/sources/mod/online.php b/sources/mod/online.php new file mode 100644 index 00000000..c6500347 --- /dev/null +++ b/sources/mod/online.php @@ -0,0 +1,11 @@ + false); + if(argc() != 2) + json_return_and_die($ret); + + $ret = get_online_status(argv(1)); + json_return_and_die($ret); +} diff --git a/sources/mod/openid.php b/sources/mod/openid.php new file mode 100644 index 00000000..70da2690 --- /dev/null +++ b/sources/mod/openid.php @@ -0,0 +1,192 @@ +validate()) { + + logger('openid: validate'); + + $authid = normalise_openid($_REQUEST['openid_identity']); + + if(! strlen($authid)) { + logger( t('OpenID protocol error. No ID returned.') . EOL); + goaway(z_root()); + } + + $x = match_openid($authid); + if($x) { + + $r = q("select * from channel where channel_id = %d limit 1", + intval($x) + ); + if($r) { + $y = q("select * from account where account_id = %d limit 1", + intval($r[0]['channel_account_id']) + ); + if($y) { + foreach($y as $record) { + if(($record['account_flags'] == ACCOUNT_OK) || ($record['account_flags'] == ACCOUNT_UNVERIFIED)) { + logger('mod_openid: openid success for ' . $x[0]['channel_name']); + $_SESSION['uid'] = $r[0]['channel_id']; + $_SESSION['account_id'] = $r[0]['channel_account_id']; + $_SESSION['authenticated'] = true; + authenticate_success($record,true,true,true,true); + goaway(z_root()); + } + } + } + } + } + + // Successful OpenID login - but we can't match it to an existing account. + // See if they've got an xchan + + $r = q("select * from xconfig left join xchan on xchan_hash = xconfig.xchan where cat = 'system' and k = 'openid' and v = '%s' limit 1", + dbesc($authid) + ); + + if($r) { + $_SESSION['authenticated'] = 1; + $_SESSION['visitor_id'] = $r[0]['xchan_hash']; + $_SESSION['my_url'] = $r[0]['xchan_url']; + $_SESSION['my_address'] = $r[0]['xchan_addr']; + $arr = array('xchan' => $r[0], 'session' => $_SESSION); + call_hooks('magic_auth_openid_success',$arr); + $a->set_observer($r[0]); + require_once('include/security.php'); + $a->set_groups(init_groups_visitor($_SESSION['visitor_id'])); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$r[0]['xchan_name'])); + logger('mod_openid: remote auth success from ' . $r[0]['xchan_addr']); + if($_SESSION['return_url']) + goaway($_SESSION['return_url']); + goaway(z_root()); + } + + // no xchan... + // create one. + // We should probably probe the openid url and figure out if they have any kind of social presence we might be able to + // scrape some identifying info from. + + $name = $authid; + $url = trim($_REQUEST['openid_identity'],'/'); + if(strpos($url,'http') === false) + $url = 'https://' . $url; + $pphoto = z_root() . '/' . get_default_profile_photo(); + $parsed = @parse_url($url); + if($parsed) { + $host = $parsed['host']; + } + + $attr = $openid->getAttributes(); + + if(is_array($attr) && count($attr)) { + foreach($attr as $k => $v) { + if($k === 'namePerson/friendly') + $nick = notags(trim($v)); + if($k === 'namePerson/first') + $first = notags(trim($v)); + if($k === 'namePerson') + $name = notags(trim($v)); + if($k === 'contact/email') + $addr = notags(trim($v)); + if($k === 'media/image/aspect11') + $photosq = trim($v); + if($k === 'media/image/default') + $photo_other = trim($v); + } + } + if(! $nick) { + if($first) + $nick = $first; + else + $nick = $name; + } + + require_once('library/urlify/URLify.php'); + $x = strtolower(URLify::transliterate($nick)); + if($nick & $host) + $addr = $nick . '@' . $host; + $network = 'unknown'; + + if($photosq) + $pphoto = $photosq; + elseif($photo_other) + $pphoto = $photo_other; + + $mimetype = guess_image_type($pphoto); + + $x = q("insert into xchan ( xchan_hash, xchan_guid, xchan_guid_sig, xchan_pubkey, xchan_photo_mimetype, + xchan_photo_l, xchan_addr, xchan_url, xchan_connurl, xchan_follow, xchan_connpage, xchan_name, xchan_network, xchan_photo_date, + xchan_name_date, xchan_hidden) + values ( '%s', '%s', '%s', '%s' , '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', 1) ", + dbesc($url), + dbesc(''), + dbesc(''), + dbesc(''), + dbesc($mimetype), + dbesc($pphoto), + dbesc($addr), + dbesc($url), + dbesc(''), + dbesc(''), + dbesc(''), + dbesc($name), + dbesc($network), + dbesc(datetime_convert()), + dbesc(datetime_convert()) + ); + if($x) { + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($url) + ); + if($r) { + + $photos = import_profile_photo($pphoto,$url); + if($photos) { + $z = q("update xchan set xchan_photo_date = '%s', xchan_photo_l = '%s', xchan_photo_m = '%s', + xchan_photo_s = '%s', xchan_photo_mimetype = '%s' where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($photos[0]), + dbesc($photos[1]), + dbesc($photos[2]), + dbesc($photos[3]), + dbesc($url) + ); + } + + set_xconfig($url,'system','openid',$authid); + $_SESSION['authenticated'] = 1; + $_SESSION['visitor_id'] = $r[0]['xchan_hash']; + $_SESSION['my_url'] = $r[0]['xchan_url']; + $_SESSION['my_address'] = $r[0]['xchan_addr']; + $arr = array('xchan' => $r[0], 'session' => $_SESSION); + call_hooks('magic_auth_openid_success',$arr); + $a->set_observer($r[0]); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$r[0]['xchan_name'])); + logger('mod_openid: remote auth success from ' . $r[0]['xchan_addr']); + if($_SESSION['return_url']) + goaway($_SESSION['return_url']); + goaway(z_root()); + } + } + + } + } + notice( t('Login failed.') . EOL); + goaway(z_root()); + // NOTREACHED +} diff --git a/sources/mod/opensearch.php b/sources/mod/opensearch.php new file mode 100644 index 00000000..d28c4f1b --- /dev/null +++ b/sources/mod/opensearch.php @@ -0,0 +1,18 @@ + $a->get_baseurl(), + '$nodename' => $a->get_hostname(), + )); + + echo $o; + + killme(); + +} diff --git a/sources/mod/page.php b/sources/mod/page.php new file mode 100644 index 00000000..b635a60f --- /dev/null +++ b/sources/mod/page.php @@ -0,0 +1,137 @@ +profile['profile_uid']) + head_set_icon($a->profile['thumb']); + + // load the item here in the init function because we need to extract + // the page layout and initialise the correct theme. + + + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + + // perm_is_allowed is denied unconditionally when 'site blocked to unauthenticated members'. + // This bypasses that restriction for sys channel (public) content + + if((! perm_is_allowed($a->profile['profile_uid'],$ob_hash,'view_pages')) && (! is_sys_channel($a->profile['profile_uid']))) { + notice( t('Permission denied.') . EOL); + return; + } + + if(argc() < 3) { + notice( t('Invalid item.') . EOL); + return; + } + + $channel_address = argv(1); + + // The page link title was stored in a urlencoded format + // php or the browser may/will have decoded it, so re-encode it for our search + + $page_id = urlencode(argv(2)); + + $u = q("select channel_id from channel where channel_address = '%s' limit 1", + dbesc($channel_address) + ); + + if(! $u) { + notice( t('Channel not found.') . EOL); + return; + } + + if($_REQUEST['rev']) + $revision = " and revision = " . intval($_REQUEST['rev']) . " "; + else + $revision = " order by revision desc "; + + require_once('include/security.php'); + $sql_options = item_permissions_sql($u[0]['channel_id']); + + $r = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and (( service = 'WEBPAGE' and item_type = %d ) + OR ( service = 'PDL' AND item_type = %d )) $sql_options $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_WEBPAGE), + intval(ITEM_TYPE_PDL) + ); + if(! $r) { + + // Check again with no permissions clause to see if it is a permissions issue + + $x = q("select item.* from item left join item_id on item.id = item_id.iid + where item.uid = %d and sid = '%s' and service = 'WEBPAGE' and + item_type = %d $revision limit 1", + intval($u[0]['channel_id']), + dbesc($page_id), + intval(ITEM_TYPE_WEBPAGE) + ); + + if($x) { + // Yes, it's there. You just aren't allowed to see it. + notice( t('Permission denied.') . EOL); + } + else { + notice( t('Page not found.') . EOL); + } + return; + } + + if($r[0]['item_type'] == ITEM_TYPE_PDL) { + require_once('include/comanche.php'); + comanche_parser(get_app(),$r[0]['body']); + get_app()->pdl = $r[0]['body']; + } + elseif($r[0]['layout_mid']) { + $l = q("select body from item where mid = '%s' and uid = %d limit 1", + dbesc($r[0]['layout_mid']), + intval($u[0]['channel_id']) + ); + + if($l) { + require_once('include/comanche.php'); + comanche_parser(get_app(),$l[0]['body']); + get_app()->pdl = $l[0]['body']; + } + } + + $a->data['webpage'] = $r; + +} + + + + +function page_content(&$a) { + + $r = $a->data['webpage']; + if(! $r) + return; + + if($r[0]['item_type'] == ITEM_TYPE_PDL) { + $r[0]['body'] = t('Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'); + $r[0]['mimetype'] = 'text/plain'; + $r[0]['title'] = ''; + + } + + xchan_query($r); + $r = fetch_post_tags($r,true); + $o .= prepare_page($r[0]); + return $o; + +} diff --git a/sources/mod/pconfig.php b/sources/mod/pconfig.php new file mode 100755 index 00000000..413dd291 --- /dev/null +++ b/sources/mod/pconfig.php @@ -0,0 +1,113 @@ +' . t('Configuration Editor') . ''; + $content .= '
    ' . t('Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature.') . '
    ' . EOL . EOL; + + + + if(argc() == 3) { + $content .= 'pconfig[' . local_channel() . ']' . EOL; + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . ']' . EOL . EOL; + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . escape_tags(argv(2)) . '] = ' . get_pconfig(local_channel(),escape_tags(argv(1)),escape_tags(argv(2))) . EOL; + + if(in_array(argv(2),disallowed_pconfig())) { + notice( t('This setting requires special processing and editing has been blocked.') . EOL); + return $content; + } + else + $content .= pconfig_form(escape_tags(argv(1)),escape_tags(argv(2))); + } + + + if(argc() == 2) { + $content .= 'pconfig[' . local_channel() . ']' . EOL; + load_pconfig(local_channel(),escape_tags(argv(1))); + foreach($a->config[local_channel()][escape_tags(argv(1))] as $k => $x) { + $content .= 'pconfig[' . local_channel() . '][' . escape_tags(argv(1)) . '][' . $k . '] = ' . escape_tags($x) . EOL; + } + } + + if(argc() == 1) { + + $r = q("select * from pconfig where uid = " . local_channel()); + if($r) { + foreach($r as $rr) { + $content .= 'pconfig[' . local_channel() . '][' . escape_tags($rr['cat']) . '][' . escape_tags($rr['k']) . '] = ' . escape_tags($rr['v']) . EOL; + } + } + } + return $content; + +} + + +function pconfig_form($cat,$k) { + + $o = '
    '; + $o .= ''; + + $v = get_pconfig(local_channel(),$cat,$k); + if(strpos($k,'password') !== false) + $v = z_unobscure($v); + + $o .= ''; + $o .= ''; + + if(strpos($v,"\n")) + $o .= ''; + else + $o .= ''; + + $o .= EOL . EOL; + $o .= ''; + $o .= '
    '; + + return $o; + +} diff --git a/sources/mod/pdledit.php b/sources/mod/pdledit.php new file mode 100644 index 00000000..93b8d52e --- /dev/null +++ b/sources/mod/pdledit.php @@ -0,0 +1,62 @@ + 1) + $module = 'mod_' . argv(1) . '.pdl'; + else { + $o .= '

    ' . t('Edit System Page Description') . '

    '; + $files = glob('mod/*'); + if($files) { + foreach($files as $f) { + $name = basename($f,'.php'); + $x = theme_include('mod_' . $name . '.pdl'); + if($x) { + $o .= '' . $name . '
    '; + } + } + } + + // list module pdl files + return $o; + } + + $t = get_pconfig(local_channel(),'system',$module); + if(! $t) + $t = file_get_contents(theme_include($module)); + if(! $t) { + notice( t('Layout not found.') . EOL); + return ''; + } + + $o = replace_macros(get_markup_template('pdledit.tpl'),array( + '$header' => t('Edit System Page Description'), + '$mname' => t('Module Name:'), + '$help' => t('Layout Help'), + '$module' => argv(1), + '$content' => htmlspecialchars($t,ENT_COMPAT,'UTF-8'), + '$submit' => t('Submit') + )); + + return $o; +} diff --git a/sources/mod/photo.php b/sources/mod/photo.php new file mode 100644 index 00000000..e8cd95f1 --- /dev/null +++ b/sources/mod/photo.php @@ -0,0 +1,244 @@ + 1)) + { + $resolution = 1; + } + } + + // If using resolution 1, make sure it exists before proceeding: + if ($resolution == 1) + { + $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1", + dbesc($photo), + intval($resolution) + ); + if (!($r)) + $resolution = 2; + } + + $r = q("SELECT uid FROM photo WHERE resource_id = '%s' AND scale = %d LIMIT 1", + dbesc($photo), + intval($resolution) + ); + if($r) { + + $allowed = (($r[0]['uid']) ? perm_is_allowed($r[0]['uid'],$observer_xchan,'view_storage') : true); + + $sql_extra = permissions_sql($r[0]['uid']); + + // Now we'll see if we can access the photo + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND scale = %d $sql_extra LIMIT 1", + dbesc($photo), + intval($resolution) + ); + + if($r && $allowed) { + $data = dbunescbin($r[0]['data']); + $mimetype = $r[0]['type']; + if(intval($r[0]['os_storage'])) + $data = file_get_contents($data); + } + else { + + // Does the picture exist? It may be a remote person with no credentials, + // but who should otherwise be able to view it. Show a default image to let + // them know permissions was denied. It may be possible to view the image + // through an authenticated profile visit. + // There won't be many completely unauthorised people seeing this because + // they won't have the photo link, so there's a reasonable chance that the person + // might be able to obtain permission to view it. + + $r = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `scale` = %d LIMIT 1", + dbesc($photo), + intval($resolution) + ); + + if($r) { + logger('mod_photo: forbidden. ' . $a->query_string); + $observer = $a->get_observer(); + logger('mod_photo: observer = ' . (($observer) ? $observer['xchan_addr'] : '(not authenticated)')); + $data = file_get_contents('images/nosign.png'); + $mimetype = 'image/png'; + $prvcachecontrol = true; + } + } + } + } + + if(! isset($data)) { + if(isset($resolution)) { + switch($resolution) { + + case 4: + $data = file_get_contents(get_default_profile_photo()); + $mimetype = 'image/png'; + break; + case 5: + $data = file_get_contents(get_default_profile_photo(80)); + $mimetype = 'image/png'; + break; + case 6: + $data = file_get_contents(get_default_profile_photo(48)); + $mimetype = 'image/png'; + break; + default: + killme(); + // NOTREACHED + break; + } + } + } + + if(isset($res) && intval($res) && $res < 500) { + $ph = photo_factory($data, $mimetype); + if($ph->is_valid()) { + $ph->scaleImageSquare($res); + $data = $ph->imageString(); + $mimetype = $ph->getType(); + } + } + + // Writing in cachefile + if (isset($cachefile) && $cachefile != '') + file_put_contents($cachefile, $data); + + if(function_exists('header_remove')) { + header_remove('Pragma'); + header_remove('pragma'); + } + + header("Content-type: " . $mimetype); + + if($prvcachecontrol) { + + // it is a private photo that they have no permission to view. + // tell the browser not to cache it, in case they authenticate + // and subsequently have permission to see it + + header("Cache-Control: no-store, no-cache, must-revalidate"); + + } + else { + // The photo cache default is 1 day to provide a privacy trade-off, + // as somebody reducing photo permissions on a photo that is already + // "in the wild" won't be able to stop the photo from being viewed + // for this amount amount of time once it is in the browser cache. + // The privacy expectations of your site members and their perception + // of privacy where it affects the entire project may be affected. + // This has performance considerations but we highly recommend you + // leave it alone. + + $cache = get_config('system','photo_cache_time'); + if(! $cache) + $cache = (3600 * 24); // 1 day + + header("Expires: " . gmdate("D, d M Y H:i:s", time() + $cache) . " GMT"); + header("Cache-Control: max-age=" . $cache); + + } + echo $data; + killme(); + // NOTREACHED +} diff --git a/sources/mod/photos.php b/sources/mod/photos.php new file mode 100644 index 00000000..dc70e4f9 --- /dev/null +++ b/sources/mod/photos.php @@ -0,0 +1,1298 @@ + 1) { + $nick = argv(1); + + profile_load($a,$nick); + + $channelx = channelx_by_nick($nick); + + if(! $channelx) + return; + + $a->data['channel'] = $channelx; + + $observer = $a->get_observer(); + $a->data['observer'] = $observer; + + $observer_xchan = (($observer) ? $observer['xchan_hash'] : ''); + + head_set_icon($a->data['channel']['xchan_photo_s']); + + $a->page['htmlhead'] .= "" ; + + } + + return; +} + + + +function photos_post(&$a) { + + logger('mod-photos: photos_post: begin' , LOGGER_DEBUG); + + + logger('mod_photos: REQUEST ' . print_r($_REQUEST,true), LOGGER_DATA); + logger('mod_photos: FILES ' . print_r($_FILES,true), LOGGER_DATA); + + $ph = photo_factory(''); + + $phototypes = $ph->supportedTypes(); + + $can_post = false; + + $page_owner_uid = $a->data['channel']['channel_id']; + + if(perm_is_allowed($page_owner_uid,get_observer_hash(),'write_storage')) + $can_post = true; + + if(! $can_post) { + notice( t('Permission denied.') . EOL ); + if(is_ajax()) + killme(); + return; + } + + $s = abook_self($page_owner_uid); + + if(! $s) { + notice( t('Page owner information could not be retrieved.') . EOL); + logger('mod_photos: post: unable to locate contact record for page owner. uid=' . $page_owner_uid); + if(is_ajax()) + killme(); + return; + } + + $owner_record = $s[0]; + + + if((argc() > 3) && (argv(2) === 'album')) { + + $album = hex2bin(argv(3)); + + if($album === t('Profile Photos')) { + // not allowed + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + } + + if(! photos_album_exists($page_owner_uid,$album)) { + notice( t('Album not found.') . EOL); + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + } + + + /* + * RENAME photo album + */ + + $newalbum = notags(trim($_REQUEST['albumname'])); + if($newalbum != $album) { + + // @fixme - syncronise with DAV or disallow completely + + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + +// $x = photos_album_rename($page_owner_uid,$album,$newalbum); +// if($x) { +// $newurl = str_replace(bin2hex($album),bin2hex($newalbum),$_SESSION['photo_return']); +// goaway($a->get_baseurl() . '/' . $newurl); +// } + } + + /* + * DELETE photo album and all its photos + */ + + if($_REQUEST['dropalbum'] == t('Delete Album')) { + + $res = array(); + + // get the list of photos we are about to delete + + if(remote_channel() && (! local_channel())) { + $str = photos_album_get_db_idstr($page_owner_uid,$album,remote_channel()); + } + elseif(local_channel()) { + $str = photos_album_get_db_idstr(local_channel(),$album); + } + else { + $str = null; + } + if(! $str) { + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + } + + $r = q("select id from item where resource_id in ( $str ) and resource_type = 'photo' and uid = %d " . item_normal(), + intval($page_owner_uid) + ); + if($r) { + foreach($r as $i) { + attach_delete($page_owner_uid, $i['resource_id'], 1 ); + drop_item($i['id'],false,DROPITEM_PHASE1,true /* force removal of linked items */); + proc_run('php','include/notifier.php','drop',$i['id']); + } + } + + // remove the associated photos in case they weren't attached to an item + + q("delete from photo where resource_id in ( $str ) and uid = %d", + intval($page_owner_uid) + ); + + // @FIXME do the same for the linked attach + + } + + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address']); + } + + if((argc() > 2) && (x($_REQUEST,'delete')) && ($_REQUEST['delete'] === t('Delete Photo'))) { + + // same as above but remove single photo + + $ob_hash = get_observer_hash(); + if(! $ob_hash) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $r = q("SELECT `id`, `resource_id` FROM `photo` WHERE ( xchan = '%s' or `uid` = %d ) AND `resource_id` = '%s' LIMIT 1", + dbesc($ob_hash), + intval(local_channel()), + dbesc($a->argv[2]) + ); + + if($r) { + q("DELETE FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s'", + intval($page_owner_uid), + dbesc($r[0]['resource_id']) + ); + attach_delete($page_owner_uid, $r[0]['resource_id'], 1 ); + + $i = q("SELECT * FROM `item` WHERE `resource_id` = '%s' AND resource_type = 'photo' and `uid` = %d LIMIT 1", + dbesc($r[0]['resource_id']), + intval($page_owner_uid) + ); + if(count($i)) { + drop_item($i[0]['id'],true,DROPITEM_PHASE1); + $url = $a->get_baseurl(); + } + } + + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . $_SESSION['album_return']); + } + + if(($a->argc > 2) && ((x($_POST,'desc') !== false) || (x($_POST,'newtag') !== false)) || (x($_POST,'albname') !== false)) { + + + $desc = ((x($_POST,'desc')) ? notags(trim($_POST['desc'])) : ''); + $rawtags = ((x($_POST,'newtag')) ? notags(trim($_POST['newtag'])) : ''); + $item_id = ((x($_POST,'item_id')) ? intval($_POST['item_id']) : 0); + $albname = ((x($_POST,'albname')) ? notags(trim($_POST['albname'])) : ''); + $is_nsfw = ((x($_POST,'adult')) ? intval($_POST['adult']) : 0); + $str_group_allow = perms2str($_POST['group_allow']); + $str_contact_allow = perms2str($_POST['contact_allow']); + $str_group_deny = perms2str($_POST['group_deny']); + $str_contact_deny = perms2str($_POST['contact_deny']); + + $resource_id = $a->argv[2]; + + if(! strlen($albname)) + $albname = datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'); + + + if((x($_POST,'rotate') !== false) && + ( (intval($_POST['rotate']) == 1) || (intval($_POST['rotate']) == 2) )) { + logger('rotate'); + + $r = q("select * from photo where `resource_id` = '%s' and uid = %d and scale = 0 limit 1", + dbesc($resource_id), + intval($page_owner_uid) + ); + if(count($r)) { + $ph = photo_factory(dbunescbin($r[0]['data']), $r[0]['type']); + if($ph->is_valid()) { + $rotate_deg = ( (intval($_POST['rotate']) == 1) ? 270 : 90 ); + $ph->rotate($rotate_deg); + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 0", + dbescbin($ph->imageString()), + intval($height), + intval($width), + dbesc($resource_id), + intval($page_owner_uid) + ); + + if($width > 640 || $height > 640) { + $ph->scaleImage(640); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 1", + dbescbin($ph->imageString()), + intval($height), + intval($width), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + + if($width > 320 || $height > 320) { + $ph->scaleImage(320); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + $x = q("update photo set data = '%s', height = %d, width = %d where `resource_id` = '%s' and uid = %d and scale = 2", + dbescbin($ph->imageString()), + intval($height), + intval($width), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + } + } + } + + $p = q("SELECT * FROM `photo` WHERE `resource_id` = '%s' AND `uid` = %d ORDER BY `scale` DESC", + dbesc($resource_id), + intval($page_owner_uid) + ); + if($p) { + $ext = $phototypes[$p[0]['type']]; + + $r = q("UPDATE `photo` SET `description` = '%s', `allow_cid` = '%s', `allow_gid` = '%s', `deny_cid` = '%s', `deny_gid` = '%s' WHERE `resource_id` = '%s' AND `uid` = %d", + dbesc($desc), + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + + $item_private = (($str_contact_allow || $str_group_allow || $str_contact_deny || $str_group_deny) ? true : false); + + $old_is_nsfw = $p[0]['is_nsfw']; + if($old_is_nsfw != $is_nsfw) { + $r = q("update photo set is_nsfw = %d where resource_id = '%s' and uid = %d", + intval($is_nsfw), + dbesc($resource_id), + intval($page_owner_uid) + ); + } + + /* Don't make the item visible if the only change was the album name */ + + $visibility = 0; + if($p[0]['description'] !== $desc || strlen($rawtags)) + $visibility = 1; + + if(! $item_id) { + $item_id = photos_create_item($a->data['channel'],get_observer_hash(),$p[0],$visibility); + + } + + if($item_id) { + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($item_id), + intval($page_owner_uid) + ); + + if($r) { + $old_tag = $r[0]['tag']; + $old_inform = $r[0]['inform']; + } + } + + + // make sure the linked item has the same permissions as the photo regardless of any other changes + $x = q("update item set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s', item_private = %d + where id = %d", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval($item_private), + intval($item_id) + ); + + // make sure the attach has the same permissions as the photo regardless of any other changes + $x = q("update attach set allow_cid = '%s', allow_gid = '%s', deny_cid = '%s', deny_gid = '%s' where hash = '%s' and uid = %d and is_photo = 1", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + dbesc($resource_id), + intval($page_owner_uid) + ); + + + + if(strlen($rawtags)) { + + $str_tags = ''; + $inform = ''; + + // if the new tag doesn't have a namespace specifier (@foo or #foo) give it a mention + + $x = substr($rawtags,0,1); + if($x !== '@' && $x !== '#') + $rawtags = '@' . $rawtags; + + require_once('include/text.php'); + $profile_uid = $a->profile['profile_uid']; + + $results = linkify_tags($a, $rawtags, (local_channel()) ? local_channel() : $profile_uid); + + $success = $results['success']; + $post_tags = array(); + + foreach($results as $result) { + $success = $result['success']; + if($success['replaced']) { + $post_tags[] = array( + 'uid' => $profile_uid, + 'type' => $success['termtype'], + 'otype' => TERM_OBJ_POST, + 'term' => $success['term'], + 'url' => $success['url'] + ); + } + } + + $r = q("select * from item where id = %d and uid = %d limit 1", + intval($item_id), + intval($page_owner_uid) + ); + + if($r) { + $r = fetch_post_tags($r,true); + $datarray = $r[0]; + if($post_tags) { + if((! array_key_exists('term',$datarray)) || (! is_array($datarray['term']))) + $datarray['term'] = $post_tags; + else + $datarray['term'] = array_merge($datarray['term'],$post_tags); + } + item_store_update($datarray,$execflag); + } + + } + + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + return; // NOTREACHED + + } + + + /** + * default post action - upload a photo + */ + + $channel = $a->data['channel']; + $observer = $a->data['observer']; + + $_REQUEST['source'] = 'photos'; + require_once('include/attach.php'); + + if(!local_channel()) { + $_REQUEST['contact_allow'] = expand_acl($channel['channel_allow_cid']); + $_REQUEST['group_allow'] = expand_acl($channel['channel_allow_gid']); + $_REQUEST['contact_deny'] = expand_acl($channel['channel_deny_cid']); + $_REQUEST['group_deny'] = expand_acl($channel['channel_deny_gid']); + } + + $r = attach_store($a->channel,get_observer_hash(), '', $_REQUEST); + + if(! $r['success']) { + notice($r['message'] . EOL); + } + + if($_REQUEST['newalbum']) + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($_REQUEST['newalbum'])); + else + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex(datetime_convert('UTC',date_default_timezone_get(),'now', 'Y'))); + +} + + + +function photos_content(&$a) { + + // URLs: + // photos/name + // photos/name/album/xxxxx (xxxxx is album name) + // photos/name/image/xxxxx + + + if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) { + notice( t('Public access denied.') . EOL); + return; + } + + $unsafe = ((array_key_exists('unsafe',$_REQUEST) && $_REQUEST['unsafe']) ? 1 : 0); + + require_once('include/bbcode.php'); + require_once('include/security.php'); + require_once('include/conversation.php'); + + if(! x($a->data,'channel')) { + notice( t('No photos selected') . EOL ); + return; + } + + $ph = photo_factory(''); + $phototypes = $ph->supportedTypes(); + + $_SESSION['photo_return'] = $a->cmd; + + // + // Parse arguments + // + + $can_comment = perm_is_allowed($a->profile['profile_uid'],get_observer_hash(),'post_comments'); + + if(argc() > 3) { + $datatype = argv(2); + $datum = argv(3); + } else { + if(argc() > 2) { + $datatype = argv(2); + $datum = ''; + } + else + $datatype = 'summary'; + } + + if(argc() > 4) + $cmd = argv(4); + else + $cmd = 'view'; + + // + // Setup permissions structures + // + + $can_post = false; + $visitor = 0; + + + $owner_uid = $a->data['channel']['channel_id']; + $owner_aid = $a->data['channel']['channel_account_id']; + + $observer = $a->get_observer(); + + $can_post = perm_is_allowed($owner_uid,$observer['xchan_hash'],'write_storage'); + $can_view = perm_is_allowed($owner_uid,$observer['xchan_hash'],'view_storage'); + + if(! $can_view) { + notice( t('Access to this item is restricted.') . EOL); + return; + } + + $sql_extra = permissions_sql($owner_uid); + + $o = ""; + + $o .= "\r\n"; + + // tabs + + $_is_owner = (local_channel() && (local_channel() == $owner_uid)); + $o .= profile_tabs($a,$_is_owner, $a->data['channel']['channel_address']); + + /** + * Display upload form + */ + + if( $can_post) { + + $uploader = ''; + + $ret = array('post_url' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'], + 'addon_text' => $uploader, + 'default_upload' => true); + + call_hooks('photo_upload_form',$ret); + + /* Show space usage */ + + $r = q("select sum(size) as total from photo where aid = %d and scale = 0 ", + intval($a->data['channel']['channel_account_id']) + ); + + + $limit = service_class_fetch($a->data['channel']['channel_id'],'photo_upload_limit'); + if($limit !== false) { + $usage_message = sprintf( t("%1$.2f MB of %2$.2f MB photo storage used."), $r[0]['total'] / 1024000, $limit / 1024000 ); + } + else { + $usage_message = sprintf( t('%1$.2f MB photo storage used.'), $r[0]['total'] / 1024000 ); + } + + if($_is_owner) { + $channel = $a->get_channel(); + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + $lockstate = (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'); + } + + $aclselect = (($_is_owner) ? populate_acl($channel_acl,false) : ''); + + $selname = (($datum) ? hex2bin($datum) : ''); + + $albums = ((array_key_exists('albums', $a->data)) ? $a->data['albums'] : photos_albums_list($a->data['channel'],$a->data['observer'])); + + if(! $selname) { + $def_album = get_pconfig($a->data['channel']['channel_id'],'system','photo_path'); + if($def_album) { + $selname = filepath_macro($def_album); + $albums['album'][] = array('text' => $selname); + } + } + + $tpl = get_markup_template('photos_upload.tpl'); + $upload_form = replace_macros($tpl,array( + '$pagename' => t('Upload Photos'), + '$sessid' => session_id(), + '$usage' => $usage_message, + '$nickname' => $a->data['channel']['channel_address'], + '$newalbum_label' => t('Enter an album name'), + '$newalbum_placeholder' => t('or select an existing album (doubleclick)'), + '$visible' => array('visible', t('Create a status post for this upload'), 0, '', array(t('No'), t('Yes'))), + '$albums' => $albums['albums'], + '$selname' => $selname, + '$permissions' => t('Permissions'), + '$aclselect' => $aclselect, + '$lockstate' => $lockstate, + '$uploader' => $ret['addon_text'], + '$default' => (($ret['default_upload']) ? true : false), + '$uploadurl' => $ret['post_url'], + '$submit' => t('Submit') + + )); + + } + + // + // dispatch request + // + + /* + * Display a single photo album + */ + + if($datatype === 'album') { + + if(strlen($datum)) { + if((strlen($datum) & 1) || (! ctype_xdigit($datum))) { + notice( t('Album name could not be decoded') . EOL); + logger('mod_photos: illegal album encoding: ' . $datum); + $datum = ''; + } + } + + $album = (($datum) ? hex2bin($datum) : ''); + + $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` = '%s' + AND `scale` <= 4 and photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY `resource_id`", + intval($owner_uid), + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($unsafe) + ); + if(count($r)) { + $a->set_pager_total(count($r)); + $a->set_pager_itemspage(60); + } else { + goaway($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address']); + } + + if($_GET['order'] === 'posted') + $order = 'ASC'; + else + $order = 'DESC'; + + + $r = q("SELECT p.resource_id, p.id, p.filename, p.type, p.scale, p.description, p.created FROM photo p INNER JOIN + (SELECT resource_id, max(scale) scale FROM photo WHERE uid = %d AND album = '%s' AND scale <= 4 AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY resource_id) ph + ON (p.resource_id = ph.resource_id AND p.scale = ph.scale) + ORDER BY created $order LIMIT %d OFFSET %d", + intval($owner_uid), + dbesc($album), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($unsafe), + intval($a->pager['itemspage']), + intval($a->pager['start']) + ); + + //edit album name + $album_edit = null; + if(($album !== t('Profile Photos')) && ($album !== 'Profile Photos') && ($album !== 'Contact Photos') && ($album !== t('Contact Photos'))) { + if($can_post) { + if($a->get_template_engine() === 'internal') { + $album_e = template_escape($album); + } + else { + $album_e = $album; + } + $albums = ((array_key_exists('albums', $a->data)) ? $a->data['albums'] : photos_albums_list($a->data['channel'],$a->data['observer'])); + + // @fixme - syncronise actions with DAV + +// $edit_tpl = get_markup_template('album_edit.tpl'); +// $album_edit = replace_macros($edit_tpl,array( +// '$nametext' => t('Enter a new album name'), +// '$name_placeholder' => t('or select an existing one (doubleclick)'), +// '$nickname' => $a->data['channel']['channel_address'], +// '$album' => $album_e, +// '$albums' => $albums['albums'], +// '$hexalbum' => bin2hex($album), +// '$submit' => t('Submit'), +// '$dropsubmit' => t('Delete Album') +// )); + + } + } + + if($_GET['order'] === 'posted') + $order = array(t('Show Newest First'), $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($album)); + else + $order = array(t('Show Oldest First'), $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($album) . '?f=&order=posted'); + + $photos = array(); + if(count($r)) { + $twist = 'rotright'; + foreach($r as $rr) { + + if($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; + + $ext = $phototypes[$rr['type']]; + + $imgalt_e = $rr['filename']; + $desc_e = $rr['description']; + + $imagelink = ($a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $rr['resource_id'] + . (($_GET['order'] === 'posted') ? '?f=&order=posted' : '')); + + $photos[] = array( + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2,4), + 'link' => $imagelink, + 'title' => t('View Photo'), + 'src' => $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . $rr['scale'] . '.' .$ext, + 'alt' => $imgalt_e, + 'desc'=> $desc_e, + 'ext' => $ext, + 'hash'=> $rr['resource_id'], + 'unknown' => t('Unknown') + ); + } + } + + if($_REQUEST['aj']) { + if($photos) { + $o = replace_macros(get_markup_template('photosajax.tpl'),array( + '$photos' => $photos, + )); + } + else { + $o = '
    '; + } + echo $o; + killme(); + } + else { + $o .= ""; + $tpl = get_markup_template('photo_album.tpl'); + $o .= replace_macros($tpl, array( + '$photos' => $photos, + '$album' => $album, + '$album_edit' => array(t('Edit Album'), $album_edit), + '$can_post' => $can_post, + '$upload' => array(t('Upload'), $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/upload/' . bin2hex($album)), + '$order' => $order, + '$upload_form' => $upload_form, + '$usage' => $usage_message + )); + + } + + if((! $photos) && ($_REQUEST['aj'])) { + $o .= '
    '; + echo $o; + killme(); + } + +// $o .= paginate($a); + + return $o; + + } + + /** + * Display one photo + */ + + if($datatype === 'image') { + + // fetch image, item containing image, then comments + + $ph = q("SELECT aid,uid,xchan,resource_id,created,edited,title,`description`,album,filename,`type`,height,width,`size`,scale,photo_usage,is_nsfw,allow_cid,allow_gid,deny_cid,deny_gid FROM `photo` WHERE `uid` = %d AND `resource_id` = '%s' + $sql_extra ORDER BY `scale` ASC ", + intval($owner_uid), + dbesc($datum) + ); + + if(! $ph) { + + /* Check again - this time without specifying permissions */ + + $ph = q("SELECT id FROM photo WHERE uid = %d AND resource_id = '%s' LIMIT 1", + intval($owner_uid), + dbesc($datum) + ); + if($ph) + notice( t('Permission denied. Access to this item may be restricted.') . EOL); + else + notice( t('Photo not available') . EOL ); + return; + } + + + + $prevlink = ''; + $nextlink = ''; + + if($_GET['order'] === 'posted') + $order = 'ASC'; + else + $order = 'DESC'; + + + $prvnxt = q("SELECT `resource_id` FROM `photo` WHERE `album` = '%s' AND `uid` = %d AND `scale` = 0 + $sql_extra ORDER BY `created` $order ", + dbesc($ph[0]['album']), + intval($owner_uid) + ); + + if(count($prvnxt)) { + for($z = 0; $z < count($prvnxt); $z++) { + if($prvnxt[$z]['resource_id'] == $ph[0]['resource_id']) { + $prv = $z - 1; + $nxt = $z + 1; + if($prv < 0) + $prv = count($prvnxt) - 1; + if($nxt >= count($prvnxt)) + $nxt = 0; + break; + } + } + + $prevlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$prv]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); + $nextlink = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $prvnxt[$nxt]['resource_id'] . (($_GET['order'] === 'posted') ? '?f=&order=posted' : ''); + } + + + if(count($ph) == 1) + $hires = $lores = $ph[0]; + if(count($ph) > 1) { + if($ph[1]['scale'] == 2) { + // original is 640 or less, we can display it directly + $hires = $lores = $ph[0]; + } + else { + $hires = $ph[0]; + $lores = $ph[1]; + } + } + + $album_link = $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($ph[0]['album']); + $tools = Null; + $lock = Null; + + if($can_post && ($ph[0]['uid'] == $owner_uid)) { + $tools = array( + 'profile'=>array($a->get_baseurl() . '/profile_photo/use/'.$ph[0]['resource_id'], t('Use as profile photo')), + ); + } + + // lockstate + $lockstate = ( ( (strlen($ph[0]['allow_cid']) || strlen($ph[0]['allow_gid']) + || strlen($ph[0]['deny_cid']) || strlen($ph[0]['deny_gid'])) ) + ? array('lock', t('Private Photo')) + : array('unlock', Null)); + + $a->page['htmlhead'] .= ''; + + if($prevlink) + $prevlink = array($prevlink, t('Previous')); + + $photo = array( + 'href' => $a->get_baseurl() . '/photo/' . $hires['resource_id'] . '-' . $hires['scale'] . '.' . $phototypes[$hires['type']], + 'title'=> t('View Full Size'), + 'src' => $a->get_baseurl() . '/photo/' . $lores['resource_id'] . '-' . $lores['scale'] . '.' . $phototypes[$lores['type']] . '?f=&_u=' . datetime_convert('','','','ymdhis') + ); + + if($nextlink) + $nextlink = array($nextlink, t('Next')); + + + // Do we have an item for this photo? + + $linked_items = q("SELECT * FROM item WHERE resource_id = '%s' and resource_type = 'photo' + $sql_extra LIMIT 1", + dbesc($datum) + ); + + $map = null; + + if($linked_items) { + + xchan_query($linked_items); + $linked_items = fetch_post_tags($linked_items,true); + + $link_item = $linked_items[0]; + $item_normal = item_normal(); + + $r = q("select * from item where parent_mid = '%s' + $item_normal and uid = %d $sql_extra ", + dbesc($link_item['mid']), + intval($link_item['uid']) + + ); + + if($r) { + xchan_query($r); + $r = fetch_post_tags($r,true); + $r = conv_sort($r,'commented'); + } + + $tags = array(); + if($link_item['term']) { + $cnt = 0; + foreach($link_item['term'] as $t) { + $tags[$cnt] = array(0 => format_term_for_display($t)); + if($can_post && ($ph[0]['uid'] == $owner_uid)) { + $tags[$cnt][1] = 'tagrm/drop/' . $link_item['id'] . '/' . bin2hex($t['term']); //?f=&item=' . $link_item['id']; + $tags[$cnt][2] = t('Remove'); + } + $cnt ++; + } + } + + if((local_channel()) && (local_channel() == $link_item['uid'])) { + q("UPDATE `item` SET item_unseen = 0 WHERE parent = %d and uid = %d and item_unseen = 1", + intval($link_item['parent']), + intval(local_channel()) + ); + } + + if($link_item['coord']) { + $map = generate_map($link_item['coord']); + } + } + +// logger('mod_photo: link_item' . print_r($link_item,true)); + + // FIXME - remove this when we move to conversation module + + $r = $r[0]['children']; + + $edit = null; + if($can_post) { + $album_e = $ph[0]['album']; + $caption_e = $ph[0]['description']; + $aclselect_e = (($_is_owner) ? populate_acl($ph[0]) : ''); + $albums = ((array_key_exists('albums', $a->data)) ? $a->data['albums'] : photos_albums_list($a->data['channel'],$a->data['observer'])); + + $_SESSION['album_return'] = bin2hex($ph[0]['album']); + + $edit = array( + 'edit' => t('Edit photo'), + 'id' => $link_item['id'], + 'rotatecw' => t('Rotate CW (right)'), + 'rotateccw' => t('Rotate CCW (left)'), + 'albums' => $albums['albums'], + 'album' => $album_e, + 'newalbum_label' => t('Enter a new album name'), + 'newalbum_placeholder' => t('or select an existing one (doubleclick)'), + 'nickname' => $a->data['channel']['channel_address'], + 'resource_id' => $ph[0]['resource_id'], + 'capt_label' => t('Caption'), + 'caption' => $caption_e, + 'tag_label' => t('Add a Tag'), + 'permissions' => t('Permissions'), + 'aclselect' => $aclselect_e, + 'lockstate' => $lockstate[0], + 'help_tags' => t('Example: @bob, @Barbara_Jensen, @jim@example.com'), + 'item_id' => ((count($linked_items)) ? $link_item['id'] : 0), + 'adult_enabled' => feature_enabled($owner_uid,'adult_photo_flagging'), + 'adult' => array('adult',t('Flag as adult in album view'), intval($ph[0]['is_nsfw']),''), + 'submit' => t('Submit'), + 'delete' => t('Delete Photo') + ); + } + + if(count($linked_items)) { + + $cmnt_tpl = get_markup_template('comment_item.tpl'); + $tpl = get_markup_template('photo_item.tpl'); + $return_url = $a->cmd; + + $like_tpl = get_markup_template('like_noshare.tpl'); + + $likebuttons = ''; + + if($can_post || $can_comment) { + $likebuttons = replace_macros($like_tpl,array( + '$id' => $link_item['id'], + '$likethis' => t("I like this \x28toggle\x29"), + '$nolike' => t("I don't like this \x28toggle\x29"), + '$share' => t('Share'), + '$wait' => t('Please wait') + )); + } + + $comments = ''; + if(! count($r)) { + if($can_post || $can_comment) { + $commentbox = replace_macros($cmnt_tpl,array( + '$return_path' => '', + '$mode' => 'photos', + '$jsreload' => $return_url, + '$type' => 'wall-comment', + '$id' => $link_item['id'], + '$parent' => $link_item['id'], + '$profile_uid' => $owner_uid, + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$preview' => t('Preview'), + '$ww' => '', + '$feature_encrypt' => false + )); + } + } + + $alike = array(); + $dlike = array(); + + $like = ''; + $dislike = ''; + + $conv_responses = array( + 'like' => array('title' => t('Likes','title')),'dislike' => array('title' => t('Dislikes','title')), + 'agree' => array('title' => t('Agree','title')),'disagree' => array('title' => t('Disagree','title')), 'abstain' => array('title' => t('Abstain','title')), + 'attendyes' => array('title' => t('Attending','title')), 'attendno' => array('title' => t('Not attending','title')), 'attendmaybe' => array('title' => t('Might attend','title')) + ); + + + + + if($r) { + + foreach($r as $item) { + builtin_activity_puller($item, $conv_responses); + } + + + $like_count = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid']] : ''); + $like_list = ((x($alike,$link_item['mid'])) ? $alike[$link_item['mid'] . '-l'] : ''); + if (count($like_list) > MAX_LIKERS) { + $like_list_part = array_slice($like_list, 0, MAX_LIKERS); + array_push($like_list_part, '' . t('View all') . ''); + } else { + $like_list_part = ''; + } + $like_button_label = tt('Like','Likes',$like_count,'noun'); + + //if (feature_enabled($conv->get_profile_owner(),'dislike')) { + $dislike_count = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid']] : ''); + $dislike_list = ((x($dlike,$link_item['mid'])) ? $dlike[$link_item['mid'] . '-l'] : ''); + $dislike_button_label = tt('Dislike','Dislikes',$dislike_count,'noun'); + if (count($dislike_list) > MAX_LIKERS) { + $dislike_list_part = array_slice($dislike_list, 0, MAX_LIKERS); + array_push($dislike_list_part, '' . t('View all') . ''); + } else { + $dislike_list_part = ''; + } + //} + + + $like = ((isset($alike[$link_item['mid']])) ? format_like($alike[$link_item['mid']],$alike[$link_item['mid'] . '-l'],'like',$link_item['mid']) : ''); + $dislike = ((isset($dlike[$link_item['mid']])) ? format_like($dlike[$link_item['mid']],$dlike[$link_item['mid'] . '-l'],'dislike',$link_item['mid']) : ''); + + // display comments + + foreach($r as $item) { + $comment = ''; + $template = $tpl; + $sparkle = ''; + + if(((activity_match($item['verb'],ACTIVITY_LIKE)) || (activity_match($item['verb'],ACTIVITY_DISLIKE))) && ($item['id'] != $item['parent'])) + continue; + + $redirect_url = $a->get_baseurl() . '/redir/' . $item['cid'] ; + + + $profile_url = zid($item['author']['xchan_url']); + $sparkle = ''; + + + $profile_name = $item['author']['xchan_name']; + $profile_avatar = $item['author']['xchan_photo_m']; + + $profile_link = $profile_url; + + $drop = ''; + + if($observer['xchan_hash'] === $item['author_xchan'] || $observer['xchan_hash'] === $item['owner_xchan']) + $drop = replace_macros(get_markup_template('photo_drop.tpl'), array('$id' => $item['id'], '$delete' => t('Delete'))); + + + $name_e = $profile_name; + $title_e = $item['title']; + unobscure($item); + $body_e = prepare_text($item['body'],$item['mimetype']); + + $comments .= replace_macros($template,array( + '$id' => $item['id'], + '$mode' => 'photos', + '$profile_url' => $profile_link, + '$name' => $name_e, + '$thumb' => $profile_avatar, + '$sparkle' => $sparkle, + '$title' => $title_e, + '$body' => $body_e, + '$ago' => relative_date($item['created']), + '$indent' => (($item['parent'] != $item['id']) ? ' comment' : ''), + '$drop' => $drop, + '$comment' => $comment + )); + + } + + if($can_post || $can_comment) { + $commentbox = replace_macros($cmnt_tpl,array( + '$return_path' => '', + '$jsreload' => $return_url, + '$type' => 'wall-comment', + '$id' => $link_item['id'], + '$parent' => $link_item['id'], + '$profile_uid' => $owner_uid, + '$mylink' => $observer['xchan_url'], + '$mytitle' => t('This is you'), + '$myphoto' => $observer['xchan_photo_s'], + '$comment' => t('Comment'), + '$submit' => t('Submit'), + '$ww' => '' + )); + } + + } + $paginate = paginate($a); + } + + $album_e = array($album_link,$ph[0]['album']); + $like_e = $like; + $dislike_e = $dislike; + + + $response_verbs = array('like'); + if(feature_enabled($owner_uid,'dislike')) + $response_verbs[] = 'dislike'; + + + $responses = get_responses($conv_responses,$response_verbs,'',$link_item); + + $photo_tpl = get_markup_template('photo_view.tpl'); + $o .= replace_macros($photo_tpl, array( + '$id' => $link_item['id'], //$ph[0]['id'], + '$album' => $album_e, + '$tools' => $tools, + '$lock' => $lockstate[1], + '$photo' => $photo, + '$prevlink' => $prevlink, + '$nextlink' => $nextlink, + '$desc' => $ph[0]['description'], + '$filename' => $ph[0]['filename'], + '$unknown' => t('Unknown'), + '$tag_hdr' => t('In This Photo:'), + '$tags' => $tags, + 'responses' => $responses, + '$edit' => $edit, + '$map' => $map, + '$map_text' => t('Map'), + '$likebuttons' => $likebuttons, + '$like' => $like_e, + '$dislike' => $dislike_e, + '$like_count' => $like_count, + '$like_list' => $like_list, + '$like_list_part' => $like_list_part, + '$like_button_label' => $like_button_label, + '$like_modal_title' => t('Likes','noun'), + '$dislike_modal_title' => t('Dislikes','noun'), + '$dislike_count' => $dislike_count, //((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_count : ''), + '$dislike_list' => $dislike_list, //((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list : ''), + '$dislike_list_part' => $dislike_list_part, //((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_list_part : ''), + '$dislike_button_label' => $dislike_button_label, //((feature_enabled($conv->get_profile_owner(),'dislike')) ? $dislike_button_label : ''), + '$modal_dismiss' => t('Close'), + '$comments' => $comments, + '$commentbox' => $commentbox, + '$paginate' => $paginate, + )); + + $a->data['photo_html'] = $o; + + return $o; + } + + // Default - show recent photos with upload link (if applicable) + //$o = ''; + + $r = q("SELECT `resource_id`, max(`scale`) AS `scale` FROM `photo` WHERE `uid` = %d AND `album` != '%s' AND `album` != '%s' + and photo_usage in ( %d, %d ) and is_nsfw = %d $sql_extra GROUP BY `resource_id`", + intval($a->data['channel']['channel_id']), + dbesc('Contact Photos'), + dbesc( t('Contact Photos')), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($unsafe) + ); + if(count($r)) { + $a->set_pager_total(count($r)); + $a->set_pager_itemspage(60); + } + + $r = q("SELECT p.resource_id, p.id, p.filename, p.type, p.album, p.scale, p.created FROM photo p INNER JOIN + (SELECT resource_id, max(scale) scale FROM photo + WHERE uid=%d AND album != '%s' AND album != '%s' + AND photo_usage IN ( %d, %d ) and is_nsfw = %d $sql_extra group by resource_id) ph + ON (p.resource_id = ph.resource_id and p.scale = ph.scale) ORDER by p.created DESC LIMIT %d OFFSET %d", + intval($a->data['channel']['channel_id']), + dbesc('Contact Photos'), + dbesc( t('Contact Photos')), + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval($unsafe), + intval($a->pager['itemspage']), + intval($a->pager['start']) + ); + + + + $photos = array(); + if(count($r)) { + $twist = 'rotright'; + foreach($r as $rr) { + if($twist == 'rotright') + $twist = 'rotleft'; + else + $twist = 'rotright'; + $ext = $phototypes[$rr['type']]; + + if($a->get_template_engine() === 'internal') { + $alt_e = template_escape($rr['filename']); + $name_e = template_escape($rr['album']); + } + else { + $alt_e = $rr['filename']; + $name_e = $rr['album']; + } + + $photos[] = array( + 'id' => $rr['id'], + 'twist' => ' ' . $twist . rand(2,4), + 'link' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/image/' . $rr['resource_id'], + 'title' => t('View Photo'), + 'src' => $a->get_baseurl() . '/photo/' . $rr['resource_id'] . '-' . ((($rr['scale']) == 6) ? 4 : $rr['scale']) . '.' . $ext, + 'alt' => $alt_e, + 'album' => array( + 'link' => $a->get_baseurl() . '/photos/' . $a->data['channel']['channel_address'] . '/album/' . bin2hex($rr['album']), + 'name' => $name_e, + 'alt' => t('View Album'), + ), + + ); + } + } + + if($_REQUEST['aj']) { + if($photos) { + $o = replace_macros(get_markup_template('photosajax.tpl'),array( + '$photos' => $photos, + )); + } + else { + $o = '
    '; + } + echo $o; + killme(); + } + else { + $o .= ""; + $tpl = get_markup_template('photos_recent.tpl'); + $o .= replace_macros($tpl, array( + '$title' => t('Recent Photos'), + '$can_post' => $can_post, + '$upload' => array(t('Upload'), $a->get_baseurl().'/photos/'.$a->data['channel']['channel_address'].'/upload'), + '$photos' => $photos, + '$upload_form' => $upload_form, + '$usage' => $usage_message + )); + + } + + if((! $photos) && ($_REQUEST['aj'])) { + $o .= '
    '; + echo $o; + killme(); + } + +// paginate($a); + return $o; +} + diff --git a/sources/mod/ping.php b/sources/mod/ping.php new file mode 100644 index 00000000..394dbf08 --- /dev/null +++ b/sources/mod/ping.php @@ -0,0 +1,491 @@ + $m); + } + unset($_SESSION['sysmsg']); + } + if(x($_SESSION, 'sysmsg_info')){ + foreach ($_SESSION['sysmsg_info'] as $m){ + $result['info'][] = array('message' => $m); + } + unset($_SESSION['sysmsg_info']); + } + if(! ($vnotify & VNOTIFY_INFO)) + $result['info'] = array(); + if(! ($vnotify & VNOTIFY_ALERT)) + $result['notice'] = array(); + + + if($a->install) { + echo json_encode($result); + killme(); + } + + /** + * Update chat presence indication (if applicable) + */ + + if(get_observer_hash() && (! $result['invalid'])) { + $r = q("select cp_id, cp_room from chatpresence where cp_xchan = '%s' and cp_client = '%s' and cp_room = 0 limit 1", + dbesc(get_observer_hash()), + dbesc($_SERVER['REMOTE_ADDR']) + ); + $basic_presence = false; + if($r) { + $basic_presence = true; + q("update chatpresence set cp_last = '%s' where cp_id = %d", + dbesc(datetime_convert()), + intval($r[0]['cp_id']) + ); + } + if(! $basic_presence) { + q("insert into chatpresence ( cp_xchan, cp_last, cp_status, cp_client) + values( '%s', '%s', '%s', '%s' ) ", + dbesc(get_observer_hash()), + dbesc(datetime_convert()), + dbesc('online'), + dbesc($_SERVER['REMOTE_ADDR']) + ); + } + } + + /** + * Chatpresence continued... if somebody hasn't pinged recently, they've most likely left the page + * and shouldn't count as online anymore. We allow an expection for bots. + */ + + q("delete from chatpresence where cp_last < %s - INTERVAL %s and cp_client != 'auto' ", + db_utcnow(), db_quoteinterval('3 MINUTE') + ); + + if((! local_channel()) || ($result['invalid'])) { + echo json_encode($result); + killme(); + } + + /** + * Everything following is only permitted under the context of a locally authenticated site member. + */ + + + /** + * Handle "mark all xyz notifications read" requests. + */ + + // mark all items read + if(x($_REQUEST, 'markRead') && local_channel()) { + switch($_REQUEST['markRead']) { + case 'network': + $r = q("update item set item_unseen = 0 where item_unseen = 1 and uid = %d", + intval(local_channel()) + ); + break; + case 'home': + $r = q("update item set item_unseen = 0 where item_unseen = 1 and item_wall = 1 and uid = %d", + intval(local_channel()) + ); + break; + case 'messages': + $r = q("update mail set mail_seen = 1 where mail_seen = 0 and channel_id = %d ", + intval(local_channel()) + ); + break; + case 'all_events': + $r = q("update event set `ignore` = 1 where `ignore` = 0 and uid = %d AND start < '%s' AND start > '%s' ", + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); + break; + case 'notify': + $r = q("update notify set seen = 1 where uid = %d", + intval(local_channel()) + ); + break; + default: + break; + } + } + + if(x($_REQUEST, 'markItemRead') && local_channel()) { + $r = q("update item set item_unseen = 0 where parent = %d and uid = %d", + intval($_REQUEST['markItemRead']), + intval(local_channel()) + ); + } + + + + /** + * URL ping/something will return detail for "something", e.g. a json list with which to populate a notification + * dropdown menu. + */ + + if(argc() > 1 && argv(1) === 'notify') { + $t = q("select count(*) as total from notify where uid = %d and seen = 0", + intval(local_channel()) + ); + if($t && intval($t[0]['total']) > 49) { + $z = q("select * from notify where uid = %d + and seen = 0 order by date desc limit 50", + intval(local_channel()) + ); + } + else { + $z1 = q("select * from notify where uid = %d + and seen = 0 order by date desc limit 50", + intval(local_channel()) + ); + $z2 = q("select * from notify where uid = %d + and seen = 1 order by date desc limit %d", + intval(local_channel()), + intval(50 - intval($t[0]['total'])) + ); + $z = array_merge($z1,$z2); + } + + if(count($z)) { + foreach($z as $zz) { + $notifs[] = array( + 'notify_link' => $a->get_baseurl() . '/notify/view/' . $zz['id'], + 'name' => $zz['name'], + 'url' => $zz['url'], + 'photo' => $zz['photo'], + 'when' => relative_date($zz['date']), + 'hclass' => (($zz['seen']) ? 'notify-seen' : 'notify-unseen'), + 'message' => strip_tags(bbcode($zz['msg'])) + ); + } + } + + echo json_encode(array('notify' => $notifs)); + killme(); + } + + if(argc() > 1 && argv(1) === 'messages') { + $channel = $a->get_channel(); + $t = q("select mail.*, xchan.* from mail left join xchan on xchan_hash = from_xchan + where channel_id = %d and mail_seen = 0 and mail_deleted = 0 + and from_xchan != '%s' order by created desc limit 50", + intval(local_channel()), + dbesc($channel['channel_hash']) + ); + + if($t) { + foreach($t as $zz) { + $notifs[] = array( + 'notify_link' => $a->get_baseurl() . '/mail/' . $zz['id'], + 'name' => $zz['xchan_name'], + 'url' => $zz['xchan_url'], + 'photo' => $zz['xchan_photo_s'], + 'when' => relative_date($zz['created']), + 'hclass' => (intval($zz['mail_seen']) ? 'notify-seen' : 'notify-unseen'), + 'message' => t('sent you a private message'), + ); + } + } + + echo json_encode(array('notify' => $notifs)); + killme(); + } + + if(argc() > 1 && (argv(1) === 'network' || argv(1) === 'home')) { + $result = array(); + + $r = q("SELECT * FROM item + WHERE item_unseen = 1 and uid = %d $item_normal + and author_xchan != '%s' ORDER BY created DESC limit 300", + intval(local_channel()), + dbesc($ob_hash) + ); + + if($r) { + xchan_query($r); + foreach($r as $item) { + if((argv(1) === 'home') && (! intval($item['item_wall']))) + continue; + $result[] = format_notification($item); + } + } +// logger('ping (network||home): ' . print_r($result, true), LOGGER_DATA); + echo json_encode(array('notify' => $result)); + killme(); + } + + if(argc() > 1 && (argv(1) === 'intros')) { + $result = array(); + + $r = q("SELECT * FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ORDER BY abook_created DESC LIMIT 50", + intval(local_channel()) + ); + + if($r) { + foreach($r as $rr) { + $result[] = array( + 'notify_link' => $a->get_baseurl() . '/connedit/' . $rr['abook_id'], + 'name' => $rr['xchan_name'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => relative_date($rr['abook_created']), + 'hclass' => ('notify-unseen'), + 'message' => t('added your channel') + ); + } + } + logger('ping (intros): ' . print_r($result, true), LOGGER_DATA); + echo json_encode(array('notify' => $result)); + killme(); + } + + if(argc() > 1 && (argv(1) === 'all_events')) { + $bd_format = t('g A l F d') ; // 8 AM Friday January 18 + + $result = array(); + + $r = q("SELECT * FROM event left join xchan on event_xchan = xchan_hash + WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0 + and type in ( 'event', 'birthday' ) + ORDER BY `start` DESC LIMIT 1000", + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); + + if($r) { + foreach($r as $rr) { + if($rr['adjust']) + $md = datetime_convert('UTC', date_default_timezone_get(), $rr['start'], 'Y/m'); + else + $md = datetime_convert('UTC', 'UTC', $rr['start'], 'Y/m'); + + $strt = datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['start']); + $today = ((substr($strt, 0, 10) === datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d')) ? true : false); + + $when = day_translate(datetime_convert('UTC', (($rr['adjust']) ? date_default_timezone_get() : 'UTC'), $rr['start'], $bd_format)) . (($today) ? ' ' . t('[today]') : ''); + + $result[] = array( + 'notify_link' => $a->get_baseurl() . '/events', // FIXME this takes you to an edit page and it may not be yours, we really want to just view the single event --> '/events/event/' . $rr['event_hash'], + 'name' => $rr['xchan_name'], + 'url' => $rr['xchan_url'], + 'photo' => $rr['xchan_photo_s'], + 'when' => $when, + 'hclass' => ('notify-unseen'), + 'message' => t('posted an event') + ); + } + } + logger('ping (all_events): ' . print_r($result, true), LOGGER_DATA); + echo json_encode(array('notify' => $result)); + killme(); + } + + + + /** + * Normal ping - just the counts, no detail + */ + + if($vnotify & VNOTIFY_SYSTEM) { + $t = q("select count(*) as total from notify where uid = %d and seen = 0", + intval(local_channel()) + ); + if($t) + $result['notify'] = intval($t[0]['total']); + } + + $t1 = dba_timer(); + + if($vnotify & (VNOTIFY_NETWORK|VNOTIFY_CHANNEL)) { + $r = q("SELECT id, item_wall FROM item + WHERE item_unseen = 1 and uid = %d + $item_normal + and author_xchan != '%s'", + intval(local_channel()), + dbesc($ob_hash) + ); + + if($r) { + $arr = array('items' => $r); + call_hooks('network_ping', $arr); + + foreach ($r as $it) { + if(intval($it['item_wall'])) + $result['home'] ++; + else + $result['network'] ++; + } + } + } + if(! ($vnotify & VNOTIFY_NETWORK)) + $result['network'] = 0; + if(! ($vnotify & VNOTIFY_CHANNEL)) + $result['home'] = 0; + + + $t2 = dba_timer(); + + if($vnotify & VNOTIFY_INTRO) { + $intr = q("SELECT COUNT(abook.abook_id) AS total FROM abook left join xchan on abook.abook_xchan = xchan.xchan_hash where abook_channel = %d and abook_pending = 1 and abook_self = 0 and abook_ignored = 0 and xchan_deleted = 0 and xchan_orphan = 0 ", + intval(local_channel()) + ); + + $t3 = dba_timer(); + + if($intr) + $result['intros'] = intval($intr[0]['total']); + } + + $t4 = dba_timer(); + $channel = get_app()->get_channel(); + + if($vnotify & VNOTIFY_MAIL) { + $mails = q("SELECT count(id) as total from mail + WHERE channel_id = %d AND mail_seen = 0 and from_xchan != '%s' ", + intval(local_channel()), + dbesc($channel['channel_hash']) + ); + if($mails) + $result['mail'] = intval($mails[0]['total']); + } + + if($vnotify & VNOTIFY_REGISTER) { + if ($a->config['system']['register_policy'] == REGISTER_APPROVE && is_site_admin()) { + $regs = q("SELECT count(account_id) as total from account where (account_flags & %d) > 0", + intval(ACCOUNT_PENDING) + ); + if($regs) + $result['register'] = intval($regs[0]['total']); + } + } + + $t5 = dba_timer(); + + if($vnotify & (VNOTIFY_EVENT|VNOTIFY_EVENTTODAY|VNOTIFY_BIRTHDAY)) { + $events = q("SELECT type, start, adjust FROM `event` + WHERE `event`.`uid` = %d AND start < '%s' AND start > '%s' and `ignore` = 0 + and type in ( 'event', 'birthday' ) + ORDER BY `start` ASC ", + intval(local_channel()), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now + ' . intval($evdays) . ' days')), + dbesc(datetime_convert('UTC', date_default_timezone_get(), 'now - 1 days')) + ); + + if($events) { + $result['all_events'] = count($events); + + if($result['all_events']) { + $str_now = datetime_convert('UTC', date_default_timezone_get(), 'now', 'Y-m-d'); + foreach($events as $x) { + $bd = false; + if($x['type'] === 'birthday') { + $result['birthdays'] ++; + $bd = true; + } + else { + $result['events'] ++; + } + if(datetime_convert('UTC', ((intval($x['adjust'])) ? date_default_timezone_get() : 'UTC'), $x['start'], 'Y-m-d') === $str_now) { + $result['all_events_today'] ++; + if($bd) + $result['birthdays_today'] ++; + else + $result['events_today'] ++; + } + } + } + } + } + if(! ($vnotify & VNOTIFY_EVENT)) + $result['all_events'] = $result['events'] = 0; + if(! ($vnotify & VNOTIFY_EVENTTODAY)) + $result['all_events_today'] = $result['events_today'] = 0; + if(! ($vnotify & VNOTIFY_BIRTHDAY)) + $result['birthdays'] = 0; + + + $x = json_encode($result); + + $t6 = dba_timer(); + +// logger('ping timer: ' . sprintf('%01.4f %01.4f %01.4f %01.4f %01.4f %01.4f',$t6 - $t5, $t5 - $t4, $t4 - $t3, $t3 - $t2, $t2 - $t1, $t1 - $t0)); + + echo $x; + killme(); +} diff --git a/sources/mod/poco.php b/sources/mod/poco.php new file mode 100644 index 00000000..098c9a24 --- /dev/null +++ b/sources/mod/poco.php @@ -0,0 +1,7 @@ +get_channel(); + + $verb = notags(trim($_REQUEST['verb'])); + + if(! $verb) + return; + + $verbs = get_poke_verbs(); + + if(! array_key_exists($verb,$verbs)) + return; + + $activity = ACTIVITY_POKE . '#' . urlencode($verbs[$verb][0]); + + $contact_id = intval($_REQUEST['cid']); + if(! $contact_id) + return; + + $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : 0); + + logger('poke: verb ' . $verb . ' contact ' . $contact_id, LOGGER_DEBUG); + + + $r = q("SELECT * FROM abook left join xchan on xchan_hash = abook_xchan where abook_id = %d and abook_channel = %d LIMIT 1", + intval($contact_id), + intval($uid) + ); + + if(! $r) { + logger('poke: no target ' . $contact_id); + return; + } + + $target = $r[0]; + $parent_item = null; + + if($parent) { + $r = q("select mid, item_private, owner_xchan, allow_cid, allow_gid, deny_cid, deny_gid + from item where id = %d and parent = %d and uid = %d limit 1", + intval($parent), + intval($parent), + intval($uid) + ); + if($r) { + $parent_item = $r[0]; + $parent_mid = $r[0]['mid']; + $item_private = $r[0]['item_private']; + $allow_cid = $r[0]['allow_cid']; + $allow_gid = $r[0]['allow_gid']; + $deny_cid = $r[0]['deny_cid']; + $deny_gid = $r[0]['deny_gid']; + } + } + else { + + $item_private = ((x($_GET,'private')) ? intval($_GET['private']) : 0); + + $allow_cid = (($item_private) ? '<' . $target['abook_xchan']. '>' : $channel['channel_allow_cid']); + $allow_gid = (($item_private) ? '' : $channel['channel_allow_gid']); + $deny_cid = (($item_private) ? '' : $channel['channel_deny_cid']); + $deny_gid = (($item_private) ? '' : $channel['channel_deny_gid']); + } + + + $arr = array(); + + $arr['item_wall'] = 1; + $arr['owner_xchan'] = (($parent_item) ? $parent_item['owner_xchan'] : $channel['channel_hash']); + $arr['parent_mid'] = (($parent_mid) ? $parent_mid : $mid); + $arr['title'] = ''; + $arr['allow_cid'] = $allow_cid; + $arr['allow_gid'] = $allow_gid; + $arr['deny_cid'] = $deny_cid; + $arr['deny_gid'] = $deny_gid; + $arr['verb'] = $activity; + $arr['item_private'] = $item_private; + $arr['obj_type'] = ACTIVITY_OBJ_PERSON; + $arr['body'] = '[zrl=' . $channel['xchan_url'] . ']' . $channel['xchan_name'] . '[/zrl]' . ' ' . t($verbs[$verb][0]) . ' ' . '[zrl=' . $target['xchan_url'] . ']' . $target['xchan_name'] . '[/zrl]'; + + $obj = array( + 'type' => ACTIVITY_OBJ_PERSON, + 'title' => $target['xchan_name'], + 'id' => $target['xchan_hash'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $target['xchan_url']), + array('rel' => 'photo', 'type' => $target['xchan_photo_mimetype'], 'href' => $target['xchan_photo_l']) + ), + ); + + $arr['object'] = json_encode($obj); + + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_unseen'] = 1; + if(! $parent_item) + $item['item_thread_top'] = 1; + + + post_activity_item($arr); + + return; +} + + + +function poke_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + $name = ''; + $id = ''; + + if(intval($_REQUEST['c'])) { + $r = q("select abook_id, xchan_name from abook left join xchan on abook_xchan = xchan_hash + where abook_id = %d and abook_channel = %d limit 1", + intval($_REQUEST['c']), + intval(local_channel()) + ); + if($r) { + $name = $r[0]['xchan_name']; + $id = $r[0]['abook_id']; + } + } + + $parent = ((x($_REQUEST,'parent')) ? intval($_REQUEST['parent']) : '0'); + + $verbs = get_poke_verbs(); + + $shortlist = array(); + foreach($verbs as $k => $v) + if($v[1] !== 'NOTRANSLATION') + $shortlist[] = array($k,$v[1]); + + $tpl = get_markup_template('poke_content.tpl'); + + $o = replace_macros($tpl,array( + '$title' => t('Poke/Prod'), + '$desc' => t('poke, prod or do other things to somebody'), + '$clabel' => t('Recipient'), + '$choice' => t('Choose what you wish to do to recipient'), + '$verbs' => $shortlist, + '$parent' => $parent, + '$prv_desc' => t('Make this post private'), + '$submit' => t('Submit'), + '$name' => $name, + '$id' => $id + )); + + return $o; + +} \ No newline at end of file diff --git a/sources/mod/post.php b/sources/mod/post.php new file mode 100644 index 00000000..dfda7db9 --- /dev/null +++ b/sources/mod/post.php @@ -0,0 +1,933 @@ + the urlencoded webbie (channel@host.domain) of the channel requesting access + * * dest => the desired destination URL (urlencoded) + * * sec => a random string which is also stored on $mysite for use during the verification phase. + * * version => the zot revision + * * delegate => optional urlencoded webbie of a local channel to invoke delegation rights for + * + * When this packet is received, an "auth-check" zot message is sent to $mysite. + * (e.g. if $_GET['auth'] is foobar@podunk.edu, a zot packet is sent to the podunk.edu zot endpoint, which is typically /post) + * If no information has been recorded about the requesting identity a zot information packet will be retrieved before + * continuing. + * + * The sender of this packet is an arbitrary/random site channel. The recipients will be a single recipient corresponding + * to the guid and guid_sig we have associated with the requesting auth identity + * + * \code{.json} + * { + * "type":"auth_check", + * "sender":{ + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TApz...", + * "url":"http:\/\/podunk.edu", + * "url_sig":"T8Bp7j..." + * }, + * "recipients":{ + * { + * "guid":"ZHSqb...", + * "guid_sig":"JsAAXi..." + * } + * } + * "callback":"\/post", + * "version":1, + * "secret":"1eaa661", + * "secret_sig":"eKV968b1..." + * } + * \endcode + * + * auth_check messages MUST use encapsulated encryption. This message is sent to the origination site, which checks the 'secret' to see + * if it is the same as the 'sec' which it passed originally. It also checks the secret_sig which is the secret signed by the + * destination channel's private key and base64url encoded. If everything checks out, a json packet is returned: + * + * \code{.json} + * { + * "success":1, + * "confirm":"q0Ysovd1u...", + * "service_class":(optional) + * "level":(optional) + * } + * \endcode + * + * 'confirm' in this case is the base64url encoded RSA signature of the concatenation of 'secret' with the + * base64url encoded whirlpool hash of the requestor's guid and guid_sig; signed with the source channel private key. + * This prevents a man-in-the-middle from inserting a rogue success packet. Upon receipt and successful + * verification of this packet, the destination site will redirect to the original destination URL and indicate a successful remote login. + * Service_class can be used by cooperating sites to provide different access rights based on account rights and subscription plans. It is + * a string whose contents are not defined by protocol. Example: "basic" or "gold". + * + * @param[in,out] App &$a + */ +function post_init(&$a) { + + if (array_key_exists('auth', $_REQUEST)) { + + $ret = array('success' => false, 'message' => ''); + + logger('mod_zot: auth request received.'); + $address = $_REQUEST['auth']; + $desturl = $_REQUEST['dest']; + $sec = $_REQUEST['sec']; + $version = $_REQUEST['version']; + $delegate = $_REQUEST['delegate']; + + $test = ((x($_REQUEST, 'test')) ? intval($_REQUEST['test']) : 0); + + // They are authenticating ultimately to the site and not to a particular channel. + // Any channel will do, providing it's currently active. We just need to have an + // identity to attach to the packet we send back. So find one. + + $c = q("select * from channel where channel_removed = 0 limit 1"); + + if (! $c) { + // nobody here + logger('mod_zot: auth: unable to find a response channel'); + if ($test) { + $ret['message'] .= 'no local channels found.' . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + + // Try and find a hubloc for the person attempting to auth + $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", + dbesc($address) + ); + + if (! $x) { + // finger them if they can't be found. + $ret = zot_finger($address, null); + if ($ret['success']) { + $j = json_decode($ret['body'], true); + if ($j) + import_xchan($j); + $x = q("select * from hubloc left join xchan on xchan_hash = hubloc_hash where hubloc_addr = '%s' order by hubloc_id desc limit 1", + dbesc($address) + ); + } + } + if(! $x) { + logger('mod_zot: auth: unable to finger ' . $address); + + if($test) { + $ret['message'] .= 'no hubloc found for ' . $address . ' and probing failed.' . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + + logger('mod_zot: auth request received from ' . $x[0]['hubloc_addr'] ); + + // check credentials and access + + // If they are already authenticated and haven't changed credentials, + // we can save an expensive network round trip and improve performance. + + $remote = remote_channel(); + $result = null; + $remote_service_class = ''; + $remote_level = 0; + $remote_hub = $x[0]['hubloc_url']; + $DNT = 0; + + // Also check that they are coming from the same site as they authenticated with originally. + + $already_authed = ((($remote) && ($x[0]['hubloc_hash'] == $remote) && ($x[0]['hubloc_url'] === $_SESSION['remote_hub'])) ? true : false); + if($delegate && $delegate !== $_SESSION['delegate_channel']) + $already_authed = false; + + $j = array(); + + if (! $already_authed) { + + // Auth packets MUST use ultra top-secret hush-hush mode - e.g. the entire packet is encrypted using the site private key + // The actual channel sending the packet ($c[0]) is not important, but this provides a generic zot packet with a sender + // which can be verified + + $p = zot_build_packet($c[0],$type = 'auth_check', array(array('guid' => $x[0]['hubloc_guid'],'guid_sig' => $x[0]['hubloc_guid_sig'])), $x[0]['hubloc_sitekey'], $sec); + if ($test) { + $ret['message'] .= 'auth check packet created using sitekey ' . $x[0]['hubloc_sitekey'] . EOL; + $ret['message'] .= 'packet contents: ' . $p . EOL; + } + + $result = zot_zot($x[0]['hubloc_callback'],$p); + + if (! $result['success']) { + logger('mod_zot: auth_check callback failed.'); + if ($test) { + $ret['message'] .= 'auth check request to your site returned .' . print_r($result, true) . EOL; + json_return_and_die($ret); + } + + goaway($desturl); + } + $j = json_decode($result['body'], true); + if (! $j) { + logger('mod_zot: auth_check json data malformed.'); + if($test) { + $ret['message'] .= 'json malformed: ' . $result['body'] . EOL; + json_return_and_die($ret); + } + } + } + + if ($test) { + $ret['message'] .= 'auth check request returned .' . print_r($j, true) . EOL; + } + + if ($already_authed || $j['success']) { + if ($j['success']) { + // legit response, but we do need to check that this wasn't answered by a man-in-middle + if (! rsa_verify($sec . $x[0]['xchan_hash'],base64url_decode($j['confirm']),$x[0]['xchan_pubkey'])) { + logger('mod_zot: auth: final confirmation failed.'); + if ($test) { + $ret['message'] .= 'final confirmation failed. ' . $sec . print_r($j,true) . print_r($x[0],true); + json_return_and_die($ret); + } + + goaway($desturl); + } + if (array_key_exists('service_class',$j)) + $remote_service_class = $j['service_class']; + if (array_key_exists('level',$j)) + $remote_level = $j['level']; + if (array_key_exists('DNT',$j)) + $DNT = $j['DNT']; + } + // everything is good... maybe + if(local_channel()) { + + // tell them to logout if they're logged in locally as anything but the target remote account + // in which case just shut up because they don't need to be doing this at all. + + if ($a->channel['channel_hash'] != $x[0]['xchan_hash']) { + logger('mod_zot: auth: already authenticated locally as somebody else.'); + notice( t('Remote authentication blocked. You are logged into this site locally. Please logout and retry.') . EOL); + if ($test) { + $ret['message'] .= 'already logged in locally with a conflicting identity.' . EOL; + json_return_and_die($ret); + } + } + goaway($desturl); + } + + // log them in + + if ($test) { + $ret['success'] = true; + $ret['message'] .= 'Authentication Success!' . EOL; + json_return_and_die($ret); + } + + $delegation_success = false; + if ($delegate) { + $r = q("select * from channel left join xchan on channel_hash = xchan_hash where xchan_addr = '%s' limit 1", + dbesc($delegate) + ); + if ($r && intval($r[0]['channel_id'])) { + $allowed = perm_is_allowed($r[0]['channel_id'],$x[0]['xchan_hash'],'delegate'); + if ($allowed) { + $_SESSION['delegate_channel'] = $r[0]['channel_id']; + $_SESSION['delegate'] = $x[0]['xchan_hash']; + $_SESSION['account_id'] = intval($r[0]['channel_account_id']); + require_once('include/security.php'); + change_channel($r[0]['channel_id']); + $delegation_success = true; + } + } + } + + $_SESSION['authenticated'] = 1; + if (! $delegation_success) { + $_SESSION['visitor_id'] = $x[0]['xchan_hash']; + $_SESSION['my_url'] = $x[0]['xchan_url']; + $_SESSION['my_address'] = $address; + $_SESSION['remote_service_class'] = $remote_service_class; + $_SESSION['remote_level'] = $remote_level; + $_SESSION['remote_hub'] = $remote_hub; + $_SESSION['DNT'] = $DNT; + } + + $arr = array('xchan' => $x[0], 'url' => $desturl, 'session' => $_SESSION); + call_hooks('magic_auth_success',$arr); + $a->set_observer($x[0]); + require_once('include/security.php'); + $a->set_groups(init_groups_visitor($_SESSION['visitor_id'])); + info(sprintf( t('Welcome %s. Remote authentication successful.'),$x[0]['xchan_name'])); + logger('mod_zot: auth success from ' . $x[0]['xchan_addr']); + } + else { + if($test) { + $ret['message'] .= 'auth failure. ' . print_r($_REQUEST,true) . print_r($j,true) . EOL; + json_return_and_die($ret); + } + logger('mod_zot: magic-auth failure - not authenticated: ' . $x[0]['xchan_addr']); + } + + /** + * @FIXME we really want to save the return_url in the session before we + * visit rmagic. This does however prevent a recursion if you visit + * rmagic directly, as it would otherwise send you back here again. + * But z_root() probably isn't where you really want to go. + */ + + if ($test) { + $ret['message'] .= 'auth failure fallthrough ' . print_r($_REQUEST,true) . print_r($j,true) . EOL; + json_return_and_die($ret); + } + + if(strstr($desturl,z_root() . '/rmagic')) + goaway(z_root()); + + goaway($desturl); + } +} + + +/** + * @brief zot communications and messaging. + * + * Sender HTTP posts to this endpoint ($site/post typically) with 'data' parameter set to json zot message packet. + * This packet is optionally encrypted, which we will discover if the json has an 'iv' element. + * $contents => array( 'alg' => 'aes256cbc', 'iv' => initialisation vector, 'key' => decryption key, 'data' => encrypted data); + * $contents->iv and $contents->key are random strings encrypted with this site's RSA public key and then base64url encoded. + * Currently only 'aes256cbc' is used, but this is extensible should that algorithm prove inadequate. + * + * Once decrypted, one will find the normal json_encoded zot message packet. + * + * Defined packet types are: notify, purge, refresh, force_refresh, auth_check, ping, and pickup + * + * Standard packet: (used by notify, purge, refresh, force_refresh, and auth_check) + * \code{.json} + * { + * "type": "notify", + * "sender":{ + * "guid":"kgVFf_1...", + * "guid_sig":"PT9-TApzp...", + * "url":"http:\/\/podunk.edu", + * "url_sig":"T8Bp7j5...", + * }, + * "recipients": { optional recipient array }, + * "callback":"\/post", + * "version":1, + * "secret":"1eaa...", + * "secret_sig": "df89025470fac8..." + * } + * \endcode + * + * Signature fields are all signed with the sender channel private key and base64url encoded. + * Recipients are arrays of guid and guid_sig, which were previously signed with the recipients private + * key and base64url encoded and later obtained via channel discovery. Absence of recipients indicates + * a public message or visible to all potential listeners on this site. + * + * "pickup" packet: + * The pickup packet is sent in response to a notify packet from another site + * \code{.json} + * { + * "type":"pickup", + * "url":"http:\/\/example.com", + * "callback":"http:\/\/example.com\/post", + * "callback_sig":"teE1_fLI...", + * "secret":"1eaa...", + * "secret_sig":"O7nB4_..." + * } + * \endcode + * + * In the pickup packet, the sig fields correspond to the respective data + * element signed with this site's system private key and then base64url encoded. + * The "secret" is the same as the original secret from the notify packet. + * + * If verification is successful, a json structure is returned containing a + * success indicator and an array of type 'pickup'. + * Each pickup element contains the original notify request and a message field + * whose contents are dependent on the message type. + * + * This JSON array is AES encapsulated using the site public key of the site + * that sent the initial zot pickup packet. + * Using the above example, this would be example.com. + * + * \code{.json} + * { + * "success":1, + * "pickup":{ + * "notify":{ + * "type":"notify", + * "sender":{ + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TApz...", + * "url":"http:\/\/z.podunk.edu", + * "url_sig":"T8Bp7j5D..." + * }, + * "callback":"\/post", + * "version":1, + * "secret":"1eaa661..." + * }, + * "message":{ + * "type":"activity", + * "message_id":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "message_top":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "message_parent":"10b049ce384cbb2da9467319bc98169ab36290b8bbb403aa0c0accd9cb072e76@podunk.edu", + * "created":"2012-11-20 04:04:16", + * "edited":"2012-11-20 04:04:16", + * "title":"", + * "body":"Hi Nickordo", + * "app":"", + * "verb":"post", + * "object_type":"", + * "target_type":"", + * "permalink":"", + * "location":"", + * "longlat":"", + * "owner":{ + * "name":"Indigo", + * "address":"indigo@podunk.edu", + * "url":"http:\/\/podunk.edu", + * "photo":{ + * "mimetype":"image\/jpeg", + * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" + * }, + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TAp...", + * }, + * "author":{ + * "name":"Indigo", + * "address":"indigo@podunk.edu", + * "url":"http:\/\/podunk.edu", + * "photo":{ + * "mimetype":"image\/jpeg", + * "src":"http:\/\/podunk.edu\/photo\/profile\/m\/5" + * }, + * "guid":"kgVFf_...", + * "guid_sig":"PT9-TAp..." + * } + * } + * } + * } + * \endcode + * + * Currently defined message types are 'activity', 'mail', 'profile', 'location' + * and 'channel_sync', which each have different content schemas. + * + * Ping packet: + * A ping packet does not require any parameters except the type. It may or may + * not be encrypted. + * + * \code{.json} + * { + * "type": "ping" + * } + * \endcode + * + * On receipt of a ping packet a ping response will be returned: + * + * \code{.json} + * { + * "success" : 1, + * "site" { + * "url": "http:\/\/podunk.edu", + * "url_sig": "T8Bp7j5...", + * "sitekey": "-----BEGIN PUBLIC KEY----- + * MIICIjANBgkqhkiG9w0BAQE..." + * } + * } + * \endcode + * + * The ping packet can be used to verify that a site has not been re-installed, and to + * initiate corrective action if it has. The url_sig is signed with the site private key + * and base64url encoded - and this should verify with the enclosed sitekey. Failure to + * verify indicates the site is corrupt or otherwise unable to communicate using zot. + * This return packet is not otherwise verified, so should be compared with other + * results obtained from this site which were verified prior to taking action. For instance + * if you have one verified result with this signature and key, and other records for this + * url which have different signatures and keys, it indicates that the site was re-installed + * and corrective action may commence (remove or mark invalid any entries with different + * signatures). + * If you have no records which match this url_sig and key - no corrective action should + * be taken as this packet may have been returned by an imposter. + * + * @param[in,out] App &$a + */ +function post_post(&$a) { + + $encrypted_packet = false; + $ret = array('success' => false); + + $data = json_decode($_REQUEST['data'],true); + + /* + * Many message packets will arrive encrypted. The existence of an 'iv' + * element tells us we need to unencapsulate the AES-256-CBC content using + * the site private key. + */ + + if($data && array_key_exists('iv',$data)) { + $encrypted_packet = true; + $data = crypto_unencapsulate($data,get_config('system','prvkey')); + logger('mod_zot: decrypt1: ' . $data, LOGGER_DATA); + $data = json_decode($data,true); + } + + if(! $data) { + + // possible Bleichenbacher's attack, just treat it as a + // message we have no handler for. It should fail a bit + // further along with "no hub". Our public key is public + // knowledge. There's no reason why anybody should get the + // encryption wrong unless they're fishing or hacking. If + // they're developing and made a goof, this can be discovered + // in the logs of the destination site. If they're fishing or + // hacking, the bottom line is we can't verify their hub. + // That's all we're going to tell them. + + $data = array('type' => 'bogus'); + } + + + $msgtype = ((array_key_exists('type',$data)) ? $data['type'] : ''); + + if($msgtype === 'ping') { + + // Useful to get a health check on a remote site. + // This will let us know if any important communication details + // that we may have stored are no longer valid, regardless of xchan details. + logger('POST: got ping send pong now back: ' . z_root() , LOGGER_DEBUG ); + + $ret['success'] = true; + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),get_config('system','prvkey'))); + $ret['site']['sitekey'] = get_config('system','pubkey'); + json_return_and_die($ret); + } + + + if($msgtype === 'pickup') { + + /* + * The 'pickup' message arrives with a tracking ID which is associated with a particular outq_hash + * First verify that that the returned signatures verify, then check that we have an outbound queue item + * with the correct hash. + * If everything verifies, find any/all outbound messages in the queue for this hubloc and send them back + */ + + if((! $data['secret']) || (! $data['secret_sig'])) { + $ret['message'] = 'no verification signature'; + logger('mod_zot: pickup: ' . $ret['message'], LOGGER_DEBUG); + json_return_and_die($ret); + } + $r = q("select distinct hubloc_sitekey from hubloc where hubloc_url = '%s' and hubloc_callback = '%s' and hubloc_sitekey != '' group by hubloc_sitekey ", + dbesc($data['url']), + dbesc($data['callback']) + ); + if(! $r) { + $ret['message'] = 'site not found'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + foreach ($r as $hubsite) { + + // verify the url_sig + // If the server was re-installed at some point, there could be multiple hubs with the same url and callback. + // Only one will have a valid key. + + $forgery = true; + $secret_fail = true; + + $sitekey = $hubsite['hubloc_sitekey']; + + logger('mod_zot: Checking sitekey: ' . $sitekey, LOGGER_DATA); + + if(rsa_verify($data['callback'],base64url_decode($data['callback_sig']),$sitekey)) { + $forgery = false; + } + if(rsa_verify($data['secret'],base64url_decode($data['secret_sig']),$sitekey)) { + $secret_fail = false; + } + if((! $forgery) && (! $secret_fail)) + break; + } + + if($forgery) { + $ret['message'] = 'possible site forgery'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + if($secret_fail) { + $ret['message'] = 'secret validation failed'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + /* + * If we made it to here, the signatures verify, but we still don't know if the tracking ID is valid. + * It wouldn't be an error if the tracking ID isn't found, because we may have sent this particular + * queue item with another pickup (after the tracking ID for the other pickup was verified). + */ + + $r = q("select outq_posturl from outq where outq_hash = '%s' and outq_posturl = '%s' limit 1", + dbesc($data['secret']), + dbesc($data['callback']) + ); + if(! $r) { + $ret['message'] = 'nothing to pick up'; + logger('mod_zot: pickup: ' . $ret['message']); + json_return_and_die($ret); + } + + /* + * Everything is good if we made it here, so find all messages that are going to this location + * and send them all. + */ + + $r = q("select * from outq where outq_posturl = '%s'", + dbesc($data['callback']) + ); + if($r) { + logger('mod_zot: successful pickup message received from ' . $data['callback'] . ' ' . count($r) . ' message(s) picked up', LOGGER_DEBUG); + + $ret['success'] = true; + $ret['pickup'] = array(); + foreach($r as $rr) { + if($rr['outq_msg']) { + $x = json_decode($rr['outq_msg'],true); + + if(! $x) + continue; + + if(array_key_exists('message_list',$x)) { + foreach($x['message_list'] as $xx) { + $ret['pickup'][] = array('notify' => json_decode($rr['outq_notify'],true),'message' => $xx); + } + } + else + $ret['pickup'][] = array('notify' => json_decode($rr['outq_notify'],true),'message' => $x); + + $x = q("delete from outq where outq_hash = '%s'", + dbesc($rr['outq_hash']) + ); + } + } + } + + $encrypted = crypto_encapsulate(json_encode($ret),$sitekey); + json_return_and_die($encrypted); + + /* pickup: end */ + } + + + /* + * All other message types require us to verify the sender. This is a generic check, so we + * will do it once here and bail if anything goes wrong. + */ + + if (array_key_exists('sender',$data)) { + $sender = $data['sender']; + } + + /* Check if the sender is already verified here */ + + $hub = zot_gethub($sender); + + if (! $hub) { + + /* Have never seen this guid or this guid coming from this location. Check it and register it. */ + + // (!!) this will validate the sender + $result = zot_register_hub($sender); + + if ((! $result['success']) || (! ($hub = zot_gethub($sender)))) { + $ret['message'] = 'Hub not available.'; + logger('mod_zot: no hub'); + json_return_and_die($ret); + } + } + + + // Update our DB to show when we last communicated successfully with this hub + // This will allow us to prune dead hubs from using up resources + + $r = q("update hubloc set hubloc_connected = '%s' where hubloc_id = %d", + dbesc(datetime_convert()), + intval($hub['hubloc_id']) + ); + + // a dead hub came back to life - reset any tombstones we might have + + if(intval($hub['hubloc_error'])) { + q("update hubloc set hubloc_error = 0 where hubloc_id = %d", + intval($hub['hubloc_id']) + ); + if(intval($r[0]['hubloc_orphancheck'])) { + q("update hubloc set hubloc_orhpancheck = 0 where hubloc_id = %d", + intval($hub['hubloc_id']) + ); + } + q("update xchan set xchan_orphan = 0 where xchan_orphan = 1 and xchan_hash = '%s'", + dbesc($hub['hubloc_hash']) + ); + } + + + /* + * This hub has now been proven to be valid. + * Any hub with the same URL and a different sitekey cannot be valid. + * Get rid of them (mark them deleted). There's a good chance they were re-installs. + */ + + q("update hubloc set hubloc_deleted = 1 where hubloc_url = '%s' and hubloc_sitekey != '%s' ", + dbesc($hub['hubloc_url']), + dbesc($hub['hubloc_sitekey']) + ); + + /** @TODO check which hub is primary and take action if mismatched */ + + if (array_key_exists('recipients', $data)) + $recipients = $data['recipients']; + + + if ($msgtype === 'auth_check') { + + /* + * Requestor visits /magic/?dest=somewhere on their own site with a browser + * magic redirects them to $destsite/post [with auth args....] + * $destsite sends an auth_check packet to originator site + * The auth_check packet is handled here by the originator's site + * - the browser session is still waiting + * inside $destsite/post for everything to verify + * If everything checks out we'll return a token to $destsite + * and then $destsite will verify the token, authenticate the browser + * session and then redirect to the original destination. + * If authentication fails, the redirection to the original destination + * will still take place but without authentication. + */ + logger('mod_zot: auth_check', LOGGER_DEBUG); + + if (! $encrypted_packet) { + logger('mod_zot: auth_check packet was not encrypted.'); + $ret['message'] .= 'no packet encryption' . EOL; + json_return_and_die($ret); + } + + $arr = $data['sender']; + $sender_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + + // garbage collect any old unused notifications + + // This was and should be 10 minutes but my hosting provider has time lag between the DB and + // the web server. We should probably convert this to webserver time rather than DB time so + // that the different clocks won't affect it and allow us to keep the time short. + + q("delete from verify where type = 'auth' and created < %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('30 MINUTE') + ); + + $y = q("select xchan_pubkey from xchan where xchan_hash = '%s' limit 1", + dbesc($sender_hash) + ); + + // We created a unique hash in mod/magic.php when we invoked remote auth, and stored it in + // the verify table. It is now coming back to us as 'secret' and is signed by a channel at the other end. + // First verify their signature. We will have obtained a zot-info packet from them as part of the sender + // verification. + + if ((! $y) || (! rsa_verify($data['secret'], base64url_decode($data['secret_sig']),$y[0]['xchan_pubkey']))) { + logger('mod_zot: auth_check: sender not found or secret_sig invalid.'); + $ret['message'] .= 'sender not found or sig invalid ' . print_r($y,true) . EOL; + json_return_and_die($ret); + } + + // There should be exactly one recipient, the original auth requestor + + $ret['message'] .= 'recipients ' . print_r($recipients,true) . EOL; + + if ($data['recipients']) { + + $arr = $data['recipients'][0]; + $recip_hash = make_xchan_hash($arr['guid'], $arr['guid_sig']); + $c = q("select channel_id, channel_account_id, channel_prvkey from channel where channel_hash = '%s' limit 1", + dbesc($recip_hash) + ); + if (! $c) { + logger('mod_zot: auth_check: recipient channel not found.'); + $ret['message'] .= 'recipient not found.' . EOL; + json_return_and_die($ret); + } + + $confirm = base64url_encode(rsa_sign($data['secret'] . $recip_hash,$c[0]['channel_prvkey'])); + + // This additionally checks for forged sites since we already stored the expected result in meta + // and we've already verified that this is them via zot_gethub() and that their key signed our token + + $z = q("select id from verify where channel = %d and type = 'auth' and token = '%s' and meta = '%s' limit 1", + intval($c[0]['channel_id']), + dbesc($data['secret']), + dbesc($data['sender']['url']) + ); + if (! $z) { + logger('mod_zot: auth_check: verification key not found.'); + $ret['message'] .= 'verification key not found' . EOL; + json_return_and_die($ret); + } + $r = q("delete from verify where id = %d", + intval($z[0]['id']) + ); + + $u = q("select account_service_class from account where account_id = %d limit 1", + intval($c[0]['channel_account_id']) + ); + + logger('mod_zot: auth_check: success', LOGGER_DEBUG); + $ret['success'] = true; + $ret['confirm'] = $confirm; + if ($u && $u[0]['account_service_class']) + $ret['service_class'] = $u[0]['account_service_class']; + + // Set "do not track" flag if this site or this channel's profile is restricted + // in some way + + if (intval(get_config('system','block_public'))) + $ret['DNT'] = true; + if (! perm_is_allowed($c[0]['channel_id'],'','view_profile')) + $ret['DNT'] = true; + if (get_pconfig($c[0]['channel_id'],'system','do_not_track')) + $ret['DNT'] = true; + if (get_pconfig($c[0]['channel_id'],'system','hide_online_status')) + $ret['DNT'] = true; + + json_return_and_die($ret); + } + json_return_and_die($ret); + } + + if ($msgtype === 'request') { + // request a particular post/conversation by message_id + $x = zot_process_message_request($data); + json_return_and_die($x); + } + + if ($msgtype === 'purge') { + if ($recipients) { + // basically this means "unfriend" + foreach ($recipients as $recip) { + $r = q("select channel.*,xchan.* from channel + left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($recip['guid']), + dbesc($recip['guid_sig']) + ); + if ($r) { + $r = q("select abook_id from abook where uid = %d and abook_xchan = '%s' limit 1", + intval($r[0]['channel_id']), + dbesc(make_xchan_hash($sender['guid'],$sender['guid_sig'])) + ); + if ($r) { + contact_remove($r[0]['channel_id'],$r[0]['abook_id']); + } + } + } + } else { + // Unfriend everybody - basically this means the channel has committed suicide + $arr = $data['sender']; + $sender_hash = make_xchan_hash($arr['guid'],$arr['guid_sig']); + + require_once('include/Contact.php'); + remove_all_xchan_resources($sender_hash); + + $ret['success'] = true; + json_return_and_die($ret); + } + } + + if (($msgtype === 'refresh') || ($msgtype === 'force_refresh')) { + + // remote channel info (such as permissions or photo or something) + // has been updated. Grab a fresh copy and sync it. + // The difference between refresh and force_refresh is that + // force_refresh unconditionally creates a directory update record, + // even if no changes were detected upon processing. + + if ($recipients) { + + // This would be a permissions update, typically for one connection + + foreach ($recipients as $recip) { + $r = q("select channel.*,xchan.* from channel + left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($recip['guid']), + dbesc($recip['guid_sig']) + ); + + $x = zot_refresh(array( + 'xchan_guid' => $sender['guid'], + 'xchan_guid_sig' => $sender['guid_sig'], + 'hubloc_url' => $sender['url'] + ), $r[0], (($msgtype === 'force_refresh') ? true : false)); + } + } else { + + // system wide refresh + + $x = zot_refresh(array( + 'xchan_guid' => $sender['guid'], + 'xchan_guid_sig' => $sender['guid_sig'], + 'hubloc_url' => $sender['url'] + ), null, (($msgtype === 'force_refresh') ? true : false)); + } + $ret['success'] = true; + json_return_and_die($ret); + } + + if ($msgtype === 'notify') { + + logger('notify received from ' . $hub['hubloc_url']); + + + $async = get_config('system','queued_fetch'); + + if ($async) { + // add to receive queue + // qreceive_add($data); + } else { + $x = zot_fetch($data); + $ret['delivery_report'] = $x; + } + + $ret['success'] = true; + json_return_and_die($ret); + } + + // catchall + json_return_and_die($ret); +} diff --git a/sources/mod/prate.php b/sources/mod/prate.php new file mode 100644 index 00000000..b89d16f4 --- /dev/null +++ b/sources/mod/prate.php @@ -0,0 +1,99 @@ +get_channel(); + + $target = argv(1); + if(! $target) + return; + + $r = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", + dbesc($channel['channel_hash']), + dbesc($target) + ); + if($r) + json_return_and_die(array('rating' => $r[0]['xlink_rating'],'rating_text' => $r[0]['xlink_rating_text'])); + killme(); +} + +function prate_post(&$a) { + + if(! local_channel()) + return; + + $channel = $a->get_channel(); + + $target = trim($_REQUEST['target']); + if(! $target) + return; + + if($target === $channel['channel_hash']) + return; + + $rating = intval($_POST['rating']); + if($rating < (-10)) + $rating = (-10); + if($rating > 10) + $rating = 10; + + $rating_text = trim(escape_tags($_REQUEST['rating_text'])); + + $signed = $target . '.' . $rating . '.' . $rating_text; + + $sig = base64url_encode(rsa_sign($signed,$channel['channel_prvkey'])); + + + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($target) + ); + if($z) { + $record = $z[0]['xlink_id']; + $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s' + where xlink_id = %d", + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()), + intval($record) + ); + } + else { + $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", + dbesc($channel['channel_hash']), + dbesc($target), + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()) + ); + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($orig_record[0]['abook_xchan']) + ); + if($z) + $record = $z[0]['xlink_id']; + } + if($record) { + proc_run('php','include/ratenotif.php','rating',$record); + } + + json_return_and_die(array('result' => true));; +} + + + + + + + + + + + diff --git a/sources/mod/pretheme.php b/sources/mod/pretheme.php new file mode 100644 index 00000000..1974f5f0 --- /dev/null +++ b/sources/mod/pretheme.php @@ -0,0 +1,22 @@ + get_theme_screenshot($theme), 'desc' => $desc, 'version' => $version, 'credits' => $credits)); + } + killme(); +} diff --git a/sources/mod/probe.php b/sources/mod/probe.php new file mode 100644 index 00000000..62a2227b --- /dev/null +++ b/sources/mod/probe.php @@ -0,0 +1,41 @@ +Probe Diagnostic'; + + $o .= '
    '; + $o .= 'Lookup address: '; + $o .= '
    '; + + $o .= '

    '; + + if(x($_GET,'addr')) { + $channel = $a->get_channel(); + $addr = trim($_GET['addr']); + $do_import = ((intval($_GET['import']) && is_site_admin()) ? true : false); + $res = zot_finger($addr,$channel,false); + $o .= '
    ';
    +		if($res['success'])
    +			$j = json_decode($res['body'],true);
    +		else {
    +			$o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n");
    +			$o .= "https connection failed. Trying again with auto failover to http.\r\n\r\n";
    +			$res = zot_finger($addr,$channel,true);
    +			if($res['success'])
    +				$j = json_decode($res['body'],true);
    +			else
    +				$o .= sprintf( t('Fetching URL returns error: %1$s'),$res['error'] . "\r\n\r\n");
    +
    +		}
    +		if($do_import && $j)
    +			$x = import_xchan($j);
    +		if($j && $j['permissions'] && $j['permissions']['iv'])
    +			$j['permissions'] = json_decode(crypto_unencapsulate($j['permissions'],$channel['channel_prvkey']),true);
    +		$o .= str_replace("\n",'
    ',print_r($j,true)); + $o .= '
    '; + } + return $o; +} diff --git a/sources/mod/profile.php b/sources/mod/profile.php new file mode 100644 index 00000000..430d039e --- /dev/null +++ b/sources/mod/profile.php @@ -0,0 +1,83 @@ + 1) + $which = argv(1); + else { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $profile = ''; + $channel = $a->get_channel(); + + if((local_channel()) && (argc() > 2) && (argv(2) === 'view')) { + $which = $channel['channel_address']; + $profile = argv(1); + $r = q("select profile_guid from profile where id = %d and uid = %d limit 1", + intval($profile), + intval(local_channel()) + ); + if(! $r) + $profile = ''; + $profile = $r[0]['profile_guid']; + } + + $a->page['htmlhead'] .= '' . "\r\n" ; + + if(! $profile) { + $x = q("select channel_id as profile_uid from channel where channel_address = '%s' limit 1", + dbesc(argv(1)) + ); + if($x) { + $a->profile = $x[0]; + } + } + + profile_load($a,$which,$profile); + + +} + +function profile_content(&$a, $update = 0) { + + if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) { + return login(); + } + + $groups = array(); + + $tab = 'profile'; + $o = ''; + + if(! (perm_is_allowed($a->profile['profile_uid'],get_observer_hash(), 'view_profile'))) { + notice( t('Permission denied.') . EOL); + return; + } + + + $is_owner = ((local_channel()) && (local_channel() == $a->profile['profile_uid']) ? true : false); + + if($a->profile['hidewall'] && (! $is_owner) && (! remote_channel())) { + notice( t('Permission denied.') . EOL); + return; + } + + $o .= profile_tabs($a, $is_owner, $a->profile['channel_address']); + + + $o .= advanced_profile($a); + call_hooks('profile_advanced',$o); + return $o; + +} diff --git a/sources/mod/profile_photo.php b/sources/mod/profile_photo.php new file mode 100644 index 00000000..13923a65 --- /dev/null +++ b/sources/mod/profile_photo.php @@ -0,0 +1,427 @@ +"; + foreach ($r1 as $entry) { + $allowcid .= "<" . $entry['abook_xchan'] . ">"; + } + foreach ($r2 as $entry) { + $allowcid .= "<" . $entry['abook_xchan'] . ">"; + } + + q("UPDATE `photo` SET allow_cid = '%s' WHERE resource_id = '%s' AND uid = %d",dbesc($allowcid),dbesc($resource_id),intval($profile['uid'])); + + } else { + q("UPDATE `photo` SET allow_cid = '' WHERE profile = 1 AND uid = %d",intval($profile['uid'])); //Reset permissions on default profile picture to public + } + } + + return; +} + +/* @brief Initalize the profile-photo edit view + * + * @param $a Current application + * @return void + * + */ + +function profile_photo_init(&$a) { + + if(! local_channel()) { + return; + } + + $channel = $a->get_channel(); + profile_load($a,$channel['channel_address']); + +} + +/* @brief Evaluate posted values + * + * @param $a Current application + * @return void + * + */ + +function profile_photo_post(&$a) { + + if(! local_channel()) { + return; + } + + check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); + + if((x($_POST,'cropfinal')) && ($_POST['cropfinal'] == 1)) { + + // unless proven otherwise + $is_default_profile = 1; + + if($_REQUEST['profile']) { + $r = q("select id, is_default from profile where id = %d and uid = %d limit 1", + intval($_REQUEST['profile']), + intval(local_channel()) + ); + if(($r) && (! intval($r[0]['is_default']))) + $is_default_profile = 0; + } + + + + // phase 2 - we have finished cropping + + if(argc() != 2) { + notice( t('Image uploaded but image cropping failed.') . EOL ); + return; + } + + $image_id = argv(1); + + if(substr($image_id,-2,1) == '-') { + $scale = substr($image_id,-1,1); + $image_id = substr($image_id,0,-2); + } + + + $srcX = $_POST['xstart']; + $srcY = $_POST['ystart']; + $srcW = $_POST['xfinal'] - $srcX; + $srcH = $_POST['yfinal'] - $srcY; + + $r = q("SELECT * FROM photo WHERE resource_id = '%s' AND uid = %d AND scale = %d LIMIT 1", + dbesc($image_id), + dbesc(local_channel()), + intval($scale)); + + if($r) { + + $base_image = $r[0]; + $base_image['data'] = dbunescbin($base_image['data']); + + $im = photo_factory($base_image['data'], $base_image['type']); + if($im->is_valid()) { + + $im->cropImage(300,$srcX,$srcY,$srcW,$srcH); + + $aid = get_account_id(); + + $p = array('aid' => $aid, 'uid' => local_channel(), 'resource_id' => $base_image['resource_id'], + 'filename' => $base_image['filename'], 'album' => t('Profile Photos')); + + $p['scale'] = 4; + $p['photo_usage'] = (($is_default_profile) ? PHOTO_PROFILE : PHOTO_NORMAL); + + $r1 = $im->save($p); + + $im->scaleImage(80); + $p['scale'] = 5; + + $r2 = $im->save($p); + + $im->scaleImage(48); + $p['scale'] = 6; + + $r3 = $im->save($p); + + if($r1 === false || $r2 === false || $r3 === false) { + // if one failed, delete them all so we can start over. + notice( t('Image resize failed.') . EOL ); + $x = q("delete from photo where resource_id = '%s' and uid = %d and scale >= 4 ", + dbesc($base_image['resource_id']), + local_channel() + ); + return; + } + + // If setting for the default profile, unset the profile photo flag from any other photos I own + + if($is_default_profile) { + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d + AND resource_id != '%s' AND `uid` = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + dbesc($base_image['resource_id']), + intval(local_channel()) + ); + } + else { + $r = q("update profile set photo = '%s', thumb = '%s' where id = %d and uid = %d", + dbesc($a->get_baseurl() . '/photo/' . $base_image['resource_id'] . '-4'), + dbesc($a->get_baseurl() . '/photo/' . $base_image['resource_id'] . '-5'), + intval($_REQUEST['profile']), + intval(local_channel()) + ); + } + + // We'll set the updated profile-photo timestamp even if it isn't the default profile, + // so that browsers will do a cache update unconditionally + + $channel = $a->get_channel(); + + $r = q("UPDATE xchan set xchan_photo_mimetype = '%s', xchan_photo_date = '%s' + where xchan_hash = '%s'", + dbesc($im->getType()), + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); + + info( t('Shift-reload the page or clear browser cache if the new photo does not display immediately.') . EOL); + + // Update directory in background + proc_run('php',"include/directory.php",$channel['channel_id']); + + // Now copy profile-permissions to pictures, to prevent privacyleaks by automatically created folder 'Profile Pictures' + + profile_photo_set_profile_perms($_REQUEST['profile']); + + } + else + notice( t('Unable to process image') . EOL); + } + + goaway($a->get_baseurl() . '/profiles'); + return; // NOTREACHED + } + + + + $hash = photo_new_resource(); + $smallest = 0; + + require_once('include/attach.php'); + + $res = attach_store($a->get_channel(), get_observer_hash(), '', array('album' => t('Profile Photos'), 'hash' => $hash)); + + logger('attach_store: ' . print_r($res,true)); + + if($res && intval($res['data']['is_photo'])) { + $i = q("select * from photo where resource_id = '%s' and uid = %d order by scale", + dbesc($hash), + intval(local_channel()) + ); + + if(! $i) { + notice( t('Image upload failed.') . EOL ); + return; + } + foreach($i as $ii) { + if(intval($ii['scale']) < 2) { + $smallest = intval($ii['scale']); + $imagedata = $ii['data']; + $filetype = $ii['type']; + } + } + } + +// $imagedata = @file_get_contents($src); + $ph = photo_factory($imagedata, $filetype); + + if(! $ph->is_valid()) { + notice( t('Unable to process image.') . EOL ); + return; + } + + return profile_photo_crop_ui_head($a, $ph, $hash, $smallest); + +} + +/* @brief Generate content of profile-photo view + * + * @param $a Current application + * @return void + * + */ + + +function profile_photo_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL ); + return; + } + + $channel = $a->get_channel(); + + $newuser = false; + + if(argc() == 2 && argv(1) === 'new') + $newuser = true; + + if(argv(1) === 'use') { + if (argc() < 3) { + notice( t('Permission denied.') . EOL ); + return; + }; + +// check_form_security_token_redirectOnErr('/profile_photo', 'profile_photo'); + + $resource_id = argv(2); + + + $r = q("SELECT id, album, scale FROM photo WHERE uid = %d AND resource_id = '%s' ORDER BY scale ASC", + intval(local_channel()), + dbesc($resource_id) + ); + if(! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + $havescale = false; + foreach($r as $rr) { + if($rr['scale'] == 5) + $havescale = true; + } + + // set an already loaded photo as profile photo + + if(($r[0]['album'] == t('Profile Photos')) && ($havescale)) { + // unset any existing profile photos + $r = q("UPDATE photo SET photo_usage = %d WHERE photo_usage = %d AND uid = %d", + intval(PHOTO_NORMAL), + intval(PHOTO_PROFILE), + intval(local_channel())); + + $r = q("UPDATE photo SET photo_usage = %d WHERE uid = %d AND resource_id = '%s'", + intval(PHOTO_PROFILE), + intval(local_channel()), + dbesc($resource_id) + ); + + $r = q("UPDATE xchan set xchan_photo_date = '%s' + where xchan_hash = '%s'", + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); + + profile_photo_set_profile_perms(); //Reset default photo permissions to public + proc_run('php','include/directory.php',local_channel()); + goaway($a->get_baseurl() . '/profiles'); + } + + $r = q("SELECT `data`, `type` FROM photo WHERE id = %d and uid = %d limit 1", + intval($r[0]['id']), + intval(local_channel()) + + ); + if(! $r) { + notice( t('Photo not available.') . EOL ); + return; + } + + $ph = photo_factory(dbunescbin($r[0]['data']), $r[0]['type']); + // go ahead as if we have just uploaded a new photo to crop + profile_photo_crop_ui_head($a, $ph); + } + + $profiles = q("select id, profile_name as name, is_default from profile where uid = %d", + intval(local_channel()) + ); + + if(! x($a->data,'imagecrop')) { + + $tpl = get_markup_template('profile_photo.tpl'); + + $o .= replace_macros($tpl,array( + '$user' => $a->channel['channel_address'], + '$lbl_upfile' => t('Upload File:'), + '$lbl_profiles' => t('Select a profile:'), + '$title' => t('Upload Profile Photo'), + '$submit' => t('Upload'), + '$profiles' => $profiles, + '$form_security_token' => get_form_security_token("profile_photo"), +// FIXME - yuk + '$select' => sprintf('%s %s', t('or'), ($newuser) ? '' . t('skip this step') . '' : '' . t('select a photo from your photo albums') . '') + )); + + call_hooks('profile_photo_content_end', $o); + + return $o; + } + else { + $filename = $a->data['imagecrop'] . '-' . $a->data['imagecrop_resolution']; + $resolution = $a->data['imagecrop_resolution']; + $tpl = get_markup_template("cropbody.tpl"); + $o .= replace_macros($tpl,array( + '$filename' => $filename, + '$profile' => intval($_REQUEST['profile']), + '$resource' => $a->data['imagecrop'] . '-' . $a->data['imagecrop_resolution'], + '$image_url' => $a->get_baseurl() . '/photo/' . $filename, + '$title' => t('Crop Image'), + '$desc' => t('Please adjust the image cropping for optimum viewing.'), + '$form_security_token' => get_form_security_token("profile_photo"), + '$done' => t('Done Editing') + )); + return $o; + } + + return; // NOTREACHED +} + +/* @brief Generate the UI for photo-cropping + * + * @param $a Current application + * @param $ph Photo-Factory + * @return void + * + */ + + + +function profile_photo_crop_ui_head(&$a, $ph, $hash, $smallest){ + + $max_length = get_config('system','max_image_length'); + if(! $max_length) + $max_length = MAX_IMAGE_LENGTH; + if($max_length > 0) + $ph->scaleImage($max_length); + + $width = $ph->getWidth(); + $height = $ph->getHeight(); + + if($width < 300 || $height < 300) { + $ph->scaleImageUp(200); + $width = $ph->getWidth(); + $height = $ph->getHeight(); + } + + + $a->data['imagecrop'] = $hash; + $a->data['imagecrop_resolution'] = $smallest; + $a->page['htmlhead'] .= replace_macros(get_markup_template("crophead.tpl"), array()); + return; +} + diff --git a/sources/mod/profiles.php b/sources/mod/profiles.php new file mode 100644 index 00000000..19e5ffc5 --- /dev/null +++ b/sources/mod/profiles.php @@ -0,0 +1,798 @@ + 2) && (argv(1) === "drop") && intval(argv(2))) { + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is_default` = 0 LIMIT 1", + intval(argv(2)), + intval(local_channel()) + ); + if(! count($r)) { + notice( t('Profile not found.') . EOL); + goaway($a->get_baseurl(true) . '/profiles'); + return; // NOTREACHED + } + $profile_guid = $r['profile_guid']; + + check_form_security_token_redirectOnErr('/profiles', 'profile_drop', 't'); + + // move every contact using this profile as their default to the user default + + $r = q("UPDATE abook SET abook_profile = (SELECT profile_guid AS FROM profile WHERE is_default = 1 AND uid = %d LIMIT 1) WHERE abook_profile = '%s' AND abook_channel = %d ", + intval(local_channel()), + dbesc($profile_guid), + intval(local_channel()) + ); + $r = q("DELETE FROM `profile` WHERE `id` = %d AND `uid` = %d", + intval(argv(2)), + intval(local_channel()) + ); + if($r) + info( t('Profile deleted.') . EOL); + + goaway($a->get_baseurl(true) . '/profiles'); + return; // NOTREACHED + } + + + + + + if((argc() > 1) && (argv(1) === 'new')) { + +// check_form_security_token_redirectOnErr('/profiles', 'profile_new', 't'); + + $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", + intval(local_channel())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + + $r1 = q("SELECT `name`, `photo`, `thumb` FROM `profile` WHERE `uid` = %d AND `is_default` = 1 LIMIT 1", + intval(local_channel())); + + $r2 = q("INSERT INTO `profile` (`aid`, `uid` , `profile_guid`, `profile_name` , `name`, `photo`, `thumb`) + VALUES ( %d, '%s', '%s', '%s', '%s', '%s', '%s' )", + intval(get_account_id()), + intval(local_channel()), + dbesc(random_string()), + dbesc($name), + dbesc($r1[0]['name']), + dbesc($r1[0]['photo']), + dbesc($r1[0]['thumb']) + ); + + $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", + intval(local_channel()), + dbesc($name) + ); + + info( t('New profile created.') . EOL); + if(count($r3) == 1) + goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); + + goaway($a->get_baseurl(true) . '/profiles'); + } + + if((argc() > 2) && (argv(1) === 'clone')) { + + check_form_security_token_redirectOnErr('/profiles', 'profile_clone', 't'); + + $r0 = q("SELECT `id` FROM `profile` WHERE `uid` = %d", + intval(local_channel())); + $num_profiles = count($r0); + + $name = t('Profile-') . ($num_profiles + 1); + $r1 = q("SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d LIMIT 1", + intval(local_channel()), + intval($a->argv[2]) + ); + if(! count($r1)) { + notice( t('Profile unavailable to clone.') . EOL); + $a->error = 404; + return; + } + unset($r1[0]['id']); + $r1[0]['is_default'] = 0; + $r1[0]['publish'] = 0; + $r1[0]['profile_name'] = dbesc($name); + $r1[0]['profile_guid'] = dbesc(random_string()); + + dbesc_array($r1[0]); + + $r2 = dbq("INSERT INTO `profile` (`" + . implode("`, `", array_keys($r1[0])) + . "`) VALUES ('" + . implode("', '", array_values($r1[0])) + . "')" ); + + $r3 = q("SELECT `id` FROM `profile` WHERE `uid` = %d AND `profile_name` = '%s' LIMIT 1", + intval(local_channel()), + dbesc($name) + ); + info( t('New profile created.') . EOL); + if(count($r3) == 1) + goaway($a->get_baseurl(true) . '/profiles/' . $r3[0]['id']); + + goaway($a->get_baseurl(true) . '/profiles'); + + return; // NOTREACHED + } + + if((argc() > 2) && (argv(1) === 'export')) { + + $r1 = q("SELECT * FROM `profile` WHERE `uid` = %d AND `id` = %d LIMIT 1", + intval(local_channel()), + intval(argv(2)) + ); + if(! $r1) { + notice( t('Profile unavailable to export.') . EOL); + $a->error = 404; + return; + } + header('content-type: application/octet_stream'); + header('content-disposition: attachment; filename="' . $r1[0]['profile_name'] . '.json"' ); + + unset($r1[0]['id']); + unset($r1[0]['aid']); + unset($r1[0]['uid']); + unset($r1[0]['is_default']); + unset($r1[0]['publish']); + unset($r1[0]['profile_name']); + unset($r1[0]['profile_guid']); + echo json_encode($r1[0]); + killme(); + } + + + + + // Run profile_load() here to make sure the theme is set before + // we start loading content + if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { + if(feature_enabled(local_channel(),'multi_profiles')) + $id = $a->argv[1]; + else { + $x = q("select id from profile where uid = %d and is_default = 1", + intval(local_channel()) + ); + if($x) + $id = $x[0]['id']; + } + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($id), + intval(local_channel()) + ); + if(! count($r)) { + notice( t('Profile not found.') . EOL); + $a->error = 404; + return; + } + + $chan = $a->get_channel(); + + profile_load($a,$chan['channel_address'],$r[0]['id']); + } +} + +function profiles_post(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + require_once('include/activities.php'); + + $namechanged = false; + + call_hooks('profile_post', $_POST); + + // import from json export file. + // Only import fields that are allowed on this hub + + if(x($_FILES,'userfile')) { + $src = $_FILES['userfile']['tmp_name']; + $filesize = intval($_FILES['userfile']['size']); + if($filesize) { + $j = @json_decode(@file_get_contents($src),true); + @unlink($src); + if($j) { + $fields = get_profile_fields_advanced(); + if($fields) { + foreach($j as $jj => $v) { + foreach($fields as $f => $n) { + if($jj == $f) { + $_POST[$f] = $v; + break; + } + } + } + } + } + } + } + + + + if((argc() > 1) && (argv(1) !== "new") && intval(argv(1))) { + $orig = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($a->argv[1]), + intval(local_channel()) + ); + if(! count($orig)) { + notice( t('Profile not found.') . EOL); + return; + } + + check_form_security_token_redirectOnErr('/profiles', 'profile_edit'); + + $is_default = (($orig[0]['is_default']) ? 1 : 0); + + $profile_name = notags(trim($_POST['profile_name'])); + if(! strlen($profile_name)) { + notify( t('Profile Name is required.') . EOL); + return; + } + + $dob = $_POST['dob'] ? escape_tags(trim($_POST['dob'])) : '0000-00-00'; // FIXME: Needs to be validated? + + $y = substr($dob,0,4); + if((! ctype_digit($y)) || ($y < 1900)) + $ignore_year = true; + else + $ignore_year = false; + + if($dob != '0000-00-00') { + if(strpos($dob,'0000-') === 0) { + $ignore_year = true; + $dob = substr($dob,5); + } + $dob = datetime_convert('UTC','UTC',(($ignore_year) ? '1900-' . $dob : $dob),(($ignore_year) ? 'm-d' : 'Y-m-d')); + if($ignore_year) + $dob = '0000-' . $dob; + } + + $name = escape_tags(trim($_POST['name'])); + + if($orig[0]['name'] != $name) + $namechanged = true; + + $pdesc = escape_tags(trim($_POST['pdesc'])); + $gender = escape_tags(trim($_POST['gender'])); + $address = escape_tags(trim($_POST['address'])); + $locality = escape_tags(trim($_POST['locality'])); + $region = escape_tags(trim($_POST['region'])); + $postal_code = escape_tags(trim($_POST['postal_code'])); + $country_name = escape_tags(trim($_POST['country_name'])); + $keywords = escape_tags(trim($_POST['keywords'])); + $marital = escape_tags(trim($_POST['marital'])); + $howlong = escape_tags(trim($_POST['howlong'])); + $sexual = escape_tags(trim($_POST['sexual'])); + $homepage = escape_tags(trim($_POST['homepage'])); + $hometown = escape_tags(trim($_POST['hometown'])); + $politic = escape_tags(trim($_POST['politic'])); + $religion = escape_tags(trim($_POST['religion'])); + + $likes = fix_mce_lf(escape_tags(trim($_POST['likes']))); + $dislikes = fix_mce_lf(escape_tags(trim($_POST['dislikes']))); + + $about = fix_mce_lf(escape_tags(trim($_POST['about']))); + $interest = fix_mce_lf(escape_tags(trim($_POST['interest']))); + $contact = fix_mce_lf(escape_tags(trim($_POST['contact']))); + $channels = fix_mce_lf(escape_tags(trim($_POST['channels']))); + $music = fix_mce_lf(escape_tags(trim($_POST['music']))); + $book = fix_mce_lf(escape_tags(trim($_POST['book']))); + $tv = fix_mce_lf(escape_tags(trim($_POST['tv']))); + $film = fix_mce_lf(escape_tags(trim($_POST['film']))); + $romance = fix_mce_lf(escape_tags(trim($_POST['romance']))); + $work = fix_mce_lf(escape_tags(trim($_POST['work']))); + $education = fix_mce_lf(escape_tags(trim($_POST['education']))); + + $hide_friends = ((intval($_POST['hide_friends'])) ? 1: 0); + + require_once('include/text.php'); + linkify_tags($a, $likes, local_channel()); + linkify_tags($a, $dislikes, local_channel()); + linkify_tags($a, $about, local_channel()); + linkify_tags($a, $interest, local_channel()); + linkify_tags($a, $interest, local_channel()); + linkify_tags($a, $contact, local_channel()); + linkify_tags($a, $channels, local_channel()); + linkify_tags($a, $music, local_channel()); + linkify_tags($a, $book, local_channel()); + linkify_tags($a, $tv, local_channel()); + linkify_tags($a, $film, local_channel()); + linkify_tags($a, $romance, local_channel()); + linkify_tags($a, $work, local_channel()); + linkify_tags($a, $education, local_channel()); + + + $with = ((x($_POST,'with')) ? escape_tags(trim($_POST['with'])) : ''); + + if(! strlen($howlong)) + $howlong = NULL_DATE; + else + $howlong = datetime_convert(date_default_timezone_get(),'UTC',$howlong); + + // linkify the relationship target if applicable + + $withchanged = false; + + if(strlen($with)) { + if($with != strip_tags($orig[0]['with'])) { + $withchanged = true; + $prf = ''; + $lookup = $with; + if(strpos($lookup,'@') === 0) + $lookup = substr($lookup,1); + $lookup = str_replace('_',' ', $lookup); + $newname = $lookup; + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_name = '%s' AND abook_channel = %d LIMIT 1", + dbesc($newname), + intval(local_channel()) + ); + if(! $r) { + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE xchan_addr = '%s' AND abook_channel = %d LIMIT 1", + dbesc($lookup . '@%'), + intval(local_channel()) + ); + } + if($r) { + $prf = $r[0]['xchan_url']; + $newname = $r[0]['xchan_name']; + } + + + if($prf) { + $with = str_replace($lookup,'' . $newname . '', $with); + if(strpos($with,'@') === 0) + $with = substr($with,1); + } + } + else + $with = $orig[0]['with']; + } + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); + if($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; + + $z = q("select * from profdef where true"); + if($z) { + foreach($z as $zz) { + if(array_key_exists($zz['field_name'],$fields)) { + $w = q("select * from profext where channel_id = %d and hash = '%s' and k = '%s' limit 1", + intval(local_channel()), + dbesc($orig[0]['profile_guid']), + dbesc($zz['field_name']) + ); + if($w) { + q("update profext set v = '%s' where id = %d", + dbesc(escape_tags(trim($_POST[$zz['field_name']]))), + intval($w[0]['id']) + ); + } + else { + q("insert into profext ( channel_id, hash, k, v ) values ( %d, '%s', '%s', '%s') ", + intval(local_channel()), + dbesc($orig[0]['profile_guid']), + dbesc($zz['field_name']), + dbesc(escape_tags(trim($_POST[$zz['field_name']]))) + ); + } + } + } + } + + $changes = array(); + $value = ''; + if($is_default) { + if($marital != $orig[0]['marital']) { + $changes[] = '[color=#ff0000]♥[/color] ' . t('Marital Status'); + $value = $marital; + } + if($withchanged) { + $changes[] = '[color=#ff0000]♥[/color] ' . t('Romantic Partner'); + $value = strip_tags($with); + } + if($likes != $orig[0]['likes']) { + $changes[] = t('Likes'); + $value = $likes; + } + if($dislikes != $orig[0]['dislikes']) { + $changes[] = t('Dislikes'); + $value = $dislikes; + } + if($work != $orig[0]['work']) { + $changes[] = t('Work/Employment'); + } + if($religion != $orig[0]['religion']) { + $changes[] = t('Religion'); + $value = $religion; + } + if($politic != $orig[0]['politic']) { + $changes[] = t('Political Views'); + $value = $politic; + } + if($gender != $orig[0]['gender']) { + $changes[] = t('Gender'); + $value = $gender; + } + if($sexual != $orig[0]['sexual']) { + $changes[] = t('Sexual Preference'); + $value = $sexual; + } + if($homepage != $orig[0]['homepage']) { + $changes[] = t('Homepage'); + $value = $homepage; + } + if($interest != $orig[0]['interest']) { + $changes[] = t('Interests'); + $value = $interest; + } + if($address != $orig[0]['address']) { + $changes[] = t('Address'); + // New address not sent in notifications, potential privacy issues + // in case this leaks to unintended recipients. Yes, it's in the public + // profile but that doesn't mean we have to broadcast it to everybody. + } + if($locality != $orig[0]['locality'] || $region != $orig[0]['region'] + || $country_name != $orig[0]['country_name']) { + $changes[] = t('Location'); + $comma1 = ((($locality) && ($region || $country_name)) ? ', ' : ' '); + $comma2 = (($region && $country_name) ? ', ' : ''); + $value = $locality . $comma1 . $region . $comma2 . $country_name; + } + + profile_activity($changes,$value); + + } + + $r = q("UPDATE `profile` + SET `profile_name` = '%s', + `name` = '%s', + `pdesc` = '%s', + `gender` = '%s', + `dob` = '%s', + `address` = '%s', + `locality` = '%s', + `region` = '%s', + `postal_code` = '%s', + `country_name` = '%s', + `marital` = '%s', + `with` = '%s', + `howlong` = '%s', + `sexual` = '%s', + `homepage` = '%s', + `hometown` = '%s', + `politic` = '%s', + `religion` = '%s', + `keywords` = '%s', + `likes` = '%s', + `dislikes` = '%s', + `about` = '%s', + `interest` = '%s', + `contact` = '%s', + `channels` = '%s', + `music` = '%s', + `book` = '%s', + `tv` = '%s', + `film` = '%s', + `romance` = '%s', + `work` = '%s', + `education` = '%s', + `hide_friends` = %d + WHERE `id` = %d AND `uid` = %d", + dbesc($profile_name), + dbesc($name), + dbesc($pdesc), + dbesc($gender), + dbesc($dob), + dbesc($address), + dbesc($locality), + dbesc($region), + dbesc($postal_code), + dbesc($country_name), + dbesc($marital), + dbesc($with), + dbesc($howlong), + dbesc($sexual), + dbesc($homepage), + dbesc($hometown), + dbesc($politic), + dbesc($religion), + dbesc($keywords), + dbesc($likes), + dbesc($dislikes), + dbesc($about), + dbesc($interest), + dbesc($contact), + dbesc($channels), + dbesc($music), + dbesc($book), + dbesc($tv), + dbesc($film), + dbesc($romance), + dbesc($work), + dbesc($education), + intval($hide_friends), + intval(argv(1)), + intval(local_channel()) + ); + + if($r) + info( t('Profile updated.') . EOL); + + $r = q("select * from profile where id = %d and uid = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if($r) { + require_once('include/zot.php'); + build_sync_packet(local_channel(),array('profile' => $r)); + } + + $channel = $a->get_channel(); + + if($namechanged && $is_default) { + $r = q("UPDATE xchan SET xchan_name = '%s', xchan_name_date = '%s' WHERE xchan_hash = '%s'", + dbesc($name), + dbesc(datetime_convert()), + dbesc($channel['xchan_hash']) + ); + } + + if($is_default) { + // reload the info for the sidebar widget - why does this not work? + profile_load($a,$channel['channel_address']); + proc_run('php','include/directory.php',local_channel()); + } + } +} + + + + +function profiles_content(&$a) { + + $o = ''; + + $channel = $a->get_channel(); + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + + require_once('include/identity.php'); + + $profile_fields_basic = get_profile_fields_basic(); + $profile_fields_advanced = get_profile_fields_advanced(); + + if(((argc() > 1) && (intval(argv(1)))) || !feature_enabled(local_channel(),'multi_profiles')) { + if(feature_enabled(local_channel(),'multi_profiles')) + $id = $a->argv[1]; + else { + $x = q("select id from profile where uid = %d and is_default = 1", + intval(local_channel()) + ); + if($x) + $id = $x[0]['id']; + } + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($id), + intval(local_channel()) + ); + if(! count($r)) { + notice( t('Profile not found.') . EOL); + return; + } + + require_once('include/profile_selectors.php'); + + + $editselect = 'none'; +// if(feature_enabled(local_channel(),'richtext')) +// $editselect = 'textareas'; + + $a->page['htmlhead'] .= replace_macros(get_markup_template('profed_head.tpl'), array( + '$baseurl' => $a->get_baseurl(true), + '$editselect' => $editselect, + )); + + $advanced = ((feature_enabled(local_channel(),'advanced_profiles')) ? true : false); + if($advanced) + $fields = $profile_fields_advanced; + else + $fields = $profile_fields_basic; + + + $opt_tpl = get_markup_template("profile_hide_friends.tpl"); + $hide_friends = replace_macros($opt_tpl,array('$field' => array( + 'hide_friends', + t('Hide your contact/friend list from viewers of this profile?'), + $r[0]['hide_friends'], + '', + ))); + + $q = q("select * from profdef where true"); + if($q) { + $extra_fields = array(); + + foreach($q as $qq) { + $mine = q("select v from profext where k = '%s' and hash = '%s' and channel_id = %d limit 1", + dbesc($qq['field_name']), + dbesc($r[0]['profile_guid']), + intval(local_channel()) + ); + + if(array_key_exists($qq['field_name'],$fields)) { + $extra_fields[] = array($qq['field_name'],$qq['field_desc'],(($mine) ? $mine[0]['v'] : ''), $qq['field_help']); + } + } + } + +//logger('extra_fields: ' . print_r($extra_fields,true)); + + $f = get_config('system','birthday_input_format'); + if(! $f) + $f = 'ymd'; + + $is_default = (($r[0]['is_default']) ? 1 : 0); + $tpl = get_markup_template("profile_edit.tpl"); + $o .= replace_macros($tpl,array( + + '$form_security_token' => get_form_security_token("profile_edit"), + '$profile_clone_link' => ((feature_enabled(local_channel(),'multi_profiles')) ? 'profiles/clone/' . $r[0]['id'] . '?t=' + . get_form_security_token("profile_clone") : ''), + '$profile_drop_link' => 'profiles/drop/' . $r[0]['id'] . '?t=' + . get_form_security_token("profile_drop"), + + '$fields' => $fields, + '$guid' => $r[0]['profile_guid'], + '$banner' => t('Edit Profile Details'), + '$submit' => t('Submit'), + '$viewprof' => t('View this profile'), + '$editvis' => t('Edit visibility'), + '$profpic' => t('Change Profile Photo'), + '$cr_prof' => t('Create a new profile using these settings'), + '$cl_prof' => t('Clone this profile'), + '$del_prof' => t('Delete this profile'), + '$exportable' => feature_enabled(local_channel(),'profile_export'), + '$lbl_import' => t('Import profile from file'), + '$lbl_export' => t('Export profile to file'), + '$lbl_profname' => t('Profile Name:'), + '$lbl_fullname' => t('Your Full Name:'), + '$lbl_title' => t('Title/Description:'), + '$lbl_gender' => t('Your Gender:'), + '$lbl_bd' => t("Birthday :"), + '$lbl_address' => t('Street Address:'), + '$lbl_city' => t('Locality/City:'), + '$lbl_zip' => t('Postal/Zip Code:'), + '$lbl_country' => t('Country:'), + '$lbl_region' => t('Region/State:'), + '$lbl_marital' => t(' Marital Status:'), + '$lbl_with' => t("Who: \x28if applicable\x29"), + '$lbl_ex1' => t('Examples: cathy123, Cathy Williams, cathy@example.com'), + '$lbl_howlong' => t('Since [date]:'), + '$lbl_sexual' => t('Sexual Preference:'), + '$lbl_homepage' => t('Homepage URL:'), + '$lbl_hometown' => t('Hometown:'), + '$lbl_politic' => t('Political Views:'), + '$lbl_religion' => t('Religious Views:'), + '$lbl_pubkey' => t('Keywords:'), + '$lbl_likes' => t('Likes:'), + '$lbl_dislikes' => t('Dislikes:'), + '$lbl_ex2' => t('Example: fishing photography software'), + '$lbl_pubdsc' => t("Used in directory listings"), + '$lbl_about' => t('Tell us about yourself...'), + '$lbl_hobbies' => t('Hobbies/Interests'), + '$lbl_social' => t('Contact information and Social Networks'), + '$lbl_channels' => t('My other channels'), + '$lbl_music' => t('Musical interests'), + '$lbl_book' => t('Books, literature'), + '$lbl_tv' => t('Television'), + '$lbl_film' => t('Film/dance/culture/entertainment'), + '$lbl_love' => t('Love/romance'), + '$lbl_work' => t('Work/employment'), + '$lbl_school' => t('School/education'), + '$disabled' => (($is_default) ? 'onclick="return false;" style="color: #BBBBFF;"' : ''), + '$baseurl' => $a->get_baseurl(true), + '$profile_id' => $r[0]['id'], + '$profile_name' => $r[0]['profile_name'], + '$is_default' => $is_default, + '$default' => t('This is your default profile.') . EOL . translate_scope(map_scope($channel['channel_r_profile'])), + '$advanced' => $advanced, + '$name' => $r[0]['name'], + '$pdesc' => $r[0]['pdesc'], + '$dob' => dob($r[0]['dob']), + '$hide_friends' => $hide_friends, + '$address' => $r[0]['address'], + '$locality' => $r[0]['locality'], + '$region' => $r[0]['region'], + '$postal_code' => $r[0]['postal_code'], + '$country_name' => $r[0]['country_name'], + '$age' => ((intval($r[0]['dob'])) ? '(' . t('Age: ') . age($r[0]['dob'],$a->user['timezone'],$a->user['timezone']) . ')' : ''), + '$gender' => gender_selector($r[0]['gender']), + '$gender_min' => gender_selector_min($r[0]['gender']), + '$marital' => marital_selector($r[0]['marital']), + '$marital_min' => marital_selector_min($r[0]['marital']), + '$with' => $r[0]['with'], + '$howlong' => ($r[0]['howlong'] === NULL_DATE ? '' : datetime_convert('UTC',date_default_timezone_get(),$r[0]['howlong'])), + '$sexual' => sexpref_selector($r[0]['sexual']), + '$sexual_min' => sexpref_selector_min($r[0]['sexual']), + '$about' => $r[0]['about'], + '$homepage' => $r[0]['homepage'], + '$hometown' => $r[0]['hometown'], + '$politic' => $r[0]['politic'], + '$religion' => $r[0]['religion'], + '$keywords' => $r[0]['keywords'], + '$likes' => $r[0]['likes'], + '$dislikes' => $r[0]['dislikes'], + '$music' => $r[0]['music'], + '$book' => $r[0]['book'], + '$tv' => $r[0]['tv'], + '$film' => $r[0]['film'], + '$interest' => $r[0]['interest'], + '$romance' => $r[0]['romance'], + '$work' => $r[0]['work'], + '$education' => $r[0]['education'], + '$contact' => $r[0]['contact'], + '$channels' => $r[0]['channels'], + '$extra_fields' => $extra_fields, + )); + + $arr = array('profile' => $r[0], 'entry' => $o); + call_hooks('profile_edit', $arr); + + return $o; + } + else { + + $r = q("SELECT * FROM `profile` WHERE `uid` = %d", + local_channel()); + if(count($r)) { + + $tpl_header = get_markup_template('profile_listing_header.tpl'); + $o .= replace_macros($tpl_header,array( + '$header' => t('Edit/Manage Profiles'), + '$addstuff' => t('Add profile things'), + '$stuff_desc' => t('Include desirable objects in your profile'), + '$chg_photo' => t('Change profile photo'), + '$cr_new' => t('Create New Profile'), + '$cr_new_link' => 'profiles/new?t=' . get_form_security_token("profile_new") + )); + + + $tpl = get_markup_template('profile_entry.tpl'); + + foreach($r as $rr) { + $o .= replace_macros($tpl, array( + '$photo' => $rr['thumb'], + '$id' => $rr['id'], + '$alt' => t('Profile Image'), + '$profile_name' => $rr['profile_name'], + '$visible' => (($rr['is_default']) + ? '' . translate_scope(map_scope($channel['channel_r_profile'])) . '' + : '' . t('Edit visibility') . '') + )); + } + + } + return $o; + } + +} diff --git a/sources/mod/profperm.php b/sources/mod/profperm.php new file mode 100644 index 00000000..4556119a --- /dev/null +++ b/sources/mod/profperm.php @@ -0,0 +1,165 @@ +get_channel(); + $which = $channel['channel_address']; + + $profile = $a->argv[1]; + + profile_load($a,$which,$profile); + +} + + +function profperm_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied') . EOL); + return; + } + + + if(argc() < 2) { + notice( t('Invalid profile identifier.') . EOL ); + return; + } + + // Switch to text mod interface if we have more than 'n' contacts or group members + + $switchtotext = get_pconfig(local_channel(),'system','groupedit_image_limit'); + if($switchtotext === false) + $switchtotext = get_config('system','groupedit_image_limit'); + if($switchtotext === false) + $switchtotext = 400; + + + if((argc() > 2) && intval(argv(1)) && intval(argv(2))) { + $r = q("SELECT abook_id FROM abook WHERE abook_id = %d and abook_channel = %d limit 1", + intval(argv(2)), + intval(local_channel()) + ); + if($r) + $change = intval(argv(2)); + } + + + if((argc() > 1) && (intval(argv(1)))) { + $r = q("SELECT * FROM `profile` WHERE `id` = %d AND `uid` = %d AND `is_default` = 0 LIMIT 1", + intval(argv(1)), + intval(local_channel()) + ); + if(! $r) { + notice( t('Invalid profile identifier.') . EOL ); + return; + } + + $profile = $r[0]; + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", + intval(local_channel()), + dbesc($profile['profile_guid']) + ); + + $ingroup = array(); + if($r) + foreach($r as $member) + $ingroup[] = $member['abook_id']; + + $members = $r; + + if($change) { + if(in_array($change,$ingroup)) { + q("UPDATE abook SET abook_profile = '' WHERE abook_id = %d AND abook_channel = %d", + intval($change), + intval(local_channel()) + ); + } + else { + q("UPDATE abook SET abook_profile = '%s' WHERE abook_id = %d AND abook_channel = %d", + dbesc($profile['profile_guid']), + intval($change), + intval(local_channel()) + ); + + } + + + //Time to update the permissions on the profile-pictures as well + require_once('mod/profile_photo.php'); + profile_photo_set_profile_perms($profile['id']); + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash WHERE abook_channel = %d AND abook_profile = '%s'", + intval(local_channel()), + dbesc($profile['profile_guid']) + ); + + $members = $r; + + $ingroup = array(); + if(count($r)) + foreach($r as $member) + $ingroup[] = $member['abook_id']; + } + + $o .= '

    ' . t('Profile Visibility Editor') . '

    '; + + $o .= '

    ' . t('Profile') . ' \'' . $profile['profile_name'] . '\'

    '; + + $o .= '
    ' . t('Click on a contact to add or remove.') . '
    '; + + } + + $o .= '
    '; + if($change) + $o = ''; + + $o .= '
    '; + $o .= '

    ' . t('Visible To') . '

    '; + $o .= '
    '; + $o .= '
    '; + + $textmode = (($switchtotext && (count($members) > $switchtotext)) ? true : false); + + foreach($members as $member) { + if($member['xchan_url']) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; + $o .= micropro($member,true,'mpprof', $textmode); + } + } + $o .= '
    '; + $o .= '
    '; + + $o .= '
    '; + $o .= '

    ' . t("All Connections") . '

    '; + $o .= '
    '; + $o .= '
    '; + + $r = abook_connections(local_channel()); + + if($r) { + $textmode = (($switchtotext && (count($r) > $switchtotext)) ? true : false); + foreach($r as $member) { + if(! in_array($member['abook_id'],$ingroup)) { + $member['click'] = 'profChangeMember(' . $profile['id'] . ',' . $member['abook_id'] . '); return false;'; + $o .= micropro($member,true,'mpprof',$textmode); + } + } + } + + $o .= '
    '; + + if($change) { + echo $o; + killme(); + } + $o .= '
    '; + return $o; + +} + diff --git a/sources/mod/public.php b/sources/mod/public.php new file mode 100644 index 00000000..2106be7a --- /dev/null +++ b/sources/mod/public.php @@ -0,0 +1,161 @@ +
    ' . "\r\n"; + $o .= "\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'public', + '$uid' => ((local_channel()) ? local_channel() : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '99', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '1', + '$nouveau' => '0', + '$wall' => '0', + '$list' => '0', + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$search' => '', + '$order' => 'comment', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$dend' => '', + '$mid' => '', + '$verb' => '', + '$dbegin' => '' + )); + } + + if($update && ! $load) { + // only setup pagination on initial page view + $pager_sql = ''; + } + else { + $a->set_pager_itemspage(20); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($a->pager['itemspage']), intval($a->pager['start'])); + } + + require_once('include/identity.php'); + require_once('include/security.php'); + + if(get_config('system','site_firehose')) { + $uids = " and item.uid in ( " . stream_perms_api_uids(PERMS_PUBLIC) . " ) and item_private = 0 and item_wall = 1 "; + } + else { + $sys = get_sys_channel(); + $uids = " and item.uid = " . intval($sys['channel_id']) . " "; + $sql_extra = item_permissions_sql($sys['channel_id']); + $a->data['firehose'] = intval($sys['channel_id']); + } + + + + $page_mode = 'list'; + + $simple_update = (($update) ? " and item.item_unseen = 1 " : ''); + + if($update && $_SESSION['loadtime']) + $simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) "; + if($load) + $simple_update = ''; + + //logger('update: ' . $update . ' load: ' . $load); + + if($update) { + + $ordering = "commented"; + + if($load) { + + // Fetch a page full of parent items for this page + + $r = q("SELECT distinct item.id AS item_id, $ordering FROM item + left join abook on item.author_xchan = abook.abook_xchan + WHERE true $uids $item_normal + AND item.parent = item.id + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets + ORDER BY $ordering DESC $pager_sql " + ); + + + } + elseif($update) { + + $r = q("SELECT distinct item.id AS item_id, $ordering FROM item + left join abook on item.author_xchan = abook.abook_xchan + WHERE true $uids $item_normal + AND item.parent = item.id $simple_update + and (abook.abook_blocked = 0 or abook.abook_flags is null) + $sql_extra3 $sql_extra $sql_nets" + ); + $_SESSION['loadtime'] = datetime_convert(); + } + // Then fetch all the children of the parents that are on this page + $parents_str = ''; + $update_unseen = ''; + + if($r) { + + $parents_str = ids_to_querystr($r,'item_id'); + + $items = q("SELECT item.*, item.id AS item_id FROM item + WHERE true $uids $item_normal + AND item.parent IN ( %s ) + $sql_extra ", + dbesc($parents_str) + ); + + xchan_query($items,true,(-1)); + $items = fetch_post_tags($items,true); + $items = conv_sort($items,$ordering); + } + else { + $items = array(); + } + + } + + // fake it + $mode = ('network'); + + $o .= conversation($a,$items,$mode,$update,$page_mode); + + if(($items) && (! $update)) + $o .= alt_pager($a,count($items)); + + return $o; + +} \ No newline at end of file diff --git a/sources/mod/pubsites.php b/sources/mod/pubsites.php new file mode 100644 index 00000000..62990c70 --- /dev/null +++ b/sources/mod/pubsites.php @@ -0,0 +1,39 @@ +' . t('Public Sites') . ''; + + $o .= '
    ' . + t('The listed sites allow public registration for the $Projectname network. All sites in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details.') . '
    ' . EOL; + + $ret = z_fetch_url($url); + if($ret['success']) { + $j = json_decode($ret['body'],true); + if($j) { + $rate_meta = ((local_channel()) ? '' . t('Rate this hub') . '' : ''); + $o .= '' . $rate_meta . ''; + if($j['sites']) { + foreach($j['sites'] as $jj) { + $host = strtolower(substr($jj['url'],strpos($jj['url'],'://')+3)); + $rate_links = ((local_channel()) ? '' : ''); + $o .= '' . $rate_links . ''; + } + } + + $o .= '
    ' . t('Site URL') . '' . t('Access Type') . '' . t('Registration Policy') . '' . t('Location') . '' . t('View hub ratings') . '
    ' . t('Rate') . '
    ' . '' . $jj['url'] . '' . '' . $jj['access'] . '' . $jj['register'] . '' . $jj['location'] . ' ' . t('View ratings') . '
    '; + } + } + return $o; +} diff --git a/sources/mod/randprof.php b/sources/mod/randprof.php new file mode 100644 index 00000000..9817685c --- /dev/null +++ b/sources/mod/randprof.php @@ -0,0 +1,12 @@ +get_baseurl() . '/profile'); +} diff --git a/sources/mod/rate.php b/sources/mod/rate.php new file mode 100644 index 00000000..a3a36b4a --- /dev/null +++ b/sources/mod/rate.php @@ -0,0 +1,172 @@ +get_channel(); + + $target = $_REQUEST['target']; + if(! $target) + return; + + $a->data['target'] = $target; + + if($target) { + $r = q("SELECT * FROM xchan where xchan_hash like '%s' LIMIT 1", + dbesc($target) + ); + if($r) { + $a->poi = $r[0]; + } + else { + $r = q("select * from site where site_url like '%s' ", + dbesc('%' . $target) + ); + if($r) { + $a->data['site'] = $r[0]; + $a->data['site']['site_url'] = strtolower($r[0]['site_url']); + } + } + } + + + return; + +} + + +function rate_post(&$a) { + + if(! local_channel()) + return; + + if(! $a->data['target']) + return; + + if(! $_REQUEST['execute']) + return; + + $channel = $a->get_channel(); + + $rating = intval($_POST['rating']); + if($rating < (-10)) + $rating = (-10); + if($rating > 10) + $rating = 10; + + $rating_text = trim(escape_tags($_REQUEST['rating_text'])); + + $signed = $a->data['target'] . '.' . $rating . '.' . $rating_text; + + $sig = base64url_encode(rsa_sign($signed,$channel['channel_prvkey'])); + + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($a->data['target']) + ); + + if($z) { + $record = $z[0]['xlink_id']; + $w = q("update xlink set xlink_rating = '%d', xlink_rating_text = '%s', xlink_sig = '%s', xlink_updated = '%s' + where xlink_id = %d", + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()), + intval($record) + ); + } + else { + $w = q("insert into xlink ( xlink_xchan, xlink_link, xlink_rating, xlink_rating_text, xlink_sig, xlink_updated, xlink_static ) values ( '%s', '%s', %d, '%s', '%s', '%s', 1 ) ", + dbesc($channel['channel_hash']), + dbesc($a->data['target']), + intval($rating), + dbesc($rating_text), + dbesc($sig), + dbesc(datetime_convert()) + ); + $z = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1 limit 1", + dbesc($channel['channel_hash']), + dbesc($a->data['target']) + ); + if($z) + $record = $z[0]['xlink_id']; + } + + if($record) { + proc_run('php','include/ratenotif.php','rating',$record); + } + +} + + + +function rate_content(&$a) { + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return; + } + +// if(! $a->data['target']) { +// notice( t('No recipients.') . EOL); +// return; +// } + + $poco_rating = get_config('system','poco_rating_enable'); + if((! $poco_rating) && ($poco_rating !== false)) { + notice('Ratings are disabled on this site.'); + return; + } + + $channel = $a->get_channel(); + + $r = q("select * from xlink where xlink_xchan = '%s' and xlink_link = '%s' and xlink_static = 1", + dbesc($channel['channel_hash']), + dbesc($a->data['target']) + ); + if($r) { + $a->data['xlink'] = $r[0]; + $rating_val = $r[0]['xlink_rating']; + $rating_text = $r[0]['xlink_rating_text']; + } + else { + $rating_val = 0; + $rating_text = ''; + } + + // if unset default to enabled + if($poco_rating === false) + $poco_rating = true; + + if($poco_rating) { + $rating = replace_macros(get_markup_template('rating_slider.tpl'),array( + '$min' => -10, + '$val' => $rating_val + )); + } + else { + $rating = false; + } + + $o = replace_macros(get_markup_template('rating_form.tpl'),array( + '$header' => t('Rating'), + '$website' => t('Website:'), + '$site' => (($a->data['site']) ? '' . $a->data['site']['site_url'] . '' : ''), + 'target' => $a->data['target'], + '$tgt_name' => (($a->poi && $a->poi['xchan_name']) ? $a->poi['xchan_name'] : sprintf( t('Remote Channel [%s] (not yet known on this site)'), substr($a->data['target'],0,16))), + '$lbl_rating' => t('Rating (this information is public)'), + '$lbl_rating_txt' => t('Optionally explain your rating (this information is public)'), + '$rating_txt' => $rating_text, + '$rating' => $rating, + '$rating_val' => $rating_val, + '$slide' => $slide, + '$submit' => t('Submit') + )); + + return $o; + +} \ No newline at end of file diff --git a/sources/mod/ratings.php b/sources/mod/ratings.php new file mode 100644 index 00000000..dc98eb23 --- /dev/null +++ b/sources/mod/ratings.php @@ -0,0 +1,110 @@ + 1) + $hash = argv(1); + + if(! $hash) { + notice('Must supply a channel identififier.'); + return; + } + + $results = false; + + $x = z_fetch_url($url . '/ratingsearch/' . urlencode($hash)); + + + if($x['success']) + $results = json_decode($x['body'],true); + + + if((! $results) || (! $results['success'])) { + + notice('No results.'); + return; + } + + if(array_key_exists('xchan_hash',$results['target'])) + $a->poi = $results['target']; + + $friends = array(); + $others = array(); + + if($results['ratings']) { + foreach($results['ratings'] as $n) { + if(is_array($a->contacts) && array_key_exists($n['xchan_hash'],$a->contacts)) + $friends[] = $n; + else + $others[] = $n; + } + } + + $a->data = array('target' => $results['target'], 'results' => array_merge($friends,$others)); + + if(! $a->data['results']) { + notice( t('No ratings') . EOL); + } + + return; +} + + + + + +function ratings_content(&$a) { + + if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) { + notice( t('Public access denied.') . EOL); + return; + } + + $poco_rating = get_config('system','poco_rating_enable'); + // if unset default to enabled + if($poco_rating === false) + $poco_rating = true; + + if(! $poco_rating) + return; + + $site_target = ((array_key_exists('target',$a->data) && array_key_exists('site_url',$a->data['target'])) ? + '' . $a->data['target']['site_url'] . '' : ''); + + + $o = replace_macros(get_markup_template('prep.tpl'),array( + '$header' => t('Ratings'), + '$rating_lbl' => t('Rating: ' ), + '$website' => t('Website: '), + '$site' => $site_target, + '$rating_text_lbl' => t('Description: '), + '$raters' => $a->data['results'] + )); + + return $o; +} + + \ No newline at end of file diff --git a/sources/mod/ratingsearch.php b/sources/mod/ratingsearch.php new file mode 100644 index 00000000..9c4f2f82 --- /dev/null +++ b/sources/mod/ratingsearch.php @@ -0,0 +1,69 @@ + false); + + $dirmode = intval(get_config('system','directory_mode')); + + if($dirmode == DIRECTORY_MODE_NORMAL) { + $ret['message'] = 'This site is not a directory server.'; + json_return_and_die($ret); + } + + if(argc() > 1) + $hash = argv(1); + + if(! $hash) { + $ret['message'] = 'No channel identifier'; + json_return_and_die($ret); + } + + if(strpos($hash,'@')) { + $r = q("select * from hubloc where hubloc_addr = '%s' limit 1", + dbesc($hash) + ); + if($r) + $hash = $r[0]['hubloc_hash']; + } + + $p = q("select * from xchan where xchan_hash like '%s'", + dbesc($hash . '%') + ); + + if($p) + $target = $p[0]['xchan_hash']; + else { + $p = q("select * from site where site_url like '%s' ", + dbesc('%' . $hash) + ); + if($p) { + $target = strtolower($hash); + } + else { + $ret['message'] = 'Rating target not found'; + json_return_and_die($ret); + } + } + + if($p) + $ret['target'] = $p[0]; + + $ret['success'] = true; + + $r = q("select * from xlink left join xchan on xlink_xchan = xchan_hash + where xlink_link = '%s' and xlink_rating != 0 and xlink_static = 1 order by xchan_name asc", + dbesc($target) + ); + + if($r) { + $ret['ratings'] = $r; + } + else + $ret['ratings'] = array(); + + json_return_and_die($ret); + +} + diff --git a/sources/mod/rbmark.php b/sources/mod/rbmark.php new file mode 100644 index 00000000..cbd32098 --- /dev/null +++ b/sources/mod/rbmark.php @@ -0,0 +1,113 @@ +get_channel(); + + $t = array('url' => escape_tags($_REQUEST['url']),'term' => escape_tags($_REQUEST['title'])); + bookmark_add($channel,$channel,$t,((x($_REQUEST,'private')) ? intval($_REQUEST['private']) : 0), + array('menu_id' => ((x($_REQUEST,'menu_id')) ? intval($_REQUEST['menu_id']) : 0), + 'menu_name' => ((x($_REQUEST,'menu_name')) ? escape_tags($_REQUEST['menu_name']) : ''), + 'ischat' => ((x($_REQUEST['ischat'])) ? intval($_REQUEST['ischat']) : 0) + )); + + goaway(z_root() . '/bookmarks'); + +} + + +function rbmark_content(&$a) { + + $o = ''; + + if(! local_channel()) { + + // The login procedure is going to bugger our $_REQUEST variables + // so save them in the session. + + if(array_key_exists('url',$_REQUEST)) { + $_SESSION['bookmark'] = $_REQUEST; + } + return login(); + } + + // If we have saved rbmark session variables, but nothing in the current $_REQUEST, recover the saved variables + + if((! array_key_exists('url',$_REQUEST)) && (array_key_exists('bookmark',$_SESSION))) { + $_REQUEST = $_SESSION['bookmark']; + unset($_SESSION['bookmark']); + } + + if($_REQUEST['remote_return']) { + $_SESSION['remote_return'] = $_REQUEST['remote_return']; + } + if(argc() > 1 && argv(1) === 'return') { + if($_SESSION['remote_return']) + goaway($_SESSION['remote_return']); + goaway(z_root() . '/bookmarks'); + } + + $channel = $a->get_channel(); + + $m = menu_list($channel,'',MENU_BOOKMARK); + $menus = array(); + if($m) { + $menus = array(0 => ''); + foreach($m as $n) { + $menus[$n['menu_id']] = $n['menu_name']; + } + } + $menu_select = array('menu_id',t('Select a bookmark folder'),false,'',$menus); + + + $o .= replace_macros(get_markup_template('rbmark.tpl'), array( + + '$header' => t('Save Bookmark'), + '$url' => array('url',t('URL of bookmark'),escape_tags($_REQUEST['url'])), + '$title' => array('title',t('Description'),escape_tags($_REQUEST['title'])), + '$ischat' => ((x($_REQUEST,'ischat')) ? intval($_REQUEST['ischat']) : 0), + '$private' => ((x($_REQUEST,'private')) ? intval($_REQUEST['private']) : 0), + '$submit' => t('Save'), + '$menu_name' => array('menu_name',t('Or enter new bookmark folder name'),'',''), + '$menus' => $menu_select + + )); + + + + + + + return $o; + +} + + diff --git a/sources/mod/regdir.php b/sources/mod/regdir.php new file mode 100644 index 00000000..dce50e76 --- /dev/null +++ b/sources/mod/regdir.php @@ -0,0 +1,103 @@ + false); + + $url = $_REQUEST['url']; + $access_token = $_REQUEST['t']; + $valid = 0; + + // we probably don't need the realm as we will find out in the probe. + // What we may want to die is throw an error if you're trying to register in a different realm + // so this configuration issue can be discovered. + + $realm = $_REQUEST['realm']; + if(! $realm) + $realm = DIRECTORY_REALM; + + if($realm === DIRECTORY_REALM) { + $valid = 1; + } else { + $token = get_config('system','realm_token'); + if($token && $access_token != $token) { + $result['message'] = 'This realm requires an access token'; + return; + } + $valid = 1; + } + + $dirmode = intval(get_config('system','directory_mode')); + + if ($dirmode == DIRECTORY_MODE_NORMAL) { + $ret['message'] = t('This site is not a directory server'); + json_return_and_die($ret); + } + + $m = null; + if ($url) { + $m = parse_url($url); + + if ((! $m) || ((! @dns_get_record($m['host'], DNS_A + DNS_CNAME + DNS_PTR)) && (! filter_var($m['host'], FILTER_VALIDATE_IP) ))) { + + $result['message'] = 'unparseable url'; + json_return_and_die($result); + } + + $f = zot_finger('[system]@' . $m['host']); + if($f['success']) { + $j = json_decode($f['body'],true); + if($j['success'] && $j['guid']) { + $x = import_xchan($j); + if($x['success']) { + $result['success'] = true; + } + } + } + + if(! $result['success']) + $valid = 0; + + q("update site set site_valid = %d where site_url = '%s' limit 1", + intval($valid), + strtolower($url) + ); + + json_return_and_die($result); + } else { + + // We can put this in the sql without the condition after 31 august 2015 assuming + // most directory servers will have updated by then + // This just makes sure it happens if I forget + + $sql_extra = ((datetime_convert() > datetime_convert('UTC','UTC','2015-08-31')) ? ' and site_valid = 1 ' : '' ); + if ($dirmode == DIRECTORY_MODE_STANDALONE) { + $r = array(array('site_url' => z_root())); + } else { + $r = q("select site_url from site where site_flags in ( 1, 2 ) and site_realm = '%s' $sql_extra ", + dbesc(get_directory_realm()) + ); + } + if ($r) { + $result['success'] = true; + $result['directories'] = array(); + foreach ($r as $rr) + $result['directories'][] = $rr['site_url']; + + json_return_and_die($result); + } + } + json_return_and_die($result); +} \ No newline at end of file diff --git a/sources/mod/register.php b/sources/mod/register.php new file mode 100644 index 00000000..70bdcf35 --- /dev/null +++ b/sources/mod/register.php @@ -0,0 +1,230 @@ + 1) ? argv(1) : ''); + + // Provide a stored request for somebody desiring a connection + // when they first need to register someplace. Once they've + // created a channel, we'll try to revive the connection request + // and process it. + + if($_REQUEST['connect']) + $_SESSION['connect'] = $_REQUEST['connect']; + + switch($cmd) { + case 'invite_check.json': + $result = check_account_invite($_REQUEST['invite_code']); + break; + case 'email_check.json': + $result = check_account_email($_REQUEST['email']); + break; + case 'password_check.json': + $result = check_account_password($_REQUEST['password']); + break; + default: + break; + } + if($result) { + json_return_and_die($result); + } +} + + +function register_post(&$a) { + + $max_dailies = intval(get_config('system','max_daily_registrations')); + if($max_dailies) { + $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('1 day') + ); + if($r && $r[0]['total'] >= $max_dailies) { + notice( t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL); + return; + } + } + + if(! x($_POST,'tos')) { + notice( t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL); + return; + } + + $policy = get_config('system','register_policy'); + + $email_verify = get_config('system','verify_email'); + + + switch($policy) { + + case REGISTER_OPEN: + $flags = ACCOUNT_OK; + break; + + case REGISTER_APPROVE: + $flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING; + break; + + default: + case REGISTER_CLOSED: + if(! is_site_admin()) { + notice( t('Permission denied.') . EOL ); + return; + } + $flags = ACCOUNT_BLOCKED; + break; + } + + if($email_verify && $policy == REGISTER_OPEN) + $flags = $flags | ACCOUNT_UNVERIFIED; + + + if((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) { + notice( t('Passwords do not match.') . EOL); + return; + } + + $arr = $_POST; + $arr['account_flags'] = $flags; + + $result = create_account($arr); + + if(! $result['success']) { + notice($result['message']); + return; + } + require_once('include/security.php'); + + + $using_invites = intval(get_config('system','invitation_only')); + $num_invites = intval(get_config('system','number_invites')); + $invite_code = ((x($_POST,'invite_code')) ? notags(trim($_POST['invite_code'])) : ''); + + if($using_invites && $invite_code) { + q("delete * from register where hash = '%s'", dbesc($invite_code)); + set_pconfig($result['account']['account_id'],'system','invites_remaining',$num_invites); + } + + if($policy == REGISTER_OPEN ) { + if($email_verify) { + $res = verify_email_address($result); + } + else { + $res = send_verification_email($result['email'],$result['password']); + } + if($res) { + info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ; + } + } + elseif($policy == REGISTER_APPROVE) { + $res = send_reg_approval_email($result); + if($res) { + info( t('Your registration is pending approval by the site owner.') . EOL ) ; + } + else { + notice( t('Your registration can not be processed.') . EOL); + } + goaway(z_root()); + } + + if($email_verify) { + goaway(z_root()); + } + + authenticate_success($result['account'],true,false,true); + + if(! strlen($next_page = get_config('system','workflow_register_next'))) + $next_page = 'new_channel'; + + $_SESSION['workflow'] = true; + + goaway(z_root() . '/' . $next_page); + +} + + + + + + + +function register_content(&$a) { + + $registration_is = ''; + $other_sites = ''; + + if(get_config('system','register_policy') == REGISTER_CLOSED) { + require_once('mod/pubsites.php'); + return pubsites_content($a); + } + + if(get_config('system','register_policy') == REGISTER_APPROVE) { + $registration_is = t('Registration on this site/hub is by approval only.'); + $other_sites = t('Register at another affiliated site/hub'); + } + + $max_dailies = intval(get_config('system','max_daily_registrations')); + if($max_dailies) { + $r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s", + db_utcnow(), db_quoteinterval('1 day') + ); + if($r && $r[0]['total'] >= $max_dailies) { + logger('max daily registrations exceeded.'); + notice( t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL); + return; + } + } + + // Configurable terms of service link + + $tosurl = get_config('system','tos_url'); + if(! $tosurl) + $tosurl = $a->get_baseurl() . '/help/TermsOfService'; + + $toslink = '' . t('Terms of Service') . ''; + + // Configurable whether to restrict age or not - default is based on international legal requirements + // This can be relaxed if you are on a restricted server that does not share with public servers + + if(get_config('system','no_age_restriction')) + $label_tos = sprintf( t('I accept the %s for this website'), $toslink); + else + $label_tos = sprintf( t('I am over 13 years of age and accept the %s for this website'), $toslink); + + $enable_tos = 1 - intval(get_config('system','no_termsofservice')); + + $email = ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : "" ); + $password = ((x($_REQUEST,'password')) ? trim($_REQUEST['password']) : "" ); + $password2 = ((x($_REQUEST,'password2')) ? trim($_REQUEST['password2']) : "" ); + $invite_code = ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : "" ); + + + require_once('include/bbcode.php'); + + $o = replace_macros(get_markup_template('register.tpl'), array( + + '$title' => t('Registration'), + '$reg_is' => $registration_is, + '$registertext' => bbcode(get_config('system','register_text')), + '$other_sites' => $other_sites, + '$invitations' => get_config('system','invitation_only'), + '$invite_desc' => t('Membership on this site is by invitation only.'), + '$label_invite' => t('Please enter your invitation code'), + '$invite_code' => $invite_code, + + '$label_email' => t('Your email address'), + '$label_pass1' => t('Choose a password'), + '$label_pass2' => t('Please re-enter your password'), + '$label_tos' => $label_tos, + '$enable_tos' => $enable_tos, + '$email' => $email, + '$pass1' => $password, + '$pass2' => $password2, + '$submit' => t('Register') + )); + + return $o; + +} + diff --git a/sources/mod/regmod.php b/sources/mod/regmod.php new file mode 100644 index 00000000..c0a75ef4 --- /dev/null +++ b/sources/mod/regmod.php @@ -0,0 +1,34 @@ +cmd; + + if(! local_channel()) { + info( t('Please login.') . EOL); + $o .= '

    ' . login(($a->config['system']['register_policy'] == REGISTER_CLOSED) ? 0 : 1); + return $o; + } + + if(! is_site_admin()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(argc() != 3) + killme(); + + $cmd = argv(1); + $hash = argv(2); + + if($cmd === 'deny') { + if (!user_deny($hash)) killme(); + } + + if($cmd === 'allow') { + if (!user_allow($hash)) killme(); + } +} diff --git a/sources/mod/regver.php b/sources/mod/regver.php new file mode 100644 index 00000000..c3ade2ee --- /dev/null +++ b/sources/mod/regver.php @@ -0,0 +1,22 @@ +cmd; + + if(argc() != 3) + killme(); + + $cmd = argv(1); + $hash = argv(2); + + if($cmd === 'deny') { + if (!user_deny($hash)) killme(); + } + + if($cmd === 'allow') { + if (!user_approve($hash)) killme(); + } +} diff --git a/sources/mod/removeaccount.php b/sources/mod/removeaccount.php new file mode 100644 index 00000000..f3fa53f7 --- /dev/null +++ b/sources/mod/removeaccount.php @@ -0,0 +1,66 @@ +get_account(); + $account_id = get_account_id(); + + if(! account_verify_password($account['account_email'],$_POST['qxz_password'])) + return; + + if($account['account_password_changed'] != NULL_DATE) { + $d1 = datetime_convert('UTC','UTC','now - 48 hours'); + if($account['account_password_changed'] > d1) { + notice( t('Account removals are not allowed within 48 hours of changing the account password.') . EOL); + return; + } + } + + require_once('include/Contact.php'); + + $global_remove = intval($_POST['global']); + + account_remove($account_id,true); + +} + + + +function removeaccount_content(&$a) { + + if(! local_channel()) + goaway(z_root()); + + $hash = random_string(); + + $_SESSION['remove_account_verify'] = $hash; + $tpl = get_markup_template('removeaccount.tpl'); + $o .= replace_macros($tpl, array( + '$basedir' => $a->get_baseurl(), + '$hash' => $hash, + '$title' => t('Remove This Account'), + '$desc' => array(t('WARNING: '), t('This account and all its channels will be completely removed from the network. '), t('This action is permanent and can not be undone!')), + '$passwd' => t('Please enter your password for verification:'), + '$global' => array('global', t('Remove this account, all its channels and all its channel clones from the network'), false, t('By default only the instances of the channels located on this hub will be removed from the network')), + '$submit' => t('Remove Account') + )); + + return $o; + +} diff --git a/sources/mod/removeme.php b/sources/mod/removeme.php new file mode 100644 index 00000000..b604bc7d --- /dev/null +++ b/sources/mod/removeme.php @@ -0,0 +1,66 @@ +get_account(); + + if(! account_verify_password($account['account_email'],$_POST['qxz_password'])) + return; + + if($account['account_password_changed'] != NULL_DATE) { + $d1 = datetime_convert('UTC','UTC','now - 48 hours'); + if($account['account_password_changed'] > d1) { + notice( t('Channel removals are not allowed within 48 hours of changing the account password.') . EOL); + return; + } + } + + require_once('include/Contact.php'); + + $global_remove = intval($_POST['global']); + + channel_remove(local_channel(),1 - $global_remove,true); + +} + + + +function removeme_content(&$a) { + + if(! local_channel()) + goaway(z_root()); + + $hash = random_string(); + + $_SESSION['remove_account_verify'] = $hash; + + $tpl = get_markup_template('removeme.tpl'); + $o .= replace_macros($tpl, array( + '$basedir' => $a->get_baseurl(), + '$hash' => $hash, + '$title' => t('Remove This Channel'), + '$desc' => array(t('WARNING: '), t('This channel will be completely removed from the network. '), t('This action is permanent and can not be undone!')), + '$passwd' => t('Please enter your password for verification:'), + '$global' => array('global', t('Remove this channel and all its clones from the network'), false, t('By default only the instance of the channel located on this hub will be removed from the network'), array(t('No'),t('Yes'))), + '$submit' => t('Remove Channel') + )); + + return $o; + +} diff --git a/sources/mod/rmagic.php b/sources/mod/rmagic.php new file mode 100644 index 00000000..597c6ed9 --- /dev/null +++ b/sources/mod/rmagic.php @@ -0,0 +1,90 @@ +query_string); + goaway($r[0]['hubloc_url'] . '/magic' . '?f=&dest=' . $dest); + } + } +} + +function rmagic_post(&$a) { + + $address = trim($_REQUEST['address']); + + if(strpos($address,'@') === false) { + $arr = array('address' => $address); + call_hooks('reverse_magic_auth', $arr); + + try { + require_once('library/openid/openid.php'); + $openid = new LightOpenID(z_root()); + $openid->identity = $address; + $openid->returnUrl = z_root() . '/openid'; + $openid->required = array('namePerson/friendly', 'namePerson'); + $openid->optional = array('namePerson/first','media/image/aspect11','media/image/default'); + goaway($openid->authUrl()); + } catch (Exception $e) { + notice( t('We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID.').'

    '. t('The error message was:').' '.$e->getMessage()); + } + + // if they're still here... + notice( t('Authentication failed.') . EOL); + return; + } + else { + + // Presumed Red identity. Perform reverse magic auth + + if(strpos($address,'@') === false) { + notice('Invalid address.'); + return; + } + + $r = null; + if($address) { + $r = q("select hubloc_url from hubloc where hubloc_addr = '%s' limit 1", + dbesc($address) + ); + } + if($r) { + $url = $r[0]['hubloc_url']; + } + else { + $url = 'https://' . substr($address,strpos($address,'@')+1); + } + + if($url) { + if($_SESSION['return_url']) + $dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',$_SESSION['return_url'])); + else + $dest = urlencode(z_root() . '/' . str_replace('zid=','zid_=',$a->query_string)); + + goaway($url . '/magic' . '?f=&dest=' . $dest); + } + } +} + + +function rmagic_content(&$a) { + + $o = replace_macros(get_markup_template('rmagic.tpl'),array( + '$title' => t('Remote Authentication'), + '$desc' => t('Enter your channel address (e.g. channel@example.com)'), + '$submit' => t('Authenticate') + )); + return $o; + +} \ No newline at end of file diff --git a/sources/mod/rpost.php b/sources/mod/rpost.php new file mode 100644 index 00000000..4a6b87cc --- /dev/null +++ b/sources/mod/rpost.php @@ -0,0 +1,139 @@ +get_observer()); + // make sure we're not looping to our own hub + if(($url) && (! stristr($url, $a->get_hostname()))) { + foreach($_REQUEST as $key => $arg) { + $url .= '&' . $key . '=' . $arg; + } + goaway($url); + } + } + + // The login procedure is going to bugger our $_REQUEST variables + // so save them in the session. + + if(array_key_exists('body',$_REQUEST)) { + $_SESSION['rpost'] = $_REQUEST; + } + return login(); + } + + // If we have saved rpost session variables, but nothing in the current $_REQUEST, recover the saved variables + + if((! array_key_exists('body',$_REQUEST)) && (array_key_exists('rpost',$_SESSION))) { + $_REQUEST = $_SESSION['rpost']; + unset($_SESSION['rpost']); + } + + if(array_key_exists('channel',$_REQUEST)) { + $r = q("select channel_id from channel where channel_account_id = %d and channel_address = '%s' limit 1", + intval(get_account_id()), + dbesc($_REQUEST['channel']) + ); + if($r) { + require_once('include/security.php'); + $change = change_channel($r[0]['channel_id']); + } + } + + if($_REQUEST['remote_return']) { + $_SESSION['remote_return'] = $_REQUEST['remote_return']; + } + if(argc() > 1 && argv(1) === 'return') { + if($_SESSION['remote_return']) + goaway($_SESSION['remote_return']); + goaway(z_root() . '/network'); + } + + $plaintext = true; +// if(feature_enabled(local_channel(),'richtext')) +// $plaintext = false; + + if(array_key_exists('type', $_REQUEST) && $_REQUEST['type'] === 'html') { + require_once('include/html2bbcode.php'); + $_REQUEST['body'] = html2bbcode($_REQUEST['body']); + } + + $channel = $a->get_channel(); + + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + if($_REQUEST['url']) { + $x = z_fetch_url(z_root() . '/urlinfo?f=&url=' . urlencode($_REQUEST['url'])); + if($x['success']) + $_REQUEST['body'] = $_REQUEST['body'] . $x['body']; + } + + $x = array( + 'is_owner' => true, + 'allow_location' => ((intval(get_pconfig($channel['channel_id'],'system','use_browser_location'))) ? '1' : ''), + 'default_location' => $channel['channel_location'], + 'nickname' => $channel['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] + || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'acl' => populate_acl($channel_acl), + 'bang' => '', + 'visitor' => true, + 'profile_uid' => local_channel(), + 'title' => $_REQUEST['title'], + 'body' => $_REQUEST['body'], + 'attachment' => $_REQUEST['attachment'], + 'source' => ((x($_REQUEST,'source')) ? strip_tags($_REQUEST['source']) : ''), + 'return_path' => 'rpost/return' + ); + + $editor = status_editor($a,$x); + + $o .= replace_macros(get_markup_template('edpost_head.tpl'), array( + '$title' => t('Edit post'), + '$editor' => $editor + )); + + return $o; + +} + + diff --git a/sources/mod/rsd_xml.php b/sources/mod/rsd_xml.php new file mode 100644 index 00000000..6fd9514c --- /dev/null +++ b/sources/mod/rsd_xml.php @@ -0,0 +1,24 @@ + + + + Red + http://friendica.com/ + + + + http://status.net/wiki/TwitterCompatibleAPI + false + + + + + + '; +die(); +} \ No newline at end of file diff --git a/sources/mod/search.php b/sources/mod/search.php new file mode 100644 index 00000000..ce8357fb --- /dev/null +++ b/sources/mod/search.php @@ -0,0 +1,217 @@ +data['search'] = $_REQUEST['search']; +} + + +function search_content(&$a,$update = 0, $load = false) { + + if((get_config('system','block_public')) || (get_config('system','block_public_search'))) { + if ((! local_channel()) && (! remote_channel())) { + notice( t('Public access denied.') . EOL); + return; + } + } + + if($load) + $_SESSION['loadtime'] = datetime_convert(); + + nav_set_selected('search'); + + require_once("include/bbcode.php"); + require_once('include/security.php'); + require_once('include/conversation.php'); + require_once('include/items.php'); + + $format = (($_REQUEST['format']) ? $_REQUEST['format'] : ''); + if($format !== '') { + $update = $load = 1; + } + + $observer = $a->get_observer(); + $observer_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $o = '' . "\r\n"; + + $o .= '

    ' . t('Search') . '

    '; + + if(x($a->data,'search')) + $search = trim($a->data['search']); + else + $search = ((x($_GET,'search')) ? trim(rawurldecode($_GET['search'])) : ''); + + $tag = false; + if(x($_GET,'tag')) { + $tag = true; + $search = ((x($_GET,'tag')) ? trim(rawurldecode($_GET['tag'])) : ''); + } + + if((! local_channel()) || (! feature_enabled(local_channel(),'savedsearch'))) + $o .= search($search,'search-box','/search',((local_channel()) ? true : false)); + + if(strpos($search,'#') === 0) { + $tag = true; + $search = substr($search,1); + } + if(strpos($search,'@') === 0) { + $search = substr($search,1); + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + if(strpos($search,'?') === 0) { + $search = substr($search,1); + goaway(z_root() . '/help' . '?f=1&navsearch=1&search=' . $search); + } + + // look for a naked webbie + if(strpos($search,'@') !== false) { + goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search); + } + + if(! $search) + return $o; + + if($tag) { + $sql_extra = sprintf(" AND `item`.`id` IN (select `oid` from term where otype = %d and type = %d and term = '%s') ", + intval(TERM_OBJ_POST), + intval(TERM_HASHTAG), + dbesc(protect_sprintf($search)) + ); + } + else { + $regstr = db_getfunc('REGEXP'); + $sql_extra = sprintf(" AND `item`.`body` $regstr '%s' ", dbesc(protect_sprintf(preg_quote($search)))); + } + + // Here is the way permissions work in the search module... + // Only public posts can be shown + // OR your own posts if you are a logged in member + // No items will be shown if the member has a blocked profile wall. + + if((! $update) && (! $load)) { + + // This is ugly, but we can't pass the profile_uid through the session to the ajax updater, + // because browser prefetching might change it on us. We have to deliver it with the page. + + $o .= '' . "\r\n"; + $o .= "\r\n"; + + $a->page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),array( + '$baseurl' => z_root(), + '$pgtype' => 'search', + '$uid' => (($a->profile['profile_uid']) ? $a->profile['profile_uid'] : '0'), + '$gid' => '0', + '$cid' => '0', + '$cmin' => '0', + '$cmax' => '0', + '$star' => '0', + '$liked' => '0', + '$conv' => '0', + '$spam' => '0', + '$fh' => '0', + '$nouveau' => '0', + '$wall' => '0', + '$list' => ((x($_REQUEST,'list')) ? intval($_REQUEST['list']) : 0), + '$page' => (($a->pager['page'] != 1) ? $a->pager['page'] : 1), + '$search' => (($tag) ? urlencode('#') : '') . $search, + '$order' => '', + '$file' => '', + '$cats' => '', + '$tags' => '', + '$mid' => '', + '$verb' => '', + '$dend' => '', + '$dbegin' => '' + )); + + + } + + $item_normal = item_normal(); + $pub_sql = public_permissions_sql($observer_hash); + + require_once('include/identity.php'); + + $sys = get_sys_channel(); + + if(($update) && ($load)) { + $itemspage = get_pconfig(local_channel(),'system','itemspage'); + $a->set_pager_itemspage(((intval($itemspage)) ? $itemspage : 20)); + $pager_sql = sprintf(" LIMIT %d OFFSET %d ", intval($a->pager['itemspage']), intval($a->pager['start'])); + + // in case somebody turned off public access to sys channel content with permissions + + if(! perm_is_allowed($sys['channel_id'],$observer_hash,'view_stream')) + $sys['xchan_hash'] .= 'disabled'; + + if($load) { + $r = null; + + if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) { + $prefix = 'distinct on (created, mid)'; + $suffix = 'ORDER BY created DESC, mid'; + } else { + $prefix = 'distinct'; + $suffix = 'group by mid ORDER BY created DESC'; + } + if(local_channel()) { + $r = q("SELECT $prefix mid, item.id as item_id, item.* from item + WHERE ((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' AND `item`.`deny_gid` = '' AND item_private = 0 ) + OR ( `item`.`uid` = %d )) OR item.owner_xchan = '%s' ) + $item_normal + $sql_extra + $suffix $pager_sql ", + intval(local_channel()), + dbesc($sys['xchan_hash']) + ); + } + if($r === null) { + $r = q("SELECT $prefix mid, item.id as item_id, item.* from item + WHERE (((( `item`.`allow_cid` = '' AND `item`.`allow_gid` = '' AND `item`.`deny_cid` = '' + AND `item`.`deny_gid` = '' AND item_private = 0 ) + and owner_xchan in ( " . stream_perms_xchans(($observer) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " )) + $pub_sql ) OR owner_xchan = '%s') + $item_normal + $sql_extra + $suffix $pager_sql", + dbesc($sys['xchan_hash']) + ); + } + } + else { + $r = array(); + } + } + + if($r) { + xchan_query($r); + $items = fetch_post_tags($r,true); + } else { + $items = array(); + } + + + if($format == 'json') { + $result = array(); + require_once('include/conversation.php'); + foreach($items as $item) { + $item['html'] = bbcode($item['body']); + $x = encode_item($item); + $x['html'] = prepare_text($item['body'],$item['mimetype']); + $result[] = $x; + } + json_return_and_die(array('success' => true,'messages' => $result)); + } + + if($tag) + $o .= '

    ' . sprintf( t('Items tagged with: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '

    '; + else + $o .= '

    ' . sprintf( t('Search results for: %s'),htmlspecialchars($search, ENT_COMPAT,'UTF-8')) . '

    '; + + $o .= conversation($a,$items,'search',$update,'client'); + + return $o; +} + diff --git a/sources/mod/search_ac.php b/sources/mod/search_ac.php new file mode 100644 index 00000000..e42945d4 --- /dev/null +++ b/sources/mod/search_ac.php @@ -0,0 +1,75 @@ + $g['xchan_photo_s'], + "name" => '@'.$g['xchan_name'], + "id" => $g['abook_id'], + "link" => $g['xchan_url'], + "label" => '', + "nick" => '', + ); + } + } + + $r = q("select distinct term, tid, url from term where type = %d $tag_sql_extra group by term order by term asc", + intval(TERM_HASHTAG) + ); + + if(count($r)) { + foreach($r as $g) { + $results[] = array( + "photo" => $a->get_baseurl() . '/images/hashtag.png', + "name" => '#'.$g['term'], + "id" => $g['tid'], + "link" => $g['url'], + "label" => '', + "nick" => '', + ); + } + } + + header("content-type: application/json"); + $o = array( + 'start' => $start, + 'count' => $count, + 'items' => $results, + ); + echo json_encode($o); + + logger('search_ac: ' . print_r($x,true)); + + killme(); +} + + diff --git a/sources/mod/service_limits.php b/sources/mod/service_limits.php new file mode 100644 index 00000000..ac96668a --- /dev/null +++ b/sources/mod/service_limits.php @@ -0,0 +1,23 @@ +get_account(); + if($account['account_service_class']) { + $x = get_config('service_class',$account['account_service_class']); + if($x) { + $o = print_r($x,true); + return $o; + } + } + return t('No service class restrictions found.'); +} + + + \ No newline at end of file diff --git a/sources/mod/settings.php b/sources/mod/settings.php new file mode 100644 index 00000000..cbd6abaf --- /dev/null +++ b/sources/mod/settings.php @@ -0,0 +1,1127 @@ +theme_info['extends']; + + if (file_exists("view/theme/$theme/php/config.php")){ + return "view/theme/$theme/php/config.php"; + } + if (file_exists("view/theme/$base_theme/php/config.php")){ + return "view/theme/$base_theme/php/config.php"; + } + return null; +} + +function settings_init(&$a) { + if(! local_channel()) + return; + + if($_SESSION['delegate']) + return; + + $a->profile_uid = local_channel(); + + // default is channel settings in the absence of other arguments + + if(argc() == 1) { + // We are setting these values - don't use the argc(), argv() functions here + $a->argc = 2; + $a->argv[] = 'channel'; + } + + + +} + + +function settings_post(&$a) { + + if(! local_channel()) + return; + + if($_SESSION['delegate']) + return; + + $channel = $a->get_channel(); + + logger('mod_settings: ' . print_r($_REQUEST,true)); + + + if((argc() > 1) && (argv(1) === 'oauth') && x($_POST,'remove')){ + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); + + $key = $_POST['remove']; + q("DELETE FROM tokens WHERE id='%s' AND uid=%d", + dbesc($key), + local_channel()); + goaway($a->get_baseurl(true)."/settings/oauth/"); + return; + } + + if((argc() > 2) && (argv(1) === 'oauth') && (argv(2) === 'edit'||(argv(2) === 'add')) && x($_POST,'submit')) { + + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth'); + + $name = ((x($_POST,'name')) ? $_POST['name'] : ''); + $key = ((x($_POST,'key')) ? $_POST['key'] : ''); + $secret = ((x($_POST,'secret')) ? $_POST['secret'] : ''); + $redirect = ((x($_POST,'redirect')) ? $_POST['redirect'] : ''); + $icon = ((x($_POST,'icon')) ? $_POST['icon'] : ''); + $ok = true; + if($name == '') { + $ok = false; + notice( t('Name is required') . EOL); + } + if($key == '' || $secret == '') { + $ok = false; + notice( t('Key and Secret are required') . EOL); + } + + if($ok) { + if ($_POST['submit']==t("Update")){ + $r = q("UPDATE clients SET + client_id='%s', + pw='%s', + name='%s', + redirect_uri='%s', + icon='%s', + uid=%d + WHERE client_id='%s'", + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()), + dbesc($key)); + } else { + $r = q("INSERT INTO clients (client_id, pw, name, redirect_uri, icon, uid) + VALUES ('%s','%s','%s','%s','%s',%d)", + dbesc($key), + dbesc($secret), + dbesc($name), + dbesc($redirect), + dbesc($icon), + intval(local_channel()) + ); + $r = q("INSERT INTO xperm (xp_client, xp_channel, xp_perm) VALUES ('%s', %d, '%s') ", + dbesc($key), + intval(local_channel()), + dbesc('all') + ); + } + } + goaway($a->get_baseurl(true)."/settings/oauth/"); + return; + } + + if((argc() > 1) && (argv(1) == 'featured')) { + check_form_security_token_redirectOnErr('/settings/featured', 'settings_featured'); + + call_hooks('feature_settings_post', $_POST); + + build_sync_packet(); + return; + } + + + + if((argc() > 1) && (argv(1) === 'features')) { + check_form_security_token_redirectOnErr('/settings/features', 'settings_features'); + + // Build list of features and check which are set + $features = get_features(); + $all_features = array(); + foreach($features as $k => $v) { + foreach($v as $f) + $all_features[] = $f[0]; + } + foreach($all_features as $k) { + if(x($_POST,"feature_$k")) + set_pconfig(local_channel(),'feature',$k, 1); + else + set_pconfig(local_channel(),'feature',$k, 0); + } + build_sync_packet(); + return; + } + + if((argc() > 1) && (argv(1) == 'display')) { + + check_form_security_token_redirectOnErr('/settings/display', 'settings_display'); + + $theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : $a->channel['channel_theme']); + $mobile_theme = ((x($_POST,'mobile_theme')) ? notags(trim($_POST['mobile_theme'])) : ''); + $user_scalable = ((x($_POST,'user_scalable')) ? intval($_POST['user_scalable']) : 0); + $nosmile = ((x($_POST,'nosmile')) ? intval($_POST['nosmile']) : 0); + $title_tosource = ((x($_POST,'title_tosource')) ? intval($_POST['title_tosource']) : 0); + $channel_list_mode = ((x($_POST,'channel_list_mode')) ? intval($_POST['channel_list_mode']) : 0); + $network_list_mode = ((x($_POST,'network_list_mode')) ? intval($_POST['network_list_mode']) : 0); + + $channel_divmore_height = ((x($_POST,'channel_divmore_height')) ? intval($_POST['channel_divmore_height']) : 400); + if($channel_divmore_height < 50) + $channel_divmore_height = 50; + $network_divmore_height = ((x($_POST,'network_divmore_height')) ? intval($_POST['network_divmore_height']) : 400); + if($network_divmore_height < 50) + $network_divmore_height = 50; + + $browser_update = ((x($_POST,'browser_update')) ? intval($_POST['browser_update']) : 0); + $browser_update = $browser_update * 1000; + if($browser_update < 10000) + $browser_update = 10000; + + $itemspage = ((x($_POST,'itemspage')) ? intval($_POST['itemspage']) : 20); + if($itemspage > 100) + $itemspage = 100; + + + if ($mobile_theme == "---") + del_pconfig(local_channel(),'system','mobile_theme'); + else { + set_pconfig(local_channel(),'system','mobile_theme',$mobile_theme); + } + + set_pconfig(local_channel(),'system','user_scalable',$user_scalable); + set_pconfig(local_channel(),'system','update_interval', $browser_update); + set_pconfig(local_channel(),'system','itemspage', $itemspage); + set_pconfig(local_channel(),'system','no_smilies',1-intval($nosmile)); + set_pconfig(local_channel(),'system','title_tosource',$title_tosource); + set_pconfig(local_channel(),'system','channel_list_mode', $channel_list_mode); + set_pconfig(local_channel(),'system','network_list_mode', $network_list_mode); + set_pconfig(local_channel(),'system','channel_divmore_height', $channel_divmore_height); + set_pconfig(local_channel(),'system','network_divmore_height', $network_divmore_height); + + if ($theme == $a->channel['channel_theme']){ + // call theme_post only if theme has not been changed + if( ($themeconfigfile = get_theme_config_file($theme)) != null){ + require_once($themeconfigfile); + theme_post($a); + } + } + + $r = q("UPDATE channel SET channel_theme = '%s' WHERE channel_id = %d", + dbesc($theme), + intval(local_channel()) + ); + + call_hooks('display_settings_post', $_POST); + build_sync_packet(); + goaway($a->get_baseurl(true) . '/settings/display' ); + return; // NOTREACHED + } + + + if(argc() > 1 && argv(1) === 'account') { + + check_form_security_token_redirectOnErr('/settings/account', 'settings_account'); + + call_hooks('settings_account', $_POST); + + $errs = array(); + + if((x($_POST,'npassword')) || (x($_POST,'confirm'))) { + + $newpass = $_POST['npassword']; + $confirm = $_POST['confirm']; + + if($newpass != $confirm ) { + $errs[] = t('Passwords do not match. Password unchanged.'); + } + + if((! x($newpass)) || (! x($confirm))) { + $errs[] = t('Empty passwords are not allowed. Password unchanged.'); + } + + if(! $errs) { + $salt = random_string(32); + $password_encoded = hash('whirlpool', $salt . $newpass); + $r = q("update account set account_salt = '%s', account_password = '%s', account_password_changed = '%s' + where account_id = %d", + dbesc($salt), + dbesc($password_encoded), + dbesc(datetime_convert()), + intval(get_account_id()) + ); + if($r) + info( t('Password changed.') . EOL); + else + $errs[] = t('Password update failed. Please try again.'); + } + } + + if($errs) { + foreach($errs as $err) + notice($err . EOL); + $errs = array(); + } + + $email = ((x($_POST,'email')) ? trim(notags($_POST['email'])) : ''); + $account = $a->get_account(); + if($email != $account['account_email']) { + if(! valid_email($email)) + $errs[] = t('Not valid email.'); + $adm = trim(get_config('system','admin_email')); + if(($adm) && (strcasecmp($email,$adm) == 0)) { + $errs[] = t('Protected email address. Cannot change to that email.'); + $email = $a->user['email']; + } + if(! $errs) { + $r = q("update account set account_email = '%s' where account_id = %d", + dbesc($email), + intval($account['account_id']) + ); + if(! $r) + $errs[] = t('System failure storing new email. Please try again.'); + } + } + + if($errs) { + foreach($errs as $err) + notice($err . EOL); + } + goaway($a->get_baseurl(true) . '/settings/account' ); + } + + + check_form_security_token_redirectOnErr('/settings', 'settings'); + + call_hooks('settings_post', $_POST); + + $set_perms = ''; + + $role = ((x($_POST,'permissions_role')) ? notags(trim($_POST['permissions_role'])) : ''); + $oldrole = get_pconfig(local_channel(),'system','permissions_role'); + + if(($role != $oldrole) || ($role === 'custom')) { + + if($role === 'custom') { + $hide_presence = (((x($_POST,'hide_presence')) && (intval($_POST['hide_presence']) == 1)) ? 1: 0); + $publish = (((x($_POST,'profile_in_directory')) && (intval($_POST['profile_in_directory']) == 1)) ? 1: 0); + $def_group = ((x($_POST,'group-selection')) ? notags(trim($_POST['group-selection'])) : ''); + $r = q("update channel set channel_default_group = '%s' where channel_id = %d", + dbesc($def_group), + intval(local_channel()) + ); + + $global_perms = get_perms(); + + foreach($global_perms as $k => $v) { + $set_perms .= ', ' . $v[0] . ' = ' . intval($_POST[$k]) . ' '; + } + + $str_group_allow = perms2str($_POST['group_allow']); + $str_contact_allow = perms2str($_POST['contact_allow']); + $str_group_deny = perms2str($_POST['group_deny']); + $str_contact_deny = perms2str($_POST['contact_deny']); + $r = q("update channel set channel_allow_cid = '%s', channel_allow_gid = '%s', channel_deny_cid = '%s', channel_deny_gid = '%s' + where channel_id = %d", + dbesc($str_contact_allow), + dbesc($str_group_allow), + dbesc($str_contact_deny), + dbesc($str_group_deny), + intval(local_channel()) + ); + } + else { + $role_permissions = get_role_perms($_POST['permissions_role']); + if(! $role_permissions) { + notice('Permissions category could not be found.'); + return; + } + $hide_presence = 1 - (intval($role_permissions['online'])); + if($role_permissions['default_collection']) { + $r = q("select hash from groups where uid = %d and name = '%s' limit 1", + intval(local_channel()), + dbesc( t('Friends') ) + ); + if(! $r) { + require_once('include/group.php'); + group_add(local_channel(), t('Friends')); + group_add_member(local_channel(),t('Friends'),$channel['channel_hash']); + $r = q("select hash from groups where uid = %d and name = '%s' limit 1", + intval(local_channel()), + dbesc( t('Friends') ) + ); + } + if($r) { + q("update channel set channel_default_group = '%s', channel_allow_gid = '%s', channel_allow_cid = '', channel_deny_gid = '', channel_deny_cid = '' where channel_id = %d", + dbesc($r[0]['hash']), + dbesc('<' . $r[0]['hash'] . '>'), + intval(local_channel()) + ); + } + else { + notice( sprintf('Default privacy collection \'%s\' not found. Please create and re-submit permission change.', t('Friends')) . EOL); + return; + } + } + // no default collection + else { + q("update channel set channel_default_group = '', channel_allow_gid = '', channel_allow_cid = '', channel_deny_gid = '', + channel_deny_cid = '' where channel_id = %d", + intval(local_channel()) + ); + } + + $r = q("update abook set abook_my_perms = %d where abook_channel = %d and abook_self = 1", + intval(($role_permissions['perms_auto']) ? intval($role_permissions['perms_accept']) : 0), + intval(local_channel()) + ); + set_pconfig(local_channel(),'system','autoperms',(($role_permissions['perms_auto']) ? intval($role_permissions['perms_accept']) : 0)); + + foreach($role_permissions as $p => $v) { + if(strpos($p,'channel_') !== false) { + $set_perms .= ', ' . $p . ' = ' . intval($v) . ' '; + } + if($p === 'directory_publish') { + $publish = intval($v); + } + } + } + + set_pconfig(local_channel(),'system','hide_online_status',$hide_presence); + set_pconfig(local_channel(),'system','permissions_role',$role); + } + + $username = ((x($_POST,'username')) ? notags(trim($_POST['username'])) : ''); + $timezone = ((x($_POST,'timezone_select')) ? notags(trim($_POST['timezone_select'])) : ''); + $defloc = ((x($_POST,'defloc')) ? notags(trim($_POST['defloc'])) : ''); + $openid = ((x($_POST,'openid_url')) ? notags(trim($_POST['openid_url'])) : ''); + $maxreq = ((x($_POST,'maxreq')) ? intval($_POST['maxreq']) : 0); + $expire = ((x($_POST,'expire')) ? intval($_POST['expire']) : 0); + $evdays = ((x($_POST,'evdays')) ? intval($_POST['evdays']) : 3); + $photo_path = ((x($_POST,'photo_path')) ? escape_tags(trim($_POST['photo_path'])) : ''); + $attach_path = ((x($_POST,'attach_path')) ? escape_tags(trim($_POST['attach_path'])) : ''); + + $channel_menu = ((x($_POST['channel_menu'])) ? htmlspecialchars_decode(trim($_POST['channel_menu']),ENT_QUOTES) : ''); + + $expire_items = ((x($_POST,'expire_items')) ? intval($_POST['expire_items']) : 0); + $expire_starred = ((x($_POST,'expire_starred')) ? intval($_POST['expire_starred']) : 0); + $expire_photos = ((x($_POST,'expire_photos'))? intval($_POST['expire_photos']) : 0); + $expire_network_only = ((x($_POST,'expire_network_only'))? intval($_POST['expire_network_only']) : 0); + + $allow_location = (((x($_POST,'allow_location')) && (intval($_POST['allow_location']) == 1)) ? 1: 0); + + + $blocktags = (((x($_POST,'blocktags')) && (intval($_POST['blocktags']) == 1)) ? 0: 1); // this setting is inverted! + $unkmail = (((x($_POST,'unkmail')) && (intval($_POST['unkmail']) == 1)) ? 1: 0); + $cntunkmail = ((x($_POST,'cntunkmail')) ? intval($_POST['cntunkmail']) : 0); + $suggestme = ((x($_POST,'suggestme')) ? intval($_POST['suggestme']) : 0); + + $post_newfriend = (($_POST['post_newfriend'] == 1) ? 1: 0); + $post_joingroup = (($_POST['post_joingroup'] == 1) ? 1: 0); + $post_profilechange = (($_POST['post_profilechange'] == 1) ? 1: 0); + $adult = (($_POST['adult'] == 1) ? 1 : 0); + + $channel = $a->get_channel(); + $pageflags = $channel['channel_pageflags']; + $existing_adult = (($pageflags & PAGE_ADULT) ? 1 : 0); + if($adult != $existing_adult) + $pageflags = ($pageflags ^ PAGE_ADULT); + + + $notify = 0; + + if(x($_POST,'notify1')) + $notify += intval($_POST['notify1']); + if(x($_POST,'notify2')) + $notify += intval($_POST['notify2']); + if(x($_POST,'notify3')) + $notify += intval($_POST['notify3']); + if(x($_POST,'notify4')) + $notify += intval($_POST['notify4']); + if(x($_POST,'notify5')) + $notify += intval($_POST['notify5']); + if(x($_POST,'notify6')) + $notify += intval($_POST['notify6']); + if(x($_POST,'notify7')) + $notify += intval($_POST['notify7']); + if(x($_POST,'notify8')) + $notify += intval($_POST['notify8']); + + + $vnotify = 0; + + if(x($_POST,'vnotify1')) + $vnotify += intval($_POST['vnotify1']); + if(x($_POST,'vnotify2')) + $vnotify += intval($_POST['vnotify2']); + if(x($_POST,'vnotify3')) + $vnotify += intval($_POST['vnotify3']); + if(x($_POST,'vnotify4')) + $vnotify += intval($_POST['vnotify4']); + if(x($_POST,'vnotify5')) + $vnotify += intval($_POST['vnotify5']); + if(x($_POST,'vnotify6')) + $vnotify += intval($_POST['vnotify6']); + if(x($_POST,'vnotify7')) + $vnotify += intval($_POST['vnotify7']); + if(x($_POST,'vnotify8')) + $vnotify += intval($_POST['vnotify8']); + if(x($_POST,'vnotify9')) + $vnotify += intval($_POST['vnotify9']); + if(x($_POST,'vnotify10')) + $vnotify += intval($_POST['vnotify10']); + if(x($_POST,'vnotify11')) + $vnotify += intval($_POST['vnotify11']); + + $always_show_in_notices = x($_POST,'always_show_in_notices') ? 1 : 0; + + $channel = $a->get_channel(); + + $err = ''; + + $name_change = false; + + if($username != $channel['channel_name']) { + $name_change = true; + require_once('include/identity.php'); + $err = validate_channelname($username); + if($err) { + notice($err); + return; + } + } + + if($timezone != $channel['channel_timezone']) { + if(strlen($timezone)) + date_default_timezone_set($timezone); + } + + set_pconfig(local_channel(),'system','use_browser_location',$allow_location); + set_pconfig(local_channel(),'system','suggestme', $suggestme); + set_pconfig(local_channel(),'system','post_newfriend', $post_newfriend); + set_pconfig(local_channel(),'system','post_joingroup', $post_joingroup); + set_pconfig(local_channel(),'system','post_profilechange', $post_profilechange); + set_pconfig(local_channel(),'system','blocktags',$blocktags); + set_pconfig(local_channel(),'system','channel_menu',$channel_menu); + set_pconfig(local_channel(),'system','vnotify',$vnotify); + set_pconfig(local_channel(),'system','always_show_in_notices',$always_show_in_notices); + set_pconfig(local_channel(),'system','evdays',$evdays); + set_pconfig(local_channel(),'system','photo_path',$photo_path); + set_pconfig(local_channel(),'system','attach_path',$attach_path); + + $r = q("update channel set channel_name = '%s', channel_pageflags = %d, channel_timezone = '%s', channel_location = '%s', channel_notifyflags = %d, channel_max_anon_mail = %d, channel_max_friend_req = %d, channel_expire_days = %d $set_perms where channel_id = %d", + dbesc($username), + intval($pageflags), + dbesc($timezone), + dbesc($defloc), + intval($notify), + intval($unkmail), + intval($maxreq), + intval($expire), + intval(local_channel()) + ); + if($r) + info( t('Settings updated.') . EOL); + + if(! is_null($publish)) { + $r = q("UPDATE profile SET publish = %d WHERE is_default = 1 AND uid = %d", + intval($publish), + intval(local_channel()) + ); + } + + if($name_change) { + $r = q("update xchan set xchan_name = '%s', xchan_name_date = '%s' where xchan_hash = '%s'", + dbesc($username), + dbesc(datetime_convert()), + dbesc($channel['channel_hash']) + ); + $r = q("update profile set name = '%s' where uid = %d and is_default = 1", + dbesc($username), + intval($channel['channel_id']) + ); + } + + proc_run('php','include/directory.php',local_channel()); + + build_sync_packet(); + + + //$_SESSION['theme'] = $theme; + if($email_changed && $a->config['system']['register_policy'] == REGISTER_VERIFY) { + + // FIXME - set to un-verified, blocked and redirect to logout + // Why? Are we verifying people or email addresses? + + } + + goaway($a->get_baseurl(true) . '/settings' ); + return; // NOTREACHED +} + + + +function settings_content(&$a) { + + $o = ''; + nav_set_selected('settings'); + + + if((! local_channel()) || ($_SESSION['delegate'])) { + notice( t('Permission denied.') . EOL ); + return login(); + } + + + $channel = $a->get_channel(); + if($channel) + head_set_icon($channel['xchan_photo_s']); + + $yes_no = array(t('No'),t('Yes')); + + if((argc() > 1) && (argv(1) === 'oauth')) { + + if((argc() > 2) && (argv(2) === 'add')) { + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Submit'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), '', t('Name of application')), + '$key' => array('key', t('Consumer Key'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$secret' => array('secret', t('Consumer Secret'), random_string(16), t('Automatically generated - change if desired. Max length 20')), + '$redirect' => array('redirect', t('Redirect'), '', t('Redirect URI - leave blank unless your application specifically requires this')), + '$icon' => array('icon', t('Icon url'), '', t('Optional')), + )); + return $o; + } + + if((argc() > 3) && (argv(2) === 'edit')) { + $r = q("SELECT * FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + + if (!count($r)){ + notice(t("You can't edit this application.")); + return; + } + $app = $r[0]; + + $tpl = get_markup_template("settings_oauth_edit.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$title' => t('Add application'), + '$submit' => t('Update'), + '$cancel' => t('Cancel'), + '$name' => array('name', t('Name'), $app['name'] , ''), + '$key' => array('key', t('Consumer Key'), $app['client_id'], ''), + '$secret' => array('secret', t('Consumer Secret'), $app['pw'], ''), + '$redirect' => array('redirect', t('Redirect'), $app['redirect_uri'], ''), + '$icon' => array('icon', t('Icon url'), $app['icon'], ''), + )); + return $o; + } + + if((argc() > 3) && (argv(2) === 'delete')) { + check_form_security_token_redirectOnErr('/settings/oauth', 'settings_oauth', 't'); + + $r = q("DELETE FROM clients WHERE client_id='%s' AND uid=%d", + dbesc(argv(3)), + local_channel()); + goaway($a->get_baseurl(true)."/settings/oauth/"); + return; + } + + + $r = q("SELECT clients.*, tokens.id as oauth_token, (clients.uid=%d) AS my + FROM clients + LEFT JOIN tokens ON clients.client_id=tokens.client_id + WHERE clients.uid IN (%d,0)", + local_channel(), + local_channel()); + + + $tpl = get_markup_template("settings_oauth.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_oauth"), + '$baseurl' => $a->get_baseurl(true), + '$title' => t('Connected Apps'), + '$add' => t('Add application'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$consumerkey' => t('Client key starts with'), + '$noname' => t('No name'), + '$remove' => t('Remove authorization'), + '$apps' => $r, + )); + return $o; + + } + if((argc() > 1) && (argv(1) === 'featured')) { + $settings_addons = ""; + + $o = ''; + + $r = q("SELECT * FROM `hook` WHERE `hook` = 'feature_settings' "); + if(! $r) + $settings_addons = t('No feature settings configured'); + + call_hooks('feature_settings', $settings_addons); + + $tpl = get_markup_template("settings_addons.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_featured"), + '$title' => t('Feature/Addon Settings'), + '$settings_addons' => $settings_addons + )); + return $o; + } + + + /* + * ACCOUNT SETTINGS + */ + + + if((argc() > 1) && (argv(1) === 'account')) { + $account_settings = ""; + + call_hooks('account_settings', $account_settings); + + $email = $a->account['account_email']; + + + $tpl = get_markup_template("settings_account.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_account"), + '$title' => t('Account Settings'), + '$password1'=> array('npassword', t('Enter New Password:'), '', ''), + '$password2'=> array('confirm', t('Confirm New Password:'), '', t('Leave password fields blank unless changing')), + '$submit' => t('Submit'), + '$email' => array('email', t('Email Address:'), $email, ''), + '$removeme' => t('Remove Account'), + '$removeaccount' => t('Remove this account including all its channels'), + '$account_settings' => $account_settings + )); + return $o; + } + + + + if((argc() > 1) && (argv(1) === 'features')) { + $arr = array(); + $features = get_features(); + + foreach($features as $fname => $fdata) { + $arr[$fname] = array(); + $arr[$fname][0] = $fdata[0]; + foreach(array_slice($fdata,1) as $f) { + $arr[$fname][1][] = array('feature_' .$f[0],$f[1],((intval(feature_enabled(local_channel(),$f[0]))) ? "1" : ''),$f[2],array(t('Off'),t('On'))); + } + } + + $tpl = get_markup_template("settings_features.tpl"); + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_features"), + '$title' => t('Additional Features'), + '$features' => $arr, + '$submit' => t('Submit'), + )); + + return $o; + } + + + + + + if((argc() > 1) && (argv(1) === 'connectors')) { + + $settings_connectors = ""; + + call_hooks('connector_settings', $settings_connectors); + + $r = null; + + $tpl = get_markup_template("settings_connectors.tpl"); + + $o .= replace_macros($tpl, array( + '$form_security_token' => get_form_security_token("settings_connectors"), + '$title' => t('Connector Settings'), + '$submit' => t('Submit'), + '$settings_connectors' => $settings_connectors + )); + + call_hooks('display_settings', $o); + return $o; + } + + /* + * DISPLAY SETTINGS + */ + + if((argc() > 1) && (argv(1) === 'display')) { + $default_theme = get_config('system','theme'); + if(! $default_theme) + $default_theme = 'default'; + $default_mobile_theme = get_config('system','mobile_theme'); + if(! $mobile_default_theme) + $mobile_default_theme = 'none'; + + $allowed_themes_str = get_config('system','allowed_themes'); + $allowed_themes_raw = explode(',',$allowed_themes_str); + $allowed_themes = array(); + if(count($allowed_themes_raw)) + foreach($allowed_themes_raw as $x) + if(strlen(trim($x)) && is_dir("view/theme/$x")) + $allowed_themes[] = trim($x); + + + $themes = array(); + $files = glob('view/theme/*'); + if($allowed_themes) { + foreach($allowed_themes as $th) { + $f = $th; + $is_experimental = file_exists('view/theme/' . $th . '/experimental'); + $unsupported = file_exists('view/theme/' . $th . '/unsupported'); + $is_mobile = file_exists('view/theme/' . $th . '/mobile'); + $is_library = file_exists('view/theme/'. $th . '/library'); + $mobile_themes["---"] = t("No special theme for mobile devices"); + + if (!$is_experimental or ($is_experimental && (get_config('experimentals','exp_themes')==1 or get_config('experimentals','exp_themes')===false))){ + $theme_name = (($is_experimental) ? sprintf(t('%s - (Experimental)'), $f) : $f); + if (! $is_library) { + if($is_mobile) { + $mobile_themes[$f] = $themes[$f] = $theme_name . ' (' . t('mobile') . ')'; + } + else { + $mobile_themes[$f] = $themes[$f] = $theme_name; + } + } + } + + } + } + $theme_selected = (!x($_SESSION,'theme')? $default_theme : $_SESSION['theme']); + $mobile_theme_selected = (!x($_SESSION,'mobile_theme')? $default_mobile_theme : $_SESSION['mobile_theme']); + + $user_scalable = get_pconfig(local_channel(),'system','user_scalable'); + $user_scalable = (($user_scalable===false)? '1': $user_scalable); // default if not set: 1 + + $browser_update = intval(get_pconfig(local_channel(), 'system','update_interval')); + $browser_update = (($browser_update == 0) ? 80 : $browser_update / 1000); // default if not set: 40 seconds + + $itemspage = intval(get_pconfig(local_channel(), 'system','itemspage')); + $itemspage = (($itemspage > 0 && $itemspage < 101) ? $itemspage : 20); // default if not set: 20 items + + $nosmile = get_pconfig(local_channel(),'system','no_smilies'); + $nosmile = (($nosmile===false)? '0': $nosmile); // default if not set: 0 + + $title_tosource = get_pconfig(local_channel(),'system','title_tosource'); + $title_tosource = (($title_tosource===false)? '0': $title_tosource); // default if not set: 0 + + $theme_config = ""; + if( ($themeconfigfile = get_theme_config_file($theme_selected)) != null){ + require_once($themeconfigfile); + $theme_config = theme_content($a); + } + + $tpl = get_markup_template("settings_display.tpl"); + $o = replace_macros($tpl, array( + '$ptitle' => t('Display Settings'), + '$d_tset' => t('Theme Settings'), + '$d_ctset' => t('Custom Theme Settings'), + '$d_cset' => t('Content Settings'), + '$form_security_token' => get_form_security_token("settings_display"), + '$submit' => t('Submit'), + '$baseurl' => $a->get_baseurl(true), + '$uid' => local_channel(), + + '$theme' => (($themes) ? array('theme', t('Display Theme:'), $theme_selected, '', $themes, 'preview') : false), + '$mobile_theme' => (($mobile_themes) ? array('mobile_theme', t('Mobile Theme:'), $mobile_theme_selected, '', $mobile_themes, '') : false), + '$user_scalable' => array('user_scalable', t("Enable user zoom on mobile devices"), $user_scalable, '', $yes_no), + '$ajaxint' => array('browser_update', t("Update browser every xx seconds"), $browser_update, t('Minimum of 10 seconds, no maximum')), + '$itemspage' => array('itemspage', t("Maximum number of conversations to load at any time:"), $itemspage, t('Maximum of 100 items')), + '$nosmile' => array('nosmile', t("Show emoticons (smilies) as images"), 1-intval($nosmile), '', $yes_no), + '$title_tosource' => array('title_tosource', t("Link post titles to source"), $title_tosource, '', $yes_no), + '$layout_editor' => t('System Page Layout Editor - (advanced)'), + '$theme_config' => $theme_config, + '$expert' => feature_enabled(local_channel(),'expert'), + '$channel_list_mode' => array('channel_list_mode', t('Use blog/list mode on channel page'), get_pconfig(local_channel(),'system','channel_list_mode'), t('(comments displayed separately)'), $yes_no), + '$network_list_mode' => array('network_list_mode', t('Use blog/list mode on matrix page'), get_pconfig(local_channel(),'system','network_list_mode'), t('(comments displayed separately)'), $yes_no), + '$channel_divmore_height' => array('channel_divmore_height', t('Channel page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','channel_divmore_height')) ? get_pconfig(local_channel(),'system','channel_divmore_height') : 400), t('click to expand content exceeding this height')), + '$network_divmore_height' => array('network_divmore_height', t('Matrix page max height of content (in pixels)'), ((get_pconfig(local_channel(),'system','network_divmore_height')) ? get_pconfig(local_channel(),'system','network_divmore_height') : 400) , t('click to expand content exceeding this height')), + + + )); + + return $o; + } + + + + + + if(argv(1) === 'channel') { + + require_once('include/acl_selectors.php'); + require_once('include/permissions.php'); + + + $p = q("SELECT * FROM `profile` WHERE `is_default` = 1 AND `uid` = %d LIMIT 1", + intval(local_channel()) + ); + if(count($p)) + $profile = $p[0]; + + load_pconfig(local_channel(),'expire'); + + $channel = $a->get_channel(); + + + $global_perms = get_perms(); + + $permiss = array(); + + $perm_opts = array( + array( t('Nobody except yourself'), 0), + array( t('Only those you specifically allow'), PERMS_SPECIFIC), + array( t('Approved connections'), PERMS_CONTACTS), + array( t('Any connections'), PERMS_PENDING), + array( t('Anybody on this website'), PERMS_SITE), + array( t('Anybody in this network'), PERMS_NETWORK), + array( t('Anybody authenticated'), PERMS_AUTHED), + array( t('Anybody on the internet'), PERMS_PUBLIC) + ); + + + foreach($global_perms as $k => $perm) { + $options = array(); + foreach($perm_opts as $opt) { + if((! $perm[2]) && $opt[1] == PERMS_PUBLIC) + continue; + $options[$opt[1]] = $opt[0]; + } + $permiss[] = array($k,$perm[3],$channel[$perm[0]],$perm[4],$options); + } + + +// logger('permiss: ' . print_r($permiss,true)); + + + + $username = $channel['channel_name']; + $nickname = $channel['channel_address']; + $timezone = $channel['channel_timezone']; + $notify = $channel['channel_notifyflags']; + $defloc = $channel['channel_location']; + + $maxreq = $channel['channel_max_friend_req']; + $expire = $channel['channel_expire_days']; + $adult_flag = intval($channel['channel_pageflags'] & PAGE_ADULT); + +// $unkmail = $a->user['unkmail']; +// $cntunkmail = $a->user['cntunkmail']; + + $hide_presence = intval(get_pconfig(local_channel(), 'system','hide_online_status')); + + + $expire_items = get_pconfig(local_channel(), 'expire','items'); + $expire_items = (($expire_items===false)? '1' : $expire_items); // default if not set: 1 + + $expire_notes = get_pconfig(local_channel(), 'expire','notes'); + $expire_notes = (($expire_notes===false)? '1' : $expire_notes); // default if not set: 1 + + $expire_starred = get_pconfig(local_channel(), 'expire','starred'); + $expire_starred = (($expire_starred===false)? '1' : $expire_starred); // default if not set: 1 + + $expire_photos = get_pconfig(local_channel(), 'expire','photos'); + $expire_photos = (($expire_photos===false)? '0' : $expire_photos); // default if not set: 0 + + $expire_network_only = get_pconfig(local_channel(), 'expire','network_only'); + $expire_network_only = (($expire_network_only===false)? '0' : $expire_network_only); // default if not set: 0 + + + $suggestme = get_pconfig(local_channel(), 'system','suggestme'); + $suggestme = (($suggestme===false)? '0': $suggestme); // default if not set: 0 + + $post_newfriend = get_pconfig(local_channel(), 'system','post_newfriend'); + $post_newfriend = (($post_newfriend===false)? '0': $post_newfriend); // default if not set: 0 + + $post_joingroup = get_pconfig(local_channel(), 'system','post_joingroup'); + $post_joingroup = (($post_joingroup===false)? '0': $post_joingroup); // default if not set: 0 + + $post_profilechange = get_pconfig(local_channel(), 'system','post_profilechange'); + $post_profilechange = (($post_profilechange===false)? '0': $post_profilechange); // default if not set: 0 + + $blocktags = get_pconfig(local_channel(),'system','blocktags'); + $blocktags = (($blocktags===false) ? '0' : $blocktags); + + $timezone = date_default_timezone_get(); + + $opt_tpl = get_markup_template("field_checkbox.tpl"); + if(get_config('system','publish_all')) { + $profile_in_dir = ''; + } + else { + $profile_in_dir = replace_macros($opt_tpl,array( + '$field' => array('profile_in_directory', t('Publish your default profile in the network directory'), $profile['publish'], '', $yes_no), + )); + } + + $suggestme = replace_macros($opt_tpl,array( + '$field' => array('suggestme', t('Allow us to suggest you as a potential friend to new members?'), $suggestme, '', $yes_no), + + )); + + $subdir = ((strlen($a->get_path())) ? '
    ' . t('or') . ' ' . $a->get_baseurl(true) . '/channel/' . $nickname : ''); + + $tpl_addr = get_markup_template("settings_nick_set.tpl"); + + $prof_addr = replace_macros($tpl_addr,array( + '$desc' => t('Your channel address is'), + '$nickname' => $nickname, + '$subdir' => $subdir, + '$basepath' => $a->get_hostname() + )); + + $stpl = get_markup_template('settings.tpl'); + + $celeb = false; + + $perm_defaults = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + + require_once('include/group.php'); + $group_select = mini_group_select(local_channel(),$channel['channel_default_group']); + + require_once('include/menu.php'); + $m1 = menu_list(local_channel()); + $menu = false; + if($m1) { + $menu = array(); + $current = get_pconfig(local_channel(),'system','channel_menu'); + $menu[] = array('name' => '', 'selected' => ((! $current) ? true : false)); + foreach($m1 as $m) { + $menu[] = array('name' => htmlspecialchars($m['menu_name'],ENT_COMPAT,'UTF-8'), 'selected' => (($m['menu_name'] === $current) ? ' selected="selected" ' : false)); + } + } + + $evdays = get_pconfig(local_channel(),'system','evdays'); + if(! $evdays) + $evdays = 3; + + $permissions_role = get_pconfig(local_channel(),'system','permissions_role'); + if(! $permissions_role) + $permissions_role = 'custom'; + + $permissions_set = (($permissions_role != 'custom') ? true : false); + $vnotify = get_pconfig(local_channel(),'system','vnotify'); + $always_show_in_notices = get_pconfig(local_channel(),'system','always_show_in_notices'); + if($vnotify === false) + $vnotify = (-1); + + $o .= replace_macros($stpl,array( + '$ptitle' => t('Channel Settings'), + + '$submit' => t('Submit'), + '$baseurl' => $a->get_baseurl(true), + '$uid' => local_channel(), + '$form_security_token' => get_form_security_token("settings"), + '$nickname_block' => $prof_addr, + '$h_basic' => t('Basic Settings'), + '$username' => array('username', t('Full Name:'), $username,''), + '$email' => array('email', t('Email Address:'), $email, ''), + '$timezone' => array('timezone_select' , t('Your Timezone:'), $timezone, '', get_timezones()), + '$defloc' => array('defloc', t('Default Post Location:'), $defloc, t('Geographical location to display on your posts')), + '$allowloc' => array('allow_location', t('Use Browser Location:'), ((get_pconfig(local_channel(),'system','use_browser_location')) ? 1 : ''), '', $yes_no), + + '$adult' => array('adult', t('Adult Content'), $adult_flag, t('This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)'), $yes_no), + + '$h_prv' => t('Security and Privacy Settings'), + '$permissions_set' => $permissions_set, + '$perms_set_msg' => t('Your permissions are already configured. Click to view/adjust'), + + '$hide_presence' => array('hide_presence', t('Hide my online presence'),$hide_presence, t('Prevents displaying in your profile that you are online'), $yes_no), + + '$lbl_pmacro' => t('Simple Privacy Settings:'), + '$pmacro3' => t('Very Public - extremely permissive (should be used with caution)'), + '$pmacro2' => t('Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)'), + '$pmacro1' => t('Private - default private, never open or public'), + '$pmacro0' => t('Blocked - default blocked to/from everybody'), + '$permiss_arr' => $permiss, + '$blocktags' => array('blocktags',t('Allow others to tag your posts'), 1-$blocktags, t('Often used by the community to retro-actively flag inappropriate content'), $yes_no), + + '$lbl_p2macro' => t('Advanced Privacy Settings'), + + '$expire' => array('expire',t('Expire other channel content after this many days'),$expire,t('0 or blank prevents expiration')), + '$maxreq' => array('maxreq', t('Maximum Friend Requests/Day:'), intval($channel['channel_max_friend_req']) , t('May reduce spam activity')), + '$permissions' => t('Default Post Permissions'), + '$permdesc' => t("\x28click to open/close\x29"), + '$aclselect' => populate_acl($perm_defaults,false), + '$suggestme' => $suggestme, + '$group_select' => $group_select, + '$role' => array('permissions_role' , t('Channel permissions category:'), $permissions_role, '', get_roles()), + + '$profile_in_dir' => $profile_in_dir, + '$hide_friends' => $hide_friends, + '$hide_wall' => $hide_wall, + '$unkmail' => $unkmail, + '$cntunkmail' => array('cntunkmail', t('Maximum private messages per day from unknown people:'), intval($channel['channel_max_anon_mail']) ,t("Useful to reduce spamming")), + + + '$h_not' => t('Notification Settings'), + '$activity_options' => t('By default post a status message when:'), + '$post_newfriend' => array('post_newfriend', t('accepting a friend request'), $post_newfriend, '', $yes_no), + '$post_joingroup' => array('post_joingroup', t('joining a forum/community'), $post_joingroup, '', $yes_no), + '$post_profilechange' => array('post_profilechange', t('making an interesting profile change'), $post_profilechange, '', $yes_no), + '$lbl_not' => t('Send a notification email when:'), + '$notify1' => array('notify1', t('You receive a connection request'), ($notify & NOTIFY_INTRO), NOTIFY_INTRO, '', $yes_no), + '$notify2' => array('notify2', t('Your connections are confirmed'), ($notify & NOTIFY_CONFIRM), NOTIFY_CONFIRM, '', $yes_no), + '$notify3' => array('notify3', t('Someone writes on your profile wall'), ($notify & NOTIFY_WALL), NOTIFY_WALL, '', $yes_no), + '$notify4' => array('notify4', t('Someone writes a followup comment'), ($notify & NOTIFY_COMMENT), NOTIFY_COMMENT, '', $yes_no), + '$notify5' => array('notify5', t('You receive a private message'), ($notify & NOTIFY_MAIL), NOTIFY_MAIL, '', $yes_no), + '$notify6' => array('notify6', t('You receive a friend suggestion'), ($notify & NOTIFY_SUGGEST), NOTIFY_SUGGEST, '', $yes_no), + '$notify7' => array('notify7', t('You are tagged in a post'), ($notify & NOTIFY_TAGSELF), NOTIFY_TAGSELF, '', $yes_no), + '$notify8' => array('notify8', t('You are poked/prodded/etc. in a post'), ($notify & NOTIFY_POKE), NOTIFY_POKE, '', $yes_no), + + + '$lbl_vnot' => t('Show visual notifications including:'), + + '$vnotify1' => array('vnotify1', t('Unseen matrix activity'), ($vnotify & VNOTIFY_NETWORK), VNOTIFY_NETWORK, '', $yes_no), + '$vnotify2' => array('vnotify2', t('Unseen channel activity'), ($vnotify & VNOTIFY_CHANNEL), VNOTIFY_CHANNEL, '', $yes_no), + '$vnotify3' => array('vnotify3', t('Unseen private messages'), ($vnotify & VNOTIFY_MAIL), VNOTIFY_MAIL, t('Recommended'), $yes_no), + '$vnotify4' => array('vnotify4', t('Upcoming events'), ($vnotify & VNOTIFY_EVENT), VNOTIFY_EVENT, '', $yes_no), + '$vnotify5' => array('vnotify5', t('Events today'), ($vnotify & VNOTIFY_EVENTTODAY), VNOTIFY_EVENTTODAY, '', $yes_no), + '$vnotify6' => array('vnotify6', t('Upcoming birthdays'), ($vnotify & VNOTIFY_BIRTHDAY), VNOTIFY_BIRTHDAY, t('Not available in all themes'), $yes_no), + '$vnotify7' => array('vnotify7', t('System (personal) notifications'), ($vnotify & VNOTIFY_SYSTEM), VNOTIFY_SYSTEM, '', $yes_no), + '$vnotify8' => array('vnotify8', t('System info messages'), ($vnotify & VNOTIFY_INFO), VNOTIFY_INFO, t('Recommended'), $yes_no), + '$vnotify9' => array('vnotify9', t('System critical alerts'), ($vnotify & VNOTIFY_ALERT), VNOTIFY_ALERT, t('Recommended'), $yes_no), + '$vnotify10' => array('vnotify10', t('New connections'), ($vnotify & VNOTIFY_INTRO), VNOTIFY_INTRO, t('Recommended'), $yes_no), + '$vnotify11' => array('vnotify11', t('System Registrations'), ($vnotify & VNOTIFY_REGISTER), VNOTIFY_REGISTER, '', $yes_no), + '$always_show_in_notices' => array('always_show_in_notices', t('Also show new wall posts, private messages and connections under Notices'), $always_show_in_notices, 1, '', $yes_no), + + '$evdays' => array('evdays', t('Notify me of events this many days in advance'), $evdays, t('Must be greater than 0')), + + '$h_advn' => t('Advanced Account/Page Type Settings'), + '$h_descadvn' => t('Change the behaviour of this account for special situations'), + '$pagetype' => $pagetype, + '$expert' => feature_enabled(local_channel(),'expert'), + '$hint' => t('Please enable expert mode (in Settings > Additional features) to adjust!'), + '$lbl_misc' => t('Miscellaneous Settings'), + '$photo_path' => array('photo_path', t('Default photo upload folder'), get_pconfig(local_channel(),'system','photo_path'), '%Y - current year, %m - current month'), + '$attach_path' => array('attach_path', t('Default file upload folder'), get_pconfig(local_channel(),'system','attach_path'), '%Y - current year, %m - current month'), + '$menus' => $menu, + '$menu_desc' => t('Personal menu to display in your channel pages'), + '$removeme' => t('Remove Channel'), + '$removechannel' => t('Remove this channel.'), + )); + + call_hooks('settings_form',$o); + + $o .= '' . "\r\n"; + + return $o; + } +} + diff --git a/sources/mod/setup.php b/sources/mod/setup.php new file mode 100755 index 00000000..15820f14 --- /dev/null +++ b/sources/mod/setup.php @@ -0,0 +1,738 @@ +get_path(); + $dbhost = trim($_POST['dbhost']); + $dbport = intval(trim($_POST['dbport'])); + $dbuser = trim($_POST['dbuser']); + $dbpass = trim($_POST['dbpass']); + $dbdata = trim($_POST['dbdata']); + $dbtype = intval(trim($_POST['dbtype'])); + $phpath = trim($_POST['phpath']); + $adminmail = trim($_POST['adminmail']); + $siteurl = trim($_POST['siteurl']); + + // $siteurl should not have a trailing slash + + $siteurl = rtrim($siteurl,'/'); + + require_once('include/dba/dba_driver.php'); + unset($db); + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); + + if(! $db->connected) { + echo 'Database Connect failed: ' . $db->error; + killme(); + $a->data['db_conn_failed']=true; + } + /*if(get_db_errno()) { + unset($db); + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, '', true); + + if(! get_db_errno()) { + $r = q("CREATE DATABASE '%s'", + dbesc($dbdata) + ); + if($r) { + unset($db); + $db = new dba($dbhost, $dbport, $dbuser, $dbpass, $dbdata, true); + } else { + $a->data['db_create_failed']=true; + } + } else { + $a->data['db_conn_failed']=true; + return; + } + }*/ + //if(get_db_errno()) { + + //} + + return; + break; + case 4: + $urlpath = $a->get_path(); + $dbhost = notags(trim($_POST['dbhost'])); + $dbport = intval(notags(trim($_POST['dbport']))); + $dbuser = notags(trim($_POST['dbuser'])); + $dbpass = notags(trim($_POST['dbpass'])); + $dbdata = notags(trim($_POST['dbdata'])); + $dbtype = intval(notags(trim($_POST['dbtype']))); + $phpath = notags(trim($_POST['phpath'])); + $timezone = notags(trim($_POST['timezone'])); + $adminmail = notags(trim($_POST['adminmail'])); + $siteurl = notags(trim($_POST['siteurl'])); + + if($siteurl != z_root()) { + $test = z_fetch_url($siteurl."/setup/testrewrite"); + if((! $test['success']) || ($test['body'] != 'ok')) { + $a->data['url_fail'] = true; + $a->data['url_error'] = $test['error']; + return; + } + } + + // connect to db + $db = dba_factory($dbhost, $dbport, $dbuser, $dbpass, $dbdata, $dbtype, true); + + if(! $db->connected) { + echo 'CRITICAL: DB not connected.'; + killme(); + } + + $tpl = get_intltext_template('htconfig.tpl'); + $txt = replace_macros($tpl,array( + '$dbhost' => $dbhost, + '$dbport' => $dbport, + '$dbuser' => $dbuser, + '$dbpass' => $dbpass, + '$dbdata' => $dbdata, + '$dbtype' => $dbtype, + '$timezone' => $timezone, + '$siteurl' => $siteurl, + '$site_id' => random_string(), + '$phpath' => $phpath, + '$adminmail' => $adminmail + )); + + $result = file_put_contents('.htconfig.php', $txt); + if(! $result) { + $a->data['txt'] = $txt; + } + + $errors = load_database($db); + + if($errors) + $a->data['db_failed'] = $errors; + else + $a->data['db_installed'] = true; + + return; + break; + } +} + +function get_db_errno() { + if(class_exists('mysqli')) + return mysqli_connect_errno(); + else + return mysql_errno(); +} + +/** + * @brief Get output for the setup page. + * + * Depending on the state we are currently in it returns different content. + * + * @param App &$a + * @return string parsed HTML output + */ +function setup_content(&$a) { + global $install_wizard_pass, $db; + + $o = ''; + $wizard_status = ''; + $install_title = t('$Projectname Server - Setup'); + + if(x($a->data, 'db_conn_failed')) { + $install_wizard_pass = 2; + $wizard_status = t('Could not connect to database.'); + } + if(x($a->data, 'url_fail')) { + $install_wizard_pass = 3; + $wizard_status = t('Could not connect to specified site URL. Possible SSL certificate or DNS issue.'); + if($a->data['url_error']) + $wizard_status .= ' ' . $a->data['url_error']; + } + + if(x($a->data, 'db_create_failed')) { + $install_wizard_pass = 2; + $wizard_status = t('Could not create table.'); + } + $db_return_text = ''; + if(x($a->data, 'db_installed')) { + $txt = '

    '; + $txt .= t('Your site database has been installed.') . EOL; + $db_return_text .= $txt; + } + if(x($a->data, 'db_failed')) { + $txt = t('You may need to import the file "install/schema_xxx.sql" manually using a database client.') . EOL; + $txt .= t('Please see the file "install/INSTALL.txt".') . EOL ."


    " ; + $txt .= "
    ".$a->data['db_failed'] . "
    ". EOL ; + $db_return_text .= $txt; + } + if($db && $db->connected) { + $r = q("SELECT COUNT(*) as `total` FROM `account`"); + if($r && count($r) && $r[0]['total']) { + $tpl = get_markup_template('install.tpl'); + return replace_macros($tpl, array( + '$title' => $install_title, + '$pass' => '', + '$status' => t('Permission denied.'), + '$text' => '', + )); + } + } + + if(x($a->data, 'txt') && strlen($a->data['txt'])) { + $db_return_text .= manual_config($a); + } + + if ($db_return_text != "") { + $tpl = get_markup_template('install.tpl'); + return replace_macros($tpl, array( + '$title' => $install_title, + '$pass' => '', + '$text' => $db_return_text . what_next(), + )); + } + + switch ($install_wizard_pass){ + case 1: { // System check + + $checks = array(); + + check_funcs($checks); + + check_htconfig($checks); + + check_store($checks); + + check_smarty3($checks); + + check_keys($checks); + + if (x($_POST, 'phpath')) + $phpath = notags(trim($_POST['phpath'])); + + check_php($phpath, $checks); + + check_phpconfig($checks); + + check_htaccess($checks); + + function check_passed($v, $c) { + if ($c['required']) + $v = $v && $c['status']; + + return $v; + } + $checkspassed = array_reduce($checks, "check_passed", true); + + $tpl = get_markup_template('install_checks.tpl'); + $o .= replace_macros($tpl, array( + '$title' => $install_title, + '$pass' => t('System check'), + '$checks' => $checks, + '$passed' => $checkspassed, + '$see_install' => t('Please see the file "install/INSTALL.txt".'), + '$next' => t('Next'), + '$reload' => t('Check again'), + '$phpath' => $phpath, + '$baseurl' => $a->get_baseurl(), + )); + return $o; + }; break; + + case 2: { // Database config + + $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : 'localhost'); + $dbuser = notags(trim($_POST['dbuser'])); + $dbport = intval(notags(trim($_POST['dbport']))); + $dbpass = notags(trim($_POST['dbpass'])); + $dbdata = notags(trim($_POST['dbdata'])); + $dbtype = intval(notags(trim($_POST['dbtype']))); + $phpath = notags(trim($_POST['phpath'])); + $adminmail = notags(trim($_POST['adminmail'])); + $siteurl = notags(trim($_POST['siteurl'])); + + $tpl = get_markup_template('install_db.tpl'); + $o .= replace_macros($tpl, array( + '$title' => $install_title, + '$pass' => t('Database connection'), + '$info_01' => t('In order to install $Projectname we need to know how to connect to your database.'), + '$info_02' => t('Please contact your hosting provider or site administrator if you have questions about these settings.'), + '$info_03' => t('The database you specify below should already exist. If it does not, please create it before continuing.'), + + '$status' => $wizard_status, + + '$dbhost' => array('dbhost', t('Database Server Name'), $dbhost, t('Default is localhost')), + '$dbport' => array('dbport', t('Database Port'), $dbport, t('Communication port number - use 0 for default')), + '$dbuser' => array('dbuser', t('Database Login Name'), $dbuser, ''), + '$dbpass' => array('dbpass', t('Database Login Password'), $dbpass, ''), + '$dbdata' => array('dbdata', t('Database Name'), $dbdata, ''), + '$dbtype' => array('dbtype', t('Database Type'), $dbtype, '', array( 0=>'MySQL', 1=>'PostgreSQL' )), + + '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.')), + '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')), + + '$lbl_10' => t('Please select a default timezone for your website'), + + '$baseurl' => $a->get_baseurl(), + + '$phpath' => $phpath, + + '$submit' => t('Submit'), + )); + return $o; + }; break; + case 3: { // Site settings + require_once('include/datetime.php'); + $dbhost = ((x($_POST,'dbhost')) ? notags(trim($_POST['dbhost'])) : 'localhost'); + $dbport = intval(notags(trim($_POST['dbuser']))); + $dbuser = notags(trim($_POST['dbuser'])); + $dbpass = notags(trim($_POST['dbpass'])); + $dbdata = notags(trim($_POST['dbdata'])); + $dbtype = intval(notags(trim($_POST['dbtype']))); + $phpath = notags(trim($_POST['phpath'])); + + $adminmail = notags(trim($_POST['adminmail'])); + $siteurl = notags(trim($_POST['siteurl'])); + $timezone = ((x($_POST,'timezone')) ? ($_POST['timezone']) : 'America/Los_Angeles'); + + $tpl = get_markup_template('install_settings.tpl'); + $o .= replace_macros($tpl, array( + '$title' => $install_title, + '$pass' => t('Site settings'), + '$status' => $wizard_status, + + '$dbhost' => $dbhost, + '$dbport' => $dbport, + '$dbuser' => $dbuser, + '$dbpass' => $dbpass, + '$dbdata' => $dbdata, + '$phpath' => $phpath, + '$dbtype' => $dbtype, + + '$adminmail' => array('adminmail', t('Site administrator email address'), $adminmail, t('Your account email address must match this in order to use the web admin panel.')), + + '$siteurl' => array('siteurl', t('Website URL'), z_root(), t('Please use SSL (https) URL if available.')), + + '$timezone' => array('timezone', t('Please select a default timezone for your website'), $timezone, '', get_timezones()), + + '$baseurl' => $a->get_baseurl(), + + '$submit' => t('Submit'), + )); + return $o; + }; break; + } +} + +/** + * @brief Add a check result to the array for output. + * + * @param[in,out] array &$checks array passed to template + * @param string $title a title for the check + * @param boolean $status + * @param boolean $required + * @param[optional] string $help optional help string + */ +function check_add(&$checks, $title, $status, $required, $help = '') { + $checks[] = array( + 'title' => $title, + 'status' => $status, + 'required' => $required, + 'help' => $help + ); +} + +/** + * @brief Checks the PHP environment. + * + * @param[in,out] string &$phpath + * @param[out] array &$checks + */ +function check_php(&$phpath, &$checks) { + $help = ''; + + if (strlen($phpath)) { + $passed = file_exists($phpath); + } else { + if(is_windows()) + $phpath = trim(shell_exec('where php')); + else + $phpath = trim(shell_exec('which php')); + + $passed = strlen($phpath); + } + + if(!$passed) { + $help .= t('Could not find a command line version of PHP in the web server PATH.'). EOL; + $help .= t('If you don\'t have a command line version of PHP installed on server, you will not be able to run background polling via cron.') . EOL; + $help .= EOL . EOL ; + $tpl = get_markup_template('field_input.tpl'); + $help .= replace_macros($tpl, array( + '$field' => array('phpath', t('PHP executable path'), $phpath, t('Enter full path to php executable. You can leave this blank to continue the installation.')), + )); + $phpath = ''; + } + + check_add($checks, t('Command line PHP').($passed?" ($phpath)":""), $passed, false, $help); + + if($passed) { + $str = autoname(8); + $cmd = "$phpath install/testargs.php $str"; + $result = trim(shell_exec($cmd)); + $passed2 = $result == $str; + $help = ''; + if(!$passed2) { + $help .= t('The command line version of PHP on your system does not have "register_argc_argv" enabled.'). EOL; + $help .= t('This is required for message delivery to work.'); + } + + check_add($checks, t('PHP register_argc_argv'), $passed, true, $help); + } +} + +/** + * @brief Some PHP configuration checks. + * + * @todo Change how we display such informational text. Add more description + * how to change them. + * + * @param[out] array &$checks + */ +function check_phpconfig(&$checks) { + require_once 'include/environment.php'; + + $help = ''; + + $result = getPhpiniUploadLimits(); + $help = sprintf(t('Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once.'), + userReadableSize($result['post_max_size']), + userReadableSize($result['max_upload_filesize']), + $result['max_file_uploads'] + ); + $help .= '
    ' . t('You can adjust these settings in the servers php.ini.'); + + check_add($checks, t('PHP upload limits'), true, false, $help); +} + +/** + * @brief Check if the openssl implementation can generate keys. + * + * @param[out] array $checks + */ +function check_keys(&$checks) { + $help = ''; + $res = false; + + if (function_exists('openssl_pkey_new')) { + $res = openssl_pkey_new(array( + 'digest_alg' => 'sha1', + 'private_key_bits' => 4096, + 'encrypt_key' => false) + ); + } + + // Get private key + + if (! $res) { + $help .= t('Error: the "openssl_pkey_new" function on this system is not able to generate encryption keys'). EOL; + $help .= t('If running under Windows, please see "http://www.php.net/manual/en/openssl.installation.php".'); + } + + check_add($checks, t('Generate encryption keys'), $res, true, $help); +} + +/** + * @brief Check for some PHP functions and modules. + * + * @param[in,out] array &$checks + */ +function check_funcs(&$checks) { + $ck_funcs = array(); + + // add check metadata, the real check is done bit later and return values set + check_add($ck_funcs, t('libCurl PHP module'), true, true); + check_add($ck_funcs, t('GD graphics PHP module'), true, true); + check_add($ck_funcs, t('OpenSSL PHP module'), true, true); + check_add($ck_funcs, t('mysqli or postgres PHP module'), true, true); + check_add($ck_funcs, t('mb_string PHP module'), true, true); + check_add($ck_funcs, t('mcrypt PHP module'), true, true); + check_add($ck_funcs, t('xml PHP module'), true, true); + + if(function_exists('apache_get_modules')){ + if (! in_array('mod_rewrite', apache_get_modules())) { + check_add($ck_funcs, t('Apache mod_rewrite module'), false, true, t('Error: Apache webserver mod-rewrite module is required but not installed.')); + } else { + check_add($ck_funcs, t('Apache mod_rewrite module'), true, true); + } + } + if((! function_exists('proc_open')) || strstr(ini_get('disable_functions'),'proc_open')) { + check_add($ck_funcs, t('proc_open'), false, true, t('Error: proc_open is required but is either not installed or has been disabled in php.ini')); + } + else { + check_add($ck_funcs, t('proc_open'), true, true); + } + + if(! function_exists('curl_init')) { + $ck_funcs[0]['status'] = false; + $ck_funcs[0]['help'] = t('Error: libCURL PHP module required but not installed.'); + } + if(! function_exists('imagecreatefromjpeg')) { + $ck_funcs[1]['status'] = false; + $ck_funcs[1]['help'] = t('Error: GD graphics PHP module with JPEG support required but not installed.'); + } + if(! function_exists('openssl_public_encrypt')) { + $ck_funcs[2]['status'] = false; + $ck_funcs[2]['help'] = t('Error: openssl PHP module required but not installed.'); + } + if(! function_exists('mysqli_connect') && !function_exists('pg_connect')) { + $ck_funcs[3]['status'] = false; + $ck_funcs[3]['help'] = t('Error: mysqli or postgres PHP module required but neither are installed.'); + } + if(! function_exists('mb_strlen')) { + $ck_funcs[4]['status'] = false; + $ck_funcs[4]['help'] = t('Error: mb_string PHP module required but not installed.'); + } + if(! function_exists('mcrypt_encrypt')) { + $ck_funcs[5]['status'] = false; + $ck_funcs[5]['help'] = t('Error: mcrypt PHP module required but not installed.'); + } + if(! extension_loaded('xml')) { + $ck_funcs[6]['status'] = false; + $ck_funcs[6]['help'] = t('Error: xml PHP module required for DAV but not installed.'); + } + + $checks = array_merge($checks, $ck_funcs); +} + +/** + * @brief Check for .htconfig requirements. + * + * @param[out] array &$checks + */ +function check_htconfig(&$checks) { + $status = true; + $help = ''; + + if( (file_exists('.htconfig.php') && !is_writable('.htconfig.php')) || + (!file_exists('.htconfig.php') && !is_writable('.')) ) { + $status = false; + $help = t('The web installer needs to be able to create a file called ".htconfig.php" in the top folder of your web server and it is unable to do so.') .EOL; + $help .= t('This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can.').EOL; + $help .= t('At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder.').EOL; + $help .= t('You can alternatively skip this procedure and perform a manual installation. Please see the file "install/INSTALL.txt" for instructions.').EOL; + } + + check_add($checks, t('.htconfig.php is writable'), $status, false, $help); +} + +/** + * @brief Checks for our templating engine Smarty3 requirements. + * + * @param[out] array &$checks + */ +function check_smarty3(&$checks) { + $status = true; + $help = ''; + + if(! is_writable(TEMPLATE_BUILD_PATH) ) { + $status = false; + $help = t('Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering.') .EOL; + $help .= sprintf( t('In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder.'), TEMPLATE_BUILD_PATH) . EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; + $help .= sprintf( t('Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains.'), TEMPLATE_BUILD_PATH) . EOL; + } + + check_add($checks, sprintf( t('%s is writable'), TEMPLATE_BUILD_PATH), $status, true, $help); +} + +/** + * @brief Check for store directory. + * + * @param[out] array &$checks + */ +function check_store(&$checks) { + $status = true; + $help = ''; + + @os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true); + + if(! is_writable('store')) { + $status = false; + $help = t('Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder') . EOL; + $help .= t('Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder.').EOL; + } + + check_add($checks, t('store is writable'), $status, true, $help); +} + +/** + * @brief Check URL rewrite und SSL certificate. + * + * @param[out] array &$checks + */ +function check_htaccess(&$checks) { + $a = get_app(); + $status = true; + $help = ''; + $ssl_error = false; + + $url = $a->get_baseurl() . '/setup/testrewrite'; + + if (function_exists('curl_init')){ + $test = z_fetch_url($url); + if(! $test['success']) { + if(strstr($url,'https://')) { + $test = z_fetch_url($url,false,0,array('novalidate' => true)); + if($test['success']) { + $ssl_error = true; + } + } + else { + $test = z_fetch_url(str_replace('http://','https://',$url),false,0,array('novalidate' => true)); + if($test['success']) { + $ssl_error = true; + } + } + + if($ssl_error) { + $help = t('SSL certificate cannot be validated. Fix certificate or disable https access to this site.') . EOL; + $help .= t('If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!') . EOL; + $help .= t('This restriction is incorporated because public posts from you may for example contain references to images on your own hub.') . EOL; + $help .= t('If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues.') . EOL; + $help .= t('This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement.') .EOL; + $help .= t('Providers are available that issue free certificates which are browser-valid.'). EOL; + + check_add($checks, t('SSL certificate validation'), false, true, $help); + } + } + + if ((! $test['success']) || ($test['body'] != "ok")) { + $status = false; + $help = t('Url rewrite in .htaccess is not working. Check your server configuration.'.'Test: '.var_export($test,true)); + } + + check_add($checks, t('Url rewrite is working'), $status, true, $help); + } else { + // cannot check modrewrite if libcurl is not installed + } +} + + +function manual_config(&$a) { + $data = htmlspecialchars($a->data['txt'], ENT_COMPAT, 'UTF-8'); + $o = t('The database configuration file ".htconfig.php" could not be written. Please use the enclosed text to create a configuration file in your web server root.'); + $o .= ""; + + return $o; +} + +function load_database_rem($v, $i){ + $l = trim($i); + if (strlen($l)>1 && ($l[0]=="-" || ($l[0]=="/" && $l[1]=="*"))){ + return $v; + } else { + return $v."\n".$i; + } +} + + +function load_database($db) { + $str = file_get_contents($db->get_install_script()); + $arr = explode(';',$str); + $errors = false; + foreach($arr as $a) { + if(strlen(trim($a))) { + $r = @$db->q(trim($a)); + if(! $r) { + $errors .= t('Errors encountered creating database tables.') . $a . EOL; + } + } + } + + return $errors; +} + +function what_next() { + $a = get_app(); + // install the standard theme + set_config('system', 'allowed_themes', 'redbasic'); + + // Set a lenient list of ciphers if using openssl. Other ssl engines + // (e.g. NSS used in RedHat) require different syntax, so hopefully + // the default curl cipher list will work for most sites. If not, + // this can set via config. Many distros are now disabling RC4, + // but many Red sites still use it and are unable to change it. + // We do not use SSL for encryption, only to protect session cookies. + // z_fetch_url() is also used to import shared links and other content + // so in theory most any cipher could show up and we should do our best + // to make the content available rather than tell folks that there's a + // weird SSL error which they can't do anything about. + + $x = curl_version(); + if(stristr($x['ssl_version'],'openssl')) + set_config('system','curl_ssl_ciphers','ALL:!eNULL'); + + // Create a system channel + require_once ('include/identity.php'); + create_sys_channel(); + + $baseurl = $a->get_baseurl(); + return + t('

    What next

    ') + ."

    ".t('IMPORTANT: You will need to [manually] setup a scheduled task for the poller.') + .t('Please see the file "install/INSTALL.txt".') + ."

    " + .t("Go to your new hub registration page and register as new member. Remember to use the same email you have entered as administrator email. This will allow you to enter the site admin panel.") + ."

    "; +} diff --git a/sources/mod/share.php b/sources/mod/share.php new file mode 100644 index 00000000..d5a389bd --- /dev/null +++ b/sources/mod/share.php @@ -0,0 +1,81 @@ + 1) ? intval(argv(1)) : 0); + + if(! $post_id) + killme(); + + if(! (local_channel() || remote_channel())) + killme(); + + $r = q("SELECT * from item left join xchan on author_xchan = xchan_hash WHERE id = %d LIMIT 1", + intval($post_id) + ); + if(! $r) + killme(); + if(($r[0]['item_private']) && ($r[0]['xchan_network'] !== 'rss')) + killme(); + + $sql_extra = item_permissions_sql($r[0]['uid']); + + $r = q("select * from item where id = %d $sql_extra", + intval($post_id) + ); + if(! $r) + killme(); + + /** @FIXME we only share bbcode */ + + if($r[0]['mimetype'] !== 'text/bbcode') + killme(); + + /** @FIXME eventually we want to post remotely via rpost on your home site */ + // When that works remove this next bit: + + if(! local_channel()) + killme(); + + xchan_query($r); + + if (strpos($r[0]['body'], "[/share]") !== false) { + $pos = strpos($r[0]['body'], "[share"); + $o = substr($r[0]['body'], $pos); + } else { + $o = "[share author='".urlencode($r[0]['author']['xchan_name']). + "' profile='".$r[0]['author']['xchan_url'] . + "' avatar='".$r[0]['author']['xchan_photo_s']. + "' link='".$r[0]['plink']. + "' posted='".$r[0]['created']. + "' message_id='".$r[0]['mid']."']"; + if($r[0]['title']) + $o .= '[b]'.$r[0]['title'].'[/b]'."\n"; + $o .= $r[0]['body']; + $o.= "[/share]"; + } + + if(local_channel()) { + echo $o; + killme(); + } + + $observer = $a->get_observer(); + $parsed = $observer['xchan_url']; + if($parsed) { + $post_url = $parsed['scheme'] . ':' . $parsed['host'] . (($parsed['port']) ? ':' . $parsed['port'] : '') + . '/rpost'; + + /** + * @FIXME we were probably called from JS so we don't know the return page. + * In fact we won't be able to load the remote page. + * we might need an iframe + */ + + $x = z_post_url($post_url, array('f' => '', 'body' => $o )); + killme(); + } +} diff --git a/sources/mod/sharedwithme.php b/sources/mod/sharedwithme.php new file mode 100644 index 00000000..bee072ea --- /dev/null +++ b/sources/mod/sharedwithme.php @@ -0,0 +1,107 @@ +get_channel(); + + $is_owner = (local_channel() && (local_channel() == $channel['channel_id'])); + + //check for updated items and remove them + require_once('include/sharedwithme.php'); + apply_updates(); + + //drop single file - localuser + if((argc() > 2) && (argv(2) === 'drop')) { + + $id = intval(argv(1)); + + q("DELETE FROM item WHERE id = %d AND uid = %d", + intval($id), + intval(local_channel()) + ); + + goaway(z_root() . '/sharedwithme'); + } + + //drop all files - localuser + if((argc() > 1) && (argv(1) === 'dropall')) { + + q("DELETE FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d", + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()) + ); + + goaway(z_root() . '/sharedwithme'); + } + + //list files + $r = q("SELECT id, uid, object, item_unseen FROM item WHERE verb = '%s' AND obj_type = '%s' AND uid = %d AND owner_xchan != '%s'", + dbesc(ACTIVITY_POST), + dbesc(ACTIVITY_OBJ_FILE), + intval(local_channel()), + dbesc($channel['channel_hash']) + ); + + $items =array(); + $ids = ''; + + if($r) { + + foreach($r as $rr) { + $object = json_decode($rr['object'],true); + + $item = array(); + $item['id'] = $rr['id']; + $item['objfiletype'] = $object['filetype']; + $item['objfiletypeclass'] = getIconFromType($object['filetype']); + $item['objurl'] = rawurldecode(get_rel_link($object['link'],'alternate')) . '?f=&zid=' . $channel['xchan_addr']; + $item['objfilename'] = $object['filename']; + $item['objfilesize'] = userReadableSize($object['filesize']); + $item['objedited'] = $object['edited']; + $item['unseen'] = $rr['item_unseen']; + + $items[] = $item; + + if($item['unseen'] > 0) { + $ids .= " '" . $rr['id'] . "',"; + } + + } + + } + + if($ids) { + + //remove trailing , + $ids = rtrim($ids, ","); + + q("UPDATE item SET item_unseen = 0 WHERE id IN ( $ids ) AND uid = %d", + intval(local_channel()) + ); + + } + + $o = profile_tabs($a, $is_owner, $channel['channel_address']); + + $o .= replace_macros(get_markup_template('sharedwithme.tpl'), array( + '$header' => t('Files: shared with me'), + '$name' => t('Name'), + '$label_new' => t('NEW'), + '$size' => t('Size'), + '$lastmod' => t('Last Modified'), + '$dropall' => t('Remove all files'), + '$drop' => t('Remove this file'), + '$items' => $items + )); + + return $o; + +} + diff --git a/sources/mod/siteinfo.php b/sources/mod/siteinfo.php new file mode 100644 index 00000000..61c20d66 --- /dev/null +++ b/sources/mod/siteinfo.php @@ -0,0 +1,180 @@ +argv[1]=="json"){ + $register_policy = Array('REGISTER_CLOSED', 'REGISTER_APPROVE', 'REGISTER_OPEN'); + $directory_mode = Array('DIRECTORY_MODE_NORMAL', 'DIRECTORY_MODE_SECONDARY','DIRECTORY_MODE_PRIMARY', 'DIRECTORY_MODE_STANDALONE'); + + $sql_extra = ''; + + $r = q("select * from channel left join account on account_id = channel_account_id where ( account_roles & 4096 )>0 and account_default_channel = channel_id"); + + + if($r) { + $admin = array(); + foreach($r as $rr) { + if($rr['channel_pageflags'] & PAGE_HUBADMIN) + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + } + if(! $admin) { + foreach($r as $rr) { + $admin[] = array( 'name' => $rr['channel_name'], 'address' => $rr['channel_address'] . '@' . get_app()->get_hostname(), 'channel' => z_root() . '/channel/' . $rr['channel_address']); + } + } + } + else { + $admin = false; + } + + $def_service_class = get_config('system','default_service_class'); + if($def_service_class) + $service_class = get_config('service_class',$def_service_class); + else + $service_class = false; + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if(count($r)) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + sort($visible_plugins); + + if(@is_dir('.git') && function_exists('shell_exec')) + $commit = trim(@shell_exec('git log -1 --format="%h"')); + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + + $site_info = get_config('system','info'); + $site_name = get_config('system','sitename'); + if(! get_config('system','hidden_version_siteinfo')) { + $version = RED_VERSION; + if(@is_dir('.git') && function_exists('shell_exec')) { + $commit = trim( @shell_exec('git log -1 --format="%h"')); + if(! get_config('system','hidden_tag_siteinfo')) + $tag = trim( @shell_exec('git describe --tags --abbrev=0')); + else + $tag = ''; + } + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + } + else { + $version = $commit = ''; + } + + //Statistics + $channels_total_stat = intval(get_config('system','channels_total_stat')); + $channels_active_halfyear_stat = intval(get_config('system','channels_active_halfyear_stat')); + $channels_active_monthly_stat = intval(get_config('system','channels_active_monthly_stat')); + $local_posts_stat = intval(get_config('system','local_posts_stat')); + $hide_in_statistics = intval(get_config('system','hide_in_statistics')); + $site_expire = intval(get_config('system', 'default_expire_days')); + + + $data = Array( + 'version' => $version, + 'version_tag' => $tag, + 'commit' => $commit, + 'url' => z_root(), + 'plugins' => $visible_plugins, + 'register_policy' => $register_policy[$a->config['system']['register_policy']], + 'directory_mode' => $directory_mode[$a->config['system']['directory_mode']], + 'language' => get_config('system','language'), + 'diaspora_emulation' => get_config('system','diaspora_enabled'), + 'rss_connections' => get_config('system','feed_contacts'), + 'expiration' => $site_expire, + 'default_service_restrictions' => $service_class, + 'admin' => $admin, + 'site_name' => (($site_name) ? $site_name : ''), + 'platform' => PLATFORM_NAME, + 'dbdriver' => $db->getdriver(), + 'lastpoll' => get_config('system','lastpoll'), + 'info' => (($site_info) ? $site_info : ''), + 'channels_total' => $channels_total_stat, + 'channels_active_halfyear' => $channels_active_halfyear_stat, + 'channels_active_monthly' => $channels_active_monthly_stat, + 'local_posts' => $local_posts_stat, + 'hide_in_statistics' => $hide_in_statistics + ); + json_return_and_die($data); + } +} + + + +function siteinfo_content(&$a) { + + if(! get_config('system','hidden_version_siteinfo')) { + $version = sprintf( t('Version %s'), RED_VERSION ); + if(@is_dir('.git') && function_exists('shell_exec')) { + $commit = @shell_exec('git log -1 --format="%h"'); + $tag = @shell_exec('git describe --tags --abbrev=0'); + } + if(! isset($commit) || strlen($commit) > 16) + $commit = ''; + } + else { + $version = $commit = ''; + } + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if(count($r)) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + + $plugins_list = ''; + if(count($visible_plugins)) { + $plugins_text = t('Installed plugins/addons/apps:'); + $sorted = $visible_plugins; + $s = ''; + sort($sorted); + foreach($sorted as $p) { + if(strlen($p)) { + if(strlen($s)) $s .= ', '; + $s .= $p; + } + } + $plugins_list .= $s; + } + else + $plugins_text = t('No installed plugins/addons/apps'); + + $txt = get_config('system','admininfo'); + $admininfo = bbcode($txt); + + if(file_exists('doc/site_donate.html')) + $donate .= file_get_contents('doc/site_donate.html'); + + $o = replace_macros(get_markup_template('siteinfo.tpl'), array( + '$title' => t('$Projectname'), + '$description' => t('This is a hub of $Projectname - a global cooperative network of decentralized privacy enhanced websites.'), + '$version' => $version, + '$tag_txt' => t('Tag: '), + '$tag' => $tag, + '$polled' => t('Last background fetch: '), + '$lastpoll' => get_poller_runtime(), + '$commit' => $commit, + '$web_location' => t('Running at web location') . ' ' . z_root(), + '$visit' => t('Please visit redmatrix.me to learn more about $Projectname.'), + '$bug_text' => t('Bug reports and issues: please visit'), + '$bug_link_url' => 'https://github.com/redmatrix/hubzilla/issues', + '$bug_link_text' => t('$projectname issues'), + '$contact' => t('Suggestions, praise, etc. - please email "redmatrix" at librelist - dot com'), + '$donate' => $donate, + '$adminlabel' => t('Site Administrators'), + '$admininfo' => $admininfo, + '$plugins_text' => $plugins_text, + '$plugins_list' => $plugins_list + )); + + call_hooks('about_hook', $o); + + return $o; + +} diff --git a/sources/mod/sitelist.php b/sources/mod/sitelist.php new file mode 100644 index 00000000..12911cbd --- /dev/null +++ b/sources/mod/sitelist.php @@ -0,0 +1,58 @@ + false); + + $r = q("select count(site_url) as total from site where true $sql_extra "); + + if($r) + $result['total'] = intval($r[0]['total']); + + $result['start'] = $start; + $result['limit'] = $limit; + + $r = q("select * from site where true $sql_extra $sql_order $sql_limit"); + + $result['results'] = 0; + $result['entries'] = array(); + + if($r) { + $result['success'] = true; + $result['results'] = count($r); + + foreach($r as $rr) { + $result['entries'][] = array('url' => $rr['site_url']); + } + + } + + echo json_encode($result); + killme(); + + +} \ No newline at end of file diff --git a/sources/mod/smilies.php b/sources/mod/smilies.php new file mode 100644 index 00000000..b22d0c6d --- /dev/null +++ b/sources/mod/smilies.php @@ -0,0 +1,15 @@ +argv[1]==="json"){ + $tmp = list_smilies(); + $results = array(); + for($i = 0; $i < count($tmp['texts']); $i++) { + $results[] = array('text' => $tmp['texts'][$i], 'icon' => $tmp['icons'][$i]); + } + json_return_and_die($results); + } + else { + return smilies('',true); + } +} diff --git a/sources/mod/sources.php b/sources/mod/sources.php new file mode 100644 index 00000000..0aaaa82b --- /dev/null +++ b/sources/mod/sources.php @@ -0,0 +1,168 @@ +get_channel(); + + if($name == '*') + $xchan = '*'; + + if($abook) { + $r = q("select abook_xchan from abook where abook_id = %d and abook_channel = %d limit 1", + intval($abook), + intval(local_channel()) + ); + if($r) + $xchan = $r[0]['abook_xchan']; + } + + if(! $xchan) { + notice ( t('Failed to create source. No channel selected.') . EOL); + return; + } + + if(! $source) { + $r = q("insert into source ( src_channel_id, src_channel_xchan, src_xchan, src_patt ) + values ( %d, '%s', '%s', '%s' ) ", + intval(local_channel()), + dbesc($channel['channel_hash']), + dbesc($xchan), + dbesc($words) + ); + if($r) { + info( t('Source created.') . EOL); + } + goaway(z_root() . '/sources'); + } + else { + $r = q("update source set src_xchan = '%s', src_patt = '%s' where src_channel_id = %d and src_id = %d", + dbesc($xchan), + dbesc($words), + intval(local_channel()), + intval($source) + ); + if($r) { + info( t('Source updated.') . EOL); + } + + } +} + + +function sources_content(&$a) { + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + return ''; + } + + if(! feature_enabled(local_channel(),'channel_sources')) { + return ''; + } + + // list sources + if(argc() == 1) { + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_channel_id = %d", + intval(local_channel()) + ); + if($r) { + for($x = 0; $x < count($r); $x ++) { + if($r[$x]['src_xchan'] == '*') { + $r[$x]['xchan_name'] = t('*'); + } + $r[$x]['src_patt'] = htmlspecialchars($r[$x]['src_patt'], ENT_COMPAT,'UTF-8'); + } + } + $o = replace_macros(get_markup_template('sources_list.tpl'), array( + '$title' => t('Channel Sources'), + '$desc' => t('Manage remote sources of content for your channel.'), + '$new' => t('New Source'), + '$sources' => $r + )); + return $o; + } + + if(argc() == 2 && argv(1) === 'new') { + // TODO add the words 'or RSS feed' and corresponding code to manage feeds and frequency + + $o = replace_macros(get_markup_template('sources_new.tpl'), array( + '$title' => t('New Source'), + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => array( 'words', t('Only import content with these words (one per line)'),'',t('Leave blank to import all public content')), + '$name' => array( 'name', t('Channel Name'), '', ''), + '$submit' => t('Submit') + )); + return $o; + + } + + if(argc() == 2 && intval(argv(1))) { + // edit source + $r = q("select source.*, xchan.* from source left join xchan on src_xchan = xchan_hash where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if($r) { + $x = q("select abook_id from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($r[0]['src_xchan']), + intval(local_channel()) + ); + } + if(! $r) { + notice( t('Source not found.') . EOL); + return ''; + } + + $r[0]['src_patt'] = htmlspecialchars($r[0]['src_patt'], ENT_QUOTES,'UTF-8'); + + $o = replace_macros(get_markup_template('sources_edit.tpl'), array( + '$title' => t('Edit Source'), + '$drop' => t('Delete Source'), + '$id' => $r[0]['src_id'], + '$desc' => t('Import all or selected content from the following channel into this channel and distribute it according to your channel settings.'), + '$words' => array( 'words', t('Only import content with these words (one per line)'),$r[0]['src_patt'],t('Leave blank to import all public content')), + '$xchan' => $r[0]['src_xchan'], + '$abook' => $x[0]['abook_id'], + '$name' => array( 'name', t('Channel Name'), $r[0]['xchan_name'], ''), + '$submit' => t('Submit') + )); + return $o; + + } + + if(argc() == 3 && intval(argv(1)) && argv(2) === 'drop') { + $r = q("select * from source where src_id = %d and src_channel_id = %d limit 1", + intval(argv(1)), + intval(local_channel()) + ); + if(! $r) { + notice( t('Source not found.') . EOL); + return ''; + } + $r = q("delete from source where src_id = %d and src_channel_id = %d", + intval(argv(1)), + intval(local_channel()) + ); + if($r) + info( t('Source removed') . EOL); + else + notice( t('Unable to remove source.') . EOL); + + goaway(z_root() . '/sources'); + + } + + // shouldn't get here. + +} \ No newline at end of file diff --git a/sources/mod/sslify.php b/sources/mod/sslify.php new file mode 100644 index 00000000..f37a8e23 --- /dev/null +++ b/sources/mod/sslify.php @@ -0,0 +1,24 @@ + 1) + $message_id = intval(argv(1)); + if(! $message_id) + killme(); + + $r = q("SELECT item_flags FROM item WHERE uid = %d AND id = %d LIMIT 1", + intval(local_channel()), + intval($message_id) + ); + if(! count($r)) + killme(); + + $item_starred = (intval($r[0]['item_starred']) ? 0 : 1); + + $r = q("UPDATE item SET item_starred = %d WHERE uid = %d and id = %d", + intval($item_starred), + intval(local_channel()), + intval($message_id) + ); + + header('Content-type: application/json'); + echo json_encode(array('result' => $item_starred)); + killme(); +} diff --git a/sources/mod/subthread.php b/sources/mod/subthread.php new file mode 100755 index 00000000..9cfe5c24 --- /dev/null +++ b/sources/mod/subthread.php @@ -0,0 +1,243 @@ + 1) ? notags(trim(argv(1))) : 0); + + $r = q("SELECT * FROM `item` WHERE `parent` = '%s' OR `parent_mid` = '%s' and parent = id LIMIT 1", + dbesc($item_id), + dbesc($item_id) + ); + + if((! $item_id) || (! $r)) { + logger('subthread: no item ' . $item_id); + return; + } + + $item = $r[0]; + + $owner_uid = $item['uid']; + $observer = $a->get_observer(); + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + if(! perm_is_allowed($owner_uid,$ob_hash,'post_comments')) + return; + + $sys = get_sys_channel(); + + $owner_uid = $item['uid']; + $owner_aid = $item['aid']; + + // if this is a "discover" item, (item['uid'] is the sys channel), + // fallback to the item comment policy, which should've been + // respected when generating the conversation thread. + // Even if the activity is rejected by the item owner, it should still get attached + // to the local discover conversation on this site. + + if(($owner_uid != $sys['channel_id']) && (! perm_is_allowed($owner_uid,$observer['xchan_hash'],'post_comments'))) { + notice( t('Permission denied') . EOL); + killme(); + } + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['owner_xchan']) + ); + if($r) + $thread_owner = $r[0]; + else + killme(); + + $r = q("select * from xchan where xchan_hash = '%s' limit 1", + dbesc($item['author_xchan']) + ); + if($r) + $item_author = $r[0]; + else + killme(); + + + $mid = item_message_id(); + + $post_type = (($item['resource_type'] === 'photo') ? t('photo') : t('status')); + + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $item['plink'])); + $objtype = (($item['resource_type'] === 'photo') ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $body = $item['body']; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $item['mid'], + 'parent' => (($item['thr_parent']) ? $item['thr_parent'] : $item['parent_mid']), + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item_author['xchan_name'], + 'address' => $item_author['xchan_addr'], + 'guid' => $item_author['xchan_guid'], + 'guid_sig' => $item_author['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item_author['xchan_url']), + array('rel' => 'photo', 'type' => $item_author['xchan_photo_mimetype'], 'href' => $item_author['xchan_photo_m'])), + ), + )); + + if(! intval($item['item_thread_top'])) + $post_type = 'comment'; + + $bodyverb = t('%1$s is following %2$s\'s %3$s'); + + $arr = array(); + + $arr['mid'] = $mid; + $arr['aid'] = $owner_aid; + $arr['uid'] = $owner_uid; + $arr['parent'] = $item['id']; + $arr['parent_mid'] = $item['mid']; + $arr['thr_parent'] = $item['mid']; + $arr['owner_xchan'] = $thread_owner['xchan_hash']; + $arr['author_xchan'] = $observer['xchan_hash']; + $arr['item_origin'] = 1; + $arr['item_notshown'] = 1; + if(intval($item['item_wall'])) + $arr['item_wall'] = 1; + else + $arr['item_wall'] = 0; + + $ulink = '[zrl=' . $item_author['xchan_url'] . ']' . $item_author['xchan_name'] . '[/zrl]'; + $alink = '[zrl=' . $observer['xchan_url'] . ']' . $observer['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $item['mid'] . ']' . $post_type . '[/zrl]'; + + $arr['body'] = sprintf( $bodyverb, $alink, $ulink, $plink ); + + $arr['verb'] = $activity; + $arr['obj_type'] = $objtype; + $arr['object'] = $obj; + + $arr['allow_cid'] = $item['allow_cid']; + $arr['allow_gid'] = $item['allow_gid']; + $arr['deny_cid'] = $item['deny_cid']; + $arr['deny_gid'] = $item['deny_gid']; + + + $post = item_store($arr); + $post_id = $post['item_id']; + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + killme(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + $post_type = (($item['resource_id']) ? t('photo') : t('status')); + $objtype = (($item['resource_id']) ? ACTIVITY_OBJ_PHOTO : ACTIVITY_OBJ_NOTE ); + + $link = xmlify('' . "\n") ; + $body = $item['body']; + + $obj = <<< EOT + + + $objtype + 1 + {$item['mid']} + $link + + $body + +EOT; + + $arr = array(); + + $arr['mid'] = $mid; + $arr['uid'] = $owner_uid; + $arr['contact-id'] = $contact['id']; + $arr['type'] = 'activity'; + $arr['wall'] = $item['wall']; + $arr['origin'] = 1; + $arr['gravity'] = GRAVITY_LIKE; + $arr['parent'] = $item['id']; + $arr['parent-mid'] = $item['mid']; + $arr['thr_parent'] = $item['mid']; + $arr['owner-name'] = $remote_owner['name']; + $arr['owner-link'] = $remote_owner['url']; + $arr['owner-avatar'] = $remote_owner['thumb']; + $arr['author-name'] = $contact['name']; + $arr['author-link'] = $contact['url']; + $arr['author-avatar'] = $contact['thumb']; + + $ulink = '[zrl=' . $contact['url'] . ']' . $contact['name'] . '[/zrl]'; + $alink = '[zrl=' . $item['author-link'] . ']' . $item['author-name'] . '[/zrl]'; + $plink = '[zrl=' . $a->get_baseurl() . '/display/' . $owner['nickname'] . '/' . $item['id'] . ']' . $post_type . '[/zrl]'; + $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink ); + + $arr['verb'] = $activity; + $arr['object-type'] = $objtype; + $arr['object'] = $obj; + $arr['allow_cid'] = $item['allow_cid']; + $arr['allow_gid'] = $item['allow_gid']; + $arr['deny_cid'] = $item['deny_cid']; + $arr['deny_gid'] = $item['deny_gid']; + $arr['visible'] = 1; + $arr['unseen'] = 1; + $arr['last-child'] = 0; + + $post = item_store($arr); + $post_id = $post['item_id']; + + if(! $item['visible']) { + $r = q("UPDATE `item` SET `visible` = 1 WHERE `id` = %d AND `uid` = %d", + intval($item['id']), + intval($owner_uid) + ); + } + + $arr['id'] = $post_id; + + call_hooks('post_local_end', $arr); + + killme(); + +} + + diff --git a/sources/mod/suggest.php b/sources/mod/suggest.php new file mode 100644 index 00000000..438d884c --- /dev/null +++ b/sources/mod/suggest.php @@ -0,0 +1,66 @@ +get_baseurl() . '/' . $a->cmd; + + $r = suggestion_query(local_channel(),get_observer_hash()); + + if(! $r) { + info( t('No suggestions available. If this is a new site, please try again in 24 hours.')); + return; + } + + $arr = array(); + + foreach($r as $rr) { + + $connlnk = $a->get_baseurl() . '/follow/?url=' . $rr['xchan_addr']; + + $arr[] = array( + 'url' => chanlink_url($rr['xchan_url']), + 'common' => $rr['total'], + 'profile' => $rr['xchan_url'], + 'name' => $rr['xchan_name'], + 'photo' => $rr['xchan_photo_m'], + 'ignlnk' => $a->get_baseurl() . '/suggest?ignore=' . $rr['xchan_hash'], + 'conntxt' => t('Connect'), + 'connlnk' => $connlnk, + 'ignore' => t('Ignore/Hide') + ); + } + + + $o = replace_macros(get_markup_template('suggest_page.tpl'),array( + '$title' => t('Channel Suggestions'), + '$entries' => $arr + )); + + return $o; + +} diff --git a/sources/mod/tagger.php b/sources/mod/tagger.php new file mode 100644 index 00000000..9f9855ed --- /dev/null +++ b/sources/mod/tagger.php @@ -0,0 +1,134 @@ + 1) ? notags(trim(argv(1))) : 0); + + logger('tagger: tag ' . $term . ' item ' . $item_id); + + + $r = q("SELECT * FROM item left join xchan on xchan_hash = author_xchan WHERE id = '%s' and uid = %d LIMIT 1", + dbesc($item_id), + intval(local_channel()) + ); + + if((! $item_id) || (! $r)) { + logger('tagger: no item ' . $item_id); + return; + } + + $item = $r[0]; + + $owner_uid = $item['uid']; + + switch($item['resource_type']) { + case 'photo': + $targettype = ACTIVITY_OBJ_PHOTO; + $post_type = t('photo'); + break; + case 'event': + $targgettype = ACTIVITY_OBJ_EVENT; + $post_type = t('event'); + break; + default: + $targettype = ACTIVITY_OBJ_NOTE; + $post_type = t('post'); + if($item['mid'] != $item['parent_mid']) + $post_type = t('comment'); + break; + } + + + $links = array(array('rel' => 'alternate','type' => 'text/html', + 'href' => z_root() . '/display/' . $item['mid'])); + + $target = json_encode(array( + 'type' => $targettype, + 'id' => $item['mid'], + 'link' => $links, + 'title' => $item['title'], + 'content' => $item['body'], + 'created' => $item['created'], + 'edited' => $item['edited'], + 'author' => array( + 'name' => $item['xchan_name'], + 'address' => $item['xchan_addr'], + 'guid' => $item['xchan_guid'], + 'guid_sig' => $item['xchan_guid_sig'], + 'link' => array( + array('rel' => 'alternate', 'type' => 'text/html', 'href' => $item['xchan_url']), + array('rel' => 'photo', 'type' => $item['xchan_photo_mimetype'], 'href' => $item['xchan_photo_m'])), + ), + )); + + + + $link = xmlify('' . "\n") ; + + $tagid = $a->get_baseurl() . '/search?tag=' . $term; + $objtype = ACTIVITY_OBJ_TAGTERM; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $tagid, + 'link' => array(array('rel' => 'alternate','type' => 'text/html', 'href' => $tagid)), + 'title' => $term, + 'content' => $term + )); + + $bodyverb = t('%1$s tagged %2$s\'s %3$s with %4$s'); + + // saving here for reference + // also check out x22d5 and x2317 and x0d6b and x0db8 and x24d0 and xff20 !!! + + $termlink = html_entity_decode('⋕') . '[zrl=' . $a->get_baseurl() . '/search?tag=' . urlencode($term) . ']'. $term . '[/zrl]'; + + $channel = $a->get_channel(); + + $arr = array(); + + $arr['owner_xchan'] = $item['owner_xchan']; + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_origin'] = 1; + $arr['item_wall'] = ((intval($item['item_wall'])) ? 1 : 0); + + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $alink = '[zrl=' . $item['xchan_url'] . ']' . $item['xchan_name'] . '[/zrl]'; + $plink = '[zrl=' . $item['plink'] . ']' . $post_type . '[/zrl]'; + + $arr['body'] = sprintf( $bodyverb, $ulink, $alink, $plink, $termlink ); + + $arr['verb'] = ACTIVITY_TAG; + $arr['tgt_type'] = $targettype; + $arr['target'] = $target; + $arr['obj_type'] = $objtype; + $arr['object'] = $obj; + $arr['parent_mid'] = $item['mid']; + + store_item_tag($item['uid'],$item['id'],TERM_OBJ_POST,TERM_HASHTAG,$term,$tagid); + $ret = post_activity_item($arr); + + if($ret['success']) + proc_run('php','include/notifier.php','tag',$ret['activity']['id']); + + killme(); + +} diff --git a/sources/mod/tagrm.php b/sources/mod/tagrm.php new file mode 100644 index 00000000..56e842fb --- /dev/null +++ b/sources/mod/tagrm.php @@ -0,0 +1,141 @@ +get_baseurl() . '/' . $_SESSION['photo_return']); + + + if((x($_POST,'submit')) && ($_POST['submit'] === t('Cancel'))) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $tag = ((x($_POST,'tag')) ? trim($_POST['tag']) : ''); + $item = ((x($_POST,'item')) ? intval($_POST['item']) : 0 ); + + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if(! $r) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r,true); + + $item = $r[0]; + $new_tags = array(); + + if($item['term']) { + for($x = 0; $x < count($item['term']); $x ++) { + if($item['term'][$x]['term'] !== hex2bin($tag)) + $new_tags[] = $item['term'][$x]; + } + } + + if($new_tags) + $item['term'] = $new_tags; + else + unset($item['term']); + + item_store_update($item); + + info( t('Tag removed') . EOL ); + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + // NOTREACHED + +} + + + +function tagrm_content(&$a) { + + if(! local_channel()) { + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + // NOTREACHED + } + + // remove tag on the fly if item and tag are provided + if((argc() == 4) && (argv(1) === 'drop') && intval(argv(2))) { + + $item = intval(argv(2)); + $tag = argv(3); + + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if(! $r) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r,true); + + $item = $r[0]; + + $new_tags = array(); + + if($item['term']) { + for($x = 0; $x < count($item['term']); $x ++) { + if($item['term'][$x]['term'] !== hex2bin($tag)) + $new_tags[] = $item['term'][$x]; + } + } + + if($new_tags) + $item['term'] = $new_tags; + else + unset($item['term']); + + item_store_update($item); + + info( t('Tag removed') . EOL ); + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + } + + //if we got only the item print a list of tags to select + if((argc() == 3) && (argv(1) === 'drop') && intval(argv(2))) { + + $o = ''; + + $item = intval(argv(2)); + + $r = q("SELECT * FROM `item` WHERE `id` = %d AND `uid` = %d LIMIT 1", + intval($item), + intval(local_channel()) + ); + + if(! $r) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $r = fetch_post_tags($r,true); + + if(! count($r[0]['term'])) + goaway($a->get_baseurl() . '/' . $_SESSION['photo_return']); + + $o .= '

    ' . t('Remove Item Tag') . '

    '; + + $o .= '

    ' . t('Select a tag to remove: ') . '

    '; + + $o .= '
    '; + $o .= ''; + $o .= '
      '; + + + foreach($r[0]['term'] as $x) { + $o .= '
    • ' . bbcode($x['term']) . '
    • '; + } + + $o .= '
    '; + $o .= ''; + $o .= ''; + $o .= '
    '; + + return $o; + + } + +} diff --git a/sources/mod/tasks.php b/sources/mod/tasks.php new file mode 100644 index 00000000..ed267cc9 --- /dev/null +++ b/sources/mod/tasks.php @@ -0,0 +1,107 @@ + 1 && argv(1) === 'fetch') { + if(argc() > 2 && argv(2) === 'all') + $arr['all'] = 1; + + $x = tasks_fetch($arr); + if($x['tasks']) { + $x['html'] = ''; + foreach($x['tasks'] as $y) { + $x['html'] .= '
    ' . $y['summary'] . '
    '; + } + } + json_return_and_die($x); + } + +} + + + +function tasks_post(&$a) { + + +// logger('post: ' . print_r($_POST,true)); + + + if(! local_channel()) + return; + + $channel = $a->get_channel(); + + if((argc() > 2) && (argv(1) === 'complete') && intval(argv(2))) { + $ret = array('success' => false); + $r = q("select * from event where `type` = 'task' and uid = %d and id = %d limit 1", + intval(local_channel()), + intval(argv(2)) + ); + if($r) { + $event = $r[0]; + if($event['event_status'] === 'COMPLETED') { + $event['event_status'] = 'IN-PROCESS'; + $event['event_status_date'] = NULL_DATE; + $event['event_percent'] = 0; + $event['event_sequence'] = $event['event_sequence'] + 1; + $event['edited'] = datetime_convert(); + } + else { + $event['event_status'] = 'COMPLETED'; + $event['event_status_date'] = datetime_convert(); + $event['event_percent'] = 100; + $event['event_sequence'] = $event['event_sequence'] + 1; + $event['edited'] = datetime_convert(); + } + $x = event_store_event($event); + if($x) + $ret['success'] = true; + } + json_return_and_die($ret); + } + + if(argc() == 2 && argv(1) === 'new') { + $text = escape_tags(trim($_REQUEST['summary'])); + if(! $text) + return array('success' => false); + $event = array(); + $event['aid'] = $channel['channel_account_id']; + $event['uid'] = $channel['channel_id']; + $event['event_xchan'] = $channel['channel_hash']; + $event['type'] = 'task'; + $event['nofinish'] = true; + $event['created'] = $event['edited'] = $event['start'] = datetime_convert(); + $event['adjust'] = 1; + $event['allow_cid'] = '<' . $channel['channel_hash'] . '>'; + $event['summary'] = escape_tags($_REQUEST['summary']); + $x = event_store_event($event); + if($x) + $x['success'] = true; + else + $x = array('success' => false); + json_return_and_die($x); + } + + +} + + + + + +function tasks_content(&$a) { + + if(! local_channel()) + return; + + + return ''; +} \ No newline at end of file diff --git a/sources/mod/thing.php b/sources/mod/thing.php new file mode 100644 index 00000000..b4b8ad02 --- /dev/null +++ b/sources/mod/thing.php @@ -0,0 +1,324 @@ +get_account(); + $channel = $a->get_channel(); + + $term_hash = (($_REQUEST['term_hash']) ? $_REQUEST['term_hash'] : ''); + + $name = escape_tags($_REQUEST['term']); + $verb = escape_tags($_REQUEST['verb']); + $activity = intval($_REQUEST['activity']); + $profile_guid = escape_tags($_REQUEST['profile_assign']); + $url = $_REQUEST['link']; + $photo = $_REQUEST['img']; + + $hash = random_string(); + + $verbs = obj_verbs(); + + /** + * verbs: [0] = first person singular, e.g. "I want", [1] = 3rd person singular, e.g. "Bill wants" + * We use the first person form when creating an activity, but the third person for use in activities + * @FIXME There is no accounting for verb gender for languages where this is significant. We may eventually + * require obj_verbs() to provide full conjugations and specify which form to use in the $_REQUEST params to this module. + */ + + $translated_verb = $verbs[$verb][1]; + + /* + * The site administrator can do things that normals cannot. + * This is restricted because it will likely cause + * an activitystreams protocol violation and the activity might + * choke in some other network and result in unnecessary + * support requests. It isn't because we're trying to be heavy-handed + * about what you can and can't do. + */ + + if(! $translated_verb) { + if(is_site_admin()) + $translated_verb = $verb; + } + + /* + * Things, objects: We do not provide definite (a, an) or indefinite (the) articles or singular/plural designators + * That needs to be specified in your thing. e.g. Mike has "a carrot", Greg wants "balls", Bob likes "the Boston Red Sox". + */ + + /* + * Future work on this module might produce more complex activities with targets, e.g. Phillip likes Karen's moustache + * and to describe other non-thing objects like channels, such as Karl wants Susan - where Susan represents a channel profile. + */ + + if((! $name) || (! $translated_verb)) + return; + + if($term_hash) { + $t = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($term_hash) + ); + if(! $t) { + notice( t('Item not found.') . EOL); + return; + } + $orig_record = $t[0]; + if($photo != $orig_record['imgurl']) { + $arr = import_profile_photo($photo,get_observer_hash(),true); + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } + else + $local_photo = $orig_record['imgurl']; + + $r = q("update term set term = '%s', url = '%s', imgurl = '%s' where term_hash = '%s' and uid = %d", + dbesc($name), + dbesc(($url) ? $url : z_root() . '/thing/' . $term_hash), + dbesc($local_photo), + dbesc($term_hash), + intval(local_channel()) + ); + + info( t('Thing updated') . EOL); + return; + } + + $sql = (($profile_guid) ? " and profile_guid = '" . dbesc($profile_guid) . "' " : " and is_default = 1 "); + $p = q("select profile_guid, is_default from profile where uid = %d $sql limit 1", + intval(local_channel()) + ); + + if($p) + $profile = $p[0]; + else + return; + + $local_photo = null; + + if($photo) { + $arr = import_profile_photo($photo,get_observer_hash(),true); + $local_photo = $arr[0]; + $local_photo_type = $arr[3]; + } + + $r = q("select * from term where uid = %d and otype = %d and type = %d and term = '%s' limit 1", + intval(local_channel()), + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name) + ); + if(! $r) { + $r = q("insert into term ( aid, uid, oid, otype, type, term, url, imgurl, term_hash ) + values( %d, %d, %d, %d, %d, '%s', '%s', '%s', '%s' ) ", + intval($account_id), + intval(local_channel()), + 0, + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name), + dbesc(($url) ? $url : z_root() . '/thing/' . $hash), + dbesc(($photo) ? $local_photo : ''), + dbesc($hash) + ); + $r = q("select * from term where uid = %d and otype = %d and type = %d and term = '%s' limit 1", + intval(local_channel()), + intval(TERM_OBJ_THING), + intval(TERM_THING), + dbesc($name) + ); + } + $term = $r[0]; + + $r = q("insert into obj ( obj_page, obj_verb, obj_type, obj_channel, obj_obj) values ('%s','%s', %d, %d, '%s') ", + dbesc($profile['profile_guid']), + dbesc($verb), + intval(TERM_OBJ_THING), + intval(local_channel()), + dbesc($term['term_hash']) + ); + + if(! $r) { + notice( t('Object store: failed')); + return; + } + + info( t('Thing added')); + + if($activity) { + $arr = array(); + $links = array(array('rel' => 'alternate','type' => 'text/html', 'href' => $term['url'])); + if($local_photo) + $links[] = array('rel' => 'photo', 'type' => $local_photo_type, 'href' => $local_photo); + + $objtype = ACTIVITY_OBJ_THING; + + $obj = json_encode(array( + 'type' => $objtype, + 'id' => $term['url'], + 'link' => $links, + 'title' => $term['term'], + 'content' => $term['term'] + )); + + $bodyverb = str_replace('OBJ: ', '',t('OBJ: %1$s %2$s %3$s')); + + $arr['owner_xchan'] = $channel['channel_hash']; + $arr['author_xchan'] = $channel['channel_hash']; + + $arr['item_origin'] = 1; + $arr['item_wall'] = 1; + $arr['item_thread_top'] = 1; + + $ulink = '[zrl=' . $channel['xchan_url'] . ']' . $channel['channel_name'] . '[/zrl]'; + $plink = '[zrl=' . $term['url'] . ']' . $term['term'] . '[/zrl]'; + + $arr['body'] = sprintf( $bodyverb, $ulink, $translated_verb, $plink ); + + if($local_photo) + $arr['body'] .= "\n\n[zmg]" . $local_photo . "[/zmg]"; + + $arr['verb'] = $verb; + $arr['obj_type'] = $objtype; + $arr['object'] = $obj; + + if(! $profile['is_default']) { + $arr['item_private'] = true; + $str = ''; + $r = q("select abook_xchan from abook where abook_channel = %d and abook_profile = '%s'", + intval(local_channel()), + dbesc($profile_guid) + ); + if($r) { + $arr['allow_cid'] = ''; + foreach($r as $rr) + $arr['allow_cid'] .= '<' . $rr['abook_xchan'] . '>'; + } + else + $arr['allow_cid'] = '<' . get_observer_hash() . '>'; + } + + $ret = post_activity_item($arr); + } +} + + +function thing_content(&$a) { + + if(argc() == 2) { + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc(argv(1)) + ); + + if($r) { + return replace_macros(get_markup_template('show_thing.tpl'), array( + '$header' => t('Show Thing'), + '$edit' => t('Edit'), + '$delete' => t('Delete'), + '$canedit' => ((local_channel() && local_channel() == $r[0]['obj_channel']) ? true : false), + '$thing' => $r[0] )); + } + else { + notice( t('item not found.') . EOL); + return; + } + } + + $channel = $a->get_channel(); + + if(! (local_channel() && $channel)) { + notice( t('Permission denied.') . EOL); + return; + } + + $thing_hash = ''; + + if(argc() == 3 && argv(1) === 'edit') { + $thing_hash = argv(2); + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if((! $r) || ($r[0]['obj_channel'] != local_channel())) { + notice( t('Permission denied.') . EOL); + return ''; + } + + $o .= replace_macros(get_markup_template('thing_edit.tpl'),array( + '$thing_hdr' => t('Edit Thing'), + '$multiprof' => feature_enabled(local_channel(),'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign($r[0]['obj_page']), + '$verb_lbl' => $channel['channel_name'], + '$verb_select' => obj_verb_selector($r[0]['obj_verb']), + '$activity' => array('activity',t('Post an activity'),true,t('Only sends to viewers of the applicable profile')), + '$thing_hash' => $thing_hash, + '$thing_lbl' => t('Name of thing e.g. something'), + '$thething' => $r[0]['term'], + '$url_lbl' => t('URL of thing (optional)'), + '$theurl' => $r[0]['url'], + '$img_lbl' => t('URL for photo of thing (optional)'), + '$imgurl' => $r[0]['imgurl'], + '$submit' => t('Submit') + )); + + return $o; + } + + if(argc() == 3 && argv(1) === 'drop') { + $thing_hash = argv(2); + + $r = q("select * from obj left join term on obj_obj = term_hash where term_hash != '' and obj_type = %d and term_hash = '%s' limit 1", + intval(TERM_OBJ_THING), + dbesc($thing_hash) + ); + + if((! $r) || ($r[0]['obj_channel'] != local_channel())) { + notice( t('Permission denied.') . EOL); + return ''; + } + + $x = q("delete from obj where obj_obj = '%s' and obj_type = %d and obj_channel = %d", + dbesc($thing_hash), + intval(TERM_OBJ_THING), + intval(local_channel()) + ); + $x = q("delete from term where term_hash = '%s' and uid = %d", + dbesc($thing_hash), + intval(local_channel()) + ); + + return $o; + } + + $o .= replace_macros(get_markup_template('thing_input.tpl'),array( + '$thing_hdr' => t('Add Thing to your Profile'), + '$multiprof' => feature_enabled(local_channel(),'multi_profiles'), + '$profile_lbl' => t('Select a profile'), + '$profile_select' => contact_profile_assign(''), + '$verb_lbl' => $channel['channel_name'], + '$activity' => array('activity',t('Post an activity'),((array_key_exists('activity',$_REQUEST)) ? $_REQUEST['activity'] : true),t('Only sends to viewers of the applicable profile')), + '$verb_select' => obj_verb_selector(), + '$thing_lbl' => t('Name of thing e.g. something'), + '$url_lbl' => t('URL of thing (optional)'), + '$img_lbl' => t('URL for photo of thing (optional)'), + '$submit' => t('Submit') + )); + + return $o; +} diff --git a/sources/mod/toggle_mobile.php b/sources/mod/toggle_mobile.php new file mode 100644 index 00000000..06dadca0 --- /dev/null +++ b/sources/mod/toggle_mobile.php @@ -0,0 +1,17 @@ +get_baseurl(); + + goaway($address); +} + diff --git a/sources/mod/toggle_safesearch.php b/sources/mod/toggle_safesearch.php new file mode 100644 index 00000000..3c800c4f --- /dev/null +++ b/sources/mod/toggle_safesearch.php @@ -0,0 +1,25 @@ + 1) { + $channel = $a->get_channel(); + + require_once('include/identity.php'); + + if(argc() > 1 && intval(argv(1)) > 1900) { + $year = intval(argv(1)); + } + + if(argc() > 2 && intval(argv(2)) > 0 && intval(argv(2)) <= 12) { + $month = intval(argv(2)); + } + + header('content-type: application/octet_stream'); + header('content-disposition: attachment; filename="' . $channel['channel_address'] . (($year) ? '-' . $year : '') . (($month) ? '-' . $month : '') . '.json"' ); + + if($year) { + echo json_encode(identity_export_year(local_channel(),$year,$month)); + killme(); + } + + if(argc() > 1 && argv(1) === 'basic') { + echo json_encode(identity_basic_export(local_channel())); + killme(); + } + + // FIXME - this basically doesn't work in the wild with a channel more than a few months old due to memory and execution time limits. + // It probably needs to be built at the CLI and offered to download as a tarball. Maybe stored in the members dav. + + if(argc() > 1 && argv(1) === 'complete') { + echo json_encode(identity_basic_export(local_channel(),true)); + killme(); + } + } +} + +function uexport_content(&$a) { + $o = replace_macros(get_markup_template('uexport.tpl'), array( + '$title' => t('Export Channel'), + '$basictitle' => t('Export Channel'), + '$basic' => t('Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but does not contain your content.'), + '$fulltitle' => t('Export Content'), + '$full' => t('Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and the last year of posts. This file may be VERY large. Please be patient - it may take several minutes for this download to begin.'), + '$by_year' => t('Export your posts from a given year.'), + + )); +return $o; +} diff --git a/sources/mod/update_channel.php b/sources/mod/update_channel.php new file mode 100644 index 00000000..5f4436d5 --- /dev/null +++ b/sources/mod/update_channel.php @@ -0,0 +1,63 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + + header("Content-type: text/html"); + echo "\r\n"; + + /** + * We can remove this hack once Internet Explorer recognises HTML5 natively + */ + + echo (($_GET['msie'] == 1) ? '
    ' : '
    '); + + /** + * + * Grab the page inner contents by calling the content function from the profile module directly, + * but move any image src attributes to another attribute name. This is because + * some browsers will prefetch all the images for the page even if we don't need them. + * The only ones we need to fetch are those for new page additions, which we'll discover + * on the client side and then swap the image back. + * + */ + + $text = channel_content($a,$profile_uid,$load); + + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + /** + * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well + */ + + echo str_replace("\t",' ',$text); + echo (($_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; + killme(); + +} \ No newline at end of file diff --git a/sources/mod/update_display.php b/sources/mod/update_display.php new file mode 100644 index 00000000..d41e2e5c --- /dev/null +++ b/sources/mod/update_display.php @@ -0,0 +1,42 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + header("Content-type: text/html"); + echo "\r\n"; + echo (($_GET['msie'] == 1) ? '
    ' : '
    '); + + + $text = display_content($a,$profile_uid, $load); + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + echo str_replace("\t",' ',$text); + echo (($_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; +// logger('update_display: ' . $text); + killme(); + +} \ No newline at end of file diff --git a/sources/mod/update_home.php b/sources/mod/update_home.php new file mode 100644 index 00000000..80ae2438 --- /dev/null +++ b/sources/mod/update_home.php @@ -0,0 +1,38 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + header("Content-type: text/html"); + echo "\r\n"; + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : '
    '); + + $text = home_content($a,$profile_uid, $load); + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + echo str_replace("\t",' ',$text); + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; +// logger('update_home: ' . $text); + killme(); + +} \ No newline at end of file diff --git a/sources/mod/update_network.php b/sources/mod/update_network.php new file mode 100644 index 00000000..acd5ccdc --- /dev/null +++ b/sources/mod/update_network.php @@ -0,0 +1,40 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + header("Content-type: text/html"); + echo "\r\n"; + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : '
    '); + + + $text = network_content($a,$profile_uid, $load); + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + echo str_replace("\t",' ',$text); + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; +// logger('update_network: ' . $text); + killme(); + +} \ No newline at end of file diff --git a/sources/mod/update_public.php b/sources/mod/update_public.php new file mode 100644 index 00000000..bac1ccf1 --- /dev/null +++ b/sources/mod/update_public.php @@ -0,0 +1,37 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + header("Content-type: text/html"); + echo "\r\n"; + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : '
    '); + + $text = public_content($a,$profile_uid, $load); + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + echo str_replace("\t",' ',$text); + echo ((array_key_exists('msie',$_GET) && $_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; + killme(); + +} \ No newline at end of file diff --git a/sources/mod/update_search.php b/sources/mod/update_search.php new file mode 100644 index 00000000..de29e89b --- /dev/null +++ b/sources/mod/update_search.php @@ -0,0 +1,66 @@ + 1) && (argv(1) == 'load')) ? 1 : 0); + + header("Content-type: text/html"); + echo "\r\n"; + + /** + * We can remove this hack once Internet Explorer recognises HTML5 natively + */ + + echo (($_GET['msie'] == 1) ? '
    ' : '
    '); + + /** + * + * Grab the page inner contents by calling the content function from the profile module directly, + * but move any image src attributes to another attribute name. This is because + * some browsers will prefetch all the images for the page even if we don't need them. + * The only ones we need to fetch are those for new page additions, which we'll discover + * on the client side and then swap the image back. + * + */ + + $text = search_content($a,$profile_uid,$load); + + $pattern = "/]*) src=\"([^\"]*)\"/"; + $replace = "'; + $pattern = "/<\s*audio[^>]*>(.*?)<\s*\/\s*audio>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*video[^>]*>(.*?)<\s*\/\s*video>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*embed[^>]*>(.*?)<\s*\/\s*embed>/i"; + $text = preg_replace($pattern, $replace, $text); + $pattern = "/<\s*iframe[^>]*>(.*?)<\s*\/\s*iframe>/i"; + $text = preg_replace($pattern, $replace, $text); + } + + /** + * reportedly some versions of MSIE don't handle tabs in XMLHttpRequest documents very well + */ + + echo str_replace("\t",' ',$text); + echo (($_GET['msie'] == 1) ? '
    ' : ''); + echo "\r\n"; + killme(); + +} \ No newline at end of file diff --git a/sources/mod/urlinfo.php b/sources/mod/urlinfo.php new file mode 100644 index 00000000..6b9be3f6 --- /dev/null +++ b/sources/mod/urlinfo.php @@ -0,0 +1,383 @@ + + + + + +

    Shiny Trinket

    + +

    Shiny trinkets are shiny.

    + +*/ + +if(!function_exists('deletenode')) { + function deletenode(&$doc, $node) + { + $xpath = new DomXPath($doc); + $list = $xpath->query("//".$node); + foreach ($list as $child) + $child->parentNode->removeChild($child); + } +} + +function completeurl($url, $scheme) { + $urlarr = parse_url($url); + + if (isset($urlarr["scheme"])) + return($url); + + $schemearr = parse_url($scheme); + + $complete = $schemearr["scheme"]."://".$schemearr["host"]; + + if ($schemearr["port"] != "") + $complete .= ":".$schemearr["port"]; + + if(strpos($urlarr['path'],'/') !== 0) + $complete .= '/'; + + $complete .= $urlarr["path"]; + + if ($urlarr["query"] != "") + $complete .= "?".$urlarr["query"]; + + if ($urlarr["fragment"] != "") + $complete .= "#".$urlarr["fragment"]; + + return($complete); +} + +function parseurl_getsiteinfo($url) { + $siteinfo = array(); + + + $result = z_fetch_url($url,false,0,array('novalidate' => true)); + if(! $result['success']) + return $siteinfo; + + $header = $result['header']; + $body = $result['body']; + + $body = mb_convert_encoding($body, 'UTF-8', 'UTF-8'); + $body = mb_convert_encoding($body, 'HTML-ENTITIES', "UTF-8"); + + $doc = new DOMDocument(); + @$doc->loadHTML($body); + + deletenode($doc, 'style'); + deletenode($doc, 'script'); + deletenode($doc, 'option'); + deletenode($doc, 'h1'); + deletenode($doc, 'h2'); + deletenode($doc, 'h3'); + deletenode($doc, 'h4'); + deletenode($doc, 'h5'); + deletenode($doc, 'h6'); + deletenode($doc, 'ol'); + deletenode($doc, 'ul'); + + $xpath = new DomXPath($doc); + + //$list = $xpath->query("head/title"); + $list = $xpath->query("//title"); + foreach ($list as $node) + $siteinfo["title"] = html_entity_decode($node->nodeValue, ENT_QUOTES, "UTF-8"); + + //$list = $xpath->query("head/meta[@name]"); + $list = $xpath->query("//meta[@name]"); + foreach ($list as $node) { + $attr = array(); + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); + + switch (strtolower($attr["name"])) { + case 'generator': + $siteinfo['generator'] = $attr['content']; + break; + case "fulltitle": + $siteinfo["title"] = $attr["content"]; + break; + case "description": + $siteinfo["text"] = $attr["content"]; + break; + case "dc.title": + $siteinfo["title"] = $attr["content"]; + break; + case "dc.description": + $siteinfo["text"] = $attr["content"]; + break; + } + } + + //$list = $xpath->query("head/meta[@property]"); + $list = $xpath->query("//meta[@property]"); + foreach ($list as $node) { + $attr = array(); + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $attr["content"] = html_entity_decode($attr["content"], ENT_QUOTES, "UTF-8"); + + switch (strtolower($attr["property"])) { + case "og:image": + $siteinfo["image"] = $attr["content"]; + break; + case "og:title": + $siteinfo["title"] = $attr["content"]; + break; + case "og:description": + $siteinfo["text"] = $attr["content"]; + break; + } + } + + if ($siteinfo["image"] == "") { + $list = $xpath->query("//img[@src]"); + foreach ($list as $node) { + $attr = array(); + if ($node->attributes->length) + foreach ($node->attributes as $attribute) + $attr[$attribute->name] = $attribute->value; + + $src = completeurl($attr["src"], $url); + $photodata = @getimagesize($src); + + if (($photodata) && ($photodata[0] > 150) and ($photodata[1] > 150)) { + if ($photodata[0] > 300) { + $photodata[1] = round($photodata[1] * (300 / $photodata[0])); + $photodata[0] = 300; + } + if ($photodata[1] > 300) { + $photodata[0] = round($photodata[0] * (300 / $photodata[1])); + $photodata[1] = 300; + } + $siteinfo["images"][] = array("src"=>$src, + "width"=>$photodata[0], + "height"=>$photodata[1]); + } + + } + } else { + $src = completeurl($siteinfo["image"], $url); + + unset($siteinfo["image"]); + + $photodata = @getimagesize($src); + + if (($photodata) && ($photodata[0] > 10) and ($photodata[1] > 10)) + $siteinfo["images"][] = array("src"=>$src, + "width"=>$photodata[0], + "height"=>$photodata[1]); + } + + if ($siteinfo["text"] == "") { + $text = ""; + + $list = $xpath->query("//div[@class='article']"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " ".trim($node->nodeValue); + + if ($text == "") { + $list = $xpath->query("//div[@class='content']"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " ".trim($node->nodeValue); + } + + // If none text was found then take the paragraph content + if ($text == "") { + $list = $xpath->query("//p"); + foreach ($list as $node) + if (strlen($node->nodeValue) > 40) + $text .= " ".trim($node->nodeValue); + } + + if ($text != "") { + $text = trim(str_replace(array("\n", "\r"), array(" ", " "), $text)); + + while (strpos($text, " ")) + $text = trim(str_replace(" ", " ", $text)); + + $siteinfo["text"] = html_entity_decode(substr($text,0,350), ENT_QUOTES, "UTF-8").'...'; + } + } + + return($siteinfo); +} + +function arr_add_hashes(&$item,$k) { + $item = '#' . $item; +} + +function urlinfo_content(&$a) { + + logger('urlinfo: ' . print_r($_REQUEST,true)); + + $text = null; + $str_tags = ''; + + + $br = "\n"; + + if(x($_GET,'binurl')) + $url = trim(hex2bin($_GET['binurl'])); + else + $url = trim($_GET['url']); + + if((substr($url,0,1) != '/') && (substr($url,0,4) != 'http')) + $url = 'http://' . $url; + + + if($_GET['title']) + $title = strip_tags(trim($_GET['title'])); + + if($_GET['description']) + $text = strip_tags(trim($_GET['description'])); + + if($_GET['tags']) { + $arr_tags = str_getcsv($_GET['tags']); + if(count($arr_tags)) { + array_walk($arr_tags,'arr_add_hashes'); + $str_tags = $br . implode(' ',$arr_tags) . $br; + } + } + + logger('urlinfo: ' . $url); + + $result = z_fetch_url($url,false,0,array('novalidate' => true, 'nobody' => true)); + if($result['success']) { + $hdrs=array(); + $h = explode("\n",$result['header']); + foreach ($h as $l) { + list($k,$v) = array_map("trim", explode(":", trim($l), 2)); + $hdrs[$k] = $v; + } + if (array_key_exists('Content-Type', $hdrs)) + $type = $hdrs['Content-Type']; + if($type) { + $zrl = is_matrix_url($url); + if(stripos($type,'image/') !== false) { + if($zrl) + echo $br . '[zmg]' . $url . '[/zmg]' . $br; + else + echo $br . '[img]' . $url . '[/img]' . $br; + killme(); + } + if(stripos($type,'video/') !== false) { + if($zrl) + echo $br . '[zvideo]' . $url . '[/zvideo]' . $br; + else + echo $br . '[video]' . $url . '[/video]' . $br; + killme(); + } + if(stripos($type,'audio/') !== false) { + if($zrl) + echo $br . '[zaudio]' . $url . '[/zaudio]' . $br; + else + echo $br . '[audio]' . $url . '[/audio]' . $br; + killme(); + } + } + } + + $template = $br . '#^[url=%s]%s[/url]%s' . $br; + + $arr = array('url' => $url, 'text' => ''); + + call_hooks('parse_link', $arr); + + if(strlen($arr['text'])) { + echo $arr['text']; + killme(); + } + + $x = oembed_process($url); + if($x) { + echo $x; + killme(); + } + + if($url && $title && $text) { + + + $text = $br . '[quote]' . trim($text) . '[/quote]' . $br; + + $title = str_replace(array("\r","\n"),array('',''),$title); + + $result = sprintf($template,$url,($title) ? $title : $url,$text) . $str_tags; + + logger('urlinfo (unparsed): returns: ' . $result); + + echo $result; + killme(); + } + + $siteinfo = parseurl_getsiteinfo($url); + + // If this is a Red site, use zrl rather than url so they get zids sent to them by default + + if( x($siteinfo,'generator') && (strpos($siteinfo['generator'],PLATFORM_NAME . ' ') === 0)) + $template = str_replace('url','zrl',$template); + + if($siteinfo["title"] == "") { + echo sprintf($template,$url,$url,'') . $str_tags; + killme(); + } else { + $text = $siteinfo["text"]; + $title = $siteinfo["title"]; + } + + $image = ""; + + if(sizeof($siteinfo["images"]) > 0){ + /* Execute below code only if image is present in siteinfo */ + + $total_images = 0; + $max_images = get_config('system','max_bookmark_images'); + if($max_images === false) + $max_images = 2; + else + $max_images = intval($max_images); + + foreach ($siteinfo["images"] as $imagedata) { + if ($url) { + $image .= sprintf('[url=%s]', $url); + } + $image .= '[img='.$imagedata["width"].'x'.$imagedata["height"].']'.$imagedata["src"].'[/img]'; + if ($url) { + $image .= '[/url]'; + } + $image .= "\n"; + $total_images ++; + if($max_images && $max_images >= $total_images) + break; + } + } + + if(strlen($text)) { + $text = $br.'[quote]'.trim($text).'[/quote]'.$br ; + } + + if($image) { + $text = $br.$br.$image.$text; + } + $title = str_replace(array("\r","\n"),array('',''),$title); + + $result = sprintf($template,$url,($title) ? $title : $url,$text) . $str_tags; + + logger('urlinfo: returns: ' . $result, LOGGER_DEBUG); + + echo trim($result); + killme(); +} diff --git a/sources/mod/view.php b/sources/mod/view.php new file mode 100644 index 00000000..d4381743 --- /dev/null +++ b/sources/mod/view.php @@ -0,0 +1,15 @@ + 1) + profile_load($a,argv(1)); +} + +function viewconnections_content(&$a) { + + if((get_config('system','block_public')) && (! local_channel()) && (! remote_channel())) { + notice( t('Public access denied.') . EOL); + return; + } + + if(((! count($a->profile)) || ($a->profile['hide_friends']))) { + notice( t('Permission denied.') . EOL); + return; + } + + if(! perm_is_allowed($a->profile['uid'], get_observer_hash(),'view_contacts')) { + notice( t('Permission denied.') . EOL); + return; + } + + if(! $_REQUEST['aj']) + $_SESSION['return_url'] = $a->query_string; + + + $is_owner = ((local_channel() && local_channel() == $a->profile['uid']) ? true : false); + + $abook_flags = " and abook_pending = 0 and abook_self = 0 "; + $sql_extra = ''; + + if(! $is_owner) { + $abook_flags = " and abook_hidden = 0 "; + $sql_extra = " and xchan_hidden = 0 "; + } + + $r = q("SELECT count(*) as total FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra ", + intval($a->profile['uid']) + ); + if($r) { + $a->set_pager_total($r[0]['total']); + } + + $r = q("SELECT * FROM abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d $abook_flags and xchan_orphan = 0 and xchan_deleted = 0 $sql_extra order by xchan_name LIMIT %d OFFSET %d ", + intval($a->profile['uid']), + intval($a->pager['itemspage']), + intval($a->pager['start']) + ); + + if((! $r) && (! $_REQUEST['aj'])) { + info( t('No connections.') . EOL ); + return $o; + } + + $contacts = array(); + + foreach($r as $rr) { + + $url = chanlink_url($rr['xchan_url']); + if($url) { + $contacts[] = array( + 'id' => $rr['abook_id'], + 'archived' => (intval($rr['abook_archived']) ? true : false), + 'img_hover' => sprintf( t('Visit %s\'s profile [%s]'), $rr['xchan_name'], $rr['xchan_url']), + 'thumb' => $rr['xchan_photo_m'], + 'name' => substr($rr['xchan_name'],0,20), + 'username' => $rr['xchan_addr'], + 'link' => $url, + 'sparkle' => '', + 'itemurl' => $rr['url'], + 'network' => '', + ); + } + } + + + if($_REQUEST['aj']) { + if($contacts) { + $o = replace_macros(get_markup_template('viewcontactsajax.tpl'),array( + '$contacts' => $contacts + )); + } + else { + $o = '
    '; + } + echo $o; + killme(); + } + else { + $o .= ""; + $tpl = get_markup_template("viewcontact_template.tpl"); + $o .= replace_macros($tpl, array( + '$title' => t('View Connections'), + '$contacts' => $contacts, +// '$paginate' => paginate($a), + )); + } + + if(! $contacts) + $o .= '
    '; + + return $o; +} diff --git a/sources/mod/viewsrc.php b/sources/mod/viewsrc.php new file mode 100644 index 00000000..cffb01b6 --- /dev/null +++ b/sources/mod/viewsrc.php @@ -0,0 +1,47 @@ + 1) ? intval(argv(1)) : 0); + $json = ((argc() > 2 && argv(2) === 'json') ? true : false); + + if(! local_channel()) { + notice( t('Permission denied.') . EOL); + } + + + if(! $item_id) { + $a->error = 404; + notice( t('Item not found.') . EOL); + } + + $item_normal = item_normal(); + + if(local_channel() && $item_id) { + $r = q("select id, item_flags, item_obscured, body from item where uid in (%d , %d) and id = %d $item_normal limit 1", + intval(local_channel()), + intval($sys['channel_id']), + intval($item_id) + ); + + if($r) { + if(intval($r[0]['item_obscured'])) + $r[0]['body'] = crypto_unencapsulate(json_decode($r[0]['body'],true),get_config('system','prvkey')); + $o = (($json) ? json_encode($r[0]['body']) : str_replace("\n",'
    ',$r[0]['body'])); + } + } + + if(is_ajax()) { + print '
    ' . t('Source of Item') . ' ' . $r[0]['id'] . '
    '; + echo $o; + killme(); + } + + return $o; +} + diff --git a/sources/mod/wall_attach.php b/sources/mod/wall_attach.php new file mode 100644 index 00000000..8677c2b8 --- /dev/null +++ b/sources/mod/wall_attach.php @@ -0,0 +1,60 @@ + 1) + $channel = get_channel_by_nick(argv(1)); + elseif($_FILES['media']) { + require_once('include/api.php'); + $user_info = api_get_user($a); + $nick = $user_info['screen_name']; + $channel = get_channel_by_nick($user_info['screen_name']); + } + + if(! $channel) + killme(); + + $observer = $a->get_observer(); + + +// if($_FILES['userfile']['tmp_name']) { +// $x = @getimagesize($_FILES['userfile']['tmp_name']); +// logger('getimagesize: ' . print_r($x,true), LOGGER_DATA); +// if(($x) && ($x[2] === IMAGETYPE_GIF || $x[2] === IMAGETYPE_JPEG || $x[2] === IMAGETYPE_PNG)) { +// $args = array( 'source' => 'editor', 'visible' => 0, 'contact_allow' => array($channel['channel_hash'])); +// $ret = photo_upload($channel,$observer,$args); +// if($ret['success']) { +// echo "\n\n" . $ret['body'] . "\n\n"; +// killme(); +// } +// if($using_api) +// return; +// notice($ret['message']); +// killme(); +// } +// } + + $def_album = get_pconfig($channel['channel_id'],'system','photo_path'); + $def_attach = get_pconfig($channel['channel_id'],'system','attach_path'); + + $r = attach_store($channel,(($observer) ? $observer['xchan_hash'] : ''),'', array('source' => 'editor', 'visible' => 0, 'album' => $def_album, 'directory' => $def_attach, 'allow_cid' => '<' . $channel['channel_hash'] . '>')); + + if(! $r['success']) { + notice( $r['message'] . EOL); + killme(); + } + + if(intval($r['data']['is_photo'])) { + echo "\n\n" . $r['body'] . "\n\n"; + if($using_api) + return; + killme(); + } + echo "\n\n" . '[attachment]' . $r['data']['hash'] . ',' . $r['data']['revision'] . '[/attachment]' . "\n"; + killme(); + +} diff --git a/sources/mod/wall_upload.php b/sources/mod/wall_upload.php new file mode 100644 index 00000000..31a497f0 --- /dev/null +++ b/sources/mod/wall_upload.php @@ -0,0 +1,51 @@ + 1) + $nick = argv(1); + } + + $channel = (($nick) ? get_channel_by_nick($nick) : false); + + if(! $channel) { + if($using_api) + return; + notice( t('Channel not found.') . EOL); + killme(); + } + + $observer = $a->get_observer(); + + $args = array( 'source' => 'editor', 'visible' => 0, 'contact_allow' => array($channel['channel_hash'])); + + $ret = photo_upload($channel,$observer,$args); + + if(! $ret['success']) { + if($using_api) + return; + notice($ret['message']); + killme(); + } + + if($using_api) + return("\n\n" . $ret['body'] . "\n\n"); + else + echo "\n\n" . $ret['body'] . "\n\n"; + killme(); +} diff --git a/sources/mod/webfinger.php b/sources/mod/webfinger.php new file mode 100644 index 00000000..a646961a --- /dev/null +++ b/sources/mod/webfinger.php @@ -0,0 +1,31 @@ +Webfinger Diagnostic'; + + $o .= '
    '; + $o .= 'Lookup address: '; + $o .= '
    '; + + $o .= '

    '; + + if(x($_GET,'addr')) { + $addr = trim($_GET['addr']); + if(strpos($addr,'@') !== false) { + $res = webfinger_rfc7033($addr); + if(! $res) + $res = old_webfinger($addr); + } + else { + if(function_exists('lrdd')) + $res = lrdd($addr); + } + $o .= '
    ';
    +		$o .= str_replace("\n",'
    ',print_r($res,true)); + $o .= '
    '; + } + return $o; +} diff --git a/sources/mod/webpages.php b/sources/mod/webpages.php new file mode 100644 index 00000000..8e12b591 --- /dev/null +++ b/sources/mod/webpages.php @@ -0,0 +1,197 @@ + 1 && argv(1) === 'sys' && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $a->is_sys = true; + } + } + + if(argc() > 1) + $which = argv(1); + else + return; + + profile_load($a,$which); + +} + + +function webpages_content(&$a) { + + if(! $a->profile) { + notice( t('Requested profile is not available.') . EOL ); + $a->error = 404; + return; + } + + $which = argv(1); + + $_SESSION['return_url'] = $a->query_string; + + $uid = local_channel(); + $owner = 0; + $channel = null; + $observer = $a->get_observer(); + + $channel = $a->get_channel(); + + if($a->is_sys && is_site_admin()) { + $sys = get_sys_channel(); + if($sys && intval($sys['channel_id'])) { + $uid = $owner = intval($sys['channel_id']); + $channel = $sys; + $observer = $sys; + } + } + + if(! $owner) { + // Figure out who the page owner is. + $r = q("select channel_id from channel where channel_address = '%s'", + dbesc($which) + ); + if($r) { + $owner = intval($r[0]['channel_id']); + } + } + + $ob_hash = (($observer) ? $observer['xchan_hash'] : ''); + + $perms = get_all_perms($owner,$ob_hash); + + if(! $perms['write_pages']) { + notice( t('Permission denied.') . EOL); + return; + } + + $mimetype = (($_REQUEST['mimetype']) ? $_REQUEST['mimetype'] : get_pconfig($owner,'system','page_mimetype')); + + if(! $mimetype) { + $mimetype = 'choose'; + } + + $layout = (($_REQUEST['layout']) ? $_REQUEST['layout'] : get_pconfig($owner,'system','page_layout')); + if(! $layout) + $layout = 'choose'; + + // Create a status editor (for now - we'll need a WYSIWYG eventually) to create pages + // Nickname is set to the observers xchan, and profile_uid to the owner's. + // This lets you post pages at other people's channels. + + if((! $channel) && ($uid) && ($uid == $a->profile_uid)) { + $channel = $a->get_channel(); + } + if($channel) { + $channel_acl = array( + 'allow_cid' => $channel['channel_allow_cid'], + 'allow_gid' => $channel['channel_allow_gid'], + 'deny_cid' => $channel['channel_deny_cid'], + 'deny_gid' => $channel['channel_deny_gid'] + ); + } + else + $channel_acl = array(); + + $is_owner = ($uid && $uid == $owner); + $o = profile_tabs($a, $is_owner, $a->profile['channel_address']); + + $x = array( + 'webpage' => ITEM_TYPE_WEBPAGE, + 'is_owner' => true, + 'nickname' => $a->profile['channel_address'], + 'lockstate' => (($channel['channel_allow_cid'] || $channel['channel_allow_gid'] || $channel['channel_deny_cid'] || $channel['channel_deny_gid']) ? 'lock' : 'unlock'), + 'bang' => '', + 'acl' => (($is_owner) ? populate_acl($channel_acl,false) : ''), + 'showacl' => (($is_owner) ? true : false), + 'visitor' => true, + 'profile_uid' => intval($owner), + 'mimetype' => $mimetype, + 'layout' => $layout, + 'expanded' => true, + 'novoting' => true + ); + + if($_REQUEST['title']) + $x['title'] = $_REQUEST['title']; + if($_REQUEST['body']) + $x['body'] = $_REQUEST['body']; + if($_REQUEST['pagetitle']) + $x['pagetitle'] = $_REQUEST['pagetitle']; + + $editor = status_editor($a,$x); + + // Get a list of webpages. We can't display all them because endless scroll makes that unusable, + // so just list titles and an edit link. + /** @TODO - this should be replaced with pagelist_widget */ + + $sql_extra = item_permissions_sql($owner); + + $r = q("select * from item_id left join item on item_id.iid = item.id + where item_id.uid = %d and service = 'WEBPAGE' and item_type = %d $sql_extra order by item.created desc", + intval($owner), + intval(ITEM_TYPE_WEBPAGE) + ); + + $pages = null; + + if($r) { + $pages = array(); + foreach($r as $rr) { + unobscure($rr); + + $lockstate = (($rr['allow_cid'] || $rr['allow_gid'] || $rr['deny_cid'] || $rr['deny_gid']) ? 'lock' : 'unlock'); + + $element_arr = array( + 'type' => 'webpage', + 'title' => $rr['title'], + 'body' => $rr['body'], + 'created' => $rr['created'], + 'edited' => $rr['edited'], + 'mimetype' => $rr['mimetype'], + 'pagetitle' => $rr['sid'], + 'mid' => $rr['mid'], + 'layout_mid' => $rr['layout_mid'] + ); + $pages[$rr['iid']][] = array( + 'url' => $rr['iid'], + 'pagetitle' => $rr['sid'], + 'title' => $rr['title'], + 'created' => datetime_convert('UTC',date_default_timezone_get(),$rr['created']), + 'edited' => datetime_convert('UTC',date_default_timezone_get(),$rr['edited']), + 'bb_element' => '[element]' . base64url_encode(json_encode($element_arr)) . '[/element]', + 'lockstate' => $lockstate + ); + } + } + + + //Build the base URL for edit links + $url = z_root() . '/editwebpage/' . $which; + + $o .= replace_macros(get_markup_template('webpagelist.tpl'), array( + '$listtitle' => t('Webpages'), + '$baseurl' => $url, + '$create' => t('Create'), + '$edit' => t('Edit'), + '$share' => t('Share'), + '$delete' => t('Delete'), + '$pages' => $pages, + '$channel' => $which, + '$editor' => $editor, + '$view' => t('View'), + '$preview' => t('Preview'), + '$actions_txt' => t('Actions'), + '$pagelink_txt' => t('Page Link'), + '$title_txt' => t('Page Title'), + '$created_txt' => t('Created'), + '$edited_txt' => t('Edited') + )); + + return $o; +} diff --git a/sources/mod/wfinger.php b/sources/mod/wfinger.php new file mode 100644 index 00000000..1493dd6b --- /dev/null +++ b/sources/mod/wfinger.php @@ -0,0 +1,120 @@ +get_hostname())) { + goaway('https://' . $host . '/.well-known/webfinger?resource=' . $resource); + } + $channel = substr($channel,0,strpos($channel,'@')); + } + } + if(strpos($resource,'http') === 0) { + $channel = str_replace('~','',basename($resource)); + } + + $r = q("select * from channel left join xchan on channel_hash = xchan_hash + where channel_address = '%s' limit 1", + dbesc($channel) + ); + + } + + + header('Access-Control-Allow-Origin: *'); + + header('Content-type: application/jrd+json'); + + + + if($resource && $r) { + + $h = q("select hubloc_addr from hubloc where hubloc_hash = '%s'", + dbesc($r[0]['channel_hash']) + ); + + $result['subject'] = $resource; + + $aliases = array( + z_root() . '/channel/' . $r[0]['channel_address'], + z_root() . '/~' . $r[0]['channel_address'] + ); + + if($h) { + foreach($h as $hh) { + $aliases[] = 'acct:' . $hh['hubloc_addr']; + } + } + + $result['aliases'] = array(); + + $result['properties'] = array('http://webfinger.net/ns/name' => $r[0]['channel_name']); + + foreach($aliases as $alias) + if($alias != $resource) + $result['aliases'][] = $alias; + + + $result['links'] = array( + + array( + 'rel' => 'http://webfinger.net/rel/avatar', + 'type' => $r[0]['xchan_photo_mimetype'], + 'href' => $r[0]['xchan_photo_l'] + ), + + array( + 'rel' => 'http://webfinger.net/rel/profile-page', + 'href' => z_root() . '/profile/' . $r[0]['channel_address'], + ), + + array( + 'rel' => 'http://webfinger.net/rel/blog', + 'href' => z_root() . '/channel/' . $r[0]['channel_address'], + ), + + array( + 'rel' => 'http://purl.org/zot/protocol', + 'href' => z_root() . '/.well-known/zot-info' . '?address=' . $r[0]['xchan_addr'], + ) + ); + + } + else { + header($_SERVER["SERVER_PROTOCOL"] . ' ' . 400 . ' ' . 'Bad Request'); + killme(); + } + + $arr = array('channel' => $r[0], 'request' => $_REQUEST, 'result' => $result); + call_hooks('webfinger',$arr); + + echo json_encode($arr['result']); + killme(); + +} \ No newline at end of file diff --git a/sources/mod/xchan.php b/sources/mod/xchan.php new file mode 100644 index 00000000..69fbdb77 --- /dev/null +++ b/sources/mod/xchan.php @@ -0,0 +1,41 @@ +' . t('Xchan Lookup') . ''; + + $o .= '
    '; + $o .= t('Lookup xchan beginning with (or webbie): '); + $o .= ''; + $o .= '
    '; + $o .= '

    '; + + if(x($_GET, 'addr')) { + $addr = trim($_GET['addr']); + + $r = q("select * from xchan where xchan_hash like '%s%%' or xchan_addr = '%s' group by xchan_hash", + dbesc($addr), + dbesc($addr) + ); + + if($r) { + foreach($r as $rr) { + $o .= str_replace(array("\n", " "), array("
    ", " "), print_r($rr, true)) . EOL; + + $s = q("select * from hubloc where hubloc_hash like '%s'", + dbesc($r[0]['xchan_hash']) + ); + + if($s) { + foreach($s as $rrr) + $o .= str_replace(array("\n", " "), array("
    ", " "), print_r($rrr, true)) . EOL; + } + } + } + else + notice( t('Not found.') . EOL); + + } + return $o; +} diff --git a/sources/mod/xpoco.php b/sources/mod/xpoco.php new file mode 100644 index 00000000..56096675 --- /dev/null +++ b/sources/mod/xpoco.php @@ -0,0 +1,7 @@ + $a->get_baseurl(), + '$dspr_guid' => $r[0]['channel_guid'], + '$dspr_key' => base64_encode(pemtorsa($r[0]['channel_pubkey'])) + )); + + $salmon_key = salmon_key($r[0]['channel_pubkey']); + + header('Access-Control-Allow-Origin: *'); + header("Content-type: text/xml"); + + + $tpl = get_markup_template('view/xrd_person.tpl'); + + $o = replace_macros(get_markup_template('xrd_person.tpl'), array( + '$nick' => $r[0]['channel_address'], + '$accturi' => $uri, + '$profile_url' => $a->get_baseurl() . '/channel/' . $r[0]['channel_address'], + '$hcard_url' => $a->get_baseurl() . '/hcard/' . $r[0]['channel_address'], + '$atom' => $a->get_baseurl() . '/feed/' . $r[0]['channel_address'], + '$zot_post' => $a->get_baseurl() . '/post/' . $r[0]['channel_address'], + '$poco_url' => $a->get_baseurl() . '/poco/' . $r[0]['channel_address'], + '$photo' => $a->get_baseurl() . '/photo/profile/l/' . $r[0]['channel_id'], + '$dspr' => $dspr, +// '$salmon' => $a->get_baseurl() . '/salmon/' . $r[0]['channel_address'], +// '$salmen' => $a->get_baseurl() . '/salmon/' . $r[0]['channel_address'] . '/mention', + '$modexp' => 'data:application/magic-public-key,' . $salmon_key, +// '$bigkey' => salmon_key($r[0]['pubkey']) + )); + + + $arr = array('user' => $r[0], 'xml' => $o); + call_hooks('personal_xrd', $arr); + + echo $arr['xml']; + killme(); + +} diff --git a/sources/mod/xref.php b/sources/mod/xref.php new file mode 100644 index 00000000..95cc22aa --- /dev/null +++ b/sources/mod/xref.php @@ -0,0 +1,20 @@ + 2) + $url = argv(2); + + goaway (z_root() . '/' . $url); + +} diff --git a/sources/mod/zfinger.php b/sources/mod/zfinger.php new file mode 100644 index 00000000..8ddd92f3 --- /dev/null +++ b/sources/mod/zfinger.php @@ -0,0 +1,301 @@ + false); + + $zhash = ((x($_REQUEST,'guid_hash')) ? $_REQUEST['guid_hash'] : ''); + $zguid = ((x($_REQUEST,'guid')) ? $_REQUEST['guid'] : ''); + $zguid_sig = ((x($_REQUEST,'guid_sig')) ? $_REQUEST['guid_sig'] : ''); + $zaddr = ((x($_REQUEST,'address')) ? $_REQUEST['address'] : ''); + $ztarget = ((x($_REQUEST,'target')) ? $_REQUEST['target'] : ''); + $zsig = ((x($_REQUEST,'target_sig')) ? $_REQUEST['target_sig'] : ''); + $zkey = ((x($_REQUEST,'key')) ? $_REQUEST['key'] : ''); + $mindate = ((x($_REQUEST,'mindate')) ? $_REQUEST['mindate'] : ''); + $feed = ((x($_REQUEST,'feed')) ? intval($_REQUEST['feed']) : 0); + + if($ztarget) { + if((! $zkey) || (! $zsig) || (! rsa_verify($ztarget,base64url_decode($zsig),$zkey))) { + logger('zfinger: invalid target signature'); + $ret['message'] = t("invalid target signature"); + json_return_and_die($ret); + } + } + + // allow re-written domains so bob@foo.example.com can provide an address of bob@example.com + // The top-level domain also needs to redirect .well-known/zot-info to the sub-domain with a 301 or 308 + + // TODO: Make 308 work in include/network.php for zot_fetch_url and zot_post_url + + if(($zaddr) && ($s = get_config('system','zotinfo_domainrewrite'))) { + $arr = explode('^',$s); + if(count($arr) == 2) + $zaddr = str_replace($arr[0],$arr[1],$zaddr); + } + + $r = null; + + if(strlen($zhash)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_hash = '%s' limit 1", + dbesc($zhash) + ); + } + elseif(strlen($zguid) && strlen($zguid_sig)) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_guid = '%s' and channel_guid_sig = '%s' limit 1", + dbesc($zguid), + dbesc($zguid_sig) + ); + } + elseif(strlen($zaddr)) { + if(strpos($zaddr,'[system]') === false) { /* normal address lookup */ + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where ( channel_address = '%s' or xchan_addr = '%s' ) limit 1", + dbesc($zaddr), + dbesc($zaddr) + ); + } + + else { + + /** + * The special address '[system]' will return a system channel if one has been defined, + * Or the first valid channel we find if there are no system channels. + * + * This is used by magic-auth if we have no prior communications with this site - and + * returns an identity on this site which we can use to create a valid hub record so that + * we can exchange signed messages. The precise identity is irrelevant. It's the hub + * information that we really need at the other end - and this will return it. + * + */ + + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_system = 1 order by channel_id limit 1"); + if(! $r) { + $r = q("select channel.*, xchan.* from channel left join xchan on channel_hash = xchan_hash + where channel_removed = 0 order by channel_id limit 1"); + } + } + } + else { + $ret['message'] = 'Invalid request'; + json_return_and_die($ret); + } + + if(! $r) { + $ret['message'] = 'Item not found.'; + json_return_and_die($ret); + } + + $e = $r[0]; + + $id = $e['channel_id']; + + $sys_channel = (intval($e['channel_system']) ? true : false); + $special_channel = (($e['channel_pageflags'] & PAGE_PREMIUM) ? true : false); + $adult_channel = (($e['channel_pageflags'] & PAGE_ADULT) ? true : false); + $censored = (($e['channel_pageflags'] & PAGE_CENSORED) ? true : false); + $searchable = (($e['channel_pageflags'] & PAGE_HIDDEN) ? false : true); + $deleted = (intval($e['xchan_deleted']) ? true : false); + + if($deleted || $censored || $sys_channel) + $searchable = false; + + $public_forum = false; + + $role = get_pconfig($e['channel_id'],'system','permissions_role'); + if($role === 'forum') { + $public_forum = true; + } + else { + // check if it has characteristics of a public forum based on custom permissions. + $t = q("select abook_my_perms from abook where abook_channel = %d and abook_self = 1 limit 1", + intval($e['channel_id']) + ); + if($t && ($t[0]['abook_my_perms'] & PERMS_W_TAGWALL)) + $public_forum = true; + } + + + // This is for birthdays and keywords, but must check access permissions + $p = q("select * from profile where uid = %d and is_default = 1", + intval($e['channel_id']) + ); + + $profile = array(); + + if($p) { + + if(! intval($p[0]['publish'])) + $searchable = false; + + $profile['description'] = $p[0]['pdesc']; + $profile['birthday'] = $p[0]['dob']; + if(($profile['birthday'] != '0000-00-00') && (($bd = z_birthday($p[0]['dob'],$e['channel_timezone'])) !== '')) + $profile['next_birthday'] = $bd; + + if($age = age($p[0]['dob'],$e['channel_timezone'],'')) + $profile['age'] = $age; + $profile['gender'] = $p[0]['gender']; + $profile['marital'] = $p[0]['marital']; + $profile['sexual'] = $p[0]['sexual']; + $profile['locale'] = $p[0]['locality']; + $profile['region'] = $p[0]['region']; + $profile['postcode'] = $p[0]['postal_code']; + $profile['country'] = $p[0]['country_name']; + $profile['about'] = $p[0]['about']; + $profile['homepage'] = $p[0]['homepage']; + $profile['hometown'] = $p[0]['hometown']; + + if($p[0]['keywords']) { + $tags = array(); + $k = explode(' ',$p[0]['keywords']); + if($k) { + foreach($k as $kk) { + if(trim($kk," \t\n\r\0\x0B,")) { + $tags[] = trim($kk," \t\n\r\0\x0B,"); + } + } + } + if($tags) + $profile['keywords'] = $tags; + } + } + + $ret['success'] = true; + + // Communication details + + $ret['guid'] = $e['xchan_guid']; + $ret['guid_sig'] = $e['xchan_guid_sig']; + $ret['key'] = $e['xchan_pubkey']; + $ret['name'] = $e['xchan_name']; + $ret['name_updated'] = $e['xchan_name_date']; + $ret['address'] = $e['xchan_addr']; + $ret['photo_mimetype'] = $e['xchan_photo_mimetype']; + $ret['photo'] = $e['xchan_photo_l']; + $ret['photo_updated'] = $e['xchan_photo_date']; + $ret['url'] = $e['xchan_url']; + $ret['connections_url']= (($e['xchan_connurl']) ? $e['xchan_connurl'] : z_root() . '/poco/' . $e['channel_address']); + $ret['target'] = $ztarget; + $ret['target_sig'] = $zsig; + $ret['searchable'] = $searchable; + $ret['adult_content'] = $adult_channel; + $ret['public_forum'] = $public_forum; + if($deleted) + $ret['deleted'] = $deleted; + + // premium or other channel desiring some contact with potential followers before connecting. + // This is a template - %s will be replaced with the follow_url we discover for the return channel. + + if($special_channel) + $ret['connect_url'] = z_root() . '/connect/' . $e['channel_address']; + + // This is a template for our follow url, %s will be replaced with a webbie + + $ret['follow_url'] = z_root() . '/follow?f=&url=%s'; + + $ztarget_hash = (($ztarget && $zsig) + ? make_xchan_hash($ztarget,$zsig) + : '' ); + + $permissions = get_all_perms($e['channel_id'],$ztarget_hash,false); + + if($ztarget_hash) { + $permissions['connected'] = false; + $b = q("select * from abook where abook_xchan = '%s' and abook_channel = %d limit 1", + dbesc($ztarget_hash), + intval($e['channel_id']) + ); + if($b) + $permissions['connected'] = true; + } + + $ret['permissions'] = (($ztarget && $zkey) ? crypto_encapsulate(json_encode($permissions),$zkey) : $permissions); + + if($permissions['view_profile']) + $ret['profile'] = $profile; + + // array of (verified) hubs this channel uses + + $x = zot_encode_locations($e); + if($x) + $ret['locations'] = $x; + + $ret['site'] = array(); + $ret['site']['url'] = z_root(); + $ret['site']['url_sig'] = base64url_encode(rsa_sign(z_root(),$e['channel_prvkey'])); + + $dirmode = get_config('system','directory_mode'); + if(($dirmode === false) || ($dirmode == DIRECTORY_MODE_NORMAL)) + $ret['site']['directory_mode'] = 'normal'; + + if($dirmode == DIRECTORY_MODE_PRIMARY) + $ret['site']['directory_mode'] = 'primary'; + elseif($dirmode == DIRECTORY_MODE_SECONDARY) + $ret['site']['directory_mode'] = 'secondary'; + elseif($dirmode == DIRECTORY_MODE_STANDALONE) + $ret['site']['directory_mode'] = 'standalone'; + if($dirmode != DIRECTORY_MODE_NORMAL) + $ret['site']['directory_url'] = z_root() . '/dirsearch'; + + + // hide detailed site information if you're off the grid + + if($dirmode != DIRECTORY_MODE_STANDALONE) { + + $register_policy = intval(get_config('system','register_policy')); + + if($register_policy == REGISTER_CLOSED) + $ret['site']['register_policy'] = 'closed'; + if($register_policy == REGISTER_APPROVE) + $ret['site']['register_policy'] = 'approve'; + if($register_policy == REGISTER_OPEN) + $ret['site']['register_policy'] = 'open'; + + + $access_policy = intval(get_config('system','access_policy')); + + if($access_policy == ACCESS_PRIVATE) + $ret['site']['access_policy'] = 'private'; + if($access_policy == ACCESS_PAID) + $ret['site']['access_policy'] = 'paid'; + if($access_policy == ACCESS_FREE) + $ret['site']['access_policy'] = 'free'; + if($access_policy == ACCESS_TIERED) + $ret['site']['access_policy'] = 'tiered'; + + $ret['site']['accounts'] = account_total(); + + require_once('include/identity.php'); + $ret['site']['channels'] = channel_total(); + + + $ret['site']['version'] = PLATFORM_NAME . ' ' . RED_VERSION . '[' . DB_UPDATE_VERSION . ']'; + + $ret['site']['admin'] = get_config('system','admin_email'); + + $visible_plugins = array(); + if(is_array($a->plugins) && count($a->plugins)) { + $r = q("select * from addon where hidden = 0"); + if($r) + foreach($r as $rr) + $visible_plugins[] = $rr['name']; + } + + $ret['site']['plugins'] = $visible_plugins; + $ret['site']['sitehash'] = get_config('system','location_hash'); + $ret['site']['sitename'] = get_config('system','sitename'); + $ret['site']['sellpage'] = get_config('system','sellpage'); + $ret['site']['location'] = get_config('system','site_location'); + $ret['site']['realm'] = get_directory_realm(); + + } + call_hooks('zot_finger',$ret); + json_return_and_die($ret); + +} diff --git a/sources/mod/zotfeed.php b/sources/mod/zotfeed.php new file mode 100644 index 00000000..fffb0e4a --- /dev/null +++ b/sources/mod/zotfeed.php @@ -0,0 +1,46 @@ + false); + + $mindate = (($_REQUEST['mindate']) ? datetime_convert('UTC','UTC',$_REQUEST['mindate']) : ''); + if(! $mindate) + $mindate = datetime_convert('UTC','UTC', 'now - 14 days'); + + if(get_config('system','block_public') && (! get_account_id()) && (! remote_channel())) { + $result['message'] = 'Public access denied'; + json_return_and_die($result); + } + + $observer = $a->get_observer(); + + + $channel_address = ((argc() > 1) ? argv(1) : ''); + if($channel_address) { + $r = q("select channel_id, channel_name from channel where channel_address = '%s' and channel_removed = 0 limit 1", + dbesc(argv(1)) + ); + } + else { + $x = get_sys_channel(); + if($x) + $r = array($x); + $mindate = datetime_convert('UTC','UTC', 'now - 14 days'); + } + if(! $r) { + $result['message'] = 'Channel not found.'; + json_return_and_die($result); + } + + logger('zotfeed request: ' . $r[0]['channel_name'], LOGGER_DEBUG); + + $result['messages'] = zot_feed($r[0]['channel_id'],$observer['xchan_hash'],array('mindate' => $mindate)); + $result['success'] = true; + json_return_and_die($result); + + +} diff --git a/sources/mod/zping.php b/sources/mod/zping.php new file mode 100644 index 00000000..31151770 --- /dev/null +++ b/sources/mod/zping.php @@ -0,0 +1,28 @@ +get_channel(),'ping'); + $r = zot_zot($url,$m); + return print_r($r,true); + +} \ No newline at end of file diff --git a/sources/tests/autoname_test.php b/sources/tests/autoname_test.php new file mode 100644 index 00000000..702e05be --- /dev/null +++ b/sources/tests/autoname_test.php @@ -0,0 +1,76 @@ +assertNotEquals($autoname1, $autoname2); + } + + /** + *autonames should be random, odd length + */ + public function testAutonameOdd() { + $autoname1=autoname(9); + $autoname2=autoname(9); + + $this->assertNotEquals($autoname1, $autoname2); + } + + /** + * try to fail autonames + */ + public function testAutonameNoLength() { + $autoname1=autoname(0); + $this->assertEquals(0, strlen($autoname1)); + } + + /** + * try to fail it with invalid input + * + * TODO: What's corect behaviour here? An exception? + */ + public function testAutonameNegativeLength() { + $autoname1=autoname(-23); + $this->assertEquals(0, strlen($autoname1)); + } + + // public function testAutonameMaxLength() { + // $autoname2=autoname(PHP_INT_MAX); + // $this->assertEquals(PHP_INT_MAX, count($autoname2)); + // } + + /** + * test with a length, that may be too short + */ + public function testAutonameLength1() { + $autoname1=autoname(1); + $this->assertEquals(1, count($autoname1)); + + $autoname2=autoname(1); + $this->assertEquals(1, count($autoname2)); + + // The following test is problematic, with only 26 possibilities + // generating the same thing twice happens often aka + // birthday paradox +// $this->assertFalse($autoname1==$autoname2); + } +} \ No newline at end of file diff --git a/sources/tests/contains_attribute_test.php b/sources/tests/contains_attribute_test.php new file mode 100644 index 00000000..b0bb06ac --- /dev/null +++ b/sources/tests/contains_attribute_test.php @@ -0,0 +1,51 @@ +assertTrue(attribute_contains($testAttr, "class3")); + $this->assertFalse(attribute_contains($testAttr, "class2")); + } + + /** + * test attribute contains + */ + public function testAttributeContains2() { + $testAttr="class1 not-class2 class3"; + $this->assertTrue(attribute_contains($testAttr, "class3")); + $this->assertFalse(attribute_contains($testAttr, "class2")); + } + + /** + * test with empty input + */ + public function testAttributeContainsEmpty() { + $testAttr=""; + $this->assertFalse(attribute_contains($testAttr, "class2")); + } + + /** + * test input with special chars + */ + public function testAttributeContainsSpecialChars() { + $testAttr="--... %\$ä() /(=?}"; + $this->assertFalse(attribute_contains($testAttr, "class2")); + } +} \ No newline at end of file diff --git a/sources/tests/expand_acl_test.php b/sources/tests/expand_acl_test.php new file mode 100644 index 00000000..154bc921 --- /dev/null +++ b/sources/tests/expand_acl_test.php @@ -0,0 +1,148 @@ +<2><3>'; + $this->assertEquals(array(1, 2, 3), expand_acl($text)); + } + + /** + * test with a big number + */ + public function testExpandAclBigNumber() { + $text='<1><'.PHP_INT_MAX.'><15>'; + $this->assertEquals(array(1, PHP_INT_MAX, 15), expand_acl($text)); + } + + /** + * test with a string in it. + * + * TODO: is this valid input? Otherwise: should there be an exception? + */ + public function testExpandAclString() { + $text="<1><279012>"; + $this->assertEquals(array(1, 279012), expand_acl($text)); + } + + /** + * test with a ' ' in it. + * + * TODO: is this valid input? Otherwise: should there be an exception? + */ + public function testExpandAclSpace() { + $text="<1><279 012><32>"; + $this->assertEquals(array(1, "279", "32"), expand_acl($text)); + } + + /** + * test empty input + */ + public function testExpandAclEmpty() { + $text=""; + $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, no < at all + * + * TODO: should there be an exception? + */ + public function testExpandAclNoBrackets() { + $text="According to documentation, that's invalid. "; //should be invalid + $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, just open < + * + * TODO: should there be an exception? + */ + public function testExpandAclJustOneBracket1() { + $text="assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, just close > + * + * TODO: should there be an exception? + */ + public function testExpandAclJustOneBracket2() { + $text="Another invalid> string"; //should be invalid + $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, just close > + * + * TODO: should there be an exception? + */ + public function testExpandAclCloseOnly() { + $text="Another> invalid> string>"; //should be invalid + $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, just open < + * + * TODO: should there be an exception? + */ + public function testExpandAclOpenOnly() { + $text="assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, open and close do not match + * + * TODO: should there be an exception? + */ + public function testExpandAclNoMatching1() { + $text=" invalid "; //should be invalid + $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, open and close do not match + * + * TODO: should there be an exception? + */ + public function testExpandAclNoMatching2() { + $text="<1>2><3>"; +// The angles are delimiters which aren't important +// the important thing is the numeric content, this returns array(1,2,3) currently +// we may wish to eliminate 2 from the results, though it isn't harmful +// It would be a better test to figure out if there is any ACL input which can +// produce this $text and fix that instead. +// $this->assertEquals(array(), expand_acl($text)); + } + + /** + * test invalid input, empty <> + * + * TODO: should there be an exception? Or array(1, 3) + * (This should be array(1,3) - mike) + */ + public function testExpandAclEmptyMatch() { + $text="<1><><3>"; + $this->assertEquals(array(1,3), expand_acl($text)); + } +} \ No newline at end of file diff --git a/sources/tests/get_tags_test.php b/sources/tests/get_tags_test.php new file mode 100644 index 00000000..40f01674 --- /dev/null +++ b/sources/tests/get_tags_test.php @@ -0,0 +1,326 @@ +15, + 'attag'=>'', 'network'=>'dfrn', + 'name'=>'Mike Lastname', 'alias'=>'Mike', + 'nick'=>'Mike', 'url'=>"http://justatest.de")); + + $args=func_get_args(); + + //last parameter is always (in this test) uid, so, it should be 11 + if($args[count($args)-1]!=11) { + return; + } + + + if(3==count($args)) { + //first call in handle_body, id only + if($result[0]['id']==$args[1]) { + return $result; + } + //second call in handle_body, name + if($result[0]['name']===$args[1]) { + return $result; + } + } + //third call in handle_body, nick or attag + if($result[0]['nick']===$args[2] || $result[0]['attag']===$args[1]) { + return $result; + } +} + +/** + * replacement for dbesc. + * I don't want to test dbesc here, so + * I just return the input. It won't be a problem, because + * the test does not use a real database. + * + * DON'T USE HAT FUNCTION OUTSIDE A TEST! + * + * @param string $str + * @return input + */ +function dbesc($str) { + return $str; +} + +/** + * TestCase for tag handling. + * + * @author alexander + * @package test.util + */ +class GetTagsTest extends PHPUnit_Framework_TestCase { + /** the mock to use as app */ + private $a; + + /** + * initialize the test. That's a phpUnit function, + * don't change its name. + */ + public function setUp() { + $this->a=new MockApp(); + } + + /** + * test with one Person tag + */ + public function testGetTagsShortPerson() { + $text="hi @Mike"; + + $tags=get_tags($text); + + $inform=''; + $str_tags=''; + foreach($tags as $tag) { + handle_tag($this->a, $text, $inform, $str_tags, 11, $tag); + } + + //correct tags found? + $this->assertEquals(1, count($tags)); + $this->assertTrue(in_array("@Mike", $tags)); + + //correct output from handle_tag? + $this->assertEquals("cid:15", $inform); + $this->assertEquals("@[url=http://justatest.de]Mike Lastname[/url]", $str_tags); + $this->assertEquals("hi @[url=http://justatest.de]Mike Lastname[/url]", $text); + } + + /** + * test with one Person tag. + * There's a minor spelling mistake... + */ + public function testGetTagsShortPersonSpelling() { + $text="hi @Mike.because"; + + $tags=get_tags($text); + + //correct tags found? + $this->assertEquals(1, count($tags)); + $this->assertTrue(in_array("@Mike.because", $tags)); + + $inform=''; + $str_tags=''; + handle_tag($this->a, $text, $inform, $str_tags, 11, $tags[0]); + + // (mike) - This is a tricky case. + // we support mentions as in @mike@example.com - which contains a period. + // This shouldn't match anything unless you have a contact named "Mike.because". + // We may need another test for "@Mike. because" - which should return the contact + // as we ignore trailing periods in tags. + +// $this->assertEquals("cid:15", $inform); +// $this->assertEquals("@[url=http://justatest.de]Mike Lastname[/url]", $str_tags); +// $this->assertEquals("hi @[url=http://justatest.de]Mike Lastname[/url].because", $text); + + $this->assertEquals("", $inform); + $this->assertEquals("", $str_tags); + + } + + /** + * test with two Person tags. + * There's a minor spelling mistake... + */ + + public function testGetTagsPerson2Spelling() { + $text="hi @Mike@campino@friendica.eu"; + + $tags=get_tags($text); + +// This construct is not supported. Results are indeterminate +// $this->assertEquals(2, count($tags)); +// $this->assertTrue(in_array("@Mike", $tags)); +// $this->assertTrue(in_array("@campino@friendica.eu", $tags)); + } + + /** + * Test with one hash tag. + */ + public function testGetTagsShortTag() { + $text="This is a #test_case"; + + $tags=get_tags($text); + + $this->assertEquals(1, count($tags)); + $this->assertTrue(in_array("#test_case", $tags)); + } + + /** + * test with a person and a hash tag + */ + public function testGetTagsShortTagAndPerson() { + $text="hi @Mike This is a #test_case"; + + $tags=get_tags($text); + + $this->assertEquals(3, count($tags)); + $this->assertTrue(in_array("@Mike", $tags)); + $this->assertTrue(in_array("@Mike This", $tags)); + $this->assertTrue(in_array("#test_case", $tags)); + + $inform=''; + $str_tags=''; + foreach($tags as $tag) { + handle_tag($this->a, $text, $inform, $str_tags, 11, $tag); + } + + $this->assertEquals("cid:15", $inform); + $this->assertEquals("@[url=http://justatest.de]Mike Lastname[/url],#[url=baseurl/search?tag=test%20case]test case[/url]", $str_tags); + $this->assertEquals("hi @[url=http://justatest.de]Mike Lastname[/url] This is a #[url=baseurl/search?tag=test%20case]test case[/url]", $text); + + } + + /** + * test with a person, a hash tag and some special chars. + */ + public function testGetTagsShortTagAndPersonSpecialChars() { + $text="hi @Mike, This is a #test_case."; + + $tags=get_tags($text); + + $this->assertEquals(2, count($tags)); + $this->assertTrue(in_array("@Mike", $tags)); + $this->assertTrue(in_array("#test_case", $tags)); + } + + /** + * Test with a person tag and text behind it. + */ + public function testGetTagsPersonOnly() { + $text="@Test I saw the Theme Dev group was created."; + + $tags=get_tags($text); + + $this->assertEquals(2, count($tags)); + $this->assertTrue(in_array("@Test I", $tags)); + $this->assertTrue(in_array("@Test", $tags)); + } + + /** + * this test demonstrates strange behaviour by intval. + * It makes the next test fail. + */ + public function testIntval() { + $this->assertEquals(15, intval("15 it")); + } + + /** + * test a tag with an id in it + */ + public function testIdTag() { + $text="Test with @mike+15 id tag"; + + $tags=get_tags($text); + + $this->assertEquals(2, count($tags)); + $this->assertTrue(in_array("@mike+15", $tags)); + + //happens right now, but it shouldn't be necessary + $this->assertTrue(in_array("@mike+15 id", $tags)); + + $inform=''; + $str_tags=''; + foreach($tags as $tag) { + handle_tag($this->a, $text, $inform, $str_tags, 11, $tag); + } + + $this->assertEquals("Test with @[url=http://justatest.de]Mike Lastname[/url] id tag", $text); + $this->assertEquals("@[url=http://justatest.de]Mike Lastname[/url]", $str_tags); + // this test may produce two cid:15 entries - which is OK because duplicates are pruned before delivery + $this->assertContains("cid:15",$inform); + } + + /** + * test with two persons and one special tag. + */ + public function testGetTags2Persons1TagSpecialChars() { + $text="hi @Mike, I'm just writing #test_cases, so" + ." so @somebody@friendica.com may change #things."; + + $tags=get_tags($text); + + $this->assertEquals(5, count($tags)); + $this->assertTrue(in_array("@Mike", $tags)); + $this->assertTrue(in_array("#test_cases", $tags)); + $this->assertTrue(in_array("@somebody@friendica.com", $tags)); + $this->assertTrue(in_array("@somebody@friendica.com may", $tags)); + $this->assertTrue(in_array("#things", $tags)); + } + + /** + * test with a long text. + */ + public function testGetTags() { + $text="hi @Mike, I'm just writing #test_cases, " + ." so @somebody@friendica.com may change #things. Of course I " + ."look for a lot of #pitfalls, like #tags at the end of a sentence " + ."@comment. I hope noone forgets about @fullstops.because that might" + ." break #things. @Mike@campino@friendica.eu is also #nice, isn't it? " + ."Now, add a @first_last tag. "; + + $tags=get_tags($text); + + $this->assertTrue(in_array("@Mike", $tags)); + $this->assertTrue(in_array("#test_cases", $tags)); + $this->assertTrue(in_array("@somebody@friendica.com", $tags)); + $this->assertTrue(in_array("#things", $tags)); + $this->assertTrue(in_array("#pitfalls", $tags)); + $this->assertTrue(in_array("#tags", $tags)); + $this->assertTrue(in_array("@comment", $tags)); + $this->assertTrue(in_array("@fullstops.because", $tags)); + $this->assertTrue(in_array("#things", $tags)); + $this->assertTrue(in_array("@Mike", $tags)); + $this->assertTrue(in_array("#nice", $tags)); + $this->assertTrue(in_array("@first_last", $tags)); + + //right now, none of the is matched (unsupported) +// $this->assertFalse(in_array("@Mike@campino@friendica.eu", $tags)); +// $this->assertTrue(in_array("@campino@friendica.eu", $tags)); +// $this->assertTrue(in_array("@campino@friendica.eu is", $tags)); + } + + /** + * test with an empty string + */ + public function testGetTagsEmpty() { + $tags=get_tags(""); + $this->assertEquals(0, count($tags)); + } +} \ No newline at end of file diff --git a/sources/tests/template_test.php b/sources/tests/template_test.php new file mode 100644 index 00000000..1f9f8053 --- /dev/null +++ b/sources/tests/template_test.php @@ -0,0 +1,224 @@ +assertTrue(is_null($second)); + } + + public function testSimpleVariableString() { + $tpl='Hello $name!'; + + $text=replace_macros($tpl, array('$name'=>'Anna')); + + $this->assertEquals('Hello Anna!', $text); + } + + public function testSimpleVariableInt() { + $tpl='There are $num new messages!'; + + $text=replace_macros($tpl, array('$num'=>172)); + + $this->assertEquals('There are 172 new messages!', $text); + } + + public function testConditionalElse() { + $tpl='There{{ if $num!=1 }} are $num new messages{{ else }} is 1 new message{{ endif }}!'; + + $text1=replace_macros($tpl, array('$num'=>1)); + $text22=replace_macros($tpl, array('$num'=>22)); + + $this->assertEquals('There is 1 new message!', $text1); + $this->assertEquals('There are 22 new messages!', $text22); + } + + public function testConditionalNoElse() { + $tpl='{{ if $num!=0 }}There are $num new messages!{{ endif }}'; + + $text0=replace_macros($tpl, array('$num'=>0)); + $text22=replace_macros($tpl, array('$num'=>22)); + + $this->assertEquals('', $text0); + $this->assertEquals('There are 22 new messages!', $text22); + } + + public function testConditionalFail() { + $tpl='There {{ if $num!=1 }} are $num new messages{{ else }} is 1 new message{{ endif }}!'; + + $text1=replace_macros($tpl, array()); + + //$this->assertEquals('There is 1 new message!', $text1); + } + + public function testSimpleFor() { + $tpl='{{ for $messages as $message }} $message {{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>array('message 1', 'message 2'))); + + $this->assertEquals(' message 1 message 2 ', $text); + } + + public function testFor() { + $tpl='{{ for $messages as $message }} from: $message.from to $message.to {{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>array(array('from'=>'Mike', 'to'=>'Alex'), array('from'=>'Alex', 'to'=>'Mike')))); + + $this->assertEquals(' from: Mike to Alex from: Alex to Mike ', $text); + } + + public function testKeyedFor() { + $tpl='{{ for $messages as $from=>$to }} from: $from to $to {{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>array('Mike'=>'Alex', 'Sven'=>'Mike'))); + + $this->assertEquals(' from: Mike to Alex from: Sven to Mike ', $text); + } + + public function testForEmpty() { + $tpl='messages: {{for $messages as $message}} from: $message.from to $message.to {{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>array())); + + $this->assertEquals('messages: ', $text); + } + + public function testForWrongType() { + $tpl='messages: {{for $messages as $message}} from: $message.from to $message.to {{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>11)); + + $this->assertEquals('messages: ', $text); + } + + public function testForConditional() { + $tpl='new messages: {{for $messages as $message}}{{ if $message.new }} $message.text{{endif}}{{ endfor }}'; + + $text=replace_macros($tpl, array('$messages'=>array( + array('new'=>true, 'text'=>'new message'), + array('new'=>false, 'text'=>'old message')))); + + $this->assertEquals('new messages: new message', $text); + } + + public function testConditionalFor() { + $tpl='{{ if $enabled }}new messages:{{for $messages as $message}} $message.text{{ endfor }}{{endif}}'; + + $text=replace_macros($tpl, array('$enabled'=>true, + '$messages'=>array( + array('new'=>true, 'text'=>'new message'), + array('new'=>false, 'text'=>'old message')))); + + $this->assertEquals('new messages: new message old message', $text); + } + + public function testFantasy() { + $tpl='Fantasy: {{fantasy $messages}}'; + + $text=replace_macros($tpl, array('$messages'=>'no no')); + + $this->assertEquals('Fantasy: {{fantasy no no}}', $text); + } + + public function testInc() { + $tpl='{{inc field_input.tpl with $field=$myvar}}{{ endinc }}'; + + $text=replace_macros($tpl, array('$myvar'=>array('myfield', 'label', 'value', 'help'))); + + $this->assertEquals(" \n" + ."
    \n" + ." \n" + ." \n" + ." help\n" + ."
    \n", $text); + } + + public function testIncNoVar() { + $tpl='{{inc field_input.tpl }}{{ endinc }}'; + + $text=replace_macros($tpl, array('$field'=>array('myfield', 'label', 'value', 'help'))); + + $this->assertEquals(" \n
    \n \n" + ." \n" + ." help\n" + ."
    \n", $text); + } + + public function testDoubleUse() { + $tpl='Hello $name! {{ if $enabled }} I love you! {{ endif }}'; + + $text=replace_macros($tpl, array('$name'=>'Anna', '$enabled'=>false)); + + $this->assertEquals('Hello Anna! ', $text); + + $tpl='Hey $name! {{ if $enabled }} I hate you! {{ endif }}'; + + $text=replace_macros($tpl, array('$name'=>'Max', '$enabled'=>true)); + + $this->assertEquals('Hey Max! I hate you! ', $text); + } + + public function testIncDouble() { + $tpl='{{inc field_input.tpl with $field=$var1}}{{ endinc }}' + .'{{inc field_input.tpl with $field=$var2}}{{ endinc }}'; + + $text=replace_macros($tpl, array('$var1'=>array('myfield', 'label', 'value', 'help'), + '$var2'=>array('myfield2', 'label2', 'value2', 'help2'))); + + $this->assertEquals(" \n" + ."
    \n" + ." \n" + ." \n" + ." help\n" + ."
    \n" + ." \n" + ."
    \n" + ." \n" + ." \n" + ." help2\n" + ."
    \n", $text); + } +} \ No newline at end of file diff --git a/sources/tests/xss_filter_test.php b/sources/tests/xss_filter_test.php new file mode 100644 index 00000000..3fb6ac31 --- /dev/null +++ b/sources/tests/xss_filter_test.php @@ -0,0 +1,71 @@ +'; + + $validstring=notags($invalidstring); + $escapedString=escape_tags($invalidstring); + + $this->assertEquals('[submit type="button" onclick="alert(\'failed!\');" /]', $validstring); + $this->assertEquals("<submit type="button" onclick="alert('failed!');" />", $escapedString); + } + + /** + *xmlify and unxmlify + */ + public function testXmlify() { + $text="I want to break\n this!11!"; + $xml=xmlify($text); + $retext=unxmlify($text); + + $this->assertEquals($text, $retext); + } + + /** + * xmlify and put in a document + */ + public function testXmlifyDocument() { + $tag="I want to break"; + $xml=xmlify($tag); + $text=''.$xml.''; + + $xml_parser=xml_parser_create(); + //should be possible to parse it + $values=array(); $index=array(); + $this->assertEquals(1, xml_parse_into_struct($xml_parser, $text, $values, $index)); + + $this->assertEquals(array('TEXT'=>array(0)), + $index); + $this->assertEquals(array(array('tag'=>'TEXT', 'type'=>'complete', 'level'=>1, 'value'=>$tag)), + $values); + + xml_parser_free($xml_parser); + } + + /** + * test hex2bin and reverse + */ + public function testHex2Bin() { + $this->assertEquals(-3, hex2bin(bin2hex(-3))); + $this->assertEquals(0, hex2bin(bin2hex(0))); + $this->assertEquals(12, hex2bin(bin2hex(12))); + $this->assertEquals(PHP_INT_MAX, hex2bin(bin2hex(PHP_INT_MAX))); + } + + //function qp, quick and dirty?? + //get_mentions + //get_contact_block, bis Zeile 538 +} +?> diff --git a/sources/util/.htaccess b/sources/util/.htaccess new file mode 100644 index 00000000..a0a0d72d --- /dev/null +++ b/sources/util/.htaccess @@ -0,0 +1,10 @@ +Options -Indexes + +# Remove the following lines or modify it to run the string translator utility + + Require all denied + + + Order deny,allow + Deny from all + diff --git a/sources/util/Doxyfile b/sources/util/Doxyfile new file mode 100644 index 00000000..55acd46e --- /dev/null +++ b/sources/util/Doxyfile @@ -0,0 +1,23 @@ +INPUT = README.md index.php boot.php mod/ include/ util/ view/ version.inc +RECURSIVE = YES +PROJECT_NAME = "The Hubzilla" +PROJECT_LOGO = images/rm-64.png +EXCLUDE = .htconfig.php library/ doc/ vendor/ .git/ util/zotsh/easywebdav/ +EXCLUDE_PATTERNS = *smarty3* *strings.php *.out *test* +OUTPUT_DIRECTORY = doc +GENERATE_HTML = YES +HTML_OUTPUT = html/ +HTML_FILE_EXTENSION = .html +GENERATE_LATEX = NO +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +GENERATE_TODOLIST = YES +USE_MDFILE_AS_MAINPAGE = README.md +REFERENCED_BY_RELATION = YES +GENERATE_TREEVIEW = YES +HTML_FOOTER = util/Doxygen.footer +ALIASES += "license=@par License:\n" +ALIASES += "fixme=\xrefitem fixme \"Fixme\" \"Fixme List\"" +ALIASES += "FIXME=\fixme" +ALIASES += "TODO=\todo" +ALIASES += "BUG=\bug" diff --git a/sources/util/Doxygen.footer b/sources/util/Doxygen.footer new file mode 100644 index 00000000..fd40910d --- /dev/null +++ b/sources/util/Doxygen.footer @@ -0,0 +1,4 @@ + + + + diff --git a/sources/util/README b/sources/util/README new file mode 100644 index 00000000..991a3fe5 --- /dev/null +++ b/sources/util/README @@ -0,0 +1,126 @@ +Utilities + +typo.php - is a crude syntax checker to avoid checking in files with simple +typos. It basically just loads each of our project files at once. Run from +cmdline and see if any parsing errors are reported. + + + +Internationalisation + +extract.php - extracts translatable strings from our project files. It +currently doesn't pick up strings in other libraries we might be using such as +tinymce, simplepie, and the HTML parsers. + +In order for extract to do its job, every use of the t() translation function +must be preceded by one space. The string also can not contain parentheses. If +parens are required in a string which requires translation, please use hex escapes. + +\x28 = ( +\x29 = ) + +This only applies to English. Other languages may use parens in strings +because they don't require extraction. + +strings.php - a recent run of the strings program. This provides output that +is suitable for direct inclusion in the program. + +There are also translatable strings in the various files in the view/en +directory. By setting $lang = 'something' in .htconfig.php, the application +will search for view/something/filename prior to the English version in +view/en/filename when loading templates and view files. + +The translated string table should be placed in view/$lang/strings.php for +automatic inclusion. + +You are not restricted to using known languages. You may also use this to +translate the software into "pirate", "surfer" or merely to replace certain +text which you don't care for. + +Note: The view/en directory contains many HTML template files, some of which +only have a few words of English text amongst the HTML. Over time we will move +the translation to the replace_macros() function which calls these files and +then relocate the files to the view directory. The files in the top-level view +directory are template files which do not require translation. + + +Placeholders + +Do not translate placeholders in strings! Things like %s, %d, %1$s and $somename +are used to add dynamic content to the string. + +%s represents a dynamic string, like in "Welcome to %s" +%d represents a dynamic number, like in "%d new messages" +$somename is a variable like in php +In %1$s %2$s, the numbers are the position index of multiple dynamic content. +You could swap position in string of indexed placeholders. +e.g. +"%1$s's %2$s" => "John's photo", "John's item" +"%2$s di %1$s" => "foto di John", "elemento di John" + + +Plural + +The tt() function supports plural form. Script extract.php write this in +strings.php as an array, one string for every plural form language supports: + +$a->string["%d message sent"] = Array( + 0 => "%d message sent", + 1 => "%d messages sent", +); + +The function string_plural_select($n) defined in strings.php, return the string +index to use, related to the numbers of item (value of $n). + +This is modelled after ngettext function of GNU gettext. +More info at http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html + + +Xgettext and .po workflow + +1. Run util/run_xgettext.sh script (on *unix sistems, with GNU xgettext installed) + This script runs xgettext on source tree, extracting strings from t() and tt() + functions, and creates a util/messages.po file. + + % cd util; ./run_xgettext.sh ../view/{language}/messages.po + + Replace {language} with the language you are working on - e.g. 'es', 'fr', 'de', etc. + +2. copy util/messages.po to view//messages.po +3. open view//messages.po with a text editor and fill in infos in + "Last-Translator: FULL NAME " + "Language-Team: LANGUAGE \n" + "Language: \n" + + (eg: + "Last-Translator: Guybrush Threepwood " + "Language-Team: Pirate Friendika \n" + "Language: pi\n" + ) + + For the line + "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + read GNU gettext manual at + http://www.gnu.org/software/hello/manual/gettext/Plural-forms.html + +4. You could then translate the strings in text editor, but I suggest to use one + of the many .po editors out there, like QtLinguist + +5. run + $ php util/po2php.php view//messages.po + to create the strings.php file + +When strings are added or modified in source, you could run + $ cd util; ./run_xgettext.sh ../view//messages.po + to extract strings from source files and join them with the existing .po file: + new strings are added, the existing are not overwritten. + +If you already translated the Hubzilla using strings.php, you could import your old +translation to messages.po. Run: +$ php util/php2po.php view//strings.php + + +You may also use the util/string_translator.php web interface to translate the string file, but it is disabled for website security reasons. The web server will need write permission to your language directories and the "Deny ..." line in util/.htaccess will need to be modified or commented to use the utility. + + + diff --git a/sources/util/add_addon_repo b/sources/util/add_addon_repo new file mode 100755 index 00000000..decd9e09 --- /dev/null +++ b/sources/util/add_addon_repo @@ -0,0 +1,39 @@ +#!/bin/bash -f + +if [ $# -ne 2 ]; then + echo usage: $0 repo_url nickname + exit 1 +fi + +mkdir -p extend/addon/$2 +mkdir addon > /dev/null 2>&1 +git clone $1 extend/addon/$2 +if [ $? -ne 0 ]; then + exit $? +fi + +filelist=(`ls extend/addon/$2`) + + +cd addon +for a in "${filelist[@]}" ; do + base=`basename $a` + if [ $base = '.git' ]; then +# echo 'ignoring git' + continue; + fi + if [ ! -d ../extend/addon/$2/$base ]; then +# echo $a 'not a directory' + continue; + fi + if [ -x $base ]; then +# echo $base 'file exists' + continue; + fi + + echo linking $base + + ln -s ../extend/addon/$2/$base $base +done + + diff --git a/sources/util/add_theme_repo b/sources/util/add_theme_repo new file mode 100755 index 00000000..d41eba6d --- /dev/null +++ b/sources/util/add_theme_repo @@ -0,0 +1,37 @@ +#!/bin/bash -f + + +if [ $# -ne 2 ]; then + echo usage: $0 repo_url nickname + exit 1 +fi + +mkdir -p extend/theme/$2 +git clone $1 extend/theme/$2 +if [ $? -ne 0 ]; then + exit $? +fi + +filelist=(`ls extend/theme/$2`) + +cd view/theme +for a in "${filelist[@]}" ; do + base=`basename $a` + if [ $base = '.git' ]; then +# echo 'ignoring git' + continue; + fi + if [ ! -d ../../extend/theme/$2/$base ]; then +# echo $a 'not a directory' + continue; + fi + if [ -x $base ]; then +# echo $base 'file exists' + continue; + fi + + echo linking $base + ln -s ../../extend/theme/$2/$base $base +done + + diff --git a/sources/util/add_widget_repo b/sources/util/add_widget_repo new file mode 100755 index 00000000..347e8e4e --- /dev/null +++ b/sources/util/add_widget_repo @@ -0,0 +1,35 @@ +#!/bin/bash -f + +if [ $# -ne 2 ]; then + echo usage: $0 repo_url nickname + exit 1 +fi + +mkdir -p extend/widget/$2 +mkdir widget > /dev/null 2>&1 +git clone $1 extend/widget/$2 +if [ $? -ne 0 ]; then + exit $? +fi + +filelist=(`ls extend/widget/$2`) + + +cd widget +for a in "${filelist[@]}" ; do + base=`basename $a` + if [ $base = '.git' ]; then +# echo 'ignoring git' + continue; + fi + if [ -x $base ]; then +# echo $base 'file exists' + continue; + fi + + echo linking $base + + ln -s ../extend/widget/$2/$base $base +done + + diff --git a/sources/util/config b/sources/util/config new file mode 100755 index 00000000..67fe14f9 --- /dev/null +++ b/sources/util/config @@ -0,0 +1,34 @@ +#!/usr/bin/env php + 3) { + set_config($argv[1],$argv[2],$argv[3]); + echo "config[{$argv[1]}][{$argv[2]}] = " . get_config($argv[1],$argv[2]) . "\n"; +} + +if($argc == 3) { + echo "config[{$argv[1]}][{$argv[2]}] = " . get_config($argv[1],$argv[2]) . "\n"; +} + +if($argc == 2) { + load_config($argv[1]); + foreach($a->config[$argv[1]] as $k => $x) { + echo "config[{$argv[1]}][{$k}] = " . $x . "\n"; + } +} + +if($argc == 1) { + $r = q("select * from config where 1"); + if($r) { + foreach($r as $rr) { + echo "config[{$rr['cat']}][{$rr['k']}] = " . $rr['v'] . "\n"; + } + } +} + diff --git a/sources/util/config.md b/sources/util/config.md new file mode 100644 index 00000000..3b834fe0 --- /dev/null +++ b/sources/util/config.md @@ -0,0 +1,26 @@ +CLI config utility +================== + +Usage: + + +config + displays all config entries + + +config family + displays all config entries for family (system, database, etc) + + +config family key + displays single config entry for specified family and key + +config family key value + set config entry for specified family and key to value and display result + + + +Notes: + Setting config entries which are manually set in .htconfig.php may result in +conflict between database settings and the manual startup settings. + diff --git a/sources/util/db_update.php b/sources/util/db_update.php new file mode 100644 index 00000000..ceef061c --- /dev/null +++ b/sources/util/db_update.php @@ -0,0 +1,22 @@ +strings[' . $a[0] . "] = array(\n"; + $s .= "\t0 => ". $a[0]. ",\n"; + $s .= "\t1 => ". $a[1]. ",\n"; + $s .= ");\n"; + } else { + if(substr($a,0,1) == '$') + continue; + $s .= '$a->strings[' . $a . '] = '. $a . ';' . "\n"; + } + } + + $zones = timezone_identifiers_list(); + foreach($zones as $zone) + $s .= '$a->strings[\'' . $zone . '\'] = \'' . $zone . '\';' . "\n"; + + echo $s; \ No newline at end of file diff --git a/sources/util/fpostit/README b/sources/util/fpostit/README new file mode 100644 index 00000000..39b7c576 --- /dev/null +++ b/sources/util/fpostit/README @@ -0,0 +1,8 @@ +fpostit + +original author: Devlon Duthied + +see his blog posting: +http://blog.duthied.com/2011/09/13/node-agnostic-friendika-bookmarklet/ + +original published at github https://github.com/duthied/Friendika-Bookmarklet diff --git a/sources/util/fpostit/fpostit.js b/sources/util/fpostit/fpostit.js new file mode 100644 index 00000000..a6c75aba --- /dev/null +++ b/sources/util/fpostit/fpostit.js @@ -0,0 +1,11 @@ +javascript: (function() { + the_url = 'http://testbubble.com/fpostit.php?url=' + encodeURIComponent(window.location.href) + '&title=' + encodeURIComponent(document.title) + '&text=' + encodeURIComponent('' (window.getSelection ? window.getSelection() : document.getSelection ? document.getSelection() : document.selection.createRange().text)); + a_funct = function() { + if (!window.open(the_url, 'fpostit', 'location=yes,links=no,scrollbars=no,toolbar=no,width=600,height=300')) location.href = the_url; + }; + if (/Firefox/.test(navigator.userAgent)) { + setTimeout(a_funct, 0) + } else { + a_funct() + } +})() \ No newline at end of file diff --git a/sources/util/fpostit/fpostit.php b/sources/util/fpostit/fpostit.php new file mode 100644 index 00000000..491d81f6 --- /dev/null +++ b/sources/util/fpostit/fpostit.php @@ -0,0 +1,129 @@ + + + + + + + + $content); + + // echo "posting to: $url
    "; + + $c = curl_init(); + curl_setopt($c, CURLOPT_URL, $url); + curl_setopt($c, CURLOPT_USERPWD, "$username:$password"); + curl_setopt($c, CURLOPT_POSTFIELDS, $data); + curl_setopt($c, CURLOPT_RETURNTRANSFER, true); + curl_setopt($c, CURLOPT_FOLLOWLOCATION, true); + $c_result = curl_exec($c); + if(curl_errno($c)){ + $error = curl_error($c); + showForm($error, $content); + } + + curl_close($c); + if (!isset($error)) { + echo ''; + } + + } else { + $error = "Missing account name and/or password...try again please"; + showForm($error, $content); + } + +} else { + showForm(null, $content); +} + +function showForm($error, $content) { + $username_cookie = $_COOKIE['username']; + $password_cookie = $_COOKIE['password']; + + echo << +

    + Friendika Bookmarklet

    +
    + +
    +
    + Enter the email address of the Friendika Account that you want to cross-post to:(example: user@friendika.org)

    + Account ID:
    + Password:
    +
    +   $error +
    +

    +
    +EOF; + +} +?> + + + \ No newline at end of file diff --git a/sources/util/fpostit/friendika-32.png b/sources/util/fpostit/friendika-32.png new file mode 100644 index 00000000..61764bf2 Binary files /dev/null and b/sources/util/fpostit/friendika-32.png differ diff --git a/sources/util/fresh b/sources/util/fresh new file mode 100755 index 00000000..8bee5dff --- /dev/null +++ b/sources/util/fresh @@ -0,0 +1,163 @@ +#!/usr/bin/env php +cmd = $line; + $a->argv = explode(' ',$line); + $a->argc = count($a->argv); + + $authenticated = false; + $channel = null; + + if($line == 'version') { + echo 'Fresh version 0.1'; + return; + } + + switch(argv(0)) { + case '?': + case 'help': + fresh_help(); + break; + + case 'finger': + if(argv(1)) { + $x = zot_finger(argv(1),$channel); + if($x['success']) + echo jindent($x['body']); + } + break; + + case 'login': + if(argv(1)) { + echo 'Password: '; + exec('/bin/stty -echo'); + $x = fgets(STDIN); + exec('/bin/stty echo'); + echo "\n"; + require_once('include/auth.php'); + $record = get_app()->account = account_verify_password(argv(1),trim($x,"\n")); + + if($record) { + $_SESSION['account_id'] = get_app()->account['account_id']; + $_SESSION['last_login_date'] = datetime_convert(); + authenticate_success($record, true, true); + echo 'logged in'; + $channel = $a->get_channel(); + if($channel) + echo ' as ' . $channel['channel_name']; + } + else + echo 'login failed.'; + + } + break; + case 'channel': + if(! local_channel()) + echo 'Permission denied.'; + if(argv(1)) { + $r = q("select * from channel where channel_address = '%s' and channel_account_id = %d limit 1", + dbesc(argv(1)), + intval(get_account_id()) + ); + if($r) { + change_channel($r[0]['channel_id']); + $channel = $a->get_channel(); + echo 'Logged in as ' . $channel['channel_name']; + } + else + echo 'Channel not found.'; + } + break; + case 'conn': + if(! local_channel()) { + echo "Permission denied."; + break; + } + if(argc() > 1) { + for($x = 1; $x < argc(); $x ++) { + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d", + intval(argv($x)), + intval(local_channel()) + ); + if($r) echo jindent(json_encode($r[0])) . "\n"; + } + } + else { + $r = q("select * from abook left join xchan on abook_xchan = xchan_hash where abook_channel = %d order by abook_id", + intval(local_channel()) + ); + if($r) { + foreach($r as $rr) + echo $rr['abook_id'] . "\t" . $rr['xchan_name'] . "\n"; + } + } + break; + + default: + break; + + } + + +} + + +function fresh_help() { + + if(argc() == 1) { + echo "help - this text\n"; + echo "login email_address - login with email_address, prompts for password\n"; + echo "finger channel_address - lookup channel_address remotely\n"; + echo "channel new_channel - change active channel to new_channel (nickname)\n"; + echo "conn [id1] [id2...] - without args list connections, or report detail of connection id1 (etc.)\n"; + echo "quit|exit - terminate fresh\n"; + + } +} \ No newline at end of file diff --git a/sources/util/fresh.md b/sources/util/fresh.md new file mode 100644 index 00000000..7bdf87ff --- /dev/null +++ b/sources/util/fresh.md @@ -0,0 +1,33 @@ +Fresh - The Freaking REd Shell +=============================== + +This will only work on Unix/Linux. If the readline module is installed, we will +use that for input, otherwise we will just read from stdin and write to stdout. + +Commands are processed sequentially until the command "exit", "quit", or end +of file is reached. + + +Commands: + +* version + Report current fresh version + +* login email_address + Prompts for a password, and authenticates email_address as the current +user. + +* finger channel_address + performs a lookup of channel_address and reports the result. + +* channel channel_nickname + switches the current channel to the channel with nickname specified. + +* conn [id1 id2 ...] + With no arguments lists all connections of the current channel, with an id. +If IDs are provided the connections details of each will be displayed. + + + + + diff --git a/sources/util/friendica-to-smarty-tpl.py b/sources/util/friendica-to-smarty-tpl.py new file mode 100755 index 00000000..3e0add77 --- /dev/null +++ b/sources/util/friendica-to-smarty-tpl.py @@ -0,0 +1,236 @@ +#!/usr/bin/python +# +# Script to convert Friendica internal template files into Smarty template files +# Copyright 2013 Zach Prezkuta +# Licensed under GPL v3 + +import os, re, string +import sys, getopt + +ldelim = '{{' +rdelim = '}}' + +def fToSmarty(matches): + match = matches.group(0) + if match == '$j': + return match + match = string.replace(match, '[', '') + match = string.replace(match, ']', '') + + ldel = ldelim + rdel = rdelim + if match.find("'") > -1: + match = string.replace(match, "'", '') + ldel = "'" + ldel + rdel = rdel + "'" + elif match.find('"') > -1: + match = string.replace(match, '"', '') + ldel = '"' + ldel + rdel = rdel + '"' + + return ldel + match + rdel + + +def fix_element(element): + # Much of the positioning here is important, e.g. if you do element.find('if ') before you do + # element.find('endif'), then you may get some multiply-replaced delimiters + + if element.find('endif') > -1: + element = ldelim + '/if' + rdelim + return element + + if element.find('if ') > -1: + element = string.replace(element, '{{ if', ldelim + 'if') + element = string.replace(element, '{{if', ldelim + 'if') + element = string.replace(element, ' }}', rdelim) + element = string.replace(element, '}}', rdelim) + return element + + if element.find('else') > -1: + element = ldelim + 'else' + rdelim + return element + + if element.find('endfor') > -1: + element = ldelim + '/foreach' + rdelim + return element + + if element.find('for ') > -1: + element = string.replace(element, '{{ for ', ldelim + 'foreach ') + element = string.replace(element, '{{for ', ldelim + 'foreach ') + element = string.replace(element, ' }}', rdelim) + element = string.replace(element, '}}', rdelim) + return element + + if element.find('endinc') > -1: + element = '' + return element + + if element.find('inc ') > -1: + parts = element.split(' ') + element = ldelim + 'include file="' + + # We need to find the file name. It'll either be in parts[1] if the element was written as {{ inc file.tpl }} + # or it'll be in parts[2] if the element was written as {{inc file.tpl}} + if parts[0].find('inc') > -1: + first = 0 + else: + first = 1 + + if parts[first+1][0] == '$': + # This takes care of elements where the filename is a variable, e.g. {{ inc $file }} + element += ldelim + parts[first+1].rstrip('}') + rdelim + else: + # This takes care of elements where the filename is a path, e.g. {{ inc file.tpl }} + element += parts[first+1].rstrip('}') + + element += '"' + + if len(parts) > first + 1 and parts[first+2] == 'with': + # Take care of variable substitutions, e.g. {{ inc file.tpl with $var=this_var }} + element += ' ' + parts[first+3].rstrip('}')[1:] + + element += rdelim + return element + + +def convert(filename, tofilename, php_tpl): + header = ldelim + "*\n *\tAUTOMATICALLY GENERATED TEMPLATE\n *\tDO NOT EDIT THIS FILE, CHANGES WILL BE OVERWRITTEN\n *\n *" + rdelim + "\n" + tofilename.write(header) + + for line in filename: + newline = '' + st_pos = 0 + brack_pos = line.find('{{') + + if php_tpl: + # If php_tpl is True, this script will only convert variables in quotes, like '$variable' + # or "$variable". This is for .tpl files that produce PHP scripts, where you don't want + # all the PHP variables converted into Smarty variables + pattern1 = re.compile(r""" +([\'\"]\$\[[a-zA-Z]\w* +(\. +(\d+|[a-zA-Z][\w-]*) +)* +(\|[\w\$:\.]*)* +\][\'\"]) +""", re.VERBOSE) + pattern2 = re.compile(r""" +([\'\"]\$[a-zA-Z]\w* +(\. +(\d+|[a-zA-Z][\w-]*) +)* +(\|[\w\$:\.]*)* +[\'\"]) +""", re.VERBOSE) + else: + # Compile the pattern for bracket-style variables, e.g. $[variable.key|filter:arg1:arg2|filter2:arg1:arg2] + # Note that dashes are only allowed in array keys if the key doesn't start + # with a number, e.g. $[variable.key-id] is ok but $[variable.12-id] isn't + # + # Doesn't currently process the argument position key 'x', i.e. filter:arg1:x:arg2 doesn't get + # changed to arg1|filter:variable:arg2 like Smarty requires + # + # Filter arguments can be variables, e.g. $variable, but currently can't have array keys with dashes + # like filter:$variable.key-name + pattern1 = re.compile(r""" +(\$\[[a-zA-Z]\w* +(\. +(\d+|[a-zA-Z][\w-]*) +)* +(\|[\w\$:\.]*)* +\]) +""", re.VERBOSE) + + # Compile the pattern for normal style variables, e.g. $variable.key + pattern2 = re.compile(r""" +(\$[a-zA-Z]\w* +(\. +(\d+|[a-zA-Z][\w-]*) +)* +(\|[\w\$:\.]*)* +) +""", re.VERBOSE) + + while brack_pos > -1: + if brack_pos > st_pos: + line_segment = line[st_pos:brack_pos] + line_segment = pattern2.sub(fToSmarty, line_segment) + newline += pattern1.sub(fToSmarty, line_segment) + + end_brack_pos = line.find('}}', brack_pos) + if end_brack_pos < 0: + print "Error: no matching bracket found" + + newline += fix_element(line[brack_pos:end_brack_pos + 2]) + st_pos = end_brack_pos + 2 + + brack_pos = line.find('{{', st_pos) + + line_segment = line[st_pos:] + line_segment = pattern2.sub(fToSmarty, line_segment) + newline += pattern1.sub(fToSmarty, line_segment) + newline = newline.replace("{#", ldelim + "*") + newline = newline.replace("#}", "*" + rdelim) + tofilename.write(newline) + + +def help(pname): + print "\nUsage:" + print "\t" + pname + " -h\n\n\t\t\tShow this help screen\n" + print "\t" + pname + " -p directory\n\n\t\t\tConvert all .tpl files in directory to\n\t\t\tSmarty templates in directory/smarty3/\n" + print "\t" + pname + "\n\n\t\t\tInteractive mode\n" + + + + +# +# Main script +# + +path = '' + +try: + opts, args = getopt.getopt(sys.argv[1:], "hp:") + for opt, arg in opts: + if opt == '-h': + help(sys.argv[0]) + sys.exit() + elif opt == '-p': + path = arg +except getopt.GetoptError: + help(sys.argv[0]) + sys.exit(2) + + +if path == '': + path = raw_input('Path to template folder to convert: ') + +if path[-1:] != '/': + path = path + '/' + +outpath = path + 'smarty3/' + +if not os.path.exists(outpath): + os.makedirs(outpath) + +files = os.listdir(path) +for a_file in files: + if a_file == 'htconfig.tpl': + php_tpl = True + else: + php_tpl = False + + filename = os.path.join(path,a_file) + ext = a_file.split('.')[-1] + if os.path.isfile(filename) and ext == 'tpl': + f = open(filename, 'r') + + newfilename = os.path.join(outpath,a_file) + outf = open(newfilename, 'w') + + print "Converting " + filename + " to " + newfilename + convert(f, outf, php_tpl) + + outf.close() + f.close() + diff --git a/sources/util/importdoc b/sources/util/importdoc new file mode 100755 index 00000000..b89e12e9 --- /dev/null +++ b/sources/util/importdoc @@ -0,0 +1,33 @@ +#!/usr/bin/env php +>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: ../../include/dba/dba_driver.php:141 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "" + +#: ../../include/photo/photo_driver.php:687 ../../mod/profile_photo.php:143 +#: ../../mod/profile_photo.php:302 ../../mod/profile_photo.php:424 +#: ../../mod/photos.php:91 ../../mod/photos.php:625 +msgid "Profile Photos" +msgstr "" + +#: ../../include/text.php:395 +msgid "prev" +msgstr "" + +#: ../../include/text.php:397 +msgid "first" +msgstr "" + +#: ../../include/text.php:426 +msgid "last" +msgstr "" + +#: ../../include/text.php:429 +msgid "next" +msgstr "" + +#: ../../include/text.php:439 +msgid "older" +msgstr "" + +#: ../../include/text.php:441 +msgid "newer" +msgstr "" + +#: ../../include/text.php:834 +msgid "No connections" +msgstr "" + +#: ../../include/text.php:848 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/text.php:861 ../../mod/viewconnections.php:104 +msgid "View Connections" +msgstr "" + +#: ../../include/text.php:918 ../../include/text.php:930 +#: ../../include/nav.php:165 ../../include/apps.php:147 +#: ../../mod/search.php:38 +msgid "Search" +msgstr "" + +#: ../../include/text.php:919 ../../include/text.php:931 +#: ../../include/widgets.php:192 ../../mod/rbmark.php:28 +#: ../../mod/rbmark.php:98 ../../mod/filer.php:50 ../../mod/admin.php:1448 +#: ../../mod/admin.php:1468 +msgid "Save" +msgstr "" + +#: ../../include/text.php:994 +msgid "poke" +msgstr "" + +#: ../../include/text.php:994 ../../include/conversation.php:243 +msgid "poked" +msgstr "" + +#: ../../include/text.php:995 +msgid "ping" +msgstr "" + +#: ../../include/text.php:995 +msgid "pinged" +msgstr "" + +#: ../../include/text.php:996 +msgid "prod" +msgstr "" + +#: ../../include/text.php:996 +msgid "prodded" +msgstr "" + +#: ../../include/text.php:997 +msgid "slap" +msgstr "" + +#: ../../include/text.php:997 +msgid "slapped" +msgstr "" + +#: ../../include/text.php:998 +msgid "finger" +msgstr "" + +#: ../../include/text.php:998 +msgid "fingered" +msgstr "" + +#: ../../include/text.php:999 +msgid "rebuff" +msgstr "" + +#: ../../include/text.php:999 +msgid "rebuffed" +msgstr "" + +#: ../../include/text.php:1009 +msgid "happy" +msgstr "" + +#: ../../include/text.php:1010 +msgid "sad" +msgstr "" + +#: ../../include/text.php:1011 +msgid "mellow" +msgstr "" + +#: ../../include/text.php:1012 +msgid "tired" +msgstr "" + +#: ../../include/text.php:1013 +msgid "perky" +msgstr "" + +#: ../../include/text.php:1014 +msgid "angry" +msgstr "" + +#: ../../include/text.php:1015 +msgid "stupified" +msgstr "" + +#: ../../include/text.php:1016 +msgid "puzzled" +msgstr "" + +#: ../../include/text.php:1017 +msgid "interested" +msgstr "" + +#: ../../include/text.php:1018 +msgid "bitter" +msgstr "" + +#: ../../include/text.php:1019 +msgid "cheerful" +msgstr "" + +#: ../../include/text.php:1020 +msgid "alive" +msgstr "" + +#: ../../include/text.php:1021 +msgid "annoyed" +msgstr "" + +#: ../../include/text.php:1022 +msgid "anxious" +msgstr "" + +#: ../../include/text.php:1023 +msgid "cranky" +msgstr "" + +#: ../../include/text.php:1024 +msgid "disturbed" +msgstr "" + +#: ../../include/text.php:1025 +msgid "frustrated" +msgstr "" + +#: ../../include/text.php:1026 +msgid "depressed" +msgstr "" + +#: ../../include/text.php:1027 +msgid "motivated" +msgstr "" + +#: ../../include/text.php:1028 +msgid "relaxed" +msgstr "" + +#: ../../include/text.php:1029 +msgid "surprised" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Monday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Tuesday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Wednesday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Thursday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Friday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Saturday" +msgstr "" + +#: ../../include/text.php:1201 +msgid "Sunday" +msgstr "" + +#: ../../include/text.php:1205 +msgid "January" +msgstr "" + +#: ../../include/text.php:1205 +msgid "February" +msgstr "" + +#: ../../include/text.php:1205 +msgid "March" +msgstr "" + +#: ../../include/text.php:1205 +msgid "April" +msgstr "" + +#: ../../include/text.php:1205 +msgid "May" +msgstr "" + +#: ../../include/text.php:1205 +msgid "June" +msgstr "" + +#: ../../include/text.php:1205 +msgid "July" +msgstr "" + +#: ../../include/text.php:1205 +msgid "August" +msgstr "" + +#: ../../include/text.php:1205 +msgid "September" +msgstr "" + +#: ../../include/text.php:1205 +msgid "October" +msgstr "" + +#: ../../include/text.php:1205 +msgid "November" +msgstr "" + +#: ../../include/text.php:1205 +msgid "December" +msgstr "" + +#: ../../include/text.php:1310 +msgid "unknown.???" +msgstr "" + +#: ../../include/text.php:1311 +msgid "bytes" +msgstr "" + +#: ../../include/text.php:1347 +msgid "remove category" +msgstr "" + +#: ../../include/text.php:1422 +msgid "remove from file" +msgstr "" + +#: ../../include/text.php:1498 ../../include/text.php:1509 +#: ../../mod/connedit.php:667 +msgid "Click to open/close" +msgstr "" + +#: ../../include/text.php:1665 ../../mod/events.php:444 +msgid "Link to Source" +msgstr "" + +#: ../../include/text.php:1686 ../../include/text.php:1757 +msgid "default" +msgstr "" + +#: ../../include/text.php:1694 +msgid "Page layout" +msgstr "" + +#: ../../include/text.php:1694 +msgid "You can create your own with the layouts tool" +msgstr "" + +#: ../../include/text.php:1735 +msgid "Page content type" +msgstr "" + +#: ../../include/text.php:1769 +msgid "Select an alternate language" +msgstr "" + +<<<<<<< HEAD +#: ../../include/text.php:1888 ../../include/conversation.php:120 +#: ../../include/diaspora.php:2082 ../../mod/like.php:346 +======= +#: ../../include/text.php:1888 ../../include/diaspora.php:2115 +#: ../../include/conversation.php:120 ../../mod/like.php:346 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +#: ../../mod/tagger.php:43 +msgid "photo" +msgstr "" + +#: ../../include/text.php:1891 ../../include/conversation.php:123 +#: ../../mod/like.php:348 ../../mod/tagger.php:47 +msgid "event" +msgstr "" + +<<<<<<< HEAD +#: ../../include/text.php:1894 ../../include/conversation.php:148 +#: ../../include/diaspora.php:2082 ../../mod/like.php:346 +======= +#: ../../include/text.php:1894 ../../include/diaspora.php:2115 +#: ../../include/conversation.php:148 ../../mod/like.php:346 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +msgid "status" +msgstr "" + +#: ../../include/text.php:1896 ../../include/conversation.php:150 +#: ../../mod/tagger.php:53 +msgid "comment" +msgstr "" + +#: ../../include/text.php:1901 +msgid "activity" +msgstr "" + +#: ../../include/text.php:2196 +msgid "Design Tools" +msgstr "" + +#: ../../include/text.php:2199 ../../mod/blocks.php:147 +msgid "Blocks" +msgstr "" + +#: ../../include/text.php:2200 ../../mod/menu.php:98 +msgid "Menus" +msgstr "" + +#: ../../include/text.php:2201 ../../mod/layouts.php:174 +msgid "Layouts" +msgstr "" + +#: ../../include/text.php:2202 +msgid "Pages" +msgstr "" + +#: ../../include/text.php:2553 ../../include/RedDAV/RedBrowser.php:131 +msgid "Collection" +msgstr "" + +#: ../../include/bbcode.php:122 ../../include/bbcode.php:761 +#: ../../include/bbcode.php:764 ../../include/bbcode.php:769 +#: ../../include/bbcode.php:772 ../../include/bbcode.php:775 +#: ../../include/bbcode.php:778 ../../include/bbcode.php:783 +#: ../../include/bbcode.php:786 ../../include/bbcode.php:791 +#: ../../include/bbcode.php:794 ../../include/bbcode.php:797 +#: ../../include/bbcode.php:800 +msgid "Image/photo" +msgstr "" + +<<<<<<< HEAD +#: ../../include/bbcode.php:161 ../../include/bbcode.php:811 +msgid "Encrypted content" +msgstr "" + +#: ../../include/bbcode.php:178 +======= +#: ../../include/diaspora.php:2144 ../../include/conversation.php:164 +#: ../../mod/like.php:394 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#, php-format +msgid "Install %s element: " +msgstr "" + +<<<<<<< HEAD +#: ../../include/bbcode.php:188 ../../mod/impel.php:37 +msgid "webpage" +msgstr "" + +#: ../../include/bbcode.php:191 ../../mod/impel.php:47 +msgid "layout" +msgstr "" + +#: ../../include/bbcode.php:194 ../../mod/impel.php:42 +msgid "block" +msgstr "" + +#: ../../include/bbcode.php:208 +msgid "QR code" +msgstr "" + +#: ../../include/bbcode.php:259 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +======= +#: ../../include/diaspora.php:2490 +msgid "Please choose" +msgstr "" + +#: ../../include/diaspora.php:2492 +msgid "Agree" +msgstr "" + +#: ../../include/diaspora.php:2494 +msgid "Disagree" +msgstr "" + +#: ../../include/diaspora.php:2496 +msgid "Abstain" +msgstr "" + +#: ../../include/diaspora.php:2518 ../../include/diaspora.php:2529 +#: ../../include/network.php:1586 ../../include/enotify.php:59 +#: ../../mod/p.php:46 +msgid "$projectname" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../include/bbcode.php:261 +msgid "post" +msgstr "" + +#: ../../include/bbcode.php:511 +msgid "Different viewers will see this text differently" +msgstr "" + +#: ../../include/bbcode.php:722 +msgid "$1 spoiler" +msgstr "" + +#: ../../include/bbcode.php:749 +msgid "$1 wrote:" +msgstr "" + +<<<<<<< HEAD +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +======= +#: ../../include/Import/import_diaspora.php:42 ../../mod/import.php:156 +msgid "Unable to create a unique channel address. Import failed." +msgstr "" + +#: ../../include/Import/import_diaspora.php:140 ../../mod/import.php:504 +msgid "Import completed." +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "" + +#: ../../include/group.php:235 +msgid "Default privacy group for new contacts" +msgstr "" + +#: ../../include/group.php:254 ../../mod/admin.php:822 +msgid "All Channels" +msgstr "" + +#: ../../include/group.php:276 +msgid "edit" +msgstr "" + +#: ../../include/group.php:298 +msgid "Collections" +msgstr "" + +#: ../../include/group.php:299 +msgid "Edit collection" +msgstr "" + +#: ../../include/group.php:300 +msgid "Add new collection" +msgstr "" + +#: ../../include/group.php:301 +msgid "Channels not in any collection" +msgstr "" + +#: ../../include/group.php:303 ../../include/widgets.php:275 +msgid "add" +msgstr "" + +#: ../../include/account.php:27 +msgid "Not a valid email address" +msgstr "" + +#: ../../include/account.php:29 +msgid "Your email domain is not among those allowed on this site" +msgstr "" + +#: ../../include/account.php:35 +msgid "Your email address is already registered at this site." +msgstr "" + +#: ../../include/account.php:67 +msgid "An invitation is required." +msgstr "" + +#: ../../include/account.php:71 +msgid "Invitation could not be verified." +msgstr "" + +#: ../../include/account.php:121 +msgid "Please enter the required information." +msgstr "" + +#: ../../include/account.php:188 +msgid "Failed to store account information." +msgstr "" + +#: ../../include/account.php:246 +#, php-format +msgid "Registration confirmation for %s" +msgstr "" + +#: ../../include/account.php:312 +#, php-format +msgid "Registration request at %s" +msgstr "" + +#: ../../include/account.php:314 ../../include/account.php:341 +#: ../../include/account.php:401 ../../include/network.php:1632 +msgid "Administrator" +msgstr "" + +#: ../../include/account.php:336 +msgid "your registration password" +msgstr "" + +#: ../../include/account.php:339 ../../include/account.php:399 +#, php-format +msgid "Registration details for %s" +msgstr "" + +#: ../../include/account.php:408 +msgid "Account approved." +msgstr "" + +#: ../../include/account.php:447 +#, php-format +msgid "Registration revoked for %s" +msgstr "" + +#: ../../include/account.php:492 +msgid "Account verified. Please login." +msgstr "" + +#: ../../include/account.php:705 ../../include/account.php:707 +msgid "Click here to upgrade." +msgstr "" + +#: ../../include/account.php:713 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "" + +#: ../../include/account.php:718 +msgid "This action is not available under your subscription plan." +msgstr "" + +#: ../../include/datetime.php:48 +msgid "Miscellaneous" +msgstr "" + +#: ../../include/datetime.php:132 +msgid "YYYY-MM-DD or MM-DD" +msgstr "" + +#: ../../include/datetime.php:235 ../../mod/events.php:635 +#: ../../mod/appman.php:91 ../../mod/appman.php:92 +msgid "Required" +msgstr "" + +#: ../../include/datetime.php:262 ../../boot.php:2354 +msgid "never" +msgstr "" + +#: ../../include/datetime.php:268 +msgid "less than a second ago" +msgstr "" + +#: ../../include/datetime.php:271 +msgid "year" +msgstr "" + +#: ../../include/datetime.php:271 +msgid "years" +msgstr "" + +#: ../../include/datetime.php:272 +msgid "month" +msgstr "" + +#: ../../include/datetime.php:272 +msgid "months" +msgstr "" + +#: ../../include/datetime.php:273 +msgid "week" +msgstr "" + +#: ../../include/datetime.php:273 +msgid "weeks" +msgstr "" + +#: ../../include/datetime.php:274 +msgid "day" +msgstr "" + +#: ../../include/datetime.php:274 +msgid "days" +msgstr "" + +#: ../../include/datetime.php:275 +msgid "hour" +msgstr "" + +#: ../../include/datetime.php:275 +msgid "hours" +msgstr "" + +#: ../../include/datetime.php:276 +msgid "minute" +msgstr "" + +#: ../../include/datetime.php:276 +msgid "minutes" +msgstr "" + +#: ../../include/datetime.php:277 +msgid "second" +msgstr "" + +#: ../../include/datetime.php:277 +msgid "seconds" +msgstr "" + +#: ../../include/datetime.php:285 +#, php-format +msgctxt "e.g. 22 hours ago, 1 minute ago" +msgid "%1$d %2$s ago" +msgstr "" + +#: ../../include/datetime.php:519 +#, php-format +msgid "%1$s's birthday" +msgstr "" + +#: ../../include/datetime.php:520 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "" + +#: ../../include/page_widgets.php:8 ../../include/page_widgets.php:36 +#: ../../include/RedDAV/RedBrowser.php:269 ../../include/ItemObject.php:100 +#: ../../include/apps.php:254 ../../include/menu.php:103 +#: ../../mod/settings.php:649 ../../mod/webpages.php:180 +#: ../../mod/thing.php:227 ../../mod/connections.php:382 +#: ../../mod/connections.php:395 ../../mod/connections.php:414 +#: ../../mod/blocks.php:153 ../../mod/editlayout.php:139 +#: ../../mod/editwebpage.php:178 ../../mod/editpost.php:113 +#: ../../mod/menu.php:103 ../../mod/editblock.php:140 +#: ../../mod/layouts.php:183 +msgid "Edit" +msgstr "" + +#: ../../include/page_widgets.php:39 ../../mod/webpages.php:186 +#: ../../mod/blocks.php:159 ../../mod/layouts.php:188 +msgid "View" +msgstr "" + +#: ../../include/page_widgets.php:40 ../../include/ItemObject.php:677 +#: ../../include/conversation.php:1155 ../../mod/webpages.php:187 +#: ../../mod/events.php:653 ../../mod/photos.php:970 +#: ../../mod/editwebpage.php:214 ../../mod/editpost.php:150 +#: ../../mod/editblock.php:176 +msgid "Preview" +msgstr "" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:188 +msgid "Actions" +msgstr "" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:189 +msgid "Page Link" +msgstr "" + +#: ../../include/page_widgets.php:43 +msgid "Title" +msgstr "" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:191 +#: ../../mod/blocks.php:150 ../../mod/layouts.php:181 +msgid "Created" +msgstr "" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:192 +#: ../../mod/blocks.php:151 ../../mod/layouts.php:182 +msgid "Edited" +msgstr "" + +#: ../../include/api.php:1193 +msgid "Public Timeline" +msgstr "" + +#: ../../include/comanche.php:34 ../../mod/admin.php:386 +#: ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "" + +#: ../../include/dir_fns.php:143 +msgid "Directory Options" +msgstr "" + +#: ../../include/dir_fns.php:144 +msgid "Alphabetic" +msgstr "" + +#: ../../include/dir_fns.php:145 +msgid "Reverse Alphabetic" +msgstr "" + +#: ../../include/dir_fns.php:146 +msgid "Newest to Oldest" +msgstr "" + +#: ../../include/dir_fns.php:147 +msgid "Oldest to Newest" +msgstr "" + +#: ../../include/dir_fns.php:148 +msgid "Sort" +msgstr "" + +#: ../../include/dir_fns.php:152 +msgid "Safe Mode" +msgstr "" + +#: ../../include/dir_fns.php:154 +msgid "Public Forums Only" +msgstr "" + +#: ../../include/dir_fns.php:155 +msgid "This Website Only" +msgstr "" + +#: ../../include/event.php:19 ../../include/bb2diaspora.php:451 +msgid "l F d, Y \\@ g:i A" +msgstr "" + +#: ../../include/event.php:27 ../../include/bb2diaspora.php:457 +msgid "Starts:" +msgstr "" + +#: ../../include/event.php:37 ../../include/bb2diaspora.php:465 +msgid "Finishes:" +msgstr "" + +<<<<<<< HEAD +#: ../../include/event.php:47 ../../include/bb2diaspora.php:473 +#: ../../include/identity.php:875 ../../mod/events.php:647 +#: ../../mod/directory.php:234 +======= +#: ../../include/event.php:47 ../../include/bb2diaspora.php:481 +#: ../../include/identity.php:879 ../../mod/events.php:647 +#: ../../mod/directory.php:295 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Location:" +msgstr "" + +#: ../../include/event.php:391 +msgid "This event has been added to your calendar." +msgstr "" + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "" + +#: ../../include/js_strings.php:6 ../../include/ItemObject.php:667 +#: ../../mod/photos.php:968 ../../mod/photos.php:1086 +msgid "Comment" +msgstr "" + +#: ../../include/js_strings.php:7 ../../include/ItemObject.php:384 +msgid "[+] show all" +msgstr "" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:39 +msgid "everybody" +msgstr "" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "" + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "" + +#: ../../include/js_strings.php:18 +msgid "Nothing new here" +msgstr "" + +#: ../../include/js_strings.php:19 +msgid "Rate This Channel (this is public)" +msgstr "" + +#: ../../include/js_strings.php:20 ../../mod/rate.php:156 +msgid "Rating" +msgstr "" + +#: ../../include/js_strings.php:21 +msgid "Describe (optional)" +msgstr "" + +#: ../../include/js_strings.php:22 ../../include/ItemObject.php:668 +<<<<<<< HEAD +#: ../../mod/settings.php:587 ../../mod/settings.php:689 +#: ../../mod/settings.php:715 ../../mod/settings.php:743 +#: ../../mod/settings.php:766 ../../mod/settings.php:848 +#: ../../mod/settings.php:1044 ../../mod/xchan.php:11 ../../mod/connect.php:93 +#: ../../mod/thing.php:275 ../../mod/thing.php:318 ../../mod/events.php:656 +#: ../../mod/group.php:81 ../../mod/photos.php:565 ../../mod/photos.php:642 +#: ../../mod/photos.php:929 ../../mod/photos.php:969 ../../mod/photos.php:1087 +#: ../../mod/pdledit.php:58 ../../mod/import.php:504 ../../mod/chat.php:177 +#: ../../mod/chat.php:211 ../../mod/rate.php:167 ../../mod/invite.php:142 +#: ../../mod/locs.php:105 ../../mod/sources.php:104 ../../mod/sources.php:138 +#: ../../mod/filestorage.php:156 ../../mod/fsuggest.php:108 +#: ../../mod/poke.php:166 ../../mod/profiles.php:667 ../../mod/setup.php:327 +#: ../../mod/setup.php:367 ../../mod/admin.php:446 ../../mod/admin.php:810 +#: ../../mod/admin.php:977 ../../mod/admin.php:1109 ../../mod/admin.php:1303 +#: ../../mod/admin.php:1388 ../../mod/mitem.php:237 ../../mod/mood.php:134 +#: ../../mod/connedit.php:679 ../../mod/mail.php:355 ../../mod/appman.php:99 +#: ../../mod/poll.php:68 ../../mod/bulksetclose.php:24 +#: ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:97 +======= +#: ../../mod/xchan.php:11 ../../mod/connect.php:93 ../../mod/thing.php:275 +#: ../../mod/thing.php:318 ../../mod/events.php:656 ../../mod/group.php:81 +#: ../../mod/photos.php:577 ../../mod/photos.php:654 ../../mod/photos.php:941 +#: ../../mod/photos.php:981 ../../mod/photos.php:1099 ../../mod/pdledit.php:58 +#: ../../mod/import.php:534 ../../mod/chat.php:177 ../../mod/chat.php:211 +#: ../../mod/rate.php:167 ../../mod/invite.php:142 ../../mod/locs.php:105 +#: ../../mod/sources.php:104 ../../mod/sources.php:138 +#: ../../mod/filestorage.php:156 ../../mod/fsuggest.php:108 +#: ../../mod/poke.php:166 ../../mod/profiles.php:667 ../../mod/setup.php:327 +#: ../../mod/setup.php:367 ../../mod/admin.php:453 ../../mod/admin.php:819 +#: ../../mod/admin.php:986 ../../mod/admin.php:1118 ../../mod/admin.php:1312 +#: ../../mod/admin.php:1397 ../../mod/settings.php:588 +#: ../../mod/settings.php:692 ../../mod/settings.php:718 +#: ../../mod/settings.php:746 ../../mod/settings.php:769 +#: ../../mod/settings.php:854 ../../mod/settings.php:1050 +#: ../../mod/mitem.php:237 ../../mod/mood.php:134 ../../mod/connedit.php:688 +#: ../../mod/mail.php:355 ../../mod/appman.php:99 ../../mod/pconfig.php:108 +#: ../../mod/poll.php:68 ../../mod/bulksetclose.php:24 +#: ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:99 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Submit" +msgstr "" + +#: ../../include/js_strings.php:23 +msgid "Please enter a link URL" +msgstr "" + +#: ../../include/js_strings.php:24 +msgid "Unsaved changes. Are you sure you wish to leave this page?" +msgstr "" + +#: ../../include/js_strings.php:26 +msgid "timeago.prefixAgo" +msgstr "" + +#: ../../include/js_strings.php:27 +msgid "timeago.prefixFromNow" +msgstr "" + +#: ../../include/js_strings.php:28 +msgid "ago" +msgstr "" + +#: ../../include/js_strings.php:29 +msgid "from now" +msgstr "" + +#: ../../include/js_strings.php:30 +msgid "less than a minute" +msgstr "" + +#: ../../include/js_strings.php:31 +msgid "about a minute" +msgstr "" + +#: ../../include/js_strings.php:32 +#, php-format +msgid "%d minutes" +msgstr "" + +#: ../../include/js_strings.php:33 +msgid "about an hour" +msgstr "" + +#: ../../include/js_strings.php:34 +#, php-format +msgid "about %d hours" +msgstr "" + +#: ../../include/js_strings.php:35 +msgid "a day" +msgstr "" + +#: ../../include/js_strings.php:36 +#, php-format +msgid "%d days" +msgstr "" + +#: ../../include/js_strings.php:37 +msgid "about a month" +msgstr "" + +#: ../../include/js_strings.php:38 +#, php-format +msgid "%d months" +msgstr "" + +#: ../../include/js_strings.php:39 +msgid "about a year" +msgstr "" + +#: ../../include/js_strings.php:40 +#, php-format +msgid "%d years" +msgstr "" + +#: ../../include/js_strings.php:41 +msgid " " +msgstr "" + +#: ../../include/js_strings.php:42 +msgid "timeago.numbers" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:107 +#: ../../include/RedDAV/RedBrowser.php:268 +msgid "parent" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:134 +msgid "Principal" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:137 +msgid "Addressbook" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:140 +msgid "Calendar" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:143 +msgid "Schedule Inbox" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:146 +msgid "Schedule Outbox" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:164 ../../include/conversation.php:1019 +#: ../../include/apps.php:336 ../../include/apps.php:387 +#: ../../mod/photos.php:681 ../../mod/photos.php:1119 +msgid "Unknown" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:227 +#, php-format +msgid "%1$s used" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:232 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:251 ../../include/nav.php:98 +#: ../../include/conversation.php:1609 ../../include/apps.php:135 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:253 +msgid "Total" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:255 +msgid "Shared" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:256 +#: ../../include/RedDAV/RedBrowser.php:306 ../../mod/webpages.php:179 +#: ../../mod/blocks.php:152 ../../mod/menu.php:107 ../../mod/layouts.php:175 +#: ../../mod/new_channel.php:121 +msgid "Create" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:257 +#: ../../include/RedDAV/RedBrowser.php:308 ../../mod/profile_photo.php:362 +#: ../../mod/photos.php:706 ../../mod/photos.php:1236 +msgid "Upload" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:264 ../../mod/settings.php:589 +#: ../../mod/settings.php:615 ../../mod/admin.php:985 +#: ../../mod/sharedwithme.php:95 +msgid "Name" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:265 +msgid "Type" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:266 ../../mod/sharedwithme.php:97 +msgid "Size" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:267 ../../mod/sharedwithme.php:98 +msgid "Last Modified" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:270 ../../include/ItemObject.php:120 +#: ../../include/conversation.php:660 ../../include/apps.php:255 +<<<<<<< HEAD +#: ../../mod/settings.php:650 ../../mod/webpages.php:182 +#: ../../mod/thing.php:228 ../../mod/group.php:176 ../../mod/blocks.php:155 +#: ../../mod/photos.php:1050 ../../mod/editlayout.php:107 +#: ../../mod/editwebpage.php:225 ../../mod/admin.php:817 +#: ../../mod/admin.php:979 ../../mod/editblock.php:113 +#: ../../mod/connedit.php:543 +======= +#: ../../mod/webpages.php:183 ../../mod/thing.php:228 ../../mod/group.php:176 +#: ../../mod/blocks.php:155 ../../mod/photos.php:1062 +#: ../../mod/editlayout.php:107 ../../mod/editwebpage.php:225 +#: ../../mod/admin.php:826 ../../mod/admin.php:988 ../../mod/editblock.php:113 +#: ../../mod/settings.php:651 ../../mod/connedit.php:549 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Delete" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:305 +msgid "Create new folder" +msgstr "" + +#: ../../include/RedDAV/RedBrowser.php:307 +msgid "Upload file" +msgstr "" + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "" + +#: ../../include/network.php:635 +msgid "view full size" +msgstr "" + +#: ../../include/network.php:1585 ../../include/enotify.php:58 +msgid "$Projectname Notification" +msgstr "" + +#: ../../include/network.php:1588 ../../include/enotify.php:61 +msgid "Thank You," +msgstr "" + +#: ../../include/network.php:1590 ../../include/enotify.php:63 +#, php-format +msgid "%s Administrator" +msgstr "" + +#: ../../include/network.php:1646 +msgid "No Subject" +msgstr "" + +#: ../../include/features.php:38 +msgid "General Features" +msgstr "" + +#: ../../include/features.php:40 +msgid "Content Expiration" +msgstr "" + +#: ../../include/features.php:40 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "" + +#: ../../include/features.php:41 +msgid "Multiple Profiles" +msgstr "" + +#: ../../include/features.php:41 +msgid "Ability to create multiple profiles" +msgstr "" + +#: ../../include/features.php:42 +msgid "Advanced Profiles" +msgstr "" + +#: ../../include/features.php:42 +msgid "Additional profile sections and selections" +msgstr "" + +#: ../../include/features.php:43 +msgid "Profile Import/Export" +msgstr "" + +#: ../../include/features.php:43 +msgid "Save and load profile details across sites/channels" +msgstr "" + +#: ../../include/features.php:44 +msgid "Web Pages" +msgstr "" + +#: ../../include/features.php:44 +msgid "Provide managed web pages on your channel" +msgstr "" + +#: ../../include/features.php:45 +msgid "Private Notes" +msgstr "" + +#: ../../include/features.php:45 +msgid "Enables a tool to store notes and reminders" +msgstr "" + +#: ../../include/features.php:46 +msgid "Navigation Channel Select" +msgstr "" + +#: ../../include/features.php:46 +msgid "Change channels directly from within the navigation dropdown menu" +msgstr "" + +#: ../../include/features.php:47 +msgid "Photo Location" +msgstr "" + +#: ../../include/features.php:47 +msgid "If location data is available on uploaded photos, link this to a map." +msgstr "" + +#: ../../include/features.php:49 +msgid "Expert Mode" +msgstr "" + +#: ../../include/features.php:49 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "" + +#: ../../include/features.php:50 +msgid "Premium Channel" +msgstr "" + +#: ../../include/features.php:50 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "" + +#: ../../include/features.php:55 +msgid "Post Composition Features" +msgstr "" + +#: ../../include/features.php:57 +msgid "Use Markdown" +msgstr "" + +#: ../../include/features.php:57 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "" + +#: ../../include/features.php:58 +msgid "Large Photos" +msgstr "" + +#: ../../include/features.php:58 +msgid "" +"Include large (640px) photo thumbnails in posts. If not enabled, use small " +"(320px) photo thumbnails" +msgstr "" + +#: ../../include/features.php:59 ../../include/widgets.php:546 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "" + +#: ../../include/features.php:59 +msgid "Automatically import channel content from other channels or feeds" +msgstr "" + +#: ../../include/features.php:60 +msgid "Even More Encryption" +msgstr "" + +#: ../../include/features.php:60 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "" + +#: ../../include/features.php:61 +msgid "Enable voting tools" +msgstr "" + +#: ../../include/features.php:61 +msgid "Provide a class of post which others can vote on" +msgstr "" + +#: ../../include/features.php:67 +msgid "Network and Stream Filtering" +msgstr "" + +#: ../../include/features.php:68 +msgid "Search by Date" +msgstr "" + +#: ../../include/features.php:68 +msgid "Ability to select posts by date ranges" +msgstr "" + +#: ../../include/features.php:69 +msgid "Collections Filter" +msgstr "" + +#: ../../include/features.php:69 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "" + +#: ../../include/features.php:70 ../../include/widgets.php:274 +msgid "Saved Searches" +msgstr "" + +#: ../../include/features.php:70 +msgid "Save search terms for re-use" +msgstr "" + +#: ../../include/features.php:71 +msgid "Network Personal Tab" +msgstr "" + +#: ../../include/features.php:71 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "" + +#: ../../include/features.php:72 +msgid "Network New Tab" +msgstr "" + +#: ../../include/features.php:72 +msgid "Enable tab to display all new Network activity" +msgstr "" + +#: ../../include/features.php:73 +msgid "Affinity Tool" +msgstr "" + +#: ../../include/features.php:73 +msgid "Filter stream activity by depth of relationships" +msgstr "" + +#: ../../include/features.php:74 +msgid "Connection Filtering" +msgstr "" + +#: ../../include/features.php:74 +msgid "Filter incoming posts from connections based on keywords/content" +msgstr "" + +#: ../../include/features.php:75 +msgid "Suggest Channels" +msgstr "" + +#: ../../include/features.php:75 +msgid "Show channel suggestions" +msgstr "" + +#: ../../include/features.php:80 +msgid "Post/Comment Tools" +msgstr "" + +#: ../../include/features.php:81 +msgid "Tagging" +msgstr "" + +#: ../../include/features.php:81 +msgid "Ability to tag existing posts" +msgstr "" + +#: ../../include/features.php:82 +msgid "Post Categories" +msgstr "" + +#: ../../include/features.php:82 +msgid "Add categories to your posts" +msgstr "" + +#: ../../include/features.php:83 ../../include/widgets.php:304 +#: ../../include/contact_widgets.php:57 +msgid "Saved Folders" +msgstr "" + +#: ../../include/features.php:83 +msgid "Ability to file posts under folders" +msgstr "" + +#: ../../include/features.php:84 +msgid "Dislike Posts" +msgstr "" + +#: ../../include/features.php:84 +msgid "Ability to dislike posts/comments" +msgstr "" + +#: ../../include/features.php:85 +msgid "Star Posts" +msgstr "" + +#: ../../include/features.php:85 +msgid "Ability to mark special posts with a star indicator" +msgstr "" + +#: ../../include/features.php:86 +msgid "Tag Cloud" +msgstr "" + +#: ../../include/features.php:86 +msgid "Provide a personal tag cloud on your channel page" +msgstr "" + +#: ../../include/widgets.php:35 ../../include/taxonomy.php:264 +#: ../../include/contact_widgets.php:92 +msgid "Categories" +msgstr "" + +#: ../../include/widgets.php:91 ../../include/nav.php:163 +#: ../../mod/apps.php:34 +msgid "Apps" +msgstr "" + +#: ../../include/widgets.php:92 +msgid "System" +msgstr "" + +#: ../../include/widgets.php:94 ../../include/conversation.php:1504 +msgid "Personal" +msgstr "" + +#: ../../include/widgets.php:95 +msgid "Create Personal App" +msgstr "" + +#: ../../include/widgets.php:96 +msgid "Edit Personal App" +msgstr "" + +#: ../../include/widgets.php:136 ../../include/widgets.php:175 +#: ../../include/Contact.php:107 ../../include/conversation.php:945 +<<<<<<< HEAD +#: ../../include/identity.php:824 ../../mod/match.php:64 +#: ../../mod/directory.php:302 ../../mod/suggest.php:52 +======= +#: ../../include/identity.php:828 ../../mod/directory.php:309 +#: ../../mod/match.php:64 ../../mod/suggest.php:52 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Connect" +msgstr "" + +#: ../../include/widgets.php:138 ../../mod/suggest.php:54 +msgid "Ignore/Hide" +msgstr "" + +#: ../../include/widgets.php:143 ../../mod/connections.php:268 +msgid "Suggestions" +msgstr "" + +#: ../../include/widgets.php:144 +msgid "See more..." +msgstr "" + +#: ../../include/widgets.php:166 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "" + +#: ../../include/widgets.php:172 +msgid "Add New Connection" +msgstr "" + +#: ../../include/widgets.php:173 +msgid "Enter the channel address" +msgstr "" + +#: ../../include/widgets.php:174 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "" + +#: ../../include/widgets.php:190 +msgid "Notes" +msgstr "" + +#: ../../include/widgets.php:266 +msgid "Remove term" +msgstr "" + +#: ../../include/widgets.php:307 ../../include/contact_widgets.php:60 +#: ../../include/contact_widgets.php:95 +msgid "Everything" +msgstr "" + +#: ../../include/widgets.php:349 +msgid "Archives" +msgstr "" + +#: ../../include/widgets.php:427 ../../mod/connedit.php:578 +msgid "Me" +msgstr "" + +#: ../../include/widgets.php:428 ../../mod/connedit.php:579 +msgid "Family" +msgstr "" + +#: ../../include/widgets.php:429 ../../include/identity.php:394 +#: ../../include/identity.php:395 ../../include/identity.php:402 +<<<<<<< HEAD +#: ../../include/profile_selectors.php:80 ../../mod/settings.php:344 +#: ../../mod/settings.php:348 ../../mod/settings.php:349 +#: ../../mod/settings.php:352 ../../mod/settings.php:363 +#: ../../mod/connedit.php:574 +======= +#: ../../include/profile_selectors.php:80 ../../mod/settings.php:345 +#: ../../mod/settings.php:349 ../../mod/settings.php:350 +#: ../../mod/settings.php:353 ../../mod/settings.php:364 +#: ../../mod/connedit.php:580 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Friends" +msgstr "" + +#: ../../include/widgets.php:430 ../../mod/connedit.php:581 +msgid "Acquaintances" +msgstr "" + +#: ../../include/widgets.php:431 ../../mod/connections.php:231 +#: ../../mod/connections.php:246 ../../mod/connedit.php:582 +msgid "All" +msgstr "" + +#: ../../include/widgets.php:450 +msgid "Refresh" +msgstr "" + +#: ../../include/widgets.php:485 +msgid "Account settings" +msgstr "" + +#: ../../include/widgets.php:491 +msgid "Channel settings" +msgstr "" + +#: ../../include/widgets.php:497 +msgid "Additional features" +msgstr "" + +#: ../../include/widgets.php:503 +msgid "Feature/Addon settings" +msgstr "" + +#: ../../include/widgets.php:509 +msgid "Display settings" +msgstr "" + +#: ../../include/widgets.php:515 +msgid "Connected apps" +msgstr "" + +#: ../../include/widgets.php:521 +msgid "Export channel" +msgstr "" + +#: ../../include/widgets.php:530 ../../mod/connedit.php:659 +msgid "Connection Default Permissions" +msgstr "" + +#: ../../include/widgets.php:538 +msgid "Premium Channel Settings" +msgstr "" + +#: ../../include/widgets.php:554 ../../include/nav.php:208 +#: ../../include/apps.php:134 ../../mod/admin.php:1070 +#: ../../mod/admin.php:1270 +msgid "Settings" +msgstr "" + +#: ../../include/widgets.php:567 ../../mod/message.php:31 +#: ../../mod/mail.php:128 +msgid "Messages" +msgstr "" + +#: ../../include/widgets.php:570 +msgid "Check Mail" +msgstr "" + +#: ../../include/widgets.php:575 ../../include/nav.php:199 +msgid "New Message" +msgstr "" + +#: ../../include/widgets.php:650 +msgid "Chat Rooms" +msgstr "" + +#: ../../include/widgets.php:670 +msgid "Bookmarked Chatrooms" +msgstr "" + +#: ../../include/widgets.php:690 +msgid "Suggested Chatrooms" +msgstr "" + +#: ../../include/widgets.php:817 ../../include/widgets.php:875 +msgid "photo/image" +msgstr "" + +#: ../../include/widgets.php:970 ../../include/widgets.php:972 +msgid "Rate Me" +msgstr "" + +#: ../../include/widgets.php:976 +msgid "View Ratings" +msgstr "" + +#: ../../include/widgets.php:987 +msgid "Public Hubs" +msgstr "" + +<<<<<<< HEAD +#: ../../include/enotify.php:58 +msgid "$Projectname Notification" +msgstr "" + +#: ../../include/enotify.php:59 ../../include/diaspora.php:2467 +#: ../../include/diaspora.php:2478 ../../mod/p.php:46 +msgid "$projectname" +msgstr "" + +#: ../../include/enotify.php:61 +msgid "Thank You," +msgstr "" + +#: ../../include/enotify.php:63 +#, php-format +msgid "%s Administrator" +msgstr "" + +======= +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../include/enotify.php:96 +#, php-format +msgid "%s " +msgstr "" + +#: ../../include/enotify.php:100 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "" + +#: ../../include/enotify.php:102 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "" + +#: ../../include/enotify.php:103 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "" + +#: ../../include/enotify.php:103 +msgid "a private message" +msgstr "" + +#: ../../include/enotify.php:104 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "" + +#: ../../include/enotify.php:158 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "" + +#: ../../include/enotify.php:166 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "" + +#: ../../include/enotify.php:175 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "" + +#: ../../include/enotify.php:186 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "" + +#: ../../include/enotify.php:187 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "" + +#: ../../include/enotify.php:190 ../../include/enotify.php:205 +#: ../../include/enotify.php:231 ../../include/enotify.php:249 +#: ../../include/enotify.php:263 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "" + +#: ../../include/enotify.php:196 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "" + +#: ../../include/enotify.php:198 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "" + +#: ../../include/enotify.php:200 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "" + +#: ../../include/enotify.php:224 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "" + +#: ../../include/enotify.php:225 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "" + +#: ../../include/enotify.php:238 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "" + +#: ../../include/enotify.php:239 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "" + +#: ../../include/enotify.php:240 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "" + +#: ../../include/enotify.php:256 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "" + +#: ../../include/enotify.php:257 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "" + +#: ../../include/enotify.php:270 +msgid "[Red:Notify] Introduction received" +msgstr "" + +#: ../../include/enotify.php:271 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "" + +#: ../../include/enotify.php:272 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "" + +#: ../../include/enotify.php:276 ../../include/enotify.php:295 +#, php-format +msgid "You may visit their profile at %s" +msgstr "" + +#: ../../include/enotify.php:278 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "" + +#: ../../include/enotify.php:285 +msgid "[Red:Notify] Friend suggestion received" +msgstr "" + +#: ../../include/enotify.php:286 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "" + +#: ../../include/enotify.php:287 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from %4$s." +msgstr "" + +#: ../../include/enotify.php:293 +msgid "Name:" +msgstr "" + +#: ../../include/enotify.php:294 +msgid "Photo:" +msgstr "" + +#: ../../include/enotify.php:297 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "" + +#: ../../include/enotify.php:508 +msgid "[Red:Notify]" +msgstr "" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:813 +#: ../../mod/admin.php:822 ../../mod/id.php:15 ../../mod/id.php:16 +#: ../../boot.php:1552 +msgid "Email" +msgstr "" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "" + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "" + +#: ../../include/message.php:45 +msgid "Unable to determine sender." +msgstr "" + +#: ../../include/message.php:200 +msgid "Stored post could not be verified." +msgstr "" + +#: ../../include/follow.php:28 +msgid "Channel is blocked on this site." +msgstr "" + +#: ../../include/follow.php:33 +msgid "Channel location missing." +msgstr "" + +#: ../../include/follow.php:83 +msgid "Response from remote channel was incomplete." +msgstr "" + +#: ../../include/follow.php:100 +msgid "Channel was deleted and no longer exists." +msgstr "" + +#: ../../include/follow.php:135 ../../include/follow.php:197 +msgid "Protocol disabled." +msgstr "" + +#: ../../include/follow.php:170 +msgid "Channel discovery failed." +msgstr "" + +#: ../../include/follow.php:186 +msgid "local account not found." +msgstr "" + +#: ../../include/follow.php:215 +msgid "Cannot connect to yourself." +msgstr "" + +#: ../../include/ItemObject.php:89 ../../include/conversation.php:667 +msgid "Private Message" +msgstr "" + +#: ../../include/ItemObject.php:126 ../../include/conversation.php:659 +msgid "Select" +msgstr "" + +#: ../../include/ItemObject.php:130 +msgid "Save to Folder" +msgstr "" + +#: ../../include/ItemObject.php:151 +msgid "I will attend" +msgstr "" + +#: ../../include/ItemObject.php:151 +msgid "I will not attend" +msgstr "" + +#: ../../include/ItemObject.php:151 +msgid "I might attend" +msgstr "" + +#: ../../include/ItemObject.php:161 +msgid "I agree" +msgstr "" + +#: ../../include/ItemObject.php:161 +msgid "I disagree" +msgstr "" + +#: ../../include/ItemObject.php:161 +msgid "I abstain" +msgstr "" + +#: ../../include/ItemObject.php:175 ../../include/ItemObject.php:187 +#: ../../include/conversation.php:1677 ../../mod/photos.php:1003 +#: ../../mod/photos.php:1015 +msgid "View all" +msgstr "" + +#: ../../include/ItemObject.php:179 ../../include/taxonomy.php:396 +#: ../../include/conversation.php:1701 ../../include/identity.php:1134 +#: ../../mod/photos.php:1007 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/ItemObject.php:184 ../../include/conversation.php:1704 +#: ../../mod/photos.php:1012 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/ItemObject.php:212 +msgid "Add Star" +msgstr "" + +#: ../../include/ItemObject.php:213 +msgid "Remove Star" +msgstr "" + +#: ../../include/ItemObject.php:214 +msgid "Toggle Star Status" +msgstr "" + +#: ../../include/ItemObject.php:218 +msgid "starred" +msgstr "" + +#: ../../include/ItemObject.php:227 ../../include/conversation.php:674 +msgid "Message signature validated" +msgstr "" + +#: ../../include/ItemObject.php:228 ../../include/conversation.php:675 +msgid "Message signature incorrect" +msgstr "" + +#: ../../include/ItemObject.php:236 +msgid "Add Tag" +msgstr "" + +#: ../../include/ItemObject.php:254 ../../mod/photos.php:947 +msgid "I like this (toggle)" +msgstr "" + +#: ../../include/ItemObject.php:254 ../../include/taxonomy.php:310 +msgid "like" +msgstr "" + +#: ../../include/ItemObject.php:255 ../../mod/photos.php:948 +msgid "I don't like this (toggle)" +msgstr "" + +#: ../../include/ItemObject.php:255 ../../include/taxonomy.php:311 +msgid "dislike" +msgstr "" + +#: ../../include/ItemObject.php:259 +msgid "Share This" +msgstr "" + +#: ../../include/ItemObject.php:259 +msgid "share" +msgstr "" + +#: ../../include/ItemObject.php:276 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/ItemObject.php:294 ../../include/ItemObject.php:295 +#, php-format +msgid "View %s's profile - %s" +msgstr "" + +#: ../../include/ItemObject.php:298 +msgid "to" +msgstr "" + +#: ../../include/ItemObject.php:299 +msgid "via" +msgstr "" + +#: ../../include/ItemObject.php:300 +msgid "Wall-to-Wall" +msgstr "" + +#: ../../include/ItemObject.php:301 +msgid "via Wall-To-Wall:" +msgstr "" + +#: ../../include/ItemObject.php:312 ../../include/conversation.php:716 +#, php-format +msgid "from %s" +msgstr "" + +#: ../../include/ItemObject.php:315 ../../include/conversation.php:719 +#, php-format +msgid "last edited: %s" +msgstr "" + +#: ../../include/ItemObject.php:316 ../../include/conversation.php:720 +#, php-format +msgid "Expires: %s" +msgstr "" + +#: ../../include/ItemObject.php:337 +msgid "Save Bookmarks" +msgstr "" + +#: ../../include/ItemObject.php:338 +msgid "Add to Calendar" +msgstr "" + +#: ../../include/ItemObject.php:347 +msgid "Mark all seen" +msgstr "" + +#: ../../include/ItemObject.php:353 ../../mod/photos.php:1133 +msgctxt "noun" +msgid "Likes" +msgstr "" + +#: ../../include/ItemObject.php:354 ../../mod/photos.php:1134 +msgctxt "noun" +msgid "Dislikes" +msgstr "" + +#: ../../include/ItemObject.php:359 ../../include/acl_selectors.php:249 +#: ../../mod/photos.php:1139 +msgid "Close" +msgstr "" + +#: ../../include/ItemObject.php:364 ../../include/conversation.php:737 +#: ../../include/conversation.php:1209 ../../mod/photos.php:950 +#: ../../mod/editlayout.php:153 ../../mod/editwebpage.php:192 +#: ../../mod/editpost.php:130 ../../mod/editblock.php:155 +#: ../../mod/mail.php:241 ../../mod/mail.php:356 +msgid "Please wait" +msgstr "" + +#: ../../include/ItemObject.php:665 ../../mod/photos.php:966 +#: ../../mod/photos.php:1084 +msgid "This is you" +msgstr "" + +#: ../../include/ItemObject.php:669 ../../include/conversation.php:1181 +#: ../../mod/editlayout.php:140 ../../mod/editwebpage.php:179 +#: ../../mod/editpost.php:114 ../../mod/editblock.php:141 +msgid "Bold" +msgstr "" + +#: ../../include/ItemObject.php:670 ../../include/conversation.php:1182 +#: ../../mod/editlayout.php:141 ../../mod/editwebpage.php:180 +#: ../../mod/editpost.php:115 ../../mod/editblock.php:142 +msgid "Italic" +msgstr "" + +#: ../../include/ItemObject.php:671 ../../include/conversation.php:1183 +#: ../../mod/editlayout.php:142 ../../mod/editwebpage.php:181 +#: ../../mod/editpost.php:116 ../../mod/editblock.php:143 +msgid "Underline" +msgstr "" + +#: ../../include/ItemObject.php:672 ../../include/conversation.php:1184 +#: ../../mod/editlayout.php:143 ../../mod/editwebpage.php:182 +#: ../../mod/editpost.php:117 ../../mod/editblock.php:144 +msgid "Quote" +msgstr "" + +#: ../../include/ItemObject.php:673 ../../include/conversation.php:1185 +#: ../../mod/editlayout.php:144 ../../mod/editwebpage.php:183 +#: ../../mod/editpost.php:118 ../../mod/editblock.php:145 +msgid "Code" +msgstr "" + +#: ../../include/ItemObject.php:674 +msgid "Image" +msgstr "" + +#: ../../include/ItemObject.php:675 +msgid "Insert Link" +msgstr "" + +#: ../../include/ItemObject.php:676 +msgid "Video" +msgstr "" + +#: ../../include/ItemObject.php:680 ../../include/conversation.php:1236 +#: ../../mod/editpost.php:158 ../../mod/mail.php:247 ../../mod/mail.php:361 +msgid "Encrypt text" +msgstr "" + +#: ../../include/Contact.php:124 +msgid "New window" +msgstr "" + +#: ../../include/Contact.php:125 +msgid "Open the selected location in a different window or browser tab" +msgstr "" + +#: ../../include/Contact.php:215 ../../mod/admin.php:730 +#, php-format +msgid "User '%s' deleted" +msgstr "" + +#: ../../include/bb2diaspora.php:373 +msgid "Attachments:" +msgstr "" + +#: ../../include/bb2diaspora.php:453 +msgid "$Projectname event notification:" +msgstr "" + +#: ../../include/nav.php:87 ../../include/nav.php:120 ../../boot.php:1549 +msgid "Logout" +msgstr "" + +#: ../../include/nav.php:87 ../../include/nav.php:120 +msgid "End this session" +msgstr "" + +#: ../../include/nav.php:90 ../../include/nav.php:151 +msgid "Home" +msgstr "" + +#: ../../include/nav.php:90 +msgid "Your posts and conversations" +msgstr "" + +#: ../../include/nav.php:91 ../../include/conversation.php:942 +#: ../../mod/connedit.php:500 ../../mod/connedit.php:666 +msgid "View Profile" +msgstr "" + +#: ../../include/nav.php:91 +msgid "Your profile page" +msgstr "" + +#: ../../include/nav.php:93 +msgid "Edit Profiles" +msgstr "" + +#: ../../include/nav.php:93 +msgid "Manage/Edit profiles" +msgstr "" + +#: ../../include/nav.php:95 ../../include/identity.php:847 +msgid "Edit Profile" +msgstr "" + +#: ../../include/nav.php:95 +msgid "Edit your profile" +msgstr "" + +#: ../../include/nav.php:97 ../../include/conversation.php:1600 +#: ../../include/apps.php:139 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "" + +#: ../../include/nav.php:97 +msgid "Your photos" +msgstr "" + +#: ../../include/nav.php:98 +msgid "Your files" +msgstr "" + +#: ../../include/nav.php:103 ../../include/apps.php:146 +msgid "Chat" +msgstr "" + +#: ../../include/nav.php:103 +msgid "Your chatrooms" +msgstr "" + +#: ../../include/nav.php:109 ../../include/conversation.php:1635 +#: ../../include/apps.php:129 +msgid "Bookmarks" +msgstr "" + +#: ../../include/nav.php:109 +msgid "Your bookmarks" +msgstr "" + +#: ../../include/nav.php:113 ../../include/conversation.php:1645 +#: ../../include/apps.php:136 ../../mod/webpages.php:177 +msgid "Webpages" +msgstr "" + +#: ../../include/nav.php:113 +msgid "Your webpages" +msgstr "" + +#: ../../include/nav.php:117 ../../include/apps.php:131 ../../boot.php:1550 +msgid "Login" +msgstr "" + +#: ../../include/nav.php:117 +msgid "Sign in" +msgstr "" + +#: ../../include/nav.php:134 +#, php-format +msgid "%s - click to logout" +msgstr "" + +#: ../../include/nav.php:137 +msgid "Remote authentication" +msgstr "" + +#: ../../include/nav.php:137 +msgid "Click to authenticate to your home hub" +msgstr "" + +#: ../../include/nav.php:151 +msgid "Home Page" +msgstr "" + +#: ../../include/nav.php:155 ../../mod/register.php:224 ../../boot.php:1526 +msgid "Register" +msgstr "" + +#: ../../include/nav.php:155 +msgid "Create an account" +msgstr "" + +#: ../../include/nav.php:160 ../../include/apps.php:142 ../../mod/help.php:67 +#: ../../mod/help.php:72 ../../mod/layouts.php:176 +msgid "Help" +msgstr "" + +#: ../../include/nav.php:160 +msgid "Help and documentation" +msgstr "" + +#: ../../include/nav.php:163 +msgid "Applications, utilities, links, games" +msgstr "" + +#: ../../include/nav.php:165 +msgid "Search site content" +msgstr "" + +#: ../../include/nav.php:168 ../../include/apps.php:141 +#: ../../mod/directory.php:366 +msgid "Directory" +msgstr "" + +#: ../../include/nav.php:168 +msgid "Channel Directory" +msgstr "" + +#: ../../include/nav.php:180 ../../include/apps.php:133 +msgid "Matrix" +msgstr "" + +#: ../../include/nav.php:180 +msgid "Your matrix" +msgstr "" + +#: ../../include/nav.php:181 +msgid "Mark all matrix notifications seen" +msgstr "" + +#: ../../include/nav.php:183 ../../include/apps.php:137 +msgid "Channel Home" +msgstr "" + +#: ../../include/nav.php:183 +msgid "Channel home" +msgstr "" + +#: ../../include/nav.php:184 +msgid "Mark all channel notifications seen" +msgstr "" + +#: ../../include/nav.php:187 ../../mod/connections.php:407 +msgid "Connections" +msgstr "" + +#: ../../include/nav.php:190 +msgid "Notices" +msgstr "" + +#: ../../include/nav.php:190 +msgid "Notifications" +msgstr "" + +#: ../../include/nav.php:191 +msgid "See all notifications" +msgstr "" + +#: ../../include/nav.php:192 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "" + +#: ../../include/nav.php:194 ../../include/apps.php:143 +msgid "Mail" +msgstr "" + +#: ../../include/nav.php:194 +msgid "Private mail" +msgstr "" + +#: ../../include/nav.php:195 +msgid "See all private messages" +msgstr "" + +#: ../../include/nav.php:196 +msgid "Mark all private messages seen" +msgstr "" + +#: ../../include/nav.php:197 +msgid "Inbox" +msgstr "" + +#: ../../include/nav.php:198 +msgid "Outbox" +msgstr "" + +#: ../../include/nav.php:202 ../../include/apps.php:140 +#: ../../mod/events.php:472 +msgid "Events" +msgstr "" + +#: ../../include/nav.php:202 +msgid "Event Calendar" +msgstr "" + +#: ../../include/nav.php:203 +msgid "See all events" +msgstr "" + +#: ../../include/nav.php:204 +msgid "Mark all events seen" +msgstr "" + +#: ../../include/nav.php:206 ../../include/apps.php:132 +#: ../../mod/manage.php:166 +msgid "Channel Manager" +msgstr "" + +#: ../../include/nav.php:206 +msgid "Manage Your Channels" +msgstr "" + +#: ../../include/nav.php:208 +msgid "Account/Channel Settings" +msgstr "" + +#: ../../include/nav.php:216 ../../mod/admin.php:120 +msgid "Admin" +msgstr "" + +#: ../../include/nav.php:216 +msgid "Site Setup and Configuration" +msgstr "" + +#: ../../include/nav.php:247 ../../include/conversation.php:850 +msgid "Loading..." +msgstr "" + +#: ../../include/nav.php:252 +msgid "@name, #tag, content" +msgstr "" + +#: ../../include/nav.php:253 +msgid "Please wait..." +msgstr "" + +#: ../../include/taxonomy.php:222 ../../include/taxonomy.php:243 +msgid "Tags" +msgstr "" + +#: ../../include/taxonomy.php:287 +msgid "Keywords" +msgstr "" + +#: ../../include/taxonomy.php:308 +msgid "have" +msgstr "" + +#: ../../include/taxonomy.php:308 +msgid "has" +msgstr "" + +#: ../../include/taxonomy.php:309 +msgid "want" +msgstr "" + +#: ../../include/taxonomy.php:309 +msgid "wants" +msgstr "" + +#: ../../include/taxonomy.php:310 +msgid "likes" +msgstr "" + +#: ../../include/taxonomy.php:311 +msgid "dislikes" +msgstr "" + +#: ../../include/activities.php:39 +msgid " and " +msgstr "" + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "" + +#: ../../include/activities.php:57 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "" + +#: ../../include/activities.php:60 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "" + +#: ../../include/security.php:349 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "" + +#: ../../include/permissions.php:26 +msgid "Can view my normal stream and posts" +msgstr "" + +#: ../../include/permissions.php:27 +msgid "Can view my default channel profile" +msgstr "" + +#: ../../include/permissions.php:28 +msgid "Can view my photo albums" +msgstr "" + +#: ../../include/permissions.php:29 +msgid "Can view my connections" +msgstr "" + +#: ../../include/permissions.php:30 +msgid "Can view my file storage" +msgstr "" + +#: ../../include/permissions.php:31 +msgid "Can view my webpages" +msgstr "" + +#: ../../include/permissions.php:34 +msgid "Can send me their channel stream and posts" +msgstr "" + +#: ../../include/permissions.php:35 +msgid "Can post on my channel page (\"wall\")" +msgstr "" + +#: ../../include/permissions.php:36 +msgid "Can comment on or like my posts" +msgstr "" + +#: ../../include/permissions.php:37 +msgid "Can send me private mail messages" +msgstr "" + +#: ../../include/permissions.php:38 +msgid "Can post photos to my photo albums" +msgstr "" + +#: ../../include/permissions.php:39 +msgid "Can like/dislike stuff" +msgstr "" + +#: ../../include/permissions.php:39 +msgid "Profiles and things other than posts/comments" +msgstr "" + +#: ../../include/permissions.php:41 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "" + +#: ../../include/permissions.php:41 +msgid "Advanced - useful for creating group forum channels" +msgstr "" + +#: ../../include/permissions.php:42 +msgid "Can chat with me (when available)" +msgstr "" + +#: ../../include/permissions.php:43 +msgid "Can write to my file storage" +msgstr "" + +#: ../../include/permissions.php:44 +msgid "Can edit my webpages" +msgstr "" + +#: ../../include/permissions.php:46 +msgid "Can source my public posts in derived channels" +msgstr "" + +#: ../../include/permissions.php:46 +msgid "Somewhat advanced - very useful in open communities" +msgstr "" + +#: ../../include/permissions.php:48 +msgid "Can administer my channel resources" +msgstr "" + +#: ../../include/permissions.php:48 +msgid "Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "" + +#: ../../include/permissions.php:893 +msgid "Social Networking" +msgstr "" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Mostly Public" +msgstr "" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Restricted" +msgstr "" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +msgid "Private" +msgstr "" + +#: ../../include/permissions.php:894 +msgid "Community Forum" +msgstr "" + +#: ../../include/permissions.php:895 +msgid "Feed Republish" +msgstr "" + +#: ../../include/permissions.php:896 +msgid "Special Purpose" +msgstr "" + +#: ../../include/permissions.php:896 +msgid "Celebrity/Soapbox" +msgstr "" + +#: ../../include/permissions.php:896 +msgid "Group Repository" +msgstr "" + +#: ../../include/permissions.php:897 ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 +msgid "Other" +msgstr "" + +#: ../../include/permissions.php:897 +msgid "Custom/Expert Mode" +msgstr "" + +#: ../../include/conversation.php:126 ../../mod/like.php:113 +msgid "channel" +msgstr "" + +#: ../../include/conversation.php:164 ../../include/diaspora.php:2111 +#: ../../mod/like.php:394 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "" + +#: ../../include/conversation.php:167 ../../mod/like.php:396 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "" + +#: ../../include/conversation.php:260 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "" + +#: ../../include/conversation.php:572 ../../mod/photos.php:984 +msgctxt "title" +msgid "Likes" +msgstr "" + +#: ../../include/conversation.php:572 ../../mod/photos.php:984 +msgctxt "title" +msgid "Dislikes" +msgstr "" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Agree" +msgstr "" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Disagree" +msgstr "" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Abstain" +msgstr "" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Attending" +msgstr "" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Not attending" +msgstr "" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Might attend" +msgstr "" + +#: ../../include/conversation.php:692 +#, php-format +msgid "View %s's profile @ %s" +msgstr "" + +#: ../../include/conversation.php:707 +msgid "Categories:" +msgstr "" + +#: ../../include/conversation.php:708 +msgid "Filed under:" +msgstr "" + +#: ../../include/conversation.php:735 +msgid "View in context" +msgstr "" + +#: ../../include/conversation.php:846 +msgid "remove" +msgstr "" + +#: ../../include/conversation.php:851 +msgid "Delete Selected Items" +msgstr "" + +#: ../../include/conversation.php:939 +msgid "View Source" +msgstr "" + +#: ../../include/conversation.php:940 +msgid "Follow Thread" +msgstr "" + +#: ../../include/conversation.php:941 +msgid "View Status" +msgstr "" + +#: ../../include/conversation.php:943 +msgid "View Photos" +msgstr "" + +#: ../../include/conversation.php:944 +msgid "Matrix Activity" +msgstr "" + +#: ../../include/conversation.php:946 +msgid "Edit Contact" +msgstr "" + +#: ../../include/conversation.php:947 +msgid "Send PM" +msgstr "" + +#: ../../include/conversation.php:948 ../../include/apps.php:145 +msgid "Poke" +msgstr "" + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s likes this." +msgstr "" + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s doesn't like this." +msgstr "" + +#: ../../include/conversation.php:1066 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1068 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1074 +msgid "and" +msgstr "" + +#: ../../include/conversation.php:1077 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s like this." +msgstr "" + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s don't like this." +msgstr "" + +#: ../../include/conversation.php:1140 +msgid "Visible to everybody" +msgstr "" + +#: ../../include/conversation.php:1141 ../../mod/mail.php:174 +#: ../../mod/mail.php:289 +msgid "Please enter a link URL:" +msgstr "" + +#: ../../include/conversation.php:1142 +msgid "Please enter a video link/URL:" +msgstr "" + +#: ../../include/conversation.php:1143 +msgid "Please enter an audio link/URL:" +msgstr "" + +#: ../../include/conversation.php:1144 +msgid "Tag term:" +msgstr "" + +#: ../../include/conversation.php:1145 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "" + +#: ../../include/conversation.php:1146 +msgid "Where are you right now?" +msgstr "" + +#: ../../include/conversation.php:1147 ../../mod/editpost.php:52 +#: ../../mod/mail.php:175 ../../mod/mail.php:290 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "" + +#: ../../include/conversation.php:1174 ../../mod/webpages.php:181 +#: ../../mod/blocks.php:154 ../../mod/photos.php:949 ../../mod/layouts.php:184 +msgid "Share" +msgstr "" + +#: ../../include/conversation.php:1176 +msgid "Page link name" +msgstr "" + +#: ../../include/conversation.php:1179 +msgid "Post as" +msgstr "" + +#: ../../include/conversation.php:1186 ../../mod/editlayout.php:145 +#: ../../mod/editwebpage.php:184 ../../mod/editpost.php:119 +#: ../../mod/editblock.php:147 ../../mod/mail.php:238 ../../mod/mail.php:352 +msgid "Upload photo" +msgstr "" + +#: ../../include/conversation.php:1187 +msgid "upload photo" +msgstr "" + +#: ../../include/conversation.php:1188 ../../mod/editlayout.php:146 +#: ../../mod/editwebpage.php:185 ../../mod/editpost.php:120 +#: ../../mod/editblock.php:148 ../../mod/mail.php:239 ../../mod/mail.php:353 +msgid "Attach file" +msgstr "" + +#: ../../include/conversation.php:1189 +msgid "attach file" +msgstr "" + +#: ../../include/conversation.php:1190 ../../mod/editlayout.php:147 +#: ../../mod/editwebpage.php:186 ../../mod/editpost.php:121 +#: ../../mod/editblock.php:149 ../../mod/mail.php:240 ../../mod/mail.php:354 +msgid "Insert web link" +msgstr "" + +#: ../../include/conversation.php:1191 +msgid "web link" +msgstr "" + +#: ../../include/conversation.php:1192 +msgid "Insert video link" +msgstr "" + +#: ../../include/conversation.php:1193 +msgid "video link" +msgstr "" + +#: ../../include/conversation.php:1194 +msgid "Insert audio link" +msgstr "" + +#: ../../include/conversation.php:1195 +msgid "audio link" +msgstr "" + +#: ../../include/conversation.php:1196 ../../mod/editlayout.php:151 +#: ../../mod/editwebpage.php:190 ../../mod/editpost.php:125 +#: ../../mod/editblock.php:153 +msgid "Set your location" +msgstr "" + +#: ../../include/conversation.php:1197 +msgid "set location" +msgstr "" + +#: ../../include/conversation.php:1198 ../../mod/editpost.php:127 +msgid "Toggle voting" +msgstr "" + +#: ../../include/conversation.php:1201 ../../mod/editlayout.php:152 +#: ../../mod/editwebpage.php:191 ../../mod/editpost.php:126 +#: ../../mod/editblock.php:154 +msgid "Clear browser location" +msgstr "" + +#: ../../include/conversation.php:1202 +msgid "clear location" +msgstr "" + +#: ../../include/conversation.php:1204 ../../mod/editwebpage.php:207 +#: ../../mod/editpost.php:142 ../../mod/editblock.php:167 +msgid "Title (optional)" +msgstr "" + +#: ../../include/conversation.php:1208 ../../mod/editlayout.php:168 +#: ../../mod/editwebpage.php:209 ../../mod/editpost.php:144 +#: ../../mod/editblock.php:170 +msgid "Categories (optional, comma-separated list)" +msgstr "" + +#: ../../include/conversation.php:1210 ../../mod/editlayout.php:154 +#: ../../mod/editwebpage.php:193 ../../mod/editpost.php:131 +#: ../../mod/editblock.php:156 +msgid "Permission settings" +msgstr "" + +#: ../../include/conversation.php:1211 +msgid "permissions" +msgstr "" + +#: ../../include/conversation.php:1219 ../../mod/editlayout.php:161 +#: ../../mod/editwebpage.php:202 ../../mod/editpost.php:139 +#: ../../mod/editblock.php:164 +msgid "Public post" +msgstr "" + +#: ../../include/conversation.php:1221 ../../mod/editlayout.php:169 +#: ../../mod/editwebpage.php:210 ../../mod/editpost.php:145 +#: ../../mod/editblock.php:171 +msgid "Example: bob@example.com, mary@example.com" +msgstr "" + +#: ../../include/conversation.php:1234 ../../mod/editlayout.php:178 +#: ../../mod/editwebpage.php:219 ../../mod/editpost.php:156 +#: ../../mod/editblock.php:181 ../../mod/mail.php:245 ../../mod/mail.php:359 +msgid "Set expiration date" +msgstr "" + +#: ../../include/conversation.php:1238 ../../mod/events.php:637 +#: ../../mod/editpost.php:160 +msgid "OK" +msgstr "" + +#: ../../include/conversation.php:1239 ../../mod/settings.php:588 +#: ../../mod/settings.php:614 ../../mod/tagrm.php:11 ../../mod/tagrm.php:134 +#: ../../mod/events.php:636 ../../mod/fbrowser.php:82 +#: ../../mod/fbrowser.php:117 ../../mod/editpost.php:161 +msgid "Cancel" +msgstr "" + +#: ../../include/conversation.php:1481 +msgid "Discover" +msgstr "" + +#: ../../include/conversation.php:1484 +msgid "Imported public streams" +msgstr "" + +#: ../../include/conversation.php:1489 +msgid "Commented Order" +msgstr "" + +#: ../../include/conversation.php:1492 +msgid "Sort by Comment Date" +msgstr "" + +#: ../../include/conversation.php:1496 +msgid "Posted Order" +msgstr "" + +#: ../../include/conversation.php:1499 +msgid "Sort by Post Date" +msgstr "" + +#: ../../include/conversation.php:1507 +msgid "Posts that mention or involve you" +msgstr "" + +#: ../../include/conversation.php:1513 ../../mod/connections.php:212 +#: ../../mod/connections.php:225 ../../mod/menu.php:105 +msgid "New" +msgstr "" + +#: ../../include/conversation.php:1516 +msgid "Activity Stream - by date" +msgstr "" + +#: ../../include/conversation.php:1522 +msgid "Starred" +msgstr "" + +#: ../../include/conversation.php:1525 +msgid "Favourite Posts" +msgstr "" + +#: ../../include/conversation.php:1532 +msgid "Spam" +msgstr "" + +#: ../../include/conversation.php:1535 +msgid "Posts flagged as SPAM" +msgstr "" + +#: ../../include/conversation.php:1579 ../../mod/admin.php:984 +msgid "Channel" +msgstr "" + +#: ../../include/conversation.php:1582 +msgid "Status Messages and Posts" +msgstr "" + +#: ../../include/conversation.php:1591 +msgid "About" +msgstr "" + +#: ../../include/conversation.php:1594 +msgid "Profile Details" +msgstr "" + +#: ../../include/conversation.php:1603 ../../include/photos.php:359 +msgid "Photo Albums" +msgstr "" + +#: ../../include/conversation.php:1612 +msgid "Files and Storage" +msgstr "" + +#: ../../include/conversation.php:1622 ../../include/conversation.php:1625 +msgid "Chatrooms" +msgstr "" + +#: ../../include/conversation.php:1638 +msgid "Saved Bookmarks" +msgstr "" + +#: ../../include/conversation.php:1648 +msgid "Manage Webpages" +msgstr "" + +#: ../../include/conversation.php:1707 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1710 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1713 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1716 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1719 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/conversation.php:1722 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/items.php:399 ../../mod/like.php:270 +#: ../../mod/subthread.php:49 ../../mod/group.php:68 ../../mod/profperm.php:23 +#: ../../mod/bulksetclose.php:11 ../../index.php:381 +msgid "Permission denied" +msgstr "" + +#: ../../include/items.php:1020 ../../include/items.php:1066 +msgid "(Unknown)" +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:1234 +msgid "Visible to anybody on the internet." +msgstr "" + +#: ../../include/items.php:1236 +msgid "Visible to you only." +msgstr "" + +#: ../../include/items.php:1238 +msgid "Visible to anybody in this network." +msgstr "" + +#: ../../include/items.php:1240 +msgid "Visible to anybody authenticated." +msgstr "" + +#: ../../include/items.php:1242 +======= +#: ../../include/items.php:1304 +msgid "Visible to anybody on the internet." +msgstr "" + +#: ../../include/items.php:1306 +msgid "Visible to you only." +msgstr "" + +#: ../../include/items.php:1308 +msgid "Visible to anybody in this network." +msgstr "" + +#: ../../include/items.php:1310 +msgid "Visible to anybody authenticated." +msgstr "" + +#: ../../include/items.php:1312 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#, php-format +msgid "Visible to anybody on %s." +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:1244 +msgid "Visible to all connections." +msgstr "" + +#: ../../include/items.php:1246 +msgid "Visible to approved connections." +msgstr "" + +#: ../../include/items.php:1248 +msgid "Visible to specific connections." +msgstr "" + +#: ../../include/items.php:4060 ../../mod/thing.php:74 +======= +#: ../../include/items.php:1314 +msgid "Visible to all connections." +msgstr "" + +#: ../../include/items.php:1316 +msgid "Visible to approved connections." +msgstr "" + +#: ../../include/items.php:1318 +msgid "Visible to specific connections." +msgstr "" + +#: ../../include/items.php:4195 ../../mod/thing.php:74 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/display.php:36 ../../mod/filestorage.php:27 +#: ../../mod/viewsrc.php:20 ../../mod/admin.php:167 ../../mod/admin.php:1016 +#: ../../mod/admin.php:1216 +msgid "Item not found." +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:4133 ../../include/photos.php:26 +#: ../../include/attach.php:137 ../../include/attach.php:184 +#: ../../include/attach.php:247 ../../include/attach.php:261 +#: ../../include/attach.php:305 ../../include/attach.php:319 +#: ../../include/attach.php:350 ../../include/attach.php:546 +#: ../../include/attach.php:618 ../../include/chat.php:131 +======= +#: ../../include/items.php:4268 ../../include/attach.php:137 +#: ../../include/attach.php:184 ../../include/attach.php:247 +#: ../../include/attach.php:261 ../../include/attach.php:305 +#: ../../include/attach.php:319 ../../include/attach.php:350 +#: ../../include/attach.php:546 ../../include/attach.php:618 +#: ../../include/chat.php:131 ../../include/photos.php:26 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/profile.php:64 ../../mod/profile.php:72 +#: ../../mod/achievements.php:30 ../../mod/manage.php:6 +#: ../../mod/settings.php:569 ../../mod/api.php:26 ../../mod/api.php:31 +#: ../../mod/webpages.php:69 ../../mod/thing.php:241 ../../mod/thing.php:256 +#: ../../mod/thing.php:290 ../../mod/profile_photo.php:264 +#: ../../mod/profile_photo.php:277 ../../mod/block.php:22 +#: ../../mod/block.php:72 ../../mod/like.php:178 ../../mod/events.php:219 +#: ../../mod/group.php:9 ../../mod/common.php:35 ../../mod/connections.php:169 +#: ../../mod/blocks.php:69 ../../mod/blocks.php:76 ../../mod/photos.php:68 +#: ../../mod/pdledit.php:21 ../../mod/authtest.php:13 +#: ../../mod/editlayout.php:63 ../../mod/editlayout.php:87 +#: ../../mod/chat.php:90 ../../mod/chat.php:95 ../../mod/editwebpage.php:64 +#: ../../mod/editwebpage.php:86 ../../mod/editwebpage.php:101 +#: ../../mod/editwebpage.php:125 ../../mod/rate.php:110 +#: ../../mod/editpost.php:13 ../../mod/invite.php:13 ../../mod/invite.php:104 +#: ../../mod/locs.php:77 ../../mod/sources.php:66 ../../mod/menu.php:69 +#: ../../mod/filestorage.php:18 ../../mod/filestorage.php:73 +#: ../../mod/filestorage.php:88 ../../mod/filestorage.php:115 +#: ../../mod/fsuggest.php:78 ../../mod/poke.php:128 ../../mod/profiles.php:188 +#: ../../mod/profiles.php:576 ../../mod/viewsrc.php:14 ../../mod/setup.php:223 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +<<<<<<< HEAD +#: ../../mod/editblock.php:65 ../../mod/register.php:72 ../../mod/item.php:206 +#: ../../mod/item.php:214 ../../mod/item.php:974 ../../mod/layouts.php:69 +#: ../../mod/layouts.php:76 ../../mod/layouts.php:87 ../../mod/id.php:71 +#: ../../mod/message.php:16 ../../mod/mitem.php:115 ../../mod/mood.php:111 +#: ../../mod/connedit.php:331 ../../mod/mail.php:114 +#: ../../mod/notifications.php:66 ../../mod/regmod.php:17 +#: ../../mod/new_channel.php:68 ../../mod/new_channel.php:99 +#: ../../mod/appman.php:66 ../../mod/network.php:12 ../../mod/page.php:28 +#: ../../mod/page.php:82 ../../mod/bookmarks.php:46 ../../mod/channel.php:100 +#: ../../mod/channel.php:219 ../../mod/channel.php:262 +#: ../../mod/suggest.php:26 ../../mod/service_limits.php:7 +#: ../../mod/sharedwithme.php:7 ../../index.php:182 ../../index.php:382 +msgid "Permission denied." +msgstr "" + +#: ../../include/items.php:4535 ../../mod/group.php:38 ../../mod/group.php:140 +======= +#: ../../mod/editblock.php:65 ../../mod/register.php:72 +#: ../../mod/settings.php:570 ../../mod/id.php:71 ../../mod/message.php:16 +#: ../../mod/mitem.php:115 ../../mod/mood.php:111 ../../mod/connedit.php:337 +#: ../../mod/mail.php:114 ../../mod/notifications.php:66 +#: ../../mod/regmod.php:17 ../../mod/new_channel.php:68 +#: ../../mod/new_channel.php:99 ../../mod/appman.php:66 +#: ../../mod/layouts.php:69 ../../mod/layouts.php:76 ../../mod/layouts.php:87 +#: ../../mod/page.php:31 ../../mod/page.php:86 ../../mod/bookmarks.php:46 +#: ../../mod/channel.php:100 ../../mod/channel.php:219 +#: ../../mod/channel.php:262 ../../mod/suggest.php:26 +#: ../../mod/service_limits.php:7 ../../mod/sharedwithme.php:7 +#: ../../index.php:182 ../../index.php:382 +msgid "Permission denied." +msgstr "" + +#: ../../include/items.php:4670 ../../mod/group.php:38 ../../mod/group.php:140 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/bulksetclose.php:51 +msgid "Collection not found." +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:4551 +msgid "Collection is empty." +msgstr "" + +#: ../../include/items.php:4558 +======= +#: ../../include/items.php:4686 +msgid "Collection is empty." +msgstr "" + +#: ../../include/items.php:4693 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#, php-format +msgid "Collection: %s" +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:4568 +======= +#: ../../include/items.php:4703 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#, php-format +msgid "Connection: %s" +msgstr "" + +<<<<<<< HEAD +#: ../../include/items.php:4570 +======= +#: ../../include/items.php:4705 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Connection not found." +msgstr "" + +#: ../../include/photos.php:94 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "" + +#: ../../include/photos.php:101 +msgid "Image file is empty." +msgstr "" + +#: ../../include/photos.php:128 ../../mod/profile_photo.php:217 +msgid "Unable to process image" +msgstr "" + +#: ../../include/photos.php:199 +msgid "Photo storage failed." +msgstr "" + +#: ../../include/photos.php:363 +msgid "Upload New Photos" +msgstr "" + +#: ../../include/zot.php:666 +msgid "Invalid data packet" +msgstr "" + +#: ../../include/zot.php:682 +msgid "Unable to verify channel signature" +msgstr "" + +#: ../../include/zot.php:2126 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "" + +#: ../../include/oembed.php:183 +msgid "Embedded content" +msgstr "" + +#: ../../include/oembed.php:192 +msgid "Embedding disabled" +msgstr "" + +#: ../../include/auth.php:131 +msgid "Logged out." +msgstr "" + +#: ../../include/auth.php:272 +msgid "Failed authentication" +msgstr "" + +#: ../../include/auth.php:286 ../../mod/openid.php:190 +msgid "Login failed." +msgstr "" + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:450 +msgid "Advanced" +msgstr "" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "" + +#: ../../include/contact_widgets.php:26 ../../mod/connections.php:413 +<<<<<<< HEAD +#: ../../mod/directory.php:362 ../../mod/directory.php:367 +msgid "Find" +msgstr "" + +#: ../../include/contact_widgets.php:27 ../../mod/directory.php:366 +======= +#: ../../mod/directory.php:372 ../../mod/directory.php:377 +msgid "Find" +msgstr "" + +#: ../../include/contact_widgets.php:27 ../../mod/directory.php:376 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../mod/suggest.php:60 +msgid "Channel Suggestions" +msgstr "" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "" + +#: ../../include/contact_widgets.php:32 +msgid "Advanced example: name=fred and country=iceland" +msgstr "" + +#: ../../include/contact_widgets.php:125 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "" +msgstr[1] "" + +#: ../../include/contact_widgets.php:130 +msgid "show more" +msgstr "" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "" + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "" + +#: ../../include/acl_selectors.php:248 ../../mod/events.php:654 +#: ../../mod/photos.php:559 ../../mod/photos.php:922 ../../mod/chat.php:209 +#: ../../mod/filestorage.php:147 +msgid "Permissions" +msgstr "" + +#: ../../include/attach.php:242 ../../include/attach.php:300 +msgid "Item was not found." +msgstr "" + +#: ../../include/attach.php:363 +msgid "No source file." +msgstr "" + +#: ../../include/attach.php:381 +msgid "Cannot locate file to replace" +msgstr "" + +#: ../../include/attach.php:399 +msgid "Cannot locate file to revise/update" +msgstr "" + +#: ../../include/attach.php:410 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "" + +#: ../../include/attach.php:422 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "" + +#: ../../include/attach.php:505 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "" + +#: ../../include/attach.php:517 +msgid "Stored file could not be verified. Upload failed." +msgstr "" + +#: ../../include/attach.php:561 ../../include/attach.php:578 +msgid "Path not available." +msgstr "" + +#: ../../include/attach.php:623 +msgid "Empty pathname" +msgstr "" + +#: ../../include/attach.php:639 +msgid "duplicate filename or path" +msgstr "" + +#: ../../include/attach.php:663 +msgid "Path not found." +msgstr "" + +#: ../../include/attach.php:714 +msgid "mkdir failed." +msgstr "" + +#: ../../include/attach.php:718 +msgid "database storage failed." +msgstr "" + +#: ../../include/identity.php:33 +msgid "Unable to obtain identity information from database" +msgstr "" + +#: ../../include/identity.php:67 +msgid "Empty name" +msgstr "" + +#: ../../include/identity.php:70 +msgid "Name too long" +msgstr "" + +#: ../../include/identity.php:186 +msgid "No account identifier" +msgstr "" + +#: ../../include/identity.php:198 +msgid "Nickname is required." +msgstr "" + +#: ../../include/identity.php:212 +msgid "Reserved nickname. Please choose another." +msgstr "" + +#: ../../include/identity.php:217 ../../include/dimport.php:34 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "" + +#: ../../include/identity.php:292 +msgid "Unable to retrieve created identity" +msgstr "" + +#: ../../include/identity.php:350 +msgid "Default Profile" +msgstr "" + +#: ../../include/identity.php:631 +msgid "Requested channel is not available." +msgstr "" + +#: ../../include/identity.php:678 ../../mod/profile.php:16 +#: ../../mod/achievements.php:11 ../../mod/webpages.php:29 +#: ../../mod/connect.php:13 ../../mod/hcard.php:8 ../../mod/blocks.php:29 +#: ../../mod/editlayout.php:27 ../../mod/editwebpage.php:28 +#: ../../mod/filestorage.php:54 ../../mod/editblock.php:29 +#: ../../mod/layouts.php:29 +msgid "Requested profile is not available." +msgstr "" + +#: ../../include/identity.php:837 ../../mod/profiles.php:774 +msgid "Change profile photo" +msgstr "" + +#: ../../include/identity.php:843 +msgid "Profiles" +msgstr "" + +#: ../../include/identity.php:843 +msgid "Manage/edit profiles" +msgstr "" + +#: ../../include/identity.php:844 ../../mod/profiles.php:775 +msgid "Create New Profile" +msgstr "" + +#: ../../include/identity.php:859 ../../mod/profiles.php:786 +msgid "Profile Image" +msgstr "" + +#: ../../include/identity.php:862 +msgid "visible to everybody" +msgstr "" + +#: ../../include/identity.php:863 ../../mod/profiles.php:669 +#: ../../mod/profiles.php:790 +msgid "Edit visibility" +msgstr "" + +#: ../../include/identity.php:879 ../../include/identity.php:1118 +msgid "Gender:" +msgstr "" + +#: ../../include/identity.php:880 ../../include/identity.php:1162 +msgid "Status:" +msgstr "" + +#: ../../include/identity.php:881 ../../include/identity.php:1173 +msgid "Homepage:" +msgstr "" + +#: ../../include/identity.php:882 +msgid "Online Now" +msgstr "" + +#: ../../include/identity.php:965 ../../include/identity.php:1043 +#: ../../mod/ping.php:324 +msgid "g A l F d" +msgstr "" + +#: ../../include/identity.php:966 ../../include/identity.php:1044 +msgid "F d" +msgstr "" + +#: ../../include/identity.php:1011 ../../include/identity.php:1083 +#: ../../mod/ping.php:346 +msgid "[today]" +msgstr "" + +#: ../../include/identity.php:1022 +msgid "Birthday Reminders" +msgstr "" + +#: ../../include/identity.php:1023 +msgid "Birthdays this week:" +msgstr "" + +#: ../../include/identity.php:1076 +msgid "[No description]" +msgstr "" + +#: ../../include/identity.php:1094 +msgid "Event Reminders" +msgstr "" + +#: ../../include/identity.php:1095 +msgid "Events this week:" +msgstr "" + +#: ../../include/identity.php:1108 ../../include/identity.php:1225 +#: ../../include/apps.php:138 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "" + +#: ../../include/identity.php:1116 ../../mod/settings.php:1050 +msgid "Full Name:" +msgstr "" + +#: ../../include/identity.php:1123 +msgid "Like this channel" +msgstr "" + +#: ../../include/identity.php:1147 +msgid "j F, Y" +msgstr "" + +#: ../../include/identity.php:1148 +msgid "j F" +msgstr "" + +#: ../../include/identity.php:1155 +msgid "Birthday:" +msgstr "" + +<<<<<<< HEAD +#: ../../include/identity.php:1159 +======= +#: ../../include/identity.php:1163 ../../mod/directory.php:290 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Age:" +msgstr "" + +#: ../../include/identity.php:1168 +#, php-format +msgid "for %1$d %2$s" +msgstr "" + +#: ../../include/identity.php:1171 ../../mod/profiles.php:691 +msgid "Sexual Preference:" +msgstr "" + +<<<<<<< HEAD +#: ../../include/identity.php:1175 ../../mod/profiles.php:693 +======= +#: ../../include/identity.php:1179 ../../mod/directory.php:306 +#: ../../mod/profiles.php:693 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "Hometown:" +msgstr "" + +#: ../../include/identity.php:1177 +msgid "Tags:" +msgstr "" + +#: ../../include/identity.php:1179 ../../mod/profiles.php:694 +msgid "Political Views:" +msgstr "" + +#: ../../include/identity.php:1181 +msgid "Religion:" +msgstr "" + +<<<<<<< HEAD +#: ../../include/identity.php:1183 +======= +#: ../../include/identity.php:1187 ../../mod/directory.php:308 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "About:" +msgstr "" + +#: ../../include/identity.php:1185 +msgid "Hobbies/Interests:" +msgstr "" + +#: ../../include/identity.php:1187 ../../mod/profiles.php:697 +msgid "Likes:" +msgstr "" + +#: ../../include/identity.php:1189 ../../mod/profiles.php:698 +msgid "Dislikes:" +msgstr "" + +#: ../../include/identity.php:1191 +msgid "Contact information and Social Networks:" +msgstr "" + +#: ../../include/identity.php:1193 +msgid "My other channels:" +msgstr "" + +#: ../../include/identity.php:1195 +msgid "Musical interests:" +msgstr "" + +#: ../../include/identity.php:1197 +msgid "Books, literature:" +msgstr "" + +#: ../../include/identity.php:1199 +msgid "Television:" +msgstr "" + +#: ../../include/identity.php:1201 +msgid "Film/dance/culture/entertainment:" +msgstr "" + +#: ../../include/identity.php:1203 +msgid "Love/Romance:" +msgstr "" + +#: ../../include/identity.php:1205 +msgid "Work/employment:" +msgstr "" + +#: ../../include/identity.php:1207 +msgid "School/education:" +msgstr "" + +#: ../../include/identity.php:1227 +msgid "Like this thing" +msgstr "" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:103 +msgid "Male" +msgstr "" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:105 +msgid "Female" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "" + +#: ../../include/apps.php:128 +msgid "Site Admin" +msgstr "" + +#: ../../include/apps.php:130 +msgid "Address Book" +msgstr "" + +#: ../../include/apps.php:144 ../../mod/mood.php:130 +msgid "Mood" +msgstr "" + +#: ../../include/apps.php:148 +msgid "Probe" +msgstr "" + +#: ../../include/apps.php:149 +msgid "Suggest" +msgstr "" + +#: ../../include/apps.php:150 +msgid "Random Channel" +msgstr "" + +#: ../../include/apps.php:151 +msgid "Invite" +msgstr "" + +#: ../../include/apps.php:152 +msgid "Features" +msgstr "" + +#: ../../include/apps.php:153 ../../mod/id.php:28 +msgid "Language" +msgstr "" + +#: ../../include/apps.php:154 +msgid "Post" +msgstr "" + +#: ../../include/apps.php:155 ../../mod/id.php:17 ../../mod/id.php:18 +#: ../../mod/id.php:19 +msgid "Profile Photo" +msgstr "" + +#: ../../include/apps.php:247 ../../mod/settings.php:84 +#: ../../mod/settings.php:613 +msgid "Update" +msgstr "" + +#: ../../include/apps.php:247 +msgid "Install" +msgstr "" + +#: ../../include/apps.php:252 +msgid "Purchase" +msgstr "" + +<<<<<<< HEAD +======= +#: ../../include/bbcode.php:122 ../../include/bbcode.php:764 +#: ../../include/bbcode.php:767 ../../include/bbcode.php:772 +#: ../../include/bbcode.php:775 ../../include/bbcode.php:778 +#: ../../include/bbcode.php:781 ../../include/bbcode.php:786 +#: ../../include/bbcode.php:789 ../../include/bbcode.php:794 +#: ../../include/bbcode.php:797 ../../include/bbcode.php:800 +#: ../../include/bbcode.php:803 +msgid "Image/photo" +msgstr "" + +#: ../../include/bbcode.php:161 ../../include/bbcode.php:814 +msgid "Encrypted content" +msgstr "" + +#: ../../include/bbcode.php:178 +#, php-format +msgid "Install %s element: " +msgstr "" + +#: ../../include/bbcode.php:188 ../../mod/impel.php:37 +msgid "webpage" +msgstr "" + +#: ../../include/bbcode.php:191 ../../mod/impel.php:47 +msgid "layout" +msgstr "" + +#: ../../include/bbcode.php:194 ../../mod/impel.php:42 +msgid "block" +msgstr "" + +#: ../../include/bbcode.php:197 ../../mod/impel.php:54 +msgid "menu" +msgstr "" + +#: ../../include/bbcode.php:211 +msgid "QR code" +msgstr "" + +#: ../../include/bbcode.php:262 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "" + +#: ../../include/bbcode.php:264 ../../mod/tagger.php:51 +msgid "post" +msgstr "" + +#: ../../include/bbcode.php:514 +msgid "Different viewers will see this text differently" +msgstr "" + +#: ../../include/bbcode.php:725 +msgid "$1 spoiler" +msgstr "" + +#: ../../include/bbcode.php:752 +msgid "$1 wrote:" +msgstr "" + +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +#: ../../include/chat.php:23 +msgid "Missing room name" +msgstr "" + +#: ../../include/chat.php:32 +msgid "Duplicate room name" +msgstr "" + +#: ../../include/chat.php:82 ../../include/chat.php:90 +msgid "Invalid room specifier." +msgstr "" + +#: ../../include/chat.php:120 +msgid "Room not found." +msgstr "" + +#: ../../include/chat.php:141 +msgid "Room is full" +msgstr "" + +#: ../../include/diaspora.php:2439 +msgid "Please choose" +msgstr "" + +#: ../../include/diaspora.php:2441 +msgid "Agree" +msgstr "" + +#: ../../include/diaspora.php:2443 +msgid "Disagree" +msgstr "" + +#: ../../include/diaspora.php:2445 +msgid "Abstain" +msgstr "" + +#: ../../mod/achievements.php:34 +msgid "Some blurb about what to do when you're new here" +msgstr "" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "" + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "" + +#: ../../mod/manage.php:167 +msgid "Current Channel" +msgstr "" + +#: ../../mod/manage.php:169 +msgid "Switch to one of your channels by selecting it." +msgstr "" + +#: ../../mod/manage.php:170 +msgid "Default Channel" +msgstr "" + +#: ../../mod/manage.php:171 +msgid "Make Default" +msgstr "" + +#: ../../mod/manage.php:174 +#, php-format +msgid "%d new messages" +msgstr "" + +#: ../../mod/manage.php:175 +#, php-format +msgid "%d new introductions" +msgstr "" + +#: ../../mod/manage.php:177 +msgid "Delegated Channels" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/settings.php:76 +msgid "Name is required" +msgstr "" + +#: ../../mod/settings.php:80 +msgid "Key and Secret are required" +msgstr "" + +#: ../../mod/settings.php:129 +msgid "Diaspora Policy Settings updated." +msgstr "" + +#: ../../mod/settings.php:237 +msgid "Passwords do not match. Password unchanged." +msgstr "" + +#: ../../mod/settings.php:241 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "" + +#: ../../mod/settings.php:255 +msgid "Password changed." +msgstr "" + +#: ../../mod/settings.php:257 +msgid "Password update failed. Please try again." +msgstr "" + +#: ../../mod/settings.php:271 +msgid "Not valid email." +msgstr "" + +#: ../../mod/settings.php:274 +msgid "Protected email address. Cannot change to that email." +msgstr "" + +#: ../../mod/settings.php:283 +msgid "System failure storing new email. Please try again." +msgstr "" + +#: ../../mod/settings.php:522 +msgid "Settings updated." +msgstr "" + +#: ../../mod/settings.php:578 ../../mod/api.php:106 ../../mod/photos.php:556 +#: ../../mod/menu.php:91 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:424 +#: ../../mod/removeme.php:60 ../../view/theme/redbasic/php/config.php:102 +#: ../../view/theme/redbasic/php/config.php:127 ../../boot.php:1554 +msgid "No" +msgstr "" + +#: ../../mod/settings.php:578 ../../mod/api.php:105 ../../mod/photos.php:556 +#: ../../mod/menu.php:91 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:426 +#: ../../mod/removeme.php:60 ../../view/theme/redbasic/php/config.php:102 +#: ../../view/theme/redbasic/php/config.php:127 ../../boot.php:1554 +msgid "Yes" +msgstr "" + +#: ../../mod/settings.php:586 ../../mod/settings.php:612 +#: ../../mod/settings.php:648 +msgid "Add application" +msgstr "" + +#: ../../mod/settings.php:589 +msgid "Name of application" +msgstr "" + +#: ../../mod/settings.php:590 ../../mod/settings.php:616 +msgid "Consumer Key" +msgstr "" + +#: ../../mod/settings.php:590 ../../mod/settings.php:591 +msgid "Automatically generated - change if desired. Max length 20" +======= +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/settings.php:591 ../../mod/settings.php:617 +msgid "Consumer Secret" +msgstr "" + +#: ../../mod/settings.php:592 ../../mod/settings.php:618 +msgid "Redirect" +msgstr "" + +#: ../../mod/settings.php:592 +msgid "" +"Redirect URI - leave blank unless your application specifically requires this" +msgstr "" + +#: ../../mod/settings.php:593 ../../mod/settings.php:619 +msgid "Icon url" +msgstr "" + +#: ../../mod/settings.php:593 +msgid "Optional" +msgstr "" + +#: ../../mod/settings.php:604 +msgid "You can't edit this application." +msgstr "" + +#: ../../mod/settings.php:647 +msgid "Connected Apps" +msgstr "" + +#: ../../mod/settings.php:651 +msgid "Client key starts with" +msgstr "" + +#: ../../mod/settings.php:652 +msgid "No name" +msgstr "" + +#: ../../mod/settings.php:653 +msgid "Remove authorization" +msgstr "" + +#: ../../mod/settings.php:667 +msgid "No feature settings configured" +msgstr "" + +#: ../../mod/settings.php:683 +msgid "Feature/Addon Settings" +msgstr "" + +#: ../../mod/settings.php:685 +msgid "Settings for the built-in Diaspora emulator" +msgstr "" + +#: ../../mod/settings.php:686 +msgid "Allow any Diaspora member to comment on your public posts" +msgstr "" + +#: ../../mod/settings.php:687 +msgid "Diaspora Policy Settings" +msgstr "" + +#: ../../mod/settings.php:688 +msgid "Prevent your hashtags from being redirected to other sites" +msgstr "" + +#: ../../mod/settings.php:712 +msgid "Account Settings" +msgstr "" + +#: ../../mod/settings.php:713 +msgid "Enter New Password:" +msgstr "" + +#: ../../mod/settings.php:714 +msgid "Confirm New Password:" +msgstr "" + +#: ../../mod/settings.php:714 +msgid "Leave password fields blank unless changing" +msgstr "" + +#: ../../mod/settings.php:716 ../../mod/settings.php:1051 +msgid "Email Address:" +msgstr "" + +#: ../../mod/settings.php:717 ../../mod/removeaccount.php:61 +msgid "Remove Account" +msgstr "" + +#: ../../mod/settings.php:718 +msgid "Remove this account including all its channels" +msgstr "" + +#: ../../mod/settings.php:734 +msgid "Off" +msgstr "" + +#: ../../mod/settings.php:734 +msgid "On" +msgstr "" + +#: ../../mod/settings.php:741 +msgid "Additional Features" +msgstr "" + +#: ../../mod/settings.php:765 +msgid "Connector Settings" +msgstr "" + +#: ../../mod/settings.php:804 +msgid "No special theme for mobile devices" +msgstr "" + +#: ../../mod/settings.php:807 +#, php-format +msgid "%s - (Experimental)" +msgstr "" + +#: ../../mod/settings.php:810 ../../mod/admin.php:396 +msgid "mobile" +msgstr "" + +#: ../../mod/settings.php:846 +msgid "Display Settings" +msgstr "" + +#: ../../mod/settings.php:852 +msgid "Display Theme:" +msgstr "" + +#: ../../mod/settings.php:853 +msgid "Mobile Theme:" +msgstr "" + +#: ../../mod/settings.php:854 +msgid "Enable user zoom on mobile devices" +msgstr "" + +#: ../../mod/settings.php:855 +msgid "Update browser every xx seconds" +msgstr "" + +#: ../../mod/settings.php:855 +msgid "Minimum of 10 seconds, no maximum" +msgstr "" + +#: ../../mod/settings.php:856 +msgid "Maximum number of conversations to load at any time:" +msgstr "" + +#: ../../mod/settings.php:856 +msgid "Maximum of 100 items" +msgstr "" + +#: ../../mod/settings.php:857 +msgid "Show emoticons (smilies) as images" +msgstr "" + +#: ../../mod/settings.php:858 +msgid "Link post titles to source" +msgstr "" + +#: ../../mod/settings.php:859 +msgid "System Page Layout Editor - (advanced)" +msgstr "" + +#: ../../mod/settings.php:862 +msgid "Use blog/list mode on channel page" +msgstr "" + +#: ../../mod/settings.php:862 ../../mod/settings.php:863 +msgid "(comments displayed separately)" +msgstr "" + +#: ../../mod/settings.php:863 +msgid "Use blog/list mode on matrix page" +msgstr "" + +#: ../../mod/settings.php:864 +msgid "Channel page max height of content (in pixels)" +msgstr "" + +#: ../../mod/settings.php:864 ../../mod/settings.php:865 +msgid "click to expand content exceeding this height" +msgstr "" + +#: ../../mod/settings.php:865 +msgid "Matrix page max height of content (in pixels)" +msgstr "" + +#: ../../mod/settings.php:899 +msgid "Nobody except yourself" +msgstr "" + +#: ../../mod/settings.php:900 +msgid "Only those you specifically allow" +msgstr "" + +#: ../../mod/settings.php:901 +msgid "Approved connections" +msgstr "" + +#: ../../mod/settings.php:902 +msgid "Any connections" +msgstr "" + +#: ../../mod/settings.php:903 +msgid "Anybody on this website" +msgstr "" + +#: ../../mod/settings.php:904 +msgid "Anybody in this network" +msgstr "" + +#: ../../mod/settings.php:905 +msgid "Anybody authenticated" +msgstr "" + +#: ../../mod/settings.php:906 +msgid "Anybody on the internet" +msgstr "" + +#: ../../mod/settings.php:980 +msgid "Publish your default profile in the network directory" +msgstr "" + +#: ../../mod/settings.php:985 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "" + +#: ../../mod/settings.php:989 ../../mod/profile_photo.php:366 +msgid "or" +msgstr "" + +#: ../../mod/settings.php:994 +msgid "Your channel address is" +msgstr "" + +#: ../../mod/settings.php:1042 +msgid "Channel Settings" +msgstr "" + +#: ../../mod/settings.php:1049 +msgid "Basic Settings" +msgstr "" + +#: ../../mod/settings.php:1052 +msgid "Your Timezone:" +msgstr "" + +#: ../../mod/settings.php:1053 +msgid "Default Post Location:" +msgstr "" + +#: ../../mod/settings.php:1053 +msgid "Geographical location to display on your posts" +msgstr "" + +#: ../../mod/settings.php:1054 +msgid "Use Browser Location:" +msgstr "" + +#: ../../mod/settings.php:1056 +msgid "Adult Content" +msgstr "" + +#: ../../mod/settings.php:1056 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "" + +#: ../../mod/settings.php:1058 +msgid "Security and Privacy Settings" +msgstr "" + +#: ../../mod/settings.php:1060 +msgid "Your permissions are already configured. Click to view/adjust" +msgstr "" + +#: ../../mod/settings.php:1062 +msgid "Hide my online presence" +msgstr "" + +#: ../../mod/settings.php:1062 +msgid "Prevents displaying in your profile that you are online" +msgstr "" + +#: ../../mod/settings.php:1064 +msgid "Simple Privacy Settings:" +msgstr "" + +#: ../../mod/settings.php:1065 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "" + +#: ../../mod/settings.php:1066 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "" + +#: ../../mod/settings.php:1067 +msgid "Private - default private, never open or public" +msgstr "" + +#: ../../mod/settings.php:1068 +msgid "Blocked - default blocked to/from everybody" +msgstr "" + +#: ../../mod/settings.php:1070 +msgid "Allow others to tag your posts" +msgstr "" + +#: ../../mod/settings.php:1070 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "" + +#: ../../mod/settings.php:1072 +msgid "Advanced Privacy Settings" +msgstr "" + +#: ../../mod/settings.php:1074 +msgid "Expire other channel content after this many days" +msgstr "" + +#: ../../mod/settings.php:1074 +msgid "0 or blank prevents expiration" +msgstr "" + +#: ../../mod/settings.php:1075 +msgid "Maximum Friend Requests/Day:" +msgstr "" + +#: ../../mod/settings.php:1075 +msgid "May reduce spam activity" +msgstr "" + +#: ../../mod/settings.php:1076 +msgid "Default Post Permissions" +msgstr "" + +#: ../../mod/settings.php:1077 ../../mod/mitem.php:159 ../../mod/mitem.php:229 +msgid "(click to open/close)" +msgstr "" + +#: ../../mod/settings.php:1081 +msgid "Channel permissions category:" +msgstr "" + +#: ../../mod/settings.php:1087 +msgid "Maximum private messages per day from unknown people:" +msgstr "" + +#: ../../mod/settings.php:1087 +msgid "Useful to reduce spamming" +msgstr "" + +#: ../../mod/settings.php:1090 +msgid "Notification Settings" +msgstr "" + +#: ../../mod/settings.php:1091 +msgid "By default post a status message when:" +msgstr "" + +#: ../../mod/settings.php:1092 +msgid "accepting a friend request" +msgstr "" + +#: ../../mod/settings.php:1093 +msgid "joining a forum/community" +msgstr "" + +#: ../../mod/settings.php:1094 +msgid "making an interesting profile change" +msgstr "" + +#: ../../mod/settings.php:1095 +msgid "Send a notification email when:" +msgstr "" + +#: ../../mod/settings.php:1096 +msgid "You receive a connection request" +msgstr "" + +#: ../../mod/settings.php:1097 +msgid "Your connections are confirmed" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/settings.php:1098 +msgid "Someone writes on your profile wall" +======= +#: ../../mod/events.php:645 ../../mod/directory.php:301 +msgid "Description:" +msgstr "" + +#: ../../mod/events.php:649 +msgid "Title:" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/settings.php:1099 +msgid "Someone writes a followup comment" +msgstr "" + +#: ../../mod/settings.php:1100 +msgid "You receive a private message" +msgstr "" + +#: ../../mod/settings.php:1101 +msgid "You receive a friend suggestion" +msgstr "" + +#: ../../mod/settings.php:1102 +msgid "You are tagged in a post" +msgstr "" + +#: ../../mod/settings.php:1103 +msgid "You are poked/prodded/etc. in a post" +msgstr "" + +#: ../../mod/settings.php:1106 +msgid "Show visual notifications including:" +msgstr "" + +#: ../../mod/settings.php:1108 +msgid "Unseen matrix activity" +msgstr "" + +#: ../../mod/settings.php:1109 +msgid "Unseen channel activity" +msgstr "" + +#: ../../mod/settings.php:1110 +msgid "Unseen private messages" +msgstr "" + +#: ../../mod/settings.php:1110 ../../mod/settings.php:1115 +#: ../../mod/settings.php:1116 ../../mod/settings.php:1117 +msgid "Recommended" +msgstr "" + +#: ../../mod/settings.php:1111 +msgid "Upcoming events" +msgstr "" + +#: ../../mod/settings.php:1112 +msgid "Events today" +msgstr "" + +#: ../../mod/settings.php:1113 +msgid "Upcoming birthdays" +msgstr "" + +#: ../../mod/settings.php:1113 +msgid "Not available in all themes" +msgstr "" + +#: ../../mod/settings.php:1114 +msgid "System (personal) notifications" +msgstr "" + +#: ../../mod/settings.php:1115 +msgid "System info messages" +msgstr "" + +#: ../../mod/settings.php:1116 +msgid "System critical alerts" +msgstr "" + +#: ../../mod/settings.php:1117 +msgid "New connections" +msgstr "" + +#: ../../mod/settings.php:1118 +msgid "System Registrations" +msgstr "" + +#: ../../mod/settings.php:1119 +msgid "" +"Also show new wall posts, private messages and connections under Notices" +msgstr "" + +#: ../../mod/settings.php:1121 +msgid "Notify me of events this many days in advance" +msgstr "" + +#: ../../mod/settings.php:1121 +msgid "Must be greater than 0" +msgstr "" + +#: ../../mod/settings.php:1123 +msgid "Advanced Account/Page Type Settings" +msgstr "" + +#: ../../mod/settings.php:1124 +msgid "Change the behaviour of this account for special situations" +msgstr "" + +#: ../../mod/settings.php:1127 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "" + +#: ../../mod/settings.php:1128 +msgid "Miscellaneous Settings" +msgstr "" + +#: ../../mod/settings.php:1130 +msgid "Personal menu to display in your channel pages" +msgstr "" + +#: ../../mod/settings.php:1131 ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "" + +#: ../../mod/settings.php:1132 +msgid "Remove this channel." +msgstr "" + +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +msgstr "" + +#: ../../mod/xchan.php:9 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "" + +#: ../../mod/xchan.php:37 ../../mod/menu.php:152 ../../mod/mitem.php:120 +msgid "Not found." +msgstr "" + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "" + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts, " +"and/or create new posts for you?" +msgstr "" + +#: ../../mod/webpages.php:190 +msgid "Page Title" +msgstr "" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "" + +#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94 +msgid "Tag removed" +msgstr "" + +#: ../../mod/tagrm.php:119 +msgid "Remove Item Tag" +msgstr "" + +#: ../../mod/tagrm.php:121 +msgid "Select a tag to remove: " +msgstr "" + +#: ../../mod/tagrm.php:133 ../../mod/photos.php:875 +msgid "Remove" +msgstr "" + +#: ../../mod/connect.php:56 ../../mod/connect.php:104 +msgid "Continue" +msgstr "" + +#: ../../mod/connect.php:85 +msgid "Premium Channel Setup" +msgstr "" + +#: ../../mod/connect.php:87 +msgid "Enable premium channel connection restrictions" +msgstr "" + +#: ../../mod/connect.php:88 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "" + +#: ../../mod/connect.php:90 ../../mod/connect.php:110 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "" + +#: ../../mod/connect.php:91 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "" + +#: ../../mod/connect.php:92 ../../mod/connect.php:113 +msgid "" +"By continuing, I certify that I have complied with any instructions provided " +"on this page." +msgstr "" + +#: ../../mod/connect.php:101 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "" + +#: ../../mod/connect.php:109 +msgid "Restricted or Premium Channel" +msgstr "" + +#: ../../mod/thing.php:94 +msgid "Thing updated" +msgstr "" + +#: ../../mod/thing.php:153 +msgid "Object store: failed" +msgstr "" + +#: ../../mod/thing.php:157 +msgid "Thing added" +msgstr "" + +#: ../../mod/thing.php:175 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "" + +#: ../../mod/thing.php:226 +msgid "Show Thing" +msgstr "" + +#: ../../mod/thing.php:233 +msgid "item not found." +msgstr "" + +#: ../../mod/thing.php:261 +msgid "Edit Thing" +msgstr "" + +#: ../../mod/thing.php:263 ../../mod/thing.php:310 +msgid "Select a profile" +msgstr "" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Post an activity" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Only sends to viewers of the applicable profile" +msgstr "" + +#: ../../mod/thing.php:269 ../../mod/thing.php:315 +msgid "Name of thing e.g. something" +======= +#: ../../mod/connections.php:94 ../../mod/connedit.php:220 +msgid "Connection updated." +msgstr "" + +#: ../../mod/connections.php:96 ../../mod/connedit.php:222 +msgid "Failed to update connection record." +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/thing.php:271 ../../mod/thing.php:316 +msgid "URL of thing (optional)" +msgstr "" + +#: ../../mod/thing.php:273 ../../mod/thing.php:317 +msgid "URL for photo of thing (optional)" +msgstr "" + +#: ../../mod/thing.php:308 +msgid "Add Thing to your Profile" +msgstr "" + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "" + +#: ../../mod/probe.php:24 ../../mod/probe.php:30 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "" + +#: ../../mod/home.php:53 ../../mod/siteinfo.php:155 +msgid "$Projectname" +msgstr "" + +#: ../../mod/home.php:124 +#, php-format +msgid "Welcome to %s" +msgstr "" + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "" + +#: ../../mod/profile_photo.php:162 +msgid "Image resize failed." +msgstr "" + +#: ../../mod/profile_photo.php:206 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "" + +#: ../../mod/profile_photo.php:233 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "" + +#: ../../mod/profile_photo.php:242 +msgid "Unable to process image." +msgstr "" + +#: ../../mod/profile_photo.php:291 ../../mod/profile_photo.php:340 +msgid "Photo not available." +msgstr "" + +#: ../../mod/profile_photo.php:359 +msgid "Upload File:" +msgstr "" + +#: ../../mod/profile_photo.php:360 +msgid "Select a profile:" +msgstr "" + +#: ../../mod/profile_photo.php:361 +msgid "Upload Profile Photo" +msgstr "" + +#: ../../mod/profile_photo.php:366 +msgid "skip this step" +msgstr "" + +#: ../../mod/profile_photo.php:366 +msgid "select a photo from your photo albums" +msgstr "" + +#: ../../mod/profile_photo.php:382 +msgid "Crop Image" +msgstr "" + +#: ../../mod/profile_photo.php:383 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "" + +#: ../../mod/profile_photo.php:385 +msgid "Done Editing" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/profile_photo.php:428 +msgid "Image uploaded successfully." +======= +#: ../../mod/directory.php:48 ../../mod/photos.php:441 ../../mod/search.php:13 +#: ../../mod/display.php:13 ../../mod/ratings.php:82 +#: ../../mod/viewconnections.php:17 +msgid "Public access denied." +msgstr "" + +#: ../../mod/directory.php:227 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/directory.php:238 +msgid "Gender: " +msgstr "" + +#: ../../mod/directory.php:240 +msgid "Status: " +msgstr "" + +#: ../../mod/directory.php:242 +msgid "Homepage: " +msgstr "" + +#: ../../mod/directory.php:310 +msgid "Public Forum:" +msgstr "" + +#: ../../mod/directory.php:313 +msgid "Keywords: " +msgstr "" + +#: ../../mod/directory.php:316 +msgid "Don't suggest" +msgstr "" + +#: ../../mod/directory.php:318 +msgid "Common connections:" +msgstr "" + +#: ../../mod/directory.php:367 +msgid "Global Directory" +msgstr "" + +#: ../../mod/directory.php:367 +msgid "Local Directory" +msgstr "" + +#: ../../mod/directory.php:373 +msgid "Finding:" +msgstr "" + +#: ../../mod/directory.php:378 +msgid "next page" +msgstr "" + +#: ../../mod/directory.php:378 +msgid "previous page" +msgstr "" + +#: ../../mod/directory.php:394 +msgid "No entries (some entries may be hidden)." +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/profile_photo.php:430 +msgid "Image upload failed." +msgstr "" + +#: ../../mod/profile_photo.php:439 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "" + +#: ../../mod/block.php:27 ../../mod/page.php:33 +msgid "Invalid item." +msgstr "" + +#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:49 +msgid "Channel not found." +msgstr "" + +#: ../../mod/block.php:75 ../../mod/help.php:79 ../../mod/display.php:106 +#: ../../mod/page.php:85 ../../index.php:230 +msgid "Page not found." +msgstr "" + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "" + +#: ../../mod/like.php:21 +msgid "" +"Please login with your $Projectname ID or register as a new $Projectname member to continue." +msgstr "" + +#: ../../mod/like.php:101 ../../mod/like.php:128 ../../mod/like.php:166 +msgid "Invalid request." +msgstr "" + +#: ../../mod/like.php:143 +msgid "thing" +msgstr "" + +#: ../../mod/like.php:189 +msgid "Channel unavailable." +msgstr "" + +#: ../../mod/like.php:228 +msgid "Previous action reversed." +msgstr "" + +#: ../../mod/like.php:398 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:400 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:402 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:404 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:406 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:408 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "" + +#: ../../mod/like.php:492 +msgid "Action completed." +msgstr "" + +#: ../../mod/like.php:493 +msgid "Thank you." +msgstr "" + +#: ../../mod/events.php:87 +msgid "Event can not end before it has started." +msgstr "" + +#: ../../mod/events.php:89 ../../mod/events.php:98 ../../mod/events.php:116 +msgid "Unable to generate preview." +msgstr "" + +#: ../../mod/events.php:96 +msgid "Event title and start time are required." +msgstr "" + +#: ../../mod/events.php:114 +msgid "Event not found." +msgstr "" + +#: ../../mod/events.php:396 +msgid "l, F j" +msgstr "" + +#: ../../mod/events.php:418 +msgid "Edit event" +msgstr "" + +#: ../../mod/events.php:419 +msgid "Delete event" +msgstr "" + +#: ../../mod/events.php:473 +msgid "Create New Event" +msgstr "" + +#: ../../mod/events.php:474 ../../mod/photos.php:827 +msgid "Previous" +msgstr "" + +#: ../../mod/events.php:475 ../../mod/photos.php:836 ../../mod/setup.php:281 +msgid "Next" +msgstr "" + +#: ../../mod/events.php:476 +msgid "Export" +msgstr "" + +#: ../../mod/events.php:504 +msgid "Event removed" +msgstr "" + +#: ../../mod/events.php:507 +msgid "Failed to remove event" +msgstr "" + +#: ../../mod/events.php:627 +msgid "Event details" +msgstr "" + +#: ../../mod/events.php:628 +msgid "Starting date and Title are required." +msgstr "" + +#: ../../mod/events.php:630 +msgid "Categories (comma-separated list)" +msgstr "" + +#: ../../mod/events.php:632 +msgid "Event Starts:" +msgstr "" + +#: ../../mod/events.php:639 +msgid "Finish date/time is not known or not relevant" +msgstr "" + +#: ../../mod/events.php:641 +msgid "Event Finishes:" +msgstr "" + +#: ../../mod/events.php:643 ../../mod/events.php:644 +msgid "Adjust for viewer timezone" +msgstr "" + +#: ../../mod/events.php:643 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." +msgstr "" + +#: ../../mod/events.php:645 +msgid "Description:" +msgstr "" + +#: ../../mod/events.php:649 +msgid "Title:" +msgstr "" + +#: ../../mod/events.php:651 +msgid "Share this event" +msgstr "" + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration for the $Projectname network. All " +"sites in the network are interlinked so membership on any of them conveys " +"membership in the network as a whole. Some sites may require subscription or " +"provide tiered service plans. The provider links may " +"provide additional details." +msgstr "" + +#: ../../mod/pubsites.php:25 +msgid "Rate this hub" +msgstr "" + +#: ../../mod/pubsites.php:26 +msgid "Site URL" +msgstr "" + +#: ../../mod/pubsites.php:26 +msgid "Access Type" +msgstr "" + +#: ../../mod/pubsites.php:26 +msgid "Registration Policy" +msgstr "" + +#: ../../mod/pubsites.php:26 ../../mod/profiles.php:454 +msgid "Location" +msgstr "" + +#: ../../mod/pubsites.php:26 +msgid "View hub ratings" +msgstr "" + +#: ../../mod/pubsites.php:30 +msgid "Rate" +msgstr "" + +#: ../../mod/pubsites.php:31 +msgid "View ratings" +msgstr "" + +#: ../../mod/rpost.php:131 ../../mod/editpost.php:42 +msgid "Edit post" +msgstr "" + +#: ../../mod/dav.php:121 +msgid "$Projectname channel" +msgstr "" + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "" + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "" + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "" + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "" + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "" + +<<<<<<< HEAD +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "" + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "" + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "" + +#: ../../mod/group.php:196 ../../mod/bulksetclose.php:89 +msgid "Members" +msgstr "" + +#: ../../mod/group.php:198 ../../mod/bulksetclose.php:91 +msgid "All Connected Channels" +msgstr "" + +#: ../../mod/group.php:233 ../../mod/bulksetclose.php:126 +msgid "Click on a channel to add or remove." +msgstr "" + +#: ../../mod/siteinfo.php:112 +#, php-format +msgid "Version %s" +msgstr "" + +#: ../../mod/siteinfo.php:133 +msgid "Installed plugins/addons/apps:" +msgstr "" + +#: ../../mod/siteinfo.php:146 +msgid "No installed plugins/addons/apps" +msgstr "" + +#: ../../mod/siteinfo.php:156 +msgid "" +"This is a hub of $Projectname - a global cooperative network of " +"decentralized privacy enhanced websites." +msgstr "" + +#: ../../mod/siteinfo.php:158 +msgid "Tag: " +msgstr "" + +#: ../../mod/siteinfo.php:160 +msgid "Last background fetch: " +msgstr "" + +#: ../../mod/siteinfo.php:163 +msgid "Running at web location" +msgstr "" + +#: ../../mod/siteinfo.php:164 +======= +#: ../../mod/import.php:110 +msgid "The data provided is not compatible with this project." +msgstr "" + +#: ../../mod/import.php:115 +#, php-format +msgid "Warning: Database versions differ by %1$d updates." +msgstr "" + +#: ../../mod/import.php:135 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "" + +#: ../../mod/import.php:176 +msgid "Channel clone failed. Import failed." +msgstr "" + +#: ../../mod/import.php:186 +msgid "Cloned channel not found. Import failed." +msgstr "" + +#: ../../mod/import.php:516 +msgid "You must be logged in to use this feature." +msgstr "" + +#: ../../mod/import.php:521 +msgid "Import Channel" +msgstr "" + +#: ../../mod/import.php:522 +msgid "" +"Use this form to import an existing channel from a different server/hub. You " +"may retrieve the channel identity from the old server/hub via the network or " +"provide an export file." +msgstr "" + +#: ../../mod/import.php:523 +msgid "File to Upload" +msgstr "" + +#: ../../mod/import.php:524 +msgid "Or provide the old server/hub details" +msgstr "" + +#: ../../mod/import.php:525 +msgid "Your old identity address (xyz@example.com)" +msgstr "" + +#: ../../mod/import.php:526 +msgid "Your old login email address" +msgstr "" + +#: ../../mod/import.php:527 +msgid "Your old login password" +msgstr "" + +#: ../../mod/import.php:528 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be " +"able to post from either location, but only one can be marked as the primary " +"location for files, photos, and media." +msgstr "" + +#: ../../mod/import.php:529 +msgid "Make this hub my primary location" +msgstr "" + +#: ../../mod/import.php:530 +msgid "" +"Import existing posts if possible (experimental - limited by available memory" +msgstr "" + +#: ../../mod/import.php:531 +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgid "" +"Please visit redmatrix.me to learn more " +"about $Projectname." +msgstr "" + +#: ../../mod/siteinfo.php:165 +msgid "Bug reports and issues: please visit" +msgstr "" + +#: ../../mod/siteinfo.php:168 +msgid "" +"Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot com" +msgstr "" + +#: ../../mod/siteinfo.php:170 +msgid "Site Administrators" +msgstr "" + +#: ../../mod/help.php:49 ../../mod/help.php:55 ../../mod/help.php:61 +msgid "Help:" +msgstr "" + +#: ../../mod/help.php:76 ../../index.php:227 +msgid "Not Found" +msgstr "" + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "" + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "" + +#: ../../mod/regdir.php:45 ../../mod/dirsearch.php:21 +msgid "This site is not a directory server" +msgstr "" + +#: ../../mod/connections.php:37 ../../mod/connedit.php:75 +msgid "Could not access contact record." +msgstr "" + +#: ../../mod/connections.php:51 ../../mod/connedit.php:99 +msgid "Could not locate selected profile." +msgstr "" + +#: ../../mod/connections.php:94 ../../mod/connedit.php:214 +msgid "Connection updated." +msgstr "" + +#: ../../mod/connections.php:96 ../../mod/connedit.php:216 +msgid "Failed to update connection record." +msgstr "" + +#: ../../mod/connections.php:192 ../../mod/connections.php:293 +msgid "Blocked" +msgstr "" + +#: ../../mod/connections.php:197 ../../mod/connections.php:300 +msgid "Ignored" +msgstr "" + +#: ../../mod/connections.php:202 ../../mod/connections.php:314 +msgid "Hidden" +msgstr "" + +#: ../../mod/connections.php:207 ../../mod/connections.php:307 +msgid "Archived" +msgstr "" + +#: ../../mod/connections.php:271 +msgid "Suggest new connections" +msgstr "" + +#: ../../mod/connections.php:274 +msgid "New Connections" +msgstr "" + +#: ../../mod/connections.php:277 +msgid "Show pending (new) connections" +msgstr "" + +#: ../../mod/connections.php:280 ../../mod/profperm.php:139 +msgid "All Connections" +msgstr "" + +#: ../../mod/connections.php:283 +msgid "Show all connections" +msgstr "" + +#: ../../mod/connections.php:286 +msgid "Unblocked" +msgstr "" + +#: ../../mod/connections.php:289 +msgid "Only show unblocked connections" +msgstr "" + +#: ../../mod/connections.php:296 +msgid "Only show blocked connections" +msgstr "" + +#: ../../mod/connections.php:303 +msgid "Only show ignored connections" +msgstr "" + +#: ../../mod/connections.php:310 +msgid "Only show archived connections" +msgstr "" + +#: ../../mod/connections.php:317 +msgid "Only show hidden connections" +msgstr "" + +#: ../../mod/connections.php:372 +#, php-format +msgid "%1$s [%2$s]" +msgstr "" + +#: ../../mod/connections.php:373 +msgid "Edit connection" +msgstr "" + +#: ../../mod/connections.php:411 +msgid "Search your connections" +msgstr "" + +#: ../../mod/connections.php:412 +msgid "Finding: " +msgstr "" + +#: ../../mod/blocks.php:95 ../../mod/blocks.php:148 +msgid "Block Name" +msgstr "" + +#: ../../mod/blocks.php:149 +msgid "Block Title" +msgstr "" + +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "" + +#: ../../mod/cloud.php:120 +msgid "$Projectname - Guests: Username: {your email address}, Password: +++" +msgstr "" + +#: ../../mod/photos.php:77 +msgid "Page owner information could not be retrieved." +msgstr "" + +#: ../../mod/photos.php:97 +msgid "Album not found." +msgstr "" + +#: ../../mod/photos.php:119 ../../mod/photos.php:643 +msgid "Delete Album" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/photos.php:159 ../../mod/photos.php:930 +msgid "Delete Photo" +msgstr "" + +#: ../../mod/photos.php:429 ../../mod/search.php:13 ../../mod/display.php:13 +#: ../../mod/ratings.php:82 ../../mod/directory.php:47 +#: ../../mod/viewconnections.php:17 +msgid "Public access denied." +======= +#: ../../mod/rate.php:161 ../../mod/connedit.php:669 +msgid "Rating (this information is public)" +msgstr "" + +#: ../../mod/rate.php:162 ../../mod/connedit.php:670 +#: ../../mod/connedit.php:674 +msgid "Optionally explain your rating (this information is public)" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/photos.php:440 +msgid "No photos selected" +msgstr "" + +#: ../../mod/photos.php:484 +msgid "Access to this item is restricted." +msgstr "" + +#: ../../mod/photos.php:523 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgstr "" + +#: ../../mod/photos.php:526 +#, php-format +msgid "%1$.2f MB photo storage used." +msgstr "" + +#: ../../mod/photos.php:550 +msgid "Upload Photos" +msgstr "" + +#: ../../mod/photos.php:554 ../../mod/photos.php:636 ../../mod/photos.php:915 +msgid "Enter a new album name" +msgstr "" + +#: ../../mod/photos.php:555 ../../mod/photos.php:637 ../../mod/photos.php:916 +msgid "or select an existing one (doubleclick)" +msgstr "" + +#: ../../mod/photos.php:556 +msgid "Create a status post for this upload" +msgstr "" + +#: ../../mod/photos.php:584 +msgid "Album name could not be decoded" +msgstr "" + +#: ../../mod/photos.php:625 ../../mod/photos.php:1157 +#: ../../mod/photos.php:1173 +msgid "Contact Photos" +msgstr "" + +#: ../../mod/photos.php:649 +msgid "Show Newest First" +msgstr "" + +#: ../../mod/photos.php:651 +msgid "Show Oldest First" +msgstr "" + +#: ../../mod/photos.php:675 ../../mod/photos.php:1205 +msgid "View Photo" +msgstr "" + +#: ../../mod/photos.php:704 +msgid "Edit Album" +msgstr "" + +#: ../../mod/photos.php:749 +msgid "Permission denied. Access to this item may be restricted." +msgstr "" + +#: ../../mod/photos.php:751 +msgid "Photo not available" +msgstr "" + +#: ../../mod/photos.php:809 +msgid "Use as profile photo" +msgstr "" + +#: ../../mod/photos.php:816 +msgid "Private Photo" +msgstr "" + +#: ../../mod/photos.php:831 +msgid "View Full Size" +msgstr "" + +#: ../../mod/photos.php:909 +msgid "Edit photo" +msgstr "" + +#: ../../mod/photos.php:911 +msgid "Rotate CW (right)" +msgstr "" + +#: ../../mod/photos.php:912 +msgid "Rotate CCW (left)" +msgstr "" + +#: ../../mod/photos.php:919 +msgid "Caption" +msgstr "" + +#: ../../mod/photos.php:921 +msgid "Add a Tag" +msgstr "" + +#: ../../mod/photos.php:925 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +msgstr "" + +#: ../../mod/photos.php:928 +msgid "Flag as adult in album view" +msgstr "" + +#: ../../mod/photos.php:1120 +msgid "In This Photo:" +msgstr "" + +#: ../../mod/photos.php:1125 +msgid "Map" +msgstr "" + +#: ../../mod/photos.php:1211 +msgid "View Album" +msgstr "" + +#: ../../mod/photos.php:1234 +msgid "Recent Photos" +msgstr "" + +#: ../../mod/search.php:206 +#, php-format +msgid "Items tagged with: %s" +msgstr "" + +#: ../../mod/search.php:208 +#, php-format +msgid "Search results for: %s" +msgstr "" + +#: ../../mod/match.php:22 +msgid "Profile Match" +msgstr "" + +#: ../../mod/match.php:31 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "" + +#: ../../mod/match.php:63 +msgid "is interested in:" +msgstr "" + +#: ../../mod/match.php:70 +msgid "No matches" +msgstr "" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "" + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "" + +#: ../../mod/rbmark.php:95 ../../mod/appman.php:93 +msgid "Description" +msgstr "" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "" + +#: ../../mod/notify.php:53 ../../mod/notifications.php:94 +msgid "No more system notifications." +msgstr "" + +#: ../../mod/notify.php:57 ../../mod/notifications.php:98 +msgid "System Notifications" +msgstr "" + +#: ../../mod/acl.php:231 +msgid "network" +msgstr "" + +#: ../../mod/acl.php:241 +msgid "RSS" +msgstr "" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "" + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "" + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "" + +#: ../../mod/pdledit.php:55 +msgid "Layout Help" +msgstr "" + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "" + +#: ../../mod/import.php:25 +#, php-format +msgid "Your service plan only allows %d channels." +msgstr "" + +#: ../../mod/import.php:51 +msgid "Nothing to import." +msgstr "" + +#: ../../mod/import.php:75 +msgid "Unable to download data from old server" +msgstr "" + +#: ../../mod/import.php:81 +msgid "Imported file is empty." +msgstr "" + +#: ../../mod/import.php:106 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "" + +#: ../../mod/import.php:127 +msgid "Unable to create a unique channel address. Import failed." +msgstr "" + +#: ../../mod/import.php:147 +msgid "Channel clone failed. Import failed." +msgstr "" + +#: ../../mod/import.php:157 +msgid "Cloned channel not found. Import failed." +msgstr "" + +#: ../../mod/import.php:475 +msgid "Import completed." +msgstr "" + +#: ../../mod/import.php:487 +msgid "You must be logged in to use this feature." +msgstr "" + +#: ../../mod/import.php:492 +msgid "Import Channel" +msgstr "" + +#: ../../mod/import.php:493 +msgid "" +"Use this form to import an existing channel from a different server/hub. You " +"may retrieve the channel identity from the old server/hub via the network or " +"provide an export file. Only identity and connections/relationships will be " +"imported. Importation of content is not yet available." +msgstr "" + +#: ../../mod/import.php:494 +msgid "File to Upload" +msgstr "" + +#: ../../mod/import.php:495 +msgid "Or provide the old server/hub details" +msgstr "" + +#: ../../mod/import.php:496 +msgid "Your old identity address (xyz@example.com)" +msgstr "" + +#: ../../mod/import.php:497 +msgid "Your old login email address" +msgstr "" + +#: ../../mod/import.php:498 +msgid "Your old login password" +msgstr "" + +#: ../../mod/import.php:499 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be " +"able to post from either location, but only one can be marked as the primary " +"location for files, photos, and media." +msgstr "" + +#: ../../mod/import.php:500 +msgid "Make this hub my primary location" +msgstr "" + +#: ../../mod/import.php:501 +msgid "Import existing posts if possible" +msgstr "" + +#: ../../mod/editlayout.php:76 ../../mod/editwebpage.php:77 +#: ../../mod/editpost.php:20 ../../mod/editblock.php:78 +#: ../../mod/editblock.php:94 +msgid "Item not found" +msgstr "" + +#: ../../mod/editlayout.php:106 +msgid "Edit Layout" +msgstr "" + +#: ../../mod/editlayout.php:117 +msgid "Delete layout?" +msgstr "" + +#: ../../mod/editlayout.php:148 ../../mod/editwebpage.php:187 +#: ../../mod/editpost.php:122 ../../mod/editblock.php:150 +msgid "Insert YouTube video" +msgstr "" + +#: ../../mod/editlayout.php:149 ../../mod/editwebpage.php:188 +#: ../../mod/editpost.php:123 ../../mod/editblock.php:151 +msgid "Insert Vorbis [.ogg] video" +msgstr "" + +#: ../../mod/editlayout.php:150 ../../mod/editwebpage.php:189 +#: ../../mod/editpost.php:124 ../../mod/editblock.php:152 +msgid "Insert Vorbis [.ogg] audio" +msgstr "" + +#: ../../mod/editlayout.php:164 ../../mod/layouts.php:124 +msgid "Layout Description (Optional)" +msgstr "" + +#: ../../mod/editlayout.php:166 ../../mod/layouts.php:121 +#: ../../mod/layouts.php:179 +msgid "Layout Name" +msgstr "" + +#: ../../mod/chat.php:19 ../../mod/channel.php:25 +msgid "You must be logged in to see this page." +msgstr "" + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "" + +#: ../../mod/editwebpage.php:152 +msgid "Delete webpage?" +msgstr "" + +#: ../../mod/editwebpage.php:173 +msgid "Page link title" +msgstr "" + +#: ../../mod/editwebpage.php:224 +msgid "Edit Webpage" +msgstr "" + +#: ../../mod/dirsearch.php:29 +msgid "This directory server requires an access token" +msgstr "" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "" + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "" + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "" + +#: ../../mod/lostpass.php:85 ../../boot.php:1558 +msgid "Password Reset" +msgstr "" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "" + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "" + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "" + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "" + +#: ../../mod/rate.php:157 +msgid "Website:" +msgstr "" + +#: ../../mod/rate.php:160 +#, php-format +msgid "Remote Channel [%s] (not yet known on this site)" +msgstr "" + +#: ../../mod/rate.php:161 ../../mod/connedit.php:663 +msgid "Rating (this information is public)" +msgstr "" + +#: ../../mod/rate.php:162 ../../mod/connedit.php:664 +msgid "Optionally explain your rating (this information is public)" +msgstr "" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "" + +#: ../../mod/editpost.php:53 +msgid "Delete item?" +msgstr "" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "" + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "" + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "" + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "" + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "" + +#: ../../mod/invite.php:131 ../../mod/mail.php:235 ../../mod/mail.php:348 +msgid "Your message:" +msgstr "" + +#: ../../mod/invite.php:132 +msgid "Please join my community on $Projectname." +msgstr "" + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "" + +#: ../../mod/invite.php:135 +msgid "1. Register at any $Projectname location (they are all inter-connected)" +msgstr "" + +#: ../../mod/invite.php:137 +msgid "2. Enter my $Projectname network address into the site searchbar." +msgstr "" + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "" + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "" + +#: ../../mod/locs.php:21 ../../mod/locs.php:52 +msgid "Location not found." +msgstr "" + +#: ../../mod/locs.php:56 +msgid "Primary location cannot be removed." +msgstr "" + +#: ../../mod/locs.php:88 +msgid "No locations found." +msgstr "" + +#: ../../mod/locs.php:101 +msgid "Manage Channel Locations" +msgstr "" + +#: ../../mod/locs.php:102 +msgid "Location (address)" +msgstr "" + +#: ../../mod/locs.php:103 +msgid "Primary Location" +msgstr "" + +#: ../../mod/locs.php:104 +msgid "Drop location" +msgstr "" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "" + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "" + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "" + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "" + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:112 +msgid "Channel Name" +msgstr "" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "" + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "" + +#: ../../mod/menu.php:44 +msgid "Unable to update menu." +msgstr "" + +#: ../../mod/menu.php:53 +msgid "Unable to create menu." +msgstr "" + +#: ../../mod/menu.php:89 ../../mod/menu.php:101 +msgid "Menu Name" +msgstr "" + +#: ../../mod/menu.php:89 +msgid "Unique name (not visible on webpage) - required" +msgstr "" + +#: ../../mod/menu.php:90 ../../mod/menu.php:102 +msgid "Menu Title" +msgstr "" + +#: ../../mod/menu.php:90 +msgid "Visible on webpage - leave empty for no title" +msgstr "" + +#: ../../mod/menu.php:91 +msgid "Allow Bookmarks" +msgstr "" + +#: ../../mod/menu.php:91 ../../mod/menu.php:143 +msgid "Menu may be used to store saved bookmarks" +msgstr "" + +#: ../../mod/menu.php:92 +msgid "Submit and proceed" +msgstr "" + +#: ../../mod/menu.php:104 +msgid "Drop" +msgstr "" + +#: ../../mod/menu.php:106 +msgid "Bookmarks allowed" +msgstr "" + +#: ../../mod/menu.php:108 +msgid "Delete this menu" +msgstr "" + +#: ../../mod/menu.php:109 ../../mod/menu.php:140 +msgid "Edit menu contents" +msgstr "" + +#: ../../mod/menu.php:110 +msgid "Edit this menu" +msgstr "" + +#: ../../mod/menu.php:124 +msgid "Menu could not be deleted." +msgstr "" + +#: ../../mod/menu.php:132 ../../mod/mitem.php:24 +msgid "Menu not found." +msgstr "" + +#: ../../mod/menu.php:137 +msgid "Edit Menu" +msgstr "" + +#: ../../mod/menu.php:139 +msgid "Add or remove entries to this menu" +msgstr "" + +#: ../../mod/menu.php:141 +msgid "Menu name" +msgstr "" + +#: ../../mod/menu.php:141 +msgid "Must be unique, only seen by you" +msgstr "" + +#: ../../mod/menu.php:142 +msgid "Menu title" +msgstr "" + +#: ../../mod/menu.php:142 +msgid "Menu title as seen by others" +msgstr "" + +#: ../../mod/menu.php:143 +msgid "Allow bookmarks" +msgstr "" + +#: ../../mod/menu.php:145 +msgid "Modify" +msgstr "" + +#: ../../mod/filestorage.php:82 +msgid "Permission Denied." +msgstr "" + +#: ../../mod/filestorage.php:98 +msgid "File not found." +msgstr "" + +#: ../../mod/filestorage.php:141 +msgid "Edit file permissions" +msgstr "" + +#: ../../mod/filestorage.php:150 +msgid "Set/edit permissions" +msgstr "" + +#: ../../mod/filestorage.php:151 +msgid "Include all files and sub folders" +msgstr "" + +#: ../../mod/filestorage.php:152 +msgid "Return to file list" +msgstr "" + +#: ../../mod/filestorage.php:154 +msgid "Copy/paste this code to attach file to a post" +msgstr "" + +#: ../../mod/filestorage.php:155 +msgid "Copy/paste this URL to link file from a web page" +msgstr "" + +#: ../../mod/filestorage.php:157 +msgid "Share this file" +msgstr "" + +#: ../../mod/filestorage.php:158 +msgid "Show URL to this file" +msgstr "" + +#: ../../mod/filestorage.php:159 +msgid "Notify your contacts about this file" +msgstr "" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "" + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "" + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "" + +#: ../../mod/magic.php:69 +msgid "Hub not found." +msgstr "" + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "" + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "" + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "" + +#: ../../mod/impel.php:54 +msgid "menu" +msgstr "" + +#: ../../mod/impel.php:186 +#, php-format +msgid "%s element installed" +msgstr "" + +#: ../../mod/impel.php:189 +#, php-format +msgid "%s element installation failed" +msgstr "" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:174 +#: ../../mod/profiles.php:231 ../../mod/profiles.php:600 +msgid "Profile not found." +msgstr "" + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "" + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "" + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "" + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "" + +#: ../../mod/profiles.php:241 +msgid "Profile Name is required." +msgstr "" + +#: ../../mod/profiles.php:404 +msgid "Marital Status" +msgstr "" + +#: ../../mod/profiles.php:408 +msgid "Romantic Partner" +msgstr "" + +#: ../../mod/profiles.php:412 +msgid "Likes" +msgstr "" + +#: ../../mod/profiles.php:416 +msgid "Dislikes" +msgstr "" + +#: ../../mod/profiles.php:420 +msgid "Work/Employment" +msgstr "" + +#: ../../mod/profiles.php:423 +msgid "Religion" +msgstr "" + +#: ../../mod/profiles.php:427 +msgid "Political Views" +msgstr "" + +#: ../../mod/profiles.php:431 ../../mod/id.php:33 +msgid "Gender" +msgstr "" + +#: ../../mod/profiles.php:435 +msgid "Sexual Preference" +msgstr "" + +#: ../../mod/profiles.php:439 +msgid "Homepage" +msgstr "" + +#: ../../mod/profiles.php:443 +msgid "Interests" +msgstr "" + +#: ../../mod/profiles.php:447 ../../mod/admin.php:985 +msgid "Address" +msgstr "" + +#: ../../mod/profiles.php:537 +msgid "Profile updated." +msgstr "" + +#: ../../mod/profiles.php:626 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "" + +#: ../../mod/profiles.php:666 +msgid "Edit Profile Details" +msgstr "" + +#: ../../mod/profiles.php:668 +msgid "View this profile" +msgstr "" + +#: ../../mod/profiles.php:670 +msgid "Change Profile Photo" +msgstr "" + +#: ../../mod/profiles.php:671 +msgid "Create a new profile using these settings" +msgstr "" + +#: ../../mod/profiles.php:672 +msgid "Clone this profile" +msgstr "" + +#: ../../mod/profiles.php:673 +msgid "Delete this profile" +msgstr "" + +#: ../../mod/profiles.php:675 +msgid "Import profile from file" +msgstr "" + +#: ../../mod/profiles.php:676 +msgid "Export profile to file" +msgstr "" + +#: ../../mod/profiles.php:677 +msgid "Profile Name:" +msgstr "" + +#: ../../mod/profiles.php:678 +msgid "Your Full Name:" +msgstr "" + +#: ../../mod/profiles.php:679 +msgid "Title/Description:" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/profiles.php:680 +msgid "Your Gender:" +======= +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "" + +#: ../../mod/uexport.php:33 ../../mod/uexport.php:34 +msgid "Export Channel" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/profiles.php:681 +msgid "Birthday :" +msgstr "" + +#: ../../mod/profiles.php:682 +msgid "Street Address:" +msgstr "" + +#: ../../mod/profiles.php:683 +msgid "Locality/City:" +msgstr "" + +#: ../../mod/profiles.php:684 +msgid "Postal/Zip Code:" +msgstr "" + +#: ../../mod/profiles.php:685 +msgid "Country:" +msgstr "" + +#: ../../mod/profiles.php:686 +msgid "Region/State:" +msgstr "" + +#: ../../mod/profiles.php:687 +msgid " Marital Status:" +msgstr "" + +#: ../../mod/profiles.php:688 +msgid "Who: (if applicable)" +msgstr "" + +#: ../../mod/profiles.php:689 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "" + +#: ../../mod/profiles.php:690 +msgid "Since [date]:" +msgstr "" + +#: ../../mod/profiles.php:692 +msgid "Homepage URL:" +msgstr "" + +#: ../../mod/profiles.php:695 +msgid "Religious Views:" +msgstr "" + +#: ../../mod/profiles.php:696 +msgid "Keywords:" +msgstr "" + +#: ../../mod/profiles.php:699 +msgid "Example: fishing photography software" +msgstr "" + +#: ../../mod/profiles.php:700 +msgid "Used in directory listings" +msgstr "" + +#: ../../mod/profiles.php:701 +msgid "Tell us about yourself..." +msgstr "" + +#: ../../mod/profiles.php:702 +msgid "Hobbies/Interests" +msgstr "" + +#: ../../mod/profiles.php:703 +msgid "Contact information and Social Networks" +msgstr "" + +#: ../../mod/profiles.php:704 +msgid "My other channels" +msgstr "" + +#: ../../mod/profiles.php:705 +msgid "Musical interests" +msgstr "" + +#: ../../mod/profiles.php:706 +msgid "Books, literature" +msgstr "" + +#: ../../mod/profiles.php:707 +msgid "Television" +msgstr "" + +#: ../../mod/profiles.php:708 +msgid "Film/dance/culture/entertainment" +msgstr "" + +#: ../../mod/profiles.php:709 +msgid "Love/romance" +msgstr "" + +#: ../../mod/profiles.php:710 +msgid "Work/employment" +msgstr "" + +#: ../../mod/profiles.php:711 +msgid "School/education" +msgstr "" + +#: ../../mod/profiles.php:717 +msgid "This is your default profile." +msgstr "" + +#: ../../mod/profiles.php:728 ../../mod/directory.php:218 +msgid "Age: " +msgstr "" + +#: ../../mod/profiles.php:771 +msgid "Edit/Manage Profiles" +msgstr "" + +#: ../../mod/profiles.php:772 +msgid "Add profile things" +msgstr "" + +#: ../../mod/profiles.php:773 +msgid "Include desirable objects in your profile" +msgstr "" + +#: ../../mod/ratings.php:69 +msgid "No ratings" +msgstr "" + +#: ../../mod/ratings.php:99 +msgid "Ratings" +msgstr "" + +#: ../../mod/ratings.php:100 +msgid "Rating: " +msgstr "" + +#: ../../mod/ratings.php:101 +msgid "Website: " +msgstr "" + +#: ../../mod/ratings.php:103 +msgid "Description: " +msgstr "" + +#: ../../mod/viewsrc.php:38 +msgid "Source of Item" +msgstr "" + +#: ../../mod/setup.php:187 +msgid "$Projectname Server - Setup" +msgstr "" + +#: ../../mod/setup.php:191 +msgid "Could not connect to database." +msgstr "" + +#: ../../mod/setup.php:195 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "" + +#: ../../mod/setup.php:202 +msgid "Could not create table." +msgstr "" + +#: ../../mod/setup.php:207 +msgid "Your site database has been installed." +msgstr "" + +#: ../../mod/setup.php:211 +msgid "" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." +msgstr "" + +#: ../../mod/setup.php:212 ../../mod/setup.php:280 ../../mod/setup.php:730 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "" + +#: ../../mod/setup.php:277 +msgid "System check" +msgstr "" + +#: ../../mod/setup.php:282 +msgid "Check again" +msgstr "" + +#: ../../mod/setup.php:304 +msgid "Database connection" +msgstr "" + +#: ../../mod/setup.php:305 +msgid "" +"In order to install $Projectname we need to know how to connect to your " +"database." +msgstr "" + +#: ../../mod/setup.php:306 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "" + +#: ../../mod/setup.php:307 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "" + +#: ../../mod/setup.php:311 +msgid "Database Server Name" +msgstr "" + +#: ../../mod/setup.php:311 +msgid "Default is localhost" +msgstr "" + +#: ../../mod/setup.php:312 +msgid "Database Port" +msgstr "" + +#: ../../mod/setup.php:312 +msgid "Communication port number - use 0 for default" +msgstr "" + +#: ../../mod/setup.php:313 +msgid "Database Login Name" +msgstr "" + +#: ../../mod/setup.php:314 +msgid "Database Login Password" +msgstr "" + +#: ../../mod/setup.php:315 +msgid "Database Name" +msgstr "" + +#: ../../mod/setup.php:316 +msgid "Database Type" +msgstr "" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "Site administrator email address" +msgstr "" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "" + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Website URL" +msgstr "" + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Please use SSL (https) URL if available." +msgstr "" + +#: ../../mod/setup.php:321 ../../mod/setup.php:363 +msgid "Please select a default timezone for your website" +msgstr "" + +#: ../../mod/setup.php:348 +msgid "Site settings" +msgstr "" + +#: ../../mod/setup.php:413 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "" + +#: ../../mod/setup.php:414 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "" + +#: ../../mod/setup.php:418 +msgid "PHP executable path" +msgstr "" + +#: ../../mod/setup.php:418 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "" + +#: ../../mod/setup.php:423 +msgid "Command line PHP" +msgstr "" + +#: ../../mod/setup.php:432 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "" + +#: ../../mod/setup.php:433 +msgid "This is required for message delivery to work." +msgstr "" + +#: ../../mod/setup.php:436 +msgid "PHP register_argc_argv" +msgstr "" + +#: ../../mod/setup.php:454 +#, php-format +msgid "" +"Your max allowed total upload size is set to %s. Maximum size of one file to " +"upload is set to %s. You are allowed to upload up to %d files at once." +msgstr "" + +#: ../../mod/setup.php:459 +msgid "You can adjust these settings in the servers php.ini." +msgstr "" + +#: ../../mod/setup.php:461 +msgid "PHP upload limits" +msgstr "" + +#: ../../mod/setup.php:484 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "" + +#: ../../mod/setup.php:485 +msgid "" +"If running under Windows, please see \"http://www.php.net/manual/en/openssl." +"installation.php\"." +msgstr "" + +#: ../../mod/setup.php:488 +msgid "Generate encryption keys" +msgstr "" + +#: ../../mod/setup.php:500 +msgid "libCurl PHP module" +msgstr "" + +#: ../../mod/setup.php:501 +msgid "GD graphics PHP module" +msgstr "" + +#: ../../mod/setup.php:502 +msgid "OpenSSL PHP module" +msgstr "" + +#: ../../mod/setup.php:503 +msgid "mysqli or postgres PHP module" +msgstr "" + +#: ../../mod/setup.php:504 +msgid "mb_string PHP module" +msgstr "" + +#: ../../mod/setup.php:505 +msgid "mcrypt PHP module" +msgstr "" + +#: ../../mod/setup.php:506 +msgid "xml PHP module" +msgstr "" + +#: ../../mod/setup.php:510 ../../mod/setup.php:512 +msgid "Apache mod_rewrite module" +msgstr "" + +#: ../../mod/setup.php:510 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "" + +#: ../../mod/setup.php:516 ../../mod/setup.php:519 +msgid "proc_open" +msgstr "" + +#: ../../mod/setup.php:516 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "" + +#: ../../mod/setup.php:524 +msgid "Error: libCURL PHP module required but not installed." +msgstr "" + +#: ../../mod/setup.php:528 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "" + +#: ../../mod/setup.php:532 +msgid "Error: openssl PHP module required but not installed." +msgstr "" + +#: ../../mod/setup.php:536 +msgid "" +"Error: mysqli or postgres PHP module required but neither are installed." +msgstr "" + +#: ../../mod/setup.php:540 +msgid "Error: mb_string PHP module required but not installed." +msgstr "" + +#: ../../mod/setup.php:544 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "" + +#: ../../mod/setup.php:548 +msgid "Error: xml PHP module required for DAV but not installed." +msgstr "" + +#: ../../mod/setup.php:566 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\" " +"in the top folder of your web server and it is unable to do so." +msgstr "" + +#: ../../mod/setup.php:567 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "" + +#: ../../mod/setup.php:568 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "" + +#: ../../mod/setup.php:569 +msgid "" +"You can alternatively skip this procedure and perform a manual installation. " +"Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "" + +#: ../../mod/setup.php:572 +msgid ".htconfig.php is writable" +msgstr "" + +#: ../../mod/setup.php:586 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "" + +#: ../../mod/setup.php:587 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "" + +#: ../../mod/setup.php:588 ../../mod/setup.php:609 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has " +"write access to this folder." +msgstr "" + +#: ../../mod/setup.php:589 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "" + +#: ../../mod/setup.php:592 +#, php-format +msgid "%s is writable" +msgstr "" + +#: ../../mod/setup.php:608 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to " +"have write access to the store directory under the Red top level folder" +msgstr "" + +#: ../../mod/setup.php:612 +msgid "store is writable" +msgstr "" + +#: ../../mod/setup.php:645 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access " +"to this site." +msgstr "" + +#: ../../mod/setup.php:646 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "" + +#: ../../mod/setup.php:647 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "" + +#: ../../mod/setup.php:648 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "" + +#: ../../mod/setup.php:649 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "" + +#: ../../mod/setup.php:650 +msgid "" +"Providers are available that issue free certificates which are browser-valid." +msgstr "" + +#: ../../mod/setup.php:652 +msgid "SSL certificate validation" +msgstr "" + +#: ../../mod/setup.php:658 +msgid "" +"Url rewrite in .htaccess is not working. Check your server configuration." +"Test: " +msgstr "" + +#: ../../mod/setup.php:661 +msgid "Url rewrite is working" +msgstr "" + +#: ../../mod/setup.php:670 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "" + +#: ../../mod/setup.php:694 +msgid "Errors encountered creating database tables." +msgstr "" + +#: ../../mod/setup.php:728 +msgid "

    What next

    " +msgstr "" + +#: ../../mod/setup.php:729 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the poller." +msgstr "" + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "" + +#: ../../mod/openid.php:72 ../../mod/openid.php:180 ../../mod/post.php:286 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "" + +#: ../../mod/directory.php:224 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/directory.php:236 +msgid "Gender: " +msgstr "" + +#: ../../mod/directory.php:238 +msgid "Status: " +msgstr "" + +#: ../../mod/directory.php:240 +msgid "Homepage: " +msgstr "" + +#: ../../mod/directory.php:243 +msgid "Hometown: " +msgstr "" + +#: ../../mod/directory.php:245 +msgid "About: " +msgstr "" + +#: ../../mod/directory.php:303 +msgid "Public Forum:" +msgstr "" + +<<<<<<< HEAD +#: ../../mod/directory.php:306 +msgid "Keywords: " +msgstr "" + +#: ../../mod/directory.php:311 +#, php-format +msgid "Common connections: %s" +======= +#: ../../mod/admin.php:827 ../../mod/connedit.php:523 +#: ../../mod/connedit.php:729 +msgid "Block" +msgstr "" + +#: ../../mod/admin.php:828 ../../mod/connedit.php:523 +#: ../../mod/connedit.php:729 +msgid "Unblock" +>>>>>>> cbfb94c55cc422359f1cef3c6fe89d86f131a104 +msgstr "" + +#: ../../mod/directory.php:363 +msgid "Finding:" +msgstr "" + +#: ../../mod/directory.php:368 +msgid "next page" +msgstr "" + +#: ../../mod/directory.php:368 +msgid "previous page" +msgstr "" + +#: ../../mod/directory.php:385 +msgid "No entries (some entries may be hidden)." +msgstr "" + +#: ../../mod/uexport.php:33 ../../mod/uexport.php:34 +msgid "Export Channel" +msgstr "" + +#: ../../mod/uexport.php:35 +msgid "" +"Export your basic channel information to a small file. This acts as a " +"backup of your connections, permissions, profile and basic data, which can " +"be used to import your data to a new hub, but\tdoes not contain your content." +msgstr "" + +#: ../../mod/uexport.php:36 +msgid "Export Content" +msgstr "" + +#: ../../mod/uexport.php:37 +msgid "" +"Export your channel information and all the content to a JSON backup. This " +"backs up all of your connections, permissions, profile data and all of your " +"content, but is generally not suitable for importing a channel to a new hub " +"as this file may be VERY large. Please be patient - it may take several " +"minutes for this download to begin." +msgstr "" + +#: ../../mod/viewconnections.php:62 +msgid "No connections." +msgstr "" + +#: ../../mod/viewconnections.php:75 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "" + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "" + +#: ../../mod/admin.php:93 ../../mod/admin.php:445 +msgid "Site" +msgstr "" + +#: ../../mod/admin.php:94 +msgid "Accounts" +msgstr "" + +#: ../../mod/admin.php:95 ../../mod/admin.php:976 +msgid "Channels" +msgstr "" + +#: ../../mod/admin.php:96 ../../mod/admin.php:1068 ../../mod/admin.php:1108 +msgid "Plugins" +msgstr "" + +#: ../../mod/admin.php:97 ../../mod/admin.php:1268 ../../mod/admin.php:1302 +msgid "Themes" +msgstr "" + +#: ../../mod/admin.php:98 +msgid "Inspect queue" +msgstr "" + +#: ../../mod/admin.php:100 +msgid "Profile Config" +msgstr "" + +#: ../../mod/admin.php:101 +msgid "DB updates" +msgstr "" + +#: ../../mod/admin.php:115 ../../mod/admin.php:122 ../../mod/admin.php:1387 +msgid "Logs" +msgstr "" + +#: ../../mod/admin.php:121 +msgid "Plugin Features" +msgstr "" + +#: ../../mod/admin.php:123 +msgid "User registrations waiting for confirmation" +msgstr "" + +#: ../../mod/admin.php:200 +msgid "# Accounts" +msgstr "" + +#: ../../mod/admin.php:201 +msgid "# blocked accounts" +msgstr "" + +#: ../../mod/admin.php:202 +msgid "# expired accounts" +msgstr "" + +#: ../../mod/admin.php:203 +msgid "# expiring accounts" +msgstr "" + +#: ../../mod/admin.php:216 +msgid "# Channels" +msgstr "" + +#: ../../mod/admin.php:217 +msgid "# primary" +msgstr "" + +#: ../../mod/admin.php:218 +msgid "# clones" +msgstr "" + +#: ../../mod/admin.php:224 +msgid "Message queues" +msgstr "" + +#: ../../mod/admin.php:240 ../../mod/admin.php:444 ../../mod/admin.php:539 +#: ../../mod/admin.php:808 ../../mod/admin.php:975 ../../mod/admin.php:1067 +#: ../../mod/admin.php:1107 ../../mod/admin.php:1267 ../../mod/admin.php:1301 +#: ../../mod/admin.php:1386 +msgid "Administration" +msgstr "" + +#: ../../mod/admin.php:241 +msgid "Summary" +msgstr "" + +#: ../../mod/admin.php:244 +msgid "Registered accounts" +msgstr "" + +#: ../../mod/admin.php:245 ../../mod/admin.php:543 +msgid "Pending registrations" +msgstr "" + +#: ../../mod/admin.php:246 +msgid "Registered channels" +msgstr "" + +#: ../../mod/admin.php:247 ../../mod/admin.php:544 +msgid "Active plugins" +msgstr "" + +#: ../../mod/admin.php:248 +msgid "Version" +msgstr "" + +#: ../../mod/admin.php:359 +msgid "Site settings updated." +msgstr "" + +#: ../../mod/admin.php:398 +msgid "experimental" +msgstr "" + +#: ../../mod/admin.php:400 +msgid "unsupported" +msgstr "" + +#: ../../mod/admin.php:425 +msgid "Yes - with approval" +msgstr "" + +#: ../../mod/admin.php:431 +msgid "My site is not a public server" +msgstr "" + +#: ../../mod/admin.php:432 +msgid "My site has paid access only" +msgstr "" + +#: ../../mod/admin.php:433 +msgid "My site has free access only" +msgstr "" + +#: ../../mod/admin.php:434 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "" + +#: ../../mod/admin.php:447 ../../mod/register.php:207 +msgid "Registration" +msgstr "" + +#: ../../mod/admin.php:448 +msgid "File upload" +msgstr "" + +#: ../../mod/admin.php:449 +msgid "Policies" +msgstr "" + +#: ../../mod/admin.php:454 +msgid "Site name" +msgstr "" + +#: ../../mod/admin.php:455 +msgid "Banner/Logo" +msgstr "" + +#: ../../mod/admin.php:456 +msgid "Administrator Information" +msgstr "" + +#: ../../mod/admin.php:456 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "" + +#: ../../mod/admin.php:457 +msgid "System language" +msgstr "" + +#: ../../mod/admin.php:458 +msgid "System theme" +msgstr "" + +#: ../../mod/admin.php:458 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "" + +#: ../../mod/admin.php:459 +msgid "Mobile system theme" +msgstr "" + +#: ../../mod/admin.php:459 +msgid "Theme for mobile devices" +msgstr "" + +#: ../../mod/admin.php:461 +msgid "Enable Diaspora Protocol" +msgstr "" + +#: ../../mod/admin.php:461 +msgid "Communicate with Diaspora and Friendica - experimental" +msgstr "" + +#: ../../mod/admin.php:462 +msgid "Allow Feeds as Connections" +msgstr "" + +#: ../../mod/admin.php:462 +msgid "(Heavy system resource usage)" +msgstr "" + +#: ../../mod/admin.php:463 +msgid "Maximum image size" +msgstr "" + +#: ../../mod/admin.php:463 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "" + +#: ../../mod/admin.php:464 +msgid "Does this site allow new member registration?" +msgstr "" + +#: ../../mod/admin.php:465 +msgid "Which best describes the types of account offered by this hub?" +msgstr "" + +#: ../../mod/admin.php:466 +msgid "Register text" +msgstr "" + +#: ../../mod/admin.php:466 +msgid "Will be displayed prominently on the registration page." +msgstr "" + +#: ../../mod/admin.php:467 +msgid "Accounts abandoned after x days" +msgstr "" + +#: ../../mod/admin.php:467 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "" + +#: ../../mod/admin.php:468 +msgid "Allowed friend domains" +msgstr "" + +#: ../../mod/admin.php:468 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "" + +#: ../../mod/admin.php:469 +msgid "Allowed email domains" +msgstr "" + +#: ../../mod/admin.php:469 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "" + +#: ../../mod/admin.php:470 +msgid "Not allowed email domains" +msgstr "" + +#: ../../mod/admin.php:470 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "" + +#: ../../mod/admin.php:471 +msgid "Block public" +msgstr "" + +#: ../../mod/admin.php:471 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "" + +#: ../../mod/admin.php:472 +msgid "Verify Email Addresses" +msgstr "" + +#: ../../mod/admin.php:472 +msgid "" +"Check to verify email addresses used in account registration (recommended)." +msgstr "" + +#: ../../mod/admin.php:473 +msgid "Force publish" +msgstr "" + +#: ../../mod/admin.php:473 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "" + +#: ../../mod/admin.php:474 +msgid "Disable discovery tab" +msgstr "" + +#: ../../mod/admin.php:474 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "" + +#: ../../mod/admin.php:475 +msgid "No login on Homepage" +msgstr "" + +#: ../../mod/admin.php:475 +msgid "" +"Check to hide the login form from your sites homepage when visitors arrive " +"who are not logged in (e.g. when you put the content of the homepage in via " +"the site channel)." +msgstr "" + +#: ../../mod/admin.php:477 +msgid "Proxy user" +msgstr "" + +#: ../../mod/admin.php:478 +msgid "Proxy URL" +msgstr "" + +#: ../../mod/admin.php:479 +msgid "Network timeout" +msgstr "" + +#: ../../mod/admin.php:479 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "" + +#: ../../mod/admin.php:480 +msgid "Delivery interval" +msgstr "" + +#: ../../mod/admin.php:480 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "" + +#: ../../mod/admin.php:481 +msgid "Poll interval" +msgstr "" + +#: ../../mod/admin.php:481 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "" + +#: ../../mod/admin.php:482 +msgid "Maximum Load Average" +msgstr "" + +#: ../../mod/admin.php:482 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "" + +#: ../../mod/admin.php:483 +msgid "Expiration period in days for imported (matrix/network) content" +msgstr "" + +#: ../../mod/admin.php:483 +msgid "0 for no expiration of imported content" +msgstr "" + +#: ../../mod/admin.php:531 +msgid "No server found" +msgstr "" + +#: ../../mod/admin.php:538 ../../mod/admin.php:822 +msgid "ID" +msgstr "" + +#: ../../mod/admin.php:538 +msgid "for channel" +msgstr "" + +#: ../../mod/admin.php:538 +msgid "on server" +msgstr "" + +#: ../../mod/admin.php:538 +msgid "Status" +msgstr "" + +#: ../../mod/admin.php:540 +msgid "Server" +msgstr "" + +#: ../../mod/admin.php:557 +msgid "Update has been marked successful" +msgstr "" + +#: ../../mod/admin.php:567 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "" + +#: ../../mod/admin.php:570 +#, php-format +msgid "Update %s was successfully applied." +msgstr "" + +#: ../../mod/admin.php:574 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "" + +#: ../../mod/admin.php:577 +#, php-format +msgid "Update function %s could not be found." +msgstr "" + +#: ../../mod/admin.php:593 +msgid "No failed updates." +msgstr "" + +#: ../../mod/admin.php:597 +msgid "Failed Updates" +msgstr "" + +#: ../../mod/admin.php:599 +msgid "Mark success (if update was manually applied)" +msgstr "" + +#: ../../mod/admin.php:600 +msgid "Attempt to execute this update step automatically" +msgstr "" + +#: ../../mod/admin.php:632 +msgid "Queue Statistics" +msgstr "" + +#: ../../mod/admin.php:633 +msgid "Total Entries" +msgstr "" + +#: ../../mod/admin.php:634 +msgid "Priority" +msgstr "" + +#: ../../mod/admin.php:635 +msgid "Destination URL" +msgstr "" + +#: ../../mod/admin.php:636 +msgid "Mark hub permanently offline" +msgstr "" + +#: ../../mod/admin.php:637 +msgid "Empty queue for this hub" +msgstr "" + +#: ../../mod/admin.php:638 +msgid "Last known contact" +msgstr "" + +#: ../../mod/admin.php:674 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/admin.php:682 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/admin.php:718 +msgid "Account not found" +msgstr "" + +#: ../../mod/admin.php:738 +#, php-format +msgid "User '%s' blocked" +msgstr "" + +#: ../../mod/admin.php:746 +#, php-format +msgid "User '%s' unblocked" +msgstr "" + +#: ../../mod/admin.php:809 ../../mod/admin.php:821 +msgid "Users" +msgstr "" + +#: ../../mod/admin.php:811 ../../mod/admin.php:978 +msgid "select all" +msgstr "" + +#: ../../mod/admin.php:812 +msgid "User registrations waiting for confirm" +msgstr "" + +#: ../../mod/admin.php:813 +msgid "Request date" +msgstr "" + +#: ../../mod/admin.php:814 +msgid "No registrations." +msgstr "" + +#: ../../mod/admin.php:815 +msgid "Approve" +msgstr "" + +#: ../../mod/admin.php:816 +msgid "Deny" +msgstr "" + +#: ../../mod/admin.php:818 ../../mod/connedit.php:517 +#: ../../mod/connedit.php:720 +msgid "Block" +msgstr "" + +#: ../../mod/admin.php:819 ../../mod/connedit.php:517 +#: ../../mod/connedit.php:720 +msgid "Unblock" +msgstr "" + +#: ../../mod/admin.php:822 +msgid "Register date" +msgstr "" + +#: ../../mod/admin.php:822 +msgid "Last login" +msgstr "" + +#: ../../mod/admin.php:822 +msgid "Expires" +msgstr "" + +#: ../../mod/admin.php:822 +msgid "Service Class" +msgstr "" + +#: ../../mod/admin.php:824 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: ../../mod/admin.php:825 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: ../../mod/admin.php:861 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channels censored/uncensored" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/admin.php:870 +#, php-format +msgid "%s channel code allowed/disallowed" +msgid_plural "%s channels code allowed/disallowed" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/admin.php:877 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "" +msgstr[1] "" + +#: ../../mod/admin.php:897 +msgid "Channel not found" +msgstr "" + +#: ../../mod/admin.php:908 +#, php-format +msgid "Channel '%s' deleted" +msgstr "" + +#: ../../mod/admin.php:920 +#, php-format +msgid "Channel '%s' censored" +msgstr "" + +#: ../../mod/admin.php:920 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "" + +#: ../../mod/admin.php:931 +#, php-format +msgid "Channel '%s' code allowed" +msgstr "" + +#: ../../mod/admin.php:931 +#, php-format +msgid "Channel '%s' code disallowed" +msgstr "" + +#: ../../mod/admin.php:980 +msgid "Censor" +msgstr "" + +#: ../../mod/admin.php:981 +msgid "Uncensor" +msgstr "" + +#: ../../mod/admin.php:982 +msgid "Allow Code" +msgstr "" + +#: ../../mod/admin.php:983 +msgid "Disallow Code" +msgstr "" + +#: ../../mod/admin.php:985 +msgid "UID" +msgstr "" + +#: ../../mod/admin.php:987 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: ../../mod/admin.php:988 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" + +#: ../../mod/admin.php:1028 +#, php-format +msgid "Plugin %s disabled." +msgstr "" + +#: ../../mod/admin.php:1032 +#, php-format +msgid "Plugin %s enabled." +msgstr "" + +#: ../../mod/admin.php:1042 ../../mod/admin.php:1240 +msgid "Disable" +msgstr "" + +#: ../../mod/admin.php:1045 ../../mod/admin.php:1242 +msgid "Enable" +msgstr "" + +#: ../../mod/admin.php:1069 ../../mod/admin.php:1269 +msgid "Toggle" +msgstr "" + +#: ../../mod/admin.php:1077 ../../mod/admin.php:1279 +msgid "Author: " +msgstr "" + +#: ../../mod/admin.php:1078 ../../mod/admin.php:1280 +msgid "Maintainer: " +msgstr "" + +#: ../../mod/admin.php:1205 +msgid "No themes found." +msgstr "" + +#: ../../mod/admin.php:1261 +msgid "Screenshot" +msgstr "" + +#: ../../mod/admin.php:1307 +msgid "[Experimental]" +msgstr "" + +#: ../../mod/admin.php:1308 +msgid "[Unsupported]" +msgstr "" + +#: ../../mod/admin.php:1332 +msgid "Log settings updated." +msgstr "" + +#: ../../mod/admin.php:1389 +msgid "Clear" +msgstr "" + +#: ../../mod/admin.php:1395 +msgid "Debugging" +msgstr "" + +#: ../../mod/admin.php:1396 +msgid "Log file" +msgstr "" + +#: ../../mod/admin.php:1396 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "" + +#: ../../mod/admin.php:1397 +msgid "Log level" +msgstr "" + +#: ../../mod/admin.php:1443 +msgid "New Profile Field" +msgstr "" + +#: ../../mod/admin.php:1444 ../../mod/admin.php:1464 +msgid "Field nickname" +msgstr "" + +#: ../../mod/admin.php:1444 ../../mod/admin.php:1464 +msgid "System name of field" +msgstr "" + +#: ../../mod/admin.php:1445 ../../mod/admin.php:1465 +msgid "Input type" +msgstr "" + +#: ../../mod/admin.php:1446 ../../mod/admin.php:1466 +msgid "Field Name" +msgstr "" + +#: ../../mod/admin.php:1446 ../../mod/admin.php:1466 +msgid "Label on profile pages" +msgstr "" + +#: ../../mod/admin.php:1447 ../../mod/admin.php:1467 +msgid "Help text" +msgstr "" + +#: ../../mod/admin.php:1447 ../../mod/admin.php:1467 +msgid "Additional info (optional)" +msgstr "" + +#: ../../mod/admin.php:1457 +msgid "Field definition not found" +msgstr "" + +#: ../../mod/admin.php:1463 +msgid "Edit Profile Field" +msgstr "" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "" + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "" + +#: ../../mod/editblock.php:112 +msgid "Edit Block" +msgstr "" + +#: ../../mod/editblock.php:123 +msgid "Delete block?" +msgstr "" + +#: ../../mod/register.php:44 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "" + +#: ../../mod/register.php:50 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "" + +#: ../../mod/register.php:84 +msgid "Passwords do not match." +msgstr "" + +#: ../../mod/register.php:117 +msgid "" +"Registration successful. Please check your email for validation instructions." +msgstr "" + +#: ../../mod/register.php:123 +msgid "Your registration is pending approval by the site owner." +msgstr "" + +#: ../../mod/register.php:126 +msgid "Your registration can not be processed." +msgstr "" + +#: ../../mod/register.php:163 +msgid "Registration on this site/hub is by approval only." +msgstr "" + +#: ../../mod/register.php:164 +msgid "Register at another affiliated site/hub" +msgstr "" + +#: ../../mod/register.php:174 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "" + +#: ../../mod/register.php:185 +msgid "Terms of Service" +msgstr "" + +#: ../../mod/register.php:191 +#, php-format +msgid "I accept the %s for this website" +msgstr "" + +#: ../../mod/register.php:193 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "" + +#: ../../mod/register.php:212 +msgid "Membership on this site is by invitation only." +msgstr "" + +#: ../../mod/register.php:213 +msgid "Please enter your invitation code" +msgstr "" + +#: ../../mod/register.php:216 +msgid "Your email address" +msgstr "" + +#: ../../mod/register.php:217 +msgid "Choose a password" +msgstr "" + +#: ../../mod/register.php:218 +msgid "Please re-enter your password" +msgstr "" + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "" + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "" + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "WARNING: " +msgstr "" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This account and all its channels will be completely removed from the " +"network. " +msgstr "" + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "This action is permanent and can not be undone!" +msgstr "" + +#: ../../mod/removeaccount.php:59 ../../mod/removeme.php:59 +msgid "Please enter your password for verification:" +msgstr "" + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "" + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "" + +#: ../../mod/item.php:174 +msgid "Unable to locate original post." +msgstr "" + +#: ../../mod/item.php:440 +msgid "Empty post discarded." +msgstr "" + +#: ../../mod/item.php:480 +msgid "Executable content type not permitted to this channel." +msgstr "" + +#: ../../mod/item.php:897 +msgid "System error. Post not saved." +msgstr "" + +#: ../../mod/item.php:1115 +msgid "Unable to obtain post information from database." +msgstr "" + +#: ../../mod/item.php:1122 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "" + +#: ../../mod/item.php:1129 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "" + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +#: ../../mod/update_home.php:21 +msgid "[Embedded content - reload page to view]" +msgstr "" + +#: ../../mod/lockview.php:37 +msgid "Remote privacy information not available." +msgstr "" + +#: ../../mod/lockview.php:58 +msgid "Visible to:" +msgstr "" + +#: ../../mod/layouts.php:176 +msgid "Comanche page description language help" +msgstr "" + +#: ../../mod/layouts.php:180 +msgid "Layout Description" +msgstr "" + +#: ../../mod/layouts.php:185 +msgid "Download PDL file" +msgstr "" + +#: ../../mod/id.php:11 +msgid "First Name" +msgstr "" + +#: ../../mod/id.php:12 +msgid "Last Name" +msgstr "" + +#: ../../mod/id.php:13 +msgid "Nickname" +msgstr "" + +#: ../../mod/id.php:14 +msgid "Full Name" +msgstr "" + +#: ../../mod/id.php:20 +msgid "Profile Photo 16px" +msgstr "" + +#: ../../mod/id.php:21 +msgid "Profile Photo 32px" +msgstr "" + +#: ../../mod/id.php:22 +msgid "Profile Photo 48px" +msgstr "" + +#: ../../mod/id.php:23 +msgid "Profile Photo 64px" +msgstr "" + +#: ../../mod/id.php:24 +msgid "Profile Photo 80px" +msgstr "" + +#: ../../mod/id.php:25 +msgid "Profile Photo 128px" +msgstr "" + +#: ../../mod/id.php:26 +msgid "Timezone" +msgstr "" + +#: ../../mod/id.php:27 +msgid "Homepage URL" +msgstr "" + +#: ../../mod/id.php:29 +msgid "Birth Year" +msgstr "" + +#: ../../mod/id.php:30 +msgid "Birth Month" +msgstr "" + +#: ../../mod/id.php:31 +msgid "Birth Day" +msgstr "" + +#: ../../mod/id.php:32 +msgid "Birthdate" +msgstr "" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "" + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "" + +#: ../../mod/message.php:72 ../../mod/mail.php:336 +msgid "Delete conversation" +msgstr "" + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "" + +#: ../../mod/mitem.php:51 +msgid "Unable to create element." +msgstr "" + +#: ../../mod/mitem.php:74 +msgid "Unable to update menu element." +msgstr "" + +#: ../../mod/mitem.php:89 +msgid "Unable to add menu element." +msgstr "" + +#: ../../mod/mitem.php:158 ../../mod/mitem.php:228 +msgid "Menu Item Permissions" +msgstr "" + +#: ../../mod/mitem.php:161 ../../mod/mitem.php:176 +msgid "Link Name" +msgstr "" + +#: ../../mod/mitem.php:162 ../../mod/mitem.php:233 +msgid "Link or Submenu Target" +msgstr "" + +#: ../../mod/mitem.php:162 +msgid "Enter URL of the link or select a menu name to create a submenu" +msgstr "" + +#: ../../mod/mitem.php:163 ../../mod/mitem.php:234 +msgid "Use magic-auth if available" +msgstr "" + +#: ../../mod/mitem.php:164 ../../mod/mitem.php:235 +msgid "Open link in new window" +msgstr "" + +#: ../../mod/mitem.php:165 ../../mod/mitem.php:236 +msgid "Order in list" +msgstr "" + +#: ../../mod/mitem.php:165 ../../mod/mitem.php:236 +msgid "Higher numbers will sink to bottom of listing" +msgstr "" + +#: ../../mod/mitem.php:166 +msgid "Submit and finish" +msgstr "" + +#: ../../mod/mitem.php:167 +msgid "Submit and continue" +msgstr "" + +#: ../../mod/mitem.php:174 +msgid "Menu:" +msgstr "" + +#: ../../mod/mitem.php:177 +msgid "Link Target" +msgstr "" + +#: ../../mod/mitem.php:180 +msgid "Edit menu" +msgstr "" + +#: ../../mod/mitem.php:183 +msgid "Edit element" +msgstr "" + +#: ../../mod/mitem.php:184 +msgid "Drop element" +msgstr "" + +#: ../../mod/mitem.php:185 +msgid "New element" +msgstr "" + +#: ../../mod/mitem.php:186 +msgid "Edit this menu container" +msgstr "" + +#: ../../mod/mitem.php:187 +msgid "Add menu element" +msgstr "" + +#: ../../mod/mitem.php:188 +msgid "Delete this menu item" +msgstr "" + +#: ../../mod/mitem.php:189 +msgid "Edit this menu item" +msgstr "" + +#: ../../mod/mitem.php:206 +msgid "Menu item not found." +msgstr "" + +#: ../../mod/mitem.php:217 +msgid "Menu item deleted." +msgstr "" + +#: ../../mod/mitem.php:219 +msgid "Menu item could not be deleted." +msgstr "" + +#: ../../mod/mitem.php:226 +msgid "Edit Menu Element" +msgstr "" + +#: ../../mod/mitem.php:232 +msgid "Link text" +msgstr "" + +#: ../../mod/mood.php:131 +msgid "Set your current mood and tell your friends" +msgstr "" + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "" + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "" + +#: ../../mod/removeme.php:58 +msgid "This channel will be completely removed from the network. " +msgstr "" + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "" + +#: ../../mod/connedit.php:268 +msgid "is now connected to" +msgstr "" + +#: ../../mod/connedit.php:381 +msgid "Could not access address book record." +msgstr "" + +#: ../../mod/connedit.php:395 +msgid "Refresh failed - channel is currently unavailable." +msgstr "" + +#: ../../mod/connedit.php:402 +msgid "Channel has been unblocked" +msgstr "" + +#: ../../mod/connedit.php:403 +msgid "Channel has been blocked" +msgstr "" + +#: ../../mod/connedit.php:407 ../../mod/connedit.php:419 +#: ../../mod/connedit.php:431 ../../mod/connedit.php:443 +#: ../../mod/connedit.php:459 +msgid "Unable to set address book parameters." +msgstr "" + +#: ../../mod/connedit.php:414 +msgid "Channel has been unignored" +msgstr "" + +#: ../../mod/connedit.php:415 +msgid "Channel has been ignored" +msgstr "" + +#: ../../mod/connedit.php:426 +msgid "Channel has been unarchived" +msgstr "" + +#: ../../mod/connedit.php:427 +msgid "Channel has been archived" +msgstr "" + +#: ../../mod/connedit.php:438 +msgid "Channel has been unhidden" +msgstr "" + +#: ../../mod/connedit.php:439 +msgid "Channel has been hidden" +msgstr "" + +#: ../../mod/connedit.php:454 +msgid "Channel has been approved" +msgstr "" + +#: ../../mod/connedit.php:455 +msgid "Channel has been unapproved" +msgstr "" + +#: ../../mod/connedit.php:483 +msgid "Connection has been removed." +msgstr "" + +#: ../../mod/connedit.php:503 +#, php-format +msgid "View %s's profile" +msgstr "" + +#: ../../mod/connedit.php:507 +msgid "Refresh Permissions" +msgstr "" + +#: ../../mod/connedit.php:510 +msgid "Fetch updated permissions" +msgstr "" + +#: ../../mod/connedit.php:514 +msgid "Recent Activity" +msgstr "" + +#: ../../mod/connedit.php:517 +msgid "View recent posts and comments" +msgstr "" + +#: ../../mod/connedit.php:526 +msgid "Block (or Unblock) all communications with this connection" +msgstr "" + +#: ../../mod/connedit.php:530 ../../mod/connedit.php:730 +msgid "Unignore" +msgstr "" + +#: ../../mod/connedit.php:530 ../../mod/connedit.php:730 +#: ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "" + +#: ../../mod/connedit.php:533 +msgid "Ignore (or Unignore) all inbound communications from this connection" +msgstr "" + +#: ../../mod/connedit.php:536 +msgid "Unarchive" +msgstr "" + +#: ../../mod/connedit.php:536 +msgid "Archive" +msgstr "" + +#: ../../mod/connedit.php:539 +msgid "" +"Archive (or Unarchive) this connection - mark channel dead but keep content" +msgstr "" + +#: ../../mod/connedit.php:542 +msgid "Unhide" +msgstr "" + +#: ../../mod/connedit.php:542 +msgid "Hide" +msgstr "" + +#: ../../mod/connedit.php:545 +msgid "Hide or Unhide this connection from your other connections" +msgstr "" + +#: ../../mod/connedit.php:552 +msgid "Delete this connection" +msgstr "" + +#: ../../mod/connedit.php:643 ../../mod/connedit.php:684 +msgid "Approve this connection" +msgstr "" + +#: ../../mod/connedit.php:643 +msgid "Accept connection to allow communication" +msgstr "" + +#: ../../mod/connedit.php:659 +#, php-format +msgid "Connections: settings for %s" +msgstr "" + +#: ../../mod/connedit.php:660 +msgid "Apply these permissions automatically" +msgstr "" + +#: ../../mod/connedit.php:664 +msgid "Apply the permissions indicated on this page to all new connections." +msgstr "" + +#: ../../mod/connedit.php:668 +msgid "Slide to adjust your degree of friendship" +msgstr "" + +#: ../../mod/connedit.php:672 +msgid "Only import posts with this text" +msgstr "" + +#: ../../mod/connedit.php:672 ../../mod/connedit.php:673 +msgid "" +"words one per line or #tags or /patterns/, leave blank to import all posts" +msgstr "" + +#: ../../mod/connedit.php:673 +msgid "Do not import posts with this text" +msgstr "" + +#: ../../mod/connedit.php:680 +msgid "" +"Default permissions for your channel type have (just) been applied. They " +"have not yet been submitted. Please review the permissions on this page and " +"make any desired changes at this time. This new connection may not " +"be able to communicate with you until you submit this page, which will " +"install and apply the selected permissions." +msgstr "" + +#: ../../mod/connedit.php:683 +msgid "inherited" +msgstr "" + +#: ../../mod/connedit.php:686 +msgid "Connection has no individual permissions!" +msgstr "" + +#: ../../mod/connedit.php:687 +msgid "" +"This may be appropriate based on your privacy settings, though you may wish to review the \"Advanced Permissions\"." +msgstr "" + +#: ../../mod/connedit.php:689 +msgid "Profile Visibility" +msgstr "" + +#: ../../mod/connedit.php:690 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "" + +#: ../../mod/connedit.php:691 +msgid "Contact Information / Notes" +msgstr "" + +#: ../../mod/connedit.php:692 +msgid "Edit contact notes" +msgstr "" + +#: ../../mod/connedit.php:694 +msgid "Their Settings" +msgstr "" + +#: ../../mod/connedit.php:695 +msgid "My Settings" +msgstr "" + +#: ../../mod/connedit.php:697 +msgid "" +"Default permissions for this channel type have (just) been applied. They " +"have not been saved and there are currently no stored default " +"permissions. Please review/edit the applied settings and click [Submit] to " +"finalize." +msgstr "" + +#: ../../mod/connedit.php:698 +msgid "Clear/Disable Automatic Permissions" +msgstr "" + +#: ../../mod/connedit.php:699 +msgid "Forum Members" +msgstr "" + +#: ../../mod/connedit.php:700 +msgid "Soapbox" +msgstr "" + +#: ../../mod/connedit.php:701 +msgid "Full Sharing (typical social network permissions)" +msgstr "" + +#: ../../mod/connedit.php:702 +msgid "Cautious Sharing " +msgstr "" + +#: ../../mod/connedit.php:703 +msgid "Follow Only" +msgstr "" + +#: ../../mod/connedit.php:704 +msgid "Individual Permissions" +msgstr "" + +#: ../../mod/connedit.php:705 +msgid "" +"Some permissions may be inherited from your channel privacy settings, which have higher priority than individual " +"settings. Changing those inherited settings on this page will have no effect." +msgstr "" + +#: ../../mod/connedit.php:706 +msgid "Advanced Permissions" +msgstr "" + +#: ../../mod/connedit.php:707 +msgid "Simple Permissions (select one and submit)" +msgstr "" + +#: ../../mod/connedit.php:711 +#, php-format +msgid "Visit %s's profile - %s" +msgstr "" + +#: ../../mod/connedit.php:712 +msgid "Block/Unblock contact" +msgstr "" + +#: ../../mod/connedit.php:713 +msgid "Ignore contact" +msgstr "" + +#: ../../mod/connedit.php:714 +msgid "Repair URL settings" +msgstr "" + +#: ../../mod/connedit.php:715 +msgid "View conversations" +msgstr "" + +#: ../../mod/connedit.php:717 +msgid "Delete contact" +msgstr "" + +#: ../../mod/connedit.php:721 +msgid "Last update:" +msgstr "" + +#: ../../mod/connedit.php:723 +msgid "Update public posts" +msgstr "" + +#: ../../mod/connedit.php:725 +msgid "Update now" +msgstr "" + +#: ../../mod/connedit.php:731 +msgid "Currently blocked" +msgstr "" + +#: ../../mod/connedit.php:732 +msgid "Currently ignored" +msgstr "" + +#: ../../mod/connedit.php:733 +msgid "Currently archived" +msgstr "" + +#: ../../mod/connedit.php:734 +msgid "Currently pending" +msgstr "" + +#: ../../mod/rmagic.php:40 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "" + +#: ../../mod/rmagic.php:40 +msgid "The error message was:" +msgstr "" + +#: ../../mod/rmagic.php:44 +msgid "Authentication failed." +msgstr "" + +#: ../../mod/rmagic.php:84 +msgid "Remote Authentication" +msgstr "" + +#: ../../mod/rmagic.php:85 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "" + +#: ../../mod/rmagic.php:86 +msgid "Authenticate" +msgstr "" + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "" + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "" + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "" + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "" + +#: ../../mod/mail.php:139 +msgid "Message deleted." +msgstr "" + +#: ../../mod/mail.php:156 +msgid "Message recalled." +msgstr "" + +#: ../../mod/mail.php:225 +msgid "Send Private Message" +msgstr "" + +#: ../../mod/mail.php:226 ../../mod/mail.php:343 +msgid "To:" +msgstr "" + +#: ../../mod/mail.php:231 ../../mod/mail.php:345 +msgid "Subject:" +msgstr "" + +#: ../../mod/mail.php:242 +msgid "Send" +msgstr "" + +#: ../../mod/mail.php:269 +msgid "Message not found." +msgstr "" + +#: ../../mod/mail.php:312 +msgid "Delete message" +msgstr "" + +#: ../../mod/mail.php:313 +msgid "Recall message" +msgstr "" + +#: ../../mod/mail.php:315 +msgid "Message has been recalled." +msgstr "" + +#: ../../mod/mail.php:332 +msgid "Private Conversation" +msgstr "" + +#: ../../mod/mail.php:338 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "" + +#: ../../mod/mail.php:342 +msgid "Send Reply" +msgstr "" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "" + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "" + +#: ../../mod/regmod.php:11 +msgid "Please login." +msgstr "" + +#: ../../mod/post.php:235 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please " +"logout and retry." +msgstr "" + +#: ../../mod/new_channel.php:109 +msgid "Add a Channel" +msgstr "" + +#: ../../mod/new_channel.php:110 +msgid "" +"A channel is your own collection of related web pages. A channel can be used " +"to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "" + +#: ../../mod/new_channel.php:113 +msgid "" +"Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation " +"Group\" " +msgstr "" + +#: ../../mod/new_channel.php:114 +msgid "Choose a short nickname" +msgstr "" + +#: ../../mod/new_channel.php:115 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "" + +#: ../../mod/new_channel.php:116 +msgid "" +"Or import an existing channel from another location" +msgstr "" + +#: ../../mod/new_channel.php:118 +msgid "" +"Please choose a channel type (such as social networking or community forum) " +"and privacy requirements so we can select the best permissions for you" +msgstr "" + +#: ../../mod/new_channel.php:119 +msgid "Channel Type" +msgstr "" + +#: ../../mod/new_channel.php:119 +msgid "Read more about roles" +msgstr "" + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "" + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "" + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "" + +#: ../../mod/ping.php:263 +msgid "sent you a private message" +msgstr "" + +#: ../../mod/ping.php:314 +msgid "added your channel" +msgstr "" + +#: ../../mod/ping.php:355 +msgid "posted an event" +msgstr "" + +#: ../../mod/network.php:91 +msgid "No such group" +msgstr "" + +#: ../../mod/network.php:129 +msgid "No such channel" +msgstr "" + +#: ../../mod/network.php:143 +msgid "Search Results For:" +msgstr "" + +#: ../../mod/network.php:198 +msgid "Collection is empty" +msgstr "" + +#: ../../mod/network.php:207 +msgid "Collection: " +msgstr "" + +#: ../../mod/network.php:226 +msgid "Connection: " +msgstr "" + +#: ../../mod/network.php:233 +msgid "Invalid connection." +msgstr "" + +#: ../../mod/page.php:122 +msgid "Ipsum Lorem" +msgstr "" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "" + +#: ../../mod/bookmarks.php:60 +msgid "My Bookmarks" +msgstr "" + +#: ../../mod/bookmarks.php:71 +msgid "My Connections Bookmarks" +msgstr "" + +#: ../../mod/channel.php:97 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "" + +#: ../../mod/pconfig.php:27 ../../mod/pconfig.php:60 +msgid "This setting requires special processing and editing has been blocked." +msgstr "" + +#: ../../mod/pconfig.php:49 +msgid "Configuration Editor" +msgstr "" + +#: ../../mod/pconfig.php:50 +msgid "" +"Warning: Changing some settings could render your channel inoperable. Please " +"leave this page unless you are comfortable with and knowledgeable about how " +"to correctly use this feature." +msgstr "" + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "" + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "" + +#: ../../mod/service_limits.php:19 +msgid "No service class restrictions found." +msgstr "" + +#: ../../mod/sharedwithme.php:94 +msgid "Files: shared with me" +msgstr "" + +#: ../../mod/sharedwithme.php:96 +msgid "NEW" +msgstr "" + +#: ../../mod/sharedwithme.php:99 +msgid "Remove all files" +msgstr "" + +#: ../../mod/sharedwithme.php:100 +msgid "Remove this file" +msgstr "" + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/redbasic/php/config.php:100 +msgid "Theme settings" +msgstr "" + +#: ../../view/theme/apw/php/config.php:260 +msgid "Set scheme" +msgstr "" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set font-size for posts and comments" +msgstr "" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:82 +msgid "Light (Hubzilla default)" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:101 +msgid "Select scheme" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Narrow navbar" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Navigation bar background color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Navigation bar gradient top color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar gradient bottom color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation active button gradient top color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation active button gradient bottom color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation bar border color " +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation bar icon color " +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar active icon color " +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "link color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Set font-color for banner" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "Set the background color" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set the background image" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color of items" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background color of comments" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the border color of comments" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the indent for comments" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the basic color for item icons" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the hover color for item icons" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set font-size for the entire application" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Example: 14px" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-color for posts and comments" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set radius of corners" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set shadow depth of photos" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set maximum width of content region in pixel" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Leave empty for default width" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Center page content" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Set size of conversation author photo" +msgstr "" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set size of followup author photos" +msgstr "" + +#: ../../boot.php:1355 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "" + +#: ../../boot.php:1358 +#, php-format +msgid "Update Error at %s" +msgstr "" + +#: ../../boot.php:1525 +msgid "" +"Create an account to access services and applications within the Hubzilla" +msgstr "" + +#: ../../boot.php:1553 +msgid "Password" +msgstr "" + +#: ../../boot.php:1554 +msgid "Remember me" +msgstr "" + +#: ../../boot.php:1557 +msgid "Forgot your password?" +msgstr "" + +#: ../../boot.php:2178 +msgid "toggle mobile" +msgstr "" + +#: ../../boot.php:2313 +msgid "Website SSL certificate is not valid. Please correct." +msgstr "" + +#: ../../boot.php:2316 +#, php-format +msgid "[red] Website SSL error for %s" +msgstr "" + +#: ../../boot.php:2353 +msgid "Cron/Scheduled tasks not running." +msgstr "" + +#: ../../boot.php:2357 +#, php-format +msgid "[red] Cron tasks not running on %s" +msgstr "" diff --git a/sources/util/pconfig b/sources/util/pconfig new file mode 100755 index 00000000..cefa6901 --- /dev/null +++ b/sources/util/pconfig @@ -0,0 +1,36 @@ +#!/usr/bin/env php + 4) { + set_pconfig($argv[1],$argv[2],$argv[3],$argv[4]); + build_sync_packet($argv[1]); + echo "pconfig[{$argv[1]}][{$argv[2]}][{$argv[3]}] = " . get_pconfig($argv[1],$argv[2],$argv[3]) . "\n"; +} + +if($argc == 4) { + echo "pconfig[{$argv[1]}][{$argv[2]}][{$argv[3]}] = " . get_pconfig($argv[1],$argv[2],$argv[3]) . "\n"; +} + +if($argc == 3) { + load_pconfig($argv[1],$argv[2]); + foreach($a->config[$argv[1]][$argv[2]] as $k => $x) { + echo "pconfig[{$argv[1]}][{$argv[2]}][{$k}] = " . $x . "\n"; + } +} + +if($argc == 2) { + $r = q("select * from pconfig where uid = " . intval($argv[1])); + if($r) { + foreach($r as $rr) { + echo "pconfig[{$rr['uid']}][{$rr['cat']}][{$rr['k']}] = " . $rr['v'] . "\n"; + } + } +} + diff --git a/sources/util/php2po.php b/sources/util/php2po.php new file mode 100644 index 00000000..d3ce0a5a --- /dev/null +++ b/sources/util/php2po.php @@ -0,0 +1,71 @@ +\n\n"; + return; + } + + $phpfile = $argv[1]; + $pofile = dirname($phpfile)."/messages.po"; + + if (!file_exists($phpfile)){ + print "Unable to find '$phpfile'\n"; + return; + } + + include_once($phpfile); + + print "Out to '$pofile'\n"; + + $out = ""; + $infile = file($pofile); + $k=""; + $ink = False; + foreach ($infile as $l) { + + if ($k!="" && substr($l,0,7)=="msgstr "){ + $ink = False; + $v = '""'; + //echo "DBG: k:'$k'\n"; + if (isset($a->strings[$k])) { + $v= '"'.$a->strings[$k].'"'; + //echo "DBG\n"; + //var_dump($k, $v, $a->strings[$k], $v); + //echo "/DBG\n"; + + } + //echo "DBG: v:'$v'\n"; + $l = "msgstr ".$v."\n"; + } + + if (substr($l,0,6)=="msgid_" || substr($l,0,7)=="msgstr[" )$ink = False;; + + if ($ink) { + $k .= trim($l,"\"\r\n"); + $k = str_replace('\"','"',$k); + } + + if (substr($l,0,6)=="msgid "){ + $arr=False; + $k = str_replace("msgid ","",$l); + if ($k != '""' ) { + $k = trim($k,"\"\r\n"); + $k = str_replace('\"','"',$k); + } else { + $k = ""; + } + $ink = True; + } + + $out .= $l; + } + //echo $out; + file_put_contents($pofile, $out); +?> \ No newline at end of file diff --git a/sources/util/po2php.php b/sources/util/po2php.php new file mode 100644 index 00000000..34aedf03 --- /dev/null +++ b/sources/util/po2php.php @@ -0,0 +1,144 @@ +\n\n"; + return; + } + + $pofile = $argv[1]; + $outfile = dirname($pofile)."/strings.php"; + + if(strstr($outfile,'util')) + $lang = 'en'; + else + $lang = str_replace('-','_',basename(dirname($pofile))); + + + + if (!file_exists($pofile)){ + print "Unable to find '$pofile'\n"; + return; + } + + print "Out to '$outfile'\n"; + + $out="strings["'.$k.'"] = '; } + if ($inv) { $inv = False; $out .= '"'.$v.'"'; } + + $v = substr($l,8,$len-10); + $v = preg_replace_callback($escape_s_exp,'escape_s',$v); + $inv = True; + //$out .= $v; + } + if ($k!="" && substr($l,0,7)=="msgstr["){ + if ($ink) { + $ink = False; + $out .= '$a->strings["'.$k.'"] = '; + } + if ($inv) { + $inv = False; + $out .= '"'.$v.'"'; + } + if (!$arr) { + $arr=True; + $out .= "array(\n"; + } + $match=Array(); + preg_match("|\[([0-9]*)\] (.*)|", $l, $match); + $out .= "\t". + preg_replace_callback($escape_s_exp,'escape_s',$match[1]) + ." => " + .preg_replace_callback($escape_s_exp,'escape_s',$match[2]) .",\n"; + } + + if (substr($l,0,6)=="msgid_") { + $ink = False; + $out .= '$a->strings["'.$k.'"] = '; + } + + + if ($ink) { + $k .= trim_message($l); + $k = preg_replace_callback($escape_s_exp,'escape_s',$k); + //$out .= '$a->strings['.$k.'] = '; + } + + if (substr($l,0,6)=="msgid "){ + if ($inv) { $inv = False; $out .= '"'.$v.'"'; } + if ($k!="") $out .= $arr?");\n":";\n"; + $arr=False; + $k = str_replace("msgid ","",$l); + $k = trim_message($k); + $k = $ctx.$k; + // echo $ctx ? $ctx."\nX\n":""; + $k = preg_replace_callback($escape_s_exp,'escape_s',$k); + $ctx = ""; + $ink = True; + } + + if ($inv && substr($l,0,6)!="msgstr" && substr($l,0,7)!="msgctxt") { + $v .= trim_message($l); + $v = preg_replace_callback($escape_s_exp,'escape_s',$v); + //$out .= '$a->strings['.$k.'] = '; + } + + if (substr($l,0,7)=="msgctxt") { + $ctx = str_replace("msgctxt ","",$l); + $ctx = trim_message($ctx); + $ctx = "__ctx:".$ctx."__ "; + $ctx = preg_replace_callback($escape_s_exp,'escape_s',$ctx); + } + + } + + if ($inv) { $inv = False; $out .= '"'.$v.'"'; } + if ($k!="") $out .= $arr?");\n":";\n"; + + file_put_contents($outfile, $out); + +} + +function trim_message($str) { + // Almost same as trim("\"\r\n") except that escaped quotes are preserved + $str = trim($str, "\r\n"); + $str = ltrim($str, "\""); + $str = preg_replace('/(?setTemplateDir($folders); + +$s->setCompileDir(TEMPLATE_BUILD_PATH . '/compiled/'); +$s->setConfigDir(TEMPLATE_BUILD_PATH . '/config/'); +$s->setCacheDir(TEMPLATE_BUILD_PATH . '/cache/'); + +$s->left_delimiter = "{{"; +$s->right_delimiter = "}}"; + +$s->compileAllTemplates('.tpl',true); \ No newline at end of file diff --git a/sources/util/run_xgettext.sh b/sources/util/run_xgettext.sh new file mode 100755 index 00000000..c85ab53d --- /dev/null +++ b/sources/util/run_xgettext.sh @@ -0,0 +1,84 @@ +#!/bin/bash + +FULLPATH=$(dirname $(readlink -f "$0")) + +ADDONMODE= +ADDONNAME= +if [ "$1" == "--addon" -o "$1" == "-a" ] +then + ADDONMODE=1 + if [ -z $2 ]; then echo -e "ERROR: missing addon name\n\nrun_xgettext.sh -a "; exit 1; fi + ADDONNAME=$2 + if [ ! -d "$FULLPATH/../addon/$ADDONNAME" ]; then echo "ERROR: addon '$ADDONNAME' not found"; exit 2; fi +fi + +if [ $ADDONMODE ] +then + cd "$FULLPATH/../addon/$ADDONNAME" + mkdir -p "$FULLPATH/../addon/$ADDONNAME/lang/C" + OUTFILE="$FULLPATH/../addon/$ADDONNAME/lang/C/messages.po" + FINDSTARTDIR="." + FINDOPTS= +else + cd "$FULLPATH/../view/en/" + OUTFILE="$FULLPATH/messages.po" + FINDSTARTDIR="../../" + # skip addon folder + FINDOPTS="-wholename */addon -prune -o" +fi + + +F9KVERSION=$(cat ../../version.inc); + +echo "Red version $F9KVERSION" + +OPTS= + +#if [ "" != "$1" ] +#then +# OUTFILE="$(readlink -f ${FULLPATH}/$1)" +# if [ -e "$OUTFILE" ] +# then +# echo "join extracted strings" +# OPTS="-j" +# fi +#fi + +KEYWORDS="-k -kt:1 -kt:1,2c,2t -ktt:1,2 -ktt:1,2,4c,4t" + +echo "extract strings to $OUTFILE.." + + +rm "$OUTFILE"; touch "$OUTFILE" +for f in $(find "$FINDSTARTDIR" $FINDOPTS -name "*.php" -type f) +do + if [ ! -d "$f" ] + then + xgettext $KEYWORDS $OPTS -j -o "$OUTFILE" --from-code=UTF-8 "$f" > /dev/null 2>&1 + fi +done + +echo "setup base info.." +if [ $ADDONMODE ] +then + sed -i "s/SOME DESCRIPTIVE TITLE./ADDON $ADDONNAME/g" "$OUTFILE" + sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER//g" "$OUTFILE" + sed -i "s/FIRST AUTHOR , YEAR.//g" "$OUTFILE" + sed -i "s/PACKAGE VERSION//g" "$OUTFILE" + sed -i "s/PACKAGE/Hubzilla $ADDONNAME addon/g" "$OUTFILE" + sed -i "s/CHARSET/UTF-8/g" "$OUTFILE" + sed -i '/^\"Plural-Forms/d' "$OUTFILE" +else + sed -i "s/SOME DESCRIPTIVE TITLE./Hubzilla Project/g" "$OUTFILE" + sed -i "s/YEAR THE PACKAGE'S COPYRIGHT HOLDER/2012-2014 the Hubzilla Project/g" "$OUTFILE" + sed -i "s/FIRST AUTHOR , YEAR./Mike Macgirvin, 2012/g" "$OUTFILE" + sed -i "s/PACKAGE VERSION/$F9KVERSION/g" "$OUTFILE" + sed -i "s/PACKAGE/Red/g" "$OUTFILE" + sed -i "s/CHARSET/UTF-8/g" "$OUTFILE" + sed -i '/^\"Plural-Forms/d' "$OUTFILE" +fi + +#grep -v "Plural-Forms:" $OUTFILE > tmpout +#mv tmpout $OUTFILE + +echo "done." diff --git a/sources/util/service_class b/sources/util/service_class new file mode 100755 index 00000000..a1a17251 --- /dev/null +++ b/sources/util/service_class @@ -0,0 +1,100 @@ +#!/usr/bin/env php + 3) { + $d = get_config('service_class', $argv[1]); + $d[$argv[2]] = $argv[3]; + set_config('service_class', $argv[1], $d); + echo 'Updated service class "' . $argv[1] . '" service "' . $argv[2] . '" to ' . $argv[3] . "\n"; +} + +if($argc == 3) { + if(substr($argv[1], 0, 10) == '--account=') { + $acct = substr($argv[1], 10); + } else if(substr($argv[1], 0, 10) == '--channel=') { + $chan = substr($argv[1], 10); + $r = q("SELECT channel_account_id FROM channel WHERE channel_address='%s'", + dbesc($chan) + ); + if(!$r) + die('could not find channel'); + + $acct = intval($r[0]['channel_account_id']); + } else { + exit(); + } + $r = q('SELECT account_service_class FROM account WHERE account_id=%d', + intval($acct) + ); + if(!$r) + die('could not find account'); + + $c = q('SELECT channel_address FROM channel WHERE channel_account_id=%d', + intval($acct) + ); + + echo "Account $acct: "; + + foreach($c as $chan) + echo $chan['channel_address'] . ', '; + + echo "\n\033[1mProperty Old\t\tNew\033[0m\n"; + + if(empty($r[0]['account_service_class'])) { + $oclass = 'None'; + $old = false; + } else { + $oclass = $r[0]['account_service_class']; + $old = get_config('service_class', $oclass); + } + echo "service_class $oclass\t\t\033[1m" . $argv[2] . "\033[0m\n"; + + $new = get_config('service_class', $argv[2]); + foreach(array('photo_upload_limit','total_items','total_pages','total_identities','total_channels','total_feeds','attach_upload_limit','minimum_feedcheck_minutes','chatrooms','chatters_inroom') as $prop) { + echo $prop . str_repeat(' ',26 - strlen($prop)) . (($old && $old[$prop]) ? $old[$prop] : 'unlimited') . "\t\t\033[1m" . (($new && $new[$prop]) ? $new[$prop] : 'unlimited') . "\033[0m\n"; + } + $r = ''; + $k = fopen('php://stdin', 'r'); + while($r != 'y' && $r != 'n') { + echo "Are you sure? (y/n)"; + $r = substr(fgets($k), 0, 1); + } + if($r == 'n') + die('no update done'); + + $r = q("UPDATE account SET account_service_class='%s' WHERE account_id=%d", + dbesc($argv[2]), + intval($acct) + ); + if($r) { + echo "updated successfully\n"; + } else { + echo "failed\n"; + } +} + + +if($argc == 2) { + $d = get_config('service_class', $argv[1]); + echo $argv[1] . ":\n"; + foreach($d as $k => $v) { + echo "$k = $v\n"; + } +} + +if($argc == 1) { + load_config('service_class'); + foreach($a->config['service_class'] as $class=>$props) { + echo "$class:\n"; + $d = unserialize($props); + foreach($d as $k => $v) { + echo "\t$k = $v\n"; + } + } +} \ No newline at end of file diff --git a/sources/util/shredder/JSON.sh b/sources/util/shredder/JSON.sh new file mode 100755 index 00000000..65f5f1f6 --- /dev/null +++ b/sources/util/shredder/JSON.sh @@ -0,0 +1,129 @@ +# The MIT License +# +# Copyright (c) 2011 Dominic Tarr +# +# 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. +# +# +# https://github.com/dominictarr/JSON.sh +# +throw () { + echo "$*" >&2 + exit 1 +} + +tokenize () { + local ESCAPE='(\\[^u[:cntrl:]]|\\u[0-9a-fA-F]{4})' + local CHAR='[^[:cntrl:]"\\]' + local STRING="\"$CHAR*($ESCAPE$CHAR*)*\"" + local NUMBER='-?(0|[1-9][0-9]*)([.][0-9]*)?([eE][+-]?[0-9]*)?' + local KEYWORD='null|false|true' + local SPACE='[[:space:]]+' + egrep -ao "$STRING|$NUMBER|$KEYWORD|$SPACE|." --color=never | + egrep -v "^$SPACE$" # eat whitespace +} + +parse_array () { + local index=0 + local ary='' + read -r token + case "$token" in + ']') ;; + *) + while : + do + parse_value "$1" "$index" + let index=$index+1 + ary="$ary""$value" + read -r token + case "$token" in + ']') break ;; + ',') ary="$ary," ;; + *) throw "EXPECTED , or ] GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=`printf '[%s]' "$ary"` +} + +parse_object () { + local key + local obj='' + read -r token + case "$token" in + '}') ;; + *) + while : + do + case "$token" in + '"'*'"') key=$token ;; + *) throw "EXPECTED string GOT ${token:-EOF}" ;; + esac + read -r token + case "$token" in + ':') ;; + *) throw "EXPECTED : GOT ${token:-EOF}" ;; + esac + read -r token + parse_value "$1" "$key" + obj="$obj$key:$value" + read -r token + case "$token" in + '}') break ;; + ',') obj="$obj," ;; + *) throw "EXPECTED , or } GOT ${token:-EOF}" ;; + esac + read -r token + done + ;; + esac + value=`printf '{%s}' "$obj"` +} + +parse_value () { + local jpath="${1:+$1,}$2" + case "$token" in + '{') parse_object "$jpath" ;; + '[') parse_array "$jpath" ;; + # At this point, the only valid single-character tokens are digits. + ''|[^0-9]) throw "EXPECTED value GOT ${token:-EOF}" ;; + *) value=$token ;; + esac + printf "[%s]\t%s\n" "$jpath" "$value" +} + +parse () { + read -r token + parse_value + read -r token + case "$token" in + '') ;; + *) throw "EXPECTED EOF GOT $token" ;; + esac +} + +if [ $0 = $BASH_SOURCE ]; +then + tokenize | parse +fi diff --git a/sources/util/shredder/OAuth.sh b/sources/util/shredder/OAuth.sh new file mode 100755 index 00000000..4be4ed35 --- /dev/null +++ b/sources/util/shredder/OAuth.sh @@ -0,0 +1,214 @@ +#!/bin/bash +# Copyright (c) 2010, 2012 Yu-Jie Lin +# +# 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. + +BASHOAUTH_VERSION=0.1.2 + +OAuth_debug () { + # Print out all parameters, each in own line + [[ "$OAUTH_DEBUG" == "" ]] && return + local t=$(date +%FT%T.%N) + while (( $# > 0 )); do + echo "[OAuth][DEBUG][$t] $1" + shift 1 + done + } + +OAuth_nonce () { + # Return a nonce + md5sum <<< "$RANDOM-$(date +%s.%N)" | cut -d' ' -f 1 + } + +OAuth_timestamp () { + # Return timestamp + echo "$(date +%s)" + } + +OAuth_PE () { + # Encode $1 using Percent-encoding as defined in + # http://tools.ietf.org/html/rfc5849#section-3.6 + # Any character other than [a-zA-Z0-9-._~] is converted into format %XX + [ -n "$1" ] \ + && echo -n "$1" | perl -p -e 's/([^A-Za-z0-9-._~])/sprintf("%%%02X", ord($1))/seg' +} + +OAuth_PE_file () { + # Encode a file $1 using Percent-encoding as defined in + # http://tools.ietf.org/html/rfc5849#section-3.6 + # $1 a filename, not the content of file + perl -p -e 's/([^A-Za-z0-9-._~])/sprintf("%%%02X", ord($1))/seg' < "$1" +} + +OAuth_params_string () { + # Sort the paramters and join them into one-line string + while (( $# > 0 )); do + echo $1 + shift 1 + done | sort | tr '\n' '&' | sed 's/&$//' + } + +OAuth_base_string () { + # $1 method: "GET", "POST", etc + # $2 url + # $3-$N params + local method=$1 + local url=$2 + shift 2 + + local params_string=$(OAuth_params_string $@) + + echo "$method&$(OAuth_PE "$url")&$(OAuth_PE "$params_string")" + } + +OAuth_param () { + # Return a percent encoded key-value pair + # $1 key + # $2 value + echo "$(OAuth_PE "$1")=$(OAuth_PE "$2")" + } + +OAuth_param_quote () { + # Return a percent encoded key-value pair, value is quoted + # $1 key + # $2 value + echo "$(OAuth_PE "$1")=\"$(OAuth_PE "$2")\"" + } + +OAuth_param_file () { + # Return a percent encoded key-value pair, the value is an encoded file content + # $1 key + # $2 filename + echo "$(OAuth_PE "$1")=$(OAuth_PE_file "$2")" + } + +OAuth_param_raw_value () { + # Return a percent encoded key-value pair, only key will be encoded by this function + # $1 key + # $2 value + echo "$(OAuth_PE "$1")=$2" + } + +OAuth_HMAC_SHA1 () { + # Hash the text $1 with key $2 + local text="$1" + local key="$2" + echo -n "$text" | openssl dgst -sha1 -binary -hmac "$key" | base64 + } + +_OAuth_signature () { + # Return the signature, note it's necessary to pass to OAuth_PE before add to header + # $1 signature_method + # $2 base_string + # $3 consumer_secret + # $4 token_secret + local signature_method="OAuth_${1//-/_}" + local base_string=$2 + local c_secret=$3 + local t_secret=$4 + $signature_method "$base_string" "$c_secret&$t_secret" + } + +OAuth_signature () { + # Return the signature, note it's necessary to pass to OAuth_PE before add to header + # $1 base_string + _OAuth_signature "$oauth_signature_method" "$1" "$oauth_consumer_secret" "$oauth_token_secret" + } + +_OAuth_authorization_header_params_string () { + while (( $# > 0 )); do + echo -n "$(cut -d\= -f 1 <<< "$1")=\"$(cut -d\= -f 2 <<< "$1")\"" + shift 1 + # Use break to prevent error code being returned + (( $# > 0 )) && echo -n ', ' || break + done + } + +_OAuth_authorization_header () { + # Return header string + # $1 header key + # $2 OAuth realm, can be empty string + # $3 OAuth consumer key + # $4 OAuth consumer secret + # $5 OAuth token + # $6 OAuth token secret + # $7 OAuth signature method + # $8 OAuth version + # $9 nonce + # $10 timestamp + # $11 method + # $12 url + # $13-$N params + echo -n "$1: OAuth " + [[ "$2" != "" ]] && echo -n "realm=\"$2\", " + local oauth_consumer_key="$3" + local oauth_consumer_secret="$4" + local oauth_token="$5" + local oauth_token_secret="$6" + local oauth_signature_method="$7" + local oauth_version="$8" + local oauth_nonce="$9" + [[ "$oauth_nonce" == "" ]] && oauth_nonce="$(OAuth_nonce)" + local oauth_timestamp="${10}" + [[ "$oauth_timestamp" == "" ]] && oauth_timestamp="$(OAuth_timestamp)" + local method="${11}" + local url="${12}" + shift 12 + local params=( + $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key") + $(OAuth_param 'oauth_signature_method' "$oauth_signature_method") + $(OAuth_param 'oauth_version' "$oauth_version") + $(OAuth_param 'oauth_nonce' "$oauth_nonce") + $(OAuth_param 'oauth_timestamp' "$oauth_timestamp") + ) + [[ "$oauth_token" != "" ]] && params[${#params[@]}]=$(OAuth_param 'oauth_token' "$oauth_token") + local sign_params=${params[@]} + while (( $# > 0 )); do + sign_params[${#sign_params[@]}]="$1" + shift 1 + done + local base_string=$(OAuth_base_string "$method" "$url" ${sign_params[@]}) + local signature=$(_OAuth_signature "$oauth_signature_method" "$base_string" "$oauth_consumer_secret" "$oauth_token_secret") + params[${#params[@]}]=$(OAuth_param 'oauth_signature' "$signature") + _OAuth_authorization_header_params_string ${params[@]} + } + +OAuth_authorization_header () { + # Return header string + # $1 header key + # $2 OAuth realm, can be empty string + # $3 OAuth nonce + # $4 OAuth timestamp + # $5 method + # $6 url + # $7-$N params + local header_key="$1" + local realm="$2" + local oauth_nonce="$3" + local oauth_timestamp="$4" + local method="$5" + local url="$6" + shift 6 + local params=() + while (( $# > 0 )); do + params[${#params[@]}]="$1" + shift 1 + done + _OAuth_authorization_header "$header_key" "$realm" "$oauth_consumer_key" "$oauth_consumer_secret" "$oauth_token" "$oauth_token_secret" "$oauth_signature_method" "$oauth_version" "$oauth_nonce" "$oauth_timestamp" "$method" "$url" ${params[@]} + } diff --git a/sources/util/shredder/ShredOAuth.sh b/sources/util/shredder/ShredOAuth.sh new file mode 100755 index 00000000..e21bea35 --- /dev/null +++ b/sources/util/shredder/ShredOAuth.sh @@ -0,0 +1,219 @@ +#!/bin/bash +# Copyright (c) 2012 Fabio Comuni +# Copyright (c) 2012 Michael Nowack +# Copyright (c) 2010, 2012 Yu-Jie Lin +# +# 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. + +FRIENDICAOAUTH_VERSION=0.1.1 + +F_API_VERSION="1" + +# Friendica API endpoints + +F_ACCOUNF_UPDATE_PROFILE_IMAGE="${hubzilla_url}/api/account/update_profile_image" +F_STATUSES_UPDATE="${hubzilla_url}/api/statuses/update" +F_STATUSES_HOME_TIMELINE="${hubzilla_url}/api/statuses/home_timeline" + +F_REQUESF_TOKEN=${hubzilla_url}'/api/oauth/request_token' +F_ACCESS_TOKEN=${hubzilla_url}'/api/oauth/access_token' +F_AUTHORIZE_TOKEN=${hubzilla_url}'/api/oauth/authorize' + +# Source OAuth.sh + +OAuth_sh=$(which OAuth.sh) +(( $? != 0 )) && echo 'Unable to locate OAuth.sh! Make sure it is in searching PATH.' && exit 1 +source "$OAuth_sh" + +FO_debug () { + # Print out all parameters, each in own line + [[ "$FO_DEBUG" == "" ]] && return + local t=$(date +%FT%T.%N) + while (( $# > 0 )); do + echo "[FO][DEBUG][$t] $1" + shift 1 + done + } + +FO_extract_value () { + # $1 key name + # $2 string to find + egrep -o "$1=[a-zA-Z0-9-]*" <<< "$2" | cut -d\= -f 2 + } + + +FO_init() { + # Initialize FriendicaOAuth + oauth_version='1.0' + oauth_signature_method='HMAC-SHA1' + oauth_basic_params=( + $(OAuth_param 'oauth_consumer_key' "$oauth_consumer_key") + $(OAuth_param 'oauth_signature_method' "$oauth_signature_method") + $(OAuth_param 'oauth_version' "$oauth_version") + ) + } + +FO_access_token_helper () { + # Help guide user to get access token + + local resp PIN + + # Request Token + + local auth_header="$(_OAuth_authorization_header 'Authorization' "$hubzilla_url/" "$oauth_consumer_key" "$oauth_consumer_secret" '' '' "$oauth_signature_method" "$oauth_version" "$(OAuth_nonce)" "$(OAuth_timestamp)" 'POST' "$F_REQUESF_TOKEN" "$(OAuth_param 'oauth_callback' 'oob')"), $(OAuth_param_quote 'oauth_callback' 'oob')" + +# echo $auth_header +# echo $F_REQUESF_TOKEN + + resp=$(curl -s -d '' -H "$auth_header" "$F_REQUESF_TOKEN") + FO_rval=$? + (( $? != 0 )) && return $FO_rval + + local _oauth_token=$(FO_extract_value 'oauth_token' "$resp") + local _oauth_token_secret=$(FO_extract_value 'oauth_token_secret' "$resp") + + echo 'Please go to the following link to get the PIN:' + echo " ${F_AUTHORIZE_TOKEN}?oauth_token=$_oauth_token" + + read -p 'PIN: ' PIN + + # Access Token + + local auth_header="$(_OAuth_authorization_header 'Authorization' "$hubzilla_url/" "$oauth_consumer_key" "$oauth_consumer_secret" "$_oauth_token" "$_oauth_token_secret" "$oauth_signature_method" "$oauth_version" "$(OAuth_nonce)" "$(OAuth_timestamp)" 'POST' "$F_ACCESS_TOKEN" "$(OAuth_param 'oauth_verifier' "$PIN")"), $(OAuth_param_quote 'oauth_verifier' "$PIN")" + + resp=$(curl -s -d "" -H "$auth_header" "$F_ACCESS_TOKEN") + FO_rval=$? + (( $? != 0 )) && return $FO_rval + + FO_ret=( + $(FO_extract_value 'oauth_token' "$resp") + $(FO_extract_value 'oauth_token_secret' "$resp") + $(FO_extract_value 'user_id' "$resp") + $(FO_extract_value 'screen_name' "$resp") + ) + } + +# APIs +###### + +FO_statuses_update () { + # $1 format + # $2 status + # $3 in_reply_to_status_id + # The followins are not implemented yet: + # $4 lat + # $5 long + # $6 place_id + # $7 display_coordinates + local format="$1" + [[ "$format" == "" ]] && format="xml" + + local params=( + $(OAuth_param 'status' "$2") + ) + + params[${#params[@]}]=$(OAuth_param 'source' "shredder") + + [[ "$3" != "" ]] && params[${#params[@]}]=$(OAuth_param 'in_reply_to_status_id' "$3") && local in_reply_to_status_id=( '--data-urlencode' "in_reply_to_status_id=$3" ) + + + local auth_header=$(OAuth_authorization_header 'Authorization' "$hubzilla_url" '' '' 'POST' "$F_STATUSES_UPDATE.$format" ${params[@]}) + + + FO_ret=$(curl -s -H "$auth_header" --data-urlencode "status=$2" --data-urlencode "source=shred" ${in_reply_to_status_id[@]} "$F_STATUSES_UPDATE.$format") + + FO_rval=$? + return $FO_rval + } + + +# gets the user home_timeline. +# +# @sets FO_ret API response +# @returns status +# @public +FO_statuses_home_timeline () { + # $1 format + # $2 screen_name + # $3 count + local format="$1" + local screen_name="$2" + local count="$3" + [[ "$format" == "" ]] && format="xml" + [[ "$count" == "" ]] && count=1 + + local params=( + $(OAuth_param 'screen_name' $screen_name) + $(OAuth_param 'count' $count) + ) + + local auth_header=$(OAuth_authorization_header 'Authorization' "$hubzilla_url" '' '' 'GET' "$F_STATUSES_HOME_TIMELINE.$format" ${params[@]}) + + convscreen=$(OAuth_PE "$screen_name"); + FO_ret=$(curl -s --get "${F_STATUSES_HOME_TIMELINE}.${format}" --data "screen_name=${convscreen}&count=${count}" --header "${auth_header}") + FO_rval=$? + + return $FO_rval + } + +FO_command () { + local command="$1" + local post="$2" + declare -a opts=("${!3}") + local params=( + $(OAuth_param 'screen_name' $screen_name) + $(OAuth_param 'count' $count) + ) + +#echo "$3" +#echo '---' +#echo "${opts[@]}" + + convscreen=$(OAuth_PE "$screen_name"); + data="screen_name=${convscreen}&count=${count}" + + if [ ${#opts[@]} != 0 ]; then + for b in ${opts[@]}; do + lhs=`echo $b | awk -F= '{print $1};'` + rhs=`echo $b | awk -F= '{print $2};'` + params=("${params[@]}" $(OAuth_param "$lhs" "$rhs")) + data=$data"&""$lhs"="$rhs" + done + fi + +#echo 'params: ' ${params[@]} + +#echo 'data: ' $data + + local auth_header=''; + + if [ "$post" == '1' ]; then + auth_header=$(OAuth_authorization_header 'Authorization' "$hubzilla_url" '' '' 'POST' "${hubzilla_url}/api/${command}.json" ${params[@]}) + FO_ret=$(curl -s "${hubzilla_url}/api/${command}.json" --data-urlencode "${data}" --header "${auth_header}") + + else + auth_header=$(OAuth_authorization_header 'Authorization' "$hubzilla_url" '' '' 'GET' "${hubzilla_url}/api/${command}.json" ${params[@]}) + FO_ret=$(curl -s --get "${hubzilla_url}/api/${command}.json" --data "${data}" --header "${auth_header}") + + fi + + FO_rval=$? + + return $FO_rval +} diff --git a/sources/util/shredder/jansson-2.6.tar.gz b/sources/util/shredder/jansson-2.6.tar.gz new file mode 100644 index 00000000..51f1598b Binary files /dev/null and b/sources/util/shredder/jansson-2.6.tar.gz differ diff --git a/sources/util/shredder/jshon.tar.gz b/sources/util/shredder/jshon.tar.gz new file mode 100644 index 00000000..ea9880ca Binary files /dev/null and b/sources/util/shredder/jshon.tar.gz differ diff --git a/sources/util/shredder/readme b/sources/util/shredder/readme new file mode 100644 index 00000000..44ed6f45 --- /dev/null +++ b/sources/util/shredder/readme @@ -0,0 +1,11 @@ +http://kmkeen.com/jshon/ + + + +Jshon was made to be part of the usual text processing pipeline. However, every single -u is printed out to its own line. Most shell tools expect fields to be tab separated, and newlines between sets of fields. The paste tool does this. However, paste breaks down on blank lines so use sed to pad out the empty lines. + +jshon ... | sed 's/^$/-/' | paste -s -d "\t\t\n" | .... + +The arguments need a little explaining. +-s is mysteriously needed for paste to correctly handle input. +-d is less obvious from the manpage, because it can take multiple characters which are looped through. The above example concatenates every three lines together. diff --git a/sources/util/shredder/shredder b/sources/util/shredder/shredder new file mode 100755 index 00000000..61e6b1fd --- /dev/null +++ b/sources/util/shredder/shredder @@ -0,0 +1,234 @@ +#!/bin/bash +# Copyright (c) 2012 Fabio Comuni +# Copyright (c) 2010, 2012 Yu-Jie Lin +# +# 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. + +FCLI_RC="$HOME/.shred.rc" + + + +usage () { + echo "usage: $0 options + +OPTIONS: + -h Show this message + + -c Command + + -C Config-Filename + + Valid Commands: + statuses_update + home_timeline + +Use -h -c command to get options for the command. +" + exit $1 + } + +show_config_help () { + echo "Please create $FCLI_RC with: +hubzilla_url=YOR_SERVER_URL (no trailing /) +oauth_consumer_key=YOUR_CONSUMER_KEY +oauth_consumer_secret=YOUR_CONSUMER_SECRET + +You can register new app consumer key and secret at + http://yourserver.com/settings/oauth +" + exit $1 + } + + +show_statuses_update () { + echo "Command statuses_update + +Requires: + -s status + +Optional: + -r in_reply_to_status_id +" + exit $1 + } + +show_home_timeline () { + echo "Command home_timeline" + + exit $1 + } + +#json helper +# +# usage: +# echo "$parsed_json" | js key1 [key2 [key3 ...]][,] +# +# echoes the value of json[key1][key2][key3], without surronding quotes +# with "," as last argument, no newline is printed +# +js () { + local arg + local rg='^\[' + local ret + for arg in $@ + do + [[ "$arg" == "," ]] && break; + if [[ $arg == ${arg//[0-9]/} ]] + then + rg="${rg}\"$arg\"," + else + rg="${rg}$arg," + fi + done + rg="${rg%?}\]" + ret=$(grep $rg | cut -f 2 | sed 's/^"\(.*\)"$/\1/' | sed "s/\\\\\//\//g" ) + if [[ "$arg" == "," ]] + then + echo -e "$ret" | tr -d '\012\015' + else + echo -e "$ret" + fi +} + + +load_config () { + + # Source Config + [[ -f "$FCLI_RC" ]] && . "$FCLI_RC" || show_config_help 1 + + THISDIR=$(dirname $0) + if [ $THISDIR == '' ]; then THISDIR=. ; fi + PATH=$THISDIR:$PATH + + # Source ShredOAuth.sh + OAuth_sh=$(which ShredOAuth.sh) + (( $? != 0 )) && echo 'Unable to locate ShredOAuth.sh! Make sure it is in searching PATH.' && exit 1 + source "$OAuth_sh" + + # Source JSON.sh + JSON_sh=$(which JSON.sh) + (( $? != 0 )) && echo 'Unable to locate JSON.sh! Make sure it is in searching PATH.' && exit 1 + source "$JSON_sh" + + + [[ "$oauth_consumer_key" == "" ]] && show_config_help 1 + [[ "$oauth_consumer_secret" == "" ]] && show_config_help 1 + + + FO_init + + if [[ "$oauth_token" == "" ]] || [[ "$oauth_token_secret" == "" ]]; then + FO_access_token_helper + if (( $? == 0 )); then + oauth_token=${FO_ret[0]} + oauth_token_secret=${FO_ret[1]} + echo "oauth_token='${FO_ret[0]}'" >> "$FCLI_RC" + echo "oauth_token_secret='${FO_ret[1]}'" >> "$FCLI_RC" + echo "Token saved." + else + echo 'Unable to get access token' + exit 1 + fi + fi + } + +main () { + + fcli_command= + fcli_status= + fcli_in_reply_to_status_id= + fcli_file= + fcli_help_flag= + fcli_opts= + fcli_post= + + while getopts "C:c:s:r:f:q:hp" name + do + case $name in + c) fcli_command="$OPTARG";; + C) FCLI_RC="$OPTARG";; + s) fcli_status="$OPTARG";; + r) fcli_in_reply_to_status_id="$OPTARG";; + f) fcli_file="$OPTARG";; + h) fcli_help_flag="1";; + p) fcli_post="1";; + q) fcli_opts=("${fcli_opts[@]}" "$OPTARG");; + ?) usage + exit 2;; + esac + done + load_config + + if [[ "$fcli_help_flag" == "1" ]]; then case $fcli_command in +# statuses_update) +# show_statuses_update 0 +# ;; + home_timeline) + show_home_timeline 0 + ;; + *) + [[ "$fcli_command" == "" ]] && usage 0 + usage 1 + esac ; fi + + case $fcli_command in + home_timeline) + FO_statuses_home_timeline 'json' '' 5 + JS_Parsed=$(echo "$FO_ret" | tokenize | parse) + for id in 0 1 2 3 4 + do + echo "$JS_Parsed" | js $id "user" "name" , + echo -n " - " + echo "$JS_Parsed" | js $id "created_at" + echo "$JS_Parsed" | js $id "text" + echo "" + echo "------------------------------------------------------------------------------" + done + + return $FO_rval + ;; + statuses_update) + [[ "$fcli_status" == "" ]] && show_statuses_update 1 + FO_statuses_update 'json' "$fcli_status" "$fcli_in_reply_to_status_id" + JS_Parsed=$(echo "$FO_ret" | tokenize | parse) + echo "$JS_Parsed" | js "user" "name" , + echo -n " - " + echo "$JS_Parsed" | js "created_at" + echo "$JS_Parsed" | js "text" + echo "" + echo "------------------------------------------------------------------------------" + return $FO_rval + ;; + + *) + +# echo "${fcli_opts[@]}" + + FO_command "$fcli_command" "$fcli_post" fcli_opts[@] + + echo $FO_ret + + return $FO_rval + + ;; + esac + return 0 + } + +main "$@" diff --git a/sources/util/strings.php b/sources/util/strings.php new file mode 100644 index 00000000..e3fdb646 --- /dev/null +++ b/sources/util/strings.php @@ -0,0 +1,2120 @@ +strings["Cannot locate DNS info for database server '%s'"] = ""; +$a->strings["Profile Photos"] = ""; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = ""; +$a->strings["created a new post"] = ""; +$a->strings["commented on %s's post"] = ""; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = ""; +$a->strings["Default privacy group for new contacts"] = ""; +$a->strings["All Channels"] = ""; +$a->strings["edit"] = ""; +$a->strings["Collections"] = ""; +$a->strings["Edit collection"] = ""; +$a->strings["Add new collection"] = ""; +$a->strings["Channels not in any collection"] = ""; +$a->strings["add"] = ""; +$a->strings["Not a valid email address"] = ""; +$a->strings["Your email domain is not among those allowed on this site"] = ""; +$a->strings["Your email address is already registered at this site."] = ""; +$a->strings["An invitation is required."] = ""; +$a->strings["Invitation could not be verified."] = ""; +$a->strings["Please enter the required information."] = ""; +$a->strings["Failed to store account information."] = ""; +$a->strings["Registration confirmation for %s"] = ""; +$a->strings["Registration request at %s"] = ""; +$a->strings["Administrator"] = ""; +$a->strings["your registration password"] = ""; +$a->strings["Registration details for %s"] = ""; +$a->strings["Account approved."] = ""; +$a->strings["Registration revoked for %s"] = ""; +$a->strings["Account verified. Please login."] = ""; +$a->strings["Click here to upgrade."] = ""; +$a->strings["This action exceeds the limits set by your subscription plan."] = ""; +$a->strings["This action is not available under your subscription plan."] = ""; +$a->strings["Miscellaneous"] = ""; +$a->strings["YYYY-MM-DD or MM-DD"] = ""; +$a->strings["Required"] = ""; +$a->strings["never"] = ""; +$a->strings["less than a second ago"] = ""; +$a->strings["year"] = ""; +$a->strings["years"] = ""; +$a->strings["month"] = ""; +$a->strings["months"] = ""; +$a->strings["week"] = ""; +$a->strings["weeks"] = ""; +$a->strings["day"] = ""; +$a->strings["days"] = ""; +$a->strings["hour"] = ""; +$a->strings["hours"] = ""; +$a->strings["minute"] = ""; +$a->strings["minutes"] = ""; +$a->strings["second"] = ""; +$a->strings["seconds"] = ""; +$a->strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = ""; +$a->strings["%1\$s's birthday"] = ""; +$a->strings["Happy Birthday %1\$s"] = ""; +$a->strings["New Page"] = ""; +$a->strings["Edit"] = ""; +$a->strings["View"] = ""; +$a->strings["Preview"] = ""; +$a->strings["Actions"] = ""; +$a->strings["Page Link"] = ""; +$a->strings["Title"] = ""; +$a->strings["Created"] = ""; +$a->strings["Edited"] = ""; +$a->strings["Public Timeline"] = ""; +$a->strings["Default"] = ""; +$a->strings["Directory Options"] = ""; +$a->strings["Alphabetic"] = ""; +$a->strings["Reverse Alphabetic"] = ""; +$a->strings["Newest to Oldest"] = ""; +$a->strings["Oldest to Newest"] = ""; +$a->strings["Sort"] = ""; +$a->strings["Safe Mode"] = ""; +$a->strings["Public Forums Only"] = ""; +$a->strings["This Website Only"] = ""; +$a->strings["l F d, Y \\@ g:i A"] = ""; +$a->strings["Starts:"] = ""; +$a->strings["Finishes:"] = ""; +$a->strings["Location:"] = ""; +$a->strings["This event has been added to your calendar."] = ""; +$a->strings["Delete this item?"] = ""; +$a->strings["Comment"] = ""; +$a->strings["[+] show all"] = ""; +$a->strings["[-] show less"] = ""; +$a->strings["[+] expand"] = ""; +$a->strings["[-] collapse"] = ""; +$a->strings["Password too short"] = ""; +$a->strings["Passwords do not match"] = ""; +$a->strings["everybody"] = ""; +$a->strings["Secret Passphrase"] = ""; +$a->strings["Passphrase hint"] = ""; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = ""; +$a->strings["close all"] = ""; +$a->strings["Nothing new here"] = ""; +$a->strings["Rate This Channel (this is public)"] = ""; +$a->strings["Rating"] = ""; +$a->strings["Describe (optional)"] = ""; +$a->strings["Submit"] = ""; +$a->strings["Please enter a link URL"] = ""; +$a->strings["Unsaved changes. Are you sure you wish to leave this page?"] = ""; +$a->strings["timeago.prefixAgo"] = ""; +$a->strings["timeago.prefixFromNow"] = ""; +$a->strings["ago"] = ""; +$a->strings["from now"] = ""; +$a->strings["less than a minute"] = ""; +$a->strings["about a minute"] = ""; +$a->strings["%d minutes"] = ""; +$a->strings["about an hour"] = ""; +$a->strings["about %d hours"] = ""; +$a->strings["a day"] = ""; +$a->strings["%d days"] = ""; +$a->strings["about a month"] = ""; +$a->strings["%d months"] = ""; +$a->strings["about a year"] = ""; +$a->strings["%d years"] = ""; +$a->strings[" "] = ""; +$a->strings["timeago.numbers"] = ""; +$a->strings["parent"] = ""; +$a->strings["Collection"] = ""; +$a->strings["Principal"] = ""; +$a->strings["Addressbook"] = ""; +$a->strings["Calendar"] = ""; +$a->strings["Schedule Inbox"] = ""; +$a->strings["Schedule Outbox"] = ""; +$a->strings["Unknown"] = ""; +$a->strings["%1\$s used"] = ""; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = ""; +$a->strings["Files"] = ""; +$a->strings["Total"] = ""; +$a->strings["Shared"] = ""; +$a->strings["Create"] = ""; +$a->strings["Upload"] = ""; +$a->strings["Name"] = ""; +$a->strings["Type"] = ""; +$a->strings["Size"] = ""; +$a->strings["Last Modified"] = ""; +$a->strings["Delete"] = ""; +$a->strings["Create new folder"] = ""; +$a->strings["Upload file"] = ""; +$a->strings["%1\$s's bookmarks"] = ""; +$a->strings["view full size"] = ""; +$a->strings["General Features"] = ""; +$a->strings["Content Expiration"] = ""; +$a->strings["Remove posts/comments and/or private messages at a future time"] = ""; +$a->strings["Multiple Profiles"] = ""; +$a->strings["Ability to create multiple profiles"] = ""; +$a->strings["Advanced Profiles"] = ""; +$a->strings["Additional profile sections and selections"] = ""; +$a->strings["Profile Import/Export"] = ""; +$a->strings["Save and load profile details across sites/channels"] = ""; +$a->strings["Web Pages"] = ""; +$a->strings["Provide managed web pages on your channel"] = ""; +$a->strings["Private Notes"] = ""; +$a->strings["Enables a tool to store notes and reminders"] = ""; +$a->strings["Navigation Channel Select"] = ""; +$a->strings["Change channels directly from within the navigation dropdown menu"] = ""; +$a->strings["Photo Location"] = ""; +$a->strings["If location data is available on uploaded photos, link this to a map."] = ""; +$a->strings["Expert Mode"] = ""; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = ""; +$a->strings["Premium Channel"] = ""; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = ""; +$a->strings["Post Composition Features"] = ""; +$a->strings["Use Markdown"] = ""; +$a->strings["Allow use of \"Markdown\" to format posts"] = ""; +$a->strings["Large Photos"] = ""; +$a->strings["Include large (640px) photo thumbnails in posts. If not enabled, use small (320px) photo thumbnails"] = ""; +$a->strings["Channel Sources"] = ""; +$a->strings["Automatically import channel content from other channels or feeds"] = ""; +$a->strings["Even More Encryption"] = ""; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = ""; +$a->strings["Enable voting tools"] = ""; +$a->strings["Provide a class of post which others can vote on"] = ""; +$a->strings["Network and Stream Filtering"] = ""; +$a->strings["Search by Date"] = ""; +$a->strings["Ability to select posts by date ranges"] = ""; +$a->strings["Collections Filter"] = ""; +$a->strings["Enable widget to display Network posts only from selected collections"] = ""; +$a->strings["Saved Searches"] = ""; +$a->strings["Save search terms for re-use"] = ""; +$a->strings["Network Personal Tab"] = ""; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = ""; +$a->strings["Network New Tab"] = ""; +$a->strings["Enable tab to display all new Network activity"] = ""; +$a->strings["Affinity Tool"] = ""; +$a->strings["Filter stream activity by depth of relationships"] = ""; +$a->strings["Suggest Channels"] = ""; +$a->strings["Show channel suggestions"] = ""; +$a->strings["Post/Comment Tools"] = ""; +$a->strings["Tagging"] = ""; +$a->strings["Ability to tag existing posts"] = ""; +$a->strings["Post Categories"] = ""; +$a->strings["Add categories to your posts"] = ""; +$a->strings["Saved Folders"] = ""; +$a->strings["Ability to file posts under folders"] = ""; +$a->strings["Dislike Posts"] = ""; +$a->strings["Ability to dislike posts/comments"] = ""; +$a->strings["Star Posts"] = ""; +$a->strings["Ability to mark special posts with a star indicator"] = ""; +$a->strings["Tag Cloud"] = ""; +$a->strings["Provide a personal tag cloud on your channel page"] = ""; +$a->strings["Categories"] = ""; +$a->strings["Apps"] = ""; +$a->strings["System"] = ""; +$a->strings["Personal"] = ""; +$a->strings["Create Personal App"] = ""; +$a->strings["Edit Personal App"] = ""; +$a->strings["Connect"] = ""; +$a->strings["Ignore/Hide"] = ""; +$a->strings["Suggestions"] = ""; +$a->strings["See more..."] = ""; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = ""; +$a->strings["Add New Connection"] = ""; +$a->strings["Enter the channel address"] = ""; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = ""; +$a->strings["Notes"] = ""; +$a->strings["Save"] = ""; +$a->strings["Remove term"] = ""; +$a->strings["Everything"] = ""; +$a->strings["Archives"] = ""; +$a->strings["Me"] = ""; +$a->strings["Family"] = ""; +$a->strings["Friends"] = ""; +$a->strings["Acquaintances"] = ""; +$a->strings["All"] = ""; +$a->strings["Refresh"] = ""; +$a->strings["Account settings"] = ""; +$a->strings["Channel settings"] = ""; +$a->strings["Additional features"] = ""; +$a->strings["Feature/Addon settings"] = ""; +$a->strings["Display settings"] = ""; +$a->strings["Connected apps"] = ""; +$a->strings["Export channel"] = ""; +$a->strings["Connection Default Permissions"] = ""; +$a->strings["Premium Channel Settings"] = ""; +$a->strings["Settings"] = ""; +$a->strings["Messages"] = ""; +$a->strings["Check Mail"] = ""; +$a->strings["New Message"] = ""; +$a->strings["Chat Rooms"] = ""; +$a->strings["Bookmarked Chatrooms"] = ""; +$a->strings["Suggested Chatrooms"] = ""; +$a->strings["photo/image"] = ""; +$a->strings["Rate Me"] = ""; +$a->strings["View Ratings"] = ""; +$a->strings["Public Hubs"] = ""; +$a->strings["\$Projectname Notification"] = ""; +$a->strings["\$projectname"] = ""; +$a->strings["Thank You,"] = ""; +$a->strings["%s Administrator"] = ""; +$a->strings["%s "] = ""; +$a->strings["[Red:Notify] New mail received at %s"] = ""; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = ""; +$a->strings["%1\$s sent you %2\$s."] = ""; +$a->strings["a private message"] = ""; +$a->strings["Please visit %s to view and/or reply to your private messages."] = ""; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = ""; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = ""; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = ""; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = ""; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = ""; +$a->strings["Please visit %s to view and/or reply to the conversation."] = ""; +$a->strings["[Red:Notify] %s posted to your profile wall"] = ""; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = ""; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = ""; +$a->strings["[Red:Notify] %s tagged you"] = ""; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = ""; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = ""; +$a->strings["[Red:Notify] %1\$s poked you"] = ""; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = ""; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = ""; +$a->strings["[Red:Notify] %s tagged your post"] = ""; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = ""; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = ""; +$a->strings["[Red:Notify] Introduction received"] = ""; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = ""; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = ""; +$a->strings["You may visit their profile at %s"] = ""; +$a->strings["Please visit %s to approve or reject the connection request."] = ""; +$a->strings["[Red:Notify] Friend suggestion received"] = ""; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = ""; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = ""; +$a->strings["Name:"] = ""; +$a->strings["Photo:"] = ""; +$a->strings["Please visit %s to approve or reject the suggestion."] = ""; +$a->strings["[Red:Notify]"] = ""; +$a->strings["Frequently"] = ""; +$a->strings["Hourly"] = ""; +$a->strings["Twice daily"] = ""; +$a->strings["Daily"] = ""; +$a->strings["Weekly"] = ""; +$a->strings["Monthly"] = ""; +$a->strings["Friendica"] = ""; +$a->strings["OStatus"] = ""; +$a->strings["RSS/Atom"] = ""; +$a->strings["Email"] = ""; +$a->strings["Diaspora"] = ""; +$a->strings["Facebook"] = ""; +$a->strings["Zot!"] = ""; +$a->strings["LinkedIn"] = ""; +$a->strings["XMPP/IM"] = ""; +$a->strings["MySpace"] = ""; +$a->strings["No recipient provided."] = ""; +$a->strings["[no subject]"] = ""; +$a->strings["Unable to determine sender."] = ""; +$a->strings["Stored post could not be verified."] = ""; +$a->strings["Channel is blocked on this site."] = ""; +$a->strings["Channel location missing."] = ""; +$a->strings["Response from remote channel was incomplete."] = ""; +$a->strings["Channel was deleted and no longer exists."] = ""; +$a->strings["Protocol disabled."] = ""; +$a->strings["Channel discovery failed."] = ""; +$a->strings["local account not found."] = ""; +$a->strings["Cannot connect to yourself."] = ""; +$a->strings["Private Message"] = ""; +$a->strings["Select"] = ""; +$a->strings["Save to Folder"] = ""; +$a->strings["I will attend"] = ""; +$a->strings["I will not attend"] = ""; +$a->strings["I might attend"] = ""; +$a->strings["I agree"] = ""; +$a->strings["I disagree"] = ""; +$a->strings["I abstain"] = ""; +$a->strings["View all"] = ""; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "", + 1 => "", +); +$a->strings["Add Star"] = ""; +$a->strings["Remove Star"] = ""; +$a->strings["Toggle Star Status"] = ""; +$a->strings["starred"] = ""; +$a->strings["Message signature validated"] = ""; +$a->strings["Message signature incorrect"] = ""; +$a->strings["Add Tag"] = ""; +$a->strings["I like this (toggle)"] = ""; +$a->strings["like"] = ""; +$a->strings["I don't like this (toggle)"] = ""; +$a->strings["dislike"] = ""; +$a->strings["Share This"] = ""; +$a->strings["share"] = ""; +$a->strings["%d comment"] = array( + 0 => "", + 1 => "", +); +$a->strings["View %s's profile - %s"] = ""; +$a->strings["to"] = ""; +$a->strings["via"] = ""; +$a->strings["Wall-to-Wall"] = ""; +$a->strings["via Wall-To-Wall:"] = ""; +$a->strings["from %s"] = ""; +$a->strings["last edited: %s"] = ""; +$a->strings["Expires: %s"] = ""; +$a->strings["Save Bookmarks"] = ""; +$a->strings["Add to Calendar"] = ""; +$a->strings["Mark all seen"] = ""; +$a->strings["__ctx:noun__ Likes"] = ""; +$a->strings["__ctx:noun__ Dislikes"] = ""; +$a->strings["Close"] = ""; +$a->strings["Please wait"] = ""; +$a->strings["This is you"] = ""; +$a->strings["Bold"] = ""; +$a->strings["Italic"] = ""; +$a->strings["Underline"] = ""; +$a->strings["Quote"] = ""; +$a->strings["Code"] = ""; +$a->strings["Image"] = ""; +$a->strings["Insert Link"] = ""; +$a->strings["Video"] = ""; +$a->strings["Encrypt text"] = ""; +$a->strings["New window"] = ""; +$a->strings["Open the selected location in a different window or browser tab"] = ""; +$a->strings["User '%s' deleted"] = ""; +$a->strings["Attachments:"] = ""; +$a->strings["\$Projectname event notification:"] = ""; +$a->strings["prev"] = ""; +$a->strings["first"] = ""; +$a->strings["last"] = ""; +$a->strings["next"] = ""; +$a->strings["older"] = ""; +$a->strings["newer"] = ""; +$a->strings["No connections"] = ""; +$a->strings["%d Connection"] = array( + 0 => "", + 1 => "", +); +$a->strings["View Connections"] = ""; +$a->strings["Search"] = ""; +$a->strings["poke"] = ""; +$a->strings["poked"] = ""; +$a->strings["ping"] = ""; +$a->strings["pinged"] = ""; +$a->strings["prod"] = ""; +$a->strings["prodded"] = ""; +$a->strings["slap"] = ""; +$a->strings["slapped"] = ""; +$a->strings["finger"] = ""; +$a->strings["fingered"] = ""; +$a->strings["rebuff"] = ""; +$a->strings["rebuffed"] = ""; +$a->strings["happy"] = ""; +$a->strings["sad"] = ""; +$a->strings["mellow"] = ""; +$a->strings["tired"] = ""; +$a->strings["perky"] = ""; +$a->strings["angry"] = ""; +$a->strings["stupified"] = ""; +$a->strings["puzzled"] = ""; +$a->strings["interested"] = ""; +$a->strings["bitter"] = ""; +$a->strings["cheerful"] = ""; +$a->strings["alive"] = ""; +$a->strings["annoyed"] = ""; +$a->strings["anxious"] = ""; +$a->strings["cranky"] = ""; +$a->strings["disturbed"] = ""; +$a->strings["frustrated"] = ""; +$a->strings["depressed"] = ""; +$a->strings["motivated"] = ""; +$a->strings["relaxed"] = ""; +$a->strings["surprised"] = ""; +$a->strings["Monday"] = ""; +$a->strings["Tuesday"] = ""; +$a->strings["Wednesday"] = ""; +$a->strings["Thursday"] = ""; +$a->strings["Friday"] = ""; +$a->strings["Saturday"] = ""; +$a->strings["Sunday"] = ""; +$a->strings["January"] = ""; +$a->strings["February"] = ""; +$a->strings["March"] = ""; +$a->strings["April"] = ""; +$a->strings["May"] = ""; +$a->strings["June"] = ""; +$a->strings["July"] = ""; +$a->strings["August"] = ""; +$a->strings["September"] = ""; +$a->strings["October"] = ""; +$a->strings["November"] = ""; +$a->strings["December"] = ""; +$a->strings["unknown.???"] = ""; +$a->strings["bytes"] = ""; +$a->strings["remove category"] = ""; +$a->strings["remove from file"] = ""; +$a->strings["Click to open/close"] = ""; +$a->strings["Link to Source"] = ""; +$a->strings["default"] = ""; +$a->strings["Page layout"] = ""; +$a->strings["You can create your own with the layouts tool"] = ""; +$a->strings["Page content type"] = ""; +$a->strings["Select an alternate language"] = ""; +$a->strings["photo"] = ""; +$a->strings["event"] = ""; +$a->strings["status"] = ""; +$a->strings["comment"] = ""; +$a->strings["activity"] = ""; +$a->strings["Design Tools"] = ""; +$a->strings["Blocks"] = ""; +$a->strings["Menus"] = ""; +$a->strings["Layouts"] = ""; +$a->strings["Pages"] = ""; +$a->strings["Logout"] = ""; +$a->strings["End this session"] = ""; +$a->strings["Home"] = ""; +$a->strings["Your posts and conversations"] = ""; +$a->strings["View Profile"] = ""; +$a->strings["Your profile page"] = ""; +$a->strings["Edit Profiles"] = ""; +$a->strings["Manage/Edit profiles"] = ""; +$a->strings["Edit Profile"] = ""; +$a->strings["Edit your profile"] = ""; +$a->strings["Photos"] = ""; +$a->strings["Your photos"] = ""; +$a->strings["Your files"] = ""; +$a->strings["Chat"] = ""; +$a->strings["Your chatrooms"] = ""; +$a->strings["Bookmarks"] = ""; +$a->strings["Your bookmarks"] = ""; +$a->strings["Webpages"] = ""; +$a->strings["Your webpages"] = ""; +$a->strings["Login"] = ""; +$a->strings["Sign in"] = ""; +$a->strings["%s - click to logout"] = ""; +$a->strings["Remote authentication"] = ""; +$a->strings["Click to authenticate to your home hub"] = ""; +$a->strings["Home Page"] = ""; +$a->strings["Register"] = ""; +$a->strings["Create an account"] = ""; +$a->strings["Help"] = ""; +$a->strings["Help and documentation"] = ""; +$a->strings["Applications, utilities, links, games"] = ""; +$a->strings["Search site content"] = ""; +$a->strings["Directory"] = ""; +$a->strings["Channel Directory"] = ""; +$a->strings["Matrix"] = ""; +$a->strings["Your matrix"] = ""; +$a->strings["Mark all matrix notifications seen"] = ""; +$a->strings["Channel Home"] = ""; +$a->strings["Channel home"] = ""; +$a->strings["Mark all channel notifications seen"] = ""; +$a->strings["Connections"] = ""; +$a->strings["Notices"] = ""; +$a->strings["Notifications"] = ""; +$a->strings["See all notifications"] = ""; +$a->strings["Mark all system notifications seen"] = ""; +$a->strings["Mail"] = ""; +$a->strings["Private mail"] = ""; +$a->strings["See all private messages"] = ""; +$a->strings["Mark all private messages seen"] = ""; +$a->strings["Inbox"] = ""; +$a->strings["Outbox"] = ""; +$a->strings["Events"] = ""; +$a->strings["Event Calendar"] = ""; +$a->strings["See all events"] = ""; +$a->strings["Mark all events seen"] = ""; +$a->strings["Channel Manager"] = ""; +$a->strings["Manage Your Channels"] = ""; +$a->strings["Account/Channel Settings"] = ""; +$a->strings["Admin"] = ""; +$a->strings["Site Setup and Configuration"] = ""; +$a->strings["Loading..."] = ""; +$a->strings["@name, #tag, content"] = ""; +$a->strings["Please wait..."] = ""; +$a->strings["Tags"] = ""; +$a->strings["Keywords"] = ""; +$a->strings["have"] = ""; +$a->strings["has"] = ""; +$a->strings["want"] = ""; +$a->strings["wants"] = ""; +$a->strings["likes"] = ""; +$a->strings["dislikes"] = ""; +$a->strings[" and "] = ""; +$a->strings["public profile"] = ""; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = ""; +$a->strings["Visit %1\$s's %2\$s"] = ""; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = ""; +$a->strings["Permission denied"] = ""; +$a->strings["(Unknown)"] = ""; +$a->strings["Visible to anybody on the internet."] = ""; +$a->strings["Visible to you only."] = ""; +$a->strings["Visible to anybody in this network."] = ""; +$a->strings["Visible to anybody authenticated."] = ""; +$a->strings["Visible to anybody on %s."] = ""; +$a->strings["Visible to all connections."] = ""; +$a->strings["Visible to approved connections."] = ""; +$a->strings["Visible to specific connections."] = ""; +$a->strings["Item not found."] = ""; +$a->strings["Permission denied."] = ""; +$a->strings["Collection not found."] = ""; +$a->strings["Collection is empty."] = ""; +$a->strings["Collection: %s"] = ""; +$a->strings["Connection: %s"] = ""; +$a->strings["Connection not found."] = ""; +$a->strings["Can view my normal stream and posts"] = ""; +$a->strings["Can view my default channel profile"] = ""; +$a->strings["Can view my photo albums"] = ""; +$a->strings["Can view my connections"] = ""; +$a->strings["Can view my file storage"] = ""; +$a->strings["Can view my webpages"] = ""; +$a->strings["Can send me their channel stream and posts"] = ""; +$a->strings["Can post on my channel page (\"wall\")"] = ""; +$a->strings["Can comment on or like my posts"] = ""; +$a->strings["Can send me private mail messages"] = ""; +$a->strings["Can post photos to my photo albums"] = ""; +$a->strings["Can like/dislike stuff"] = ""; +$a->strings["Profiles and things other than posts/comments"] = ""; +$a->strings["Can forward to all my channel contacts via post @mentions"] = ""; +$a->strings["Advanced - useful for creating group forum channels"] = ""; +$a->strings["Can chat with me (when available)"] = ""; +$a->strings["Can write to my file storage"] = ""; +$a->strings["Can edit my webpages"] = ""; +$a->strings["Can source my public posts in derived channels"] = ""; +$a->strings["Somewhat advanced - very useful in open communities"] = ""; +$a->strings["Can administer my channel resources"] = ""; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = ""; +$a->strings["Social Networking"] = ""; +$a->strings["Mostly Public"] = ""; +$a->strings["Restricted"] = ""; +$a->strings["Private"] = ""; +$a->strings["Community Forum"] = ""; +$a->strings["Feed Republish"] = ""; +$a->strings["Special Purpose"] = ""; +$a->strings["Celebrity/Soapbox"] = ""; +$a->strings["Group Repository"] = ""; +$a->strings["Other"] = ""; +$a->strings["Custom/Expert Mode"] = ""; +$a->strings["channel"] = ""; +$a->strings["%1\$s likes %2\$s's %3\$s"] = ""; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = ""; +$a->strings["%1\$s is now connected with %2\$s"] = ""; +$a->strings["%1\$s poked %2\$s"] = ""; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = ""; +$a->strings["__ctx:title__ Likes"] = ""; +$a->strings["__ctx:title__ Dislikes"] = ""; +$a->strings["__ctx:title__ Agree"] = ""; +$a->strings["__ctx:title__ Disagree"] = ""; +$a->strings["__ctx:title__ Abstain"] = ""; +$a->strings["__ctx:title__ Attending"] = ""; +$a->strings["__ctx:title__ Not attending"] = ""; +$a->strings["__ctx:title__ Might attend"] = ""; +$a->strings["View %s's profile @ %s"] = ""; +$a->strings["Categories:"] = ""; +$a->strings["Filed under:"] = ""; +$a->strings["View in context"] = ""; +$a->strings["remove"] = ""; +$a->strings["Delete Selected Items"] = ""; +$a->strings["View Source"] = ""; +$a->strings["Follow Thread"] = ""; +$a->strings["View Status"] = ""; +$a->strings["View Photos"] = ""; +$a->strings["Matrix Activity"] = ""; +$a->strings["Edit Contact"] = ""; +$a->strings["Send PM"] = ""; +$a->strings["Poke"] = ""; +$a->strings["%s likes this."] = ""; +$a->strings["%s doesn't like this."] = ""; +$a->strings["%2\$d people like this."] = array( + 0 => "", + 1 => "", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "", + 1 => "", +); +$a->strings["and"] = ""; +$a->strings[", and %d other people"] = array( + 0 => "", + 1 => "", +); +$a->strings["%s like this."] = ""; +$a->strings["%s don't like this."] = ""; +$a->strings["Visible to everybody"] = ""; +$a->strings["Please enter a link URL:"] = ""; +$a->strings["Please enter a video link/URL:"] = ""; +$a->strings["Please enter an audio link/URL:"] = ""; +$a->strings["Tag term:"] = ""; +$a->strings["Save to Folder:"] = ""; +$a->strings["Where are you right now?"] = ""; +$a->strings["Expires YYYY-MM-DD HH:MM"] = ""; +$a->strings["Share"] = ""; +$a->strings["Page link name"] = ""; +$a->strings["Post as"] = ""; +$a->strings["Upload photo"] = ""; +$a->strings["upload photo"] = ""; +$a->strings["Attach file"] = ""; +$a->strings["attach file"] = ""; +$a->strings["Insert web link"] = ""; +$a->strings["web link"] = ""; +$a->strings["Insert video link"] = ""; +$a->strings["video link"] = ""; +$a->strings["Insert audio link"] = ""; +$a->strings["audio link"] = ""; +$a->strings["Set your location"] = ""; +$a->strings["set location"] = ""; +$a->strings["Toggle voting"] = ""; +$a->strings["Clear browser location"] = ""; +$a->strings["clear location"] = ""; +$a->strings["Title (optional)"] = ""; +$a->strings["Categories (optional, comma-separated list)"] = ""; +$a->strings["Permission settings"] = ""; +$a->strings["permissions"] = ""; +$a->strings["Public post"] = ""; +$a->strings["Example: bob@example.com, mary@example.com"] = ""; +$a->strings["Set expiration date"] = ""; +$a->strings["OK"] = ""; +$a->strings["Cancel"] = ""; +$a->strings["Discover"] = ""; +$a->strings["Imported public streams"] = ""; +$a->strings["Commented Order"] = ""; +$a->strings["Sort by Comment Date"] = ""; +$a->strings["Posted Order"] = ""; +$a->strings["Sort by Post Date"] = ""; +$a->strings["Posts that mention or involve you"] = ""; +$a->strings["New"] = ""; +$a->strings["Activity Stream - by date"] = ""; +$a->strings["Starred"] = ""; +$a->strings["Favourite Posts"] = ""; +$a->strings["Spam"] = ""; +$a->strings["Posts flagged as SPAM"] = ""; +$a->strings["Channel"] = ""; +$a->strings["Status Messages and Posts"] = ""; +$a->strings["About"] = ""; +$a->strings["Profile Details"] = ""; +$a->strings["Photo Albums"] = ""; +$a->strings["Files and Storage"] = ""; +$a->strings["Chatrooms"] = ""; +$a->strings["Saved Bookmarks"] = ""; +$a->strings["Manage Webpages"] = ""; +$a->strings["__ctx:noun__ Attending"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Not Attending"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Undecided"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Agree"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Disagree"] = array( + 0 => "", + 1 => "", +); +$a->strings["__ctx:noun__ Abstain"] = array( + 0 => "", + 1 => "", +); +$a->strings["Image/photo"] = ""; +$a->strings["Encrypted content"] = ""; +$a->strings["Install design element: "] = ""; +$a->strings["QR code"] = ""; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = ""; +$a->strings["post"] = ""; +$a->strings["Different viewers will see this text differently"] = ""; +$a->strings["$1 spoiler"] = ""; +$a->strings["$1 wrote:"] = ""; +$a->strings["Image exceeds website size limit of %lu bytes"] = ""; +$a->strings["Image file is empty."] = ""; +$a->strings["Unable to process image"] = ""; +$a->strings["Photo storage failed."] = ""; +$a->strings["Upload New Photos"] = ""; +$a->strings["Invalid data packet"] = ""; +$a->strings["Unable to verify channel signature"] = ""; +$a->strings["Unable to verify site signature for %s"] = ""; +$a->strings["Embedded content"] = ""; +$a->strings["Embedding disabled"] = ""; +$a->strings["Logged out."] = ""; +$a->strings["Failed authentication"] = ""; +$a->strings["Login failed."] = ""; +$a->strings["%d invitation available"] = array( + 0 => "", + 1 => "", +); +$a->strings["Advanced"] = ""; +$a->strings["Find Channels"] = ""; +$a->strings["Enter name or interest"] = ""; +$a->strings["Connect/Follow"] = ""; +$a->strings["Examples: Robert Morgenstein, Fishing"] = ""; +$a->strings["Find"] = ""; +$a->strings["Channel Suggestions"] = ""; +$a->strings["Random Profile"] = ""; +$a->strings["Invite Friends"] = ""; +$a->strings["Advanced example: name=fred and country=iceland"] = ""; +$a->strings["%d connection in common"] = array( + 0 => "", + 1 => "", +); +$a->strings["show more"] = ""; +$a->strings["Visible to your default audience"] = ""; +$a->strings["Show"] = ""; +$a->strings["Don't show"] = ""; +$a->strings["Permissions"] = ""; +$a->strings["Item was not found."] = ""; +$a->strings["No source file."] = ""; +$a->strings["Cannot locate file to replace"] = ""; +$a->strings["Cannot locate file to revise/update"] = ""; +$a->strings["File exceeds size limit of %d"] = ""; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = ""; +$a->strings["File upload failed. Possible system limit or action terminated."] = ""; +$a->strings["Stored file could not be verified. Upload failed."] = ""; +$a->strings["Path not available."] = ""; +$a->strings["Empty pathname"] = ""; +$a->strings["duplicate filename or path"] = ""; +$a->strings["Path not found."] = ""; +$a->strings["mkdir failed."] = ""; +$a->strings["database storage failed."] = ""; +$a->strings["Unable to obtain identity information from database"] = ""; +$a->strings["Empty name"] = ""; +$a->strings["Name too long"] = ""; +$a->strings["No account identifier"] = ""; +$a->strings["Nickname is required."] = ""; +$a->strings["Reserved nickname. Please choose another."] = ""; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = ""; +$a->strings["Unable to retrieve created identity"] = ""; +$a->strings["Default Profile"] = ""; +$a->strings["Requested channel is not available."] = ""; +$a->strings["Requested profile is not available."] = ""; +$a->strings["Change profile photo"] = ""; +$a->strings["Profiles"] = ""; +$a->strings["Manage/edit profiles"] = ""; +$a->strings["Create New Profile"] = ""; +$a->strings["Profile Image"] = ""; +$a->strings["visible to everybody"] = ""; +$a->strings["Edit visibility"] = ""; +$a->strings["Gender:"] = ""; +$a->strings["Status:"] = ""; +$a->strings["Homepage:"] = ""; +$a->strings["Online Now"] = ""; +$a->strings["g A l F d"] = ""; +$a->strings["F d"] = ""; +$a->strings["[today]"] = ""; +$a->strings["Birthday Reminders"] = ""; +$a->strings["Birthdays this week:"] = ""; +$a->strings["[No description]"] = ""; +$a->strings["Event Reminders"] = ""; +$a->strings["Events this week:"] = ""; +$a->strings["Profile"] = ""; +$a->strings["Full Name:"] = ""; +$a->strings["Like this channel"] = ""; +$a->strings["j F, Y"] = ""; +$a->strings["j F"] = ""; +$a->strings["Birthday:"] = ""; +$a->strings["Age:"] = ""; +$a->strings["for %1\$d %2\$s"] = ""; +$a->strings["Sexual Preference:"] = ""; +$a->strings["Hometown:"] = ""; +$a->strings["Tags:"] = ""; +$a->strings["Political Views:"] = ""; +$a->strings["Religion:"] = ""; +$a->strings["About:"] = ""; +$a->strings["Hobbies/Interests:"] = ""; +$a->strings["Likes:"] = ""; +$a->strings["Dislikes:"] = ""; +$a->strings["Contact information and Social Networks:"] = ""; +$a->strings["My other channels:"] = ""; +$a->strings["Musical interests:"] = ""; +$a->strings["Books, literature:"] = ""; +$a->strings["Television:"] = ""; +$a->strings["Film/dance/culture/entertainment:"] = ""; +$a->strings["Love/Romance:"] = ""; +$a->strings["Work/employment:"] = ""; +$a->strings["School/education:"] = ""; +$a->strings["Like this thing"] = ""; +$a->strings["Male"] = ""; +$a->strings["Female"] = ""; +$a->strings["Currently Male"] = ""; +$a->strings["Currently Female"] = ""; +$a->strings["Mostly Male"] = ""; +$a->strings["Mostly Female"] = ""; +$a->strings["Transgender"] = ""; +$a->strings["Intersex"] = ""; +$a->strings["Transsexual"] = ""; +$a->strings["Hermaphrodite"] = ""; +$a->strings["Neuter"] = ""; +$a->strings["Non-specific"] = ""; +$a->strings["Undecided"] = ""; +$a->strings["Males"] = ""; +$a->strings["Females"] = ""; +$a->strings["Gay"] = ""; +$a->strings["Lesbian"] = ""; +$a->strings["No Preference"] = ""; +$a->strings["Bisexual"] = ""; +$a->strings["Autosexual"] = ""; +$a->strings["Abstinent"] = ""; +$a->strings["Virgin"] = ""; +$a->strings["Deviant"] = ""; +$a->strings["Fetish"] = ""; +$a->strings["Oodles"] = ""; +$a->strings["Nonsexual"] = ""; +$a->strings["Single"] = ""; +$a->strings["Lonely"] = ""; +$a->strings["Available"] = ""; +$a->strings["Unavailable"] = ""; +$a->strings["Has crush"] = ""; +$a->strings["Infatuated"] = ""; +$a->strings["Dating"] = ""; +$a->strings["Unfaithful"] = ""; +$a->strings["Sex Addict"] = ""; +$a->strings["Friends/Benefits"] = ""; +$a->strings["Casual"] = ""; +$a->strings["Engaged"] = ""; +$a->strings["Married"] = ""; +$a->strings["Imaginarily married"] = ""; +$a->strings["Partners"] = ""; +$a->strings["Cohabiting"] = ""; +$a->strings["Common law"] = ""; +$a->strings["Happy"] = ""; +$a->strings["Not looking"] = ""; +$a->strings["Swinger"] = ""; +$a->strings["Betrayed"] = ""; +$a->strings["Separated"] = ""; +$a->strings["Unstable"] = ""; +$a->strings["Divorced"] = ""; +$a->strings["Imaginarily divorced"] = ""; +$a->strings["Widowed"] = ""; +$a->strings["Uncertain"] = ""; +$a->strings["It's complicated"] = ""; +$a->strings["Don't care"] = ""; +$a->strings["Ask me"] = ""; +$a->strings["Site Admin"] = ""; +$a->strings["Address Book"] = ""; +$a->strings["Mood"] = ""; +$a->strings["Probe"] = ""; +$a->strings["Suggest"] = ""; +$a->strings["Random Channel"] = ""; +$a->strings["Invite"] = ""; +$a->strings["Features"] = ""; +$a->strings["Language"] = ""; +$a->strings["Post"] = ""; +$a->strings["Profile Photo"] = ""; +$a->strings["Update"] = ""; +$a->strings["Install"] = ""; +$a->strings["Purchase"] = ""; +$a->strings["Missing room name"] = ""; +$a->strings["Duplicate room name"] = ""; +$a->strings["Invalid room specifier."] = ""; +$a->strings["Room not found."] = ""; +$a->strings["Room is full"] = ""; +$a->strings["Please choose"] = ""; +$a->strings["Agree"] = ""; +$a->strings["Disagree"] = ""; +$a->strings["Abstain"] = ""; +$a->strings["projectname"] = ""; +$a->strings["Some blurb about what to do when you're new here"] = ""; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = ""; +$a->strings["Create a new channel"] = ""; +$a->strings["Current Channel"] = ""; +$a->strings["Switch to one of your channels by selecting it."] = ""; +$a->strings["Default Channel"] = ""; +$a->strings["Make Default"] = ""; +$a->strings["%d new messages"] = ""; +$a->strings["%d new introductions"] = ""; +$a->strings["Delegated Channels"] = ""; +$a->strings["Name is required"] = ""; +$a->strings["Key and Secret are required"] = ""; +$a->strings["Diaspora Policy Settings updated."] = ""; +$a->strings["Passwords do not match. Password unchanged."] = ""; +$a->strings["Empty passwords are not allowed. Password unchanged."] = ""; +$a->strings["Password changed."] = ""; +$a->strings["Password update failed. Please try again."] = ""; +$a->strings["Not valid email."] = ""; +$a->strings["Protected email address. Cannot change to that email."] = ""; +$a->strings["System failure storing new email. Please try again."] = ""; +$a->strings["Settings updated."] = ""; +$a->strings["No"] = ""; +$a->strings["Yes"] = ""; +$a->strings["Add application"] = ""; +$a->strings["Name of application"] = ""; +$a->strings["Consumer Key"] = ""; +$a->strings["Automatically generated - change if desired. Max length 20"] = ""; +$a->strings["Consumer Secret"] = ""; +$a->strings["Redirect"] = ""; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = ""; +$a->strings["Icon url"] = ""; +$a->strings["Optional"] = ""; +$a->strings["You can't edit this application."] = ""; +$a->strings["Connected Apps"] = ""; +$a->strings["Client key starts with"] = ""; +$a->strings["No name"] = ""; +$a->strings["Remove authorization"] = ""; +$a->strings["No feature settings configured"] = ""; +$a->strings["Feature/Addon Settings"] = ""; +$a->strings["Settings for the built-in Diaspora emulator"] = ""; +$a->strings["Allow any Diaspora member to comment on your public posts"] = ""; +$a->strings["Diaspora Policy Settings"] = ""; +$a->strings["Prevent your hashtags from being redirected to other sites"] = ""; +$a->strings["Account Settings"] = ""; +$a->strings["Enter New Password:"] = ""; +$a->strings["Confirm New Password:"] = ""; +$a->strings["Leave password fields blank unless changing"] = ""; +$a->strings["Email Address:"] = ""; +$a->strings["Remove Account"] = ""; +$a->strings["Remove this account including all its channels"] = ""; +$a->strings["Off"] = ""; +$a->strings["On"] = ""; +$a->strings["Additional Features"] = ""; +$a->strings["Connector Settings"] = ""; +$a->strings["No special theme for mobile devices"] = ""; +$a->strings["%s - (Experimental)"] = ""; +$a->strings["mobile"] = ""; +$a->strings["Display Settings"] = ""; +$a->strings["Display Theme:"] = ""; +$a->strings["Mobile Theme:"] = ""; +$a->strings["Enable user zoom on mobile devices"] = ""; +$a->strings["Update browser every xx seconds"] = ""; +$a->strings["Minimum of 10 seconds, no maximum"] = ""; +$a->strings["Maximum number of conversations to load at any time:"] = ""; +$a->strings["Maximum of 100 items"] = ""; +$a->strings["Show emoticons (smilies) as images"] = ""; +$a->strings["Link post titles to source"] = ""; +$a->strings["System Page Layout Editor - (advanced)"] = ""; +$a->strings["Use blog/list mode on channel page"] = ""; +$a->strings["(comments displayed separately)"] = ""; +$a->strings["Use blog/list mode on matrix page"] = ""; +$a->strings["Channel page max height of content (in pixels)"] = ""; +$a->strings["click to expand content exceeding this height"] = ""; +$a->strings["Matrix page max height of content (in pixels)"] = ""; +$a->strings["Nobody except yourself"] = ""; +$a->strings["Only those you specifically allow"] = ""; +$a->strings["Approved connections"] = ""; +$a->strings["Any connections"] = ""; +$a->strings["Anybody on this website"] = ""; +$a->strings["Anybody in this network"] = ""; +$a->strings["Anybody authenticated"] = ""; +$a->strings["Anybody on the internet"] = ""; +$a->strings["Publish your default profile in the network directory"] = ""; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = ""; +$a->strings["or"] = ""; +$a->strings["Your channel address is"] = ""; +$a->strings["Channel Settings"] = ""; +$a->strings["Basic Settings"] = ""; +$a->strings["Your Timezone:"] = ""; +$a->strings["Default Post Location:"] = ""; +$a->strings["Geographical location to display on your posts"] = ""; +$a->strings["Use Browser Location:"] = ""; +$a->strings["Adult Content"] = ""; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = ""; +$a->strings["Security and Privacy Settings"] = ""; +$a->strings["Your permissions are already configured. Click to view/adjust"] = ""; +$a->strings["Hide my online presence"] = ""; +$a->strings["Prevents displaying in your profile that you are online"] = ""; +$a->strings["Simple Privacy Settings:"] = ""; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = ""; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = ""; +$a->strings["Private - default private, never open or public"] = ""; +$a->strings["Blocked - default blocked to/from everybody"] = ""; +$a->strings["Allow others to tag your posts"] = ""; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = ""; +$a->strings["Advanced Privacy Settings"] = ""; +$a->strings["Expire other channel content after this many days"] = ""; +$a->strings["0 or blank prevents expiration"] = ""; +$a->strings["Maximum Friend Requests/Day:"] = ""; +$a->strings["May reduce spam activity"] = ""; +$a->strings["Default Post Permissions"] = ""; +$a->strings["(click to open/close)"] = ""; +$a->strings["Channel permissions category:"] = ""; +$a->strings["Maximum private messages per day from unknown people:"] = ""; +$a->strings["Useful to reduce spamming"] = ""; +$a->strings["Notification Settings"] = ""; +$a->strings["By default post a status message when:"] = ""; +$a->strings["accepting a friend request"] = ""; +$a->strings["joining a forum/community"] = ""; +$a->strings["making an interesting profile change"] = ""; +$a->strings["Send a notification email when:"] = ""; +$a->strings["You receive a connection request"] = ""; +$a->strings["Your connections are confirmed"] = ""; +$a->strings["Someone writes on your profile wall"] = ""; +$a->strings["Someone writes a followup comment"] = ""; +$a->strings["You receive a private message"] = ""; +$a->strings["You receive a friend suggestion"] = ""; +$a->strings["You are tagged in a post"] = ""; +$a->strings["You are poked/prodded/etc. in a post"] = ""; +$a->strings["Show visual notifications including:"] = ""; +$a->strings["Unseen matrix activity"] = ""; +$a->strings["Unseen channel activity"] = ""; +$a->strings["Unseen private messages"] = ""; +$a->strings["Recommended"] = ""; +$a->strings["Upcoming events"] = ""; +$a->strings["Events today"] = ""; +$a->strings["Upcoming birthdays"] = ""; +$a->strings["Not available in all themes"] = ""; +$a->strings["System (personal) notifications"] = ""; +$a->strings["System info messages"] = ""; +$a->strings["System critical alerts"] = ""; +$a->strings["New connections"] = ""; +$a->strings["System Registrations"] = ""; +$a->strings["Also show new wall posts, private messages and connections under Notices"] = ""; +$a->strings["Notify me of events this many days in advance"] = ""; +$a->strings["Must be greater than 0"] = ""; +$a->strings["Advanced Account/Page Type Settings"] = ""; +$a->strings["Change the behaviour of this account for special situations"] = ""; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = ""; +$a->strings["Miscellaneous Settings"] = ""; +$a->strings["Personal menu to display in your channel pages"] = ""; +$a->strings["Remove Channel"] = ""; +$a->strings["Remove this channel."] = ""; +$a->strings["Xchan Lookup"] = ""; +$a->strings["Lookup xchan beginning with (or webbie): "] = ""; +$a->strings["Not found."] = ""; +$a->strings["Authorize application connection"] = ""; +$a->strings["Return to your app and insert this Securty Code:"] = ""; +$a->strings["Please login to continue."] = ""; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = ""; +$a->strings["Page Title"] = ""; +$a->strings["Channel added."] = ""; +$a->strings["Tag removed"] = ""; +$a->strings["Remove Item Tag"] = ""; +$a->strings["Select a tag to remove: "] = ""; +$a->strings["Remove"] = ""; +$a->strings["Continue"] = ""; +$a->strings["Premium Channel Setup"] = ""; +$a->strings["Enable premium channel connection restrictions"] = ""; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = ""; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = ""; +$a->strings["Potential connections will then see the following text before proceeding:"] = ""; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = ""; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = ""; +$a->strings["Restricted or Premium Channel"] = ""; +$a->strings["Thing updated"] = ""; +$a->strings["Object store: failed"] = ""; +$a->strings["Thing added"] = ""; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = ""; +$a->strings["Show Thing"] = ""; +$a->strings["item not found."] = ""; +$a->strings["Edit Thing"] = ""; +$a->strings["Select a profile"] = ""; +$a->strings["Post an activity"] = ""; +$a->strings["Only sends to viewers of the applicable profile"] = ""; +$a->strings["Name of thing e.g. something"] = ""; +$a->strings["URL of thing (optional)"] = ""; +$a->strings["URL for photo of thing (optional)"] = ""; +$a->strings["Add Thing to your Profile"] = ""; +$a->strings["Item not available."] = ""; +$a->strings["Fetching URL returns error: %1\$s"] = ""; +$a->strings["\$Projectname"] = ""; +$a->strings["Welcome to %s"] = ""; +$a->strings["Image uploaded but image cropping failed."] = ""; +$a->strings["Image resize failed."] = ""; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = ""; +$a->strings["Image exceeds size limit of %d"] = ""; +$a->strings["Unable to process image."] = ""; +$a->strings["Photo not available."] = ""; +$a->strings["Upload File:"] = ""; +$a->strings["Select a profile:"] = ""; +$a->strings["Upload Profile Photo"] = ""; +$a->strings["skip this step"] = ""; +$a->strings["select a photo from your photo albums"] = ""; +$a->strings["Crop Image"] = ""; +$a->strings["Please adjust the image cropping for optimum viewing."] = ""; +$a->strings["Done Editing"] = ""; +$a->strings["Image uploaded successfully."] = ""; +$a->strings["Image upload failed."] = ""; +$a->strings["Image size reduction [%s] failed."] = ""; +$a->strings["Invalid item."] = ""; +$a->strings["Channel not found."] = ""; +$a->strings["Page not found."] = ""; +$a->strings["Like/Dislike"] = ""; +$a->strings["This action is restricted to members."] = ""; +$a->strings["Please login with your \$Projectname ID or register as a new \$Projectname member to continue."] = ""; +$a->strings["Invalid request."] = ""; +$a->strings["thing"] = ""; +$a->strings["Channel unavailable."] = ""; +$a->strings["Previous action reversed."] = ""; +$a->strings["%1\$s agrees with %2\$s's %3\$s"] = ""; +$a->strings["%1\$s doesn't agree with %2\$s's %3\$s"] = ""; +$a->strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = ""; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = ""; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = ""; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = ""; +$a->strings["Action completed."] = ""; +$a->strings["Thank you."] = ""; +$a->strings["Event can not end before it has started."] = ""; +$a->strings["Unable to generate preview."] = ""; +$a->strings["Event title and start time are required."] = ""; +$a->strings["Event not found."] = ""; +$a->strings["l, F j"] = ""; +$a->strings["Edit event"] = ""; +$a->strings["Delete event"] = ""; +$a->strings["Create New Event"] = ""; +$a->strings["Previous"] = ""; +$a->strings["Next"] = ""; +$a->strings["Export"] = ""; +$a->strings["Event removed"] = ""; +$a->strings["Failed to remove event"] = ""; +$a->strings["Event details"] = ""; +$a->strings["Starting date and Title are required."] = ""; +$a->strings["Categories (comma-separated list)"] = ""; +$a->strings["Event Starts:"] = ""; +$a->strings["Finish date/time is not known or not relevant"] = ""; +$a->strings["Event Finishes:"] = ""; +$a->strings["Adjust for viewer timezone"] = ""; +$a->strings["Important for events that happen in a particular place. Not practical for global holidays."] = ""; +$a->strings["Description:"] = ""; +$a->strings["Title:"] = ""; +$a->strings["Share this event"] = ""; +$a->strings["%1\$s is following %2\$s's %3\$s"] = ""; +$a->strings["Public Sites"] = ""; +$a->strings["The listed sites allow public registration for the \$Projectname network. All sites in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = ""; +$a->strings["Rate this hub"] = ""; +$a->strings["Site URL"] = ""; +$a->strings["Access Type"] = ""; +$a->strings["Registration Policy"] = ""; +$a->strings["Location"] = ""; +$a->strings["View hub ratings"] = ""; +$a->strings["Rate"] = ""; +$a->strings["View ratings"] = ""; +$a->strings["Edit post"] = ""; +$a->strings["\$Projectname channel"] = ""; +$a->strings["Collection created."] = ""; +$a->strings["Could not create collection."] = ""; +$a->strings["Collection updated."] = ""; +$a->strings["Create a collection of channels."] = ""; +$a->strings["Collection Name: "] = ""; +$a->strings["Members are visible to other channels"] = ""; +$a->strings["Collection removed."] = ""; +$a->strings["Unable to remove collection."] = ""; +$a->strings["Collection Editor"] = ""; +$a->strings["Members"] = ""; +$a->strings["All Connected Channels"] = ""; +$a->strings["Click on a channel to add or remove."] = ""; +$a->strings["Version %s"] = ""; +$a->strings["Installed plugins/addons/apps:"] = ""; +$a->strings["No installed plugins/addons/apps"] = ""; +$a->strings["This is a hub of \$Projectname - a global cooperative network of decentralized privacy enhanced websites."] = ""; +$a->strings["Tag: "] = ""; +$a->strings["Last background fetch: "] = ""; +$a->strings["Running at web location"] = ""; +$a->strings["Please visit redmatrix.me to learn more about \$Projectname."] = ""; +$a->strings["Bug reports and issues: please visit"] = ""; +$a->strings["Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot com"] = ""; +$a->strings["Site Administrators"] = ""; +$a->strings["Help:"] = ""; +$a->strings["Not Found"] = ""; +$a->strings["\$Projectname Server - Setup"] = ""; +$a->strings["Could not connect to database."] = ""; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = ""; +$a->strings["Could not create table."] = ""; +$a->strings["Your site database has been installed."] = ""; +$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = ""; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = ""; +$a->strings["System check"] = ""; +$a->strings["Check again"] = ""; +$a->strings["Database connection"] = ""; +$a->strings["In order to install \$Projectname we need to know how to connect to your database."] = ""; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = ""; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = ""; +$a->strings["Database Server Name"] = ""; +$a->strings["Default is localhost"] = ""; +$a->strings["Database Port"] = ""; +$a->strings["Communication port number - use 0 for default"] = ""; +$a->strings["Database Login Name"] = ""; +$a->strings["Database Login Password"] = ""; +$a->strings["Database Name"] = ""; +$a->strings["Database Type"] = ""; +$a->strings["Site administrator email address"] = ""; +$a->strings["Your account email address must match this in order to use the web admin panel."] = ""; +$a->strings["Website URL"] = ""; +$a->strings["Please use SSL (https) URL if available."] = ""; +$a->strings["Please select a default timezone for your website"] = ""; +$a->strings["Site settings"] = ""; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = ""; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = ""; +$a->strings["PHP executable path"] = ""; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = ""; +$a->strings["Command line PHP"] = ""; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = ""; +$a->strings["This is required for message delivery to work."] = ""; +$a->strings["PHP register_argc_argv"] = ""; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = ""; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = ""; +$a->strings["Generate encryption keys"] = ""; +$a->strings["libCurl PHP module"] = ""; +$a->strings["GD graphics PHP module"] = ""; +$a->strings["OpenSSL PHP module"] = ""; +$a->strings["mysqli or postgres PHP module"] = ""; +$a->strings["mb_string PHP module"] = ""; +$a->strings["mcrypt PHP module"] = ""; +$a->strings["Apache mod_rewrite module"] = ""; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = ""; +$a->strings["proc_open"] = ""; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = ""; +$a->strings["Error: libCURL PHP module required but not installed."] = ""; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = ""; +$a->strings["Error: openssl PHP module required but not installed."] = ""; +$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = ""; +$a->strings["Error: mb_string PHP module required but not installed."] = ""; +$a->strings["Error: mcrypt PHP module required but not installed."] = ""; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = ""; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = ""; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = ""; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = ""; +$a->strings[".htconfig.php is writable"] = ""; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = ""; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = ""; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = ""; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = ""; +$a->strings["%s is writable"] = ""; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = ""; +$a->strings["store is writable"] = ""; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = ""; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = ""; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = ""; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = ""; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = ""; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = ""; +$a->strings["SSL certificate validation"] = ""; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = ""; +$a->strings["Url rewrite is working"] = ""; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = ""; +$a->strings["Errors encountered creating database tables."] = ""; +$a->strings["

    What next

    "] = ""; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = ""; +$a->strings["No channel."] = ""; +$a->strings["Common connections"] = ""; +$a->strings["No connections in common."] = ""; +$a->strings["This site is not a directory server"] = ""; +$a->strings["Could not access contact record."] = ""; +$a->strings["Could not locate selected profile."] = ""; +$a->strings["Connection updated."] = ""; +$a->strings["Failed to update connection record."] = ""; +$a->strings["Blocked"] = ""; +$a->strings["Ignored"] = ""; +$a->strings["Hidden"] = ""; +$a->strings["Archived"] = ""; +$a->strings["Suggest new connections"] = ""; +$a->strings["New Connections"] = ""; +$a->strings["Show pending (new) connections"] = ""; +$a->strings["All Connections"] = ""; +$a->strings["Show all connections"] = ""; +$a->strings["Unblocked"] = ""; +$a->strings["Only show unblocked connections"] = ""; +$a->strings["Only show blocked connections"] = ""; +$a->strings["Only show ignored connections"] = ""; +$a->strings["Only show archived connections"] = ""; +$a->strings["Only show hidden connections"] = ""; +$a->strings["%1\$s [%2\$s]"] = ""; +$a->strings["Edit connection"] = ""; +$a->strings["Search your connections"] = ""; +$a->strings["Finding: "] = ""; +$a->strings["Block Name"] = ""; +$a->strings["Block Title"] = ""; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = ""; +$a->strings["\$Projectname - Guests: Username: {your email address}, Password: +++"] = ""; +$a->strings["Page owner information could not be retrieved."] = ""; +$a->strings["Album not found."] = ""; +$a->strings["Delete Album"] = ""; +$a->strings["Delete Photo"] = ""; +$a->strings["Public access denied."] = ""; +$a->strings["No photos selected"] = ""; +$a->strings["Access to this item is restricted."] = ""; +$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = ""; +$a->strings["%1$.2f MB photo storage used."] = ""; +$a->strings["Upload Photos"] = ""; +$a->strings["Enter a new album name"] = ""; +$a->strings["or select an existing one (doubleclick)"] = ""; +$a->strings["Create a status post for this upload"] = ""; +$a->strings["Album name could not be decoded"] = ""; +$a->strings["Contact Photos"] = ""; +$a->strings["Show Newest First"] = ""; +$a->strings["Show Oldest First"] = ""; +$a->strings["View Photo"] = ""; +$a->strings["Edit Album"] = ""; +$a->strings["Permission denied. Access to this item may be restricted."] = ""; +$a->strings["Photo not available"] = ""; +$a->strings["Use as profile photo"] = ""; +$a->strings["Private Photo"] = ""; +$a->strings["View Full Size"] = ""; +$a->strings["Edit photo"] = ""; +$a->strings["Rotate CW (right)"] = ""; +$a->strings["Rotate CCW (left)"] = ""; +$a->strings["Caption"] = ""; +$a->strings["Add a Tag"] = ""; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = ""; +$a->strings["Flag as adult in album view"] = ""; +$a->strings["In This Photo:"] = ""; +$a->strings["Map"] = ""; +$a->strings["View Album"] = ""; +$a->strings["Recent Photos"] = ""; +$a->strings["Profile Match"] = ""; +$a->strings["No keywords to match. Please add keywords to your default profile."] = ""; +$a->strings["is interested in:"] = ""; +$a->strings["No matches"] = ""; +$a->strings["Away"] = ""; +$a->strings["Online"] = ""; +$a->strings["Select a bookmark folder"] = ""; +$a->strings["Save Bookmark"] = ""; +$a->strings["URL of bookmark"] = ""; +$a->strings["Description"] = ""; +$a->strings["Or enter new bookmark folder name"] = ""; +$a->strings["No more system notifications."] = ""; +$a->strings["System Notifications"] = ""; +$a->strings["network"] = ""; +$a->strings["RSS"] = ""; +$a->strings["Layout updated."] = ""; +$a->strings["Edit System Page Description"] = ""; +$a->strings["Layout not found."] = ""; +$a->strings["Module Name:"] = ""; +$a->strings["Layout Help"] = ""; +$a->strings["- select -"] = ""; +$a->strings["Your service plan only allows %d channels."] = ""; +$a->strings["Nothing to import."] = ""; +$a->strings["Unable to download data from old server"] = ""; +$a->strings["Imported file is empty."] = ""; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = ""; +$a->strings["Unable to create a unique channel address. Import failed."] = ""; +$a->strings["Channel clone failed. Import failed."] = ""; +$a->strings["Cloned channel not found. Import failed."] = ""; +$a->strings["Import completed."] = ""; +$a->strings["You must be logged in to use this feature."] = ""; +$a->strings["Import Channel"] = ""; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = ""; +$a->strings["File to Upload"] = ""; +$a->strings["Or provide the old server/hub details"] = ""; +$a->strings["Your old identity address (xyz@example.com)"] = ""; +$a->strings["Your old login email address"] = ""; +$a->strings["Your old login password"] = ""; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = ""; +$a->strings["Make this hub my primary location"] = ""; +$a->strings["Import existing posts if possible"] = ""; +$a->strings["Item not found"] = ""; +$a->strings["Edit Layout"] = ""; +$a->strings["Delete layout?"] = ""; +$a->strings["Insert YouTube video"] = ""; +$a->strings["Insert Vorbis [.ogg] video"] = ""; +$a->strings["Insert Vorbis [.ogg] audio"] = ""; +$a->strings["Layout Description (Optional)"] = ""; +$a->strings["Layout Name"] = ""; +$a->strings["You must be logged in to see this page."] = ""; +$a->strings["Room not found"] = ""; +$a->strings["Leave Room"] = ""; +$a->strings["Delete This Room"] = ""; +$a->strings["I am away right now"] = ""; +$a->strings["I am online"] = ""; +$a->strings["Bookmark this room"] = ""; +$a->strings["New Chatroom"] = ""; +$a->strings["Chatroom Name"] = ""; +$a->strings["%1\$s's Chatrooms"] = ""; +$a->strings["Delete webpage?"] = ""; +$a->strings["Page link title"] = ""; +$a->strings["Edit Webpage"] = ""; +$a->strings["This directory server requires an access token"] = ""; +$a->strings["No valid account found."] = ""; +$a->strings["Password reset request issued. Check your email."] = ""; +$a->strings["Site Member (%s)"] = ""; +$a->strings["Password reset requested at %s"] = ""; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = ""; +$a->strings["Password Reset"] = ""; +$a->strings["Your password has been reset as requested."] = ""; +$a->strings["Your new password is"] = ""; +$a->strings["Save or copy your new password - and then"] = ""; +$a->strings["click here to login"] = ""; +$a->strings["Your password may be changed from the Settings page after successful login."] = ""; +$a->strings["Your password has changed at %s"] = ""; +$a->strings["Forgot your Password?"] = ""; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = ""; +$a->strings["Email Address"] = ""; +$a->strings["Reset"] = ""; +$a->strings["Website:"] = ""; +$a->strings["Remote Channel [%s] (not yet known on this site)"] = ""; +$a->strings["Rating (this information is public)"] = ""; +$a->strings["Optionally explain your rating (this information is public)"] = ""; +$a->strings["Item is not editable"] = ""; +$a->strings["Delete item?"] = ""; +$a->strings["Total invitation limit exceeded."] = ""; +$a->strings["%s : Not a valid email address."] = ""; +$a->strings["Please join us on Red"] = ""; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = ""; +$a->strings["%s : Message delivery failed."] = ""; +$a->strings["%d message sent."] = array( + 0 => "", + 1 => "", +); +$a->strings["You have no more invitations available"] = ""; +$a->strings["Send invitations"] = ""; +$a->strings["Enter email addresses, one per line:"] = ""; +$a->strings["Your message:"] = ""; +$a->strings["Please join my community on \$Projectname."] = ""; +$a->strings["You will need to supply this invitation code: "] = ""; +$a->strings["1. Register at any \$Projectname location (they are all inter-connected)"] = ""; +$a->strings["2. Enter my \$Projectname network address into the site searchbar."] = ""; +$a->strings["or visit "] = ""; +$a->strings["3. Click [Connect]"] = ""; +$a->strings["Location not found."] = ""; +$a->strings["Primary location cannot be removed."] = ""; +$a->strings["No locations found."] = ""; +$a->strings["Manage Channel Locations"] = ""; +$a->strings["Location (address)"] = ""; +$a->strings["Primary Location"] = ""; +$a->strings["Drop location"] = ""; +$a->strings["Failed to create source. No channel selected."] = ""; +$a->strings["Source created."] = ""; +$a->strings["Source updated."] = ""; +$a->strings["*"] = ""; +$a->strings["Manage remote sources of content for your channel."] = ""; +$a->strings["New Source"] = ""; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = ""; +$a->strings["Only import content with these words (one per line)"] = ""; +$a->strings["Leave blank to import all public content"] = ""; +$a->strings["Channel Name"] = ""; +$a->strings["Source not found."] = ""; +$a->strings["Edit Source"] = ""; +$a->strings["Delete Source"] = ""; +$a->strings["Source removed"] = ""; +$a->strings["Unable to remove source."] = ""; +$a->strings["Unable to update menu."] = ""; +$a->strings["Unable to create menu."] = ""; +$a->strings["Menu Name"] = ""; +$a->strings["Unique name (not visible on webpage) - required"] = ""; +$a->strings["Menu Title"] = ""; +$a->strings["Visible on webpage - leave empty for no title"] = ""; +$a->strings["Allow Bookmarks"] = ""; +$a->strings["Menu may be used to store saved bookmarks"] = ""; +$a->strings["Submit and proceed"] = ""; +$a->strings["Drop"] = ""; +$a->strings["Bookmarks allowed"] = ""; +$a->strings["Delete this menu"] = ""; +$a->strings["Edit menu contents"] = ""; +$a->strings["Edit this menu"] = ""; +$a->strings["Menu could not be deleted."] = ""; +$a->strings["Menu not found."] = ""; +$a->strings["Edit Menu"] = ""; +$a->strings["Add or remove entries to this menu"] = ""; +$a->strings["Menu name"] = ""; +$a->strings["Must be unique, only seen by you"] = ""; +$a->strings["Menu title"] = ""; +$a->strings["Menu title as seen by others"] = ""; +$a->strings["Allow bookmarks"] = ""; +$a->strings["Modify"] = ""; +$a->strings["Permission Denied."] = ""; +$a->strings["File not found."] = ""; +$a->strings["Edit file permissions"] = ""; +$a->strings["Set/edit permissions"] = ""; +$a->strings["Include all files and sub folders"] = ""; +$a->strings["Return to file list"] = ""; +$a->strings["Copy/paste this code to attach file to a post"] = ""; +$a->strings["Copy/paste this URL to link file from a web page"] = ""; +$a->strings["Share this file"] = ""; +$a->strings["Show URL to this file"] = ""; +$a->strings["Notify your contacts about this file"] = ""; +$a->strings["Contact not found."] = ""; +$a->strings["Friend suggestion sent."] = ""; +$a->strings["Suggest Friends"] = ""; +$a->strings["Suggest a friend for %s"] = ""; +$a->strings["Hub not found."] = ""; +$a->strings["Poke/Prod"] = ""; +$a->strings["poke, prod or do other things to somebody"] = ""; +$a->strings["Recipient"] = ""; +$a->strings["Choose what you wish to do to recipient"] = ""; +$a->strings["Make this post private"] = ""; +$a->strings["Invalid profile identifier."] = ""; +$a->strings["Profile Visibility Editor"] = ""; +$a->strings["Click on a contact to add or remove."] = ""; +$a->strings["Visible To"] = ""; +$a->strings["webpage"] = ""; +$a->strings["block"] = ""; +$a->strings["layout"] = ""; +$a->strings["%s element installed"] = ""; +$a->strings["Profile not found."] = ""; +$a->strings["Profile deleted."] = ""; +$a->strings["Profile-"] = ""; +$a->strings["New profile created."] = ""; +$a->strings["Profile unavailable to clone."] = ""; +$a->strings["Profile unavailable to export."] = ""; +$a->strings["Profile Name is required."] = ""; +$a->strings["Marital Status"] = ""; +$a->strings["Romantic Partner"] = ""; +$a->strings["Likes"] = ""; +$a->strings["Dislikes"] = ""; +$a->strings["Work/Employment"] = ""; +$a->strings["Religion"] = ""; +$a->strings["Political Views"] = ""; +$a->strings["Gender"] = ""; +$a->strings["Sexual Preference"] = ""; +$a->strings["Homepage"] = ""; +$a->strings["Interests"] = ""; +$a->strings["Address"] = ""; +$a->strings["Profile updated."] = ""; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = ""; +$a->strings["Edit Profile Details"] = ""; +$a->strings["View this profile"] = ""; +$a->strings["Change Profile Photo"] = ""; +$a->strings["Create a new profile using these settings"] = ""; +$a->strings["Clone this profile"] = ""; +$a->strings["Delete this profile"] = ""; +$a->strings["Import profile from file"] = ""; +$a->strings["Export profile to file"] = ""; +$a->strings["Profile Name:"] = ""; +$a->strings["Your Full Name:"] = ""; +$a->strings["Title/Description:"] = ""; +$a->strings["Your Gender:"] = ""; +$a->strings["Birthday :"] = ""; +$a->strings["Street Address:"] = ""; +$a->strings["Locality/City:"] = ""; +$a->strings["Postal/Zip Code:"] = ""; +$a->strings["Country:"] = ""; +$a->strings["Region/State:"] = ""; +$a->strings[" Marital Status:"] = ""; +$a->strings["Who: (if applicable)"] = ""; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = ""; +$a->strings["Since [date]:"] = ""; +$a->strings["Homepage URL:"] = ""; +$a->strings["Religious Views:"] = ""; +$a->strings["Keywords:"] = ""; +$a->strings["Example: fishing photography software"] = ""; +$a->strings["Used in directory listings"] = ""; +$a->strings["Tell us about yourself..."] = ""; +$a->strings["Hobbies/Interests"] = ""; +$a->strings["Contact information and Social Networks"] = ""; +$a->strings["My other channels"] = ""; +$a->strings["Musical interests"] = ""; +$a->strings["Books, literature"] = ""; +$a->strings["Television"] = ""; +$a->strings["Film/dance/culture/entertainment"] = ""; +$a->strings["Love/romance"] = ""; +$a->strings["Work/employment"] = ""; +$a->strings["School/education"] = ""; +$a->strings["This is your default profile."] = ""; +$a->strings["Age: "] = ""; +$a->strings["Edit/Manage Profiles"] = ""; +$a->strings["Add profile things"] = ""; +$a->strings["Include desirable objects in your profile"] = ""; +$a->strings["No ratings"] = ""; +$a->strings["Ratings"] = ""; +$a->strings["Rating: "] = ""; +$a->strings["Website: "] = ""; +$a->strings["Description: "] = ""; +$a->strings["Source of Item"] = ""; +$a->strings["OpenID protocol error. No ID returned."] = ""; +$a->strings["Welcome %s. Remote authentication successful."] = ""; +$a->strings["%d rating"] = array( + 0 => "", + 1 => "", +); +$a->strings["Gender: "] = ""; +$a->strings["Status: "] = ""; +$a->strings["Homepage: "] = ""; +$a->strings["Hometown: "] = ""; +$a->strings["About: "] = ""; +$a->strings["Public Forum:"] = ""; +$a->strings["Keywords: "] = ""; +$a->strings["Common connections: %s"] = ""; +$a->strings["Finding:"] = ""; +$a->strings["next page"] = ""; +$a->strings["previous page"] = ""; +$a->strings["No entries (some entries may be hidden)."] = ""; +$a->strings["Export Channel"] = ""; +$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = ""; +$a->strings["Export Content"] = ""; +$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = ""; +$a->strings["No connections."] = ""; +$a->strings["Visit %s's profile [%s]"] = ""; +$a->strings["invalid target signature"] = ""; +$a->strings["Theme settings updated."] = ""; +$a->strings["Site"] = ""; +$a->strings["Accounts"] = ""; +$a->strings["Channels"] = ""; +$a->strings["Plugins"] = ""; +$a->strings["Themes"] = ""; +$a->strings["Inspect queue"] = ""; +$a->strings["Profile Config"] = ""; +$a->strings["DB updates"] = ""; +$a->strings["Logs"] = ""; +$a->strings["Plugin Features"] = ""; +$a->strings["User registrations waiting for confirmation"] = ""; +$a->strings["# Accounts"] = ""; +$a->strings["# blocked accounts"] = ""; +$a->strings["# expired accounts"] = ""; +$a->strings["# expiring accounts"] = ""; +$a->strings["# Channels"] = ""; +$a->strings["# primary"] = ""; +$a->strings["# clones"] = ""; +$a->strings["Message queues"] = ""; +$a->strings["Administration"] = ""; +$a->strings["Summary"] = ""; +$a->strings["Registered accounts"] = ""; +$a->strings["Pending registrations"] = ""; +$a->strings["Registered channels"] = ""; +$a->strings["Active plugins"] = ""; +$a->strings["Version"] = ""; +$a->strings["Site settings updated."] = ""; +$a->strings["experimental"] = ""; +$a->strings["unsupported"] = ""; +$a->strings["Yes - with approval"] = ""; +$a->strings["My site is not a public server"] = ""; +$a->strings["My site has paid access only"] = ""; +$a->strings["My site has free access only"] = ""; +$a->strings["My site offers free accounts with optional paid upgrades"] = ""; +$a->strings["Registration"] = ""; +$a->strings["File upload"] = ""; +$a->strings["Policies"] = ""; +$a->strings["Site name"] = ""; +$a->strings["Banner/Logo"] = ""; +$a->strings["Administrator Information"] = ""; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = ""; +$a->strings["System language"] = ""; +$a->strings["System theme"] = ""; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = ""; +$a->strings["Mobile system theme"] = ""; +$a->strings["Theme for mobile devices"] = ""; +$a->strings["Enable Diaspora Protocol"] = ""; +$a->strings["Communicate with Diaspora and Friendica - experimental"] = ""; +$a->strings["Allow Feeds as Connections"] = ""; +$a->strings["(Heavy system resource usage)"] = ""; +$a->strings["Maximum image size"] = ""; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = ""; +$a->strings["Does this site allow new member registration?"] = ""; +$a->strings["Which best describes the types of account offered by this hub?"] = ""; +$a->strings["Register text"] = ""; +$a->strings["Will be displayed prominently on the registration page."] = ""; +$a->strings["Accounts abandoned after x days"] = ""; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = ""; +$a->strings["Allowed friend domains"] = ""; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = ""; +$a->strings["Allowed email domains"] = ""; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = ""; +$a->strings["Not allowed email domains"] = ""; +$a->strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = ""; +$a->strings["Block public"] = ""; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = ""; +$a->strings["Verify Email Addresses"] = ""; +$a->strings["Check to verify email addresses used in account registration (recommended)."] = ""; +$a->strings["Force publish"] = ""; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = ""; +$a->strings["Disable discovery tab"] = ""; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = ""; +$a->strings["No login on Homepage"] = ""; +$a->strings["Check to hide the login form from your sites homepage when visitors arrive who are not logged in (e.g. when you put the content of the homepage in via the site channel)."] = ""; +$a->strings["Proxy user"] = ""; +$a->strings["Proxy URL"] = ""; +$a->strings["Network timeout"] = ""; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = ""; +$a->strings["Delivery interval"] = ""; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = ""; +$a->strings["Poll interval"] = ""; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = ""; +$a->strings["Maximum Load Average"] = ""; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = ""; +$a->strings["Expiration period in days for imported (matrix/network) content"] = ""; +$a->strings["0 for no expiration of imported content"] = ""; +$a->strings["No server found"] = ""; +$a->strings["ID"] = ""; +$a->strings["for channel"] = ""; +$a->strings["on server"] = ""; +$a->strings["Status"] = ""; +$a->strings["Server"] = ""; +$a->strings["Update has been marked successful"] = ""; +$a->strings["Executing %s failed. Check system logs."] = ""; +$a->strings["Update %s was successfully applied."] = ""; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = ""; +$a->strings["Update function %s could not be found."] = ""; +$a->strings["No failed updates."] = ""; +$a->strings["Failed Updates"] = ""; +$a->strings["Mark success (if update was manually applied)"] = ""; +$a->strings["Attempt to execute this update step automatically"] = ""; +$a->strings["Queue Statistics"] = ""; +$a->strings["Total Entries"] = ""; +$a->strings["Priority"] = ""; +$a->strings["Destination URL"] = ""; +$a->strings["Mark hub permanently offline"] = ""; +$a->strings["Empty queue for this hub"] = ""; +$a->strings["Last known contact"] = ""; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "", + 1 => "", +); +$a->strings["%s user deleted"] = array( + 0 => "", + 1 => "", +); +$a->strings["Account not found"] = ""; +$a->strings["User '%s' blocked"] = ""; +$a->strings["User '%s' unblocked"] = ""; +$a->strings["Users"] = ""; +$a->strings["select all"] = ""; +$a->strings["User registrations waiting for confirm"] = ""; +$a->strings["Request date"] = ""; +$a->strings["No registrations."] = ""; +$a->strings["Approve"] = ""; +$a->strings["Deny"] = ""; +$a->strings["Block"] = ""; +$a->strings["Unblock"] = ""; +$a->strings["Register date"] = ""; +$a->strings["Last login"] = ""; +$a->strings["Expires"] = ""; +$a->strings["Service Class"] = ""; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "", + 1 => "", +); +$a->strings["%s channel deleted"] = array( + 0 => "", + 1 => "", +); +$a->strings["Channel not found"] = ""; +$a->strings["Channel '%s' deleted"] = ""; +$a->strings["Channel '%s' uncensored"] = ""; +$a->strings["Channel '%s' censored"] = ""; +$a->strings["Censor"] = ""; +$a->strings["Uncensor"] = ""; +$a->strings["UID"] = ""; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = ""; +$a->strings["Plugin %s disabled."] = ""; +$a->strings["Plugin %s enabled."] = ""; +$a->strings["Disable"] = ""; +$a->strings["Enable"] = ""; +$a->strings["Toggle"] = ""; +$a->strings["Author: "] = ""; +$a->strings["Maintainer: "] = ""; +$a->strings["No themes found."] = ""; +$a->strings["Screenshot"] = ""; +$a->strings["[Experimental]"] = ""; +$a->strings["[Unsupported]"] = ""; +$a->strings["Log settings updated."] = ""; +$a->strings["Clear"] = ""; +$a->strings["Debugging"] = ""; +$a->strings["Log file"] = ""; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = ""; +$a->strings["Log level"] = ""; +$a->strings["New Profile Field"] = ""; +$a->strings["Field nickname"] = ""; +$a->strings["System name of field"] = ""; +$a->strings["Input type"] = ""; +$a->strings["Field Name"] = ""; +$a->strings["Label on profile pages"] = ""; +$a->strings["Help text"] = ""; +$a->strings["Additional info (optional)"] = ""; +$a->strings["Field definition not found"] = ""; +$a->strings["Edit Profile Field"] = ""; +$a->strings["Unable to find your hub."] = ""; +$a->strings["Post successful."] = ""; +$a->strings["Edit Block"] = ""; +$a->strings["Delete block?"] = ""; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = ""; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = ""; +$a->strings["Passwords do not match."] = ""; +$a->strings["Registration successful. Please check your email for validation instructions."] = ""; +$a->strings["Your registration is pending approval by the site owner."] = ""; +$a->strings["Your registration can not be processed."] = ""; +$a->strings["Registration on this site/hub is by approval only."] = ""; +$a->strings["Register at another affiliated site/hub"] = ""; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = ""; +$a->strings["Terms of Service"] = ""; +$a->strings["I accept the %s for this website"] = ""; +$a->strings["I am over 13 years of age and accept the %s for this website"] = ""; +$a->strings["Membership on this site is by invitation only."] = ""; +$a->strings["Please enter your invitation code"] = ""; +$a->strings["Your email address"] = ""; +$a->strings["Choose a password"] = ""; +$a->strings["Please re-enter your password"] = ""; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = ""; +$a->strings["Remove This Account"] = ""; +$a->strings["WARNING: "] = ""; +$a->strings["This account and all its channels will be completely removed from the network. "] = ""; +$a->strings["This action is permanent and can not be undone!"] = ""; +$a->strings["Please enter your password for verification:"] = ""; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = ""; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = ""; +$a->strings["Unable to locate original post."] = ""; +$a->strings["Empty post discarded."] = ""; +$a->strings["Executable content type not permitted to this channel."] = ""; +$a->strings["System error. Post not saved."] = ""; +$a->strings["Unable to obtain post information from database."] = ""; +$a->strings["You have reached your limit of %1$.0f top level posts."] = ""; +$a->strings["You have reached your limit of %1$.0f webpages."] = ""; +$a->strings["[Embedded content - reload page to view]"] = ""; +$a->strings["Remote privacy information not available."] = ""; +$a->strings["Visible to:"] = ""; +$a->strings["Comanche page description language help"] = ""; +$a->strings["Layout Description"] = ""; +$a->strings["Download PDL file"] = ""; +$a->strings["First Name"] = ""; +$a->strings["Last Name"] = ""; +$a->strings["Nickname"] = ""; +$a->strings["Full Name"] = ""; +$a->strings["Profile Photo 16px"] = ""; +$a->strings["Profile Photo 32px"] = ""; +$a->strings["Profile Photo 48px"] = ""; +$a->strings["Profile Photo 64px"] = ""; +$a->strings["Profile Photo 80px"] = ""; +$a->strings["Profile Photo 128px"] = ""; +$a->strings["Timezone"] = ""; +$a->strings["Homepage URL"] = ""; +$a->strings["Birth Year"] = ""; +$a->strings["Birth Month"] = ""; +$a->strings["Birth Day"] = ""; +$a->strings["Birthdate"] = ""; +$a->strings["Conversation removed."] = ""; +$a->strings["No messages."] = ""; +$a->strings["Delete conversation"] = ""; +$a->strings["D, d M Y - g:i A"] = ""; +$a->strings["Unable to create element."] = ""; +$a->strings["Unable to update menu element."] = ""; +$a->strings["Unable to add menu element."] = ""; +$a->strings["Menu Item Permissions"] = ""; +$a->strings["Link Name"] = ""; +$a->strings["Link or Submenu Target"] = ""; +$a->strings["Enter URL of the link or select a menu name to create a submenu"] = ""; +$a->strings["Use magic-auth if available"] = ""; +$a->strings["Open link in new window"] = ""; +$a->strings["Order in list"] = ""; +$a->strings["Higher numbers will sink to bottom of listing"] = ""; +$a->strings["Submit and finish"] = ""; +$a->strings["Submit and continue"] = ""; +$a->strings["Menu:"] = ""; +$a->strings["Link Target"] = ""; +$a->strings["Edit menu"] = ""; +$a->strings["Edit element"] = ""; +$a->strings["Drop element"] = ""; +$a->strings["New element"] = ""; +$a->strings["Edit this menu container"] = ""; +$a->strings["Add menu element"] = ""; +$a->strings["Delete this menu item"] = ""; +$a->strings["Edit this menu item"] = ""; +$a->strings["Menu item not found."] = ""; +$a->strings["Menu item deleted."] = ""; +$a->strings["Menu item could not be deleted."] = ""; +$a->strings["Edit Menu Element"] = ""; +$a->strings["Link text"] = ""; +$a->strings["Set your current mood and tell your friends"] = ""; +$a->strings["Total votes"] = ""; +$a->strings["Average Rating"] = ""; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = ""; +$a->strings["Remove This Channel"] = ""; +$a->strings["This channel will be completely removed from the network. "] = ""; +$a->strings["Remove this channel and all its clones from the network"] = ""; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = ""; +$a->strings["is now connected to"] = ""; +$a->strings["Could not access address book record."] = ""; +$a->strings["Refresh failed - channel is currently unavailable."] = ""; +$a->strings["Channel has been unblocked"] = ""; +$a->strings["Channel has been blocked"] = ""; +$a->strings["Unable to set address book parameters."] = ""; +$a->strings["Channel has been unignored"] = ""; +$a->strings["Channel has been ignored"] = ""; +$a->strings["Channel has been unarchived"] = ""; +$a->strings["Channel has been archived"] = ""; +$a->strings["Channel has been unhidden"] = ""; +$a->strings["Channel has been hidden"] = ""; +$a->strings["Channel has been approved"] = ""; +$a->strings["Channel has been unapproved"] = ""; +$a->strings["Connection has been removed."] = ""; +$a->strings["View %s's profile"] = ""; +$a->strings["Refresh Permissions"] = ""; +$a->strings["Fetch updated permissions"] = ""; +$a->strings["Recent Activity"] = ""; +$a->strings["View recent posts and comments"] = ""; +$a->strings["Block (or Unblock) all communications with this connection"] = ""; +$a->strings["Unignore"] = ""; +$a->strings["Ignore"] = ""; +$a->strings["Ignore (or Unignore) all inbound communications from this connection"] = ""; +$a->strings["Unarchive"] = ""; +$a->strings["Archive"] = ""; +$a->strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = ""; +$a->strings["Unhide"] = ""; +$a->strings["Hide"] = ""; +$a->strings["Hide or Unhide this connection from your other connections"] = ""; +$a->strings["Delete this connection"] = ""; +$a->strings["Approve this connection"] = ""; +$a->strings["Accept connection to allow communication"] = ""; +$a->strings["Connections: settings for %s"] = ""; +$a->strings["Apply these permissions automatically"] = ""; +$a->strings["Apply the permissions indicated on this page to all new connections."] = ""; +$a->strings["Slide to adjust your degree of friendship"] = ""; +$a->strings["Default permissions for your channel type have (just) been applied. They have not yet been submitted. Please review the permissions on this page and make any desired changes at this time. This new connection may not be able to communicate with you until you submit this page, which will install and apply the selected permissions."] = ""; +$a->strings["inherited"] = ""; +$a->strings["Connection has no individual permissions!"] = ""; +$a->strings["This may be appropriate based on your privacy settings, though you may wish to review the \"Advanced Permissions\"."] = ""; +$a->strings["Profile Visibility"] = ""; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = ""; +$a->strings["Contact Information / Notes"] = ""; +$a->strings["Edit contact notes"] = ""; +$a->strings["Their Settings"] = ""; +$a->strings["My Settings"] = ""; +$a->strings["Default permissions for this channel type have (just) been applied. They have not been saved and there are currently no stored default permissions. Please review/edit the applied settings and click [Submit] to finalize."] = ""; +$a->strings["Clear/Disable Automatic Permissions"] = ""; +$a->strings["Forum Members"] = ""; +$a->strings["Soapbox"] = ""; +$a->strings["Full Sharing (typical social network permissions)"] = ""; +$a->strings["Cautious Sharing "] = ""; +$a->strings["Follow Only"] = ""; +$a->strings["Individual Permissions"] = ""; +$a->strings["Some permissions may be inherited from your channel privacy settings, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect."] = ""; +$a->strings["Advanced Permissions"] = ""; +$a->strings["Simple Permissions (select one and submit)"] = ""; +$a->strings["Visit %s's profile - %s"] = ""; +$a->strings["Block/Unblock contact"] = ""; +$a->strings["Ignore contact"] = ""; +$a->strings["Repair URL settings"] = ""; +$a->strings["View conversations"] = ""; +$a->strings["Delete contact"] = ""; +$a->strings["Last update:"] = ""; +$a->strings["Update public posts"] = ""; +$a->strings["Update now"] = ""; +$a->strings["Currently blocked"] = ""; +$a->strings["Currently ignored"] = ""; +$a->strings["Currently archived"] = ""; +$a->strings["Currently pending"] = ""; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = ""; +$a->strings["The error message was:"] = ""; +$a->strings["Authentication failed."] = ""; +$a->strings["Remote Authentication"] = ""; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = ""; +$a->strings["Authenticate"] = ""; +$a->strings["Unable to lookup recipient."] = ""; +$a->strings["Unable to communicate with requested channel."] = ""; +$a->strings["Cannot verify requested channel."] = ""; +$a->strings["Selected channel has private message restrictions. Send failed."] = ""; +$a->strings["Message deleted."] = ""; +$a->strings["Message recalled."] = ""; +$a->strings["Send Private Message"] = ""; +$a->strings["To:"] = ""; +$a->strings["Subject:"] = ""; +$a->strings["Send"] = ""; +$a->strings["Message not found."] = ""; +$a->strings["Delete message"] = ""; +$a->strings["Recall message"] = ""; +$a->strings["Message has been recalled."] = ""; +$a->strings["Private Conversation"] = ""; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = ""; +$a->strings["Send Reply"] = ""; +$a->strings["Invalid request identifier."] = ""; +$a->strings["Discard"] = ""; +$a->strings["Please login."] = ""; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = ""; +$a->strings["Add a Channel"] = ""; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = ""; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = ""; +$a->strings["Choose a short nickname"] = ""; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = ""; +$a->strings["Or import an existing channel from another location"] = ""; +$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = ""; +$a->strings["Channel Type"] = ""; +$a->strings["Read more about roles"] = ""; +$a->strings["App installed."] = ""; +$a->strings["Malformed app."] = ""; +$a->strings["Embed code"] = ""; +$a->strings["Edit App"] = ""; +$a->strings["Create App"] = ""; +$a->strings["Name of app"] = ""; +$a->strings["Location (URL) of app"] = ""; +$a->strings["Photo icon URL"] = ""; +$a->strings["80 x 80 pixels - optional"] = ""; +$a->strings["Version ID"] = ""; +$a->strings["Price of app"] = ""; +$a->strings["Location (URL) to purchase app"] = ""; +$a->strings["sent you a private message"] = ""; +$a->strings["added your channel"] = ""; +$a->strings["posted an event"] = ""; +$a->strings["No such group"] = ""; +$a->strings["No such channel"] = ""; +$a->strings["Search Results For:"] = ""; +$a->strings["Collection is empty"] = ""; +$a->strings["Collection: "] = ""; +$a->strings["Connection: "] = ""; +$a->strings["Invalid connection."] = ""; +$a->strings["Ipsum Lorem"] = ""; +$a->strings["Bookmark added"] = ""; +$a->strings["My Bookmarks"] = ""; +$a->strings["My Connections Bookmarks"] = ""; +$a->strings["Insufficient permissions. Request redirected to profile page."] = ""; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = ""; +$a->strings["Poll"] = ""; +$a->strings["View Results"] = ""; +$a->strings["No service class restrictions found."] = ""; +$a->strings["Files: shared with me"] = ""; +$a->strings["NEW"] = ""; +$a->strings["Remove all files"] = ""; +$a->strings["Remove this file"] = ""; +$a->strings["Schema Default"] = ""; +$a->strings["Sans-Serif"] = ""; +$a->strings["Monospace"] = ""; +$a->strings["Theme settings"] = ""; +$a->strings["Set scheme"] = ""; +$a->strings["Set font-size for posts and comments"] = ""; +$a->strings["Set font face"] = ""; +$a->strings["Set iconset"] = ""; +$a->strings["Set big shadow size, default 15px 15px 15px"] = ""; +$a->strings["Set small shadow size, default 5px 5px 5px"] = ""; +$a->strings["Set shadow color, default #000"] = ""; +$a->strings["Set radius size, default 5px"] = ""; +$a->strings["Set line-height for posts and comments"] = ""; +$a->strings["Set background image"] = ""; +$a->strings["Set background attachment"] = ""; +$a->strings["Set background color"] = ""; +$a->strings["Set section background image"] = ""; +$a->strings["Set section background color"] = ""; +$a->strings["Set color of items - use hex"] = ""; +$a->strings["Set color of links - use hex"] = ""; +$a->strings["Set max-width for items. Default 400px"] = ""; +$a->strings["Set min-width for items. Default 240px"] = ""; +$a->strings["Set the generic content wrapper width. Default 48%"] = ""; +$a->strings["Set color of fonts - use hex"] = ""; +$a->strings["Set background-size element"] = ""; +$a->strings["Item opacity"] = ""; +$a->strings["Display post previews only"] = ""; +$a->strings["Display side bar on channel page"] = ""; +$a->strings["Colour of the navigation bar"] = ""; +$a->strings["Item float"] = ""; +$a->strings["Left offset of the section element"] = ""; +$a->strings["Right offset of the section element"] = ""; +$a->strings["Section width"] = ""; +$a->strings["Left offset of the aside"] = ""; +$a->strings["Right offset of the aside element"] = ""; +$a->strings["Light (Hubzilla default)"] = ""; +$a->strings["Select scheme"] = ""; +$a->strings["Narrow navbar"] = ""; +$a->strings["Navigation bar background color"] = ""; +$a->strings["Navigation bar gradient top color"] = ""; +$a->strings["Navigation bar gradient bottom color"] = ""; +$a->strings["Navigation active button gradient top color"] = ""; +$a->strings["Navigation active button gradient bottom color"] = ""; +$a->strings["Navigation bar border color "] = ""; +$a->strings["Navigation bar icon color "] = ""; +$a->strings["Navigation bar active icon color "] = ""; +$a->strings["link color"] = ""; +$a->strings["Set font-color for banner"] = ""; +$a->strings["Set the background color"] = ""; +$a->strings["Set the background image"] = ""; +$a->strings["Set the background color of items"] = ""; +$a->strings["Set the background color of comments"] = ""; +$a->strings["Set the border color of comments"] = ""; +$a->strings["Set the indent for comments"] = ""; +$a->strings["Set the basic color for item icons"] = ""; +$a->strings["Set the hover color for item icons"] = ""; +$a->strings["Set font-size for the entire application"] = ""; +$a->strings["Example: 14px"] = ""; +$a->strings["Set font-color for posts and comments"] = ""; +$a->strings["Set radius of corners"] = ""; +$a->strings["Set shadow depth of photos"] = ""; +$a->strings["Set maximum width of content region in pixel"] = ""; +$a->strings["Leave empty for default width"] = ""; +$a->strings["Center page content"] = ""; +$a->strings["Set minimum opacity of nav bar - to hide it"] = ""; +$a->strings["Set size of conversation author photo"] = ""; +$a->strings["Set size of followup author photos"] = ""; +$a->strings["Update %s failed. See error logs."] = ""; +$a->strings["Update Error at %s"] = ""; +$a->strings["Create an account to access services and applications within the Hubzilla"] = ""; +$a->strings["Password"] = ""; +$a->strings["Remember me"] = ""; +$a->strings["Forgot your password?"] = ""; +$a->strings["toggle mobile"] = ""; +$a->strings["Website SSL certificate is not valid. Please correct."] = ""; +$a->strings["[red] Website SSL error for %s"] = ""; +$a->strings["Cron/Scheduled tasks not running."] = ""; +$a->strings["[red] Cron tasks not running on %s"] = ""; diff --git a/sources/util/tpldebug.php b/sources/util/tpldebug.php new file mode 100644 index 00000000..80da410d --- /dev/null +++ b/sources/util/tpldebug.php @@ -0,0 +1,43 @@ + 1) { + echo "{$argv[1]}: templates\n"; + print_template($argv[1]); +} +else { + + + echo 'boot.php: templates' . "\n"; + print_template('boot.php'); + + $files = glob('include/*.php'); + foreach($files as $file) { + echo $file . ': templates'. "\n"; + print_template($file); + } + + $files = glob('mod/*.php'); + foreach($files as $file) { + echo $file . ': templates'. "\n"; + print_template($file); + } +} + +function print_template($s) { + $x = file_get_contents($s); + + $cnt = preg_match_all('/replace_macros(.*?)\)\;/ism',$x,$matches); + + if($cnt) { + print_r($matches[0]); + + } + +} \ No newline at end of file diff --git a/sources/util/typo.php b/sources/util/typo.php new file mode 100644 index 00000000..9edb7e78 --- /dev/null +++ b/sources/util/typo.php @@ -0,0 +1,80 @@ +config,'system') && x($a->config['system'],'php_path')) + $phpath = $a->config['system']['php_path']; + else + $phpath = 'php'; + + echo "String files\n"; + + echo 'util/strings.php' . "\n"; + include_once('util/strings.php'); + echo count($a->strings) . ' strings' . "\n"; + + $files = glob('view/*/strings.php'); + + foreach($files as $file) { + echo $file . "\n"; + passthru($phpath . ' util/typohelper.php ' . $file); +// include_once($file); + } diff --git a/sources/util/typohelper.php b/sources/util/typohelper.php new file mode 100644 index 00000000..589702a0 --- /dev/null +++ b/sources/util/typohelper.php @@ -0,0 +1,11 @@ + + Authenticate to 'hostname' and switch to it + +cd + changhe remote dir + + +ls [path] [-a] [-l] [-d] + list remote files in current dir if 'path' not defined + -a list all, show hidden dot-files + -l list verbose + -d list only dirs + +exists + Check existence of 'path' + +mkdir + Create directory 'name' + +mkdirs + Create parent directories to path, if they don't exists + +rmdir + Delete directory 'name' + +delete + Delete file 'path' + +upload [remote_path] + Upload local file 'local_paht' to 'remote_paht' + +download [local_path] + Download remote file 'remote_path' and save it as 'local_path' + +cat + Print content of 'remote_path' + +pwd + Print current path + +lcd +lpwd +lls + Local file management + +quit +help + + + +Config +------ + +Create a .zotshrc file in your home or in same folder with zotsh.py: + + + [zotsh] + host = https://yourhost.com/ + username = your_username + password = your_password + + +Optionally adds + + verify_ssl = false + +to skip verification of ssl certs + + +Changelog +---------- +0.0.2 Fix "CommandNotFound" exception, new 'cat' command + +0.0.1 First release + + +Links +----- + +_0 : https://github.com/amnong/easywebdav +_1 : http://docs.python-requests.org/en/latest/ +_2 : http://docs.python-requests.org/en/latest/user/install/ \ No newline at end of file diff --git a/sources/util/zotsh/easywebdav/LICENSE b/sources/util/zotsh/easywebdav/LICENSE new file mode 100644 index 00000000..4f24108f --- /dev/null +++ b/sources/util/zotsh/easywebdav/LICENSE @@ -0,0 +1,5 @@ +Copyright (c) 2012 year, Amnon Grossman + +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/sources/util/zotsh/easywebdav/__init__.py b/sources/util/zotsh/easywebdav/__init__.py new file mode 100644 index 00000000..3bc2cad2 --- /dev/null +++ b/sources/util/zotsh/easywebdav/__init__.py @@ -0,0 +1,5 @@ +from .client import * + +def connect(*args, **kwargs): + """connect(host, port=0, auth=None, username=None, password=None, protocol='http', path="/")""" + return Client(*args, **kwargs) diff --git a/sources/util/zotsh/easywebdav/__init__.pyc b/sources/util/zotsh/easywebdav/__init__.pyc new file mode 100644 index 00000000..b609b06c Binary files /dev/null and b/sources/util/zotsh/easywebdav/__init__.pyc differ diff --git a/sources/util/zotsh/easywebdav/__version__.py b/sources/util/zotsh/easywebdav/__version__.py new file mode 100644 index 00000000..d293e3a3 --- /dev/null +++ b/sources/util/zotsh/easywebdav/__version__.py @@ -0,0 +1 @@ +__version__ = "1.2.0" diff --git a/sources/util/zotsh/easywebdav/__version__.pyc b/sources/util/zotsh/easywebdav/__version__.pyc new file mode 100644 index 00000000..5da5a28e Binary files /dev/null and b/sources/util/zotsh/easywebdav/__version__.pyc differ diff --git a/sources/util/zotsh/easywebdav/client.py b/sources/util/zotsh/easywebdav/client.py new file mode 100644 index 00000000..da7bf325 --- /dev/null +++ b/sources/util/zotsh/easywebdav/client.py @@ -0,0 +1,202 @@ +import requests +import platform +from numbers import Number +import xml.etree.cElementTree as xml +from collections import namedtuple + +py_majversion, py_minversion, py_revversion = platform.python_version_tuple() + +if py_majversion == '2': + from httplib import responses as HTTP_CODES + from urlparse import urlparse +else: + from http.client import responses as HTTP_CODES + from urllib.parse import urlparse + +DOWNLOAD_CHUNK_SIZE_BYTES = 1 * 1024 * 1024 + +class WebdavException(Exception): + pass + +class ConnectionFailed(WebdavException): + pass + + +def codestr(code): + return HTTP_CODES.get(code, 'UNKNOWN') + + +File = namedtuple('File', ['name', 'size', 'mtime', 'ctime', 'contenttype']) + + +def prop(elem, name, default=None): + child = elem.find('.//{DAV:}' + name) + return default if child is None else child.text + + +def elem2file(elem): + return File( + prop(elem, 'href'), + int(prop(elem, 'getcontentlength', 0)), + prop(elem, 'getlastmodified', ''), + prop(elem, 'creationdate', ''), + prop(elem, 'getcontenttype', ''), + ) + + +class OperationFailed(WebdavException): + _OPERATIONS = dict( + HEAD = "get header", + GET = "download", + PUT = "upload", + DELETE = "delete", + MKCOL = "create directory", + PROPFIND = "list directory", + ) + + def __init__(self, method, path, expected_code, actual_code): + self.method = method + self.path = path + self.expected_code = expected_code + self.actual_code = actual_code + operation_name = self._OPERATIONS[method] + self.reason = 'Failed to {operation_name} "{path}"'.format(**locals()) + expected_codes = (expected_code,) if isinstance(expected_code, Number) else expected_code + expected_codes_str = ", ".join('{0} {1}'.format(code, codestr(code)) for code in expected_codes) + actual_code_str = codestr(actual_code) + msg = '''\ +{self.reason}. + Operation : {method} {path} + Expected code : {expected_codes_str} + Actual code : {actual_code} {actual_code_str}'''.format(**locals()) + super(OperationFailed, self).__init__(msg) + +class Client(object): + def __init__(self, host, port=0, auth=None, username=None, password=None, + protocol='http', verify_ssl=True, path=None, cert=None, session=None): + if not port: + port = 443 if protocol == 'https' else 80 + self.baseurl = '{0}://{1}:{2}'.format(protocol, host, port) + if path: + self.baseurl = '{0}/{1}'.format(self.baseurl, path) + self.cwd = '/' + if session is None: + self.session = requests.session() + else: + self.session = session + self.session.verify = verify_ssl + self.session.stream = True + + if cert: + self.session.cert = cert + + if auth: + self.session.auth = auth + elif username and password: + self.session.auth = (username, password) + + def _send(self, method, path, expected_code, **kwargs): + url = self._get_url(path).strip(".") + #~ print self.session + #~ print self.session.verify + #~ print self.session.params + #~ print self.session.cookies + response = self.session.request(method, url, allow_redirects=False, **kwargs) + #~ print response.request.method + #~ print response.request.url + if isinstance(expected_code, Number) and response.status_code != expected_code \ + or not isinstance(expected_code, Number) and response.status_code not in expected_code: + raise OperationFailed(method, path, expected_code, response.status_code) + return response + + def _get_url(self, path): + path = str(path).strip() + if path.startswith('/'): + return self.baseurl + path + return "".join((self.baseurl, self.cwd, path)) + + def cd(self, path): + path = path.strip() + if not path: + return + stripped_path = '/'.join(part for part in path.split('/') if part) + '/' + + if stripped_path == '/': + self.cwd = stripped_path + elif path.startswith('/'): + self.cwd = '/' + stripped_path + elif stripped_path == "./": + return + elif stripped_path == "../": + self.cwd ='/'.join( self.cwd.split('/')[:-2] ) + '/' + else: + self.cwd += stripped_path + + def mkdir(self, path, safe=False): + expected_codes = 201 if not safe else (201, 301, 405) + self._send('MKCOL', path, expected_codes) + + def mkdirs(self, path): + dirs = [d for d in path.split('/') if d] + if not dirs: + return + if path.startswith('/'): + dirs[0] = '/' + dirs[0] + old_cwd = self.cwd + try: + for dir in dirs: + try: + self.mkdir(dir, safe=True) + except Exception as e: + if e.actual_code == 409: + raise + finally: + self.cd(dir) + finally: + self.cd(old_cwd) + + def rmdir(self, path, safe=False): + path = str(path).rstrip('/') + '/' + expected_codes = 204 if not safe else (204, 404) + self._send('DELETE', path, expected_codes) + + def delete(self, path): + self._send('DELETE', path, 204) + + def upload(self, local_path_or_fileobj, remote_path): + if isinstance(local_path_or_fileobj, basestring): + with open(local_path_or_fileobj, 'rb') as f: + self._upload(f, remote_path) + else: + self._upload(local_path_or_fileobj, remote_path) + + def _upload(self, fileobj, remote_path): + self._send('PUT', remote_path, (200, 201, 204), data=fileobj) + + def download(self, remote_path, local_path_or_fileobj): + response = self._send('GET', remote_path, 200, stream=True) + if isinstance(local_path_or_fileobj, basestring): + with open(local_path_or_fileobj, 'wb') as f: + self._download(f, response) + else: + self._download(local_path_or_fileobj, response) + + def _download(self, fileobj, response): + for chunk in response.iter_content(DOWNLOAD_CHUNK_SIZE_BYTES): + fileobj.write(chunk) + + def ls(self, remote_path='.'): + headers = {'Depth': '1'} + response = self._send('PROPFIND', remote_path, (207, 301), headers=headers) + + # Redirect + if response.status_code == 301: + url = urlparse(response.headers['location']) + return self.ls(url.path) + + tree = xml.fromstring(response.content) + return [elem2file(elem) for elem in tree.findall('{DAV:}response')] + + def exists(self, remote_path): + response = self._send('HEAD', remote_path, (200, 301, 404)) + return True if response.status_code != 404 else False diff --git a/sources/util/zotsh/easywebdav/client.pyc b/sources/util/zotsh/easywebdav/client.pyc new file mode 100644 index 00000000..4c42d260 Binary files /dev/null and b/sources/util/zotsh/easywebdav/client.pyc differ diff --git a/sources/util/zotsh/zotsh.py b/sources/util/zotsh/zotsh.py new file mode 100755 index 00000000..36506b39 --- /dev/null +++ b/sources/util/zotsh/zotsh.py @@ -0,0 +1,324 @@ +#!/usr/bin/env python2 +import sys, os +import ConfigParser +import requests +from requests.auth import HTTPBasicAuth +import easywebdav +import easywebdav.__version__ as easywebdavversion + +__version__= "0.0.2" + +SERVER = None +USER = None +PASSWD = None +VERIFY_SSL=True + +##################################################### + +class CommandNotFound(Exception): + pass + +class ZotSH(object): + commands = ['cd','ls','exists','mkdir','mkdirs','rmdir','delete','upload','download', + 'host', 'pwd','cat', + 'lcd','lpwd', 'lls', + 'quit', 'help'] + def __init__(self, host, session=None, davclient=None): + self.sessions = {} + self.host = host + self.session = session + self.davclient = davclient + + + @property + def host(self): + return self._host + + @host.setter + def host(self, host): + self._host = host + self._hostname = host.replace("https:","").replace("/","") + + @property + def hostname(self): + return self._hostname + + @hostname.setter + def hostname(self, hostname): + self._host = "https://%s/" % (hostname) + self._hostname = hostname + + @property + def session(self): + return self._session + + @session.setter + def session(self, session): + self._session = session + self.davclient = easywebdav.connect( self.hostname, protocol='https', session=session, path="cloud", verify_ssl=VERIFY_SSL) + + @property + def PS1(self): + if self.davclient is None: + return "[!]> " + return "%s:%s> " % (self.hostname, self.davclient.cwd) + + def get_host_session(self, host=None): + #~ if host is None: + #~ host = self.host + #~ if not host.startswith("https"): + #~ host = "https://%s/" % (host) + #~ if host in self.sessions: + #~ session = self.sessions[host] + #~ else: + #~ session = requests.Session() + #~ self.sessions[host] = session + #~ if not host == SERVER + #~ session.params.update({'davguest':1}) + #~ return session + + if self.session is None: + session = requests.Session() + #session.params.update({'davguest':1}) + else: + session = self.session + session.params.update({'davguest': (not host == SERVER) }) + return session + + def do(self, command, *args): + if not command in self.commands: + raise CommandNotFound("Unknow command '%s'" % command) + + cmd = getattr(self, "cmd_%s"%command, None) + if cmd is None: + cmd = getattr(self.davclient, command) + + return cmd(*args) + + def cmd_exists(self, *args): + if (len(args)==0): + return + return self.davclient.exists(args[0]) + + def cmd_mkdir(self, *args): + if (len(args)==0): + return + return self.davclient.mkdir(args[0]) + + def cmd_mkdirs(self, *args): + if (len(args)==0): + return + return self.davclient.mkdirs(args[0]) + + def cmd_rmdir(self, *args): + if (len(args)==0): + return + return self.davclient.rmdir(args[0]) + + def cmd_delete(self, *args): + if (len(args)==0): + return + return self.davclient.delete(args[0]) + + def cmd_upload(self, *args): + if (len(args)==0): + return + args = list(args) + if (len(args)==1): + args.append(args[0]) + + return self.davclient.upload(args[0], args[1]) + + def cmd_download(self, *args): + if (len(args)==0): + return + args = list(args) + if (len(args)==1): + args.append(args[0]) + + return self.davclient.download(args[0], args[1]) + + def cmd_host(self, *args): + if (len(args)==0): + return + newhostname = args[0] + newhost = "https://%s/" % newhostname + if newhostname == "~" or newhost == SERVER: + # bach to home server + self.host = SERVER + self.session = self.get_host_session(SERVER) + return + + session_remote = self.get_host_session(newhost) + session_home = self.get_host_session(SERVER) + + # call /magic on SERVER + r = session_home.get( + SERVER + "magic", + params={'dest': newhost}, + allow_redirects=False, + verify=VERIFY_SSL ) + + if not 'location' in r.headers: + raise Exception("Cannot start magic auth to '%s'" % newhostname) + auth_url = r.headers['location'] + + + # call auth_url with "test" param + + r = session_remote.get( + auth_url, + params={'test': 1 }, + verify=VERIFY_SSL ) + + if r.json()['success']: + self.hostname = newhostname + self.session = session_remote + else: + raise Exception("Cannot magic auth to '%s'" % newhostname) + + + def cmd_pwd(self, *args): + return "%s%s" % ( self.davclient.baseurl, self.davclient.cwd ) + + def cmd_ls(self, *args): + extra_args = ["-a", "-l", "-d"] + + show_hidden = "-a" in args + show_list = "-l" in args + show_only_dir = "-d" in args + args = [ a for a in args if not a in extra_args ] + + + r = self.davclient.ls(*args) + l = max([ len(str(f.size)) for f in r ] + [7,]) + + def _fmt(type, size, name): + if show_list: + return "%s %*d %s" % (type, l, f.size , name) + else: + return name + + if show_hidden : + print _fmt('d', 0, "./") + if self.davclient.cwd!="/": + print _fmt('d', 0, "../") + + for f in r: + name = f.name.replace("/cloud"+self.davclient.cwd,"") + type = "-" + if name.endswith("/"): + type = "d" + if name!="": + if show_hidden or not name.startswith("."): + if not show_only_dir or type=="d": + print _fmt(type, f.size , name) + + def cmd_lpwd(self, *args): + return os.getcwd() + + def cmd_lcd(self, *args): + if (len(args)==0): + return + os.chdir(args[0]) + + def cmd_lls(self, *args): + for f in os.listdir(os.getcwd()): + if os.path.isdir(f): + f=f+"/" + print f + + def cmd_help(self, *args): + print "ZotSH",__version__ + print + print "Commands:" + for c in self.commands: + print "\t",c + print + print "easywebdav", easywebdavversion.__version__, "(mod)" + print "requests", requests.__version__ + + def cmd_cat(self,*args): + if (len(args)==0): + return + rfile = args[0] + resp = self.davclient._send('GET', rfile, (200,)) + print resp.text + +def load_conf(): + global SERVER,USER,PASSWD,VERIFY_SSL + homedir = os.getenv("HOME") + if homedir is None: + homedir = os.path.join(os.getenv("HOMEDRIVE"), os.getenv("HOMEPATH")) + + optsfile = ".zotshrc" + if not os.path.isfile(optsfile): + optsfile = os.path.join(homedir, ".zotshrc") + + if not os.path.isfile(optsfile): + print "Please create a configuration file called '.zotshrc':" + print "[zotsh]" + print "host = https://yourhost.com/" + print "username = your_username" + print "password = your_password" + sys.exit(-1) + + config = ConfigParser.ConfigParser() + config.read(optsfile) + SERVER = config.get('zotsh', 'host') + USER = config.get('zotsh', 'username') + PASSWD = config.get('zotsh', 'password') + if config.has_option('zotsh', 'verify_ssl'): + VERIFY_SSL = config.getboolean('zotsh', 'verify_ssl') + + +def zotsh(): + + zotsh = ZotSH( SERVER) + + session_home = zotsh.get_host_session() + + #~ #login on home server + print "loggin in..." + r = session_home.get( + SERVER + "api/account/verify_credentials", + auth=HTTPBasicAuth(USER, PASSWD), + verify=VERIFY_SSL ) + + print "Hi", r.json()['name'] + + zotsh.session = session_home + + # command loop + input = raw_input(zotsh.PS1) + while (input != "quit"): + input = input.strip() + if len(input)>0: + toks = [ x.strip() for x in input.split(" ") ] + + command = toks[0] + args = toks[1:] + try: + ret = zotsh.do(command, *args) + except easywebdav.client.OperationFailed, e: + print e + except CommandNotFound, e: + print e + else: + if ret is not None: + print ret + + + input = raw_input(zotsh.PS1) + + + + +if __name__=="__main__": + load_conf() + zotsh() + sys.exit() + + + + diff --git a/sources/vendor/autoload.php b/sources/vendor/autoload.php new file mode 100644 index 00000000..655527c5 --- /dev/null +++ b/sources/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0 class loader + * + * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + + public function getPrefixes() + { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-0 base directories + * @param bool $prepend Whether to prepend the directories + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731 + if ('\\' == $class[0]) { + $class = substr($class, 1); + } + + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { + if (0 === strpos($class, $prefix)) { + foreach ($this->prefixDirsPsr4[$prefix] as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/sources/vendor/composer/autoload_classmap.php b/sources/vendor/composer/autoload_classmap.php new file mode 100644 index 00000000..7a91153b --- /dev/null +++ b/sources/vendor/composer/autoload_classmap.php @@ -0,0 +1,9 @@ + array($vendorDir . '/sabre/vobject/lib'), + 'Sabre\\HTTP' => array($vendorDir . '/sabre/dav/lib'), + 'Sabre\\DAVACL' => array($vendorDir . '/sabre/dav/lib'), + 'Sabre\\DAV' => array($vendorDir . '/sabre/dav/lib'), + 'Sabre\\CardDAV' => array($vendorDir . '/sabre/dav/lib'), + 'Sabre\\CalDAV' => array($vendorDir . '/sabre/dav/lib'), +); diff --git a/sources/vendor/composer/autoload_psr4.php b/sources/vendor/composer/autoload_psr4.php new file mode 100644 index 00000000..b265c64a --- /dev/null +++ b/sources/vendor/composer/autoload_psr4.php @@ -0,0 +1,9 @@ + $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + + $loader->register(true); + + return $loader; + } +} + +function composerRequirea478c0bdc9041edcc4f485e8fb39b90d($file) +{ + require $file; +} diff --git a/sources/vendor/composer/installed.json b/sources/vendor/composer/installed.json new file mode 100644 index 00000000..42f46fb2 --- /dev/null +++ b/sources/vendor/composer/installed.json @@ -0,0 +1,129 @@ +[ + { + "name": "sabre/vobject", + "version": "2.1.4", + "version_normalized": "2.1.4.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-vobject.git", + "reference": "199b6ec87104b05e3013dfd5b90eafbbe4cf97dc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-vobject/zipball/199b6ec87104b05e3013dfd5b90eafbbe4cf97dc", + "reference": "199b6ec87104b05e3013dfd5b90eafbbe4cf97dc", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=5.3.1" + }, + "time": "2014-03-30 23:01:06", + "bin": [ + "bin/vobjectvalidate.php" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Sabre\\VObject": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "evert@rooftopsolutions.nl", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "The VObject library for PHP allows you to easily parse and manipulate iCalendar and vCard objects", + "homepage": "https://github.com/fruux/sabre-vobject", + "keywords": [ + "VObject", + "iCalendar", + "vCard" + ] + }, + { + "name": "sabre/dav", + "version": "1.8.10", + "version_normalized": "1.8.10.0", + "source": { + "type": "git", + "url": "https://github.com/fruux/sabre-dav.git", + "reference": "0d064536ed3c7974e486b6ebb5b17ad7a974fe18" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruux/sabre-dav/zipball/0d064536ed3c7974e486b6ebb5b17ad7a974fe18", + "reference": "0d064536ed3c7974e486b6ebb5b17ad7a974fe18", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-date": "*", + "ext-dom": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-pcre": "*", + "ext-simplexml": "*", + "ext-spl": "*", + "php": ">=5.3.1", + "sabre/vobject": "~2.1.0" + }, + "provide": { + "evert/sabredav": "1.7.*" + }, + "require-dev": { + "evert/phpdoc-md": "~0.0.7", + "phpunit/phpunit": "~4.0.0" + }, + "suggest": { + "ext-apc": "*", + "ext-curl": "*", + "ext-pdo": "*" + }, + "time": "2014-05-16 00:14:02", + "bin": [ + "bin/sabredav" + ], + "type": "library", + "installation-source": "dist", + "autoload": { + "psr-0": { + "Sabre\\DAV": "lib/", + "Sabre\\HTTP": "lib/", + "Sabre\\DAVACL": "lib/", + "Sabre\\CalDAV": "lib/", + "Sabre\\CardDAV": "lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Evert Pot", + "email": "me@evertpot.com", + "homepage": "http://evertpot.com/", + "role": "Developer" + } + ], + "description": "WebDAV Framework for PHP", + "homepage": "http://code.google.com/p/sabredav/", + "keywords": [ + "CalDAV", + "CardDAV", + "WebDAV", + "framework", + "iCalendar" + ] + } +] diff --git a/sources/vendor/sabre/dav/.gitignore b/sources/vendor/sabre/dav/.gitignore new file mode 100644 index 00000000..9a17f774 --- /dev/null +++ b/sources/vendor/sabre/dav/.gitignore @@ -0,0 +1,22 @@ +docs/api +docs/wikidocs +build.properties +build +public +data +fileserver.php +fileserver2.php +calendarserver.php +groupwareserver.php +package.xml +tmpdata +tests/temp +tests/.sabredav +*.swp +composer.lock +vendor +bin/phing +bin/phpunit +bin/vobjectvalidate.php +bin/phpdocmd +bin/phpunit diff --git a/sources/vendor/sabre/dav/.travis.yml b/sources/vendor/sabre/dav/.travis.yml new file mode 100644 index 00000000..9c98702f --- /dev/null +++ b/sources/vendor/sabre/dav/.travis.yml @@ -0,0 +1,28 @@ +language: php +php: + - 5.3.3 + - 5.3 + - 5.4 + - 5.5 + - 5.6 + - hhvm + +matrix: + allow_failures: + - php: 5.6 + - php: hhvm + +services: + - mysql + +before_script: + - mysql -e 'create database sabredav' + - composer self-update + - composer install --prefer-source +# - echo "zend.enable_gc=0" >> `php --ini | grep "Loaded Configuration" | sed -e "s|.*:\s*||"` + +script: + - phpunit --configuration tests/phpunit.xml + - cp tests/composer.vobject3.json composer.json + - composer update --no-dev + - phpunit --configuration tests/phpunit.xml diff --git a/sources/vendor/sabre/dav/ChangeLog b/sources/vendor/sabre/dav/ChangeLog new file mode 100644 index 00000000..92fe1a23 --- /dev/null +++ b/sources/vendor/sabre/dav/ChangeLog @@ -0,0 +1,1164 @@ +1.8.10-stable (2014-05-15) + * The zip release ships with sabre/vobject 2.1.4. + * includes changes from version 1.7.12. + +1.8.9-stable (2014-02-26) + * The zip release ships with sabre/vobject 2.1.3. + * includes changes from version 1.7.11. + +1.8.8-stable (2014-02-09) + * The zip release ships with sabre/vobject 2.1.3. + * includes changes from version 1.7.10. + +1.8.7-stable (2013-10-02) + * the zip release ships with sabre/vobject 2.1.3. + * includes changes from version 1.7.9. + +1.8.6-stable (2013-06-18) + * The zip release ships with sabre/vobject 2.1.0. + * Includes changes from version 1.7.8. + +1.8.5-stable (2013-04-11) + * The zip release ships with sabre/vobject 2.0.7. + * Includes changes from version 1.7.7. + +1.8.4-stable (2013-04-08) + * The zip release ships with sabre/vobject 2.0.7. + * Includes changes from version 1.7.6. + +1.8.3-stable (2013-03-01) + * The zip release ships with sabre/vobject 2.0.6. + * Includes changes from version 1.7.5. + * Fixed: organizer email-address for shared calendars is now prefixed with + mailto:, as it should. + +1.8.2-stable (2013-01-19) + * The zip release ships with sabre/vobject 2.0.5. + * Includes changes from version 1.7.4. + +1.8.1-stable (2012-12-01) + * The zip release ships with sabre/vobject 2.0.5. + * Includes changes from version 1.7.3. + * Fixed: Typo in 1.7 migration script caused it to fail. + +1.8.0-stable (2012-11-08) + * The zip release ships with sabre/vobject 2.0.5. + * BC Break: Moved the entire codebase to PHP namespaces. + * BC Break: Every backend package (CalDAV, CardDAV, Auth, Locks, + Principals) now has consistent naming conventions. There's a + BackendInterface, and an AbstractBackend class. + * BC Break: Changed a bunch of constructor signatures in the CalDAV + package, to reduce dependencies on the ACL package. + * BC Break: Sabre_CalDAV_ISharedCalendar now also has a getShares method, + so sharees can figure out who is also on a shared calendar. + + * Added: Sabre_DAVACL_IPrincipalCollection interface, to advertise support + for principal-property-search on any node. + * Added: Simple console script to fire up a fileserver in the current + directory using PHP 5.4's built-in webserver. + * Added: Sharee's can now also read out the list of invites for a shared + calendar. + * Added: The Proxy principal classes now both implement an interface, for + greater flexiblity. + +1.7.13-stable (????-??-??) + * Changed: Removed phing and went with a custom build script for now. + +1.7.12-stable (2014-05-15) + * The zip release ships with sabre/vobject 2.1.4. + * Updated: Issue #439. Lots of updates in PATCH support. The + Sabre_DAV_PartialUpdate_IFile interface is now deprecated and will be + removed in a future version. + * Fixed: Restoring old setting after changing + libxml_disable_entity_loader. + * Fixed: Issue #422: Preconditions were not being set on PUT on non- + existant files. Not really a chance for data-loss, but incorrect + nevertheless. + * Fixed: Issue #427: Now checking preconditions on DELETE requests. + * Fixed: Issue #428: Etag check with If: fails if the target is a + collection. + * Fixed: Issue #393: PATCH request with missing end-range was handled + incorrectly. + * Added: Sabre_DAV_Exception_LengthRequired to omit 411 errors. + +1.7.11-stable (2014-02-26) + * The zip release ships with sabre/vobject 2.1.3. + * Fixed: Issue #407: large downloads failed. + * Fixed: Issue #414: XXE security problem on older PHP versions. + +1.7.10-stable (2014-02-09) + * The zip release ships with sabre/vobject 2.1.3. + * Fixed: Potential security vulnerability in the http client. + * Fixed: Issue #374: Don't urlescape colon (:) when it's not required. + +1.7.9-stable (2013-10-02) + * The zip release ships with sabre/vobject 2.1.3. + * Fixed: Issue #365. Incorrect output when principal urls have spaces in + them. + * Added: Issue #367: Automatically adding a UID to vcards that don't have + them. + +1.7.8-stable (2013-06-17) + * The zip release ships with sabre/vobject 2.1.0. + * Changed: Sabre\DAV\Client::verifyPeer is now a protected property + (instead of private). + * Fixed: Text was incorrectly escaped in the Href and HrefList properties, + disallowing urls with ampersands (&) in them. + * Added: deserializer for Sabre\DAVACL\Property\CurrentUserPrivilegeSet. + * Fixed: Issue 335: Client only deserializes properties with status 200. + * Fixed: Issue 341: Escaping xml in 423 Locked error responses. + * Added: Issue 339: beforeGetPropertiesForPath event. + +1.7.7-stable (2013-04-11) + * The zip release ships with sabre/vobject 2.0.7. + * Fixed: Assets in the browser plugins were not being served on windows + machines. + +1.7.6-stable (2013-04-08) + * The zip release ships with sabre/vobject 2.0.7. + * Fixed: vcardurl in database schema can now hold 255 characters instead + of 80 (which is often way to small). + * Fixed: The browser plugin potentially allowed people to open any + arbitrary file on windows servers (CVE-2013-1939). + +1.7.5-stable (2013-03-01) + * The zip release ships with sabre/vobject 2.0.6. + * Change: No longer advertising support for 4.0 vcards. iOS and OS X + address book don't handle this well, and just advertising 3.0 support + seems like the most logical course of action. + * Added: ->setVerifyPeers to Sabre_DAV_Client (greatly resisting against + it, don't use this..). + +1.7.4-stable (2013-01-19) + * The zip release ships with sabre/vobject 2.0.5. + * Changed: To be compatibile with MS Office 2011 for Mac, a workaround was + removed that was added to support old versions of Windows XP (pre-SP3). + Indeed! We needed a crazy workaround to work with one MS product in the + past, and we can't keep that workaround to be compatible with another MS + product. + * Fixed: expand-properties REPORT had incorrect values for the href + element. + * Fixed: Range requests now work for non-seekable streams. (Thanks Alfred + Klomp). + * Fixed: Changed serialization of {DAV:}getlastmodified and + {DAV:}supportedlock to improve compatiblity with MS Office 2011 for Mac. + * Changed: reverted the automatic translation of 'DAV:' xml namespaces to + 'urn:DAV' when parsing files. Issues were reported with libxml 2.6.32, + on a relatively recent debian release, so we'll wait till 2015 to take + this one out again. + * Added: Sabre_DAV_Exception_ServiceUnavailable, for emitting 503's. + +1.7.3-stable (2012-12-01) + * The zip release ships with sabre/vobject 2.0.5. + * Fixed: Removing double slashes from getPropertiesForPath. + * Change: Marked a few more properties in the CardDAV as protected, + instead of private. + * Fixed: SharingPlugin now plays nicer with other plugins with similar + functionality. + * Fixed: Issue 174. Sending back HTTP/1.0 for requests with this version. + +1.7.2-stable (2012-11-08) + * The zip release ships with sabre/vobject 2.0.5. + * Added: ACL plugin advertises support for 'calendarserver-principal- + property-search'. + * Fixed: [#153] Allowing for relative http principals in iMip requests. + * Added: Support for cs:first-name and cs:last-name properties in sharing + invites. + * Fixed: Made a bunch of properties protected, where they were private + before. + * Added: Some non-standard properties for sharing to improve + compatibility. + * Fixed: some bugfixes in postgres sql script. + * Fixed: When requesting some properties using PROPFIND, they could show + up as both '200 Ok' and '403 Forbidden'. + * Fixed: calendar-proxy principals were not checked for deeper principal + membership than 1 level. + * Fixed: setGroupMemberSet argument now correctly receives relative + principal urls, instead of the absolute ones. + * Fixed: Server class will filter out any bonus properties if any extra + were returned. This means the implementor of the IProperty class can be + a bit lazier when implementing. + +Note: bug numbers after this line refer to Google Code tickets. We're using +github now. + +1.7.1-stable (2012-10-07) + * Fixed: include path problem in the migration script. + +1.7.0-stable (2012-10-06) + * BC Break: The calendarobjects database table has a bunch of new + fields, and a migration script is required to ensure everything will + keep working. Read the wiki for more details. + * BC Break: The ICalendar interface now has a new method: calendarQuery. + * BC Break: In this version a number of classes have been deleted, that + have been previously deprecated. Namely: + - Sabre_DAV_Directory (now: Sabre_DAV_Collection) + - Sabre_DAV_SimpleDirectory (now: Sabre_DAV_SimpleCollection) + * BC Break: Sabre_CalDAV_Schedule_IMip::sendMessage now has an extra + argument. If you extended this class, you should fix this method. It's + only used for informational purposes. + * BC Break: The DAV: namespace is no longer converted to urn:DAV. This was + a workaround for a bug in older PHP versions (pre-5.3). + * Removed: Sabre.includes.php was deprecated, and is now removed. + * Removed: Sabre_CalDAV_Server was deprecated, and is now removed. Please + use Sabre_DAV_Server and check the examples in the examples/ directory. + * Changed: The Sabre_VObject library now spawned into it's own project! + The VObject library is still included in the SabreDAV zip package. + * Added: Experimental interfaces to allow implementation of caldav-sharing. + Note that no implementation is provided yet, just the api hooks. + * Added: Free-busy reporting compliant with the caldav-scheduling + standard. This allows iCal and other clients to fetch other users' + free-busy data. + * Added: Experimental NotificationSupport interface to add + caldav notifications. + * Added: VCF Export plugin. If enabled, it can generate an export of an + entire addressbook. + * Added: Support for PATCH using a SabreDAV format, to live-patch files. + * Added: Support for Prefer: return-minimal and Brief: t headers for + PROPFIND and PROPPATCH requests. + * Changed: Responsibility for dealing with the calendar-query is now + moved from the CalDAV plugin to the CalDAV backends. This allows for + heavy optimizations. + * Changed: The CalDAV PDO backend is now a lot faster for common + calendar queries. + * Changed: We are now using the composer autoloader. + * Changed: The CalDAV backend now all implement an interface. + * Changed: Instead of Sabre_DAV_Property, Sabre_DAV_PropertyInterface is + now the basis of every property class. + * Update: Caching results for principal lookups. This should cut down + queries and performance for a number of heavy requests. + * Update: ObjectTree caches lookups much more aggresively, which will help + especially speeding up a bunch of REPORT queries. + * Added: Support for the schedule-calendar-transp property. + * Fixed: Marking both the text/calendar and text/x-vcard as UTF-8 + encoded. + * Fixed: Workaround for the SOGO connector, as it doesn't understand + receiving "text/x-vcard; charset=utf-8" for a contenttype. + * Added: Sabre_DAV_Client now throws more specific exceptions in cases + where we already has an exception class. + * Added: Sabre_DAV_PartialUpdate. This plugin allows you to use the + PATCH method to update parts of a file. + * Added: Tons of timezone name mappings for Microsoft Exchange. + * Added: Support for an 'exception' event in the server class. + * Fixed: Uploaded VCards without a UID are now rejected. (thanks Dominik!) + * Fixed: Rejecting calendar objects if they are not in the + supported-calendar-component list. (thanks Armin!) + * Fixed: Issue 219: serialize() now reorders correctly. + * Fixed: Sabre_DAV_XMLUtil no longer returns empty $dom->childNodes + if there is whitespace in $dom. + * Fixed: Returning 409 Conflict instead of 500 when an attempt is made to + create a file as a child of something that's not a collection. + * Fixed: Issue 237: xml-encoding values in SabreDAV error responses. + * Fixed: Returning 403, instead of 501 when an unknown REPORT is + requested. + * Fixed: Postfixing slash on {DAV:}owner properties. + * Fixed: Several embarrassing spelling mistakes in docblocks. + +1.6.10-stable (2013-06-17) + * Fixed: Text was incorrectly escaped in the Href and HrefList properties, + disallowing urls with ampersands (&) in them. + * Fixed: Issue 341: Escaping xml in 423 Locked error responses. + +1.6.9-stable (2013-04-11) + * Fixed: Assets in the browser plugins were not being served on windows + machines. + +1.6.8-stable (2013-04-08) + * Fixed: vcardurl in database schema can now hold 255 characters instead + of 80 (which is often way to small). + * Fixed: The browser plugin potentially allowed people to open any + arbitrary file on windows servers. (CVE-2013-1939). + +1.6.7-stable (2013-03-01) + * Change: No longer advertising support for 4.0 vcards. iOS and OS X + address book don't handle this well, and just advertising 3.0 support + seems like the most logical course of action. + * Added: ->setVerifyPeers to Sabre_DAV_Client (greatly resisting against + it, don't use this..). + +1.6.6-stable (2013-01-19) + * Fixed: Backported a fix for broken XML serialization in error responses. + (Thanks @DeepDiver1975!) + +1.6.5-stable (2012-10-04) + * Fixed: Workaround for line-ending bug OS X 10.8 addressbook has. + * Added: Ability to allow users to set SSL certificates for the Client + class. (Thanks schiesbn!). + * Fixed: Directory indexes with lots of nodes should be a lot faster. + * Fixed: Issue 235: E_NOTICE thrown when doing a propfind request with + Sabre_DAV_Client, and no valid properties are returned. + * Fixed: Issue with filtering on alarms in tasks. + +1.6.4-stable (2012-08-02) + * Fixed: Issue 220: Calendar-query filters may fail when filtering on + alarms, if an overridden event has it's alarm removed. + * Fixed: Compatibility for OS/X 10.8 iCal in the IMipHandler. + * Fixed: Issue 222: beforeWriteContent shouldn't be called for lock + requests. + * Fixed: Problem with POST requests to the outbox if mailto: was not lower + cased. + * Fixed: Yearly recurrence rule expansion on leap-days no behaves + correctly. + * Fixed: Correctly checking if recurring, all-day events with no dtstart + fall in a timerange if the start of the time-range exceeds the start of + the instance of an event, but not the end. + * Fixed: All-day recurring events wouldn't match if an occurence ended + exactly on the start of a time-range. + * Fixed: HTTP basic auth did not correctly deal with passwords containing + colons on some servers. + * Fixed: Issue 228: DTEND is now non-inclusive for all-day events in the + calendar-query REPORT and free-busy calculations. + +1.6.3-stable (2012-06-12) + * Added: It's now possible to specify in Sabre_DAV_Client which type of + authentication is to be used. + * Fixed: Issue 206: Sabre_DAV_Client PUT requests are fixed. + * Fixed: Issue 205: Parsing an iCalendar 0-second date interval. + * Fixed: Issue 112: Stronger validation of iCalendar objects. Now making + sure every iCalendar object only contains 1 component, and disallowing + vcards, forcing every component to have a UID. + * Fixed: Basic validation for vcards in the CardDAV plugin. + * Fixed: Issue 213: Workaround for an Evolution bug, that prevented it + from updating events. + * Fixed: Issue 211: A time-limit query on a non-relative alarm trigger in + a recurring event could result in an endless loop. + * Fixed: All uri fields are now a maximum of 200 characters. The Bynari + outlook plugin used much longer strings so this should improve + compatibility. + * Fixed: Added a workaround for a bug in KDE 4.8.2 contact syncing. See + https://bugs.kde.org/show_bug.cgi?id=300047 + * Fixed: Issue 217: Sabre_DAV_Tree_FileSystem was pretty broken. + +1.6.2-stable (2012-04-16) + * Fixed: Sabre_VObject_Node::$parent should have been public. + * Fixed: Recurrence rules of events are now taken into consideration when + doing time-range queries on alarms. + * Fixed: Added a workaround for the fact that php's DateInterval cannot + parse weeks and days at the same time. + * Added: Sabre_DAV_Server::$exposeVersion, allowing you to hide SabreDAV's + version number from various outputs. + * Fixed: DTSTART values would be incorrect when expanding events. + * Fixed: DTSTART and DTEND would be incorrect for expansion of WEEKLY + BYDAY recurrences. + * Fixed: Issue 203: A problem with overridden events hitting the exact + date and time of a subsequent event in the recurrence set. + * Fixed: There was a problem with recurrence rules, for example the 5th + tuesday of the month, if this day did not exist. + * Added: New HTTP status codes from draft-nottingham-http-new-status-04. + +1.6.1-stable (2012-03-05) + * Added: createFile and put() can now return an ETag. + * Added: Sending back an ETag on for operations on CardDAV backends. This + should help with OS X 10.6 Addressbook compatibility. + * Fixed: Fixed a bug where an infinite loop could occur in the recurrence + iterator if the recurrence was YEARLY, with a BYMONTH rule, and either + BYDAY or BYMONTHDAY match the first day of the month. + * Fixed: Events that are excluded using EXDATE are still counted in the + COUNT= parameter in the RRULE property. + * Added: Support for time-range filters on VALARM components. + * Fixed: Correctly filtering all-day events. + * Fixed: Sending back correct mimetypes from the browser plugin (thanks + Jürgen). + * Fixed: Issue 195: Sabre_CardDAV pear package had an incorrect dependency. + * Fixed: Calendardata would be destroyed when performing a MOVE request. + +1.6.0-stable (2012-02-22) + * BC Break: Now requires PHP 5.3 + * BC Break: Any node that implemented Sabre_DAVACL_IACL must now also + implement the getSupportedPrivilegeSet method. See website for details. + * BC Break: Moved functions from Sabre_CalDAV_XMLUtil to + Sabre_VObject_DateTimeParser. + * BC Break: The Sabre_DAVACL_IPrincipalCollection now has two new methods: + 'searchPrincipals' and 'updatePrincipal'. + * BC Break: Sabre_DAV_ILockable is removed and all related per-node + locking functionality. + * BC Break: Sabre_DAV_Exception_FileNotFound is now deprecated in favor of + Sabre_DAV_Exception_NotFound. The former will be removed in a later + version. + * BC Break: Removed Sabre_CalDAV_ICalendarUtil, use Sabre_VObject instead. + * BC Break: Sabre_CalDAV_Server is now deprecated, check out the + documentation on how to setup a caldav server with just + Sabre_DAV_Server. + * BC Break: Default Principals PDO backend now needs a new field in the + 'principals' table. See the website for details. + * Added: Ability to create new calendars and addressbooks from within the + browser plugin. + * Added: Browser plugin: icons for various nodes. + * Added: Support for FREEBUSY reports! + * Added: Support for creating principals with admin-level privileges. + * Added: Possibility to let server send out invitation emails on behalf of + CalDAV client, using Sabre_CalDAV_Schedule_IMip. + * Changed: beforeCreateFile event now passes data argument by reference. + * Changed: The 'propertyMap' property from Sabre_VObject_Reader, must now + be specified in Sabre_VObject_Property::$classMap. + * Added: Ability for plugins to tell the ACL plugin which principal + plugins are searchable. + * Added: [DAVACL] Per-node overriding of supported privileges. This allows + for custom privileges where needed. + * Added: [DAVACL] Public 'principalSearch' method on the DAVACL plugin, + which allows for easy searching for principals, based on their + properties. + * Added: Sabre_VObject_Component::getComponents() to return a list of only + components and not properties. + * Added: An includes.php file in every sub-package (CalDAV, CardDAV, DAV, + DAVACL, HTTP, VObject) as an alternative to the autoloader. This often + works much faster. + * Added: Support for the 'Me card', which allows Addressbook.app users + specify which vcard is their own. + * Added: Support for updating principal properties in the DAVACL principal + backends. + * Changed: Major refactoring in the calendar-query REPORT code. Should + make things more flexible and correct. + * Changed: The calendar-proxy-[read|write] principals will now only appear + in the tree, if they actually exist in the Principal backend. This should + reduce some problems people have been having with this. + * Changed: Sabre_VObject_Element_* classes are now renamed to + Sabre_VObject_Property. Old classes are retained for backwards + compatibility, but this will be removed in the future. + * Added: Sabre_VObject_FreeBusyGenerator to generate free-busy reports + based on lists of events. + * Added: Sabre_VObject_RecurrenceIterator to find all the dates and times + for recurring events. + * Fixed: Issue 97: Correctly handling RRULE for the calendar-query REPORT. + * Fixed: Issue 154: Encoding of VObject parameters with no value was + incorrect. + * Added: Support for {DAV:}acl-restrictions property from RFC3744. + * Added: The contentlength for calendar objects can now be supplied by a + CalDAV backend, allowing for more optimizations. + * Fixed: Much faster implementation of Sabre_DAV_URLUtil::encodePath. + * Fixed: {DAV:}getcontentlength may now be not specified. + * Fixed: Issue 66: Using rawurldecode instead of urldecode to decode paths + from clients. This means that + will now be treated as a literal rather + than a space, and this should improve compatibility with the Windows + built-in client. + * Added: Sabre_DAV_Exception_PaymentRequired exception, to emit HTTP 402 + status codes. + * Added: Some mysql unique constraints to example files. + * Fixed: Correctly formatting HTTP dates. + * Fixed: Issue 94: Sending back Last-Modified header for 304 responses. + * Added: Sabre_VObject_Component_VEvent, Sabre_VObject_Component_VJournal, + Sabre_VObject_Component_VTodo and Sabre_VObject_Component_VCalendar. + * Changed: Properties are now also automatically mapped to their + appropriate classes, if they are created using the add() or __set() + methods. + * Changed: Cloning VObject objects now clones the entire tree, rather than + just the default shallow copy. + * Added: Support for recurrence expansion in the CALDAV:calendar-multiget + and CALDAV:calendar-query REPORTS. + * Changed: CalDAV PDO backend now sorts calendars based on the internal + 'calendarorder' field. + * Added: Issue 181: Carddav backends may no optionally not supply the carddata in + getCards, if etag and size are specified. This may speed up certain + requests. + * Added: More arguments to beforeWriteContent and beforeCreateFile (see + WritingPlugins wiki document). + * Added: Hook for iCalendar validation. This allows us to validate + iCalendar objects when they're uploaded. At the moment we're just + validating syntax. + * Added: VObject now support Windows Timezone names correctly (thanks + mrpace2). + * Added: If a timezonename could not be detected, we fall back on the + default PHP timezone. + * Added: Now a Composer package (thanks willdurand). + * Fixed: Support for \N as a newline character in the VObject reader. + * Added: afterWriteContent, afterCreateFile and afterUnbind events. + * Added: Postgresql example files. Not part of the unittests though, so + use at your own risk. + * Fixed: Issue 182: Removed backticks from sql queries, so it will work + with Postgres. + +1.5.9-stable (2012-04-16) + * Fixed: Issue with parsing timezone identifiers that were surrounded by + quotes. (Fixes emClient compatibility). + +1.5.8-stable (2012-02-22) + * Fixed: Issue 95: Another timezone parsing issue, this time in + calendar-query. + +1.5.7-stable (2012-02-19) + * Fixed: VObject properties are now always encoded before components. + * Fixed: Sabre_DAVACL had issues with multiple levels of privilege + aggregration. + * Changed: Added 'GuessContentType' plugin to fileserver.php example. + * Fixed: The Browser plugin will now trigger the correct events when + creating files. + * Fixed: The ICSExportPlugin now considers ACL's. + * Added: Made it optional to supply carddata from an Addressbook backend + when requesting getCards. This can make some operations much faster, and + could result in much lower memory use. + * Fixed: Issue 187: Sabre_DAV_UUIDUtil was missing from includes file. + * Fixed: Issue 191: beforeUnlock was triggered twice. + +1.5.6-stable (2012-01-07) + * Fixed: Issue 174: VObject could break UTF-8 characters. + * Fixed: pear package installation issues. + +1.5.5-stable (2011-12-16) + * Fixed: CalDAV time-range filter workaround for recurring events. + * Fixed: Bug in Sabre_DAV_Locks_Backend_File that didn't allow multiple + files to be locked at the same time. + +1.5.4-stable (2011-10-28) + * Fixed: GuessContentType plugin now supports mixed case file extensions. + * Fixed: DATE-TIME encoding was wrong in VObject. (we used 'DATETIME'). + * Changed: Sending back HTTP 204 after a PUT request on an existing resource + instead of HTTP 200. This should fix Evolution CardDAV client + compatibility. + * Fixed: Issue 95: Parsing X-LIC-LOCATION if it's available. + * Added: All VObject elements now have a reference to their parent node. + +1.5.3-stable (2011-09-28) + * Fixed: Sabre_DAV_Collection was missing from the includes file. + * Fixed: Issue 152. iOS 1.4.2 apparantly requires HTTP/1.1 200 OK to be in + uppercase. + * Fixed: Issue 153: Support for files with mixed newline styles in + Sabre_VObject. + * Fixed: Issue 159: Automatically converting any vcard and icalendardata + to UTF-8. + * Added: Sabre_DAV_SimpleFile class for easy static file creation. + * Added: Issue 158: Support for the CARDDAV:supported-address-data + property. + +1.5.2-stable (2011-09-21) + * Fixed: carddata and calendardata MySQL fields are now of type + 'mediumblob'. 'TEXT' was too small sometimes to hold all the data. + * Fixed: {DAV:}supported-report-set is now correctly reporting the reports + for IAddressBook. + * Added: Sabre_VObject_Property::add() to add duplicate parameters to + properties. + * Added: Issue 151: Sabre_CalDAV_ICalendar and Sabre_CalDAV_ICalendarObject + interfaces. + * Fixed: Issue 140: Not returning 201 Created if an event cancelled the + creation of a file. + * Fixed: Issue 150: Faster URLUtil::encodePath() implementation. + * Fixed: Issue 144: Browser plugin could interfere with + TemporaryFileFilterPlugin if it was loaded first. + * Added: It's not possible to specify more 'alternate uris' in principal + backends. + +1.5.1-stable (2011-08-24) + * Fixed: Issue 137. Hiding action interface in HTML browser for + non-collections. + * Fixed: addressbook-query is now correctly returned from the + {DAV:}supported-report-set property. + * Fixed: Issue 142: Bugs in groupwareserver.php example. + * Fixed: Issue 139: Rejecting PUT requests with Content-Range. + +1.5.0-stable (2011-08-12) + * Added: CardDAV support. + * Added: An experimental WebDAV client. + * Added: MIME-Directory grouping support in the VObject library. This is + very useful for people attempting to parse vcards. + * BC Break: Adding parameters with the VObject libraries now overwrites + the previous parameter, rather than just add it. This makes more sense + for 99% of the cases. + * BC Break: lib/Sabre.autoload.php is now removed in favor of + lib/Sabre/autoload.php. + * Deprecated: Sabre_DAV_Directory is now deprecated and will be removed in + a future version. Use Sabre_DAV_Collection instead. + * Deprecated: Sabre_DAV_SimpleDirectory is now deprecated and will be + removed in a future version. Use Sabre_DAV_SimpleCollection instead. + * Fixed: Problem with overriding tablenames for the CalDAV backend. + * Added: Clark-notation parser to XML utility. + * Added: unset() support to VObject components. + * Fixed: Refactored CalDAV property fetching to be faster and simpler. + * Added: Central string-matcher for CalDAV and CardDAV plugins. + * Added: i;unicode-casemap support + * Fixed: VObject bug: wouldn't parse parameters if they weren't specified + in uppercase. + * Fixed: VObject bug: Parameters now behave more like Properties. + * Fixed: VObject bug: Parameters with no value are now correctly parsed. + * Changed: If calendars don't specify which components they allow, 'all' + components are assumed (e.g.: VEVENT, VTODO, VJOURNAL). + * Changed: Browser plugin now uses POST variable 'sabreAction' instead of + 'action' to reduce the chance of collisions. + +1.4.4-stable (2011-07-07) + * Fixed: Issue 131: Custom CalDAV backends could break in certain cases. + * Added: The option to override the default tablename all PDO backends + use. (Issue 60). + * Fixed: Issue 124: 'File' authentication backend now takes realm into + consideration. + * Fixed: Sabre_DAV_Property_HrefList now properly deserializes. This + allows users to update the {DAV:}group-member-set property. + * Added: Helper functions for DateTime-values in Sabre_VObject package. + * Added: VObject library can now automatically map iCalendar properties to + custom classes. + +1.4.3-stable (2011-04-25) + * Fixed: Issue 123: Added workaround for Windows 7 UNLOCK bug. + * Fixed: datatype of lastmodified field in mysql.calendars.sql. Please + change the DATETIME field to an INT to ensure this field will work + correctly. + * Change: Sabre_DAV_Property_Principal is now renamed to + Sabre_DAVACL_Property_Principal. + * Added: API level support for ACL HTTP method. + * Fixed: Bug in serializing {DAV:}acl property. + * Added: deserializer for {DAV:}resourcetype property. + * Added: deserializer for {DAV:}acl property. + * Added: deserializer for {DAV:}principal property. + +1.4.2-beta (2011-04-01) + * Added: It's not possible to disable listing of nodes that are denied + read access by ACL. + * Fixed: Changed a few properties in CalDAV classes from private to + protected. + * Fixed: Issue 119: Terrible things could happen when relying on + guessBaseUri, the server was running on the root of the domain and a user + tried to access a file ending in .php. This is a slight BC break. + * Fixed: Issue 118: Lock tokens in If headers without a uri should be + treated as the request uri, not 'all relevant uri's. + * Fixed: Issue 120: PDO backend was incorrectly fetching too much locks in + cases where there were similar named locked files in a directory. + +1.4.1-beta (2011-02-26) + * Fixed: Sabre_DAV_Locks_Backend_PDO returned too many locks. + * Fixed: Sabre_HTTP_Request::getHeader didn't return Content-Type when + running on apache, so a few workarounds were added. + * Change: Slightly changed CalDAV Backend API's, to allow for heavy + optimizations. This is non-bc breaking. + +1.4.0-beta (2011-02-12) + * Added: Partly RFC3744 ACL support. + * Added: Calendar-delegation (caldav-proxy) support. + * BC break: In order to fix Issue 99, a new argument had to be added to + Sabre_DAV_Locks_Backend_*::getLocks classes. Consult the classes for + details. + * Deprecated: Sabre_DAV_Locks_Backend_FS is now deprecated and will be + removed in a later version. Use PDO or the new File class instead. + * Deprecated: The Sabre_CalDAV_ICalendarUtil class is now marked + deprecated, and will be removed in a future version. Please use + Sabre_VObject instead. + * Removed: All principal-related functionality has been removed from the + Sabre_DAV_Auth_Plugin, and moved to the Sabre_DAVACL_Plugin. + * Added: VObject library, for easy vcard/icalendar parsing using a natural + interface. + * Added: Ability to automatically generate full .ics feeds off calendars. + To use: Add the Sabre_CalDAV_ICSExportPlugin, and add ?export to your + calendar url. + * Added: Plugins can now specify a pluginname, for easy access using + Sabre_DAV_Server::getPlugin(). + * Added: beforeGetProperties event. + * Added: updateProperties event. + * Added: Principal listings and calendar-access can now be done privately, + disallowing users from accessing or modifying other users' data. + * Added: You can now pass arrays to the Sabre_DAV_Server constructor. If + it's an array with node-objects, a Root collection will automatically be + created, and the nodes are used as top-level children. + * Added: The principal base uri is now customizable. It used to be + hardcoded to 'principals/[user]'. + * Added: getSupportedReportSet method in ServerPlugin class. This allows + you to easily specify which reports you're implementing. + * Added: A '..' link to the HTML browser. + * Fixed: Issue 99: Locks on child elements were ignored when their parent + nodes were deleted. + * Fixed: Issue 90: lockdiscovery property and LOCK response now include a + {DAV}lockroot element. + * Fixed: Issue 96: support for 'default' collation in CalDAV text-match + filters. + * Fixed: Issue 102: Ensuring that copy and move with identical source and + destination uri's fails. + * Fixed: Issue 105: Supporting MKCALENDAR with no body. + * Fixed: Issue 109: Small fixes in Sabre_HTTP_Util. + * Fixed: Issue 111: Properly catching the ownername in a lock (if it's a + string) + * Fixed: Sabre_DAV_ObjectTree::nodeExist always returned false for the + root node. + * Added: Global way to easily supply new resourcetypes for certain node + classes. + * Fixed: Issue 59: Allowing the user to override the authentication realm + in Sabre_CalDAV_Server. + * Update: Issue 97: Looser time-range checking if there's a recurrence + rule in an event. This fixes 'missing recurring events'. + +1.3.0 (2010-10-14) + * Added: childExists method to Sabre_DAV_ICollection. This is an api + break, so if you implement Sabre_DAV_ICollection directly, add the method. + * Changed: Almost all HTTP method implementations now take a uri argument, + including events. This allows for internal rerouting of certain calls. + If you have custom plugins, make sure they use this argument. If they + don't, they will likely still work, but it might get in the way of + future changes. + * Changed: All getETag methods MUST now surround the etag with + double-quotes. This was a mistake made in all previous SabreDAV + versions. If you don't do this, any If-Match, If-None-Match and If: + headers using Etags will work incorrectly. (Issue 85). + * Added: Sabre_DAV_Auth_Backend_AbstractBasic class, which can be used to + easily implement basic authentication. + * Removed: Sabre_DAV_PermissionDenied class. Use Sabre_DAV_Forbidden + instead. + * Removed: Sabre_DAV_IDirectory interface, use Sabre_DAV_ICollection + instead. + * Added: Browser plugin now uses {DAV:}displayname if this property is + available. + * Added: Cache layer in the ObjectTree. + * Added: Tree classes now have a delete and getChildren method. + * Fixed: If-Modified-Since and If-Unmodified-Since would be incorrect if + the date is an exact match. + * Fixed: Support for multiple ETags in If-Match and If-None-Match headers. + * Fixed: Improved baseUrl handling. + * Fixed: Issue 67: Non-seekable stream support in ::put()/::get(). + * Fixed: Issue 65: Invalid dates are now ignored. + * Updated: Refactoring in Sabre_CalDAV to make everything a bit more + ledgable. + * Fixed: Issue 88, Issue 89: Fixed compatibility for running SabreDAV on + Windows. + * Fixed: Issue 86: Fixed Content-Range top-boundary from 'file size' to + 'file size'-1. + +1.2.4 (2010-07-13) + * Fixed: Issue 62: Guessing baseUrl fails when url contains a + query-string. + * Added: Apache configuration sample for CGI/FastCGI setups. + * Fixed: Issue 64: Only returning calendar-data when it was actually + requested. + +1.2.3 (2010-06-26) + * Fixed: Issue 57: Supporting quotes around etags in If-Match and + If-None-Match + +1.2.2 (2010-06-21) + * Updated: SabreDAV now attempts to guess the BaseURI if it's not set. + * Updated: Better compatibility with BitKinex + * Fixed: Issue 56: Incorrect behaviour for If-None-Match headers and GET + requests. + * Fixed: Issue with certain encoded paths in Browser Plugin. + +1.2.1 (2010-06-07) + * Fixed: Issue 50, patch by Mattijs Hoitink. + * Fixed: Issue 51, Adding windows 7 lockfiles to TemporaryFileFilter. + * Fixed: Issue 38, Allowing custom filters to be added to + TemporaryFileFilter. + * Fixed: Issue 53, ETags in the If: header were always failing. This + behaviour is now corrected. + * Added: Apache Authentication backend, in case authentication through + .htaccess is desired. + * Updated: Small improvements to example files. + +1.2.0 (2010-05-24) + * Fixed: Browser plugin now displays international characters. + * Changed: More properties in CalDAV classes are now protected instead of + private. + +1.2.0beta3 (2010-05-14) + * Fixed: Custom properties were not properly sent back for allprops + requests. + * Fixed: Issue 49, incorrect parsing of PROPPATCH, affecting Office 2007. + * Changed: Removed CalDAV items from includes.php, and added a few missing + ones. + +1.2.0beta2 (2010-05-04) + * Fixed: Issue 46: Fatal error for some non-existent nodes. + * Updated: some example sql to include email address. + * Added: 208 and 508 statuscodes from RFC5842. + * Added: Apache2 configuration examples + +1.2.0beta1 (2010-04-28) + * Fixed: redundant namespace declaration in resourcetypes. + * Fixed: 2 locking bugs triggered by litmus when no Sabre_DAV_ILockable + interface is used. + * Changed: using http://sabredav.org/ns for all custom xml properties. + * Added: email address property to principals. + * Updated: CalendarObject validation. + +1.2.0alpha4 (2010-04-24) + * Added: Support for If-Range, If-Match, If-None-Match, If-Modified-Since, + If-Unmodified-Since. + * Changed: Brand new build system. Functionality is split up between + Sabre, Sabre_HTTP, Sabre_DAV and Sabre_CalDAV packages. In addition to + that a new non-pear package will be created with all this functionality + combined. + * Changed: Autoloader moved to Sabre/autoload.php. + * Changed: The Allow: header is now more accurate, with appropriate HTTP + methods per uri. + * Changed: Now throwing back Sabre_DAV_Exception_MethodNotAllowed on a few + places where Sabre_DAV_Exception_NotImplemented was used. + +1.2.0alpha3 (2010-04-20) + * Update: Complete rewrite of property updating. Now easier to use and + atomic. + * Fixed: Issue 16, automatically adding trailing / to baseUri. + * Added: text/plain is used for .txt files in GuessContentType plugin. + * Added: support for principal-property-search and + principal-search-property-set reports. + * Added: Issue 31: Hiding exception information by default. Can be turned + on with the Sabre_DAV_Server::$debugExceptions property. + +1.2.0alpha2 (2010-04-08) + * Added: Calendars are now private and can only be read by the owner. + * Fixed: double namespace declaration in multistatus responses. + * Added: MySQL database dumps. MySQL is now also supported next to SQLite. + * Added: expand-properties REPORT from RFC 3253. + * Added: Sabre_DAV_Property_IHref interface for properties exposing urls. + * Added: Issue 25: Throwing error on broken Finder behaviour. + * Changed: Authentication backend is now aware of current user. + +1.2.0alpha1 (2010-03-31) + * Fixed: Issue 26: Workaround for broken GVFS behaviour with encoded + special characters. + * Fixed: Issue 34: Incorrect Lock-Token response header for LOCK. Fixes + Office 2010 compatibility. + * Added: Issue 35: SabreDAV version to header to OPTIONS response to ease + debugging. + * Fixed: Issue 36: Incorrect variable name, throwing error in some + requests. + * Fixed: Issue 37: Incorrect smultron regex in temporary filefilter. + * Fixed: Issue 33: Converting ISO-8859-1 characters to UTF-8. + * Fixed: Issue 39 & Issue 40: Basename fails on non-utf-8 locales. + * Added: More unittests. + * Added: SabreDAV version to all error responses. + * Added: URLUtil class for decoding urls. + * Changed: Now using pear.sabredav.org pear channel. + * Changed: Sabre_DAV_Server::getCopyAndMoveInfo is now a public method. + +1.1.2-alpha (2010-03-18) + * Added: RFC5397 - current-user-principal support. + * Fixed: Issue 27: encoding entities in property responses. + * Added: naturalselection script now allows the user to specify a 'minimum + number of bytes' for deletion. This should reduce load due to less + crawling + * Added: Full support for the calendar-query report. + * Added: More unittests. + * Added: Support for complex property deserialization through the static + ::unserialize() method. + * Added: Support for modifying calendar-component-set + * Fixed: Issue 29: Added TIMEOUT_INFINITE constant + +1.1.1-alpha (2010-03-11) + * Added: RFC5689 - Extended MKCOL support. + * Fixed: Evolution support for CalDAV. + * Fixed: PDO-locks backend was pretty much completely broken. This is + 100% unittested now. + * Added: support for ctags. + * Fixed: Comma's between HTTP methods in 'Allow' method. + * Changed: default argument for Sabre_DAV_Locks_Backend_FS. This means a + datadirectory must always be specified from now on. + * Changed: Moved Sabre_DAV_Server::parseProps to + Sabre_DAV_XMLUtil::parseProperties. + * Changed: Sabre_DAV_IDirectory is now Sabre_DAV_ICollection. + * Changed: Sabre_DAV_Exception_PermissionDenied is now + Sabre_DAV_Exception_Forbidden. + * Changed: Sabre_CalDAV_ICalendarCollection is removed. + * Added: Sabre_DAV_IExtendedCollection. + * Added: Many more unittests. + * Added: support for calendar-timezone property. + +1.1.0-alpha (2010-03-01) + * Note: This version is forked from version 1.0.5, so release dates may be + out of order. + * Added: CalDAV - RFC 4791 + * Removed: Sabre_PHP_Exception. PHP has a built-in ErrorException for + this. + * Added: PDO authentication backend. + * Added: Example sql for auth, caldav, locks for sqlite. + * Added: Sabre_DAV_Browser_GuessContentType plugin + * Changed: Authentication plugin refactored, making it possible to + implement non-digest authentication. + * Fixed: Better error display in browser plugin. + * Added: Support for {DAV:}supported-report-set + * Added: XML utility class with helper functions for the WebDAV protocol. + * Added: Tons of unittests + * Added: PrincipalCollection and Principal classes + * Added: Sabre_DAV_Server::getProperties for easy property retrieval + * Changed: {DAV:}resourceType defaults to 0 + * Changed: Any non-null resourceType now gets a / appended to the href + value. Before this was just for {DAV:}collection's, but this is now also + the case for for example {DAV:}principal. + * Changed: The Href property class can now optionally create non-relative + uri's. + * Changed: Sabre_HTTP_Response now returns false if headers are already + sent and header-methods are called. + * Fixed: Issue 19: HEAD requests on Collections + * Fixed: Issue 21: Typo in Sabre_DAV_Property_Response + * Fixed: Issue 18: Doesn't work with Evolution Contacts + +1.0.15-stable (2010-05-28) + * Added: Issue 31: Hiding exception information by default. Can be turned + on with the Sabre_DAV_Server::$debugExceptions property. + * Added: Moved autoload from lib/ to lib/Sabre/autoload.php. This is also + the case in the upcoming 1.2.0, so it will improve future compatibility. + +1.0.14-stable (2010-04-15) + * Fixed: double namespace declaration in multistatus responses. + +1.0.13-stable (2010-03-30) + * Fixed: Issue 40: Last references to basename/dirname + +1.0.12-stable (2010-03-30) + * Fixed: Issue 37: Incorrect smultron regex in temporary filefilter. + * Fixed: Issue 26: Workaround for broken GVFS behaviour with encoded + special characters. + * Fixed: Issue 33: Converting ISO-8859-1 characters to UTF-8. + * Fixed: Issue 39: Basename fails on non-utf-8 locales. + * Added: More unittests. + * Added: SabreDAV version to all error responses. + * Added: URLUtil class for decoding urls. + * Updated: Now using pear.sabredav.org pear channel. + +1.0.11-stable (2010-03-23) + * Non-public release. This release is identical to 1.0.10, but it is used + to test releasing packages to pear.sabredav.org. + +1.0.10-stable (2010-03-22) + * Fixed: Issue 34: Invalid Lock-Token header response. + * Added: Issue 35: Addign SabreDAV version to HTTP OPTIONS responses. + +1.0.9-stable (2010-03-19) + * Fixed: Issue 27: Entities not being encoded in PROPFIND responses. + * Fixed: Issue 29: Added missing TIMEOUT_INFINITE constant. + +1.0.8-stable (2010-03-03) + * Fixed: Issue 21: typos causing errors + * Fixed: Issue 23: Comma's between methods in Allow header. + * Added: Sabre_DAV_ICollection interface, to aid in future compatibility. + * Added: Sabre_DAV_Exception_Forbidden exception. This will replace + Sabre_DAV_Exception_PermissionDenied in the future, and can already be + used to ensure future compatibility. + +1.0.7-stable (2010-02-24) + * Fixed: Issue 19 regression for MS Office + +1.0.6-stable (2010-02-23) + * Fixed: Issue 19: HEAD requests on Collections + +1.0.5-stable (2010-01-22) + * Fixed: Fatal error when a malformed url was used for unlocking, in + conjuction with Sabre.autoload.php due to a incorrect filename. + * Fixed: Improved unittests and build system + +1.0.4-stable (2010-01-11) + * Fixed: needed 2 different releases. One for googlecode and one for + pearfarm. This is to retain the old method to install SabreDAV until + pearfarm becomes the standard installation method. + +1.0.3-stable (2010-01-11) + * Added: RFC4709 support (davmount) + * Added: 6 unittests + * Added: naturalselection. A tool to keep cache directories below a + specified theshold. + * Changed: Now using pearfarm.org channel server. + +1.0.1-stable (2009-12-22) + * Fixed: Issue 15: typos in examples + * Fixed: Minor pear installation issues + +1.0.0-stable (2009-11-02) + * Added: SimpleDirectory class. This class allows creating static + directory structures with ease. + * Changed: Custom complex properties and exceptions now get an instance of + Sabre_DAV_Server as their first argument in serialize() + * Changed: Href complex property now prepends server's baseUri + * Changed: delete before an overwriting copy/move is now handles by server + class instead of tree classes + * Changed: events must now explicitly return false to stop execution. + Before, execution would be stopped by anything loosely evaluating to + false. + * Changed: the getPropertiesForPath method now takes a different set of + arguments, and returns a different response. This allows plugin + developers to return statuses for properties other than 200 and 404. The + hrefs are now also always calculated relative to the baseUri, and not + the uri of the request. + * Changed: generatePropFindResponse is renamed to generateMultiStatus, and + now takes a list of properties similar to the response of + getPropertiesForPath. This was also needed to improve flexibility for + plugin development. + * Changed: Auth plugins are no longer included. They were not yet stable + quality, so they will probably be reintroduced in a later version. + * Changed: PROPPATCH also used generateMultiStatus now. + * Removed: unknownProperties event. This is replaced by the + afterGetProperties event, which should provide more flexibility. + * Fixed: Only calling getSize() on IFile instances in httpHead() + * Added: beforeBind event. This is invoked upon file or directory creation + * Added: beforeWriteContent event, this is invoked by PUT and LOCK on an + existing resource. + * Added: beforeUnbind event. This is invoked right before deletion of any + resource. + * Added: afterGetProperties event. This event can be used to make + modifications to property responses. + * Added: beforeLock and beforeUnlock events. + * Added: afterBind event. + * Fixed: Copy and Move could fail in the root directory. This is now + fixed. + * Added: Plugins can now be retrieved by their classname. This is useful + for inter-plugin communication. + * Added: The Auth backend can now return usernames and user-id's. + * Added: The Auth backend got a getUsers method + * Added: Sabre_DAV_FSExt_Directory now returns quota info + +0.12.1-beta (2009-09-11) + * Fixed: UNLOCK bug. Unlock didn't work at all + +0.12-beta (2009-09-10) + * Updated: Browser plugin now shows multiple {DAV:}resourcetype values + if available. + * Added: Experimental PDO backend for Locks Manager + * Fixed: Sending Content-Length: 0 for every empty response. This + improves NGinx compatibility. + * Fixed: Last modification time is reported in UTC timezone. This improves + Finder compatibility. + +0.11-beta (2009-08-11) + * Updated: Now in Beta + * Updated: Pear package no longer includes docs/ directory. These just + contained rfc's, which are publically available. This reduces the + package from ~800k to ~60k + * Added: generatePropfindResponse now takes a baseUri argument + * Added: ResourceType property can now contain multiple resourcetypes. + * Fixed: Issue 13. + +0.10-alpha (2009-08-03) + * Added: Plugin to automatically map GET requests to non-files to + PROPFIND (Sabre_DAV_Browser_MapGetToPropFind). This should allow + easier debugging of complicated WebDAV setups. + * Added: Sabre_DAV_Property_Href class. For future use. + * Added: Ability to choose to use auth-int, auth or both for HTTP Digest + authentication. (Issue 11) + * Changed: Made more methods in Sabre_DAV_Server public. + * Fixed: TemporaryFileFilter plugin now intercepts HTTP LOCK requests + to non-existent files. (Issue 12) + * Added: Central list of defined xml namespace prefixes. This can reduce + Bandwidth and legibility for xml bodies with user-defined namespaces. + * Added: now a PEAR-compatible package again, thanks to Michael Gauthier + * Changed: moved default copy and move logic from ObjectTree to Tree class + +0.9-alpha (2009-07-21) + * Changed: Major refactoring, removed most of the logic from the Tree + objects. The Server class now directly works with the INode, IFile + and IDirectory objects. If you created your own Tree objects, + this will most likely break in this release. + * Changed: Moved all the Locking logic from the Tree and Server classes + into a separate plugin. + * Changed: TemporaryFileFilter is now a plugin. + * Added: Comes with an autoloader script. This can be used instead of + the includer script, and is preferred by some people. + * Added: AWS Authentication class. + * Added: simpleserversetup.py script. This will quickly get a fileserver + up and running. + * Added: When subscribing to events, it is now possible to supply a + priority. This is for example needed to ensure that the Authentication + Plugin is used before any other Plugin. + * Added: 22 new tests. + * Added: Users-manager plugin for .htdigest files. Experimental and + subject to change. + * Added: RFC 2324 HTTP 418 status code + * Fixed: Exclusive locks could in some cases be picked up as shared locks + * Fixed: Digest auth for non-apache servers had a bug (still not actually + tested this well). + +0.8-alpha (2009-05-30) + * Changed: Renamed all exceptions! This is a compatibility break. Every + Exception now follows Sabre_DAV_Exception_FileNotFound convention + instead of Sabre_DAV_FileNotFoundException. + * Added: Browser plugin now allows uploading and creating directories + straight from the browser. + * Added: 12 more unittests + * Fixed: Locking bug, which became prevalent on Windows Vista. + * Fixed: Netdrive support + * Fixed: TemporaryFileFilter filtered out too many files. Fixed some + of the regexes. + * Fixed: Added README and ChangeLog to package + +0.7-alpha (2009-03-29) + * Added: System to return complex properties from PROPFIND. + * Added: support for {DAV:}supportedlock. + * Added: support for {DAV:}lockdiscovery. + * Added: 6 new tests. + * Added: New plugin system. + * Added: Simple HTML directory plugin, for browser access. + * Added: Server class now sends back standard pre-condition error xml + bodies. This was new since RFC4918. + * Added: Sabre_DAV_Tree_Aggregrate, which can 'host' multiple Tree objects + into one. + * Added: simple basis for HTTP REPORT method. This method is not used yet, + but can be used by plugins to add reports. + * Changed: ->getSize is only called for files, no longer for collections. + r303 + * Changed: Sabre_DAV_FilterTree is now Sabre_DAV_Tree_Filter + * Changed: Sabre_DAV_TemporaryFileFilter is now called + Sabre_DAV_Tree_TemporaryFileFilter. + * Changed: removed functions (get(/set)HTTPRequest(/Response)) from Server + class, and using a public property instead. + * Fixed: bug related to parsing proppatch and propfind requests. Didn't + show up in most clients, but it needed fixing regardless. (r255) + * Fixed: auth-int is now properly supported within HTTP Digest. + * Fixed: Using application/xml for a mimetype vs. text/xml as per RFC4918 + sec 8.2. + * Fixed: TemporaryFileFilter now lets through GET's if they actually + exist on the backend. (r274) + * FIxed: Some methods didn't get passed through in the FilterTree (r283). + * Fixed: LockManager is now slightly more complex, Tree classes slightly + less. (r287) + +0.6-alpha (2009-02-16) + * Added: Now uses streams for files, instead of strings. + This means it won't require to hold entire files in memory, which can be + an issue if you're dealing with big files. Note that this breaks + compatibility for put() and createFile methods. + * Added: HTTP Digest Authentication helper class. + * Added: Support for HTTP Range header + * Added: Support for ETags within If: headers + * Added: The API can now return ETags and override the default Content-Type + * Added: starting with basic framework for unittesting, using PHPUnit. + * Added: 49 unittests. + * Added: Abstraction for the HTTP request. + * Updated: Using Clark Notation for tags in properties. This means tags + are serialized as {namespace}tagName instead of namespace#tagName + * Fixed: HTTP_BasicAuth class now works as expected. + * Fixed: DAV_Server uses / for a default baseUrl. + * Fixed: Last modification date is no longer ignored in PROPFIND. + * Fixed: PROPFIND now sends back information about the requestUri even + when "Depth: 1" is specified. + +0.5-alpha (2009-01-14) + * Added: Added a very simple example for implementing a mapping to PHP + file streams. This should allow easy implementation of for example a + WebDAV to FTP proxy. + * Added: HTTP Basic Authentication helper class. + * Added: Sabre_HTTP_Response class. This centralizes HTTP operations and + will be a start towards the creating of a testing framework. + * Updated: Backwards compatibility break: all require_once() statements + are removed + from all the files. It is now recommended to use autoloading of + classes, or just including lib/Sabre.includes.php. This fix was made + to allow easier integration into applications not using this standard + inclusion model. + * Updated: Better in-file documentation. + * Updated: Sabre_DAV_Tree can now work with Sabre_DAV_LockManager. + * Updated: Fixes a shared-lock bug. + * Updated: Removed ?> from the bottom of each php file. + * Updated: Split up some operations from Sabre_DAV_Server to + Sabre_HTTP_Response. + * Fixed: examples are now actually included in the pear package. + +0.4-alpha (2008-11-05) + * Passes all litmus tests! + * Added: more examples + * Added: Custom property support + * Added: Shared lock support + * Added: Depth support to locks + * Added: Locking on unmapped urls (non-existent nodes) + * Fixed: Advertising as WebDAV class 3 support + +0.3-alpha (2008-06-29) + * Fully working in MS Windows clients. + * Added: temporary file filter: support for smultron files. + * Added: Phing build scripts + * Added: PEAR package + * Fixed: MOVE bug identified using finder. + * Fixed: Using gzuncompress instead of gzdecode in the temporary file + filter. This seems more common. + +0.2-alpha (2008-05-27) + * Somewhat working in Windows clients + * Added: Working PROPPATCH method (doesn't support custom properties yet) + * Added: Temporary filename handling system + * Added: Sabre_DAV_IQuota to return quota information + * Added: PROPFIND now reads the request body and only supplies the + requested properties + +0.1-alpha (2008-04-04) + * First release! + * Passes litmus: basic, http and copymove test. + * Fully working in Finder and DavFSv2 + +Project started: 2007-12-13 diff --git a/sources/vendor/sabre/dav/LICENSE b/sources/vendor/sabre/dav/LICENSE new file mode 100644 index 00000000..7435c19f --- /dev/null +++ b/sources/vendor/sabre/dav/LICENSE @@ -0,0 +1,27 @@ +Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). + +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 SabreDAV nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. diff --git a/sources/vendor/sabre/dav/README.md b/sources/vendor/sabre/dav/README.md new file mode 100644 index 00000000..8346c9a3 --- /dev/null +++ b/sources/vendor/sabre/dav/README.md @@ -0,0 +1,30 @@ +# What is SabreDAV + +SabreDAV allows you to easily add WebDAV support to a PHP application. SabreDAV is meant to cover the entire standard, and attempts to allow integration using an easy to understand API. + +### Feature list: + +* Fully WebDAV compliant +* Supports Windows XP, Windows Vista, Mac OS/X, DavFSv2, Cadaver, Netdrive, Open Office, and probably more. +* Passing all Litmus tests. +* Supporting class 1, 2 and 3 Webdav servers. +* Locking support. +* Custom property support. +* CalDAV (tested with [Evolution](http://code.google.com/p/sabredav/wiki/Evolution), [iCal](http://code.google.com/p/sabredav/wiki/ICal), [iPhone](http://code.google.com/p/sabredav/wiki/IPhone) and [Lightning](http://code.google.com/p/sabredav/wiki/Lightning)). +* CardDAV (tested with [OS/X addressbook](http://code.google.com/p/sabredav/wiki/OSXAddressbook), the [iOS addressbook](http://code.google.com/p/sabredav/wiki/iOSCardDAV) and [Evolution](http://code.google.com/p/sabredav/wiki/Evolution)). +* Over 97% unittest code coverage. + +### Supported RFC's: + +* [RFC2617](http://www.ietf.org/rfc/rfc2617.txt): Basic/Digest auth. +* [RFC2518](http://www.ietf.org/rfc/rfc2518.txt): First WebDAV spec. +* [RFC3744](http://www.ietf.org/rfc/rfc3744.txt): ACL (some features missing). +* [RFC4709](http://www.ietf.org/rfc/rfc4709.txt): [DavMount](http://code.google.com/p/sabredav/wiki/DavMount). +* [RFC4791](http://www.ietf.org/rfc/rfc4791.txt): CalDAV. +* [RFC4918](http://www.ietf.org/rfc/rfc4918.txt): WebDAV revision. +* [RFC5397](http://www.ietf.org/rfc/rfc5689.txt): current-user-principal. +* [RFC5689](http://www.ietf.org/rfc/rfc5689.txt): Extended MKCOL. +* [RFC5789](http://tools.ietf.org/html/rfc5789): PATCH method for HTTP. +* [RFC6352](http://www.ietf.org/rfc/rfc6352.txt): CardDAV +* [draft-daboo-carddav-directory-gateway](http://tools.ietf.org/html/draft-daboo-carddav-directory-gateway): CardDAV directory gateway +* CalDAV ctag, CalDAV-proxy. diff --git a/sources/vendor/sabre/dav/bin/build.php b/sources/vendor/sabre/dav/bin/build.php new file mode 100644 index 00000000..11cca1e6 --- /dev/null +++ b/sources/vendor/sabre/dav/bin/build.php @@ -0,0 +1,137 @@ + [ + 'init', 'test', 'clean', + ], + 'markrelease' => [ + 'init', 'test', 'clean', + ], + 'clean' => [], + 'test' => [ + 'composerupdate', + ], + 'init' => [], + 'composerupdate' => [], + ]; + +$default = 'buildzip'; + +$baseDir = __DIR__ . '/../'; +chdir($baseDir); + +$currentTask = $default; +if ($argc > 1) $currentTask = $argv[1]; +$version = null; +if ($argc > 2) $version = $argv[2]; + +if (!isset($tasks[$currentTask])) { + echo "Task not found: ", $currentTask, "\n"; + die(1); +} + +// Creating the dependency graph +$newTaskList = []; +$oldTaskList = [$currentTask => true]; + +while(count($oldTaskList)>0) { + + foreach($oldTaskList as $task=>$foo) { + + if (!isset($tasks[$task])) { + echo "Dependency not found: " . $task, "\n"; + die(1); + } + $dependencies = $tasks[$task]; + + $fullFilled = true; + foreach($dependencies as $dependency) { + if (isset($newTaskList[$dependency])) { + // Already in the fulfilled task list. + continue; + } else { + $oldTaskList[$dependency] = true; + $fullFilled = false; + } + + } + if ($fullFilled) { + unset($oldTaskList[$task]); + $newTaskList[$task] = 1; + } + + } + +} + +foreach(array_keys($newTaskList) as $task) { + + echo "task: " . $task, "\n"; + call_user_func($task); + echo "\n"; + +} + +function init() { + + global $version; + if (!$version) { + include __DIR__ . '/../vendor/autoload.php'; + $version = Sabre\DAV\Version::VERSION; + } + + echo " Building sabre/dav " . $version, "\n"; + +} + +function clean() { + + global $baseDir; + echo " Removing build files\n"; + $outputDir = $baseDir . '/build/SabreDAV'; + if (is_dir($outputDir)) { + system('rm -r ' . $baseDir . '/build/SabreDAV'); + } + +} + +function composerupdate() { + + global $baseDir; + echo " Updating composer packages to latest version\n\n"; + system('cd ' . $baseDir . '; composer update --dev'); +} + +function test() { + + global $baseDir; + + echo " Running all unittests.\n"; + echo " This may take a while.\n\n"; + system(__DIR__ . '/phpunit --configuration ' . $baseDir . '/tests/phpunit.xml --stop-on-failure', $code); + if ($code != 0) { + echo "PHPUnit reported error code $code\n"; + die(1); + } + +} + +function buildzip() { + + global $baseDir, $version; + echo " Asking composer to download sabre/dav $version\n\n"; + system("composer create-project --no-dev sabre/dav build/SabreDAV $version", $code); + if ($code!==0) { + echo "Composer reported error code $code\n"; + die(1); + } + // + + echo "\n"; + echo "Zipping the sabredav distribution\n\n"; + system('cd build; zip -qr sabredav-' . $version . '.zip SabreDAV'); + + echo "Done."; + +} diff --git a/sources/vendor/sabre/dav/bin/googlecode_upload.py b/sources/vendor/sabre/dav/bin/googlecode_upload.py new file mode 100755 index 00000000..caafd5de --- /dev/null +++ b/sources/vendor/sabre/dav/bin/googlecode_upload.py @@ -0,0 +1,248 @@ +#!/usr/bin/env python +# +# Copyright 2006, 2007 Google Inc. All Rights Reserved. +# Author: danderson@google.com (David Anderson) +# +# Script for uploading files to a Google Code project. +# +# This is intended to be both a useful script for people who want to +# streamline project uploads and a reference implementation for +# uploading files to Google Code projects. +# +# To upload a file to Google Code, you need to provide a path to the +# file on your local machine, a small summary of what the file is, a +# project name, and a valid account that is a member or owner of that +# project. You can optionally provide a list of labels that apply to +# the file. The file will be uploaded under the same name that it has +# in your local filesystem (that is, the "basename" or last path +# component). Run the script with '--help' to get the exact syntax +# and available options. +# +# Note that the upload script requests that you enter your +# googlecode.com password. This is NOT your Gmail account password! +# This is the password you use on googlecode.com for committing to +# Subversion and uploading files. You can find your password by going +# to http://code.google.com/hosting/settings when logged in with your +# Gmail account. If you have already committed to your project's +# Subversion repository, the script will automatically retrieve your +# credentials from there (unless disabled, see the output of '--help' +# for details). +# +# If you are looking at this script as a reference for implementing +# your own Google Code file uploader, then you should take a look at +# the upload() function, which is the meat of the uploader. You +# basically need to build a multipart/form-data POST request with the +# right fields and send it to https://PROJECT.googlecode.com/files . +# Authenticate the request using HTTP Basic authentication, as is +# shown below. +# +# Licensed under the terms of the Apache Software License 2.0: +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Questions, comments, feature requests and patches are most welcome. +# Please direct all of these to the Google Code users group: +# http://groups.google.com/group/google-code-hosting + +"""Google Code file uploader script. +""" + +__author__ = 'danderson@google.com (David Anderson)' + +import httplib +import os.path +import optparse +import getpass +import base64 +import sys + + +def upload(file, project_name, user_name, password, summary, labels=None): + """Upload a file to a Google Code project's file server. + + Args: + file: The local path to the file. + project_name: The name of your project on Google Code. + user_name: Your Google account name. + password: The googlecode.com password for your account. + Note that this is NOT your global Google Account password! + summary: A small description for the file. + labels: an optional list of label strings with which to tag the file. + + Returns: a tuple: + http_status: 201 if the upload succeeded, something else if an + error occurred. + http_reason: The human-readable string associated with http_status + file_url: If the upload succeeded, the URL of the file on Google + Code, None otherwise. + """ + # The login is the user part of user@gmail.com. If the login provided + # is in the full user@domain form, strip it down. + if user_name.endswith('@gmail.com'): + user_name = user_name[:user_name.index('@gmail.com')] + + form_fields = [('summary', summary)] + if labels is not None: + form_fields.extend([('label', l.strip()) for l in labels]) + + content_type, body = encode_upload_request(form_fields, file) + + upload_host = '%s.googlecode.com' % project_name + upload_uri = '/files' + auth_token = base64.b64encode('%s:%s'% (user_name, password)) + headers = { + 'Authorization': 'Basic %s' % auth_token, + 'User-Agent': 'Googlecode.com uploader v0.9.4', + 'Content-Type': content_type, + } + + server = httplib.HTTPSConnection(upload_host) + server.request('POST', upload_uri, body, headers) + resp = server.getresponse() + server.close() + + if resp.status == 201: + location = resp.getheader('Location', None) + else: + location = None + return resp.status, resp.reason, location + + +def encode_upload_request(fields, file_path): + """Encode the given fields and file into a multipart form body. + + fields is a sequence of (name, value) pairs. file is the path of + the file to upload. The file will be uploaded to Google Code with + the same file name. + + Returns: (content_type, body) ready for httplib.HTTP instance + """ + BOUNDARY = '----------Googlecode_boundary_reindeer_flotilla' + CRLF = '\r\n' + + body = [] + + # Add the metadata about the upload first + for key, value in fields: + body.extend( + ['--' + BOUNDARY, + 'Content-Disposition: form-data; name="%s"' % key, + '', + value, + ]) + + # Now add the file itself + file_name = os.path.basename(file_path) + f = open(file_path, 'rb') + file_content = f.read() + f.close() + + body.extend( + ['--' + BOUNDARY, + 'Content-Disposition: form-data; name="filename"; filename="%s"' + % file_name, + # The upload server determines the mime-type, no need to set it. + 'Content-Type: application/octet-stream', + '', + file_content, + ]) + + # Finalize the form body + body.extend(['--' + BOUNDARY + '--', '']) + + return 'multipart/form-data; boundary=%s' % BOUNDARY, CRLF.join(body) + + +def upload_find_auth(file_path, project_name, summary, labels=None, + user_name=None, password=None, tries=3): + """Find credentials and upload a file to a Google Code project's file server. + + file_path, project_name, summary, and labels are passed as-is to upload. + + Args: + file_path: The local path to the file. + project_name: The name of your project on Google Code. + summary: A small description for the file. + labels: an optional list of label strings with which to tag the file. + config_dir: Path to Subversion configuration directory, 'none', or None. + user_name: Your Google account name. + tries: How many attempts to make. + """ + + while tries > 0: + if user_name is None: + # Read username if not specified or loaded from svn config, or on + # subsequent tries. + sys.stdout.write('Please enter your googlecode.com username: ') + sys.stdout.flush() + user_name = sys.stdin.readline().rstrip() + if password is None: + # Read password if not loaded from svn config, or on subsequent tries. + print 'Please enter your googlecode.com password.' + print '** Note that this is NOT your Gmail account password! **' + print 'It is the password you use to access Subversion repositories,' + print 'and can be found here: http://code.google.com/hosting/settings' + password = getpass.getpass() + + status, reason, url = upload(file_path, project_name, user_name, password, + summary, labels) + # Returns 403 Forbidden instead of 401 Unauthorized for bad + # credentials as of 2007-07-17. + if status in [httplib.FORBIDDEN, httplib.UNAUTHORIZED]: + # Rest for another try. + user_name = password = None + tries = tries - 1 + else: + # We're done. + break + + return status, reason, url + + +def main(): + parser = optparse.OptionParser(usage='googlecode-upload.py -s SUMMARY ' + '-p PROJECT [options] FILE') + parser.add_option('-s', '--summary', dest='summary', + help='Short description of the file') + parser.add_option('-p', '--project', dest='project', + help='Google Code project name') + parser.add_option('-u', '--user', dest='user', + help='Your Google Code username') + parser.add_option('-w', '--password', dest='password', + help='Your Google Code password') + parser.add_option('-l', '--labels', dest='labels', + help='An optional list of comma-separated labels to attach ' + 'to the file') + + options, args = parser.parse_args() + + if not options.summary: + parser.error('File summary is missing.') + elif not options.project: + parser.error('Project name is missing.') + elif len(args) < 1: + parser.error('File to upload not provided.') + elif len(args) > 1: + parser.error('Only one file may be specified.') + + file_path = args[0] + + if options.labels: + labels = options.labels.split(',') + else: + labels = None + + status, reason, url = upload_find_auth(file_path, options.project, + options.summary, labels, + options.user, options.password) + if url: + print 'The file was uploaded successfully.' + print 'URL: %s' % url + return 0 + else: + print 'An error occurred. Your file was not uploaded.' + print 'Google Code upload server said: %s (%s)' % (reason, status) + return 1 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/sources/vendor/sabre/dav/bin/migrateto17.php b/sources/vendor/sabre/dav/bin/migrateto17.php new file mode 100755 index 00000000..66a9ee56 --- /dev/null +++ b/sources/vendor/sabre/dav/bin/migrateto17.php @@ -0,0 +1,284 @@ +#!/usr/bin/env php +setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); +$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); + +echo "Validating existing table layout\n"; + +// The only cross-db way to do this, is to just fetch a single record. +$row = $pdo->query("SELECT * FROM calendarobjects LIMIT 1")->fetch(); + +if (!$row) { + echo "Error: This database did not have any records in the calendarobjects table, you should just recreate the table.\n"; + exit(-1); +} + +$requiredFields = array( + 'id', + 'calendardata', + 'uri', + 'calendarid', + 'lastmodified', +); + +foreach($requiredFields as $requiredField) { + if (!array_key_exists($requiredField,$row)) { + echo "Error: The current 'calendarobjects' table was missing a field we expected to exist.\n"; + echo "For safety reasons, this process is stopped.\n"; + exit(-1); + } +} + +$fields17 = array( + 'etag', + 'size', + 'componenttype', + 'firstoccurence', + 'lastoccurence', +); + +$found = 0; +foreach($fields17 as $field) { + if (array_key_exists($field, $row)) { + $found++; + } +} + +if ($found === 0) { + echo "The database had the 1.6 schema. Table will now be altered.\n"; + echo "This may take some time for large tables\n"; + + switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) { + + case 'mysql' : + + $pdo->exec(<<exec('ALTER TABLE calendarobjects ADD etag text'); + $pdo->exec('ALTER TABLE calendarobjects ADD size integer'); + $pdo->exec('ALTER TABLE calendarobjects ADD componenttype TEXT'); + $pdo->exec('ALTER TABLE calendarobjects ADD firstoccurence integer'); + $pdo->exec('ALTER TABLE calendarobjects ADD lastoccurence integer'); + break; + + default : + die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n"); + + } + echo "Database schema upgraded.\n"; + +} elseif ($found === 5) { + + echo "Database already had the 1.7 schema\n"; + +} else { + + echo "The database had $found out of 5 from the changes for 1.7. This is scary and unusual, so we have to abort.\n"; + echo "You can manually try to upgrade the schema, and then run this script again.\n"; + exit(-1); + +} + +echo "Now, we need to parse every record and pull out some information.\n"; + +$result = $pdo->query('SELECT id, calendardata FROM calendarobjects'); +$stmt = $pdo->prepare('UPDATE calendarobjects SET etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ? WHERE id = ?'); + +echo "Total records found: " . $result->rowCount() . "\n"; +$done = 0; +$total = $result->rowCount(); +while($row = $result->fetch()) { + + try { + $newData = getDenormalizedData($row['calendardata']); + } catch (Exception $e) { + echo "===\nException caught will trying to parser calendarobject.\n"; + echo "Error message: " . $e->getMessage() . "\n"; + echo "Record id: " . $row['id'] . "\n"; + echo "This record is ignored, you should inspect it to see if there's anything wrong.\n===\n"; + continue; + } + $stmt->execute(array( + $newData['etag'], + $newData['size'], + $newData['componentType'], + $newData['firstOccurence'], + $newData['lastOccurence'], + $row['id'], + )); + $done++; + + if ($done % 500 === 0) { + echo "Completed: $done / $total\n"; + } +} +echo "Completed: $done / $total\n"; + +echo "Checking the calendars table needs changes.\n"; +$row = $pdo->query("SELECT * FROM calendars LIMIT 1")->fetch(); + +if (array_key_exists('transparent', $row)) { + + echo "The calendars table is already up to date\n"; + +} else { + + echo "Adding the 'transparent' field to the calendars table\n"; + + switch($pdo->getAttribute(PDO::ATTR_DRIVER_NAME)) { + + case 'mysql' : + $pdo->exec("ALTER TABLE calendars ADD transparent TINYINT(1) NOT NULL DEFAULT '0'"); + break; + case 'sqlite' : + $pdo->exec("ALTER TABLE calendars ADD transparent bool"); + break; + + default : + die('This upgrade script does not support this driver (' . $pdo->getAttribute(PDO::ATTR_DRIVER_NAME) . ")\n"); + + } + +} + +echo "Process completed!\n"; + +/** + * Parses some information from calendar objects, used for optimized + * calendar-queries. + * + * Blantently copied from Sabre\CalDAV\Backend\PDO + * + * Returns an array with the following keys: + * * etag + * * size + * * componentType + * * firstOccurence + * * lastOccurence + * + * @param string $calendarData + * @return array + */ +function getDenormalizedData($calendarData) { + + $vObject = \Sabre\VObject\Reader::read($calendarData); + $componentType = null; + $component = null; + $firstOccurence = null; + $lastOccurence = null; + foreach($vObject->getComponents() as $component) { + if ($component->name!=='VTIMEZONE') { + $componentType = $component->name; + break; + } + } + if (!$componentType) { + throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component'); + } + if ($componentType === 'VEVENT') { + $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp(); + // Finding the last occurence is a bit harder + if (!isset($component->RRULE)) { + if (isset($component->DTEND)) { + $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp(); + } elseif (isset($component->DURATION)) { + $endDate = clone $component->DTSTART->getDateTime(); + $endDate->add(\Sabre\VObject\DateTimeParser::parse($component->DURATION->value)); + $lastOccurence = $endDate->getTimeStamp(); + } elseif (!$component->DTSTART->hasTime()) { + $endDate = clone $component->DTSTART->getDateTime(); + $endDate->modify('+1 day'); + $lastOccurence = $endDate->getTimeStamp(); + } else { + $lastOccurence = $firstOccurence; + } + } else { + $it = new \Sabre\VObject\RecurrenceIterator($vObject, (string)$component->UID); + $maxDate = new DateTime(\Sabre\CalDAV\Backend\PDO::MAX_DATE); + if ($it->isInfinite()) { + $lastOccurence = $maxDate->getTimeStamp(); + } else { + $end = $it->getDtEnd(); + while($it->valid() && $end < $maxDate) { + $end = $it->getDtEnd(); + $it->next(); + + } + $lastOccurence = $end->getTimeStamp(); + } + + } + } + + return array( + 'etag' => md5($calendarData), + 'size' => strlen($calendarData), + 'componentType' => $componentType, + 'firstOccurence' => $firstOccurence, + 'lastOccurence' => $lastOccurence, + ); + +} diff --git a/sources/vendor/sabre/dav/bin/naturalselection.py b/sources/vendor/sabre/dav/bin/naturalselection.py new file mode 100755 index 00000000..aa5554dd --- /dev/null +++ b/sources/vendor/sabre/dav/bin/naturalselection.py @@ -0,0 +1,140 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2009-2010 Evert Pot +# All rights reserved. +# http://www.rooftopsolutions.nl/ +# +# This utility is distributed along with SabreDAV +# license: http://code.google.com/p/sabredav/wiki/License Modified BSD License + +import os +from optparse import OptionParser +import time + +def getfreespace(path): + stat = os.statvfs(path) + return stat.f_frsize * stat.f_bavail + +def getbytesleft(path,treshold): + return getfreespace(path)-treshold + +def run(cacheDir, treshold, sleep=5, simulate=False, min_erase = 0): + + bytes = getbytesleft(cacheDir,treshold) + if (bytes>0): + print "Bytes to go before we hit treshhold:", bytes + else: + print "Treshold exceeded with:", -bytes, "bytes" + dir = os.listdir(cacheDir) + dir2 = [] + for file in dir: + path = cacheDir + '/' + file + dir2.append({ + "path" : path, + "atime": os.stat(path).st_atime, + "size" : os.stat(path).st_size + }) + + dir2.sort(lambda x,y: int(x["atime"]-y["atime"])) + + filesunlinked = 0 + gainedspace = 0 + + # Left is the amount of bytes that need to be freed up + # The default is the 'min_erase setting' + left = min_erase + + # If the min_erase setting is lower than the amount of bytes over + # the treshold, we use that number instead. + if left < -bytes : + left = -bytes + + print "Need to delete at least:", left; + + for file in dir2: + + # Only deleting files if we're not simulating + if not simulate: os.unlink(file["path"]) + left = int(left - file["size"]) + gainedspace = gainedspace + file["size"] + filesunlinked = filesunlinked + 1 + + if(left<0): + break + + print "%d files deleted (%d bytes)" % (filesunlinked, gainedspace) + + + time.sleep(sleep) + + + +def main(): + parser = OptionParser( + version="naturalselecton v0.3", + description="Cache directory manager. Deletes cache entries based on accesstime and free space tresholds.\n" + + "This utility is distributed alongside SabreDAV.", + usage="usage: %prog [options] cacheDirectory", + ) + parser.add_option( + '-s', + dest="simulate", + action="store_true", + help="Don't actually make changes, but just simulate the behaviour", + ) + parser.add_option( + '-r','--runs', + help="How many times to check before exiting. -1 is infinite, which is the default", + type="int", + dest="runs", + default=-1 + ) + parser.add_option( + '-n','--interval', + help="Sleep time in seconds (default = 5)", + type="int", + dest="sleep", + default=5 + ) + parser.add_option( + '-l','--treshold', + help="Treshhold in bytes (default = 10737418240, which is 10GB)", + type="int", + dest="treshold", + default=10737418240 + ) + parser.add_option( + '-m', '--min-erase', + help="Minimum number of bytes to erase when the treshold is reached. " + + "Setting this option higher will reduce the amount of times the cache directory will need to be scanned. " + + "(the default is 1073741824, which is 1GB.)", + type="int", + dest="min_erase", + default=1073741824 + ) + + options,args = parser.parse_args() + if len(args)<1: + parser.error("This utility requires at least 1 argument") + cacheDir = args[0] + + print "Natural Selection" + print "Cache directory:", cacheDir + free = getfreespace(cacheDir); + print "Current free disk space:", free + + runs = options.runs; + while runs!=0 : + run( + cacheDir, + sleep=options.sleep, + simulate=options.simulate, + treshold=options.treshold, + min_erase=options.min_erase + ) + if runs>0: + runs = runs - 1 + +if __name__ == '__main__' : + main() diff --git a/sources/vendor/sabre/dav/bin/sabredav b/sources/vendor/sabre/dav/bin/sabredav new file mode 100755 index 00000000..032371ba --- /dev/null +++ b/sources/vendor/sabre/dav/bin/sabredav @@ -0,0 +1,2 @@ +#!/bin/sh +php -S 0.0.0.0:8080 `dirname $0`/sabredav.php diff --git a/sources/vendor/sabre/dav/bin/sabredav.php b/sources/vendor/sabre/dav/bin/sabredav.php new file mode 100755 index 00000000..34a674fd --- /dev/null +++ b/sources/vendor/sabre/dav/bin/sabredav.php @@ -0,0 +1,53 @@ +stream = fopen('php://stdout','w'); + + } + + function log($msg) { + fwrite($this->stream, $msg . "\n"); + } + +} + +$log = new CliLog(); + +if (php_sapi_name()!=='cli-server') { + die("This script is intended to run on the built-in php webserver"); +} + +// Finding composer + + +$paths = array( + __DIR__ . '/../vendor/autoload.php', + __DIR__ . '/../../../autoload.php', +); + +foreach($paths as $path) { + if (file_exists($path)) { + include $path; + break; + } +} + +use Sabre\DAV; + +// Root +$root = new DAV\FS\Directory(getcwd()); + +// Setting up server. +$server = new DAV\Server($root); + +// Browser plugin +$server->addPlugin(new DAV\Browser\Plugin()); + +$server->exec(); diff --git a/sources/vendor/sabre/dav/examples/addressbookserver.php b/sources/vendor/sabre/dav/examples/addressbookserver.php new file mode 100644 index 00000000..b8986bc4 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/addressbookserver.php @@ -0,0 +1,56 @@ +setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); + +//Mapping PHP errors to exceptions +function exception_error_handler($errno, $errstr, $errfile, $errline ) { + throw new ErrorException($errstr, 0, $errno, $errfile, $errline); +} +set_error_handler("exception_error_handler"); + +// Autoloader +require_once 'vendor/autoload.php'; + +// Backends +$authBackend = new Sabre\DAV\Auth\Backend\PDO($pdo); +$principalBackend = new Sabre\DAVACL\PrincipalBackend\PDO($pdo); +$carddavBackend = new Sabre\CardDAV\Backend\PDO($pdo); +//$caldavBackend = new Sabre\CalDAV\Backend\PDO($pdo); + +// Setting up the directory tree // +$nodes = array( + new Sabre\DAVACL\PrincipalCollection($principalBackend), +// new Sabre\CalDAV\CalendarRootNode($authBackend, $caldavBackend), + new Sabre\CardDAV\AddressBookRoot($principalBackend, $carddavBackend), +); + +// The object tree needs in turn to be passed to the server class +$server = new Sabre\DAV\Server($nodes); +$server->setBaseUri($baseUri); + +// Plugins +$server->addPlugin(new Sabre\DAV\Auth\Plugin($authBackend,'SabreDAV')); +$server->addPlugin(new Sabre\DAV\Browser\Plugin()); +//$server->addPlugin(new Sabre\CalDAV\Plugin()); +$server->addPlugin(new Sabre\CardDAV\Plugin()); +$server->addPlugin(new Sabre\DAVACL\Plugin()); + +// And off we go! +$server->exec(); diff --git a/sources/vendor/sabre/dav/examples/basicauth.php b/sources/vendor/sabre/dav/examples/basicauth.php new file mode 100644 index 00000000..743c07ce --- /dev/null +++ b/sources/vendor/sabre/dav/examples/basicauth.php @@ -0,0 +1,26 @@ +getUserPass(); + +if (!$result || $result[0]!=$u || $result[1]!=$p) { + + $auth->requireLogin(); + echo "Authentication required\n"; + die(); + +} diff --git a/sources/vendor/sabre/dav/examples/digestauth.php b/sources/vendor/sabre/dav/examples/digestauth.php new file mode 100644 index 00000000..1f4a74b4 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/digestauth.php @@ -0,0 +1,25 @@ +init(); + +if ($auth->getUsername() != $u || !$auth->validatePassword($p)) { + + $auth->requireLogin(); + echo "Authentication required\n"; + die(); + +} diff --git a/sources/vendor/sabre/dav/examples/simplefsserver.php b/sources/vendor/sabre/dav/examples/simplefsserver.php new file mode 100644 index 00000000..f1b4a110 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/simplefsserver.php @@ -0,0 +1,123 @@ +myPath = $myPath; + + } + + function getChildren() { + + $children = array(); + // Loop through the directory, and create objects for each node + foreach(scandir($this->myPath) as $node) { + + // Ignoring files staring with . + if ($node[0]==='.') continue; + + $children[] = $this->getChild($node); + + } + + return $children; + + } + + function getChild($name) { + + $path = $this->myPath . '/' . $name; + + // We have to throw a NotFound exception if the file didn't exist + if (!file\exists($this->myPath)) throw new \Sabre\DAV\Exception\NotFound('The file with name: ' . $name . ' could not be found'); + // Some added security + + if ($name[0]=='.') throw new \Sabre\DAV\Exception\Forbidden('Access denied'); + + if (is_dir($path)) { + + return new \MyCollection($name); + + } else { + + return new \MyFile($path); + + } + + } + + function getName() { + + return basename($this->myPath); + + } + +} + +class MyFile extends \Sabre\DAV\File { + + private $myPath; + + function __construct($myPath) { + + $this->myPath = $myPath; + + } + + function getName() { + + return basename($this->myPath); + + } + + function get() { + + return fopen($this->myPath,'r'); + + } + + function getSize() { + + return filesize($this->myPath); + + } + +} + +// Make sure there is a directory in your current directory named 'public'. We will be exposing that directory to WebDAV +$rootNode = new \MyCollection($publicDir); + +// The rootNode needs to be passed to the server object. +$server = new \Sabre\DAV\Server($rootNode); + +// And off we go! +$server->exec(); diff --git a/sources/vendor/sabre/dav/examples/sql/mysql.addressbook.sql b/sources/vendor/sabre/dav/examples/sql/mysql.addressbook.sql new file mode 100644 index 00000000..f603ad4c --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/mysql.addressbook.sql @@ -0,0 +1,18 @@ +CREATE TABLE addressbooks ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principaluri VARCHAR(255), + displayname VARCHAR(255), + uri VARCHAR(200), + description TEXT, + ctag INT(11) UNSIGNED NOT NULL DEFAULT '1', + UNIQUE(principaluri, uri) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +CREATE TABLE cards ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + addressbookid INT(11) UNSIGNED NOT NULL, + carddata MEDIUMBLOB, + uri VARCHAR(200), + lastmodified INT(11) UNSIGNED +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + diff --git a/sources/vendor/sabre/dav/examples/sql/mysql.calendars.sql b/sources/vendor/sabre/dav/examples/sql/mysql.calendars.sql new file mode 100644 index 00000000..a8eb102d --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/mysql.calendars.sql @@ -0,0 +1,28 @@ +CREATE TABLE calendarobjects ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + calendardata MEDIUMBLOB, + uri VARCHAR(200), + calendarid INTEGER UNSIGNED NOT NULL, + lastmodified INT(11) UNSIGNED, + etag VARCHAR(32), + size INT(11) UNSIGNED NOT NULL, + componenttype VARCHAR(8), + firstoccurence INT(11) UNSIGNED, + lastoccurence INT(11) UNSIGNED, + UNIQUE(calendarid, uri) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +CREATE TABLE calendars ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principaluri VARCHAR(100), + displayname VARCHAR(100), + uri VARCHAR(200), + ctag INTEGER UNSIGNED NOT NULL DEFAULT '0', + description TEXT, + calendarorder INTEGER UNSIGNED NOT NULL DEFAULT '0', + calendarcolor VARCHAR(10), + timezone TEXT, + components VARCHAR(20), + transparent TINYINT(1) NOT NULL DEFAULT '0', + UNIQUE(principaluri, uri) +) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; diff --git a/sources/vendor/sabre/dav/examples/sql/mysql.locks.sql b/sources/vendor/sabre/dav/examples/sql/mysql.locks.sql new file mode 100644 index 00000000..cf3caf4f --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/mysql.locks.sql @@ -0,0 +1,13 @@ +CREATE TABLE locks ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + owner VARCHAR(100), + timeout INTEGER UNSIGNED, + created INTEGER, + token VARCHAR(100), + scope TINYINT, + depth TINYINT, + uri VARCHAR(1000), + INDEX(token), + INDEX(uri) +); + diff --git a/sources/vendor/sabre/dav/examples/sql/mysql.principals.sql b/sources/vendor/sabre/dav/examples/sql/mysql.principals.sql new file mode 100644 index 00000000..da928281 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/mysql.principals.sql @@ -0,0 +1,22 @@ +CREATE TABLE principals ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + uri VARCHAR(200) NOT NULL, + email VARCHAR(80), + displayname VARCHAR(80), + vcardurl VARCHAR(255), + UNIQUE(uri) +); + +CREATE TABLE groupmembers ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principal_id INTEGER UNSIGNED NOT NULL, + member_id INTEGER UNSIGNED NOT NULL, + UNIQUE(principal_id, member_id) +); + + +INSERT INTO principals (uri,email,displayname) VALUES +('principals/admin', 'admin@example.org','Administrator'), +('principals/admin/calendar-proxy-read', null, null), +('principals/admin/calendar-proxy-write', null, null); + diff --git a/sources/vendor/sabre/dav/examples/sql/mysql.users.sql b/sources/vendor/sabre/dav/examples/sql/mysql.users.sql new file mode 100644 index 00000000..1244f596 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/mysql.users.sql @@ -0,0 +1,9 @@ +CREATE TABLE users ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + username VARCHAR(50), + digesta1 VARCHAR(32), + UNIQUE(username) +); + +INSERT INTO users (username,digesta1) VALUES +('admin', '87fd274b7b6c01e48d7c2f965da8ddf7'); diff --git a/sources/vendor/sabre/dav/examples/sql/pgsql.addressbook.sql b/sources/vendor/sabre/dav/examples/sql/pgsql.addressbook.sql new file mode 100644 index 00000000..c3ca8b29 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/pgsql.addressbook.sql @@ -0,0 +1,33 @@ +CREATE TABLE addressbooks ( + id SERIAL NOT NULL, + principaluri VARCHAR(255), + displayname VARCHAR(255), + uri VARCHAR(200), + description TEXT, + ctag INTEGER NOT NULL DEFAULT 1 +); + +ALTER TABLE ONLY addressbooks + ADD CONSTRAINT addressbooks_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX addressbooks_ukey + ON addressbooks USING btree (principaluri, uri); + +CREATE TABLE cards ( + id SERIAL NOT NULL, + addressbookid INTEGER NOT NULL, + carddata TEXT, + uri VARCHAR(200), + lastmodified INTEGER +); + +ALTER TABLE ONLY cards + ADD CONSTRAINT cards_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX cards_ukey + ON cards USING btree (addressbookid, uri); + +ALTER TABLE ONLY cards + ADD CONSTRAINT cards_addressbookid_fkey FOREIGN KEY (addressbookid) REFERENCES addressbooks(id) + ON DELETE CASCADE; + diff --git a/sources/vendor/sabre/dav/examples/sql/pgsql.calendars.sql b/sources/vendor/sabre/dav/examples/sql/pgsql.calendars.sql new file mode 100644 index 00000000..23465ae9 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/pgsql.calendars.sql @@ -0,0 +1,42 @@ +CREATE TABLE calendars ( + id SERIAL NOT NULL, + principaluri VARCHAR(100), + displayname VARCHAR(100), + uri VARCHAR(200), + ctag INTEGER NOT NULL DEFAULT 0, + description TEXT, + calendarorder INTEGER NOT NULL DEFAULT 0, + calendarcolor VARCHAR(10), + timezone TEXT, + components VARCHAR(20), + transparent SMALLINT NOT NULL DEFAULT '0' +); + +ALTER TABLE ONLY calendars + ADD CONSTRAINT calendars_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX calendars_ukey + ON calendars USING btree (principaluri, uri); + +CREATE TABLE calendarobjects ( + id SERIAL NOT NULL, + calendarid INTEGER NOT NULL, + calendardata TEXT, + uri VARCHAR(200), + etag VARCHAR(32), + size INTEGER NOT NULL, + componenttype VARCHAR(8), + lastmodified INTEGER, + firstoccurence INTEGER, + lastoccurence INTEGER +); + +ALTER TABLE ONLY calendarobjects + ADD CONSTRAINT calendarobjects_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX calendarobjects_ukey + ON calendarobjects USING btree (calendarid, uri); + +ALTER TABLE ONLY calendarobjects + ADD CONSTRAINT calendarobjects_calendarid_fkey FOREIGN KEY (calendarid) REFERENCES calendars(id) + ON DELETE CASCADE; diff --git a/sources/vendor/sabre/dav/examples/sql/pgsql.locks.sql b/sources/vendor/sabre/dav/examples/sql/pgsql.locks.sql new file mode 100644 index 00000000..ca6c82e9 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/pgsql.locks.sql @@ -0,0 +1,13 @@ +CREATE TABLE locks ( + id SERIAL NOT NULL, + owner VARCHAR(100), + timeout INTEGER, + created INTEGER, + token VARCHAR(100), + scope smallint, + depth smallint, + uri text +); + +ALTER TABLE ONLY locks + ADD CONSTRAINT locks_pkey PRIMARY KEY (id); diff --git a/sources/vendor/sabre/dav/examples/sql/pgsql.principals.sql b/sources/vendor/sabre/dav/examples/sql/pgsql.principals.sql new file mode 100644 index 00000000..4afe5106 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/pgsql.principals.sql @@ -0,0 +1,40 @@ +CREATE TABLE principals ( + id SERIAL NOT NULL, + uri VARCHAR(100) NOT NULL, + email VARCHAR(80), + displayname VARCHAR(80), + vcardurl VARCHAR(255) +); + +ALTER TABLE ONLY principals + ADD CONSTRAINT principals_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX principals_ukey + ON principals USING btree (uri); + +CREATE TABLE groupmembers ( + id SERIAL NOT NULL, + principal_id INTEGER NOT NULL, + member_id INTEGER NOT NULL +); + +ALTER TABLE ONLY groupmembers + ADD CONSTRAINT groupmembers_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX groupmembers_ukey + ON groupmembers USING btree (principal_id, member_id); + +ALTER TABLE ONLY groupmembers + ADD CONSTRAINT groupmembers_principal_id_fkey FOREIGN KEY (principal_id) REFERENCES principals(id) + ON DELETE CASCADE; + +-- Is this correct correct link ... or not? +-- ALTER TABLE ONLY groupmembers +-- ADD CONSTRAINT groupmembers_member_id_id_fkey FOREIGN KEY (member_id) REFERENCES users(id) +-- ON DELETE CASCADE; + +INSERT INTO principals (uri,email,displayname) VALUES +('principals/admin', 'admin@example.org','Administrator'), +('principals/admin/calendar-proxy-read', null, null), +('principals/admin/calendar-proxy-write', null, null); + diff --git a/sources/vendor/sabre/dav/examples/sql/pgsql.users.sql b/sources/vendor/sabre/dav/examples/sql/pgsql.users.sql new file mode 100644 index 00000000..939c931d --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/pgsql.users.sql @@ -0,0 +1,15 @@ +CREATE TABLE users ( + id SERIAL NOT NULL, + username VARCHAR(50), + digesta1 VARCHAR(32), + UNIQUE(username) +); + +ALTER TABLE ONLY users + ADD CONSTRAINT users_pkey PRIMARY KEY (id); + +CREATE UNIQUE INDEX users_ukey + ON users USING btree (username); + +INSERT INTO users (username,digesta1) VALUES +('admin', '87fd274b7b6c01e48d7c2f965da8ddf7'); diff --git a/sources/vendor/sabre/dav/examples/sql/sqlite.addressbooks.sql b/sources/vendor/sabre/dav/examples/sql/sqlite.addressbooks.sql new file mode 100644 index 00000000..aa7639c5 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/sqlite.addressbooks.sql @@ -0,0 +1,17 @@ +CREATE TABLE addressbooks ( + id integer primary key asc, + principaluri text, + displayname text, + uri text, + description text, + ctag integer +); + +CREATE TABLE cards ( + id integer primary key asc, + addressbookid integer, + carddata blob, + uri text, + lastmodified integer +); + diff --git a/sources/vendor/sabre/dav/examples/sql/sqlite.calendars.sql b/sources/vendor/sabre/dav/examples/sql/sqlite.calendars.sql new file mode 100644 index 00000000..53778990 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/sqlite.calendars.sql @@ -0,0 +1,26 @@ +CREATE TABLE calendarobjects ( + id integer primary key asc, + calendardata blob, + uri text, + calendarid integer, + lastmodified integer, + etag text, + size integer, + componenttype text, + firstoccurence integer, + lastoccurence integer +); + +CREATE TABLE calendars ( + id integer primary key asc, + principaluri text, + displayname text, + uri text, + ctag integer, + description text, + calendarorder integer, + calendarcolor text, + timezone text, + components text, + transparent bool +); diff --git a/sources/vendor/sabre/dav/examples/sql/sqlite.locks.sql b/sources/vendor/sabre/dav/examples/sql/sqlite.locks.sql new file mode 100644 index 00000000..fd89b41e --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/sqlite.locks.sql @@ -0,0 +1,12 @@ +BEGIN TRANSACTION; +CREATE TABLE locks ( + id integer primary key asc, + owner text, + timeout integer, + created integer, + token text, + scope integer, + depth integer, + uri text +); +COMMIT; diff --git a/sources/vendor/sabre/dav/examples/sql/sqlite.principals.sql b/sources/vendor/sabre/dav/examples/sql/sqlite.principals.sql new file mode 100644 index 00000000..09dbc4d2 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/sqlite.principals.sql @@ -0,0 +1,21 @@ +CREATE TABLE principals ( + id INTEGER PRIMARY KEY ASC, + uri TEXT, + email TEXT, + displayname TEXT, + vcardurl TEXT, + UNIQUE(uri) +); + +CREATE TABLE groupmembers ( + id INTEGER PRIMARY KEY ASC, + principal_id INTEGER, + member_id INTEGER, + UNIQUE(principal_id, member_id) +); + + +INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin', 'admin@example.org','Administrator'); +INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin/calendar-proxy-read', null, null); +INSERT INTO principals (uri,email,displayname) VALUES ('principals/admin/calendar-proxy-write', null, null); + diff --git a/sources/vendor/sabre/dav/examples/sql/sqlite.users.sql b/sources/vendor/sabre/dav/examples/sql/sqlite.users.sql new file mode 100644 index 00000000..f4b2c167 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/sql/sqlite.users.sql @@ -0,0 +1,9 @@ +CREATE TABLE users ( + id integer primary key asc, + username TEXT, + digesta1 TEXT, + UNIQUE(username) +); + +INSERT INTO users (username,digesta1) VALUES +('admin', '87fd274b7b6c01e48d7c2f965da8ddf7'); diff --git a/sources/vendor/sabre/dav/examples/webserver/apache2_htaccess.conf b/sources/vendor/sabre/dav/examples/webserver/apache2_htaccess.conf new file mode 100644 index 00000000..c5f29ba8 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/webserver/apache2_htaccess.conf @@ -0,0 +1,16 @@ +RewriteEngine On +# This makes every request go to server.php +RewriteRule (.*) server.php [L] + +# Output buffering needs to be off, to prevent high memory usage +php_flag output_buffering off + +# This is also to prevent high memory usage +php_flag always_populate_raw_post_data off + +# This is almost a given, but magic quotes is *still* on on some +# linux distributions +php_flag magic_quotes_gpc off + +# SabreDAV is not compatible with mbstring function overloading +php_flag mbstring.func_overload off diff --git a/sources/vendor/sabre/dav/examples/webserver/apache2_vhost.conf b/sources/vendor/sabre/dav/examples/webserver/apache2_vhost.conf new file mode 100644 index 00000000..bb374eb0 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/webserver/apache2_vhost.conf @@ -0,0 +1,33 @@ +# This is a sample configuration to setup a dedicated Apache vhost for WebDAV. +# +# The main thing that should be configured is the servername, and the path to +# your SabreDAV installation (DocumentRoot). +# +# This configuration assumed mod_php5 is used, as it sets a few default php +# settings as well. + + + # Don't forget to change the server name + # ServerName dav.example.org + + # The DocumentRoot is also required + # DocumentRoot /home/sabredav/ + + RewriteEngine On + # This makes every request go to server.php + RewriteRule ^/(.*)$ /server.php [L] + + # Output buffering needs to be off, to prevent high memory usage + php_flag output_buffering off + + # This is also to prevent high memory usage + php_flag always_populate_raw_post_data off + + # This is almost a given, but magic quotes is *still* on on some + # linux distributions + php_flag magic_quotes_gpc off + + # SabreDAV is not compatible with mbstring function overloading + php_flag mbstring.func_overload off + + diff --git a/sources/vendor/sabre/dav/examples/webserver/apache2_vhost_cgi.conf b/sources/vendor/sabre/dav/examples/webserver/apache2_vhost_cgi.conf new file mode 100644 index 00000000..607254c6 --- /dev/null +++ b/sources/vendor/sabre/dav/examples/webserver/apache2_vhost_cgi.conf @@ -0,0 +1,21 @@ +# This is a sample configuration to setup a dedicated Apache vhost for WebDAV. +# +# The main thing that should be configured is the servername, and the path to +# your SabreDAV installation (DocumentRoot). +# +# This configuration assumes CGI or FastCGI is used. + + + # Don't forget to change the server name + # ServerName dav.example.org + + # The DocumentRoot is also required + # DocumentRoot /home/sabredav/ + + # This makes every request go to server.php. This also makes sure + # the Authentication information is available. If your server script is + # not called server.php, be sure to change it. + RewriteEngine On + RewriteRule ^/(.*)$ /server.php [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/AbstractBackend.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/AbstractBackend.php new file mode 100644 index 00000000..c83409ea --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/AbstractBackend.php @@ -0,0 +1,155 @@ + array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param mixed $calendarId + * @param array $mutations + * @return bool|array + */ + public function updateCalendar($calendarId, array $mutations) { + + return false; + + } + + /** + * Performs a calendar-query on the contents of this calendar. + * + * The calendar-query is defined in RFC4791 : CalDAV. Using the + * calendar-query it is possible for a client to request a specific set of + * object, based on contents of iCalendar properties, date-ranges and + * iCalendar component types (VTODO, VEVENT). + * + * This method should just return a list of (relative) urls that match this + * query. + * + * The list of filters are specified as an array. The exact array is + * documented by \Sabre\CalDAV\CalendarQueryParser. + * + * Note that it is extremely likely that getCalendarObject for every path + * returned from this method will be called almost immediately after. You + * may want to anticipate this to speed up these requests. + * + * This method provides a default implementation, which parses *all* the + * iCalendar objects in the specified calendar. + * + * This default may well be good enough for personal use, and calendars + * that aren't very large. But if you anticipate high usage, big calendars + * or high loads, you are strongly adviced to optimize certain paths. + * + * The best way to do so is override this method and to optimize + * specifically for 'common filters'. + * + * Requests that are extremely common are: + * * requests for just VEVENTS + * * requests for just VTODO + * * requests with a time-range-filter on either VEVENT or VTODO. + * + * ..and combinations of these requests. It may not be worth it to try to + * handle every possible situation and just rely on the (relatively + * easy to use) CalendarQueryValidator to handle the rest. + * + * Note that especially time-range-filters may be difficult to parse. A + * time-range filter specified on a VEVENT must for instance also handle + * recurrence rules correctly. + * A good example of how to interprete all these filters can also simply + * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct + * as possible, so it gives you a good idea on what type of stuff you need + * to think of. + * + * @param mixed $calendarId + * @param array $filters + * @return array + */ + public function calendarQuery($calendarId, array $filters) { + + $result = array(); + $objects = $this->getCalendarObjects($calendarId); + + $validator = new \Sabre\CalDAV\CalendarQueryValidator(); + + foreach($objects as $object) { + + if ($this->validateFilterForObject($object, $filters)) { + $result[] = $object['uri']; + } + + } + + return $result; + + } + + /** + * This method validates if a filters (as passed to calendarQuery) matches + * the given object. + * + * @param array $object + * @param array $filters + * @return bool + */ + protected function validateFilterForObject(array $object, array $filters) { + + // Unfortunately, setting the 'calendardata' here is optional. If + // it was excluded, we actually need another call to get this as + // well. + if (!isset($object['calendardata'])) { + $object = $this->getCalendarObject($object['calendarid'], $object['uri']); + } + + $data = is_resource($object['calendardata'])?stream_get_contents($object['calendardata']):$object['calendardata']; + $vObject = VObject\Reader::read($data); + + $validator = new CalDAV\CalendarQueryValidator(); + return $validator->validate($vObject, $filters); + + } + + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/BackendInterface.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/BackendInterface.php new file mode 100644 index 00000000..0dc31e5f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/BackendInterface.php @@ -0,0 +1,233 @@ + array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param mixed $calendarId + * @param array $mutations + * @return bool|array + */ + public function updateCalendar($calendarId, array $mutations); + + /** + * Delete a calendar and all it's objects + * + * @param mixed $calendarId + * @return void + */ + public function deleteCalendar($calendarId); + + /** + * Returns all calendar objects within a calendar. + * + * Every item contains an array with the following keys: + * * id - unique identifier which will be used for subsequent updates + * * calendardata - The iCalendar-compatible calendar data + * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string. + * * lastmodified - a timestamp of the last modification time + * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: + * ' "abcdef"') + * * calendarid - The calendarid as it was passed to this function. + * * size - The size of the calendar objects, in bytes. + * + * Note that the etag is optional, but it's highly encouraged to return for + * speed reasons. + * + * The calendardata is also optional. If it's not returned + * 'getCalendarObject' will be called later, which *is* expected to return + * calendardata. + * + * If neither etag or size are specified, the calendardata will be + * used/fetched to determine these numbers. If both are specified the + * amount of times this is needed is reduced by a great degree. + * + * @param mixed $calendarId + * @return array + */ + public function getCalendarObjects($calendarId); + + /** + * Returns information from a single calendar object, based on it's object + * uri. + * + * The returned array must have the same keys as getCalendarObjects. The + * 'calendardata' object is required here though, while it's not required + * for getCalendarObjects. + * + * This method must return null if the object did not exist. + * + * @param mixed $calendarId + * @param string $objectUri + * @return array|null + */ + public function getCalendarObject($calendarId,$objectUri); + + /** + * Creates a new calendar object. + * + * It is possible return an etag from this function, which will be used in + * the response to this PUT request. Note that the ETag must be surrounded + * by double-quotes. + * + * However, you should only really return this ETag if you don't mangle the + * calendar-data. If the result of a subsequent GET to this object is not + * the exact same as this request body, you should omit the ETag. + * + * @param mixed $calendarId + * @param string $objectUri + * @param string $calendarData + * @return string|null + */ + public function createCalendarObject($calendarId,$objectUri,$calendarData); + + /** + * Updates an existing calendarobject, based on it's uri. + * + * It is possible return an etag from this function, which will be used in + * the response to this PUT request. Note that the ETag must be surrounded + * by double-quotes. + * + * However, you should only really return this ETag if you don't mangle the + * calendar-data. If the result of a subsequent GET to this object is not + * the exact same as this request body, you should omit the ETag. + * + * @param mixed $calendarId + * @param string $objectUri + * @param string $calendarData + * @return string|null + */ + public function updateCalendarObject($calendarId,$objectUri,$calendarData); + + /** + * Deletes an existing calendar object. + * + * @param mixed $calendarId + * @param string $objectUri + * @return void + */ + public function deleteCalendarObject($calendarId,$objectUri); + + /** + * Performs a calendar-query on the contents of this calendar. + * + * The calendar-query is defined in RFC4791 : CalDAV. Using the + * calendar-query it is possible for a client to request a specific set of + * object, based on contents of iCalendar properties, date-ranges and + * iCalendar component types (VTODO, VEVENT). + * + * This method should just return a list of (relative) urls that match this + * query. + * + * The list of filters are specified as an array. The exact array is + * documented by Sabre\CalDAV\CalendarQueryParser. + * + * Note that it is extremely likely that getCalendarObject for every path + * returned from this method will be called almost immediately after. You + * may want to anticipate this to speed up these requests. + * + * This method provides a default implementation, which parses *all* the + * iCalendar objects in the specified calendar. + * + * This default may well be good enough for personal use, and calendars + * that aren't very large. But if you anticipate high usage, big calendars + * or high loads, you are strongly adviced to optimize certain paths. + * + * The best way to do so is override this method and to optimize + * specifically for 'common filters'. + * + * Requests that are extremely common are: + * * requests for just VEVENTS + * * requests for just VTODO + * * requests with a time-range-filter on either VEVENT or VTODO. + * + * ..and combinations of these requests. It may not be worth it to try to + * handle every possible situation and just rely on the (relatively + * easy to use) CalendarQueryValidator to handle the rest. + * + * Note that especially time-range-filters may be difficult to parse. A + * time-range filter specified on a VEVENT must for instance also handle + * recurrence rules correctly. + * A good example of how to interprete all these filters can also simply + * be found in Sabre\CalDAV\CalendarQueryFilter. This class is as correct + * as possible, so it gives you a good idea on what type of stuff you need + * to think of. + * + * @param mixed $calendarId + * @param array $filters + * @return array + */ + public function calendarQuery($calendarId, array $filters); + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/NotificationSupport.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/NotificationSupport.php new file mode 100644 index 00000000..96533ad6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/NotificationSupport.php @@ -0,0 +1,47 @@ + 'displayname', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'description', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => 'timezone', + '{http://apple.com/ns/ical/}calendar-order' => 'calendarorder', + '{http://apple.com/ns/ical/}calendar-color' => 'calendarcolor', + ); + + /** + * Creates the backend + * + * @param \PDO $pdo + * @param string $calendarTableName + * @param string $calendarObjectTableName + */ + public function __construct(\PDO $pdo, $calendarTableName = 'calendars', $calendarObjectTableName = 'calendarobjects') { + + $this->pdo = $pdo; + $this->calendarTableName = $calendarTableName; + $this->calendarObjectTableName = $calendarObjectTableName; + + } + + /** + * Returns a list of calendars for a principal. + * + * Every project is an array with the following keys: + * * id, a unique id that will be used by other functions to modify the + * calendar. This can be the same as the uri or a database key. + * * uri, which the basename of the uri with which the calendar is + * accessed. + * * principaluri. The owner of the calendar. Almost always the same as + * principalUri passed to this method. + * + * Furthermore it can contain webdav properties in clark notation. A very + * common one is '{DAV:}displayname'. + * + * @param string $principalUri + * @return array + */ + public function getCalendarsForUser($principalUri) { + + $fields = array_values($this->propertyMap); + $fields[] = 'id'; + $fields[] = 'uri'; + $fields[] = 'ctag'; + $fields[] = 'components'; + $fields[] = 'principaluri'; + $fields[] = 'transparent'; + + // Making fields a comma-delimited list + $fields = implode(', ', $fields); + $stmt = $this->pdo->prepare("SELECT " . $fields . " FROM ".$this->calendarTableName." WHERE principaluri = ? ORDER BY calendarorder ASC"); + $stmt->execute(array($principalUri)); + + $calendars = array(); + while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + + $components = array(); + if ($row['components']) { + $components = explode(',',$row['components']); + } + + $calendar = array( + 'id' => $row['id'], + 'uri' => $row['uri'], + 'principaluri' => $row['principaluri'], + '{' . CalDAV\Plugin::NS_CALENDARSERVER . '}getctag' => $row['ctag']?$row['ctag']:'0', + '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet($components), + '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp($row['transparent']?'transparent':'opaque'), + ); + + + foreach($this->propertyMap as $xmlName=>$dbName) { + $calendar[$xmlName] = $row[$dbName]; + } + + $calendars[] = $calendar; + + } + + return $calendars; + + } + + /** + * Creates a new calendar for a principal. + * + * If the creation was a success, an id must be returned that can be used to reference + * this calendar in other methods, such as updateCalendar + * + * @param string $principalUri + * @param string $calendarUri + * @param array $properties + * @return string + */ + public function createCalendar($principalUri, $calendarUri, array $properties) { + + $fieldNames = array( + 'principaluri', + 'uri', + 'ctag', + 'transparent', + ); + $values = array( + ':principaluri' => $principalUri, + ':uri' => $calendarUri, + ':ctag' => 1, + ':transparent' => 0, + ); + + // Default value + $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'; + $fieldNames[] = 'components'; + if (!isset($properties[$sccs])) { + $values[':components'] = 'VEVENT,VTODO'; + } else { + if (!($properties[$sccs] instanceof CalDAV\Property\SupportedCalendarComponentSet)) { + throw new DAV\Exception('The ' . $sccs . ' property must be of type: \Sabre\CalDAV\Property\SupportedCalendarComponentSet'); + } + $values[':components'] = implode(',',$properties[$sccs]->getValue()); + } + $transp = '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp'; + if (isset($properties[$transp])) { + $values[':transparent'] = $properties[$transp]->getValue()==='transparent'; + } + + foreach($this->propertyMap as $xmlName=>$dbName) { + if (isset($properties[$xmlName])) { + + $values[':' . $dbName] = $properties[$xmlName]; + $fieldNames[] = $dbName; + } + } + + $stmt = $this->pdo->prepare("INSERT INTO ".$this->calendarTableName." (".implode(', ', $fieldNames).") VALUES (".implode(', ',array_keys($values)).")"); + $stmt->execute($values); + + return $this->pdo->lastInsertId(); + + } + + /** + * Updates properties for a calendar. + * + * The mutations array uses the propertyName in clark-notation as key, + * and the array value for the property value. In the case a property + * should be deleted, the property value will be null. + * + * This method must be atomic. If one property cannot be changed, the + * entire operation must fail. + * + * If the operation was successful, true can be returned. + * If the operation failed, false can be returned. + * + * Deletion of a non-existent property is always successful. + * + * Lastly, it is optional to return detailed information about any + * failures. In this case an array should be returned with the following + * structure: + * + * array( + * 403 => array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param string $calendarId + * @param array $mutations + * @return bool|array + */ + public function updateCalendar($calendarId, array $mutations) { + + $newValues = array(); + $result = array( + 200 => array(), // Ok + 403 => array(), // Forbidden + 424 => array(), // Failed Dependency + ); + + $hasError = false; + + foreach($mutations as $propertyName=>$propertyValue) { + + switch($propertyName) { + case '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-calendar-transp' : + $fieldName = 'transparent'; + $newValues[$fieldName] = $propertyValue->getValue()==='transparent'; + break; + default : + // Checking the property map + if (!isset($this->propertyMap[$propertyName])) { + // We don't know about this property. + $hasError = true; + $result[403][$propertyName] = null; + unset($mutations[$propertyName]); + continue; + } + + $fieldName = $this->propertyMap[$propertyName]; + $newValues[$fieldName] = $propertyValue; + } + + } + + // If there were any errors we need to fail the request + if ($hasError) { + // Properties has the remaining properties + foreach($mutations as $propertyName=>$propertyValue) { + $result[424][$propertyName] = null; + } + + // Removing unused statuscodes for cleanliness + foreach($result as $status=>$properties) { + if (is_array($properties) && count($properties)===0) unset($result[$status]); + } + + return $result; + + } + + // Success + + // Now we're generating the sql query. + $valuesSql = array(); + foreach($newValues as $fieldName=>$value) { + $valuesSql[] = $fieldName . ' = ?'; + } + $valuesSql[] = 'ctag = ctag + 1'; + + $stmt = $this->pdo->prepare("UPDATE " . $this->calendarTableName . " SET " . implode(', ',$valuesSql) . " WHERE id = ?"); + $newValues['id'] = $calendarId; + $stmt->execute(array_values($newValues)); + + return true; + + } + + /** + * Delete a calendar and all it's objects + * + * @param string $calendarId + * @return void + */ + public function deleteCalendar($calendarId) { + + $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?'); + $stmt->execute(array($calendarId)); + + $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarTableName.' WHERE id = ?'); + $stmt->execute(array($calendarId)); + + } + + /** + * Returns all calendar objects within a calendar. + * + * Every item contains an array with the following keys: + * * id - unique identifier which will be used for subsequent updates + * * calendardata - The iCalendar-compatible calendar data + * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string. + * * lastmodified - a timestamp of the last modification time + * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: + * ' "abcdef"') + * * calendarid - The calendarid as it was passed to this function. + * * size - The size of the calendar objects, in bytes. + * + * Note that the etag is optional, but it's highly encouraged to return for + * speed reasons. + * + * The calendardata is also optional. If it's not returned + * 'getCalendarObject' will be called later, which *is* expected to return + * calendardata. + * + * If neither etag or size are specified, the calendardata will be + * used/fetched to determine these numbers. If both are specified the + * amount of times this is needed is reduced by a great degree. + * + * @param string $calendarId + * @return array + */ + public function getCalendarObjects($calendarId) { + + $stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size FROM '.$this->calendarObjectTableName.' WHERE calendarid = ?'); + $stmt->execute(array($calendarId)); + + $result = array(); + foreach($stmt->fetchAll(\PDO::FETCH_ASSOC) as $row) { + $result[] = array( + 'id' => $row['id'], + 'uri' => $row['uri'], + 'lastmodified' => $row['lastmodified'], + 'etag' => '"' . $row['etag'] . '"', + 'calendarid' => $row['calendarid'], + 'size' => (int)$row['size'], + ); + } + + return $result; + + } + + /** + * Returns information from a single calendar object, based on it's object + * uri. + * + * The returned array must have the same keys as getCalendarObjects. The + * 'calendardata' object is required here though, while it's not required + * for getCalendarObjects. + * + * This method must return null if the object did not exist. + * + * @param string $calendarId + * @param string $objectUri + * @return array|null + */ + public function getCalendarObject($calendarId,$objectUri) { + + $stmt = $this->pdo->prepare('SELECT id, uri, lastmodified, etag, calendarid, size, calendardata FROM '.$this->calendarObjectTableName.' WHERE calendarid = ? AND uri = ?'); + $stmt->execute(array($calendarId, $objectUri)); + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + + if(!$row) return null; + + return array( + 'id' => $row['id'], + 'uri' => $row['uri'], + 'lastmodified' => $row['lastmodified'], + 'etag' => '"' . $row['etag'] . '"', + 'calendarid' => $row['calendarid'], + 'size' => (int)$row['size'], + 'calendardata' => $row['calendardata'], + ); + + } + + + /** + * Creates a new calendar object. + * + * It is possible return an etag from this function, which will be used in + * the response to this PUT request. Note that the ETag must be surrounded + * by double-quotes. + * + * However, you should only really return this ETag if you don't mangle the + * calendar-data. If the result of a subsequent GET to this object is not + * the exact same as this request body, you should omit the ETag. + * + * @param mixed $calendarId + * @param string $objectUri + * @param string $calendarData + * @return string|null + */ + public function createCalendarObject($calendarId,$objectUri,$calendarData) { + + $extraData = $this->getDenormalizedData($calendarData); + + $stmt = $this->pdo->prepare('INSERT INTO '.$this->calendarObjectTableName.' (calendarid, uri, calendardata, lastmodified, etag, size, componenttype, firstoccurence, lastoccurence) VALUES (?,?,?,?,?,?,?,?,?)'); + $stmt->execute(array( + $calendarId, + $objectUri, + $calendarData, + time(), + $extraData['etag'], + $extraData['size'], + $extraData['componentType'], + $extraData['firstOccurence'], + $extraData['lastOccurence'], + )); + $stmt = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?'); + $stmt->execute(array($calendarId)); + + return '"' . $extraData['etag'] . '"'; + + } + + /** + * Updates an existing calendarobject, based on it's uri. + * + * It is possible return an etag from this function, which will be used in + * the response to this PUT request. Note that the ETag must be surrounded + * by double-quotes. + * + * However, you should only really return this ETag if you don't mangle the + * calendar-data. If the result of a subsequent GET to this object is not + * the exact same as this request body, you should omit the ETag. + * + * @param mixed $calendarId + * @param string $objectUri + * @param string $calendarData + * @return string|null + */ + public function updateCalendarObject($calendarId,$objectUri,$calendarData) { + + $extraData = $this->getDenormalizedData($calendarData); + + $stmt = $this->pdo->prepare('UPDATE '.$this->calendarObjectTableName.' SET calendardata = ?, lastmodified = ?, etag = ?, size = ?, componenttype = ?, firstoccurence = ?, lastoccurence = ? WHERE calendarid = ? AND uri = ?'); + $stmt->execute(array($calendarData,time(), $extraData['etag'], $extraData['size'], $extraData['componentType'], $extraData['firstOccurence'], $extraData['lastOccurence'] ,$calendarId,$objectUri)); + $stmt = $this->pdo->prepare('UPDATE '.$this->calendarTableName.' SET ctag = ctag + 1 WHERE id = ?'); + $stmt->execute(array($calendarId)); + + return '"' . $extraData['etag'] . '"'; + + } + + /** + * Parses some information from calendar objects, used for optimized + * calendar-queries. + * + * Returns an array with the following keys: + * * etag + * * size + * * componentType + * * firstOccurence + * * lastOccurence + * + * @param string $calendarData + * @return array + */ + protected function getDenormalizedData($calendarData) { + + $vObject = VObject\Reader::read($calendarData); + $componentType = null; + $component = null; + $firstOccurence = null; + $lastOccurence = null; + foreach($vObject->getComponents() as $component) { + if ($component->name!=='VTIMEZONE') { + $componentType = $component->name; + break; + } + } + if (!$componentType) { + throw new \Sabre\DAV\Exception\BadRequest('Calendar objects must have a VJOURNAL, VEVENT or VTODO component'); + } + if ($componentType === 'VEVENT') { + $firstOccurence = $component->DTSTART->getDateTime()->getTimeStamp(); + // Finding the last occurence is a bit harder + if (!isset($component->RRULE)) { + if (isset($component->DTEND)) { + $lastOccurence = $component->DTEND->getDateTime()->getTimeStamp(); + } elseif (isset($component->DURATION)) { + $endDate = clone $component->DTSTART->getDateTime(); + $endDate->add(VObject\DateTimeParser::parse($component->DURATION->getValue())); + $lastOccurence = $endDate->getTimeStamp(); + } elseif (!$component->DTSTART->hasTime()) { + $endDate = clone $component->DTSTART->getDateTime(); + $endDate->modify('+1 day'); + $lastOccurence = $endDate->getTimeStamp(); + } else { + $lastOccurence = $firstOccurence; + } + } else { + $it = new VObject\RecurrenceIterator($vObject, (string)$component->UID); + $maxDate = new \DateTime(self::MAX_DATE); + if ($it->isInfinite()) { + $lastOccurence = $maxDate->getTimeStamp(); + } else { + $end = $it->getDtEnd(); + while($it->valid() && $end < $maxDate) { + $end = $it->getDtEnd(); + $it->next(); + + } + $lastOccurence = $end->getTimeStamp(); + } + + } + } + + return array( + 'etag' => md5($calendarData), + 'size' => strlen($calendarData), + 'componentType' => $componentType, + 'firstOccurence' => $firstOccurence, + 'lastOccurence' => $lastOccurence, + ); + + } + + /** + * Deletes an existing calendar object. + * + * @param string $calendarId + * @param string $objectUri + * @return void + */ + public function deleteCalendarObject($calendarId,$objectUri) { + + $stmt = $this->pdo->prepare('DELETE FROM '.$this->calendarObjectTableName.' WHERE calendarid = ? AND uri = ?'); + $stmt->execute(array($calendarId,$objectUri)); + $stmt = $this->pdo->prepare('UPDATE '. $this->calendarTableName .' SET ctag = ctag + 1 WHERE id = ?'); + $stmt->execute(array($calendarId)); + + } + + /** + * Performs a calendar-query on the contents of this calendar. + * + * The calendar-query is defined in RFC4791 : CalDAV. Using the + * calendar-query it is possible for a client to request a specific set of + * object, based on contents of iCalendar properties, date-ranges and + * iCalendar component types (VTODO, VEVENT). + * + * This method should just return a list of (relative) urls that match this + * query. + * + * The list of filters are specified as an array. The exact array is + * documented by \Sabre\CalDAV\CalendarQueryParser. + * + * Note that it is extremely likely that getCalendarObject for every path + * returned from this method will be called almost immediately after. You + * may want to anticipate this to speed up these requests. + * + * This method provides a default implementation, which parses *all* the + * iCalendar objects in the specified calendar. + * + * This default may well be good enough for personal use, and calendars + * that aren't very large. But if you anticipate high usage, big calendars + * or high loads, you are strongly adviced to optimize certain paths. + * + * The best way to do so is override this method and to optimize + * specifically for 'common filters'. + * + * Requests that are extremely common are: + * * requests for just VEVENTS + * * requests for just VTODO + * * requests with a time-range-filter on a VEVENT. + * + * ..and combinations of these requests. It may not be worth it to try to + * handle every possible situation and just rely on the (relatively + * easy to use) CalendarQueryValidator to handle the rest. + * + * Note that especially time-range-filters may be difficult to parse. A + * time-range filter specified on a VEVENT must for instance also handle + * recurrence rules correctly. + * A good example of how to interprete all these filters can also simply + * be found in \Sabre\CalDAV\CalendarQueryFilter. This class is as correct + * as possible, so it gives you a good idea on what type of stuff you need + * to think of. + * + * This specific implementation (for the PDO) backend optimizes filters on + * specific components, and VEVENT time-ranges. + * + * @param string $calendarId + * @param array $filters + * @return array + */ + public function calendarQuery($calendarId, array $filters) { + + $result = array(); + $validator = new \Sabre\CalDAV\CalendarQueryValidator(); + + $componentType = null; + $requirePostFilter = true; + $timeRange = null; + + // if no filters were specified, we don't need to filter after a query + if (!$filters['prop-filters'] && !$filters['comp-filters']) { + $requirePostFilter = false; + } + + // Figuring out if there's a component filter + if (count($filters['comp-filters']) > 0 && !$filters['comp-filters'][0]['is-not-defined']) { + $componentType = $filters['comp-filters'][0]['name']; + + // Checking if we need post-filters + if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['time-range'] && !$filters['comp-filters'][0]['prop-filters']) { + $requirePostFilter = false; + } + // There was a time-range filter + if ($componentType == 'VEVENT' && isset($filters['comp-filters'][0]['time-range'])) { + $timeRange = $filters['comp-filters'][0]['time-range']; + + // If start time OR the end time is not specified, we can do a + // 100% accurate mysql query. + if (!$filters['prop-filters'] && !$filters['comp-filters'][0]['comp-filters'] && !$filters['comp-filters'][0]['prop-filters'] && (!$timeRange['start'] || !$timeRange['end'])) { + $requirePostFilter = false; + } + } + + } + + if ($requirePostFilter) { + $query = "SELECT uri, calendardata FROM ".$this->calendarObjectTableName." WHERE calendarid = :calendarid"; + } else { + $query = "SELECT uri FROM ".$this->calendarObjectTableName." WHERE calendarid = :calendarid"; + } + + $values = array( + 'calendarid' => $calendarId, + ); + + if ($componentType) { + $query.=" AND componenttype = :componenttype"; + $values['componenttype'] = $componentType; + } + + if ($timeRange && $timeRange['start']) { + $query.=" AND lastoccurence > :startdate"; + $values['startdate'] = $timeRange['start']->getTimeStamp(); + } + if ($timeRange && $timeRange['end']) { + $query.=" AND firstoccurence < :enddate"; + $values['enddate'] = $timeRange['end']->getTimeStamp(); + } + + $stmt = $this->pdo->prepare($query); + $stmt->execute($values); + + $result = array(); + while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + if ($requirePostFilter) { + if (!$this->validateFilterForObject($row, $filters)) { + continue; + } + } + $result[] = $row['uri']; + + } + + return $result; + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/SharingSupport.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/SharingSupport.php new file mode 100644 index 00000000..4538fa5b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Backend/SharingSupport.php @@ -0,0 +1,243 @@ +caldavBackend = $caldavBackend; + $this->calendarInfo = $calendarInfo; + + } + + /** + * Returns the name of the calendar + * + * @return string + */ + public function getName() { + + return $this->calendarInfo['uri']; + + } + + /** + * Updates properties such as the display name and description + * + * @param array $mutations + * @return array + */ + public function updateProperties($mutations) { + + return $this->caldavBackend->updateCalendar($this->calendarInfo['id'],$mutations); + + } + + /** + * Returns the list of properties + * + * @param array $requestedProperties + * @return array + */ + public function getProperties($requestedProperties) { + + $response = array(); + + foreach($requestedProperties as $prop) switch($prop) { + + case '{urn:ietf:params:xml:ns:caldav}supported-calendar-data' : + $response[$prop] = new Property\SupportedCalendarData(); + break; + case '{urn:ietf:params:xml:ns:caldav}supported-collation-set' : + $response[$prop] = new Property\SupportedCollationSet(); + break; + case '{DAV:}owner' : + $response[$prop] = new DAVACL\Property\Principal(DAVACL\Property\Principal::HREF,$this->calendarInfo['principaluri']); + break; + default : + if (isset($this->calendarInfo[$prop])) $response[$prop] = $this->calendarInfo[$prop]; + break; + + } + return $response; + + } + + /** + * Returns a calendar object + * + * The contained calendar objects are for example Events or Todo's. + * + * @param string $name + * @return \Sabre\CalDAV\ICalendarObject + */ + public function getChild($name) { + + $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name); + + if (!$obj) throw new DAV\Exception\NotFound('Calendar object not found'); + + $obj['acl'] = $this->getACL(); + // Removing the irrelivant + foreach($obj['acl'] as $key=>$acl) { + if ($acl['privilege'] === '{' . Plugin::NS_CALDAV . '}read-free-busy') { + unset($obj['acl'][$key]); + } + } + + return new CalendarObject($this->caldavBackend,$this->calendarInfo,$obj); + + } + + /** + * Returns the full list of calendar objects + * + * @return array + */ + public function getChildren() { + + $objs = $this->caldavBackend->getCalendarObjects($this->calendarInfo['id']); + $children = array(); + foreach($objs as $obj) { + $obj['acl'] = $this->getACL(); + // Removing the irrelivant + foreach($obj['acl'] as $key=>$acl) { + if ($acl['privilege'] === '{' . Plugin::NS_CALDAV . '}read-free-busy') { + unset($obj['acl'][$key]); + } + } + $children[] = new CalendarObject($this->caldavBackend,$this->calendarInfo,$obj); + } + return $children; + + } + + /** + * Checks if a child-node exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + $obj = $this->caldavBackend->getCalendarObject($this->calendarInfo['id'],$name); + if (!$obj) + return false; + else + return true; + + } + + /** + * Creates a new directory + * + * We actually block this, as subdirectories are not allowed in calendars. + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + throw new DAV\Exception\MethodNotAllowed('Creating collections in calendar objects is not allowed'); + + } + + /** + * Creates a new file + * + * The contents of the new file must be a valid ICalendar string. + * + * @param string $name + * @param resource $calendarData + * @return string|null + */ + public function createFile($name,$calendarData = null) { + + if (is_resource($calendarData)) { + $calendarData = stream_get_contents($calendarData); + } + return $this->caldavBackend->createCalendarObject($this->calendarInfo['id'],$name,$calendarData); + + } + + /** + * Deletes the calendar. + * + * @return void + */ + public function delete() { + + $this->caldavBackend->deleteCalendar($this->calendarInfo['id']); + + } + + /** + * Renames the calendar. Note that most calendars use the + * {DAV:}displayname to display a name to display a name. + * + * @param string $newName + * @return void + */ + public function setName($newName) { + + throw new DAV\Exception\MethodNotAllowed('Renaming calendars is not yet supported'); + + } + + /** + * Returns the last modification date as a unix timestamp. + * + * @return void + */ + public function getLastModified() { + + return null; + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->calendarInfo['principaluri']; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner(), + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->getOwner(), + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner() . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->getOwner() . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner() . '/calendar-proxy-read', + 'protected' => true, + ), + array( + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ), + + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet(); + + // We need to inject 'read-free-busy' in the tree, aggregated under + // {DAV:}read. + foreach($default['aggregates'] as &$agg) { + + if ($agg['privilege'] !== '{DAV:}read') continue; + + $agg['aggregates'][] = array( + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + ); + + } + return $default; + + } + + /** + * Performs a calendar-query on the contents of this calendar. + * + * The calendar-query is defined in RFC4791 : CalDAV. Using the + * calendar-query it is possible for a client to request a specific set of + * object, based on contents of iCalendar properties, date-ranges and + * iCalendar component types (VTODO, VEVENT). + * + * This method should just return a list of (relative) urls that match this + * query. + * + * The list of filters are specified as an array. The exact array is + * documented by Sabre\CalDAV\CalendarQueryParser. + * + * @param array $filters + * @return array + */ + public function calendarQuery(array $filters) { + + return $this->caldavBackend->calendarQuery($this->calendarInfo['id'], $filters); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarObject.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarObject.php new file mode 100644 index 00000000..2b9d2877 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarObject.php @@ -0,0 +1,279 @@ +caldavBackend = $caldavBackend; + + if (!isset($objectData['calendarid'])) { + throw new \InvalidArgumentException('The objectData argument must contain a \'calendarid\' property'); + } + if (!isset($objectData['uri'])) { + throw new \InvalidArgumentException('The objectData argument must contain an \'uri\' property'); + } + + $this->calendarInfo = $calendarInfo; + $this->objectData = $objectData; + + } + + /** + * Returns the uri for this object + * + * @return string + */ + public function getName() { + + return $this->objectData['uri']; + + } + + /** + * Returns the ICalendar-formatted object + * + * @return string + */ + public function get() { + + // Pre-populating the 'calendardata' is optional, if we don't have it + // already we fetch it from the backend. + if (!isset($this->objectData['calendardata'])) { + $this->objectData = $this->caldavBackend->getCalendarObject($this->objectData['calendarid'], $this->objectData['uri']); + } + return $this->objectData['calendardata']; + + } + + /** + * Updates the ICalendar-formatted object + * + * @param string|resource $calendarData + * @return string + */ + public function put($calendarData) { + + if (is_resource($calendarData)) { + $calendarData = stream_get_contents($calendarData); + } + $etag = $this->caldavBackend->updateCalendarObject($this->calendarInfo['id'],$this->objectData['uri'],$calendarData); + $this->objectData['calendardata'] = $calendarData; + $this->objectData['etag'] = $etag; + + return $etag; + + } + + /** + * Deletes the calendar object + * + * @return void + */ + public function delete() { + + $this->caldavBackend->deleteCalendarObject($this->calendarInfo['id'],$this->objectData['uri']); + + } + + /** + * Returns the mime content-type + * + * @return string + */ + public function getContentType() { + + return 'text/calendar; charset=utf-8'; + + } + + /** + * Returns an ETag for this object. + * + * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. + * + * @return string + */ + public function getETag() { + + if (isset($this->objectData['etag'])) { + return $this->objectData['etag']; + } else { + return '"' . md5($this->get()). '"'; + } + + } + + /** + * Returns the last modification date as a unix timestamp + * + * @return int + */ + public function getLastModified() { + + return $this->objectData['lastmodified']; + + } + + /** + * Returns the size of this object in bytes + * + * @return int + */ + public function getSize() { + + if (array_key_exists('size',$this->objectData)) { + return $this->objectData['size']; + } else { + return strlen($this->get()); + } + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->calendarInfo['principaluri']; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + // An alternative acl may be specified in the object data. + if (isset($this->objectData['acl'])) { + return $this->objectData['acl']; + } + + // The default ACL + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->calendarInfo['principaluri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->calendarInfo['principaluri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->calendarInfo['principaluri'] . '/calendar-proxy-read', + 'protected' => true, + ), + + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new \Sabre\DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See \Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryParser.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryParser.php new file mode 100644 index 00000000..0a347240 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryParser.php @@ -0,0 +1,298 @@ +dom = $dom; + $this->xpath = new \DOMXPath($dom); + $this->xpath->registerNameSpace('cal',Plugin::NS_CALDAV); + $this->xpath->registerNameSpace('dav','urn:DAV'); + + } + + /** + * Parses the request. + * + * @return void + */ + public function parse() { + + $filterNode = null; + + $filter = $this->xpath->query('/cal:calendar-query/cal:filter'); + if ($filter->length !== 1) { + throw new \Sabre\DAV\Exception\BadRequest('Only one filter element is allowed'); + } + + $compFilters = $this->parseCompFilters($filter->item(0)); + if (count($compFilters)!==1) { + throw new \Sabre\DAV\Exception\BadRequest('There must be exactly 1 top-level comp-filter.'); + } + + $this->filters = $compFilters[0]; + $this->requestedProperties = array_keys(\Sabre\DAV\XMLUtil::parseProperties($this->dom->firstChild)); + + $expand = $this->xpath->query('/cal:calendar-query/dav:prop/cal:calendar-data/cal:expand'); + if ($expand->length>0) { + $this->expand = $this->parseExpand($expand->item(0)); + } + + + } + + /** + * Parses all the 'comp-filter' elements from a node + * + * @param \DOMElement $parentNode + * @return array + */ + protected function parseCompFilters(\DOMElement $parentNode) { + + $compFilterNodes = $this->xpath->query('cal:comp-filter', $parentNode); + $result = array(); + + for($ii=0; $ii < $compFilterNodes->length; $ii++) { + + $compFilterNode = $compFilterNodes->item($ii); + + $compFilter = array(); + $compFilter['name'] = $compFilterNode->getAttribute('name'); + $compFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $compFilterNode)->length>0; + $compFilter['comp-filters'] = $this->parseCompFilters($compFilterNode); + $compFilter['prop-filters'] = $this->parsePropFilters($compFilterNode); + $compFilter['time-range'] = $this->parseTimeRange($compFilterNode); + + if ($compFilter['time-range'] && !in_array($compFilter['name'],array( + 'VEVENT', + 'VTODO', + 'VJOURNAL', + 'VFREEBUSY', + 'VALARM', + ))) { + throw new \Sabre\DAV\Exception\BadRequest('The time-range filter is not defined for the ' . $compFilter['name'] . ' component'); + }; + + $result[] = $compFilter; + + } + + return $result; + + } + + /** + * Parses all the prop-filter elements from a node + * + * @param \DOMElement $parentNode + * @return array + */ + protected function parsePropFilters(\DOMElement $parentNode) { + + $propFilterNodes = $this->xpath->query('cal:prop-filter', $parentNode); + $result = array(); + + for ($ii=0; $ii < $propFilterNodes->length; $ii++) { + + $propFilterNode = $propFilterNodes->item($ii); + $propFilter = array(); + $propFilter['name'] = $propFilterNode->getAttribute('name'); + $propFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $propFilterNode)->length>0; + $propFilter['param-filters'] = $this->parseParamFilters($propFilterNode); + $propFilter['text-match'] = $this->parseTextMatch($propFilterNode); + $propFilter['time-range'] = $this->parseTimeRange($propFilterNode); + + $result[] = $propFilter; + + } + + return $result; + + } + + /** + * Parses the param-filter element + * + * @param \DOMElement $parentNode + * @return array + */ + protected function parseParamFilters(\DOMElement $parentNode) { + + $paramFilterNodes = $this->xpath->query('cal:param-filter', $parentNode); + $result = array(); + + for($ii=0;$ii<$paramFilterNodes->length;$ii++) { + + $paramFilterNode = $paramFilterNodes->item($ii); + $paramFilter = array(); + $paramFilter['name'] = $paramFilterNode->getAttribute('name'); + $paramFilter['is-not-defined'] = $this->xpath->query('cal:is-not-defined', $paramFilterNode)->length>0; + $paramFilter['text-match'] = $this->parseTextMatch($paramFilterNode); + + $result[] = $paramFilter; + + } + + return $result; + + } + + /** + * Parses the text-match element + * + * @param \DOMElement $parentNode + * @return array|null + */ + protected function parseTextMatch(\DOMElement $parentNode) { + + $textMatchNodes = $this->xpath->query('cal:text-match', $parentNode); + + if ($textMatchNodes->length === 0) + return null; + + $textMatchNode = $textMatchNodes->item(0); + $negateCondition = $textMatchNode->getAttribute('negate-condition'); + $negateCondition = $negateCondition==='yes'; + $collation = $textMatchNode->getAttribute('collation'); + if (!$collation) $collation = 'i;ascii-casemap'; + + return array( + 'negate-condition' => $negateCondition, + 'collation' => $collation, + 'value' => $textMatchNode->nodeValue + ); + + } + + /** + * Parses the time-range element + * + * @param \DOMElement $parentNode + * @return array|null + */ + protected function parseTimeRange(\DOMElement $parentNode) { + + $timeRangeNodes = $this->xpath->query('cal:time-range', $parentNode); + if ($timeRangeNodes->length === 0) { + return null; + } + + $timeRangeNode = $timeRangeNodes->item(0); + + if ($start = $timeRangeNode->getAttribute('start')) { + $start = VObject\DateTimeParser::parseDateTime($start); + } else { + $start = null; + } + if ($end = $timeRangeNode->getAttribute('end')) { + $end = VObject\DateTimeParser::parseDateTime($end); + } else { + $end = null; + } + + if (!is_null($start) && !is_null($end) && $end <= $start) { + throw new \Sabre\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the time-range filter'); + } + + return array( + 'start' => $start, + 'end' => $end, + ); + + } + + /** + * Parses the CALDAV:expand element + * + * @param \DOMElement $parentNode + * @return void + */ + protected function parseExpand(\DOMElement $parentNode) { + + $start = $parentNode->getAttribute('start'); + if(!$start) { + throw new \Sabre\DAV\Exception\BadRequest('The "start" attribute is required for the CALDAV:expand element'); + } + $start = VObject\DateTimeParser::parseDateTime($start); + + $end = $parentNode->getAttribute('end'); + if(!$end) { + throw new \Sabre\DAV\Exception\BadRequest('The "end" attribute is required for the CALDAV:expand element'); + } + + $end = VObject\DateTimeParser::parseDateTime($end); + + if ($end <= $start) { + throw new \Sabre\DAV\Exception\BadRequest('The end-date must be larger than the start-date in the expand element.'); + } + + return array( + 'start' => $start, + 'end' => $end, + ); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryValidator.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryValidator.php new file mode 100644 index 00000000..494aed1a --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarQueryValidator.php @@ -0,0 +1,392 @@ +name !== $filters['name']) { + return false; + } + + return + $this->validateCompFilters($vObject, $filters['comp-filters']) && + $this->validatePropFilters($vObject, $filters['prop-filters']); + + + } + + /** + * This method checks the validity of comp-filters. + * + * A list of comp-filters needs to be specified. Also the parent of the + * component we're checking should be specified, not the component to check + * itself. + * + * @param VObject\Component $parent + * @param array $filters + * @return bool + */ + protected function validateCompFilters(VObject\Component $parent, array $filters) { + + foreach($filters as $filter) { + + $isDefined = isset($parent->$filter['name']); + + if ($filter['is-not-defined']) { + + if ($isDefined) { + return false; + } else { + continue; + } + + } + if (!$isDefined) { + return false; + } + + if ($filter['time-range']) { + foreach($parent->$filter['name'] as $subComponent) { + if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) { + continue 2; + } + } + return false; + } + + if (!$filter['comp-filters'] && !$filter['prop-filters']) { + continue; + } + + // If there are sub-filters, we need to find at least one component + // for which the subfilters hold true. + foreach($parent->$filter['name'] as $subComponent) { + + if ( + $this->validateCompFilters($subComponent, $filter['comp-filters']) && + $this->validatePropFilters($subComponent, $filter['prop-filters'])) { + // We had a match, so this comp-filter succeeds + continue 2; + } + + } + + // If we got here it means there were sub-comp-filters or + // sub-prop-filters and there was no match. This means this filter + // needs to return false. + return false; + + } + + // If we got here it means we got through all comp-filters alive so the + // filters were all true. + return true; + + } + + /** + * This method checks the validity of prop-filters. + * + * A list of prop-filters needs to be specified. Also the parent of the + * property we're checking should be specified, not the property to check + * itself. + * + * @param VObject\Component $parent + * @param array $filters + * @return bool + */ + protected function validatePropFilters(VObject\Component $parent, array $filters) { + + foreach($filters as $filter) { + + $isDefined = isset($parent->$filter['name']); + + if ($filter['is-not-defined']) { + + if ($isDefined) { + return false; + } else { + continue; + } + + } + if (!$isDefined) { + return false; + } + + if ($filter['time-range']) { + foreach($parent->$filter['name'] as $subComponent) { + if ($this->validateTimeRange($subComponent, $filter['time-range']['start'], $filter['time-range']['end'])) { + continue 2; + } + } + return false; + } + + if (!$filter['param-filters'] && !$filter['text-match']) { + continue; + } + + // If there are sub-filters, we need to find at least one property + // for which the subfilters hold true. + foreach($parent->$filter['name'] as $subComponent) { + + if( + $this->validateParamFilters($subComponent, $filter['param-filters']) && + (!$filter['text-match'] || $this->validateTextMatch($subComponent, $filter['text-match'])) + ) { + // We had a match, so this prop-filter succeeds + continue 2; + } + + } + + // If we got here it means there were sub-param-filters or + // text-match filters and there was no match. This means the + // filter needs to return false. + return false; + + } + + // If we got here it means we got through all prop-filters alive so the + // filters were all true. + return true; + + } + + /** + * This method checks the validity of param-filters. + * + * A list of param-filters needs to be specified. Also the parent of the + * parameter we're checking should be specified, not the parameter to check + * itself. + * + * @param VObject\Property $parent + * @param array $filters + * @return bool + */ + protected function validateParamFilters(VObject\Property $parent, array $filters) { + + foreach($filters as $filter) { + + $isDefined = isset($parent[$filter['name']]); + + if ($filter['is-not-defined']) { + + if ($isDefined) { + return false; + } else { + continue; + } + + } + if (!$isDefined) { + return false; + } + + if (!$filter['text-match']) { + continue; + } + + if (version_compare(VObject\Version::VERSION, '3.0.0beta1', '>=')) { + + // If there are sub-filters, we need to find at least one parameter + // for which the subfilters hold true. + foreach($parent[$filter['name']]->getParts() as $subParam) { + + if($this->validateTextMatch($subParam,$filter['text-match'])) { + // We had a match, so this param-filter succeeds + continue 2; + } + + } + + } else { + + // If there are sub-filters, we need to find at least one parameter + // for which the subfilters hold true. + foreach($parent[$filter['name']] as $subParam) { + + if($this->validateTextMatch($subParam,$filter['text-match'])) { + // We had a match, so this param-filter succeeds + continue 2; + } + + } + + } + + // If we got here it means there was a text-match filter and there + // were no matches. This means the filter needs to return false. + return false; + + } + + // If we got here it means we got through all param-filters alive so the + // filters were all true. + return true; + + } + + /** + * This method checks the validity of a text-match. + * + * A single text-match should be specified as well as the specific property + * or parameter we need to validate. + * + * @param VObject\Node|string $check Value to check against. + * @param array $textMatch + * @return bool + */ + protected function validateTextMatch($check, array $textMatch) { + + if ($check instanceof VObject\Node) { + $check = (string)$check; + } + + $isMatching = \Sabre\DAV\StringUtil::textMatch($check, $textMatch['value'], $textMatch['collation']); + + return ($textMatch['negate-condition'] xor $isMatching); + + } + + /** + * Validates if a component matches the given time range. + * + * This is all based on the rules specified in rfc4791, which are quite + * complex. + * + * @param VObject\Node $component + * @param DateTime $start + * @param DateTime $end + * @return bool + */ + protected function validateTimeRange(VObject\Node $component, $start, $end) { + + if (is_null($start)) { + $start = new DateTime('1900-01-01'); + } + if (is_null($end)) { + $end = new DateTime('3000-01-01'); + } + + switch($component->name) { + + case 'VEVENT' : + case 'VTODO' : + case 'VJOURNAL' : + + return $component->isInTimeRange($start, $end); + + case 'VALARM' : + + // If the valarm is wrapped in a recurring event, we need to + // expand the recursions, and validate each. + // + // Our datamodel doesn't easily allow us to do this straight + // in the VALARM component code, so this is a hack, and an + // expensive one too. + if ($component->parent->name === 'VEVENT' && $component->parent->RRULE) { + + // Fire up the iterator! + $it = new VObject\RecurrenceIterator($component->parent->parent, (string)$component->parent->UID); + while($it->valid()) { + $expandedEvent = $it->getEventObject(); + + // We need to check from these expanded alarms, which + // one is the first to trigger. Based on this, we can + // determine if we can 'give up' expanding events. + $firstAlarm = null; + if ($expandedEvent->VALARM !== null) { + foreach($expandedEvent->VALARM as $expandedAlarm) { + + $effectiveTrigger = $expandedAlarm->getEffectiveTriggerTime(); + if ($expandedAlarm->isInTimeRange($start, $end)) { + return true; + } + + if ((string)$expandedAlarm->TRIGGER['VALUE'] === 'DATE-TIME') { + // This is an alarm with a non-relative trigger + // time, likely created by a buggy client. The + // implication is that every alarm in this + // recurring event trigger at the exact same + // time. It doesn't make sense to traverse + // further. + } else { + // We store the first alarm as a means to + // figure out when we can stop traversing. + if (!$firstAlarm || $effectiveTrigger < $firstAlarm) { + $firstAlarm = $effectiveTrigger; + } + } + } + } + if (is_null($firstAlarm)) { + // No alarm was found. + // + // Or technically: No alarm that will change for + // every instance of the recurrence was found, + // which means we can assume there was no match. + return false; + } + if ($firstAlarm > $end) { + return false; + } + $it->next(); + } + return false; + } else { + return $component->isInTimeRange($start, $end); + } + + case 'VFREEBUSY' : + throw new \Sabre\DAV\Exception\NotImplemented('time-range filters are currently not supported on ' . $component->name . ' components'); + + case 'COMPLETED' : + case 'CREATED' : + case 'DTEND' : + case 'DTSTAMP' : + case 'DTSTART' : + case 'DUE' : + case 'LAST-MODIFIED' : + return ($start <= $component->getDateTime() && $end >= $component->getDateTime()); + + + + default : + throw new \Sabre\DAV\Exception\BadRequest('You cannot create a time-range filter on a ' . $component->name . ' component'); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarRootNode.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarRootNode.php new file mode 100644 index 00000000..4f72ad44 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/CalendarRootNode.php @@ -0,0 +1,77 @@ +caldavBackend = $caldavBackend; + + } + + /** + * Returns the nodename + * + * We're overriding this, because the default will be the 'principalPrefix', + * and we want it to be Sabre\CalDAV\Plugin::CALENDAR_ROOT + * + * @return string + */ + public function getName() { + + return Plugin::CALENDAR_ROOT; + + } + + /** + * This method returns a node for a principal. + * + * The passed array contains principal information, and is guaranteed to + * at least contain a uri item. Other properties may or may not be + * supplied by the authentication backend. + * + * @param array $principal + * @return \Sabre\DAV\INode + */ + public function getChildForPrincipal(array $principal) { + + return new UserCalendars($this->caldavBackend, $principal); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Exception/InvalidComponentType.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Exception/InvalidComponentType.php new file mode 100644 index 00000000..f2a64e33 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Exception/InvalidComponentType.php @@ -0,0 +1,35 @@ +ownerDocument; + + $np = $doc->createElementNS(CalDAV\Plugin::NS_CALDAV,'cal:supported-calendar-component'); + $errorNode->appendChild($np); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICSExportPlugin.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICSExportPlugin.php new file mode 100644 index 00000000..bba7fbd5 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICSExportPlugin.php @@ -0,0 +1,142 @@ +server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90); + + } + + /** + * 'beforeMethod' event handles. This event handles intercepts GET requests ending + * with ?export + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + if ($method!='GET') return; + if ($this->server->httpRequest->getQueryString()!='export') return; + + // splitting uri + list($uri) = explode('?',$uri,2); + + $node = $this->server->tree->getNodeForPath($uri); + + if (!($node instanceof Calendar)) return; + + // Checking ACL, if available. + if ($aclPlugin = $this->server->getPlugin('acl')) { + $aclPlugin->checkPrivileges($uri, '{DAV:}read'); + } + + $this->server->httpResponse->setHeader('Content-Type','text/calendar'); + $this->server->httpResponse->sendStatus(200); + + $nodes = $this->server->getPropertiesForPath($uri, array( + '{' . Plugin::NS_CALDAV . '}calendar-data', + ),1); + + $this->server->httpResponse->sendBody($this->generateICS($nodes)); + + // Returning false to break the event chain + return false; + + } + + /** + * Merges all calendar objects, and builds one big ics export + * + * @param array $nodes + * @return string + */ + public function generateICS(array $nodes) { + + $calendar = new VObject\Component\VCalendar(); + $calendar->version = '2.0'; + if (DAV\Server::$exposeVersion) { + $calendar->prodid = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN'; + } else { + $calendar->prodid = '-//SabreDAV//SabreDAV//EN'; + } + $calendar->calscale = 'GREGORIAN'; + + $collectedTimezones = array(); + + $timezones = array(); + $objects = array(); + + foreach($nodes as $node) { + + if (!isset($node[200]['{' . Plugin::NS_CALDAV . '}calendar-data'])) { + continue; + } + $nodeData = $node[200]['{' . Plugin::NS_CALDAV . '}calendar-data']; + + $nodeComp = VObject\Reader::read($nodeData); + + foreach($nodeComp->children() as $child) { + + switch($child->name) { + case 'VEVENT' : + case 'VTODO' : + case 'VJOURNAL' : + $objects[] = $child; + break; + + // VTIMEZONE is special, because we need to filter out the duplicates + case 'VTIMEZONE' : + // Naively just checking tzid. + if (in_array((string)$child->TZID, $collectedTimezones)) continue; + + $timezones[] = $child; + $collectedTimezones[] = $child->TZID; + break; + + } + + } + + } + + foreach($timezones as $tz) $calendar->add($tz); + foreach($objects as $obj) $calendar->add($obj); + + return $calendar->serialize(); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICalendar.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICalendar.php new file mode 100644 index 00000000..0f054704 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ICalendar.php @@ -0,0 +1,36 @@ +caldavBackend = $caldavBackend; + $this->principalUri = $principalUri; + + } + + /** + * Returns all notifications for a principal + * + * @return array + */ + public function getChildren() { + + $children = array(); + $notifications = $this->caldavBackend->getNotificationsForPrincipal($this->principalUri); + + foreach($notifications as $notification) { + + $children[] = new Node( + $this->caldavBackend, + $this->principalUri, + $notification + ); + } + + return $children; + + } + + /** + * Returns the name of this object + * + * @return string + */ + public function getName() { + + return 'notifications'; + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalUri; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'principal' => $this->getOwner(), + 'privilege' => '{DAV:}read', + 'protected' => true, + ), + array( + 'principal' => $this->getOwner(), + 'privilege' => '{DAV:}write', + 'protected' => true, + ) + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's as an array argument. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/ICollection.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/ICollection.php new file mode 100644 index 00000000..26e13b21 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/ICollection.php @@ -0,0 +1,24 @@ +caldavBackend = $caldavBackend; + $this->principalUri = $principalUri; + $this->notification = $notification; + + } + + /** + * Returns the path name for this notification + * + * @return id + */ + public function getName() { + + return $this->notification->getId() . '.xml'; + + } + + /** + * Returns the etag for the notification. + * + * The etag must be surrounded by litteral double-quotes. + * + * @return string + */ + public function getETag() { + + return $this->notification->getETag(); + + } + + /** + * This method must return an xml element, using the + * Sabre\CalDAV\Notifications\INotificationType classes. + * + * @return INotificationType + */ + public function getNotificationType() { + + return $this->notification; + + } + + /** + * Deletes this notification + * + * @return void + */ + public function delete() { + + $this->caldavBackend->deleteNotification($this->getOwner(), $this->notification); + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalUri; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'principal' => $this->getOwner(), + 'privilege' => '{DAV:}read', + 'protected' => true, + ), + array( + 'principal' => $this->getOwner(), + 'privilege' => '{DAV:}write', + 'protected' => true, + ) + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's as an array argument. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\NotImplemented('Updating ACLs is not implemented here'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/Invite.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/Invite.php new file mode 100644 index 00000000..8d6974d4 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/Invite.php @@ -0,0 +1,324 @@ +$value) { + if (!property_exists($this, $key)) { + throw new \InvalidArgumentException('Unknown option: ' . $key); + } + $this->$key = $value; + } + + } + + /** + * Serializes the notification as a single property. + * + * You should usually just encode the single top-level element of the + * notification. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $node) { + + $prop = $node->ownerDocument->createElement('cs:invite-notification'); + $node->appendChild($prop); + + } + + /** + * This method serializes the entire notification, as it is used in the + * response body. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serializeBody(DAV\Server $server, \DOMElement $node) { + + $doc = $node->ownerDocument; + + $dt = $doc->createElement('cs:dtstamp'); + $this->dtStamp->setTimezone(new \DateTimezone('GMT')); + $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z'))); + $node->appendChild($dt); + + $prop = $doc->createElement('cs:invite-notification'); + $node->appendChild($prop); + + $uid = $doc->createElement('cs:uid'); + $uid->appendChild( $doc->createTextNode($this->id) ); + $prop->appendChild($uid); + + $href = $doc->createElement('d:href'); + $href->appendChild( $doc->createTextNode( $this->href ) ); + $prop->appendChild($href); + + $nodeName = null; + switch($this->type) { + + case SharingPlugin::STATUS_ACCEPTED : + $nodeName = 'cs:invite-accepted'; + break; + case SharingPlugin::STATUS_DECLINED : + $nodeName = 'cs:invite-declined'; + break; + case SharingPlugin::STATUS_DELETED : + $nodeName = 'cs:invite-deleted'; + break; + case SharingPlugin::STATUS_NORESPONSE : + $nodeName = 'cs:invite-noresponse'; + break; + + } + $prop->appendChild( + $doc->createElement($nodeName) + ); + $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl); + $hostUrl = $doc->createElement('cs:hosturl'); + $hostUrl->appendChild($hostHref); + $prop->appendChild($hostUrl); + + $access = $doc->createElement('cs:access'); + if ($this->readOnly) { + $access->appendChild($doc->createElement('cs:read')); + } else { + $access->appendChild($doc->createElement('cs:read-write')); + } + $prop->appendChild($access); + + $organizerUrl = $doc->createElement('cs:organizer'); + // If the organizer contains a 'mailto:' part, it means it should be + // treated as absolute. + if (strtolower(substr($this->organizer,0,7))==='mailto:') { + $organizerHref = new DAV\Property\Href($this->organizer, false); + } else { + $organizerHref = new DAV\Property\Href($this->organizer, true); + } + $organizerHref->serialize($server, $organizerUrl); + + if ($this->commonName) { + $commonName = $doc->createElement('cs:common-name'); + $commonName->appendChild($doc->createTextNode($this->commonName)); + $organizerUrl->appendChild($commonName); + + $commonNameOld = $doc->createElement('cs:organizer-cn'); + $commonNameOld->appendChild($doc->createTextNode($this->commonName)); + $prop->appendChild($commonNameOld); + + } + if ($this->firstName) { + $firstName = $doc->createElement('cs:first-name'); + $firstName->appendChild($doc->createTextNode($this->firstName)); + $organizerUrl->appendChild($firstName); + + $firstNameOld = $doc->createElement('cs:organizer-first'); + $firstNameOld->appendChild($doc->createTextNode($this->firstName)); + $prop->appendChild($firstNameOld); + } + if ($this->lastName) { + $lastName = $doc->createElement('cs:last-name'); + $lastName->appendChild($doc->createTextNode($this->lastName)); + $organizerUrl->appendChild($lastName); + + $lastNameOld = $doc->createElement('cs:organizer-last'); + $lastNameOld->appendChild($doc->createTextNode($this->lastName)); + $prop->appendChild($lastNameOld); + } + $prop->appendChild($organizerUrl); + + if ($this->summary) { + $summary = $doc->createElement('cs:summary'); + $summary->appendChild($doc->createTextNode($this->summary)); + $prop->appendChild($summary); + } + if ($this->supportedComponents) { + + $xcomp = $doc->createElement('cal:supported-calendar-component-set'); + $this->supportedComponents->serialize($server, $xcomp); + $prop->appendChild($xcomp); + + } + + } + + /** + * Returns a unique id for this notification + * + * This is just the base url. This should generally be some kind of unique + * id. + * + * @return string + */ + public function getId() { + + return $this->id; + + } + + /** + * Returns the ETag for this notification. + * + * The ETag must be surrounded by literal double-quotes. + * + * @return string + */ + public function getETag() { + + return $this->etag; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/InviteReply.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/InviteReply.php new file mode 100644 index 00000000..e4075134 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/InviteReply.php @@ -0,0 +1,218 @@ +$value) { + if (!property_exists($this, $key)) { + throw new \InvalidArgumentException('Unknown option: ' . $key); + } + $this->$key = $value; + } + + } + + /** + * Serializes the notification as a single property. + * + * You should usually just encode the single top-level element of the + * notification. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $node) { + + $prop = $node->ownerDocument->createElement('cs:invite-reply'); + $node->appendChild($prop); + + } + + /** + * This method serializes the entire notification, as it is used in the + * response body. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serializeBody(DAV\Server $server, \DOMElement $node) { + + $doc = $node->ownerDocument; + + $dt = $doc->createElement('cs:dtstamp'); + $this->dtStamp->setTimezone(new \DateTimezone('GMT')); + $dt->appendChild($doc->createTextNode($this->dtStamp->format('Ymd\\THis\\Z'))); + $node->appendChild($dt); + + $prop = $doc->createElement('cs:invite-reply'); + $node->appendChild($prop); + + $uid = $doc->createElement('cs:uid'); + $uid->appendChild($doc->createTextNode($this->id)); + $prop->appendChild($uid); + + $inReplyTo = $doc->createElement('cs:in-reply-to'); + $inReplyTo->appendChild( $doc->createTextNode($this->inReplyTo) ); + $prop->appendChild($inReplyTo); + + $href = $doc->createElement('d:href'); + $href->appendChild( $doc->createTextNode($this->href) ); + $prop->appendChild($href); + + $nodeName = null; + switch($this->type) { + + case SharingPlugin::STATUS_ACCEPTED : + $nodeName = 'cs:invite-accepted'; + break; + case SharingPlugin::STATUS_DECLINED : + $nodeName = 'cs:invite-declined'; + break; + + } + $prop->appendChild( + $doc->createElement($nodeName) + ); + $hostHref = $doc->createElement('d:href', $server->getBaseUri() . $this->hostUrl); + $hostUrl = $doc->createElement('cs:hosturl'); + $hostUrl->appendChild($hostHref); + $prop->appendChild($hostUrl); + + if ($this->summary) { + $summary = $doc->createElement('cs:summary'); + $summary->appendChild($doc->createTextNode($this->summary)); + $prop->appendChild($summary); + } + + } + + /** + * Returns a unique id for this notification + * + * This is just the base url. This should generally be some kind of unique + * id. + * + * @return string + */ + public function getId() { + + return $this->id; + + } + + /** + * Returns the ETag for this notification. + * + * The ETag must be surrounded by literal double-quotes. + * + * @return string + */ + public function getETag() { + + return $this->etag; + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/SystemStatus.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/SystemStatus.php new file mode 100644 index 00000000..608892da --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Notifications/Notification/SystemStatus.php @@ -0,0 +1,182 @@ +id = $id; + $this->type = $type; + $this->description = $description; + $this->href = $href; + $this->etag = $etag; + + } + + /** + * Serializes the notification as a single property. + * + * You should usually just encode the single top-level element of the + * notification. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $node) { + + switch($this->type) { + case self::TYPE_LOW : + $type = 'low'; + break; + case self::TYPE_MEDIUM : + $type = 'medium'; + break; + default : + case self::TYPE_HIGH : + $type = 'high'; + break; + } + + $prop = $node->ownerDocument->createElement('cs:systemstatus'); + $prop->setAttribute('type', $type); + + $node->appendChild($prop); + + } + + /** + * This method serializes the entire notification, as it is used in the + * response body. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serializeBody(DAV\Server $server, \DOMElement $node) { + + switch($this->type) { + case self::TYPE_LOW : + $type = 'low'; + break; + case self::TYPE_MEDIUM : + $type = 'medium'; + break; + default : + case self::TYPE_HIGH : + $type = 'high'; + break; + } + + $prop = $node->ownerDocument->createElement('cs:systemstatus'); + $prop->setAttribute('type', $type); + + if ($this->description) { + $text = $node->ownerDocument->createTextNode($this->description); + $desc = $node->ownerDocument->createElement('cs:description'); + $desc->appendChild($text); + $prop->appendChild($desc); + } + if ($this->href) { + $text = $node->ownerDocument->createTextNode($this->href); + $href = $node->ownerDocument->createElement('d:href'); + $href->appendChild($text); + $prop->appendChild($href); + } + + $node->appendChild($prop); + + } + + /** + * Returns a unique id for this notification + * + * This is just the base url. This should generally be some kind of unique + * id. + * + * @return string + */ + public function getId() { + + return $this->id; + + } + + /* + * Returns the ETag for this notification. + * + * The ETag must be surrounded by literal double-quotes. + * + * @return string + */ + public function getETag() { + + return $this->etag; + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Plugin.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Plugin.php new file mode 100644 index 00000000..61092938 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Plugin.php @@ -0,0 +1,1338 @@ +imipHandler = $imipHandler; + + } + + /** + * Use this method to tell the server this plugin defines additional + * HTTP methods. + * + * This method is passed a uri. It should only return HTTP methods that are + * available for the specified uri. + * + * @param string $uri + * @return array + */ + public function getHTTPMethods($uri) { + + // The MKCALENDAR is only available on unmapped uri's, whose + // parents extend IExtendedCollection + list($parent, $name) = DAV\URLUtil::splitPath($uri); + + $node = $this->server->tree->getNodeForPath($parent); + + if ($node instanceof DAV\IExtendedCollection) { + try { + $node->getChild($name); + } catch (DAV\Exception\NotFound $e) { + return array('MKCALENDAR'); + } + } + return array(); + + } + + /** + * Returns a list of features for the DAV: HTTP header. + * + * @return array + */ + public function getFeatures() { + + return array('calendar-access', 'calendar-proxy'); + + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using DAV\Server::getPlugin + * + * @return string + */ + public function getPluginName() { + + return 'caldav'; + + } + + /** + * Returns a list of reports this plugin supports. + * + * This will be used in the {DAV:}supported-report-set property. + * Note that you still need to subscribe to the 'report' event to actually + * implement them + * + * @param string $uri + * @return array + */ + public function getSupportedReportSet($uri) { + + $node = $this->server->tree->getNodeForPath($uri); + + $reports = array(); + if ($node instanceof ICalendar || $node instanceof ICalendarObject) { + $reports[] = '{' . self::NS_CALDAV . '}calendar-multiget'; + $reports[] = '{' . self::NS_CALDAV . '}calendar-query'; + } + if ($node instanceof ICalendar) { + $reports[] = '{' . self::NS_CALDAV . '}free-busy-query'; + } + return $reports; + + } + + /** + * Initializes the plugin + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + + $server->subscribeEvent('unknownMethod',array($this,'unknownMethod')); + //$server->subscribeEvent('unknownMethod',array($this,'unknownMethod2'),1000); + $server->subscribeEvent('report',array($this,'report')); + $server->subscribeEvent('beforeGetProperties',array($this,'beforeGetProperties')); + $server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel')); + $server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction')); + $server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent')); + $server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile')); + $server->subscribeEvent('beforeMethod', array($this,'beforeMethod')); + + $server->xmlNamespaces[self::NS_CALDAV] = 'cal'; + $server->xmlNamespaces[self::NS_CALENDARSERVER] = 'cs'; + + $server->propertyMap['{' . self::NS_CALDAV . '}supported-calendar-component-set'] = 'Sabre\\CalDAV\\Property\\SupportedCalendarComponentSet'; + $server->propertyMap['{' . self::NS_CALDAV . '}schedule-calendar-transp'] = 'Sabre\\CalDAV\\Property\\ScheduleCalendarTransp'; + + $server->resourceTypeMapping['\\Sabre\\CalDAV\\ICalendar'] = '{urn:ietf:params:xml:ns:caldav}calendar'; + $server->resourceTypeMapping['\\Sabre\\CalDAV\\Schedule\\IOutbox'] = '{urn:ietf:params:xml:ns:caldav}schedule-outbox'; + $server->resourceTypeMapping['\\Sabre\\CalDAV\\Principal\\IProxyRead'] = '{http://calendarserver.org/ns/}calendar-proxy-read'; + $server->resourceTypeMapping['\\Sabre\\CalDAV\\Principal\\IProxyWrite'] = '{http://calendarserver.org/ns/}calendar-proxy-write'; + $server->resourceTypeMapping['\\Sabre\\CalDAV\\Notifications\\ICollection'] = '{' . self::NS_CALENDARSERVER . '}notification'; + + array_push($server->protectedProperties, + + '{' . self::NS_CALDAV . '}supported-calendar-component-set', + '{' . self::NS_CALDAV . '}supported-calendar-data', + '{' . self::NS_CALDAV . '}max-resource-size', + '{' . self::NS_CALDAV . '}min-date-time', + '{' . self::NS_CALDAV . '}max-date-time', + '{' . self::NS_CALDAV . '}max-instances', + '{' . self::NS_CALDAV . '}max-attendees-per-instance', + '{' . self::NS_CALDAV . '}calendar-home-set', + '{' . self::NS_CALDAV . '}supported-collation-set', + '{' . self::NS_CALDAV . '}calendar-data', + + // scheduling extension + '{' . self::NS_CALDAV . '}schedule-inbox-URL', + '{' . self::NS_CALDAV . '}schedule-outbox-URL', + '{' . self::NS_CALDAV . '}calendar-user-address-set', + '{' . self::NS_CALDAV . '}calendar-user-type', + + // CalendarServer extensions + '{' . self::NS_CALENDARSERVER . '}getctag', + '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for', + '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for', + '{' . self::NS_CALENDARSERVER . '}notification-URL', + '{' . self::NS_CALENDARSERVER . '}notificationtype' + + ); + } + + /** + * This function handles support for the MKCALENDAR method + * + * @param string $method + * @param string $uri + * @return bool + */ + public function unknownMethod($method, $uri) { + + switch ($method) { + case 'MKCALENDAR' : + $this->httpMkCalendar($uri); + // false is returned to stop the propagation of the + // unknownMethod event. + return false; + case 'POST' : + + // Checking if this is a text/calendar content type + $contentType = $this->server->httpRequest->getHeader('Content-Type'); + if (strpos($contentType, 'text/calendar')!==0) { + return; + } + + // Checking if we're talking to an outbox + try { + $node = $this->server->tree->getNodeForPath($uri); + } catch (DAV\Exception\NotFound $e) { + return; + } + if (!$node instanceof Schedule\IOutbox) + return; + + $this->outboxRequest($node, $uri); + return false; + + } + + } + + /** + * This functions handles REPORT requests specific to CalDAV + * + * @param string $reportName + * @param \DOMNode $dom + * @return bool + */ + public function report($reportName,$dom) { + + switch($reportName) { + case '{'.self::NS_CALDAV.'}calendar-multiget' : + $this->calendarMultiGetReport($dom); + return false; + case '{'.self::NS_CALDAV.'}calendar-query' : + $this->calendarQueryReport($dom); + return false; + case '{'.self::NS_CALDAV.'}free-busy-query' : + $this->freeBusyQueryReport($dom); + return false; + + } + + + } + + /** + * This function handles the MKCALENDAR HTTP method, which creates + * a new calendar. + * + * @param string $uri + * @return void + */ + public function httpMkCalendar($uri) { + + // Due to unforgivable bugs in iCal, we're completely disabling MKCALENDAR support + // for clients matching iCal in the user agent + //$ua = $this->server->httpRequest->getHeader('User-Agent'); + //if (strpos($ua,'iCal/')!==false) { + // throw new \Sabre\DAV\Exception\Forbidden('iCal has major bugs in it\'s RFC3744 support. Therefore we are left with no other choice but disabling this feature.'); + //} + + $body = $this->server->httpRequest->getBody(true); + $properties = array(); + + if ($body) { + + $dom = DAV\XMLUtil::loadDOMDocument($body); + + foreach($dom->firstChild->childNodes as $child) { + + if (DAV\XMLUtil::toClarkNotation($child)!=='{DAV:}set') continue; + foreach(DAV\XMLUtil::parseProperties($child,$this->server->propertyMap) as $k=>$prop) { + $properties[$k] = $prop; + } + + } + } + + $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar'); + + $this->server->createCollection($uri,$resourceType,$properties); + + $this->server->httpResponse->sendStatus(201); + $this->server->httpResponse->setHeader('Content-Length',0); + } + + /** + * beforeGetProperties + * + * This method handler is invoked before any after properties for a + * resource are fetched. This allows us to add in any CalDAV specific + * properties. + * + * @param string $path + * @param DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @return void + */ + public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties) { + + if ($node instanceof DAVACL\IPrincipal) { + + // calendar-home-set property + $calHome = '{' . self::NS_CALDAV . '}calendar-home-set'; + if (in_array($calHome,$requestedProperties)) { + $principalId = $node->getName(); + $calendarHomePath = self::CALENDAR_ROOT . '/' . $principalId . '/'; + + unset($requestedProperties[array_search($calHome, $requestedProperties)]); + $returnedProperties[200][$calHome] = new DAV\Property\Href($calendarHomePath); + + } + + // schedule-outbox-URL property + $scheduleProp = '{' . self::NS_CALDAV . '}schedule-outbox-URL'; + if (in_array($scheduleProp,$requestedProperties)) { + $principalId = $node->getName(); + $outboxPath = self::CALENDAR_ROOT . '/' . $principalId . '/outbox'; + + unset($requestedProperties[array_search($scheduleProp, $requestedProperties)]); + $returnedProperties[200][$scheduleProp] = new DAV\Property\Href($outboxPath); + + } + + // calendar-user-address-set property + $calProp = '{' . self::NS_CALDAV . '}calendar-user-address-set'; + if (in_array($calProp,$requestedProperties)) { + + $addresses = $node->getAlternateUriSet(); + $addresses[] = $this->server->getBaseUri() . DAV\URLUtil::encodePath($node->getPrincipalUrl() . '/'); + unset($requestedProperties[array_search($calProp, $requestedProperties)]); + $returnedProperties[200][$calProp] = new DAV\Property\HrefList($addresses, false); + + } + + // These two properties are shortcuts for ical to easily find + // other principals this principal has access to. + $propRead = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-read-for'; + $propWrite = '{' . self::NS_CALENDARSERVER . '}calendar-proxy-write-for'; + if (in_array($propRead,$requestedProperties) || in_array($propWrite,$requestedProperties)) { + + $aclPlugin = $this->server->getPlugin('acl'); + $membership = $aclPlugin->getPrincipalMembership($path); + $readList = array(); + $writeList = array(); + + foreach($membership as $group) { + + $groupNode = $this->server->tree->getNodeForPath($group); + + // If the node is either ap proxy-read or proxy-write + // group, we grab the parent principal and add it to the + // list. + if ($groupNode instanceof Principal\IProxyRead) { + list($readList[]) = DAV\URLUtil::splitPath($group); + } + if ($groupNode instanceof Principal\IProxyWrite) { + list($writeList[]) = DAV\URLUtil::splitPath($group); + } + + } + if (in_array($propRead,$requestedProperties)) { + unset($requestedProperties[$propRead]); + $returnedProperties[200][$propRead] = new DAV\Property\HrefList($readList); + } + if (in_array($propWrite,$requestedProperties)) { + unset($requestedProperties[$propWrite]); + $returnedProperties[200][$propWrite] = new DAV\Property\HrefList($writeList); + } + + } + + // notification-URL property + $notificationUrl = '{' . self::NS_CALENDARSERVER . '}notification-URL'; + if (($index = array_search($notificationUrl, $requestedProperties)) !== false) { + $principalId = $node->getName(); + $calendarHomePath = 'calendars/' . $principalId . '/notifications/'; + unset($requestedProperties[$index]); + $returnedProperties[200][$notificationUrl] = new DAV\Property\Href($calendarHomePath); + } + + } // instanceof IPrincipal + + if ($node instanceof Notifications\INode) { + + $propertyName = '{' . self::NS_CALENDARSERVER . '}notificationtype'; + if (($index = array_search($propertyName, $requestedProperties)) !== false) { + + $returnedProperties[200][$propertyName] = + $node->getNotificationType(); + + unset($requestedProperties[$index]); + + } + + } // instanceof Notifications_INode + + + if ($node instanceof ICalendarObject) { + // The calendar-data property is not supposed to be a 'real' + // property, but in large chunks of the spec it does act as such. + // Therefore we simply expose it as a property. + $calDataProp = '{' . Plugin::NS_CALDAV . '}calendar-data'; + if (in_array($calDataProp, $requestedProperties)) { + unset($requestedProperties[$calDataProp]); + $val = $node->get(); + if (is_resource($val)) + $val = stream_get_contents($val); + + // Taking out \r to not screw up the xml output + $returnedProperties[200][$calDataProp] = str_replace("\r","", $val); + + } + } + + } + + /** + * This function handles the calendar-multiget REPORT. + * + * This report is used by the client to fetch the content of a series + * of urls. Effectively avoiding a lot of redundant requests. + * + * @param \DOMNode $dom + * @return void + */ + public function calendarMultiGetReport($dom) { + + $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)); + $hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href'); + + $xpath = new \DOMXPath($dom); + $xpath->registerNameSpace('cal',Plugin::NS_CALDAV); + $xpath->registerNameSpace('dav','urn:DAV'); + + $expand = $xpath->query('/cal:calendar-multiget/dav:prop/cal:calendar-data/cal:expand'); + if ($expand->length>0) { + $expandElem = $expand->item(0); + $start = $expandElem->getAttribute('start'); + $end = $expandElem->getAttribute('end'); + if(!$start || !$end) { + throw new DAV\Exception\BadRequest('The "start" and "end" attributes are required for the CALDAV:expand element'); + } + $start = VObject\DateTimeParser::parseDateTime($start); + $end = VObject\DateTimeParser::parseDateTime($end); + + if ($end <= $start) { + throw new DAV\Exception\BadRequest('The end-date must be larger than the start-date in the expand element.'); + } + + $expand = true; + + } else { + + $expand = false; + + } + + foreach($hrefElems as $elem) { + $uri = $this->server->calculateUri($elem->nodeValue); + list($objProps) = $this->server->getPropertiesForPath($uri,$properties); + + if ($expand && isset($objProps[200]['{' . self::NS_CALDAV . '}calendar-data'])) { + $vObject = VObject\Reader::read($objProps[200]['{' . self::NS_CALDAV . '}calendar-data']); + $vObject->expand($start, $end); + $objProps[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); + } + + $propertyList[]=$objProps; + + } + + $prefer = $this->server->getHTTPPRefer(); + + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal'])); + + } + + /** + * This function handles the calendar-query REPORT + * + * This report is used by clients to request calendar objects based on + * complex conditions. + * + * @param \DOMNode $dom + * @return void + */ + public function calendarQueryReport($dom) { + + $parser = new CalendarQueryParser($dom); + $parser->parse(); + + $node = $this->server->tree->getNodeForPath($this->server->getRequestUri()); + $depth = $this->server->getHTTPDepth(0); + + // The default result is an empty array + $result = array(); + + // The calendarobject was requested directly. In this case we handle + // this locally. + if ($depth == 0 && $node instanceof ICalendarObject) { + + $requestedCalendarData = true; + $requestedProperties = $parser->requestedProperties; + + if (!in_array('{urn:ietf:params:xml:ns:caldav}calendar-data', $requestedProperties)) { + + // We always retrieve calendar-data, as we need it for filtering. + $requestedProperties[] = '{urn:ietf:params:xml:ns:caldav}calendar-data'; + + // If calendar-data wasn't explicitly requested, we need to remove + // it after processing. + $requestedCalendarData = false; + } + + $properties = $this->server->getPropertiesForPath( + $this->server->getRequestUri(), + $requestedProperties, + 0 + ); + + // This array should have only 1 element, the first calendar + // object. + $properties = current($properties); + + // If there wasn't any calendar-data returned somehow, we ignore + // this. + if (isset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data'])) { + + $validator = new CalendarQueryValidator(); + + $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); + if ($validator->validate($vObject,$parser->filters)) { + + // If the client didn't require the calendar-data property, + // we won't give it back. + if (!$requestedCalendarData) { + unset($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); + } else { + if ($parser->expand) { + $vObject->expand($parser->expand['start'], $parser->expand['end']); + $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); + } + } + + $result = array($properties); + + } + + } + + } + // If we're dealing with a calendar, the calendar itself is responsible + // for the calendar-query. + if ($node instanceof ICalendar && $depth = 1) { + + $nodePaths = $node->calendarQuery($parser->filters); + + foreach($nodePaths as $path) { + + list($properties) = + $this->server->getPropertiesForPath($this->server->getRequestUri() . '/' . $path, $parser->requestedProperties); + + if ($parser->expand) { + // We need to do some post-processing + $vObject = VObject\Reader::read($properties[200]['{urn:ietf:params:xml:ns:caldav}calendar-data']); + $vObject->expand($parser->expand['start'], $parser->expand['end']); + $properties[200]['{' . self::NS_CALDAV . '}calendar-data'] = $vObject->serialize(); + } + + $result[] = $properties; + + } + + } + + $prefer = $this->server->getHTTPPRefer(); + + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal'])); + + } + + /** + * This method is responsible for parsing the request and generating the + * response for the CALDAV:free-busy-query REPORT. + * + * @param \DOMNode $dom + * @return void + */ + protected function freeBusyQueryReport(\DOMNode $dom) { + + $start = null; + $end = null; + + foreach($dom->firstChild->childNodes as $childNode) { + + $clark = DAV\XMLUtil::toClarkNotation($childNode); + if ($clark == '{' . self::NS_CALDAV . '}time-range') { + $start = $childNode->getAttribute('start'); + $end = $childNode->getAttribute('end'); + break; + } + + } + if ($start) { + $start = VObject\DateTimeParser::parseDateTime($start); + } + if ($end) { + $end = VObject\DateTimeParser::parseDateTime($end); + } + + if (!$start && !$end) { + throw new DAV\Exception\BadRequest('The freebusy report must have a time-range filter'); + } + $acl = $this->server->getPlugin('acl'); + + if (!$acl) { + throw new DAV\Exception('The ACL plugin must be loaded for free-busy queries to work'); + } + $uri = $this->server->getRequestUri(); + $acl->checkPrivileges($uri,'{' . self::NS_CALDAV . '}read-free-busy'); + + $calendar = $this->server->tree->getNodeForPath($uri); + if (!$calendar instanceof ICalendar) { + throw new DAV\Exception\NotImplemented('The free-busy-query REPORT is only implemented on calendars'); + } + + // Doing a calendar-query first, to make sure we get the most + // performance. + $urls = $calendar->calendarQuery(array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => $start, + 'end' => $end, + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + )); + + $objects = array_map(function($url) use ($calendar) { + $obj = $calendar->getChild($url)->get(); + return $obj; + }, $urls); + + $generator = new VObject\FreeBusyGenerator(); + $generator->setObjects($objects); + $generator->setTimeRange($start, $end); + $result = $generator->getResult(); + $result = $result->serialize(); + + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type', 'text/calendar'); + $this->server->httpResponse->setHeader('Content-Length', strlen($result)); + $this->server->httpResponse->sendBody($result); + + } + + /** + * This method is triggered before a file gets updated with new content. + * + * This plugin uses this method to ensure that CalDAV objects receive + * valid calendar data. + * + * @param string $path + * @param DAV\IFile $node + * @param resource $data + * @return void + */ + public function beforeWriteContent($path, DAV\IFile $node, &$data) { + + if (!$node instanceof ICalendarObject) + return; + + $this->validateICalendar($data, $path); + + } + + /** + * This method is triggered before a new file is created. + * + * This plugin uses this method to ensure that newly created calendar + * objects contain valid calendar data. + * + * @param string $path + * @param resource $data + * @param DAV\ICollection $parentNode + * @return void + */ + public function beforeCreateFile($path, &$data, DAV\ICollection $parentNode) { + + if (!$parentNode instanceof Calendar) + return; + + $this->validateICalendar($data, $path); + + } + + /** + * This event is triggered before any HTTP request is handled. + * + * We use this to intercept GET calls to notification nodes, and return the + * proper response. + * + * @param string $method + * @param string $path + * @return void + */ + public function beforeMethod($method, $path) { + + if ($method!=='GET') return; + + try { + $node = $this->server->tree->getNodeForPath($path); + } catch (DAV\Exception\NotFound $e) { + return; + } + + if (!$node instanceof Notifications\INode) + return; + + if (!$this->server->checkPreconditions(true)) return false; + $dom = new \DOMDocument('1.0', 'UTF-8'); + + $dom->formatOutput = true; + + $root = $dom->createElement('cs:notification'); + foreach($this->server->xmlNamespaces as $namespace => $prefix) { + $root->setAttribute('xmlns:' . $prefix, $namespace); + } + + $dom->appendChild($root); + $node->getNotificationType()->serializeBody($this->server, $root); + + $this->server->httpResponse->setHeader('Content-Type','application/xml'); + $this->server->httpResponse->setHeader('ETag',$node->getETag()); + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->sendBody($dom->saveXML()); + + return false; + + } + + /** + * Checks if the submitted iCalendar data is in fact, valid. + * + * An exception is thrown if it's not. + * + * @param resource|string $data + * @param string $path + * @return void + */ + protected function validateICalendar(&$data, $path) { + + // If it's a stream, we convert it to a string first. + if (is_resource($data)) { + $data = stream_get_contents($data); + } + + // Converting the data to unicode, if needed. + $data = DAV\StringUtil::ensureUTF8($data); + + try { + + $vobj = VObject\Reader::read($data); + + } catch (VObject\ParseException $e) { + + throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid iCalendar 2.0 data. Parse error: ' . $e->getMessage()); + + } + + if ($vobj->name !== 'VCALENDAR') { + throw new DAV\Exception\UnsupportedMediaType('This collection can only support iCalendar objects.'); + } + + // Get the Supported Components for the target calendar + list($parentPath,$object) = DAV\URLUtil::splitPath($path); + $calendarProperties = $this->server->getProperties($parentPath,array('{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set')); + $supportedComponents = $calendarProperties['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue(); + + $foundType = null; + $foundUID = null; + foreach($vobj->getComponents() as $component) { + switch($component->name) { + case 'VTIMEZONE' : + continue 2; + case 'VEVENT' : + case 'VTODO' : + case 'VJOURNAL' : + if (is_null($foundType)) { + $foundType = $component->name; + if (!in_array($foundType, $supportedComponents)) { + throw new Exception\InvalidComponentType('This calendar only supports ' . implode(', ', $supportedComponents) . '. We found a ' . $foundType); + } + if (!isset($component->UID)) { + throw new DAV\Exception\BadRequest('Every ' . $component->name . ' component must have an UID'); + } + $foundUID = (string)$component->UID; + } else { + if ($foundType !== $component->name) { + throw new DAV\Exception\BadRequest('A calendar object must only contain 1 component. We found a ' . $component->name . ' as well as a ' . $foundType); + } + if ($foundUID !== (string)$component->UID) { + throw new DAV\Exception\BadRequest('Every ' . $component->name . ' in this object must have identical UIDs'); + } + } + break; + default : + throw new DAV\Exception\BadRequest('You are not allowed to create components of type: ' . $component->name . ' here'); + + } + } + if (!$foundType) + throw new DAV\Exception\BadRequest('iCalendar object must contain at least 1 of VEVENT, VTODO or VJOURNAL'); + + } + + /** + * This method handles POST requests to the schedule-outbox. + * + * Currently, two types of requests are support: + * * FREEBUSY requests from RFC 6638 + * * Simple iTIP messages from draft-desruisseaux-caldav-sched-04 + * + * The latter is from an expired early draft of the CalDAV scheduling + * extensions, but iCal depends on a feature from that spec, so we + * implement it. + * + * @param Schedule\IOutbox $outboxNode + * @param string $outboxUri + * @return void + */ + public function outboxRequest(Schedule\IOutbox $outboxNode, $outboxUri) { + + // Parsing the request body + try { + $vObject = VObject\Reader::read($this->server->httpRequest->getBody(true)); + } catch (VObject\ParseException $e) { + throw new DAV\Exception\BadRequest('The request body must be a valid iCalendar object. Parse error: ' . $e->getMessage()); + } + + // The incoming iCalendar object must have a METHOD property, and a + // component. The combination of both determines what type of request + // this is. + $componentType = null; + foreach($vObject->getComponents() as $component) { + if ($component->name !== 'VTIMEZONE') { + $componentType = $component->name; + break; + } + } + if (is_null($componentType)) { + throw new DAV\Exception\BadRequest('We expected at least one VTODO, VJOURNAL, VFREEBUSY or VEVENT component'); + } + + // Validating the METHOD + $method = strtoupper((string)$vObject->METHOD); + if (!$method) { + throw new DAV\Exception\BadRequest('A METHOD property must be specified in iTIP messages'); + } + + // So we support two types of requests: + // + // REQUEST with a VFREEBUSY component + // REQUEST, REPLY, ADD, CANCEL on VEVENT components + + $acl = $this->server->getPlugin('acl'); + + if ($componentType === 'VFREEBUSY' && $method === 'REQUEST') { + + $acl && $acl->checkPrivileges($outboxUri,'{' . Plugin::NS_CALDAV . '}schedule-query-freebusy'); + $this->handleFreeBusyRequest($outboxNode, $vObject); + + } elseif ($componentType === 'VEVENT' && in_array($method, array('REQUEST','REPLY','ADD','CANCEL'))) { + + $acl && $acl->checkPrivileges($outboxUri,'{' . Plugin::NS_CALDAV . '}schedule-post-vevent'); + $this->handleEventNotification($outboxNode, $vObject); + + } else { + + throw new DAV\Exception\NotImplemented('SabreDAV supports only VFREEBUSY (REQUEST) and VEVENT (REQUEST, REPLY, ADD, CANCEL)'); + + } + + } + + /** + * This method handles the REQUEST, REPLY, ADD and CANCEL methods for + * VEVENT iTip messages. + * + * @return void + */ + protected function handleEventNotification(Schedule\IOutbox $outboxNode, VObject\Component $vObject) { + + $originator = $this->server->httpRequest->getHeader('Originator'); + $recipients = $this->server->httpRequest->getHeader('Recipient'); + + if (!$originator) { + throw new DAV\Exception\BadRequest('The Originator: header must be specified when making POST requests'); + } + if (!$recipients) { + throw new DAV\Exception\BadRequest('The Recipient: header must be specified when making POST requests'); + } + + $recipients = explode(',',$recipients); + foreach($recipients as $k=>$recipient) { + + $recipient = trim($recipient); + if (!preg_match('/^mailto:(.*)@(.*)$/i', $recipient)) { + throw new DAV\Exception\BadRequest('Recipients must start with mailto: and must be valid email address'); + } + $recipient = substr($recipient, 7); + $recipients[$k] = $recipient; + } + + // We need to make sure that 'originator' matches one of the email + // addresses of the selected principal. + $principal = $outboxNode->getOwner(); + $props = $this->server->getProperties($principal,array( + '{' . self::NS_CALDAV . '}calendar-user-address-set', + )); + + $addresses = array(); + if (isset($props['{' . self::NS_CALDAV . '}calendar-user-address-set'])) { + $addresses = $props['{' . self::NS_CALDAV . '}calendar-user-address-set']->getHrefs(); + } + + $found = false; + foreach($addresses as $address) { + + // Trimming the / on both sides, just in case.. + if (rtrim(strtolower($originator),'/') === rtrim(strtolower($address),'/')) { + $found = true; + break; + } + + } + + if (!$found) { + throw new DAV\Exception\Forbidden('The addresses specified in the Originator header did not match any addresses in the owners calendar-user-address-set header'); + } + + // If the Originator header was a url, and not a mailto: address.. + // we're going to try to pull the mailto: from the vobject body. + if (strtolower(substr($originator,0,7)) !== 'mailto:') { + $originator = (string)$vObject->VEVENT->ORGANIZER; + + } + if (strtolower(substr($originator,0,7)) !== 'mailto:') { + throw new DAV\Exception\Forbidden('Could not find mailto: address in both the Orignator header, and the ORGANIZER property in the VEVENT'); + } + $originator = substr($originator,7); + + $result = $this->iMIPMessage($originator, $recipients, $vObject, $principal); + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','application/xml'); + $this->server->httpResponse->sendBody($this->generateScheduleResponse($result)); + + } + + /** + * Sends an iMIP message by email. + * + * This method must return an array with status codes per recipient. + * This should look something like: + * + * array( + * 'user1@example.org' => '2.0;Success' + * ) + * + * Formatting for this status code can be found at: + * https://tools.ietf.org/html/rfc5545#section-3.8.8.3 + * + * A list of valid status codes can be found at: + * https://tools.ietf.org/html/rfc5546#section-3.6 + * + * @param string $originator + * @param array $recipients + * @param VObject\Component $vObject + * @param string $principal Principal url + * @return array + */ + protected function iMIPMessage($originator, array $recipients, VObject\Component $vObject, $principal) { + + if (!$this->imipHandler) { + $resultStatus = '5.2;This server does not support this operation'; + } else { + $this->imipHandler->sendMessage($originator, $recipients, $vObject, $principal); + $resultStatus = '2.0;Success'; + } + + $result = array(); + foreach($recipients as $recipient) { + $result[$recipient] = $resultStatus; + } + + return $result; + + } + + /** + * Generates a schedule-response XML body + * + * The recipients array is a key->value list, containing email addresses + * and iTip status codes. See the iMIPMessage method for a description of + * the value. + * + * @param array $recipients + * @return string + */ + public function generateScheduleResponse(array $recipients) { + + $dom = new \DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + $xscheduleResponse = $dom->createElement('cal:schedule-response'); + $dom->appendChild($xscheduleResponse); + + foreach($this->server->xmlNamespaces as $namespace=>$prefix) { + + $xscheduleResponse->setAttribute('xmlns:' . $prefix, $namespace); + + } + + foreach($recipients as $recipient=>$status) { + $xresponse = $dom->createElement('cal:response'); + + $xrecipient = $dom->createElement('cal:recipient'); + $xrecipient->appendChild($dom->createTextNode($recipient)); + $xresponse->appendChild($xrecipient); + + $xrequestStatus = $dom->createElement('cal:request-status'); + $xrequestStatus->appendChild($dom->createTextNode($status)); + $xresponse->appendChild($xrequestStatus); + + $xscheduleResponse->appendChild($xresponse); + + } + + return $dom->saveXML(); + + } + + /** + * This method is responsible for parsing a free-busy query request and + * returning it's result. + * + * @param Schedule\IOutbox $outbox + * @param string $request + * @return string + */ + protected function handleFreeBusyRequest(Schedule\IOutbox $outbox, VObject\Component $vObject) { + + $vFreeBusy = $vObject->VFREEBUSY; + $organizer = $vFreeBusy->organizer; + + $organizer = (string)$organizer; + + // Validating if the organizer matches the owner of the inbox. + $owner = $outbox->getOwner(); + + $caldavNS = '{' . Plugin::NS_CALDAV . '}'; + + $uas = $caldavNS . 'calendar-user-address-set'; + $props = $this->server->getProperties($owner,array($uas)); + + if (empty($props[$uas]) || !in_array($organizer, $props[$uas]->getHrefs())) { + throw new DAV\Exception\Forbidden('The organizer in the request did not match any of the addresses for the owner of this inbox'); + } + + if (!isset($vFreeBusy->ATTENDEE)) { + throw new DAV\Exception\BadRequest('You must at least specify 1 attendee'); + } + + $attendees = array(); + foreach($vFreeBusy->ATTENDEE as $attendee) { + $attendees[]= (string)$attendee; + } + + + if (!isset($vFreeBusy->DTSTART) || !isset($vFreeBusy->DTEND)) { + throw new DAV\Exception\BadRequest('DTSTART and DTEND must both be specified'); + } + + $startRange = $vFreeBusy->DTSTART->getDateTime(); + $endRange = $vFreeBusy->DTEND->getDateTime(); + + $results = array(); + foreach($attendees as $attendee) { + $results[] = $this->getFreeBusyForEmail($attendee, $startRange, $endRange, $vObject); + } + + $dom = new \DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + $scheduleResponse = $dom->createElement('cal:schedule-response'); + foreach($this->server->xmlNamespaces as $namespace=>$prefix) { + + $scheduleResponse->setAttribute('xmlns:' . $prefix,$namespace); + + } + $dom->appendChild($scheduleResponse); + + foreach($results as $result) { + $response = $dom->createElement('cal:response'); + + $recipient = $dom->createElement('cal:recipient'); + $recipientHref = $dom->createElement('d:href'); + + $recipientHref->appendChild($dom->createTextNode($result['href'])); + $recipient->appendChild($recipientHref); + $response->appendChild($recipient); + + $reqStatus = $dom->createElement('cal:request-status'); + $reqStatus->appendChild($dom->createTextNode($result['request-status'])); + $response->appendChild($reqStatus); + + if (isset($result['calendar-data'])) { + + $calendardata = $dom->createElement('cal:calendar-data'); + $calendardata->appendChild($dom->createTextNode(str_replace("\r\n","\n",$result['calendar-data']->serialize()))); + $response->appendChild($calendardata); + + } + $scheduleResponse->appendChild($response); + } + + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','application/xml'); + $this->server->httpResponse->sendBody($dom->saveXML()); + + } + + /** + * Returns free-busy information for a specific address. The returned + * data is an array containing the following properties: + * + * calendar-data : A VFREEBUSY VObject + * request-status : an iTip status code. + * href: The principal's email address, as requested + * + * The following request status codes may be returned: + * * 2.0;description + * * 3.7;description + * + * @param string $email address + * @param \DateTime $start + * @param \DateTime $end + * @param VObject\Component $request + * @return array + */ + protected function getFreeBusyForEmail($email, \DateTime $start, \DateTime $end, VObject\Component $request) { + + $caldavNS = '{' . Plugin::NS_CALDAV . '}'; + + $aclPlugin = $this->server->getPlugin('acl'); + if (substr($email,0,7)==='mailto:') $email = substr($email,7); + + $result = $aclPlugin->principalSearch( + array('{http://sabredav.org/ns}email-address' => $email), + array( + '{DAV:}principal-URL', $caldavNS . 'calendar-home-set', + '{http://sabredav.org/ns}email-address', + ) + ); + + if (!count($result)) { + return array( + 'request-status' => '3.7;Could not find principal', + 'href' => 'mailto:' . $email, + ); + } + + if (!isset($result[0][200][$caldavNS . 'calendar-home-set'])) { + return array( + 'request-status' => '3.7;No calendar-home-set property found', + 'href' => 'mailto:' . $email, + ); + } + $homeSet = $result[0][200][$caldavNS . 'calendar-home-set']->getHref(); + + // Grabbing the calendar list + $objects = array(); + foreach($this->server->tree->getNodeForPath($homeSet)->getChildren() as $node) { + if (!$node instanceof ICalendar) { + continue; + } + $aclPlugin->checkPrivileges($homeSet . $node->getName() ,$caldavNS . 'read-free-busy'); + + // Getting the list of object uris within the time-range + $urls = $node->calendarQuery(array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => $start, + 'end' => $end, + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + )); + + $calObjects = array_map(function($url) use ($node) { + $obj = $node->getChild($url)->get(); + return $obj; + }, $urls); + + $objects = array_merge($objects,$calObjects); + + } + + $vcalendar = new VObject\Component\VCalendar(); + $vcalendar->VERSION = '2.0'; + $vcalendar->METHOD = 'REPLY'; + $vcalendar->CALSCALE = 'GREGORIAN'; + $vcalendar->PRODID = '-//SabreDAV//SabreDAV ' . DAV\Version::VERSION . '//EN'; + + $generator = new VObject\FreeBusyGenerator(); + $generator->setObjects($objects); + $generator->setTimeRange($start, $end); + $generator->setBaseObject($vcalendar); + + $result = $generator->getResult(); + + $vcalendar->VFREEBUSY->ATTENDEE = 'mailto:' . $email; + $vcalendar->VFREEBUSY->UID = (string)$request->VFREEBUSY->UID; + $vcalendar->VFREEBUSY->ORGANIZER = clone $request->VFREEBUSY->ORGANIZER; + + return array( + 'calendar-data' => $result, + 'request-status' => '2.0;Success', + 'href' => 'mailto:' . $email, + ); + } + + /** + * This method is used to generate HTML output for the + * DAV\Browser\Plugin. This allows us to generate an interface users + * can use to create new calendars. + * + * @param DAV\INode $node + * @param string $output + * @return bool + */ + public function htmlActionsPanel(DAV\INode $node, &$output) { + + if (!$node instanceof UserCalendars) + return; + + $output.= '
    +

    Create new calendar

    + +
    +
    + +
    + '; + + return false; + + } + + /** + * This method allows us to intercept the 'mkcalendar' sabreAction. This + * action enables the user to create new calendars from the browser plugin. + * + * @param string $uri + * @param string $action + * @param array $postVars + * @return bool + */ + public function browserPostAction($uri, $action, array $postVars) { + + if ($action!=='mkcalendar') + return; + + $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:caldav}calendar'); + $properties = array(); + if (isset($postVars['{DAV:}displayname'])) { + $properties['{DAV:}displayname'] = $postVars['{DAV:}displayname']; + } + $this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties); + return false; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/Collection.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/Collection.php new file mode 100644 index 00000000..8a747a64 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/Collection.php @@ -0,0 +1,32 @@ +principalBackend, $principalInfo); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/IProxyRead.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/IProxyRead.php new file mode 100644 index 00000000..548411fa --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/IProxyRead.php @@ -0,0 +1,19 @@ +principalInfo = $principalInfo; + $this->principalBackend = $principalBackend; + + } + + /** + * Returns this principals name. + * + * @return string + */ + public function getName() { + + return 'calendar-proxy-read'; + + } + + /** + * Returns the last modification time + * + * @return null + */ + public function getLastModified() { + + return null; + + } + + /** + * Deletes the current node + * + * @throws DAV\Exception\Forbidden + * @return void + */ + public function delete() { + + throw new DAV\Exception\Forbidden('Permission denied to delete node'); + + } + + /** + * Renames the node + * + * @throws DAV\Exception\Forbidden + * @param string $name The new name + * @return void + */ + public function setName($name) { + + throw new DAV\Exception\Forbidden('Permission denied to rename file'); + + } + + + /** + * Returns a list of alternative urls for a principal + * + * This can for example be an email address, or ldap url. + * + * @return array + */ + public function getAlternateUriSet() { + + return array(); + + } + + /** + * Returns the full principal url + * + * @return string + */ + public function getPrincipalUrl() { + + return $this->principalInfo['uri'] . '/' . $this->getName(); + + } + + /** + * Returns the list of group members + * + * If this principal is a group, this function should return + * all member principal uri's for the group. + * + * @return array + */ + public function getGroupMemberSet() { + + return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl()); + + } + + /** + * Returns the list of groups this principal is member of + * + * If this principal is a member of a (list of) groups, this function + * should return a list of principal uri's for it's members. + * + * @return array + */ + public function getGroupMembership() { + + return $this->principalBackend->getGroupMembership($this->getPrincipalUrl()); + + } + + /** + * Sets a list of group members + * + * If this principal is a group, this method sets all the group members. + * The list of members is always overwritten, never appended to. + * + * This method should throw an exception if the members could not be set. + * + * @param array $principals + * @return void + */ + public function setGroupMemberSet(array $principals) { + + $this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals); + + } + + /** + * Returns the displayname + * + * This should be a human readable name for the principal. + * If none is available, return the nodename. + * + * @return string + */ + public function getDisplayName() { + + return $this->getName(); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/ProxyWrite.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/ProxyWrite.php new file mode 100644 index 00000000..02cd81f7 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/ProxyWrite.php @@ -0,0 +1,180 @@ +principalInfo = $principalInfo; + $this->principalBackend = $principalBackend; + + } + + /** + * Returns this principals name. + * + * @return string + */ + public function getName() { + + return 'calendar-proxy-write'; + + } + + /** + * Returns the last modification time + * + * @return null + */ + public function getLastModified() { + + return null; + + } + + /** + * Deletes the current node + * + * @throws DAV\Exception\Forbidden + * @return void + */ + public function delete() { + + throw new DAV\Exception\Forbidden('Permission denied to delete node'); + + } + + /** + * Renames the node + * + * @throws DAV\Exception\Forbidden + * @param string $name The new name + * @return void + */ + public function setName($name) { + + throw new DAV\Exception\Forbidden('Permission denied to rename file'); + + } + + + /** + * Returns a list of alternative urls for a principal + * + * This can for example be an email address, or ldap url. + * + * @return array + */ + public function getAlternateUriSet() { + + return array(); + + } + + /** + * Returns the full principal url + * + * @return string + */ + public function getPrincipalUrl() { + + return $this->principalInfo['uri'] . '/' . $this->getName(); + + } + + /** + * Returns the list of group members + * + * If this principal is a group, this function should return + * all member principal uri's for the group. + * + * @return array + */ + public function getGroupMemberSet() { + + return $this->principalBackend->getGroupMemberSet($this->getPrincipalUrl()); + + } + + /** + * Returns the list of groups this principal is member of + * + * If this principal is a member of a (list of) groups, this function + * should return a list of principal uri's for it's members. + * + * @return array + */ + public function getGroupMembership() { + + return $this->principalBackend->getGroupMembership($this->getPrincipalUrl()); + + } + + /** + * Sets a list of group members + * + * If this principal is a group, this method sets all the group members. + * The list of members is always overwritten, never appended to. + * + * This method should throw an exception if the members could not be set. + * + * @param array $principals + * @return void + */ + public function setGroupMemberSet(array $principals) { + + $this->principalBackend->setGroupMemberSet($this->getPrincipalUrl(), $principals); + + } + + /** + * Returns the displayname + * + * This should be a human readable name for the principal. + * If none is available, return the nodename. + * + * @return string + */ + public function getDisplayName() { + + return $this->getName(); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/User.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/User.php new file mode 100644 index 00000000..6f3ccb86 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Principal/User.php @@ -0,0 +1,134 @@ +principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/' . $name); + if (!$principal) { + throw new DAV\Exception\NotFound('Node with name ' . $name . ' was not found'); + } + if ($name === 'calendar-proxy-read') + return new ProxyRead($this->principalBackend, $this->principalProperties); + + if ($name === 'calendar-proxy-write') + return new ProxyWrite($this->principalBackend, $this->principalProperties); + + throw new DAV\Exception\NotFound('Node with name ' . $name . ' was not found'); + + } + + /** + * Returns an array with all the child nodes + * + * @return DAV\INode[] + */ + public function getChildren() { + + $r = array(); + if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-read')) { + $r[] = new ProxyRead($this->principalBackend, $this->principalProperties); + } + if ($this->principalBackend->getPrincipalByPath($this->getPrincipalURL() . '/calendar-proxy-write')) { + $r[] = new ProxyWrite($this->principalBackend, $this->principalProperties); + } + + return $r; + + } + + /** + * Returns whether or not the child node exists + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + try { + $this->getChild($name); + return true; + } catch (DAV\Exception\NotFound $e) { + return false; + } + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + $acl = parent::getACL(); + $acl[] = array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalProperties['uri'] . '/calendar-proxy-read', + 'protected' => true, + ); + $acl[] = array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalProperties['uri'] . '/calendar-proxy-write', + 'protected' => true, + ); + return $acl; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/AllowedSharingModes.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/AllowedSharingModes.php new file mode 100644 index 00000000..ca8312d4 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/AllowedSharingModes.php @@ -0,0 +1,74 @@ +canBeShared = $canBeShared; + $this->canBePublished = $canBePublished; + + } + + /** + * Serializes the property in a DOMDocument + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $node) { + + $doc = $node->ownerDocument; + if ($this->canBeShared) { + $xcomp = $doc->createElement('cs:can-be-shared'); + $node->appendChild($xcomp); + } + if ($this->canBePublished) { + $xcomp = $doc->createElement('cs:can-be-published'); + $node->appendChild($xcomp); + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/Invite.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/Invite.php new file mode 100644 index 00000000..86ef69e8 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/Invite.php @@ -0,0 +1,227 @@ +users = $users; + $this->organizer = $organizer; + + } + + /** + * Returns the list of users, as it was passed to the constructor. + * + * @return array + */ + public function getValue() { + + return $this->users; + + } + + /** + * Serializes the property in a DOMDocument + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + + if (!is_null($this->organizer)) { + + $xorganizer = $doc->createElement('cs:organizer'); + + $href = $doc->createElement('d:href'); + $href->appendChild($doc->createTextNode($this->organizer['href'])); + $xorganizer->appendChild($href); + + if (isset($this->organizer['commonName']) && $this->organizer['commonName']) { + $commonName = $doc->createElement('cs:common-name'); + $commonName->appendChild($doc->createTextNode($this->organizer['commonName'])); + $xorganizer->appendChild($commonName); + } + if (isset($this->organizer['firstName']) && $this->organizer['firstName']) { + $firstName = $doc->createElement('cs:first-name'); + $firstName->appendChild($doc->createTextNode($this->organizer['firstName'])); + $xorganizer->appendChild($firstName); + } + if (isset($this->organizer['lastName']) && $this->organizer['lastName']) { + $lastName = $doc->createElement('cs:last-name'); + $lastName->appendChild($doc->createTextNode($this->organizer['lastName'])); + $xorganizer->appendChild($lastName); + } + + $node->appendChild($xorganizer); + + + } + + foreach($this->users as $user) { + + $xuser = $doc->createElement('cs:user'); + + $href = $doc->createElement('d:href'); + $href->appendChild($doc->createTextNode($user['href'])); + $xuser->appendChild($href); + + if (isset($user['commonName']) && $user['commonName']) { + $commonName = $doc->createElement('cs:common-name'); + $commonName->appendChild($doc->createTextNode($user['commonName'])); + $xuser->appendChild($commonName); + } + + switch($user['status']) { + + case SharingPlugin::STATUS_ACCEPTED : + $status = $doc->createElement('cs:invite-accepted'); + $xuser->appendChild($status); + break; + case SharingPlugin::STATUS_DECLINED : + $status = $doc->createElement('cs:invite-declined'); + $xuser->appendChild($status); + break; + case SharingPlugin::STATUS_NORESPONSE : + $status = $doc->createElement('cs:invite-noresponse'); + $xuser->appendChild($status); + break; + case SharingPlugin::STATUS_INVALID : + $status = $doc->createElement('cs:invite-invalid'); + $xuser->appendChild($status); + break; + + } + + $xaccess = $doc->createElement('cs:access'); + + if ($user['readOnly']) { + $xaccess->appendChild( + $doc->createElement('cs:read') + ); + } else { + $xaccess->appendChild( + $doc->createElement('cs:read-write') + ); + } + $xuser->appendChild($xaccess); + + if (isset($user['summary']) && $user['summary']) { + $summary = $doc->createElement('cs:summary'); + $summary->appendChild($doc->createTextNode($user['summary'])); + $xuser->appendChild($summary); + } + + $node->appendChild($xuser); + + } + + + } + + /** + * Unserializes the property. + * + * This static method should return a an instance of this object. + * + * @param \DOMElement $prop + * @return DAV\IProperty + */ + static function unserialize(\DOMElement $prop) { + + $xpath = new \DOMXPath($prop->ownerDocument); + $xpath->registerNamespace('cs', CalDAV\Plugin::NS_CALENDARSERVER); + $xpath->registerNamespace('d', 'urn:DAV'); + + $users = array(); + + foreach($xpath->query('cs:user', $prop) as $user) { + + $status = null; + if ($xpath->evaluate('boolean(cs:invite-accepted)', $user)) { + $status = SharingPlugin::STATUS_ACCEPTED; + } elseif ($xpath->evaluate('boolean(cs:invite-declined)', $user)) { + $status = SharingPlugin::STATUS_DECLINED; + } elseif ($xpath->evaluate('boolean(cs:invite-noresponse)', $user)) { + $status = SharingPlugin::STATUS_NORESPONSE; + } elseif ($xpath->evaluate('boolean(cs:invite-invalid)', $user)) { + $status = SharingPlugin::STATUS_INVALID; + } else { + throw new DAV\Exception('Every cs:user property must have one of cs:invite-accepted, cs:invite-declined, cs:invite-noresponse or cs:invite-invalid'); + } + $users[] = array( + 'href' => $xpath->evaluate('string(d:href)', $user), + 'commonName' => $xpath->evaluate('string(cs:common-name)', $user), + 'readOnly' => $xpath->evaluate('boolean(cs:access/cs:read)', $user), + 'summary' => $xpath->evaluate('string(cs:summary)', $user), + 'status' => $status, + ); + + } + + return new self($users); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/ScheduleCalendarTransp.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/ScheduleCalendarTransp.php new file mode 100644 index 00000000..7f12d758 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/ScheduleCalendarTransp.php @@ -0,0 +1,102 @@ +value = $value; + + } + + /** + * Returns the current value + * + * @return string + */ + public function getValue() { + + return $this->value; + + } + + /** + * Serializes the property in a DOMDocument + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + switch($this->value) { + case self::TRANSPARENT : + $xval = $doc->createElement('cal:transparent'); + break; + case self::OPAQUE : + $xval = $doc->createElement('cal:opaque'); + break; + } + + $node->appendChild($xval); + + } + + /** + * Unserializes the DOMElement back into a Property class. + * + * @param \DOMElement $node + * @return ScheduleCalendarTransp + */ + static function unserialize(\DOMElement $node) { + + $value = null; + foreach($node->childNodes as $childNode) { + switch(DAV\XMLUtil::toClarkNotation($childNode)) { + case '{' . CalDAV\Plugin::NS_CALDAV . '}opaque' : + $value = self::OPAQUE; + break; + case '{' . CalDAV\Plugin::NS_CALDAV . '}transparent' : + $value = self::TRANSPARENT; + break; + } + } + if (is_null($value)) + return null; + + return new self($value); + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarComponentSet.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarComponentSet.php new file mode 100644 index 00000000..2538fa45 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarComponentSet.php @@ -0,0 +1,88 @@ +components = $components; + + } + + /** + * Returns the list of supported components + * + * @return array + */ + public function getValue() { + + return $this->components; + + } + + /** + * Serializes the property in a DOMDocument + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + foreach($this->components as $component) { + + $xcomp = $doc->createElement('cal:comp'); + $xcomp->setAttribute('name',$component); + $node->appendChild($xcomp); + + } + + } + + /** + * Unserializes the DOMElement back into a Property class. + * + * @param \DOMElement $node + * @return Property_SupportedCalendarComponentSet + */ + static function unserialize(\DOMElement $node) { + + $components = array(); + foreach($node->childNodes as $childNode) { + if (DAV\XMLUtil::toClarkNotation($childNode)==='{' . CalDAV\Plugin::NS_CALDAV . '}comp') { + $components[] = $childNode->getAttribute('name'); + } + } + return new self($components); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarData.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarData.php new file mode 100644 index 00000000..efab80a9 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCalendarData.php @@ -0,0 +1,40 @@ +ownerDocument; + + $prefix = isset($server->xmlNamespaces[Plugin::NS_CALDAV])?$server->xmlNamespaces[Plugin::NS_CALDAV]:'cal'; + + $caldata = $doc->createElement($prefix . ':calendar-data'); + $caldata->setAttribute('content-type','text/calendar'); + $caldata->setAttribute('version','2.0'); + + $node->appendChild($caldata); + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCollationSet.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCollationSet.php new file mode 100644 index 00000000..63c37fe5 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Property/SupportedCollationSet.php @@ -0,0 +1,45 @@ +ownerDocument; + + $prefix = $node->lookupPrefix('urn:ietf:params:xml:ns:caldav'); + if (!$prefix) $prefix = 'cal'; + + $node->appendChild( + $doc->createElement($prefix . ':supported-collation','i;ascii-casemap') + ); + $node->appendChild( + $doc->createElement($prefix . ':supported-collation','i;octet') + ); + $node->appendChild( + $doc->createElement($prefix . ':supported-collation','i;unicode-casemap') + ); + + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IMip.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IMip.php new file mode 100644 index 00000000..b2b0d98b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IMip.php @@ -0,0 +1,111 @@ +senderEmail = $senderEmail; + + } + + /** + * Sends one or more iTip messages through email. + * + * @param string $originator Originator Email + * @param array $recipients Array of email addresses + * @param VObject\Component $vObject + * @param string $principal Principal Url of the originator + * @return void + */ + public function sendMessage($originator, array $recipients, VObject\Component $vObject, $principal) { + + foreach($recipients as $recipient) { + + $to = $recipient; + $replyTo = $originator; + $subject = 'SabreDAV iTIP message'; + + switch(strtoupper($vObject->METHOD)) { + case 'REPLY' : + $subject = 'Response for: ' . $vObject->VEVENT->SUMMARY; + break; + case 'REQUEST' : + $subject = 'Invitation for: ' .$vObject->VEVENT->SUMMARY; + break; + case 'CANCEL' : + $subject = 'Cancelled event: ' . $vObject->VEVENT->SUMMARY; + break; + } + + $headers = array(); + $headers[] = 'Reply-To: ' . $replyTo; + $headers[] = 'From: ' . $this->senderEmail; + $headers[] = 'Content-Type: text/calendar; method=' . (string)$vObject->method . '; charset=utf-8'; + if (DAV\Server::$exposeVersion) { + $headers[] = 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY; + } + + $vcalBody = $vObject->serialize(); + + $this->mail($to, $subject, $vcalBody, $headers); + + } + + } + + // @codeCoverageIgnoreStart + // This is deemed untestable in a reasonable manner + + /** + * This function is reponsible for sending the actual email. + * + * @param string $to Recipient email address + * @param string $subject Subject of the email + * @param string $body iCalendar body + * @param array $headers List of headers + * @return void + */ + protected function mail($to, $subject, $body, array $headers) { + + + mail($to, $subject, $body, implode("\r\n", $headers)); + + } + + // @codeCoverageIgnoreEnd + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IOutbox.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IOutbox.php new file mode 100644 index 00000000..7341eaa8 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Schedule/IOutbox.php @@ -0,0 +1,16 @@ +principalUri = $principalUri; + + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + public function getName() { + + return 'outbox'; + + } + + /** + * Returns an array with all the child nodes + * + * @return \Sabre\DAV\INode[] + */ + public function getChildren() { + + return array(); + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalUri; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy', + 'principal' => $this->getOwner(), + 'protected' => true, + ), + array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent', + 'principal' => $this->getOwner(), + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->getOwner(), + 'protected' => true, + ), + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('You\'re not allowed to update the ACL'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + $default = DAVACL\Plugin::getDefaultSupportedPrivilegeSet(); + $default['aggregates'][] = array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy', + ); + $default['aggregates'][] = array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent', + ); + + return $default; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ShareableCalendar.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ShareableCalendar.php new file mode 100644 index 00000000..cabf7eb9 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/ShareableCalendar.php @@ -0,0 +1,72 @@ +caldavBackend->updateShares($this->calendarInfo['id'], $add, $remove); + + } + + /** + * Returns the list of people whom this calendar is shared with. + * + * Every element in this array should have the following properties: + * * href - Often a mailto: address + * * commonName - Optional, for example a first + last name + * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. + * * readOnly - boolean + * * summary - Optional, a description for the share + * + * @return array + */ + public function getShares() { + + return $this->caldavBackend->getShares($this->calendarInfo['id']); + + } + + /** + * Marks this calendar as published. + * + * Publishing a calendar should automatically create a read-only, public, + * subscribable calendar. + * + * @param bool $value + * @return void + */ + public function setPublishStatus($value) { + + $this->caldavBackend->setPublishStatus($this->calendarInfo['id'], $value); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharedCalendar.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharedCalendar.php new file mode 100644 index 00000000..79eda43a --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharedCalendar.php @@ -0,0 +1,116 @@ +calendarInfo['{http://calendarserver.org/ns/}shared-url']; + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->calendarInfo['{http://sabredav.org/ns}owner-principal']; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + // The top-level ACL only contains access information for the true + // owner of the calendar, so we need to add the information for the + // sharee. + $acl = parent::getACL(); + $acl[] = array( + 'privilege' => '{DAV:}read', + 'principal' => $this->calendarInfo['principaluri'], + 'protected' => true, + ); + if (!$this->calendarInfo['{http://sabredav.org/ns}read-only']) { + $acl[] = array( + 'privilege' => '{DAV:}write', + 'principal' => $this->calendarInfo['principaluri'], + 'protected' => true, + ); + } + return $acl; + + } + + /** + * Returns the list of people whom this calendar is shared with. + * + * Every element in this array should have the following properties: + * * href - Often a mailto: address + * * commonName - Optional, for example a first + last name + * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. + * * readOnly - boolean + * * summary - Optional, a description for the share + * + * @return array + */ + public function getShares() { + + return $this->caldavBackend->getShares($this->calendarInfo['id']); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharingPlugin.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharingPlugin.php new file mode 100644 index 00000000..e869cb27 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/SharingPlugin.php @@ -0,0 +1,526 @@ +server = $server; + $server->resourceTypeMapping['Sabre\\CalDAV\\ISharedCalendar'] = '{' . Plugin::NS_CALENDARSERVER . '}shared'; + + array_push( + $this->server->protectedProperties, + '{' . Plugin::NS_CALENDARSERVER . '}invite', + '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', + '{' . Plugin::NS_CALENDARSERVER . '}shared-url' + ); + + $this->server->subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties')); + $this->server->subscribeEvent('afterGetProperties', array($this, 'afterGetProperties')); + $this->server->subscribeEvent('updateProperties', array($this, 'updateProperties')); + $this->server->subscribeEvent('unknownMethod', array($this,'unknownMethod')); + + } + + /** + * This event is triggered when properties are requested for a certain + * node. + * + * This allows us to inject any properties early. + * + * @param string $path + * @param DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @return void + */ + public function beforeGetProperties($path, DAV\INode $node, &$requestedProperties, &$returnedProperties) { + + if ($node instanceof IShareableCalendar) { + if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}invite', $requestedProperties))!==false) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}invite'] = + new Property\Invite( + $node->getShares() + ); + + } + + } + + if ($node instanceof ISharedCalendar) { + + if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}shared-url', $requestedProperties))!==false) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}shared-url'] = + new DAV\Property\Href( + $node->getSharedUrl() + ); + + } + // The 'invite' property is slightly different for the 'shared' + // instance of the calendar, as it also contains the owner + // information. + if (($index = array_search('{' . Plugin::NS_CALENDARSERVER . '}invite', $requestedProperties))!==false) { + + unset($requestedProperties[$index]); + + // Fetching owner information + $props = $this->server->getPropertiesForPath($node->getOwner(), array( + '{http://sabredav.org/ns}email-address', + '{DAV:}displayname', + ), 1); + + $ownerInfo = array( + 'href' => $node->getOwner(), + ); + + if (isset($props[0][200])) { + + // We're mapping the internal webdav properties to the + // elements caldav-sharing expects. + if (isset($props[0][200]['{http://sabredav.org/ns}email-address'])) { + $ownerInfo['href'] = 'mailto:' . $props[0][200]['{http://sabredav.org/ns}email-address']; + } + if (isset($props[0][200]['{DAV:}displayname'])) { + $ownerInfo['commonName'] = $props[0][200]['{DAV:}displayname']; + } + + } + + $returnedProperties[200]['{' . Plugin::NS_CALENDARSERVER . '}invite'] = + new Property\Invite( + $node->getShares(), + $ownerInfo + ); + + } + + + } + + } + + /** + * This method is triggered *after* all properties have been retrieved. + * This allows us to inject the correct resourcetype for calendars that + * have been shared. + * + * @param string $path + * @param array $properties + * @param DAV\INode $node + * @return void + */ + public function afterGetProperties($path, &$properties, DAV\INode $node) { + + if ($node instanceof IShareableCalendar) { + if (isset($properties[200]['{DAV:}resourcetype'])) { + if (count($node->getShares())>0) { + $properties[200]['{DAV:}resourcetype']->add( + '{' . Plugin::NS_CALENDARSERVER . '}shared-owner' + ); + } + } + $propName = '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes'; + if (array_key_exists($propName, $properties[404])) { + unset($properties[404][$propName]); + $properties[200][$propName] = new Property\AllowedSharingModes(true,false); + } + + } + + } + + /** + * This method is trigged when a user attempts to update a node's + * properties. + * + * A previous draft of the sharing spec stated that it was possible to use + * PROPPATCH to remove 'shared-owner' from the resourcetype, thus unsharing + * the calendar. + * + * Even though this is no longer in the current spec, we keep this around + * because OS X 10.7 may still make use of this feature. + * + * @param array $mutations + * @param array $result + * @param DAV\INode $node + * @return void + */ + public function updateProperties(array &$mutations, array &$result, DAV\INode $node) { + + if (!$node instanceof IShareableCalendar) + return; + + if (!isset($mutations['{DAV:}resourcetype'])) { + return; + } + + // Only doing something if shared-owner is indeed not in the list. + if($mutations['{DAV:}resourcetype']->is('{' . Plugin::NS_CALENDARSERVER . '}shared-owner')) return; + + $shares = $node->getShares(); + $remove = array(); + foreach($shares as $share) { + $remove[] = $share['href']; + } + $node->updateShares(array(), $remove); + + // We're marking this update as 200 OK + $result[200]['{DAV:}resourcetype'] = null; + + // Removing it from the mutations list + unset($mutations['{DAV:}resourcetype']); + + } + + /** + * This event is triggered when the server didn't know how to handle a + * certain request. + * + * We intercept this to handle POST requests on calendars. + * + * @param string $method + * @param string $uri + * @return null|bool + */ + public function unknownMethod($method, $uri) { + + if ($method!=='POST') { + return; + } + + // Only handling xml + $contentType = $this->server->httpRequest->getHeader('Content-Type'); + if (strpos($contentType,'application/xml')===false && strpos($contentType,'text/xml')===false) + return; + + // Making sure the node exists + try { + $node = $this->server->tree->getNodeForPath($uri); + } catch (DAV\Exception\NotFound $e) { + return; + } + + $requestBody = $this->server->httpRequest->getBody(true); + + // If this request handler could not deal with this POST request, it + // will return 'null' and other plugins get a chance to handle the + // request. + // + // However, we already requested the full body. This is a problem, + // because a body can only be read once. This is why we preemptively + // re-populated the request body with the existing data. + $this->server->httpRequest->setBody($requestBody); + + $dom = DAV\XMLUtil::loadDOMDocument($requestBody); + + $documentType = DAV\XMLUtil::toClarkNotation($dom->firstChild); + + switch($documentType) { + + // Dealing with the 'share' document, which modified invitees on a + // calendar. + case '{' . Plugin::NS_CALENDARSERVER . '}share' : + + // We can only deal with IShareableCalendar objects + if (!$node instanceof IShareableCalendar) { + return; + } + + // Getting ACL info + $acl = $this->server->getPlugin('acl'); + + // If there's no ACL support, we allow everything + if ($acl) { + $acl->checkPrivileges($uri, '{DAV:}write'); + } + + $mutations = $this->parseShareRequest($dom); + + $node->updateShares($mutations[0], $mutations[1]); + + $this->server->httpResponse->sendStatus(200); + // Adding this because sending a response body may cause issues, + // and I wanted some type of indicator the response was handled. + $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); + + // Breaking the event chain + return false; + + // The invite-reply document is sent when the user replies to an + // invitation of a calendar share. + case '{'. Plugin::NS_CALENDARSERVER.'}invite-reply' : + + // This only works on the calendar-home-root node. + if (!$node instanceof UserCalendars) { + return; + } + + // Getting ACL info + $acl = $this->server->getPlugin('acl'); + + // If there's no ACL support, we allow everything + if ($acl) { + $acl->checkPrivileges($uri, '{DAV:}write'); + } + + $message = $this->parseInviteReplyRequest($dom); + + $url = $node->shareReply( + $message['href'], + $message['status'], + $message['calendarUri'], + $message['inReplyTo'], + $message['summary'] + ); + + $this->server->httpResponse->sendStatus(200); + // Adding this because sending a response body may cause issues, + // and I wanted some type of indicator the response was handled. + $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); + + if ($url) { + $dom = new \DOMDocument('1.0', 'UTF-8'); + $dom->formatOutput = true; + + $root = $dom->createElement('cs:shared-as'); + foreach($this->server->xmlNamespaces as $namespace => $prefix) { + $root->setAttribute('xmlns:' . $prefix, $namespace); + } + + $dom->appendChild($root); + $href = new DAV\Property\Href($url); + + $href->serialize($this->server, $root); + $this->server->httpResponse->setHeader('Content-Type','application/xml'); + $this->server->httpResponse->sendBody($dom->saveXML()); + + } + + // Breaking the event chain + return false; + + case '{' . Plugin::NS_CALENDARSERVER . '}publish-calendar' : + + // We can only deal with IShareableCalendar objects + if (!$node instanceof IShareableCalendar) { + return; + } + + // Getting ACL info + $acl = $this->server->getPlugin('acl'); + + // If there's no ACL support, we allow everything + if ($acl) { + $acl->checkPrivileges($uri, '{DAV:}write'); + } + + $node->setPublishStatus(true); + + // iCloud sends back the 202, so we will too. + $this->server->httpResponse->sendStatus(202); + + // Adding this because sending a response body may cause issues, + // and I wanted some type of indicator the response was handled. + $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); + + // Breaking the event chain + return false; + + case '{' . Plugin::NS_CALENDARSERVER . '}unpublish-calendar' : + + // We can only deal with IShareableCalendar objects + if (!$node instanceof IShareableCalendar) { + return; + } + + // Getting ACL info + $acl = $this->server->getPlugin('acl'); + + // If there's no ACL support, we allow everything + if ($acl) { + $acl->checkPrivileges($uri, '{DAV:}write'); + } + + $node->setPublishStatus(false); + + $this->server->httpResponse->sendStatus(200); + + // Adding this because sending a response body may cause issues, + // and I wanted some type of indicator the response was handled. + $this->server->httpResponse->setHeader('X-Sabre-Status', 'everything-went-well'); + + // Breaking the event chain + return false; + + } + + + + } + + /** + * Parses the 'share' POST request. + * + * This method returns an array, containing two arrays. + * The first array is a list of new sharees. Every element is a struct + * containing a: + * * href element. (usually a mailto: address) + * * commonName element (often a first and lastname, but can also be + * false) + * * readOnly (true or false) + * * summary (A description of the share, can also be false) + * + * The second array is a list of sharees that are to be removed. This is + * just a simple array with 'hrefs'. + * + * @param \DOMDocument $dom + * @return array + */ + protected function parseShareRequest(\DOMDocument $dom) { + + $xpath = new \DOMXPath($dom); + $xpath->registerNamespace('cs', Plugin::NS_CALENDARSERVER); + $xpath->registerNamespace('d', 'urn:DAV'); + + $set = array(); + $elems = $xpath->query('cs:set'); + + for($i=0; $i < $elems->length; $i++) { + + $xset = $elems->item($i); + $set[] = array( + 'href' => $xpath->evaluate('string(d:href)', $xset), + 'commonName' => $xpath->evaluate('string(cs:common-name)', $xset), + 'summary' => $xpath->evaluate('string(cs:summary)', $xset), + 'readOnly' => $xpath->evaluate('boolean(cs:read)', $xset)!==false + ); + + } + + $remove = array(); + $elems = $xpath->query('cs:remove'); + + for($i=0; $i < $elems->length; $i++) { + + $xremove = $elems->item($i); + $remove[] = $xpath->evaluate('string(d:href)', $xremove); + + } + + return array($set, $remove); + + } + + /** + * Parses the 'invite-reply' POST request. + * + * This method returns an array, containing the following properties: + * * href - The sharee who is replying + * * status - One of the self::STATUS_* constants + * * calendarUri - The url of the shared calendar + * * inReplyTo - The unique id of the share invitation. + * * summary - Optional description of the reply. + * + * @param \DOMDocument $dom + * @return array + */ + protected function parseInviteReplyRequest(\DOMDocument $dom) { + + $xpath = new \DOMXPath($dom); + $xpath->registerNamespace('cs', Plugin::NS_CALENDARSERVER); + $xpath->registerNamespace('d', 'urn:DAV'); + + $hostHref = $xpath->evaluate('string(cs:hosturl/d:href)'); + if (!$hostHref) { + throw new DAV\Exception\BadRequest('The {' . Plugin::NS_CALENDARSERVER . '}hosturl/{DAV:}href element is required'); + } + + return array( + 'href' => $xpath->evaluate('string(d:href)'), + 'calendarUri' => $this->server->calculateUri($hostHref), + 'inReplyTo' => $xpath->evaluate('string(cs:in-reply-to)'), + 'summary' => $xpath->evaluate('string(cs:summary)'), + 'status' => $xpath->evaluate('boolean(cs:invite-accepted)')?self::STATUS_ACCEPTED:self::STATUS_DECLINED + ); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/UserCalendars.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/UserCalendars.php new file mode 100644 index 00000000..6e700eb0 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/UserCalendars.php @@ -0,0 +1,342 @@ +caldavBackend = $caldavBackend; + $this->principalInfo = $principalInfo; + + } + + /** + * Returns the name of this object + * + * @return string + */ + public function getName() { + + list(,$name) = DAV\URLUtil::splitPath($this->principalInfo['uri']); + return $name; + + } + + /** + * Updates the name of this object + * + * @param string $name + * @return void + */ + public function setName($name) { + + throw new DAV\Exception\Forbidden(); + + } + + /** + * Deletes this object + * + * @return void + */ + public function delete() { + + throw new DAV\Exception\Forbidden(); + + } + + /** + * Returns the last modification date + * + * @return int + */ + public function getLastModified() { + + return null; + + } + + /** + * Creates a new file under this object. + * + * This is currently not allowed + * + * @param string $filename + * @param resource $data + * @return void + */ + public function createFile($filename, $data=null) { + + throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported'); + + } + + /** + * Creates a new directory under this object. + * + * This is currently not allowed. + * + * @param string $filename + * @return void + */ + public function createDirectory($filename) { + + throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported'); + + } + + /** + * Returns a single calendar, by name + * + * @param string $name + * @todo needs optimizing + * @return Calendar + */ + public function getChild($name) { + + foreach($this->getChildren() as $child) { + if ($name==$child->getName()) + return $child; + + } + throw new DAV\Exception\NotFound('Calendar with name \'' . $name . '\' could not be found'); + + } + + /** + * Checks if a calendar exists. + * + * @param string $name + * @todo needs optimizing + * @return bool + */ + public function childExists($name) { + + foreach($this->getChildren() as $child) { + if ($name==$child->getName()) + return true; + + } + return false; + + } + + /** + * Returns a list of calendars + * + * @return array + */ + public function getChildren() { + + $calendars = $this->caldavBackend->getCalendarsForUser($this->principalInfo['uri']); + $objs = array(); + foreach($calendars as $calendar) { + if ($this->caldavBackend instanceof Backend\SharingSupport) { + if (isset($calendar['{http://calendarserver.org/ns/}shared-url'])) { + $objs[] = new SharedCalendar($this->caldavBackend, $calendar); + } else { + $objs[] = new ShareableCalendar($this->caldavBackend, $calendar); + } + } else { + $objs[] = new Calendar($this->caldavBackend, $calendar); + } + } + $objs[] = new Schedule\Outbox($this->principalInfo['uri']); + + // We're adding a notifications node, if it's supported by the backend. + if ($this->caldavBackend instanceof Backend\NotificationSupport) { + $objs[] = new Notifications\Collection($this->caldavBackend, $this->principalInfo['uri']); + } + return $objs; + + } + + /** + * Creates a new calendar + * + * @param string $name + * @param array $resourceType + * @param array $properties + * @return void + */ + public function createExtendedCollection($name, array $resourceType, array $properties) { + + $isCalendar = false; + foreach($resourceType as $rt) { + switch ($rt) { + case '{DAV:}collection' : + case '{http://calendarserver.org/ns/}shared-owner' : + // ignore + break; + case '{urn:ietf:params:xml:ns:caldav}calendar' : + $isCalendar = true; + break; + default : + throw new DAV\Exception\InvalidResourceType('Unknown resourceType: ' . $rt); + } + } + if (!$isCalendar) { + throw new DAV\Exception\InvalidResourceType('You can only create calendars in this collection'); + } + $this->caldavBackend->createCalendar($this->principalInfo['uri'], $name, $properties); + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalInfo['uri']; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalInfo['uri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->principalInfo['uri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalInfo['uri'] . '/calendar-proxy-read', + 'protected' => true, + ), + + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + + /** + * This method is called when a user replied to a request to share. + * + * This method should return the url of the newly created calendar if the + * share was accepted. + * + * @param string href The sharee who is replying (often a mailto: address) + * @param int status One of the SharingPlugin::STATUS_* constants + * @param string $calendarUri The url to the calendar thats being shared + * @param string $inReplyTo The unique id this message is a response to + * @param string $summary A description of the reply + * @return null|string + */ + public function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) { + + if (!$this->caldavBackend instanceof Backend\SharingSupport) { + throw new DAV\Exception\NotImplemented('Sharing support is not implemented by this backend.'); + } + + return $this->caldavBackend->shareReply($href, $status, $calendarUri, $inReplyTo, $summary); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Version.php b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Version.php new file mode 100644 index 00000000..f30fc20e --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CalDAV/Version.php @@ -0,0 +1,24 @@ +carddavBackend = $carddavBackend; + $this->addressBookInfo = $addressBookInfo; + + } + + /** + * Returns the name of the addressbook + * + * @return string + */ + public function getName() { + + return $this->addressBookInfo['uri']; + + } + + /** + * Returns a card + * + * @param string $name + * @return \ICard + */ + public function getChild($name) { + + $obj = $this->carddavBackend->getCard($this->addressBookInfo['id'],$name); + if (!$obj) throw new DAV\Exception\NotFound('Card not found'); + return new Card($this->carddavBackend,$this->addressBookInfo,$obj); + + } + + /** + * Returns the full list of cards + * + * @return array + */ + public function getChildren() { + + $objs = $this->carddavBackend->getCards($this->addressBookInfo['id']); + $children = array(); + foreach($objs as $obj) { + $children[] = new Card($this->carddavBackend,$this->addressBookInfo,$obj); + } + return $children; + + } + + /** + * Creates a new directory + * + * We actually block this, as subdirectories are not allowed in addressbooks. + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + throw new DAV\Exception\MethodNotAllowed('Creating collections in addressbooks is not allowed'); + + } + + /** + * Creates a new file + * + * The contents of the new file must be a valid VCARD. + * + * This method may return an ETag. + * + * @param string $name + * @param resource $vcardData + * @return string|null + */ + public function createFile($name,$vcardData = null) { + + if (is_resource($vcardData)) { + $vcardData = stream_get_contents($vcardData); + } + // Converting to UTF-8, if needed + $vcardData = DAV\StringUtil::ensureUTF8($vcardData); + + return $this->carddavBackend->createCard($this->addressBookInfo['id'],$name,$vcardData); + + } + + /** + * Deletes the entire addressbook. + * + * @return void + */ + public function delete() { + + $this->carddavBackend->deleteAddressBook($this->addressBookInfo['id']); + + } + + /** + * Renames the addressbook + * + * @param string $newName + * @return void + */ + public function setName($newName) { + + throw new DAV\Exception\MethodNotAllowed('Renaming addressbooks is not yet supported'); + + } + + /** + * Returns the last modification date as a unix timestamp. + * + * @return void + */ + public function getLastModified() { + + return null; + + } + + /** + * Updates properties on this node, + * + * The properties array uses the propertyName in clark-notation as key, + * and the array value for the property value. In the case a property + * should be deleted, the property value will be null. + * + * This method must be atomic. If one property cannot be changed, the + * entire operation must fail. + * + * If the operation was successful, true can be returned. + * If the operation failed, false can be returned. + * + * Deletion of a non-existent property is always successful. + * + * Lastly, it is optional to return detailed information about any + * failures. In this case an array should be returned with the following + * structure: + * + * array( + * 403 => array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param array $mutations + * @return bool|array + */ + public function updateProperties($mutations) { + + return $this->carddavBackend->updateAddressBook($this->addressBookInfo['id'], $mutations); + + } + + /** + * Returns a list of properties for this nodes. + * + * The properties list is a list of propertynames the client requested, + * encoded in clark-notation {xmlnamespace}tagname + * + * If the array is empty, it means 'all properties' were requested. + * + * @param array $properties + * @return array + */ + public function getProperties($properties) { + + $response = array(); + foreach($properties as $propertyName) { + + if (isset($this->addressBookInfo[$propertyName])) { + + $response[$propertyName] = $this->addressBookInfo[$propertyName]; + + } + + } + + return $response; + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->addressBookInfo['principaluri']; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->addressBookInfo['principaluri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->addressBookInfo['principaluri'], + 'protected' => true, + ), + + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookQueryParser.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookQueryParser.php new file mode 100644 index 00000000..3277d98b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookQueryParser.php @@ -0,0 +1,221 @@ +dom = $dom; + + $this->xpath = new \DOMXPath($dom); + $this->xpath->registerNameSpace('card',Plugin::NS_CARDDAV); + + } + + /** + * Parses the request. + * + * @return void + */ + public function parse() { + + $filterNode = null; + + $limit = $this->xpath->evaluate('number(/card:addressbook-query/card:limit/card:nresults)'); + if (is_nan($limit)) $limit = null; + + $filter = $this->xpath->query('/card:addressbook-query/card:filter'); + + // According to the CardDAV spec there needs to be exactly 1 filter + // element. However, KDE 4.8.2 contains a bug that will encode 0 filter + // elements, so this is a workaround for that. + // + // See: https://bugs.kde.org/show_bug.cgi?id=300047 + if ($filter->length === 0) { + $test = null; + $filter = null; + } elseif ($filter->length === 1) { + $filter = $filter->item(0); + $test = $this->xpath->evaluate('string(@test)', $filter); + } else { + throw new DAV\Exception\BadRequest('Only one filter element is allowed'); + } + + if (!$test) $test = self::TEST_ANYOF; + if ($test !== self::TEST_ANYOF && $test !== self::TEST_ALLOF) { + throw new DAV\Exception\BadRequest('The test attribute must either hold "anyof" or "allof"'); + } + + $propFilters = array(); + + $propFilterNodes = $this->xpath->query('card:prop-filter', $filter); + for($ii=0; $ii < $propFilterNodes->length; $ii++) { + + $propFilters[] = $this->parsePropFilterNode($propFilterNodes->item($ii)); + + + } + + $this->filters = $propFilters; + $this->limit = $limit; + $this->requestedProperties = array_keys(DAV\XMLUtil::parseProperties($this->dom->firstChild)); + $this->test = $test; + + } + + /** + * Parses the prop-filter xml element + * + * @param \DOMElement $propFilterNode + * @return array + */ + protected function parsePropFilterNode(\DOMElement $propFilterNode) { + + $propFilter = array(); + $propFilter['name'] = $propFilterNode->getAttribute('name'); + $propFilter['test'] = $propFilterNode->getAttribute('test'); + if (!$propFilter['test']) $propFilter['test'] = 'anyof'; + + $propFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $propFilterNode)->length>0; + + $paramFilterNodes = $this->xpath->query('card:param-filter', $propFilterNode); + + $propFilter['param-filters'] = array(); + + + for($ii=0;$ii<$paramFilterNodes->length;$ii++) { + + $propFilter['param-filters'][] = $this->parseParamFilterNode($paramFilterNodes->item($ii)); + + } + $propFilter['text-matches'] = array(); + $textMatchNodes = $this->xpath->query('card:text-match', $propFilterNode); + + for($ii=0;$ii<$textMatchNodes->length;$ii++) { + + $propFilter['text-matches'][] = $this->parseTextMatchNode($textMatchNodes->item($ii)); + + } + + return $propFilter; + + } + + /** + * Parses the param-filter element + * + * @param \DOMElement $paramFilterNode + * @return array + */ + public function parseParamFilterNode(\DOMElement $paramFilterNode) { + + $paramFilter = array(); + $paramFilter['name'] = $paramFilterNode->getAttribute('name'); + $paramFilter['is-not-defined'] = $this->xpath->query('card:is-not-defined', $paramFilterNode)->length>0; + $paramFilter['text-match'] = null; + + $textMatch = $this->xpath->query('card:text-match', $paramFilterNode); + if ($textMatch->length>0) { + $paramFilter['text-match'] = $this->parseTextMatchNode($textMatch->item(0)); + } + + return $paramFilter; + + } + + /** + * Text match + * + * @param \DOMElement $textMatchNode + * @return array + */ + public function parseTextMatchNode(\DOMElement $textMatchNode) { + + $matchType = $textMatchNode->getAttribute('match-type'); + if (!$matchType) $matchType = 'contains'; + + if (!in_array($matchType, array('contains', 'equals', 'starts-with', 'ends-with'))) { + throw new DAV\Exception\BadRequest('Unknown match-type: ' . $matchType); + } + + $negateCondition = $textMatchNode->getAttribute('negate-condition'); + $negateCondition = $negateCondition==='yes'; + $collation = $textMatchNode->getAttribute('collation'); + if (!$collation) $collation = 'i;unicode-casemap'; + + return array( + 'negate-condition' => $negateCondition, + 'collation' => $collation, + 'match-type' => $matchType, + 'value' => $textMatchNode->nodeValue + ); + + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookRoot.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookRoot.php new file mode 100644 index 00000000..789abbc5 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/AddressBookRoot.php @@ -0,0 +1,80 @@ +carddavBackend = $carddavBackend; + parent::__construct($principalBackend, $principalPrefix); + + } + + /** + * Returns the name of the node + * + * @return string + */ + public function getName() { + + return Plugin::ADDRESSBOOK_ROOT; + + } + + /** + * This method returns a node for a principal. + * + * The passed array contains principal information, and is guaranteed to + * at least contain a uri item. Other properties may or may not be + * supplied by the authentication backend. + * + * @param array $principal + * @return \Sabre\DAV\INode + */ + public function getChildForPrincipal(array $principal) { + + return new UserAddressBooks($this->carddavBackend, $principal['uri']); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Backend/AbstractBackend.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Backend/AbstractBackend.php new file mode 100644 index 00000000..46909efe --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Backend/AbstractBackend.php @@ -0,0 +1,18 @@ +pdo = $pdo; + $this->addressBooksTableName = $addressBooksTableName; + $this->cardsTableName = $cardsTableName; + + } + + /** + * Returns the list of addressbooks for a specific user. + * + * @param string $principalUri + * @return array + */ + public function getAddressBooksForUser($principalUri) { + + $stmt = $this->pdo->prepare('SELECT id, uri, displayname, principaluri, description, ctag FROM '.$this->addressBooksTableName.' WHERE principaluri = ?'); + $stmt->execute(array($principalUri)); + + $addressBooks = array(); + + foreach($stmt->fetchAll() as $row) { + + $addressBooks[] = array( + 'id' => $row['id'], + 'uri' => $row['uri'], + 'principaluri' => $row['principaluri'], + '{DAV:}displayname' => $row['displayname'], + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => $row['description'], + '{http://calendarserver.org/ns/}getctag' => $row['ctag'], + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => + new CardDAV\Property\SupportedAddressData(), + ); + + } + + return $addressBooks; + + } + + + /** + * Updates an addressbook's properties + * + * See Sabre\DAV\IProperties for a description of the mutations array, as + * well as the return value. + * + * @param mixed $addressBookId + * @param array $mutations + * @see Sabre\DAV\IProperties::updateProperties + * @return bool|array + */ + public function updateAddressBook($addressBookId, array $mutations) { + + $updates = array(); + + foreach($mutations as $property=>$newValue) { + + switch($property) { + case '{DAV:}displayname' : + $updates['displayname'] = $newValue; + break; + case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' : + $updates['description'] = $newValue; + break; + default : + // If any unsupported values were being updated, we must + // let the entire request fail. + return false; + } + + } + + // No values are being updated? + if (!$updates) { + return false; + } + + $query = 'UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 '; + foreach($updates as $key=>$value) { + $query.=', `' . $key . '` = :' . $key . ' '; + } + $query.=' WHERE id = :addressbookid'; + + $stmt = $this->pdo->prepare($query); + $updates['addressbookid'] = $addressBookId; + + $stmt->execute($updates); + + return true; + + } + + /** + * Creates a new address book + * + * @param string $principalUri + * @param string $url Just the 'basename' of the url. + * @param array $properties + * @return void + */ + public function createAddressBook($principalUri, $url, array $properties) { + + $values = array( + 'displayname' => null, + 'description' => null, + 'principaluri' => $principalUri, + 'uri' => $url, + ); + + foreach($properties as $property=>$newValue) { + + switch($property) { + case '{DAV:}displayname' : + $values['displayname'] = $newValue; + break; + case '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' : + $values['description'] = $newValue; + break; + default : + throw new DAV\Exception\BadRequest('Unknown property: ' . $property); + } + + } + + $query = 'INSERT INTO ' . $this->addressBooksTableName . ' (uri, displayname, description, principaluri, ctag) VALUES (:uri, :displayname, :description, :principaluri, 1)'; + $stmt = $this->pdo->prepare($query); + $stmt->execute($values); + + } + + /** + * Deletes an entire addressbook and all its contents + * + * @param int $addressBookId + * @return void + */ + public function deleteAddressBook($addressBookId) { + + $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?'); + $stmt->execute(array($addressBookId)); + + $stmt = $this->pdo->prepare('DELETE FROM ' . $this->addressBooksTableName . ' WHERE id = ?'); + $stmt->execute(array($addressBookId)); + + } + + /** + * Returns all cards for a specific addressbook id. + * + * This method should return the following properties for each card: + * * carddata - raw vcard data + * * uri - Some unique url + * * lastmodified - A unix timestamp + * + * It's recommended to also return the following properties: + * * etag - A unique etag. This must change every time the card changes. + * * size - The size of the card in bytes. + * + * If these last two properties are provided, less time will be spent + * calculating them. If they are specified, you can also ommit carddata. + * This may speed up certain requests, especially with large cards. + * + * @param mixed $addressbookId + * @return array + */ + public function getCards($addressbookId) { + + $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ?'); + $stmt->execute(array($addressbookId)); + + return $stmt->fetchAll(\PDO::FETCH_ASSOC); + + + } + + /** + * Returns a specfic card. + * + * The same set of properties must be returned as with getCards. The only + * exception is that 'carddata' is absolutely required. + * + * @param mixed $addressBookId + * @param string $cardUri + * @return array + */ + public function getCard($addressBookId, $cardUri) { + + $stmt = $this->pdo->prepare('SELECT id, carddata, uri, lastmodified FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ? LIMIT 1'); + $stmt->execute(array($addressBookId, $cardUri)); + + $result = $stmt->fetchAll(\PDO::FETCH_ASSOC); + + return (count($result)>0?$result[0]:false); + + } + + /** + * Creates a new card. + * + * The addressbook id will be passed as the first argument. This is the + * same id as it is returned from the getAddressbooksForUser method. + * + * The cardUri is a base uri, and doesn't include the full path. The + * cardData argument is the vcard body, and is passed as a string. + * + * It is possible to return an ETag from this method. This ETag is for the + * newly created resource, and must be enclosed with double quotes (that + * is, the string itself must contain the double quotes). + * + * You should only return the ETag if you store the carddata as-is. If a + * subsequent GET request on the same card does not have the same body, + * byte-by-byte and you did return an ETag here, clients tend to get + * confused. + * + * If you don't return an ETag, you can just return null. + * + * @param mixed $addressBookId + * @param string $cardUri + * @param string $cardData + * @return string|null + */ + public function createCard($addressBookId, $cardUri, $cardData) { + + $stmt = $this->pdo->prepare('INSERT INTO ' . $this->cardsTableName . ' (carddata, uri, lastmodified, addressbookid) VALUES (?, ?, ?, ?)'); + + $result = $stmt->execute(array($cardData, $cardUri, time(), $addressBookId)); + + $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?'); + $stmt2->execute(array($addressBookId)); + + return '"' . md5($cardData) . '"'; + + } + + /** + * Updates a card. + * + * The addressbook id will be passed as the first argument. This is the + * same id as it is returned from the getAddressbooksForUser method. + * + * The cardUri is a base uri, and doesn't include the full path. The + * cardData argument is the vcard body, and is passed as a string. + * + * It is possible to return an ETag from this method. This ETag should + * match that of the updated resource, and must be enclosed with double + * quotes (that is: the string itself must contain the actual quotes). + * + * You should only return the ETag if you store the carddata as-is. If a + * subsequent GET request on the same card does not have the same body, + * byte-by-byte and you did return an ETag here, clients tend to get + * confused. + * + * If you don't return an ETag, you can just return null. + * + * @param mixed $addressBookId + * @param string $cardUri + * @param string $cardData + * @return string|null + */ + public function updateCard($addressBookId, $cardUri, $cardData) { + + $stmt = $this->pdo->prepare('UPDATE ' . $this->cardsTableName . ' SET carddata = ?, lastmodified = ? WHERE uri = ? AND addressbookid =?'); + $stmt->execute(array($cardData, time(), $cardUri, $addressBookId)); + + $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?'); + $stmt2->execute(array($addressBookId)); + + return '"' . md5($cardData) . '"'; + + } + + /** + * Deletes a card + * + * @param mixed $addressBookId + * @param string $cardUri + * @return bool + */ + public function deleteCard($addressBookId, $cardUri) { + + $stmt = $this->pdo->prepare('DELETE FROM ' . $this->cardsTableName . ' WHERE addressbookid = ? AND uri = ?'); + $stmt->execute(array($addressBookId, $cardUri)); + + $stmt2 = $this->pdo->prepare('UPDATE ' . $this->addressBooksTableName . ' SET ctag = ctag + 1 WHERE id = ?'); + $stmt2->execute(array($addressBookId)); + + return $stmt->rowCount()===1; + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Card.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Card.php new file mode 100644 index 00000000..cc65f760 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Card.php @@ -0,0 +1,260 @@ +carddavBackend = $carddavBackend; + $this->addressBookInfo = $addressBookInfo; + $this->cardData = $cardData; + + } + + /** + * Returns the uri for this object + * + * @return string + */ + public function getName() { + + return $this->cardData['uri']; + + } + + /** + * Returns the VCard-formatted object + * + * @return string + */ + public function get() { + + // Pre-populating 'carddata' is optional. If we don't yet have it + // already, we fetch it from the backend. + if (!isset($this->cardData['carddata'])) { + $this->cardData = $this->carddavBackend->getCard($this->addressBookInfo['id'], $this->cardData['uri']); + } + return $this->cardData['carddata']; + + } + + /** + * Updates the VCard-formatted object + * + * @param string $cardData + * @return string|null + */ + public function put($cardData) { + + if (is_resource($cardData)) + $cardData = stream_get_contents($cardData); + + // Converting to UTF-8, if needed + $cardData = DAV\StringUtil::ensureUTF8($cardData); + + $etag = $this->carddavBackend->updateCard($this->addressBookInfo['id'],$this->cardData['uri'],$cardData); + $this->cardData['carddata'] = $cardData; + $this->cardData['etag'] = $etag; + + return $etag; + + } + + /** + * Deletes the card + * + * @return void + */ + public function delete() { + + $this->carddavBackend->deleteCard($this->addressBookInfo['id'],$this->cardData['uri']); + + } + + /** + * Returns the mime content-type + * + * @return string + */ + public function getContentType() { + + return 'text/x-vcard; charset=utf-8'; + + } + + /** + * Returns an ETag for this object + * + * @return string + */ + public function getETag() { + + if (isset($this->cardData['etag'])) { + return $this->cardData['etag']; + } else { + $data = $this->get(); + if (is_string($data)) { + return '"' . md5($data) . '"'; + } else { + // We refuse to calculate the md5 if it's a stream. + return null; + } + } + + } + + /** + * Returns the last modification date as a unix timestamp + * + * @return int + */ + public function getLastModified() { + + return isset($this->cardData['lastmodified'])?$this->cardData['lastmodified']:null; + + } + + /** + * Returns the size of this object in bytes + * + * @return int + */ + public function getSize() { + + if (array_key_exists('size', $this->cardData)) { + return $this->cardData['size']; + } else { + return strlen($this->get()); + } + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->addressBookInfo['principaluri']; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->addressBookInfo['principaluri'], + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->addressBookInfo['principaluri'], + 'protected' => true, + ), + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/IAddressBook.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/IAddressBook.php new file mode 100644 index 00000000..e9e990cb --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/IAddressBook.php @@ -0,0 +1,20 @@ +subscribeEvent('beforeGetProperties', array($this, 'beforeGetProperties')); + $server->subscribeEvent('afterGetProperties', array($this, 'afterGetProperties')); + $server->subscribeEvent('updateProperties', array($this, 'updateProperties')); + $server->subscribeEvent('report', array($this,'report')); + $server->subscribeEvent('onHTMLActionsPanel', array($this,'htmlActionsPanel')); + $server->subscribeEvent('onBrowserPostAction', array($this,'browserPostAction')); + $server->subscribeEvent('beforeWriteContent', array($this, 'beforeWriteContent')); + $server->subscribeEvent('beforeCreateFile', array($this, 'beforeCreateFile')); + + /* Namespaces */ + $server->xmlNamespaces[self::NS_CARDDAV] = 'card'; + + /* Mapping Interfaces to {DAV:}resourcetype values */ + $server->resourceTypeMapping['Sabre\\CardDAV\\IAddressBook'] = '{' . self::NS_CARDDAV . '}addressbook'; + $server->resourceTypeMapping['Sabre\\CardDAV\\IDirectory'] = '{' . self::NS_CARDDAV . '}directory'; + + /* Adding properties that may never be changed */ + $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-address-data'; + $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}max-resource-size'; + $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}addressbook-home-set'; + $server->protectedProperties[] = '{' . self::NS_CARDDAV . '}supported-collation-set'; + + $server->propertyMap['{http://calendarserver.org/ns/}me-card'] = 'Sabre\\DAV\\Property\\Href'; + + $this->server = $server; + + } + + /** + * Returns a list of supported features. + * + * This is used in the DAV: header in the OPTIONS and PROPFIND requests. + * + * @return array + */ + public function getFeatures() { + + return array('addressbook'); + + } + + /** + * Returns a list of reports this plugin supports. + * + * This will be used in the {DAV:}supported-report-set property. + * Note that you still need to subscribe to the 'report' event to actually + * implement them + * + * @param string $uri + * @return array + */ + public function getSupportedReportSet($uri) { + + $node = $this->server->tree->getNodeForPath($uri); + if ($node instanceof IAddressBook || $node instanceof ICard) { + return array( + '{' . self::NS_CARDDAV . '}addressbook-multiget', + '{' . self::NS_CARDDAV . '}addressbook-query', + ); + } + return array(); + + } + + + /** + * Adds all CardDAV-specific properties + * + * @param string $path + * @param DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @return void + */ + public function beforeGetProperties($path, DAV\INode $node, array &$requestedProperties, array &$returnedProperties) { + + if ($node instanceof DAVACL\IPrincipal) { + + // calendar-home-set property + $addHome = '{' . self::NS_CARDDAV . '}addressbook-home-set'; + if (in_array($addHome,$requestedProperties)) { + $principalId = $node->getName(); + $addressbookHomePath = self::ADDRESSBOOK_ROOT . '/' . $principalId . '/'; + unset($requestedProperties[array_search($addHome, $requestedProperties)]); + $returnedProperties[200][$addHome] = new DAV\Property\Href($addressbookHomePath); + } + + $directories = '{' . self::NS_CARDDAV . '}directory-gateway'; + if ($this->directories && in_array($directories, $requestedProperties)) { + unset($requestedProperties[array_search($directories, $requestedProperties)]); + $returnedProperties[200][$directories] = new DAV\Property\HrefList($this->directories); + } + + } + + if ($node instanceof ICard) { + + // The address-data property is not supposed to be a 'real' + // property, but in large chunks of the spec it does act as such. + // Therefore we simply expose it as a property. + $addressDataProp = '{' . self::NS_CARDDAV . '}address-data'; + if (in_array($addressDataProp, $requestedProperties)) { + unset($requestedProperties[$addressDataProp]); + $val = $node->get(); + if (is_resource($val)) + $val = stream_get_contents($val); + + $returnedProperties[200][$addressDataProp] = $val; + + } + } + + if ($node instanceof UserAddressBooks) { + + $meCardProp = '{http://calendarserver.org/ns/}me-card'; + if (in_array($meCardProp, $requestedProperties)) { + + $props = $this->server->getProperties($node->getOwner(), array('{http://sabredav.org/ns}vcard-url')); + if (isset($props['{http://sabredav.org/ns}vcard-url'])) { + + $returnedProperties[200][$meCardProp] = new DAV\Property\Href( + $props['{http://sabredav.org/ns}vcard-url'] + ); + $pos = array_search($meCardProp, $requestedProperties); + unset($requestedProperties[$pos]); + + } + + } + + } + + } + + /** + * This event is triggered when a PROPPATCH method is executed + * + * @param array $mutations + * @param array $result + * @param DAV\INode $node + * @return bool + */ + public function updateProperties(&$mutations, &$result, DAV\INode $node) { + + if (!$node instanceof UserAddressBooks) { + return true; + } + + $meCard = '{http://calendarserver.org/ns/}me-card'; + + // The only property we care about + if (!isset($mutations[$meCard])) + return true; + + $value = $mutations[$meCard]; + unset($mutations[$meCard]); + + if ($value instanceof DAV\Property\IHref) { + $value = $value->getHref(); + $value = $this->server->calculateUri($value); + } elseif (!is_null($value)) { + $result[400][$meCard] = null; + return false; + } + + $innerResult = $this->server->updateProperties( + $node->getOwner(), + array( + '{http://sabredav.org/ns}vcard-url' => $value, + ) + ); + + $closureResult = false; + foreach($innerResult as $status => $props) { + if (is_array($props) && array_key_exists('{http://sabredav.org/ns}vcard-url', $props)) { + $result[$status][$meCard] = null; + $closureResult = ($status>=200 && $status<300); + } + + } + + return $result; + + } + + /** + * This functions handles REPORT requests specific to CardDAV + * + * @param string $reportName + * @param \DOMNode $dom + * @return bool + */ + public function report($reportName,$dom) { + + switch($reportName) { + case '{'.self::NS_CARDDAV.'}addressbook-multiget' : + $this->addressbookMultiGetReport($dom); + return false; + case '{'.self::NS_CARDDAV.'}addressbook-query' : + $this->addressBookQueryReport($dom); + return false; + default : + return; + + } + + + } + + /** + * This function handles the addressbook-multiget REPORT. + * + * This report is used by the client to fetch the content of a series + * of urls. Effectively avoiding a lot of redundant requests. + * + * @param \DOMNode $dom + * @return void + */ + public function addressbookMultiGetReport($dom) { + + $properties = array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)); + + $hrefElems = $dom->getElementsByTagNameNS('urn:DAV','href'); + $propertyList = array(); + + foreach($hrefElems as $elem) { + + $uri = $this->server->calculateUri($elem->nodeValue); + list($propertyList[]) = $this->server->getPropertiesForPath($uri,$properties); + + } + + $prefer = $this->server->getHTTPPRefer(); + + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($propertyList, $prefer['return-minimal'])); + + } + + /** + * This method is triggered before a file gets updated with new content. + * + * This plugin uses this method to ensure that Card nodes receive valid + * vcard data. + * + * @param string $path + * @param DAV\IFile $node + * @param resource $data + * @return void + */ + public function beforeWriteContent($path, DAV\IFile $node, &$data) { + + if (!$node instanceof ICard) + return; + + $this->validateVCard($data); + + } + + /** + * This method is triggered before a new file is created. + * + * This plugin uses this method to ensure that Card nodes receive valid + * vcard data. + * + * @param string $path + * @param resource $data + * @param DAV\ICollection $parentNode + * @return void + */ + public function beforeCreateFile($path, &$data, DAV\ICollection $parentNode) { + + if (!$parentNode instanceof IAddressBook) + return; + + $this->validateVCard($data); + + } + + /** + * Checks if the submitted iCalendar data is in fact, valid. + * + * An exception is thrown if it's not. + * + * @param resource|string $data + * @return void + */ + protected function validateVCard(&$data) { + + // If it's a stream, we convert it to a string first. + if (is_resource($data)) { + $data = stream_get_contents($data); + } + + // Converting the data to unicode, if needed. + $data = DAV\StringUtil::ensureUTF8($data); + + try { + + $vobj = VObject\Reader::read($data); + + } catch (VObject\ParseException $e) { + + throw new DAV\Exception\UnsupportedMediaType('This resource only supports valid vcard data. Parse error: ' . $e->getMessage()); + + } + + if ($vobj->name !== 'VCARD') { + throw new DAV\Exception\UnsupportedMediaType('This collection can only support vcard objects.'); + } + + if (!isset($vobj->UID)) { + // No UID in vcards is invalid, but we'll just add it in anyway. + $vobj->add('UID', DAV\UUIDUtil::getUUID()); + $data = $vobj->serialize(); + } + + } + + + /** + * This function handles the addressbook-query REPORT + * + * This report is used by the client to filter an addressbook based on a + * complex query. + * + * @param \DOMNode $dom + * @return void + */ + protected function addressbookQueryReport($dom) { + + $query = new AddressBookQueryParser($dom); + $query->parse(); + + $depth = $this->server->getHTTPDepth(0); + + if ($depth==0) { + $candidateNodes = array( + $this->server->tree->getNodeForPath($this->server->getRequestUri()) + ); + } else { + $candidateNodes = $this->server->tree->getChildren($this->server->getRequestUri()); + } + + $validNodes = array(); + foreach($candidateNodes as $node) { + + if (!$node instanceof ICard) + continue; + + $blob = $node->get(); + if (is_resource($blob)) { + $blob = stream_get_contents($blob); + } + + if (!$this->validateFilters($blob, $query->filters, $query->test)) { + continue; + } + + $validNodes[] = $node; + + if ($query->limit && $query->limit <= count($validNodes)) { + // We hit the maximum number of items, we can stop now. + break; + } + + } + + $result = array(); + foreach($validNodes as $validNode) { + + if ($depth==0) { + $href = $this->server->getRequestUri(); + } else { + $href = $this->server->getRequestUri() . '/' . $validNode->getName(); + } + + list($result[]) = $this->server->getPropertiesForPath($href, $query->requestedProperties, 0); + + } + + $prefer = $this->server->getHTTPPRefer(); + + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal'])); + + } + + /** + * Validates if a vcard makes it throught a list of filters. + * + * @param string $vcardData + * @param array $filters + * @param string $test anyof or allof (which means OR or AND) + * @return bool + */ + public function validateFilters($vcardData, array $filters, $test) { + + $vcard = VObject\Reader::read($vcardData); + + if (!$filters) return true; + + foreach($filters as $filter) { + + $isDefined = isset($vcard->{$filter['name']}); + if ($filter['is-not-defined']) { + if ($isDefined) { + $success = false; + } else { + $success = true; + } + } elseif ((!$filter['param-filters'] && !$filter['text-matches']) || !$isDefined) { + + // We only need to check for existence + $success = $isDefined; + + } else { + + $vProperties = $vcard->select($filter['name']); + + $results = array(); + if ($filter['param-filters']) { + $results[] = $this->validateParamFilters($vProperties, $filter['param-filters'], $filter['test']); + } + if ($filter['text-matches']) { + $texts = array(); + foreach($vProperties as $vProperty) + $texts[] = $vProperty->getValue(); + + $results[] = $this->validateTextMatches($texts, $filter['text-matches'], $filter['test']); + } + + if (count($results)===1) { + $success = $results[0]; + } else { + if ($filter['test'] === 'anyof') { + $success = $results[0] || $results[1]; + } else { + $success = $results[0] && $results[1]; + } + } + + } // else + + // There are two conditions where we can already determine whether + // or not this filter succeeds. + if ($test==='anyof' && $success) { + return true; + } + if ($test==='allof' && !$success) { + return false; + } + + } // foreach + + // If we got all the way here, it means we haven't been able to + // determine early if the test failed or not. + // + // This implies for 'anyof' that the test failed, and for 'allof' that + // we succeeded. Sounds weird, but makes sense. + return $test==='allof'; + + } + + /** + * Validates if a param-filter can be applied to a specific property. + * + * @todo currently we're only validating the first parameter of the passed + * property. Any subsequence parameters with the same name are + * ignored. + * @param array $vProperties + * @param array $filters + * @param string $test + * @return bool + */ + protected function validateParamFilters(array $vProperties, array $filters, $test) { + + foreach($filters as $filter) { + + $isDefined = false; + foreach($vProperties as $vProperty) { + $isDefined = isset($vProperty[$filter['name']]); + if ($isDefined) break; + } + + if ($filter['is-not-defined']) { + if ($isDefined) { + $success = false; + } else { + $success = true; + } + + // If there's no text-match, we can just check for existence + } elseif (!$filter['text-match'] || !$isDefined) { + + $success = $isDefined; + + } else { + + $success = false; + foreach($vProperties as $vProperty) { + // If we got all the way here, we'll need to validate the + // text-match filter. + $success = DAV\StringUtil::textMatch($vProperty[$filter['name']]->getValue(), $filter['text-match']['value'], $filter['text-match']['collation'], $filter['text-match']['match-type']); + if ($success) break; + } + if ($filter['text-match']['negate-condition']) { + $success = !$success; + } + + } // else + + // There are two conditions where we can already determine whether + // or not this filter succeeds. + if ($test==='anyof' && $success) { + return true; + } + if ($test==='allof' && !$success) { + return false; + } + + } + + // If we got all the way here, it means we haven't been able to + // determine early if the test failed or not. + // + // This implies for 'anyof' that the test failed, and for 'allof' that + // we succeeded. Sounds weird, but makes sense. + return $test==='allof'; + + } + + /** + * Validates if a text-filter can be applied to a specific property. + * + * @param array $texts + * @param array $filters + * @param string $test + * @return bool + */ + protected function validateTextMatches(array $texts, array $filters, $test) { + + foreach($filters as $filter) { + + $success = false; + foreach($texts as $haystack) { + $success = DAV\StringUtil::textMatch($haystack, $filter['value'], $filter['collation'], $filter['match-type']); + + // Breaking on the first match + if ($success) break; + } + if ($filter['negate-condition']) { + $success = !$success; + } + + if ($success && $test==='anyof') + return true; + + if (!$success && $test=='allof') + return false; + + + } + + // If we got all the way here, it means we haven't been able to + // determine early if the test failed or not. + // + // This implies for 'anyof' that the test failed, and for 'allof' that + // we succeeded. Sounds weird, but makes sense. + return $test==='allof'; + + } + + /** + * This event is triggered after webdav-properties have been retrieved. + * + * @return bool + */ + public function afterGetProperties($uri, &$properties) { + + // If the request was made using the SOGO connector, we must rewrite + // the content-type property. By default SabreDAV will send back + // text/x-vcard; charset=utf-8, but for SOGO we must strip that last + // part. + if (!isset($properties[200]['{DAV:}getcontenttype'])) + return; + + if (strpos($this->server->httpRequest->getHeader('User-Agent'),'Thunderbird')===false) { + return; + } + + if (strpos($properties[200]['{DAV:}getcontenttype'],'text/x-vcard')===0) { + $properties[200]['{DAV:}getcontenttype'] = 'text/x-vcard'; + } + + } + + /** + * This method is used to generate HTML output for the + * Sabre\DAV\Browser\Plugin. This allows us to generate an interface users + * can use to create new calendars. + * + * @param DAV\INode $node + * @param string $output + * @return bool + */ + public function htmlActionsPanel(DAV\INode $node, &$output) { + + if (!$node instanceof UserAddressBooks) + return; + + $output.= '
    +

    Create new address book

    + +
    +
    + +
    + '; + + return false; + + } + + /** + * This method allows us to intercept the 'mkcalendar' sabreAction. This + * action enables the user to create new calendars from the browser plugin. + * + * @param string $uri + * @param string $action + * @param array $postVars + * @return bool + */ + public function browserPostAction($uri, $action, array $postVars) { + + if ($action!=='mkaddressbook') + return; + + $resourceType = array('{DAV:}collection','{urn:ietf:params:xml:ns:carddav}addressbook'); + $properties = array(); + if (isset($postVars['{DAV:}displayname'])) { + $properties['{DAV:}displayname'] = $postVars['{DAV:}displayname']; + } + $this->server->createCollection($uri . '/' . $postVars['name'],$resourceType,$properties); + return false; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Property/SupportedAddressData.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Property/SupportedAddressData.php new file mode 100644 index 00000000..9d8dd2e6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Property/SupportedAddressData.php @@ -0,0 +1,72 @@ + 'text/vcard', 'version' => '3.0'), + // array('contentType' => 'text/vcard', 'version' => '4.0'), + ); + } + + $this->supportedData = $supportedData; + + } + + /** + * Serializes the property in a DOMDocument + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + + $prefix = + isset($server->xmlNamespaces[CardDAV\Plugin::NS_CARDDAV]) ? + $server->xmlNamespaces[CardDAV\Plugin::NS_CARDDAV] : + 'card'; + + foreach($this->supportedData as $supported) { + + $caldata = $doc->createElementNS(CardDAV\Plugin::NS_CARDDAV, $prefix . ':address-data-type'); + $caldata->setAttribute('content-type',$supported['contentType']); + $caldata->setAttribute('version',$supported['version']); + $node->appendChild($caldata); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/UserAddressBooks.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/UserAddressBooks.php new file mode 100644 index 00000000..b4af8614 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/UserAddressBooks.php @@ -0,0 +1,260 @@ +carddavBackend = $carddavBackend; + $this->principalUri = $principalUri; + + } + + /** + * Returns the name of this object + * + * @return string + */ + public function getName() { + + list(,$name) = DAV\URLUtil::splitPath($this->principalUri); + return $name; + + } + + /** + * Updates the name of this object + * + * @param string $name + * @return void + */ + public function setName($name) { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + /** + * Deletes this object + * + * @return void + */ + public function delete() { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + /** + * Returns the last modification date + * + * @return int + */ + public function getLastModified() { + + return null; + + } + + /** + * Creates a new file under this object. + * + * This is currently not allowed + * + * @param string $filename + * @param resource $data + * @return void + */ + public function createFile($filename, $data=null) { + + throw new DAV\Exception\MethodNotAllowed('Creating new files in this collection is not supported'); + + } + + /** + * Creates a new directory under this object. + * + * This is currently not allowed. + * + * @param string $filename + * @return void + */ + public function createDirectory($filename) { + + throw new DAV\Exception\MethodNotAllowed('Creating new collections in this collection is not supported'); + + } + + /** + * Returns a single calendar, by name + * + * @param string $name + * @todo needs optimizing + * @return \AddressBook + */ + public function getChild($name) { + + foreach($this->getChildren() as $child) { + if ($name==$child->getName()) + return $child; + + } + throw new DAV\Exception\NotFound('Addressbook with name \'' . $name . '\' could not be found'); + + } + + /** + * Returns a list of addressbooks + * + * @return array + */ + public function getChildren() { + + $addressbooks = $this->carddavBackend->getAddressbooksForUser($this->principalUri); + $objs = array(); + foreach($addressbooks as $addressbook) { + $objs[] = new AddressBook($this->carddavBackend, $addressbook); + } + return $objs; + + } + + /** + * Creates a new addressbook + * + * @param string $name + * @param array $resourceType + * @param array $properties + * @return void + */ + public function createExtendedCollection($name, array $resourceType, array $properties) { + + if (!in_array('{'.Plugin::NS_CARDDAV.'}addressbook',$resourceType) || count($resourceType)!==2) { + throw new DAV\Exception\InvalidResourceType('Unknown resourceType for this collection'); + } + $this->carddavBackend->createAddressBook($this->principalUri, $name, $properties); + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalUri; + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalUri, + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->principalUri, + 'protected' => true, + ), + + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Changing ACL is not yet supported'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/VCFExportPlugin.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/VCFExportPlugin.php new file mode 100644 index 00000000..3f91a301 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/VCFExportPlugin.php @@ -0,0 +1,108 @@ +server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90); + + } + + /** + * 'beforeMethod' event handles. This event handles intercepts GET requests ending + * with ?export + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + if ($method!='GET') return; + if ($this->server->httpRequest->getQueryString()!='export') return; + + // splitting uri + list($uri) = explode('?',$uri,2); + + $node = $this->server->tree->getNodeForPath($uri); + + if (!($node instanceof IAddressBook)) return; + + // Checking ACL, if available. + if ($aclPlugin = $this->server->getPlugin('acl')) { + $aclPlugin->checkPrivileges($uri, '{DAV:}read'); + } + + $this->server->httpResponse->setHeader('Content-Type','text/directory'); + $this->server->httpResponse->sendStatus(200); + + $nodes = $this->server->getPropertiesForPath($uri, array( + '{' . Plugin::NS_CARDDAV . '}address-data', + ),1); + + $this->server->httpResponse->sendBody($this->generateVCF($nodes)); + + // Returning false to break the event chain + return false; + + } + + /** + * Merges all vcard objects, and builds one big vcf export + * + * @param array $nodes + * @return string + */ + public function generateVCF(array $nodes) { + + $output = ""; + + foreach($nodes as $node) { + + if (!isset($node[200]['{' . Plugin::NS_CARDDAV . '}address-data'])) { + continue; + } + $nodeData = $node[200]['{' . Plugin::NS_CARDDAV . '}address-data']; + + // Parsing this node so VObject can clean up the output. + $output .= + VObject\Reader::read($nodeData)->serialize(); + + } + + return $output; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Version.php b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Version.php new file mode 100644 index 00000000..00221941 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/CardDAV/Version.php @@ -0,0 +1,26 @@ +currentUser; + } + + + /** + * Authenticates the user based on the current request. + * + * If authentication is successful, true must be returned. + * If authentication fails, an exception must be thrown. + * + * @param DAV\Server $server + * @param string $realm + * @throws DAV\Exception\NotAuthenticated + * @return bool + */ + public function authenticate(DAV\Server $server, $realm) { + + $auth = new HTTP\BasicAuth(); + $auth->setHTTPRequest($server->httpRequest); + $auth->setHTTPResponse($server->httpResponse); + $auth->setRealm($realm); + $userpass = $auth->getUserPass(); + if (!$userpass) { + $auth->requireLogin(); + throw new DAV\Exception\NotAuthenticated('No basic authentication headers were found'); + } + + // Authenticates the user + if (!$this->validateUserPass($userpass[0],$userpass[1])) { + $auth->requireLogin(); + throw new DAV\Exception\NotAuthenticated('Username or password does not match'); + } + $this->currentUser = $userpass[0]; + return true; + } + + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/AbstractDigest.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/AbstractDigest.php new file mode 100644 index 00000000..dc00438c --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/AbstractDigest.php @@ -0,0 +1,101 @@ +setHTTPRequest($server->httpRequest); + $digest->setHTTPResponse($server->httpResponse); + + $digest->setRealm($realm); + $digest->init(); + + $username = $digest->getUsername(); + + // No username was given + if (!$username) { + $digest->requireLogin(); + throw new DAV\Exception\NotAuthenticated('No digest authentication headers were found'); + } + + $hash = $this->getDigestHash($realm, $username); + // If this was false, the user account didn't exist + if ($hash===false || is_null($hash)) { + $digest->requireLogin(); + throw new DAV\Exception\NotAuthenticated('The supplied username was not on file'); + } + if (!is_string($hash)) { + throw new DAV\Exception('The returned value from getDigestHash must be a string or null'); + } + + // If this was false, the password or part of the hash was incorrect. + if (!$digest->validateA1($hash)) { + $digest->requireLogin(); + throw new DAV\Exception\NotAuthenticated('Incorrect username'); + } + + $this->currentUser = $username; + return true; + + } + + /** + * Returns the currently logged in username. + * + * @return string|null + */ + public function getCurrentUser() { + + return $this->currentUser; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/Apache.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/Apache.php new file mode 100644 index 00000000..66fdd91e --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/Apache.php @@ -0,0 +1,63 @@ +httpRequest->getRawServerValue('REMOTE_USER'); + if (is_null($remoteUser)) { + throw new DAV\Exception('We did not receive the $_SERVER[REMOTE_USER] property. This means that apache might have been misconfigured'); + } + + $this->remoteUser = $remoteUser; + return true; + + } + + /** + * Returns information about the currently logged in user. + * + * If nobody is currently logged in, this method should return null. + * + * @return array|null + */ + public function getCurrentUser() { + + return $this->remoteUser; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/BackendInterface.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/BackendInterface.php new file mode 100644 index 00000000..b8d04e2e --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/BackendInterface.php @@ -0,0 +1,36 @@ +loadFile($filename); + + } + + /** + * Loads an htdigest-formatted file. This method can be called multiple times if + * more than 1 file is used. + * + * @param string $filename + * @return void + */ + public function loadFile($filename) { + + foreach(file($filename,FILE_IGNORE_NEW_LINES) as $line) { + + if (substr_count($line, ":") !== 2) + throw new DAV\Exception('Malformed htdigest file. Every line should contain 2 colons'); + + list($username,$realm,$A1) = explode(':',$line); + + if (!preg_match('/^[a-zA-Z0-9]{32}$/', $A1)) + throw new DAV\Exception('Malformed htdigest file. Invalid md5 hash'); + + $this->users[$realm . ':' . $username] = $A1; + + } + + } + + /** + * Returns a users' information + * + * @param string $realm + * @param string $username + * @return string + */ + public function getDigestHash($realm, $username) { + + return isset($this->users[$realm . ':' . $username])?$this->users[$realm . ':' . $username]:false; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/PDO.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/PDO.php new file mode 100644 index 00000000..f153d842 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Backend/PDO.php @@ -0,0 +1,65 @@ +pdo = $pdo; + $this->tableName = $tableName; + + } + + /** + * Returns the digest hash for a user. + * + * @param string $realm + * @param string $username + * @return string|null + */ + public function getDigestHash($realm,$username) { + + $stmt = $this->pdo->prepare('SELECT username, digesta1 FROM '.$this->tableName.' WHERE username = ?'); + $stmt->execute(array($username)); + $result = $stmt->fetchAll(); + + if (!count($result)) return; + + return $result[0]['digesta1']; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Plugin.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Plugin.php new file mode 100644 index 00000000..dbebc20f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Auth/Plugin.php @@ -0,0 +1,112 @@ +authBackend = $authBackend; + $this->realm = $realm; + + } + + /** + * Initializes the plugin. This function is automatically called by the server + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),10); + + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using DAV\Server::getPlugin + * + * @return string + */ + public function getPluginName() { + + return 'auth'; + + } + + /** + * Returns the current users' principal uri. + * + * If nobody is logged in, this will return null. + * + * @return string|null + */ + public function getCurrentUser() { + + $userInfo = $this->authBackend->getCurrentUser(); + if (!$userInfo) return null; + + return $userInfo; + + } + + /** + * This method is called before any HTTP method and forces users to be authenticated + * + * @param string $method + * @param string $uri + * @throws Sabre\DAV\Exception\NotAuthenticated + * @return bool + */ + public function beforeMethod($method, $uri) { + + $this->authBackend->authenticate($this->server,$this->realm); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/GuessContentType.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/GuessContentType.php new file mode 100644 index 00000000..9fd47b93 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/GuessContentType.php @@ -0,0 +1,99 @@ + 'image/jpeg', + 'gif' => 'image/gif', + 'png' => 'image/png', + + // groupware + 'ics' => 'text/calendar', + 'vcf' => 'text/x-vcard', + + // text + 'txt' => 'text/plain', + + ); + + /** + * Initializes the plugin + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + // Using a relatively low priority (200) to allow other extensions + // to set the content-type first. + $server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties'),200); + + } + + /** + * Handler for teh afterGetProperties event + * + * @param string $path + * @param array $properties + * @return void + */ + public function afterGetProperties($path, &$properties) { + + if (array_key_exists('{DAV:}getcontenttype', $properties[404])) { + + list(, $fileName) = DAV\URLUtil::splitPath($path); + $contentType = $this->getContentType($fileName); + + if ($contentType) { + $properties[200]['{DAV:}getcontenttype'] = $contentType; + unset($properties[404]['{DAV:}getcontenttype']); + } + + } + + } + + /** + * Simple method to return the contenttype + * + * @param string $fileName + * @return string + */ + protected function getContentType($fileName) { + + // Just grabbing the extension + $extension = strtolower(substr($fileName,strrpos($fileName,'.')+1)); + if (isset($this->extensionMap[$extension])) + return $this->extensionMap[$extension]; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/MapGetToPropFind.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/MapGetToPropFind.php new file mode 100644 index 00000000..881c063b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/MapGetToPropFind.php @@ -0,0 +1,57 @@ +server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor')); + } + + /** + * This method intercepts GET requests to non-files, and changes it into an HTTP PROPFIND request + * + * @param string $method + * @param string $uri + * @return bool + */ + public function httpGetInterceptor($method, $uri) { + + if ($method!='GET') return true; + + $node = $this->server->tree->getNodeForPath($uri); + if ($node instanceof DAV\IFile) return; + + $this->server->invokeMethod('PROPFIND',$uri); + return false; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/Plugin.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/Plugin.php new file mode 100644 index 00000000..751c2296 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/Plugin.php @@ -0,0 +1,491 @@ + 'icons/file', + 'Sabre\\DAV\\ICollection' => 'icons/collection', + 'Sabre\\DAVACL\\IPrincipal' => 'icons/principal', + 'Sabre\\CalDAV\\ICalendar' => 'icons/calendar', + 'Sabre\\CardDAV\\IAddressBook' => 'icons/addressbook', + 'Sabre\\CardDAV\\ICard' => 'icons/card', + ); + + /** + * The file extension used for all icons + * + * @var string + */ + public $iconExtension = '.png'; + + /** + * reference to server class + * + * @var Sabre\DAV\Server + */ + protected $server; + + /** + * enablePost turns on the 'actions' panel, which allows people to create + * folders and upload files straight from a browser. + * + * @var bool + */ + protected $enablePost = true; + + /** + * By default the browser plugin will generate a favicon and other images. + * To turn this off, set this property to false. + * + * @var bool + */ + protected $enableAssets = true; + + /** + * Creates the object. + * + * By default it will allow file creation and uploads. + * Specify the first argument as false to disable this + * + * @param bool $enablePost + * @param bool $enableAssets + */ + public function __construct($enablePost=true, $enableAssets = true) { + + $this->enablePost = $enablePost; + $this->enableAssets = $enableAssets; + + } + + /** + * Initializes the plugin and subscribes to events + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'httpGetInterceptor')); + $this->server->subscribeEvent('onHTMLActionsPanel', array($this, 'htmlActionsPanel'),200); + if ($this->enablePost) $this->server->subscribeEvent('unknownMethod',array($this,'httpPOSTHandler')); + } + + /** + * This method intercepts GET requests to collections and returns the html + * + * @param string $method + * @param string $uri + * @return bool + */ + public function httpGetInterceptor($method, $uri) { + + if ($method !== 'GET') return true; + + // We're not using straight-up $_GET, because we want everything to be + // unit testable. + $getVars = array(); + parse_str($this->server->httpRequest->getQueryString(), $getVars); + + if (isset($getVars['sabreAction']) && $getVars['sabreAction'] === 'asset' && isset($getVars['assetName'])) { + $this->serveAsset($getVars['assetName']); + return false; + } + + try { + $node = $this->server->tree->getNodeForPath($uri); + } catch (DAV\Exception\NotFound $e) { + // We're simply stopping when the file isn't found to not interfere + // with other plugins. + return; + } + if ($node instanceof DAV\IFile) + return; + + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','text/html; charset=utf-8'); + + $this->server->httpResponse->sendBody( + $this->generateDirectoryIndex($uri) + ); + + return false; + + } + + /** + * Handles POST requests for tree operations. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function httpPOSTHandler($method, $uri) { + + if ($method!='POST') return; + $contentType = $this->server->httpRequest->getHeader('Content-Type'); + list($contentType) = explode(';', $contentType); + if ($contentType !== 'application/x-www-form-urlencoded' && + $contentType !== 'multipart/form-data') { + return; + } + $postVars = $this->server->httpRequest->getPostVars(); + + if (!isset($postVars['sabreAction'])) + return; + + if ($this->server->broadcastEvent('onBrowserPostAction', array($uri, $postVars['sabreAction'], $postVars))) { + + switch($postVars['sabreAction']) { + + case 'mkcol' : + if (isset($postVars['name']) && trim($postVars['name'])) { + // Using basename() because we won't allow slashes + list(, $folderName) = DAV\URLUtil::splitPath(trim($postVars['name'])); + $this->server->createDirectory($uri . '/' . $folderName); + } + break; + case 'put' : + if ($_FILES) $file = current($_FILES); + else break; + + list(, $newName) = DAV\URLUtil::splitPath(trim($file['name'])); + if (isset($postVars['name']) && trim($postVars['name'])) + $newName = trim($postVars['name']); + + // Making sure we only have a 'basename' component + list(, $newName) = DAV\URLUtil::splitPath($newName); + + if (is_uploaded_file($file['tmp_name'])) { + $this->server->createFile($uri . '/' . $newName, fopen($file['tmp_name'],'r')); + } + break; + + } + + } + $this->server->httpResponse->setHeader('Location',$this->server->httpRequest->getUri()); + $this->server->httpResponse->sendStatus(302); + return false; + + } + + /** + * Escapes a string for html. + * + * @param string $value + * @return string + */ + public function escapeHTML($value) { + + return htmlspecialchars($value,ENT_QUOTES,'UTF-8'); + + } + + /** + * Generates the html directory index for a given url + * + * @param string $path + * @return string + */ + public function generateDirectoryIndex($path) { + + $version = ''; + if (DAV\Server::$exposeVersion) { + $version = DAV\Version::VERSION ."-". DAV\Version::STABILITY; + } + + $html = " + + Index for " . $this->escapeHTML($path) . "/ - SabreDAV " . $version . " + + "; + + if ($this->enableAssets) { + $html.=''; + } + + $html .= " + +

    Index for " . $this->escapeHTML($path) . "/

    + + + "; + + $files = $this->server->getPropertiesForPath($path,array( + '{DAV:}displayname', + '{DAV:}resourcetype', + '{DAV:}getcontenttype', + '{DAV:}getcontentlength', + '{DAV:}getlastmodified', + ),1); + + $parent = $this->server->tree->getNodeForPath($path); + + + if ($path) { + + list($parentUri) = DAV\URLUtil::splitPath($path); + $fullPath = DAV\URLUtil::encodePath($this->server->getBaseUri() . $parentUri); + + $icon = $this->enableAssets?'Parent':''; + $html.= " + + + + + + "; + + } + + foreach($files as $file) { + + // This is the current directory, we can skip it + if (rtrim($file['href'],'/')==$path) continue; + + list(, $name) = DAV\URLUtil::splitPath($file['href']); + + $type = null; + + + if (isset($file[200]['{DAV:}resourcetype'])) { + $type = $file[200]['{DAV:}resourcetype']->getValue(); + + // resourcetype can have multiple values + if (!is_array($type)) $type = array($type); + + foreach($type as $k=>$v) { + + // Some name mapping is preferred + switch($v) { + case '{DAV:}collection' : + $type[$k] = 'Collection'; + break; + case '{DAV:}principal' : + $type[$k] = 'Principal'; + break; + case '{urn:ietf:params:xml:ns:carddav}addressbook' : + $type[$k] = 'Addressbook'; + break; + case '{urn:ietf:params:xml:ns:caldav}calendar' : + $type[$k] = 'Calendar'; + break; + case '{urn:ietf:params:xml:ns:caldav}schedule-inbox' : + $type[$k] = 'Schedule Inbox'; + break; + case '{urn:ietf:params:xml:ns:caldav}schedule-outbox' : + $type[$k] = 'Schedule Outbox'; + break; + case '{http://calendarserver.org/ns/}calendar-proxy-read' : + $type[$k] = 'Proxy-Read'; + break; + case '{http://calendarserver.org/ns/}calendar-proxy-write' : + $type[$k] = 'Proxy-Write'; + break; + } + + } + $type = implode(', ', $type); + } + + // If no resourcetype was found, we attempt to use + // the contenttype property + if (!$type && isset($file[200]['{DAV:}getcontenttype'])) { + $type = $file[200]['{DAV:}getcontenttype']; + } + if (!$type) $type = 'Unknown'; + + $size = isset($file[200]['{DAV:}getcontentlength'])?(int)$file[200]['{DAV:}getcontentlength']:''; + $lastmodified = isset($file[200]['{DAV:}getlastmodified'])?$file[200]['{DAV:}getlastmodified']->getTime()->format(\DateTime::ATOM):''; + + $fullPath = DAV\URLUtil::encodePath('/' . trim($this->server->getBaseUri() . ($path?$path . '/':'') . $name,'/')); + + $displayName = isset($file[200]['{DAV:}displayname'])?$file[200]['{DAV:}displayname']:$name; + + $displayName = $this->escapeHTML($displayName); + $type = $this->escapeHTML($type); + + $icon = ''; + + if ($this->enableAssets) { + $node = $this->server->tree->getNodeForPath(($path?$path.'/':'') . $name); + foreach(array_reverse($this->iconMap) as $class=>$iconName) { + + if ($node instanceof $class) { + $icon = ''; + break; + } + + + } + + } + + $html.= " + + + + + + "; + + } + + $html.= ""; + + $output = ''; + + if ($this->enablePost) { + $this->server->broadcastEvent('onHTMLActionsPanel',array($parent, &$output)); + } + + $html.=$output; + + $html.= "
    NameTypeSizeLast modified

    $icon..[parent]
    $icon{$displayName}{$type}{$size}{$lastmodified}

    +
    Generated by SabreDAV " . $version . " (c)2007-2014 http://sabre.io/
    + + "; + + return $html; + + } + + /** + * This method is used to generate the 'actions panel' output for + * collections. + * + * This specifically generates the interfaces for creating new files, and + * creating new directories. + * + * @param DAV\INode $node + * @param mixed $output + * @return void + */ + public function htmlActionsPanel(DAV\INode $node, &$output) { + + if (!$node instanceof DAV\ICollection) + return; + + // We also know fairly certain that if an object is a non-extended + // SimpleCollection, we won't need to show the panel either. + if (get_class($node)==='Sabre\\DAV\\SimpleCollection') + return; + + $output.= '
    +

    Create new folder

    + + Name:
    + +
    +
    +

    Upload file

    + + Name (optional):
    + File:
    + +
    + '; + + } + + /** + * This method takes a path/name of an asset and turns it into url + * suiteable for http access. + * + * @param string $assetName + * @return string + */ + protected function getAssetUrl($assetName) { + + return $this->server->getBaseUri() . '?sabreAction=asset&assetName=' . urlencode($assetName); + + } + + /** + * This method returns a local pathname to an asset. + * + * @param string $assetName + * @return string + */ + protected function getLocalAssetPath($assetName) { + + $assetDir = __DIR__ . '/assets/'; + $path = $assetDir . $assetName; + + // Making sure people aren't trying to escape from the base path. + if (strpos(realpath($path), realpath($assetDir)) === 0) { + return $path; + } + throw new DAV\Exception\Forbidden('Path does not exist, or escaping from the base path was detected'); + } + + /** + * This method reads an asset from disk and generates a full http response. + * + * @param string $assetName + * @return void + */ + protected function serveAsset($assetName) { + + $assetPath = $this->getLocalAssetPath($assetName); + if (!file_exists($assetPath)) { + throw new DAV\Exception\NotFound('Could not find an asset with this name'); + } + // Rudimentary mime type detection + switch(strtolower(substr($assetPath,strpos($assetPath,'.')+1))) { + + case 'ico' : + $mime = 'image/vnd.microsoft.icon'; + break; + + case 'png' : + $mime = 'image/png'; + break; + + default: + $mime = 'application/octet-stream'; + break; + + } + + $this->server->httpResponse->setHeader('Content-Type', $mime); + $this->server->httpResponse->setHeader('Content-Length', filesize($assetPath)); + $this->server->httpResponse->setHeader('Cache-Control', 'public, max-age=1209600'); + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->sendBody(fopen($assetPath,'r')); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/addressbook.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/addressbook.png new file mode 100644 index 00000000..c9acc841 Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/addressbook.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/calendar.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/calendar.png new file mode 100644 index 00000000..3ecd6a80 Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/calendar.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/card.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/card.png new file mode 100644 index 00000000..2ce95486 Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/card.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/collection.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/collection.png new file mode 100644 index 00000000..156fa64f Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/collection.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/file.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/file.png new file mode 100644 index 00000000..3b98551c Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/file.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/parent.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/parent.png new file mode 100644 index 00000000..156fa64f Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/parent.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/principal.png b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/principal.png new file mode 100644 index 00000000..f8988f82 Binary files /dev/null and b/sources/vendor/sabre/dav/lib/Sabre/DAV/Browser/assets/icons/principal.png differ diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Client.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Client.php new file mode 100644 index 00000000..705b3219 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Client.php @@ -0,0 +1,575 @@ +$validSetting = $settings[$validSetting]; + } + } + + if (isset($settings['authType'])) { + $this->authType = $settings['authType']; + } else { + $this->authType = self::AUTH_BASIC | self::AUTH_DIGEST; + } + + $this->propertyMap['{DAV:}resourcetype'] = 'Sabre\\DAV\\Property\\ResourceType'; + + } + + /** + * Add trusted root certificates to the webdav client. + * + * The parameter certificates should be a absolute path to a file + * which contains all trusted certificates + * + * @param string $certificates + */ + public function addTrustedCertificates($certificates) { + $this->trustedCertificates = $certificates; + } + + /** + * Enables/disables SSL peer verification + * + * @param boolean $value + */ + public function setVerifyPeer($value) { + $this->verifyPeer = $value; + } + + /** + * Does a PROPFIND request + * + * The list of requested properties must be specified as an array, in clark + * notation. + * + * The returned array will contain a list of filenames as keys, and + * properties as values. + * + * The properties array will contain the list of properties. Only properties + * that are actually returned from the server (without error) will be + * returned, anything else is discarded. + * + * Depth should be either 0 or 1. A depth of 1 will cause a request to be + * made to the server to also return all child resources. + * + * @param string $url + * @param array $properties + * @param int $depth + * @return array + */ + public function propFind($url, array $properties, $depth = 0) { + + $body = '' . "\n"; + $body.= '' . "\n"; + $body.= ' ' . "\n"; + + foreach($properties as $property) { + + list( + $namespace, + $elementName + ) = XMLUtil::parseClarkNotation($property); + + if ($namespace === 'DAV:') { + $body.=' ' . "\n"; + } else { + $body.=" \n"; + } + + } + + $body.= ' ' . "\n"; + $body.= ''; + + $response = $this->request('PROPFIND', $url, $body, array( + 'Depth' => $depth, + 'Content-Type' => 'application/xml' + )); + + $result = $this->parseMultiStatus($response['body']); + + // If depth was 0, we only return the top item + if ($depth===0) { + reset($result); + $result = current($result); + return isset($result[200])?$result[200]:array(); + } + + $newResult = array(); + foreach($result as $href => $statusList) { + + $newResult[$href] = isset($statusList[200])?$statusList[200]:array(); + + } + + return $newResult; + + } + + /** + * Updates a list of properties on the server + * + * The list of properties must have clark-notation properties for the keys, + * and the actual (string) value for the value. If the value is null, an + * attempt is made to delete the property. + * + * @todo Must be building the request using the DOM, and does not yet + * support complex properties. + * @param string $url + * @param array $properties + * @return void + */ + public function propPatch($url, array $properties) { + + $body = '' . "\n"; + $body.= '' . "\n"; + + foreach($properties as $propName => $propValue) { + + list( + $namespace, + $elementName + ) = XMLUtil::parseClarkNotation($propName); + + if ($propValue === null) { + + $body.="\n"; + + if ($namespace === 'DAV:') { + $body.=' ' . "\n"; + } else { + $body.=" \n"; + } + + $body.="\n"; + + } else { + + $body.="\n"; + if ($namespace === 'DAV:') { + $body.=' '; + } else { + $body.=" "; + } + // Shitty.. i know + $body.=htmlspecialchars($propValue, ENT_NOQUOTES, 'UTF-8'); + if ($namespace === 'DAV:') { + $body.='' . "\n"; + } else { + $body.="\n"; + } + $body.="\n"; + + } + + } + + $body.= ''; + + $this->request('PROPPATCH', $url, $body, array( + 'Content-Type' => 'application/xml' + )); + + } + + /** + * Performs an HTTP options request + * + * This method returns all the features from the 'DAV:' header as an array. + * If there was no DAV header, or no contents this method will return an + * empty array. + * + * @return array + */ + public function options() { + + $result = $this->request('OPTIONS'); + if (!isset($result['headers']['dav'])) { + return array(); + } + + $features = explode(',', $result['headers']['dav']); + foreach($features as &$v) { + $v = trim($v); + } + return $features; + + } + + /** + * Performs an actual HTTP request, and returns the result. + * + * If the specified url is relative, it will be expanded based on the base + * url. + * + * The returned array contains 3 keys: + * * body - the response body + * * httpCode - a HTTP code (200, 404, etc) + * * headers - a list of response http headers. The header names have + * been lowercased. + * + * @param string $method + * @param string $url + * @param string $body + * @param array $headers + * @return array + */ + public function request($method, $url = '', $body = null, $headers = array()) { + + $url = $this->getAbsoluteUrl($url); + + $curlSettings = array( + CURLOPT_RETURNTRANSFER => true, + // Return headers as part of the response + CURLOPT_HEADER => true, + + // For security we cast this to a string. If somehow an array could + // be passed here, it would be possible for an attacker to use @ to + // post local files. + CURLOPT_POSTFIELDS => (string)$body, + // Automatically follow redirects + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + ); + + if($this->verifyPeer !== null) { + $curlSettings[CURLOPT_SSL_VERIFYPEER] = $this->verifyPeer; + } + + if($this->trustedCertificates) { + $curlSettings[CURLOPT_CAINFO] = $this->trustedCertificates; + } + + switch ($method) { + case 'HEAD' : + + // do not read body with HEAD requests (this is necessary because cURL does not ignore the body with HEAD + // requests when the Content-Length header is given - which in turn is perfectly valid according to HTTP + // specs...) cURL does unfortunately return an error in this case ("transfer closed transfer closed with + // ... bytes remaining to read") this can be circumvented by explicitly telling cURL to ignore the + // response body + $curlSettings[CURLOPT_NOBODY] = true; + $curlSettings[CURLOPT_CUSTOMREQUEST] = 'HEAD'; + break; + + default: + $curlSettings[CURLOPT_CUSTOMREQUEST] = $method; + break; + + } + + // Adding HTTP headers + $nHeaders = array(); + foreach($headers as $key=>$value) { + + $nHeaders[] = $key . ': ' . $value; + + } + $curlSettings[CURLOPT_HTTPHEADER] = $nHeaders; + + if ($this->proxy) { + $curlSettings[CURLOPT_PROXY] = $this->proxy; + } + + if ($this->userName && $this->authType) { + $curlType = 0; + if ($this->authType & self::AUTH_BASIC) { + $curlType |= CURLAUTH_BASIC; + } + if ($this->authType & self::AUTH_DIGEST) { + $curlType |= CURLAUTH_DIGEST; + } + $curlSettings[CURLOPT_HTTPAUTH] = $curlType; + $curlSettings[CURLOPT_USERPWD] = $this->userName . ':' . $this->password; + } + + list( + $response, + $curlInfo, + $curlErrNo, + $curlError + ) = $this->curlRequest($url, $curlSettings); + + $headerBlob = substr($response, 0, $curlInfo['header_size']); + $response = substr($response, $curlInfo['header_size']); + + // In the case of 100 Continue, or redirects we'll have multiple lists + // of headers for each separate HTTP response. We can easily split this + // because they are separated by \r\n\r\n + $headerBlob = explode("\r\n\r\n", trim($headerBlob, "\r\n")); + + // We only care about the last set of headers + $headerBlob = $headerBlob[count($headerBlob)-1]; + + // Splitting headers + $headerBlob = explode("\r\n", $headerBlob); + + $headers = array(); + foreach($headerBlob as $header) { + $parts = explode(':', $header, 2); + if (count($parts)==2) { + $headers[strtolower(trim($parts[0]))] = trim($parts[1]); + } + } + + $response = array( + 'body' => $response, + 'statusCode' => $curlInfo['http_code'], + 'headers' => $headers + ); + + if ($curlErrNo) { + throw new Exception('[CURL] Error while making request: ' . $curlError . ' (error code: ' . $curlErrNo . ')'); + } + + if ($response['statusCode']>=400) { + switch ($response['statusCode']) { + case 400 : + throw new Exception\BadRequest('Bad request'); + case 401 : + throw new Exception\NotAuthenticated('Not authenticated'); + case 402 : + throw new Exception\PaymentRequired('Payment required'); + case 403 : + throw new Exception\Forbidden('Forbidden'); + case 404: + throw new Exception\NotFound('Resource not found.'); + case 405 : + throw new Exception\MethodNotAllowed('Method not allowed'); + case 409 : + throw new Exception\Conflict('Conflict'); + case 412 : + throw new Exception\PreconditionFailed('Precondition failed'); + case 416 : + throw new Exception\RequestedRangeNotSatisfiable('Requested Range Not Satisfiable'); + case 500 : + throw new Exception('Internal server error'); + case 501 : + throw new Exception\NotImplemented('Not Implemented'); + case 507 : + throw new Exception\InsufficientStorage('Insufficient storage'); + default: + throw new Exception('HTTP error response. (errorcode ' . $response['statusCode'] . ')'); + } + } + + return $response; + + } + + /** + * Wrapper for all curl functions. + * + * The only reason this was split out in a separate method, is so it + * becomes easier to unittest. + * + * @param string $url + * @param array $settings + * @return array + */ + // @codeCoverageIgnoreStart + protected function curlRequest($url, $settings) { + + $curl = curl_init($url); + curl_setopt_array($curl, $settings); + + return array( + curl_exec($curl), + curl_getinfo($curl), + curl_errno($curl), + curl_error($curl) + ); + + } + // @codeCoverageIgnoreEnd + + /** + * Returns the full url based on the given url (which may be relative). All + * urls are expanded based on the base url as given by the server. + * + * @param string $url + * @return string + */ + protected function getAbsoluteUrl($url) { + + // If the url starts with http:// or https://, the url is already absolute. + if (preg_match('/^http(s?):\/\//', $url)) { + return $url; + } + + // If the url starts with a slash, we must calculate the url based off + // the root of the base url. + if (strpos($url,'/') === 0) { + $parts = parse_url($this->baseUri); + return $parts['scheme'] . '://' . $parts['host'] . (isset($parts['port'])?':' . $parts['port']:'') . $url; + } + + // Otherwise... + return $this->baseUri . $url; + + } + + /** + * Parses a WebDAV multistatus response body + * + * This method returns an array with the following structure + * + * array( + * 'url/to/resource' => array( + * '200' => array( + * '{DAV:}property1' => 'value1', + * '{DAV:}property2' => 'value2', + * ), + * '404' => array( + * '{DAV:}property1' => null, + * '{DAV:}property2' => null, + * ), + * ) + * 'url/to/resource2' => array( + * .. etc .. + * ) + * ) + * + * + * @param string $body xml body + * @return array + */ + public function parseMultiStatus($body) { + + $body = XMLUtil::convertDAVNamespace($body); + + // Fixes an XXE vulnerability on PHP versions older than 5.3.23 or + // 5.4.13. + $previous = libxml_disable_entity_loader(true); + $responseXML = simplexml_load_string($body, null, LIBXML_NOBLANKS | LIBXML_NOCDATA); + libxml_disable_entity_loader($previous); + + if ($responseXML===false) { + throw new \InvalidArgumentException('The passed data is not valid XML'); + } + + $responseXML->registerXPathNamespace('d', 'urn:DAV'); + + $propResult = array(); + + foreach($responseXML->xpath('d:response') as $response) { + $response->registerXPathNamespace('d', 'urn:DAV'); + $href = $response->xpath('d:href'); + $href = (string)$href[0]; + + $properties = array(); + + foreach($response->xpath('d:propstat') as $propStat) { + + $propStat->registerXPathNamespace('d', 'urn:DAV'); + $status = $propStat->xpath('d:status'); + list($httpVersion, $statusCode, $message) = explode(' ', (string)$status[0],3); + + // Only using the propertymap for results with status 200. + $propertyMap = $statusCode==='200' ? $this->propertyMap : array(); + + $properties[$statusCode] = XMLUtil::parseProperties(dom_import_simplexml($propStat), $propertyMap); + + } + + $propResult[$href] = $properties; + + } + + return $propResult; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Collection.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Collection.php new file mode 100644 index 00000000..0090a4d6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Collection.php @@ -0,0 +1,110 @@ +getChildren() as $child) { + + if ($child->getName()==$name) return $child; + + } + throw new Exception\NotFound('File not found: ' . $name); + + } + + /** + * Checks is a child-node exists. + * + * It is generally a good idea to try and override this. Usually it can be optimized. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + try { + + $this->getChild($name); + return true; + + } catch(Exception\NotFound $e) { + + return false; + + } + + } + + /** + * Creates a new file in the directory + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After succesful creation of the file, you may choose to return the ETag + * of the new file here. + * + * The returned ETag must be surrounded by double-quotes (The quotes should + * be part of the actual string). + * + * If you cannot accurately determine the ETag, you should not return it. + * If you don't store the file exactly as-is (you're transforming it + * somehow) you should also not return an ETag. + * + * This means that if a subsequent GET to this new file does not exactly + * return the same contents of what was submitted here, you are strongly + * recommended to omit the ETag. + * + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @return null|string + */ + public function createFile($name, $data = null) { + + throw new Exception\Forbidden('Permission denied to create file (filename ' . $name . ')'); + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @throws Exception\Forbidden + * @return void + */ + public function createDirectory($name) { + + throw new Exception\Forbidden('Permission denied to create directory'); + + } + + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception.php new file mode 100644 index 00000000..22a319e9 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception.php @@ -0,0 +1,64 @@ +lock) { + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:no-conflicting-lock'); + $errorNode->appendChild($error); + if (!is_object($this->lock)) var_dump($this->lock); + $error->appendChild($errorNode->ownerDocument->createElementNS('DAV:','d:href',$this->lock->uri)); + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/FileNotFound.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/FileNotFound.php new file mode 100644 index 00000000..aa4844cb --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/FileNotFound.php @@ -0,0 +1,19 @@ +ownerDocument->createElementNS('DAV:','d:valid-resourcetype'); + $errorNode->appendChild($error); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/LengthRequired.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/LengthRequired.php new file mode 100644 index 00000000..9487686d --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/LengthRequired.php @@ -0,0 +1,30 @@ +message = 'The locktoken supplied does not match any locks on this entity'; + + } + + /** + * This method allows the exception to include additional information into the WebDAV error response + * + * @param DAV\Server $server + * @param \DOMElement $errorNode + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $errorNode) { + + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-matches-request-uri'); + $errorNode->appendChild($error); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/Locked.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/Locked.php new file mode 100644 index 00000000..2bee1b02 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/Locked.php @@ -0,0 +1,73 @@ +lock = $lock; + + } + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 423; + + } + + /** + * This method allows the exception to include additional information into the WebDAV error response + * + * @param DAV\Server $server + * @param \DOMElement $errorNode + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $errorNode) { + + if ($this->lock) { + $error = $errorNode->ownerDocument->createElementNS('DAV:','d:lock-token-submitted'); + $errorNode->appendChild($error); + + $href = $errorNode->ownerDocument->createElementNS('DAV:','d:href'); + $href->appendChild($errorNode->ownerDocument->createTextNode($this->lock->uri)); + $error->appendChild( + $href + ); + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/MethodNotAllowed.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/MethodNotAllowed.php new file mode 100644 index 00000000..05970cfa --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/MethodNotAllowed.php @@ -0,0 +1,45 @@ +getAllowedMethods($server->getRequestUri()); + + return array( + 'Allow' => strtoupper(implode(', ',$methods)), + ); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/NotAuthenticated.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/NotAuthenticated.php new file mode 100644 index 00000000..c082d489 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/NotAuthenticated.php @@ -0,0 +1,30 @@ +header = $header; + + } + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 412; + + } + + /** + * This method allows the exception to include additional information into the WebDAV error response + * + * @param DAV\Server $server + * @param \DOMElement $errorNode + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $errorNode) { + + if ($this->header) { + $prop = $errorNode->ownerDocument->createElement('s:header'); + $prop->nodeValue = $this->header; + $errorNode->appendChild($prop); + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/ReportNotSupported.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/ReportNotSupported.php new file mode 100644 index 00000000..8e32096e --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/ReportNotSupported.php @@ -0,0 +1,32 @@ +ownerDocument->createElementNS('DAV:','d:supported-report'); + $errorNode->appendChild($error); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php new file mode 100644 index 00000000..25002be6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/RequestedRangeNotSatisfiable.php @@ -0,0 +1,31 @@ + + * @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). + * @license http://sabre.io/license/ Modified BSD License + */ +class ServiceUnavailable extends DAV\Exception { + + /** + * Returns the HTTP statuscode for this exception + * + * @return int + */ + public function getHTTPCode() { + + return 503; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/UnsupportedMediaType.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/UnsupportedMediaType.php new file mode 100644 index 00000000..46eea60d --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Exception/UnsupportedMediaType.php @@ -0,0 +1,28 @@ +path . '/' . $name; + file_put_contents($newPath,$data); + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + $newPath = $this->path . '/' . $name; + mkdir($newPath); + + } + + /** + * Returns a specific child node, referenced by its name + * + * This method must throw DAV\Exception\NotFound if the node does not + * exist. + * + * @param string $name + * @throws DAV\Exception\NotFound + * @return DAV\INode + */ + public function getChild($name) { + + $path = $this->path . '/' . $name; + + if (!file_exists($path)) throw new DAV\Exception\NotFound('File with name ' . $path . ' could not be located'); + + if (is_dir($path)) { + + return new Directory($path); + + } else { + + return new File($path); + + } + + } + + /** + * Returns an array with all the child nodes + * + * @return DAV\INode[] + */ + public function getChildren() { + + $nodes = array(); + foreach(scandir($this->path) as $node) if($node!='.' && $node!='..') $nodes[] = $this->getChild($node); + return $nodes; + + } + + /** + * Checks if a child exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + $path = $this->path . '/' . $name; + return file_exists($path); + + } + + /** + * Deletes all files in this directory, and then itself + * + * @return void + */ + public function delete() { + + foreach($this->getChildren() as $child) $child->delete(); + rmdir($this->path); + + } + + /** + * Returns available diskspace information + * + * @return array + */ + public function getQuotaInfo() { + + return array( + disk_total_space($this->path)-disk_free_space($this->path), + disk_free_space($this->path) + ); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/File.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/File.php new file mode 100644 index 00000000..d10370fa --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/File.php @@ -0,0 +1,91 @@ +path,$data); + + } + + /** + * Returns the data + * + * @return string + */ + public function get() { + + return fopen($this->path,'r'); + + } + + /** + * Delete the current file + * + * @return void + */ + public function delete() { + + unlink($this->path); + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + public function getSize() { + + return filesize($this->path); + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + * + * @return mixed + */ + public function getETag() { + + return null; + + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + * + * @return mixed + */ + public function getContentType() { + + return null; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/Node.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/Node.php new file mode 100644 index 00000000..605fa3c8 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/FS/Node.php @@ -0,0 +1,82 @@ +path = $path; + + } + + + + /** + * Returns the name of the node + * + * @return string + */ + public function getName() { + + list(, $name) = DAV\URLUtil::splitPath($this->path); + return $name; + + } + + /** + * Renames the node + * + * @param string $name The new name + * @return void + */ + public function setName($name) { + + list($parentPath, ) = DAV\URLUtil::splitPath($this->path); + list(, $newName) = DAV\URLUtil::splitPath($name); + + $newPath = $parentPath . '/' . $newName; + rename($this->path,$newPath); + + $this->path = $newPath; + + } + + + + /** + * Returns the last modification time, as a unix timestamp + * + * @return int + */ + public function getLastModified() { + + return filemtime($this->path); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Directory.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Directory.php new file mode 100644 index 00000000..da3d2cc6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Directory.php @@ -0,0 +1,159 @@ +path . '/' . $name; + file_put_contents($newPath,$data); + + return '"' . md5_file($newPath) . '"'; + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + // We're not allowing dots + if ($name=='.' || $name=='..') throw new DAV\Exception\Forbidden('Permission denied to . and ..'); + $newPath = $this->path . '/' . $name; + mkdir($newPath); + + } + + /** + * Returns a specific child node, referenced by its name + * + * This method must throw Sabre\DAV\Exception\NotFound if the node does not + * exist. + * + * @param string $name + * @throws DAV\Exception\NotFound + * @return DAV\INode + */ + public function getChild($name) { + + $path = $this->path . '/' . $name; + + if (!file_exists($path)) throw new DAV\Exception\NotFound('File could not be located'); + if ($name=='.' || $name=='..') throw new DAV\Exception\Forbidden('Permission denied to . and ..'); + + if (is_dir($path)) { + + return new Directory($path); + + } else { + + return new File($path); + + } + + } + + /** + * Checks if a child exists. + * + * @param string $name + * @return bool + */ + public function childExists($name) { + + if ($name=='.' || $name=='..') + throw new DAV\Exception\Forbidden('Permission denied to . and ..'); + + $path = $this->path . '/' . $name; + return file_exists($path); + + } + + /** + * Returns an array with all the child nodes + * + * @return DAV\INode[] + */ + public function getChildren() { + + $nodes = array(); + foreach(scandir($this->path) as $node) if($node!='.' && $node!='..' && $node!='.sabredav') $nodes[] = $this->getChild($node); + return $nodes; + + } + + /** + * Deletes all files in this directory, and then itself + * + * @return bool + */ + public function delete() { + + // Deleting all children + foreach($this->getChildren() as $child) $child->delete(); + + // Removing resource info, if its still around + if (file_exists($this->path . '/.sabredav')) unlink($this->path . '/.sabredav'); + + // Removing the directory itself + rmdir($this->path); + + return parent::delete(); + + } + + /** + * Returns available diskspace information + * + * @return array + */ + public function getQuotaInfo() { + + return array( + disk_total_space($this->path)-disk_free_space($this->path), + disk_free_space($this->path) + ); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/File.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/File.php new file mode 100644 index 00000000..6588fad7 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/File.php @@ -0,0 +1,146 @@ +path,$data); + return '"' . md5_file($this->path) . '"'; + + } + + /** + * Updates the file based on a range specification. + * + * The first argument is the data, which is either a readable stream + * resource or a string. + * + * The second argument is the type of update we're doing. + * This is either: + * * 1. append + * * 2. update based on a start byte + * * 3. update based on an end byte + *; + * The third argument is the start or end byte. + * + * After a successful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * @param resource|string $data + * @param int $rangeType + * @param int $offset + * @return string|null + */ + public function patch($data, $rangeType, $offset = null) { + + switch($rangeType) { + case 1 : + $f = fopen($this->path, 'a'); + break; + case 2 : + $f = fopen($this->path, 'c'); + fseek($f,$offset); + break; + case 3 : + $f = fopen($this->path, 'c'); + fseek($f, $offset, SEEK_END); + break; + } + if (is_string($data)) { + fwrite($f, $data); + } else { + stream_copy_to_stream($data,$f); + } + fclose($f); + return '"' . md5_file($this->path) . '"'; + + } + + /** + * Returns the data + * + * @return resource + */ + public function get() { + + return fopen($this->path,'r'); + + } + + /** + * Delete the current file + * + * @return bool + */ + public function delete() { + + unlink($this->path); + return parent::delete(); + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + * + * @return string|null + */ + public function getETag() { + + return '"' . md5_file($this->path). '"'; + + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + * + * @return string|null + */ + public function getContentType() { + + return null; + + } + + /** + * Returns the size of the file, in bytes + * + * @return int + */ + public function getSize() { + + return filesize($this->path); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Node.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Node.php new file mode 100644 index 00000000..0e11582f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/FSExt/Node.php @@ -0,0 +1,214 @@ +getResourceData(); + + foreach($properties as $propertyName=>$propertyValue) { + + // If it was null, we need to delete the property + if (is_null($propertyValue)) { + if (isset($resourceData['properties'][$propertyName])) { + unset($resourceData['properties'][$propertyName]); + } + } else { + $resourceData['properties'][$propertyName] = $propertyValue; + } + + } + + $this->putResourceData($resourceData); + return true; + } + + /** + * Returns a list of properties for this nodes.; + * + * The properties list is a list of propertynames the client requested, encoded as xmlnamespace#tagName, for example: http://www.example.org/namespace#author + * If the array is empty, all properties should be returned + * + * @param array $properties + * @return array + */ + function getProperties($properties) { + + $resourceData = $this->getResourceData(); + + // if the array was empty, we need to return everything + if (!$properties) return $resourceData['properties']; + + $props = array(); + foreach($properties as $property) { + if (isset($resourceData['properties'][$property])) $props[$property] = $resourceData['properties'][$property]; + } + + return $props; + + } + + /** + * Returns the path to the resource file + * + * @return string + */ + protected function getResourceInfoPath() { + + list($parentDir) = DAV\URLUtil::splitPath($this->path); + return $parentDir . '/.sabredav'; + + } + + /** + * Returns all the stored resource information + * + * @return array + */ + protected function getResourceData() { + + $path = $this->getResourceInfoPath(); + if (!file_exists($path)) return array('properties' => array()); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'r'); + flock($handle,LOCK_SH); + $data = ''; + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // We're all good + fclose($handle); + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (!isset($data[$this->getName()])) { + return array('properties' => array()); + } + + $data = $data[$this->getName()]; + if (!isset($data['properties'])) $data['properties'] = array(); + return $data; + + } + + /** + * Updates the resource information + * + * @param array $newData + * @return void + */ + protected function putResourceData(array $newData) { + + $path = $this->getResourceInfoPath(); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + $data = ''; + + rewind($handle); + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + $data[$this->getName()] = $newData; + ftruncate($handle,0); + rewind($handle); + + fwrite($handle,serialize($data)); + fclose($handle); + + } + + /** + * Renames the node + * + * @param string $name The new name + * @return void + */ + public function setName($name) { + + list($parentPath, ) = DAV\URLUtil::splitPath($this->path); + list(, $newName) = DAV\URLUtil::splitPath($name); + $newPath = $parentPath . '/' . $newName; + + // We're deleting the existing resourcedata, and recreating it + // for the new path. + $resourceData = $this->getResourceData(); + $this->deleteResourceData(); + + rename($this->path,$newPath); + $this->path = $newPath; + $this->putResourceData($resourceData); + + + } + + /** + * @return bool + */ + public function deleteResourceData() { + + // When we're deleting this node, we also need to delete any resource information + $path = $this->getResourceInfoPath(); + if (!file_exists($path)) return true; + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + $data = ''; + + rewind($handle); + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (isset($data[$this->getName()])) unset($data[$this->getName()]); + ftruncate($handle,0); + rewind($handle); + fwrite($handle,serialize($data)); + fclose($handle); + + return true; + } + + public function delete() { + + return $this->deleteResourceData(); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/File.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/File.php new file mode 100644 index 00000000..af8ce735 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/File.php @@ -0,0 +1,85 @@ + array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param array $mutations + * @return bool|array + */ + function updateProperties($mutations); + + /** + * Returns a list of properties for this nodes. + * + * The properties list is a list of propertynames the client requested, + * encoded in clark-notation {xmlnamespace}tagname + * + * If the array is empty, it means 'all properties' were requested. + * + * Note that it's fine to liberally give properties back, instead of + * conforming to the list of requested properties. + * The Server class will filter out the extra. + * + * @param array $properties + * @return void + */ + function getProperties($properties); + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/IQuota.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/IQuota.php new file mode 100644 index 00000000..988df3d0 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/IQuota.php @@ -0,0 +1,27 @@ +dataDir = $dataDir; + + } + + protected function getFileNameForUri($uri) { + + return $this->dataDir . '/sabredav_' . md5($uri) . '.locks'; + + } + + + /** + * Returns a list of Sabre\DAV\Locks\LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * If returnChildLocks is set to true, this method should also look for + * any locks in the subtree of the uri for locks. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + public function getLocks($uri, $returnChildLocks) { + + $lockList = array(); + $currentPath = ''; + + foreach(explode('/',$uri) as $uriPart) { + + // weird algorithm that can probably be improved, but we're traversing the path top down + if ($currentPath) $currentPath.='/'; + $currentPath.=$uriPart; + + $uriLocks = $this->getData($currentPath); + + foreach($uriLocks as $uriLock) { + + // Unless we're on the leaf of the uri-tree we should ignore locks with depth 0 + if($uri==$currentPath || $uriLock->depth!=0) { + $uriLock->uri = $currentPath; + $lockList[] = $uriLock; + } + + } + + } + + // Checking if we can remove any of these locks + foreach($lockList as $k=>$lock) { + if (time() > $lock->timeout + $lock->created) unset($lockList[$k]); + } + return $lockList; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function lock($uri, LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 1800; + $lockInfo->created = time(); + + $locks = $this->getLocks($uri,false); + foreach($locks as $k=>$lock) { + if ($lock->token == $lockInfo->token) unset($locks[$k]); + } + $locks[] = $lockInfo; + $this->putData($uri,$locks); + return true; + + } + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function unlock($uri, LockInfo $lockInfo) { + + $locks = $this->getLocks($uri,false); + foreach($locks as $k=>$lock) { + + if ($lock->token == $lockInfo->token) { + + unset($locks[$k]); + $this->putData($uri,$locks); + return true; + + } + } + return false; + + } + + /** + * Returns the stored data for a uri + * + * @param string $uri + * @return array + */ + protected function getData($uri) { + + $path = $this->getFilenameForUri($uri); + if (!file_exists($path)) return array(); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'r'); + flock($handle,LOCK_SH); + $data = ''; + + // Reading data until the eof + while(!feof($handle)) { + $data.=fread($handle,8192); + } + + // We're all good + fclose($handle); + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (!$data) return array(); + return $data; + + } + + /** + * Updates the lock information + * + * @param string $uri + * @param array $newData + * @return void + */ + protected function putData($uri,array $newData) { + + $path = $this->getFileNameForUri($uri); + + // opening up the file, and creating a shared lock + $handle = fopen($path,'a+'); + flock($handle,LOCK_EX); + ftruncate($handle,0); + rewind($handle); + + fwrite($handle,serialize($newData)); + fclose($handle); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/File.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/File.php new file mode 100644 index 00000000..9ac7e06b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/File.php @@ -0,0 +1,183 @@ +locksFile = $locksFile; + + } + + /** + * Returns a list of Sabre\DAV\Locks\LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * If returnChildLocks is set to true, this method should also look for + * any locks in the subtree of the uri for locks. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + public function getLocks($uri, $returnChildLocks) { + + $newLocks = array(); + + $locks = $this->getData(); + + foreach($locks as $lock) { + + if ($lock->uri === $uri || + //deep locks on parents + ($lock->depth!=0 && strpos($uri, $lock->uri . '/')===0) || + + // locks on children + ($returnChildLocks && (strpos($lock->uri, $uri . '/')===0)) ) { + + $newLocks[] = $lock; + + } + + } + + // Checking if we can remove any of these locks + foreach($newLocks as $k=>$lock) { + if (time() > $lock->timeout + $lock->created) unset($newLocks[$k]); + } + return $newLocks; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function lock($uri, LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 1800; + $lockInfo->created = time(); + $lockInfo->uri = $uri; + + $locks = $this->getData(); + + foreach($locks as $k=>$lock) { + if ( + ($lock->token == $lockInfo->token) || + (time() > $lock->timeout + $lock->created) + ) { + unset($locks[$k]); + } + } + $locks[] = $lockInfo; + $this->putData($locks); + return true; + + } + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function unlock($uri, LockInfo $lockInfo) { + + $locks = $this->getData(); + foreach($locks as $k=>$lock) { + + if ($lock->token == $lockInfo->token) { + + unset($locks[$k]); + $this->putData($locks); + return true; + + } + } + return false; + + } + + /** + * Loads the lockdata from the filesystem. + * + * @return array + */ + protected function getData() { + + if (!file_exists($this->locksFile)) return array(); + + // opening up the file, and creating a shared lock + $handle = fopen($this->locksFile,'r'); + flock($handle,LOCK_SH); + + // Reading data until the eof + $data = stream_get_contents($handle); + + // We're all good + fclose($handle); + + // Unserializing and checking if the resource file contains data for this file + $data = unserialize($data); + if (!$data) return array(); + return $data; + + } + + /** + * Saves the lockdata + * + * @param array $newData + * @return void + */ + protected function putData(array $newData) { + + // opening up the file, and creating an exclusive lock + $handle = fopen($this->locksFile,'a+'); + flock($handle,LOCK_EX); + + // We can only truncate and rewind once the lock is acquired. + ftruncate($handle,0); + rewind($handle); + + fwrite($handle,serialize($newData)); + fclose($handle); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/PDO.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/PDO.php new file mode 100644 index 00000000..ebaeef86 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/Backend/PDO.php @@ -0,0 +1,167 @@ +pdo = $pdo; + $this->tableName = $tableName; + + } + + /** + * Returns a list of Sabre\DAV\Locks\LockInfo objects + * + * This method should return all the locks for a particular uri, including + * locks that might be set on a parent uri. + * + * If returnChildLocks is set to true, this method should also look for + * any locks in the subtree of the uri for locks. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + public function getLocks($uri, $returnChildLocks) { + + // NOTE: the following 10 lines or so could be easily replaced by + // pure sql. MySQL's non-standard string concatenation prevents us + // from doing this though. + $query = 'SELECT owner, token, timeout, created, scope, depth, uri FROM '.$this->tableName.' WHERE ((created + timeout) > CAST(? AS UNSIGNED INTEGER)) AND ((uri = ?)'; + $params = array(time(),$uri); + + // We need to check locks for every part in the uri. + $uriParts = explode('/',$uri); + + // We already covered the last part of the uri + array_pop($uriParts); + + $currentPath=''; + + foreach($uriParts as $part) { + + if ($currentPath) $currentPath.='/'; + $currentPath.=$part; + + $query.=' OR (depth!=0 AND uri = ?)'; + $params[] = $currentPath; + + } + + if ($returnChildLocks) { + + $query.=' OR (uri LIKE ?)'; + $params[] = $uri . '/%'; + + } + $query.=')'; + + $stmt = $this->pdo->prepare($query); + $stmt->execute($params); + $result = $stmt->fetchAll(); + + $lockList = array(); + foreach($result as $row) { + + $lockInfo = new LockInfo(); + $lockInfo->owner = $row['owner']; + $lockInfo->token = $row['token']; + $lockInfo->timeout = $row['timeout']; + $lockInfo->created = $row['created']; + $lockInfo->scope = $row['scope']; + $lockInfo->depth = $row['depth']; + $lockInfo->uri = $row['uri']; + $lockList[] = $lockInfo; + + } + + return $lockList; + + } + + /** + * Locks a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function lock($uri, LockInfo $lockInfo) { + + // We're making the lock timeout 30 minutes + $lockInfo->timeout = 30*60; + $lockInfo->created = time(); + $lockInfo->uri = $uri; + + $locks = $this->getLocks($uri,false); + $exists = false; + foreach($locks as $lock) { + if ($lock->token == $lockInfo->token) $exists = true; + } + + if ($exists) { + $stmt = $this->pdo->prepare('UPDATE '.$this->tableName.' SET owner = ?, timeout = ?, scope = ?, depth = ?, uri = ?, created = ? WHERE token = ?'); + $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token)); + } else { + $stmt = $this->pdo->prepare('INSERT INTO '.$this->tableName.' (owner,timeout,scope,depth,uri,created,token) VALUES (?,?,?,?,?,?,?)'); + $stmt->execute(array($lockInfo->owner,$lockInfo->timeout,$lockInfo->scope,$lockInfo->depth,$uri,$lockInfo->created,$lockInfo->token)); + } + + return true; + + } + + + + /** + * Removes a lock from a uri + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function unlock($uri, LockInfo $lockInfo) { + + $stmt = $this->pdo->prepare('DELETE FROM '.$this->tableName.' WHERE uri = ? AND token = ?'); + $stmt->execute(array($uri,$lockInfo->token)); + + return $stmt->rowCount()===1; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/LockInfo.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/LockInfo.php new file mode 100644 index 00000000..74bdb0f9 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Locks/LockInfo.php @@ -0,0 +1,81 @@ +addPlugin($lockPlugin); + * + * @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). + * @author Evert Pot (http://evertpot.com/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Plugin extends DAV\ServerPlugin { + + /** + * locksBackend + * + * @var Backend\Backend\Interface + */ + protected $locksBackend; + + /** + * server + * + * @var Sabre\DAV\Server + */ + protected $server; + + /** + * __construct + * + * @param Backend\BackendInterface $locksBackend + */ + public function __construct(Backend\BackendInterface $locksBackend = null) { + + $this->locksBackend = $locksBackend; + + } + + /** + * Initializes the plugin + * + * This method is automatically called by the Server class after addPlugin. + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + $server->subscribeEvent('unknownMethod',array($this,'unknownMethod')); + $server->subscribeEvent('beforeMethod',array($this,'beforeMethod'),50); + $server->subscribeEvent('afterGetProperties',array($this,'afterGetProperties')); + + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using Sabre\DAV\Server::getPlugin + * + * @return string + */ + public function getPluginName() { + + return 'locks'; + + } + + /** + * This method is called by the Server if the user used an HTTP method + * the server didn't recognize. + * + * This plugin intercepts the LOCK and UNLOCK methods. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function unknownMethod($method, $uri) { + + switch($method) { + + case 'LOCK' : $this->httpLock($uri); return false; + case 'UNLOCK' : $this->httpUnlock($uri); return false; + + } + + } + + /** + * This method is called after most properties have been found + * it allows us to add in any Lock-related properties + * + * @param string $path + * @param array $newProperties + * @return bool + */ + public function afterGetProperties($path, &$newProperties) { + + foreach($newProperties[404] as $propName=>$discard) { + + switch($propName) { + + case '{DAV:}supportedlock' : + $val = false; + if ($this->locksBackend) $val = true; + $newProperties[200][$propName] = new DAV\Property\SupportedLock($val); + unset($newProperties[404][$propName]); + break; + + case '{DAV:}lockdiscovery' : + $newProperties[200][$propName] = new DAV\Property\LockDiscovery($this->getLocks($path)); + unset($newProperties[404][$propName]); + break; + + } + + + } + return true; + + } + + + /** + * This method is called before the logic for any HTTP method is + * handled. + * + * This plugin uses that feature to intercept access to locked resources. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + switch($method) { + + case 'DELETE' : + $lastLock = null; + if (!$this->validateLock($uri,$lastLock, true)) + throw new DAV\Exception\Locked($lastLock); + break; + case 'MKCOL' : + case 'PROPPATCH' : + case 'PUT' : + case 'PATCH' : + $lastLock = null; + if (!$this->validateLock($uri,$lastLock)) + throw new DAV\Exception\Locked($lastLock); + break; + case 'MOVE' : + $lastLock = null; + if (!$this->validateLock(array( + $uri, + $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')), + ),$lastLock, true)) + throw new DAV\Exception\Locked($lastLock); + break; + case 'COPY' : + $lastLock = null; + if (!$this->validateLock( + $this->server->calculateUri($this->server->httpRequest->getHeader('Destination')), + $lastLock, true)) + throw new DAV\Exception\Locked($lastLock); + break; + } + + return true; + + } + + /** + * Use this method to tell the server this plugin defines additional + * HTTP methods. + * + * This method is passed a uri. It should only return HTTP methods that are + * available for the specified uri. + * + * @param string $uri + * @return array + */ + public function getHTTPMethods($uri) { + + if ($this->locksBackend) + return array('LOCK','UNLOCK'); + + return array(); + + } + + /** + * Returns a list of features for the HTTP OPTIONS Dav: header. + * + * In this case this is only the number 2. The 2 in the Dav: header + * indicates the server supports locks. + * + * @return array + */ + public function getFeatures() { + + return array(2); + + } + + /** + * Returns all lock information on a particular uri + * + * This function should return an array with Sabre\DAV\Locks\LockInfo objects. If there are no locks on a file, return an empty array. + * + * Additionally there is also the possibility of locks on parent nodes, so we'll need to traverse every part of the tree + * If the $returnChildLocks argument is set to true, we'll also traverse all the children of the object + * for any possible locks and return those as well. + * + * @param string $uri + * @param bool $returnChildLocks + * @return array + */ + public function getLocks($uri, $returnChildLocks = false) { + + $lockList = array(); + + if ($this->locksBackend) + $lockList = array_merge($lockList,$this->locksBackend->getLocks($uri, $returnChildLocks)); + + return $lockList; + + } + + /** + * Locks an uri + * + * The WebDAV lock request can be operated to either create a new lock on a file, or to refresh an existing lock + * If a new lock is created, a full XML body should be supplied, containing information about the lock such as the type + * of lock (shared or exclusive) and the owner of the lock + * + * If a lock is to be refreshed, no body should be supplied and there should be a valid If header containing the lock + * + * Additionally, a lock can be requested for a non-existent file. In these case we're obligated to create an empty file as per RFC4918:S7.3 + * + * @param string $uri + * @return void + */ + protected function httpLock($uri) { + + $lastLock = null; + if (!$this->validateLock($uri,$lastLock)) { + + // If the existing lock was an exclusive lock, we need to fail + if (!$lastLock || $lastLock->scope == LockInfo::EXCLUSIVE) { + //var_dump($lastLock); + throw new DAV\Exception\ConflictingLock($lastLock); + } + + } + + if ($body = $this->server->httpRequest->getBody(true)) { + // This is a new lock request + $lockInfo = $this->parseLockRequest($body); + $lockInfo->depth = $this->server->getHTTPDepth(); + $lockInfo->uri = $uri; + if($lastLock && $lockInfo->scope != LockInfo::SHARED) throw new DAV\Exception\ConflictingLock($lastLock); + + } elseif ($lastLock) { + + // This must have been a lock refresh + $lockInfo = $lastLock; + + // The resource could have been locked through another uri. + if ($uri!=$lockInfo->uri) $uri = $lockInfo->uri; + + } else { + + // There was neither a lock refresh nor a new lock request + throw new DAV\Exception\BadRequest('An xml body is required for lock requests'); + + } + + if ($timeout = $this->getTimeoutHeader()) $lockInfo->timeout = $timeout; + + $newFile = false; + + // If we got this far.. we should go check if this node actually exists. If this is not the case, we need to create it first + try { + $this->server->tree->getNodeForPath($uri); + + // We need to call the beforeWriteContent event for RFC3744 + // Edit: looks like this is not used, and causing problems now. + // + // See Issue 222 + // $this->server->broadcastEvent('beforeWriteContent',array($uri)); + + } catch (DAV\Exception\NotFound $e) { + + // It didn't, lets create it + $this->server->createFile($uri,fopen('php://memory','r')); + $newFile = true; + + } + + $this->lockNode($uri,$lockInfo); + + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Lock-Token','token . '>'); + $this->server->httpResponse->sendStatus($newFile?201:200); + $this->server->httpResponse->sendBody($this->generateLockResponse($lockInfo)); + + } + + /** + * Unlocks a uri + * + * This WebDAV method allows you to remove a lock from a node. The client should provide a valid locktoken through the Lock-token http header + * The server should return 204 (No content) on success + * + * @param string $uri + * @return void + */ + protected function httpUnlock($uri) { + + $lockToken = $this->server->httpRequest->getHeader('Lock-Token'); + + // If the locktoken header is not supplied, we need to throw a bad request exception + if (!$lockToken) throw new DAV\Exception\BadRequest('No lock token was supplied'); + + $locks = $this->getLocks($uri); + + // Windows sometimes forgets to include < and > in the Lock-Token + // header + if ($lockToken[0]!=='<') $lockToken = '<' . $lockToken . '>'; + + foreach($locks as $lock) { + + if ('token . '>' == $lockToken) { + + $this->unlockNode($uri,$lock); + $this->server->httpResponse->setHeader('Content-Length','0'); + $this->server->httpResponse->sendStatus(204); + return; + + } + + } + + // If we got here, it means the locktoken was invalid + throw new DAV\Exception\LockTokenMatchesRequestUri(); + + } + + /** + * Locks a uri + * + * All the locking information is supplied in the lockInfo object. The object has a suggested timeout, but this can be safely ignored + * It is important that if the existing timeout is ignored, the property is overwritten, as this needs to be sent back to the client + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function lockNode($uri,LockInfo $lockInfo) { + + if (!$this->server->broadcastEvent('beforeLock',array($uri,$lockInfo))) return; + + if ($this->locksBackend) return $this->locksBackend->lock($uri,$lockInfo); + throw new DAV\Exception\MethodNotAllowed('Locking support is not enabled for this resource. No Locking backend was found so if you didn\'t expect this error, please check your configuration.'); + + } + + /** + * Unlocks a uri + * + * This method removes a lock from a uri. It is assumed all the supplied information is correct and verified + * + * @param string $uri + * @param LockInfo $lockInfo + * @return bool + */ + public function unlockNode($uri, LockInfo $lockInfo) { + + if (!$this->server->broadcastEvent('beforeUnlock',array($uri,$lockInfo))) return; + if ($this->locksBackend) return $this->locksBackend->unlock($uri,$lockInfo); + + } + + + /** + * Returns the contents of the HTTP Timeout header. + * + * The method formats the header into an integer. + * + * @return int + */ + public function getTimeoutHeader() { + + $header = $this->server->httpRequest->getHeader('Timeout'); + + if ($header) { + + if (stripos($header,'second-')===0) $header = (int)(substr($header,7)); + else if (strtolower($header)=='infinite') $header = LockInfo::TIMEOUT_INFINITE; + else throw new DAV\Exception\BadRequest('Invalid HTTP timeout header'); + + } else { + + $header = 0; + + } + + return $header; + + } + + /** + * Generates the response for successful LOCK requests + * + * @param LockInfo $lockInfo + * @return string + */ + protected function generateLockResponse(LockInfo $lockInfo) { + + $dom = new \DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + + $prop = $dom->createElementNS('DAV:','d:prop'); + $dom->appendChild($prop); + + $lockDiscovery = $dom->createElementNS('DAV:','d:lockdiscovery'); + $prop->appendChild($lockDiscovery); + + $lockObj = new DAV\Property\LockDiscovery(array($lockInfo),true); + $lockObj->serialize($this->server,$lockDiscovery); + + return $dom->saveXML(); + + } + + /** + * validateLock should be called when a write operation is about to happen + * It will check if the requested url is locked, and see if the correct lock tokens are passed + * + * @param mixed $urls List of relevant urls. Can be an array, a string or nothing at all for the current request uri + * @param mixed $lastLock This variable will be populated with the last checked lock object (Sabre\DAV\Locks\LockInfo) + * @param bool $checkChildLocks If set to true, this function will also look for any locks set on child resources of the supplied urls. This is needed for for example deletion of entire trees. + * @return bool + */ + protected function validateLock($urls = null,&$lastLock = null, $checkChildLocks = false) { + + if (is_null($urls)) { + $urls = array($this->server->getRequestUri()); + } elseif (is_string($urls)) { + $urls = array($urls); + } elseif (!is_array($urls)) { + throw new DAV\Exception('The urls parameter should either be null, a string or an array'); + } + + $conditions = $this->getIfConditions(); + + // We're going to loop through the urls and make sure all lock conditions are satisfied + foreach($urls as $url) { + + $locks = $this->getLocks($url, $checkChildLocks); + + // If there were no conditions, but there were locks, we fail + if (!$conditions && $locks) { + reset($locks); + $lastLock = current($locks); + return false; + } + + // If there were no locks or conditions, we go to the next url + if (!$locks && !$conditions) continue; + + foreach($conditions as $condition) { + + if (!$condition['uri']) { + $conditionUri = $this->server->getRequestUri(); + } else { + $conditionUri = $this->server->calculateUri($condition['uri']); + } + + // If the condition has a url, and it isn't part of the affected url at all, check the next condition + if ($conditionUri && strpos($url,$conditionUri)!==0) continue; + + // The tokens array contians arrays with 2 elements. 0=true/false for normal/not condition, 1=locktoken + // At least 1 condition has to be satisfied + foreach($condition['tokens'] as $conditionToken) { + + $etagValid = true; + $lockValid = true; + + // key 2 can contain an etag + if ($conditionToken[2]) { + + $uri = $conditionUri?$conditionUri:$this->server->getRequestUri(); + $node = $this->server->tree->getNodeForPath($uri); + $etagValid = $node instanceof DAV\IFile && $node->getETag()==$conditionToken[2]; + + } + + // key 1 can contain a lock token + if ($conditionToken[1]) { + + $lockValid = false; + // Match all the locks + foreach($locks as $lockIndex=>$lock) { + + $lockToken = 'opaquelocktoken:' . $lock->token; + + // Checking NOT + if (!$conditionToken[0] && $lockToken != $conditionToken[1]) { + + // Condition valid, onto the next + $lockValid = true; + break; + } + if ($conditionToken[0] && $lockToken == $conditionToken[1]) { + + $lastLock = $lock; + // Condition valid and lock matched + unset($locks[$lockIndex]); + $lockValid = true; + break; + + } + + } + + } + + // If, after checking both etags and locks they are stil valid, + // we can continue with the next condition. + if ($etagValid && $lockValid) continue 2; + } + // No conditions matched, so we fail + throw new DAV\Exception\PreconditionFailed('The tokens provided in the if header did not match','If'); + } + + // Conditions were met, we'll also need to check if all the locks are gone + if (count($locks)) { + + reset($locks); + + // There's still locks, we fail + $lastLock = current($locks); + return false; + + } + + + } + + // We got here, this means every condition was satisfied + return true; + + } + + /** + * This method is created to extract information from the WebDAV HTTP 'If:' header + * + * The If header can be quite complex, and has a bunch of features. We're using a regex to extract all relevant information + * The function will return an array, containing structs with the following keys + * + * * uri - the uri the condition applies to. If this is returned as an + * empty string, this implies it's referring to the request url. + * * tokens - The lock token. another 2 dimensional array containing 2 elements (0 = true/false.. If this is a negative condition its set to false, 1 = the actual token) + * * etag - an etag, if supplied + * + * @return array + */ + public function getIfConditions() { + + $header = $this->server->httpRequest->getHeader('If'); + if (!$header) return array(); + + $matches = array(); + + $regex = '/(?:\<(?P.*?)\>\s)?\((?PNot\s)?(?:\<(?P[^\>]*)\>)?(?:\s?)(?:\[(?P[^\]]*)\])?\)/im'; + preg_match_all($regex,$header,$matches,PREG_SET_ORDER); + + $conditions = array(); + + foreach($matches as $match) { + + $condition = array( + 'uri' => $match['uri'], + 'tokens' => array( + array($match['not']?0:1,$match['token'],isset($match['etag'])?$match['etag']:'') + ), + ); + + if (!$condition['uri'] && count($conditions)) $conditions[count($conditions)-1]['tokens'][] = array( + $match['not']?0:1, + $match['token'], + isset($match['etag'])?$match['etag']:'' + ); + else { + $conditions[] = $condition; + } + + } + + return $conditions; + + } + + /** + * Parses a webdav lock xml body, and returns a new Sabre\DAV\Locks\LockInfo object + * + * @param string $body + * @return DAV\Locks\LockInfo + */ + protected function parseLockRequest($body) { + + // Fixes an XXE vulnerability on PHP versions older than 5.3.23 or + // 5.4.13. + $previous = libxml_disable_entity_loader(true); + + + $xml = simplexml_load_string( + DAV\XMLUtil::convertDAVNamespace($body), + null, + LIBXML_NOWARNING); + libxml_disable_entity_loader($previous); + + $xml->registerXPathNamespace('d','urn:DAV'); + $lockInfo = new LockInfo(); + + $children = $xml->children("urn:DAV"); + $lockInfo->owner = (string)$children->owner; + + $lockInfo->token = DAV\UUIDUtil::getUUID(); + $lockInfo->scope = count($xml->xpath('d:lockscope/d:exclusive'))>0 ? LockInfo::EXCLUSIVE : LockInfo::SHARED; + + return $lockInfo; + + } + + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Mount/Plugin.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Mount/Plugin.php new file mode 100644 index 00000000..8376b03b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Mount/Plugin.php @@ -0,0 +1,83 @@ +server = $server; + $this->server->subscribeEvent('beforeMethod',array($this,'beforeMethod'), 90); + + } + + /** + * 'beforeMethod' event handles. This event handles intercepts GET requests ending + * with ?mount + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + if ($method!='GET') return; + if ($this->server->httpRequest->getQueryString()!='mount') return; + + $currentUri = $this->server->httpRequest->getAbsoluteUri(); + + // Stripping off everything after the ? + list($currentUri) = explode('?',$currentUri); + + $this->davMount($currentUri); + + // Returning false to break the event chain + return false; + + } + + /** + * Generates the davmount response + * + * @param string $uri absolute uri + * @return void + */ + public function davMount($uri) { + + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->setHeader('Content-Type','application/davmount+xml'); + ob_start(); + echo '', "\n"; + echo "\n"; + echo " ", htmlspecialchars($uri, ENT_NOQUOTES, 'UTF-8'), "\n"; + echo ""; + $this->server->httpResponse->sendBody(ob_get_clean()); + + } + + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Node.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Node.php new file mode 100644 index 00000000..44e47be6 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Node.php @@ -0,0 +1,55 @@ +rootNode = $rootNode; + + } + + /** + * Returns the INode object for the requested path + * + * @param string $path + * @return INode + */ + public function getNodeForPath($path) { + + $path = trim($path,'/'); + if (isset($this->cache[$path])) return $this->cache[$path]; + + // Is it the root node? + if (!strlen($path)) { + return $this->rootNode; + } + + // Attempting to fetch its parent + list($parentName, $baseName) = URLUtil::splitPath($path); + + // If there was no parent, we must simply ask it from the root node. + if ($parentName==="") { + $node = $this->rootNode->getChild($baseName); + } else { + // Otherwise, we recursively grab the parent and ask him/her. + $parent = $this->getNodeForPath($parentName); + + if (!($parent instanceof ICollection)) + throw new Exception\NotFound('Could not find node at path: ' . $path); + + $node = $parent->getChild($baseName); + + } + + $this->cache[$path] = $node; + return $node; + + } + + /** + * This function allows you to check if a node exists. + * + * @param string $path + * @return bool + */ + public function nodeExists($path) { + + try { + + // The root always exists + if ($path==='') return true; + + list($parent, $base) = URLUtil::splitPath($path); + + $parentNode = $this->getNodeForPath($parent); + if (!$parentNode instanceof ICollection) return false; + return $parentNode->childExists($base); + + } catch (Exception\NotFound $e) { + + return false; + + } + + } + + /** + * Returns a list of childnodes for a given path. + * + * @param string $path + * @return array + */ + public function getChildren($path) { + + $node = $this->getNodeForPath($path); + $children = $node->getChildren(); + foreach($children as $child) { + + $this->cache[trim($path,'/') . '/' . $child->getName()] = $child; + + } + return $children; + + } + + /** + * This method is called with every tree update + * + * Examples of tree updates are: + * * node deletions + * * node creations + * * copy + * * move + * * renaming nodes + * + * If Tree classes implement a form of caching, this will allow + * them to make sure caches will be expired. + * + * If a path is passed, it is assumed that the entire subtree is dirty + * + * @param string $path + * @return void + */ + public function markDirty($path) { + + // We don't care enough about sub-paths + // flushing the entire cache + $path = trim($path,'/'); + foreach($this->cache as $nodePath=>$node) { + if ($nodePath == $path || strpos($nodePath,$path.'/')===0) + unset($this->cache[$nodePath]); + + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/PartialUpdate/IFile.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/PartialUpdate/IFile.php new file mode 100644 index 00000000..9cfb4737 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/PartialUpdate/IFile.php @@ -0,0 +1,39 @@ +addPlugin($patchPlugin); + * + * @copyright Copyright (C) 2007-2014 fruux GmbH (https://fruux.com/). + * @author Jean-Tiare LE BIGOT (http://www.jtlebi.fr/) + * @license http://sabre.io/license/ Modified BSD License + */ +class Plugin extends DAV\ServerPlugin { + + const RANGE_APPEND = 1; + const RANGE_START = 2; + const RANGE_END = 3; + + /** + * Reference to server + * + * @var Sabre\DAV\Server + */ + protected $server; + + /** + * Initializes the plugin + * + * This method is automatically called by the Server class after addPlugin. + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + $server->subscribeEvent('unknownMethod',array($this,'unknownMethod')); + + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using DAV\Server::getPlugin + * + * @return string + */ + public function getPluginName() { + + return 'partialupdate'; + + } + + /** + * This method is called by the Server if the user used an HTTP method + * the server didn't recognize. + * + * This plugin intercepts the PATCH methods. + * + * @param string $method + * @param string $uri + * @return bool|null + */ + public function unknownMethod($method, $uri) { + + switch($method) { + + case 'PATCH': + return $this->httpPatch($uri); + + } + + } + + /** + * Use this method to tell the server this plugin defines additional + * HTTP methods. + * + * This method is passed a uri. It should only return HTTP methods that are + * available for the specified uri. + * + * We claim to support PATCH method (partial update) if and only if + * - the node exist + * - the node implements our partial update interface + * + * @param string $uri + * @return array + */ + public function getHTTPMethods($uri) { + + $tree = $this->server->tree; + if ($tree->nodeExists($uri)) { + $node = $tree->getNodeForPath($uri); + if ($node instanceof IFile || $node instanceof IPatchSupport) { + return array('PATCH'); + } + } + return array(); + + } + + /** + * Returns a list of features for the HTTP OPTIONS Dav: header. + * + * @return array + */ + public function getFeatures() { + + return array('sabredav-partialupdate'); + + } + + /** + * Patch an uri + * + * The WebDAV patch request can be used to modify only a part of an + * existing resource. If the resource does not exist yet and the first + * offset is not 0, the request fails + * + * @param string $uri + * @return void + */ + protected function httpPatch($uri) { + + // Get the node. Will throw a 404 if not found + $node = $this->server->tree->getNodeForPath($uri); + if (!$node instanceof IFile && !$node instanceof IPatchSupport) { + throw new DAV\Exception\MethodNotAllowed('The target resource does not support the PATCH method.'); + } + + $range = $this->getHTTPUpdateRange(); + + if (!$range) { + throw new DAV\Exception\BadRequest('No valid "X-Update-Range" found in the headers'); + } + + $contentType = strtolower( + $this->server->httpRequest->getHeader('Content-Type') + ); + + if ($contentType != 'application/x-sabredav-partialupdate') { + throw new DAV\Exception\UnsupportedMediaType('Unknown Content-Type header "' . $contentType . '"'); + } + + $len = $this->server->httpRequest->getHeader('Content-Length'); + if (!$len) throw new DAV\Exception\LengthRequired('A Content-Length header is required'); + + switch($range[0]) { + case self::RANGE_START : + // Calculate the end-range if it doesn't exist. + if (!$range[2]) { + $range[2] = $range[1] + $len - 1; + } else { + if ($range[2] < $range[1]) { + throw new DAV\Exception\RequestedRangeNotSatisfiable('The end offset (' . $range[2] . ') is lower than the start offset (' . $range[1] . ')'); + } + if($range[2] - $range[1] + 1 != $len) { + throw new DAV\Exception\RequestedRangeNotSatisfiable('Actual data length (' . $len . ') is not consistent with begin (' . $range[1] . ') and end (' . $range[2] . ') offsets'); + } + } + break; + } + // Checking If-None-Match and related headers. + if (!$this->server->checkPreconditions()) return; + + if (!$this->server->broadcastEvent('beforeWriteContent',array($uri, $node, null))) + return; + + $body = $this->server->httpRequest->getBody(); + + + if ($node instanceof IPatchSupport) { + $etag = $node->patch($body, $range[0], isset($range[1])?$range[1]:null); + } else { + // The old interface + switch($range[0]) { + case self::RANGE_APPEND : + throw new DAV\Exception\NotImplemented('This node does not support the append syntax. Please upgrade it to IPatchSupport'); + case self::RANGE_START : + $etag = $node->putRange($body, $range[1]); + break; + case self::RANGE_END : + throw new DAV\Exception\NotImplemented('This node does not support the end-range syntax. Please upgrade it to IPatchSupport'); + break; + } + } + + $this->server->broadcastEvent('afterWriteContent',array($uri, $node)); + + $this->server->httpResponse->setHeader('Content-Length','0'); + if ($etag) $this->server->httpResponse->setHeader('ETag',$etag); + $this->server->httpResponse->sendStatus(204); + + return false; + + } + + /** + * Returns the HTTP custom range update header + * + * This method returns null if there is no well-formed HTTP range request + * header. It returns array(1) if it was an append request, array(2, + * $start, $end) if it's a start and end range, lastly it's array(3, + * $endoffset) if the offset was negative, and should be calculated from + * the end of the file. + * + * Examples: + * + * null - invalid + * array(1) - append + * array(2,10,15) - update bytes 10, 11, 12, 13, 14, 15 + * array(2,10,null) - update bytes 10 until the end of the patch body + * array(3,-5) - update from 5 bytes from the end of the file. + * + * @return array|null + */ + public function getHTTPUpdateRange() { + + $range = $this->server->httpRequest->getHeader('X-Update-Range'); + if (is_null($range)) return null; + + // Matching "Range: bytes=1234-5678: both numbers are optional + + if (!preg_match('/^(append)|(?:bytes=([0-9]+)-([0-9]*))|(?:bytes=(-[0-9]+))$/i',$range,$matches)) return null; + + if ($matches[1]==='append') { + return array(self::RANGE_APPEND); + } elseif (strlen($matches[2])>0) { + return array(self::RANGE_START, $matches[2], $matches[3]?:null); + } elseif ($matches[4]) { + return array(self::RANGE_END, $matches[4]); + } else { + return null; + } + + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property.php new file mode 100644 index 00000000..d0c26590 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property.php @@ -0,0 +1,31 @@ +time = $time; + } elseif (is_int($time) || ctype_digit($time)) { + $this->time = new \DateTime('@' . $time); + } else { + $this->time = new \DateTime($time); + } + + // Setting timezone to UTC + $this->time->setTimezone(new \DateTimeZone('UTC')); + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $prop + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $prop) { + + $doc = $prop->ownerDocument; + //$prop->setAttribute('xmlns:b','urn:uuid:c2f41010-65b3-11d1-a29f-00aa00c14882/'); + //$prop->setAttribute('b:dt','dateTime.rfc1123'); + $prop->nodeValue = HTTP\Util::toHTTPDate($this->time); + + } + + /** + * getTime + * + * @return \DateTime + */ + public function getTime() { + + return $this->time; + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Href.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Href.php new file mode 100644 index 00000000..f0c16270 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Href.php @@ -0,0 +1,99 @@ +href = $href; + $this->autoPrefix = $autoPrefix; + + } + + /** + * Returns the uri + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Serializes this property. + * + * It will additionally prepend the href property with the server's base uri. + * + * @param DAV\Server $server + * @param \DOMElement $dom + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $dom) { + + $prefix = $server->xmlNamespaces['DAV:']; + $elem = $dom->ownerDocument->createElement($prefix . ':href'); + + if ($this->autoPrefix) { + $value = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href); + } else { + $value = $this->href; + } + $elem->appendChild($dom->ownerDocument->createTextNode($value)); + + $dom->appendChild($elem); + + } + + /** + * Unserializes this property from a DOM Element + * + * This method returns an instance of this class. + * It will only decode {DAV:}href values. For non-compatible elements null will be returned. + * + * @param \DOMElement $dom + * @return DAV\Property\Href + */ + static function unserialize(\DOMElement $dom) { + + if ($dom->firstChild && DAV\XMLUtil::toClarkNotation($dom->firstChild)==='{DAV:}href') { + return new self($dom->firstChild->textContent,false); + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/HrefList.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/HrefList.php new file mode 100644 index 00000000..a5bad4ac --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/HrefList.php @@ -0,0 +1,105 @@ +hrefs = $hrefs; + $this->autoPrefix = $autoPrefix; + + } + + /** + * Returns the uris + * + * @return array + */ + public function getHrefs() { + + return $this->hrefs; + + } + + /** + * Serializes this property. + * + * It will additionally prepend the href property with the server's base uri. + * + * @param DAV\Server $server + * @param \DOMElement $dom + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $dom) { + + $prefix = $server->xmlNamespaces['DAV:']; + + foreach($this->hrefs as $href) { + + $elem = $dom->ownerDocument->createElement($prefix . ':href'); + if ($this->autoPrefix) { + $value = $server->getBaseUri() . DAV\URLUtil::encodePath($href); + } else { + $value = $href; + } + $elem->appendChild($dom->ownerDocument->createTextNode($value)); + + $dom->appendChild($elem); + } + + } + + /** + * Unserializes this property from a DOM Element + * + * This method returns an instance of this class. + * It will only decode {DAV:}href values. + * + * @param \DOMElement $dom + * @return DAV\Property\HrefList + */ + static function unserialize(\DOMElement $dom) { + + $hrefs = array(); + foreach($dom->childNodes as $child) { + if (DAV\XMLUtil::toClarkNotation($child)==='{DAV:}href') { + $hrefs[] = $child->textContent; + } + } + return new self($hrefs, false); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/IHref.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/IHref.php new file mode 100644 index 00000000..268ab8d5 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/IHref.php @@ -0,0 +1,25 @@ +locks = $locks; + $this->revealLockToken = $revealLockToken; + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $prop + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $prop) { + + $doc = $prop->ownerDocument; + + foreach($this->locks as $lock) { + + $activeLock = $doc->createElementNS('DAV:','d:activelock'); + $prop->appendChild($activeLock); + + $lockScope = $doc->createElementNS('DAV:','d:lockscope'); + $activeLock->appendChild($lockScope); + + $lockScope->appendChild($doc->createElementNS('DAV:','d:' . ($lock->scope==DAV\Locks\LockInfo::EXCLUSIVE?'exclusive':'shared'))); + + $lockType = $doc->createElementNS('DAV:','d:locktype'); + $activeLock->appendChild($lockType); + + $lockType->appendChild($doc->createElementNS('DAV:','d:write')); + + /* {DAV:}lockroot */ + if (!self::$hideLockRoot) { + $lockRoot = $doc->createElementNS('DAV:','d:lockroot'); + $activeLock->appendChild($lockRoot); + $href = $doc->createElementNS('DAV:','d:href'); + $href->appendChild($doc->createTextNode($server->getBaseUri() . $lock->uri)); + $lockRoot->appendChild($href); + } + + $activeLock->appendChild($doc->createElementNS('DAV:','d:depth',($lock->depth == DAV\Server::DEPTH_INFINITY?'infinity':$lock->depth))); + $activeLock->appendChild($doc->createElementNS('DAV:','d:timeout','Second-' . $lock->timeout)); + + if ($this->revealLockToken) { + $lockToken = $doc->createElementNS('DAV:','d:locktoken'); + $activeLock->appendChild($lockToken); + $lockToken->appendChild($doc->createElementNS('DAV:','d:href','opaquelocktoken:' . $lock->token)); + } + + $activeLock->appendChild($doc->createElementNS('DAV:','d:owner',$lock->owner)); + + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResourceType.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResourceType.php new file mode 100644 index 00000000..68134f3f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResourceType.php @@ -0,0 +1,127 @@ +resourceType = array(); + elseif ($resourceType === DAV\Server::NODE_DIRECTORY) + $this->resourceType = array('{DAV:}collection'); + elseif (is_array($resourceType)) + $this->resourceType = $resourceType; + else + $this->resourceType = array($resourceType); + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $prop + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $prop) { + + $propName = null; + $rt = $this->resourceType; + + foreach($rt as $resourceType) { + if (preg_match('/^{([^}]*)}(.*)$/',$resourceType,$propName)) { + + if (isset($server->xmlNamespaces[$propName[1]])) { + $prop->appendChild($prop->ownerDocument->createElement($server->xmlNamespaces[$propName[1]] . ':' . $propName[2])); + } else { + $prop->appendChild($prop->ownerDocument->createElementNS($propName[1],'custom:' . $propName[2])); + } + + } + } + + } + + /** + * Returns the values in clark-notation + * + * For example array('{DAV:}collection') + * + * @return array + */ + public function getValue() { + + return $this->resourceType; + + } + + /** + * Checks if the principal contains a certain value + * + * @param string $type + * @return bool + */ + public function is($type) { + + return in_array($type, $this->resourceType); + + } + + /** + * Adds a resourcetype value to this property + * + * @param string $type + * @return void + */ + public function add($type) { + + $this->resourceType[] = $type; + $this->resourceType = array_unique($this->resourceType); + + } + + /** + * Unserializes a DOM element into a ResourceType property. + * + * @param \DOMElement $dom + * @return DAV\Property\ResourceType + */ + static public function unserialize(\DOMElement $dom) { + + $value = array(); + foreach($dom->childNodes as $child) { + + $value[] = DAV\XMLUtil::toClarkNotation($child); + + } + + return new self($value); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Response.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Response.php new file mode 100644 index 00000000..370abc26 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/Response.php @@ -0,0 +1,157 @@ +href = $href; + $this->responseProperties = $responseProperties; + + } + + /** + * Returns the url + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Returns the property list + * + * @return array + */ + public function getResponseProperties() { + + return $this->responseProperties; + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $dom + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $dom) { + + $document = $dom->ownerDocument; + $properties = $this->responseProperties; + + $xresponse = $document->createElement('d:response'); + $dom->appendChild($xresponse); + + $uri = DAV\URLUtil::encodePath($this->href); + + // Adding the baseurl to the beginning of the url + $uri = $server->getBaseUri() . $uri; + + $xresponse->appendChild($document->createElement('d:href',$uri)); + + // The properties variable is an array containing properties, grouped by + // HTTP status + foreach($properties as $httpStatus=>$propertyGroup) { + + // The 'href' is also in this array, and it's special cased. + // We will ignore it + if ($httpStatus=='href') continue; + + // If there are no properties in this group, we can also just carry on + if (!count($propertyGroup)) continue; + + $xpropstat = $document->createElement('d:propstat'); + $xresponse->appendChild($xpropstat); + + $xprop = $document->createElement('d:prop'); + $xpropstat->appendChild($xprop); + + $nsList = $server->xmlNamespaces; + + foreach($propertyGroup as $propertyName=>$propertyValue) { + + $propName = null; + preg_match('/^{([^}]*)}(.*)$/',$propertyName,$propName); + + // special case for empty namespaces + if ($propName[1]=='') { + + $currentProperty = $document->createElement($propName[2]); + $xprop->appendChild($currentProperty); + $currentProperty->setAttribute('xmlns',''); + + } else { + + if (!isset($nsList[$propName[1]])) { + $nsList[$propName[1]] = 'x' . count($nsList); + } + + // If the namespace was defined in the top-level xml namespaces, it means + // there was already a namespace declaration, and we don't have to worry about it. + if (isset($server->xmlNamespaces[$propName[1]])) { + $currentProperty = $document->createElement($nsList[$propName[1]] . ':' . $propName[2]); + } else { + $currentProperty = $document->createElementNS($propName[1],$nsList[$propName[1]].':' . $propName[2]); + } + $xprop->appendChild($currentProperty); + + } + + if (is_scalar($propertyValue)) { + $text = $document->createTextNode($propertyValue); + $currentProperty->appendChild($text); + } elseif ($propertyValue instanceof DAV\PropertyInterface) { + $propertyValue->serialize($server,$currentProperty); + } elseif (!is_null($propertyValue)) { + throw new DAV\Exception('Unknown property value type: ' . gettype($propertyValue) . ' for property: ' . $propertyName); + } + + } + + $xpropstat->appendChild($document->createElement('d:status',$server->httpResponse->getStatusMessage($httpStatus))); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResponseList.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResponseList.php new file mode 100644 index 00000000..9db6cbbf --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/ResponseList.php @@ -0,0 +1,59 @@ +responses = $responses; + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $dom + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $dom) { + + foreach($this->responses as $response) { + $response->serialize($server, $dom); + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedLock.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedLock.php new file mode 100644 index 00000000..035c2f33 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedLock.php @@ -0,0 +1,78 @@ +supportsLocks = $supportsLocks; + + } + + /** + * serialize + * + * @param DAV\Server $server + * @param \DOMElement $prop + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $prop) { + + $doc = $prop->ownerDocument; + + if (!$this->supportsLocks) return null; + + $lockEntry1 = $doc->createElement('d:lockentry'); + $lockEntry2 = $doc->createElement('d:lockentry'); + + $prop->appendChild($lockEntry1); + $prop->appendChild($lockEntry2); + + $lockScope1 = $doc->createElement('d:lockscope'); + $lockScope2 = $doc->createElement('d:lockscope'); + $lockType1 = $doc->createElement('d:locktype'); + $lockType2 = $doc->createElement('d:locktype'); + + $lockEntry1->appendChild($lockScope1); + $lockEntry1->appendChild($lockType1); + $lockEntry2->appendChild($lockScope2); + $lockEntry2->appendChild($lockType2); + + $lockScope1->appendChild($doc->createElement('d:exclusive')); + $lockScope2->appendChild($doc->createElement('d:shared')); + + $lockType1->appendChild($doc->createElement('d:write')); + $lockType2->appendChild($doc->createElement('d:write')); + + //$frag->appendXML(''); + //$frag->appendXML(''); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedReportSet.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedReportSet.php new file mode 100644 index 00000000..a8a90bb1 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Property/SupportedReportSet.php @@ -0,0 +1,111 @@ +addReport($reports); + + } + + /** + * Adds a report to this property + * + * The report must be a string in clark-notation. + * Multiple reports can be specified as an array. + * + * @param mixed $report + * @return void + */ + public function addReport($report) { + + if (!is_array($report)) $report = array($report); + + foreach($report as $r) { + + if (!preg_match('/^{([^}]*)}(.*)$/',$r)) + throw new DAV\Exception('Reportname must be in clark-notation'); + + $this->reports[] = $r; + + } + + } + + /** + * Returns the list of supported reports + * + * @return array + */ + public function getValue() { + + return $this->reports; + + } + + /** + * Serializes the node + * + * @param DAV\Server $server + * @param \DOMElement $prop + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $prop) { + + foreach($this->reports as $reportName) { + + $supportedReport = $prop->ownerDocument->createElement('d:supported-report'); + $prop->appendChild($supportedReport); + + $report = $prop->ownerDocument->createElement('d:report'); + $supportedReport->appendChild($report); + + preg_match('/^{([^}]*)}(.*)$/',$reportName,$matches); + + list(, $namespace, $element) = $matches; + + $prefix = isset($server->xmlNamespaces[$namespace])?$server->xmlNamespaces[$namespace]:null; + + if ($prefix) { + $report->appendChild($prop->ownerDocument->createElement($prefix . ':' . $element)); + } else { + $report->appendChild($prop->ownerDocument->createElementNS($namespace, 'x:' . $element)); + } + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/PropertyInterface.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/PropertyInterface.php new file mode 100644 index 00000000..2fb0d7db --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/PropertyInterface.php @@ -0,0 +1,21 @@ + 'd', + 'http://sabredav.org/ns' => 's', + ); + + /** + * The propertymap can be used to map properties from + * requests to property classes. + * + * @var array + */ + public $propertyMap = array( + '{DAV:}resourcetype' => 'Sabre\\DAV\\Property\\ResourceType', + ); + + public $protectedProperties = array( + // RFC4918 + '{DAV:}getcontentlength', + '{DAV:}getetag', + '{DAV:}getlastmodified', + '{DAV:}lockdiscovery', + '{DAV:}supportedlock', + + // RFC4331 + '{DAV:}quota-available-bytes', + '{DAV:}quota-used-bytes', + + // RFC3744 + '{DAV:}supported-privilege-set', + '{DAV:}current-user-privilege-set', + '{DAV:}acl', + '{DAV:}acl-restrictions', + '{DAV:}inherited-acl-set', + + ); + + /** + * This is a flag that allow or not showing file, line and code + * of the exception in the returned XML + * + * @var bool + */ + public $debugExceptions = false; + + /** + * This property allows you to automatically add the 'resourcetype' value + * based on a node's classname or interface. + * + * The preset ensures that {DAV:}collection is automaticlly added for nodes + * implementing Sabre\DAV\ICollection. + * + * @var array + */ + public $resourceTypeMapping = array( + 'Sabre\\DAV\\ICollection' => '{DAV:}collection', + ); + + /** + * If this setting is turned off, SabreDAV's version number will be hidden + * from various places. + * + * Some people feel this is a good security measure. + * + * @var bool + */ + static public $exposeVersion = true; + + /** + * Sets up the server + * + * If a Sabre\DAV\Tree object is passed as an argument, it will + * use it as the directory tree. If a Sabre\DAV\INode is passed, it + * will create a Sabre\DAV\ObjectTree and use the node as the root. + * + * If nothing is passed, a Sabre\DAV\SimpleCollection is created in + * a Sabre\DAV\ObjectTree. + * + * If an array is passed, we automatically create a root node, and use + * the nodes in the array as top-level children. + * + * @param Tree|INode|array|null $treeOrNode The tree object + */ + public function __construct($treeOrNode = null) { + + if ($treeOrNode instanceof Tree) { + $this->tree = $treeOrNode; + } elseif ($treeOrNode instanceof INode) { + $this->tree = new ObjectTree($treeOrNode); + } elseif (is_array($treeOrNode)) { + + // If it's an array, a list of nodes was passed, and we need to + // create the root node. + foreach($treeOrNode as $node) { + if (!($node instanceof INode)) { + throw new Exception('Invalid argument passed to constructor. If you\'re passing an array, all the values must implement Sabre\\DAV\\INode'); + } + } + + $root = new SimpleCollection('root', $treeOrNode); + $this->tree = new ObjectTree($root); + + } elseif (is_null($treeOrNode)) { + $root = new SimpleCollection('root'); + $this->tree = new ObjectTree($root); + } else { + throw new Exception('Invalid argument passed to constructor. Argument must either be an instance of Sabre\\DAV\\Tree, Sabre\\DAV\\INode, an array or null'); + } + $this->httpResponse = new HTTP\Response(); + $this->httpRequest = new HTTP\Request(); + + } + + /** + * Starts the DAV Server + * + * @return void + */ + public function exec() { + + try { + + // If nginx (pre-1.2) is used as a proxy server, and SabreDAV as an + // origin, we must make sure we send back HTTP/1.0 if this was + // requested. + // This is mainly because nginx doesn't support Chunked Transfer + // Encoding, and this forces the webserver SabreDAV is running on, + // to buffer entire responses to calculate Content-Length. + $this->httpResponse->defaultHttpVersion = $this->httpRequest->getHTTPVersion(); + + $this->invokeMethod($this->httpRequest->getMethod(), $this->getRequestUri()); + + } catch (Exception $e) { + + try { + $this->broadcastEvent('exception', array($e)); + } catch (Exception $ignore) { + } + $DOM = new \DOMDocument('1.0','utf-8'); + $DOM->formatOutput = true; + + $error = $DOM->createElementNS('DAV:','d:error'); + $error->setAttribute('xmlns:s',self::NS_SABREDAV); + $DOM->appendChild($error); + + $h = function($v) { + + return htmlspecialchars($v, ENT_NOQUOTES, 'UTF-8'); + + }; + + $error->appendChild($DOM->createElement('s:exception',$h(get_class($e)))); + $error->appendChild($DOM->createElement('s:message',$h($e->getMessage()))); + if ($this->debugExceptions) { + $error->appendChild($DOM->createElement('s:file',$h($e->getFile()))); + $error->appendChild($DOM->createElement('s:line',$h($e->getLine()))); + $error->appendChild($DOM->createElement('s:code',$h($e->getCode()))); + $error->appendChild($DOM->createElement('s:stacktrace',$h($e->getTraceAsString()))); + + } + if (self::$exposeVersion) { + $error->appendChild($DOM->createElement('s:sabredav-version',$h(Version::VERSION))); + } + + if($e instanceof Exception) { + + $httpCode = $e->getHTTPCode(); + $e->serialize($this,$error); + $headers = $e->getHTTPHeaders($this); + + } else { + + $httpCode = 500; + $headers = array(); + + } + $headers['Content-Type'] = 'application/xml; charset=utf-8'; + + $this->httpResponse->sendStatus($httpCode); + $this->httpResponse->setHeaders($headers); + $this->httpResponse->sendBody($DOM->saveXML()); + + } + + } + + /** + * Sets the base server uri + * + * @param string $uri + * @return void + */ + public function setBaseUri($uri) { + + // If the baseUri does not end with a slash, we must add it + if ($uri[strlen($uri)-1]!=='/') + $uri.='/'; + + $this->baseUri = $uri; + + } + + /** + * Returns the base responding uri + * + * @return string + */ + public function getBaseUri() { + + if (is_null($this->baseUri)) $this->baseUri = $this->guessBaseUri(); + return $this->baseUri; + + } + + /** + * This method attempts to detect the base uri. + * Only the PATH_INFO variable is considered. + * + * If this variable is not set, the root (/) is assumed. + * + * @return string + */ + public function guessBaseUri() { + + $pathInfo = $this->httpRequest->getRawServerValue('PATH_INFO'); + $uri = $this->httpRequest->getRawServerValue('REQUEST_URI'); + + // If PATH_INFO is found, we can assume it's accurate. + if (!empty($pathInfo)) { + + // We need to make sure we ignore the QUERY_STRING part + if ($pos = strpos($uri,'?')) + $uri = substr($uri,0,$pos); + + // PATH_INFO is only set for urls, such as: /example.php/path + // in that case PATH_INFO contains '/path'. + // Note that REQUEST_URI is percent encoded, while PATH_INFO is + // not, Therefore they are only comparable if we first decode + // REQUEST_INFO as well. + $decodedUri = URLUtil::decodePath($uri); + + // A simple sanity check: + if(substr($decodedUri,strlen($decodedUri)-strlen($pathInfo))===$pathInfo) { + $baseUri = substr($decodedUri,0,strlen($decodedUri)-strlen($pathInfo)); + return rtrim($baseUri,'/') . '/'; + } + + throw new Exception('The REQUEST_URI ('. $uri . ') did not end with the contents of PATH_INFO (' . $pathInfo . '). This server might be misconfigured.'); + + } + + // The last fallback is that we're just going to assume the server root. + return '/'; + + } + + /** + * Adds a plugin to the server + * + * For more information, console the documentation of Sabre\DAV\ServerPlugin + * + * @param ServerPlugin $plugin + * @return void + */ + public function addPlugin(ServerPlugin $plugin) { + + $this->plugins[$plugin->getPluginName()] = $plugin; + $plugin->initialize($this); + + } + + /** + * Returns an initialized plugin by it's name. + * + * This function returns null if the plugin was not found. + * + * @param string $name + * @return ServerPlugin + */ + public function getPlugin($name) { + + if (isset($this->plugins[$name])) + return $this->plugins[$name]; + + // This is a fallback and deprecated. + foreach($this->plugins as $plugin) { + if (get_class($plugin)===$name) return $plugin; + } + + return null; + + } + + /** + * Returns all plugins + * + * @return array + */ + public function getPlugins() { + + return $this->plugins; + + } + + + /** + * Subscribe to an event. + * + * When the event is triggered, we'll call all the specified callbacks. + * It is possible to control the order of the callbacks through the + * priority argument. + * + * This is for example used to make sure that the authentication plugin + * is triggered before anything else. If it's not needed to change this + * number, it is recommended to ommit. + * + * @param string $event + * @param callback $callback + * @param int $priority + * @return void + */ + public function subscribeEvent($event, $callback, $priority = 100) { + + if (!isset($this->eventSubscriptions[$event])) { + $this->eventSubscriptions[$event] = array(); + } + while(isset($this->eventSubscriptions[$event][$priority])) $priority++; + $this->eventSubscriptions[$event][$priority] = $callback; + ksort($this->eventSubscriptions[$event]); + + } + + /** + * Broadcasts an event + * + * This method will call all subscribers. If one of the subscribers returns false, the process stops. + * + * The arguments parameter will be sent to all subscribers + * + * @param string $eventName + * @param array $arguments + * @return bool + */ + public function broadcastEvent($eventName,$arguments = array()) { + + if (isset($this->eventSubscriptions[$eventName])) { + + foreach($this->eventSubscriptions[$eventName] as $subscriber) { + + $result = call_user_func_array($subscriber,$arguments); + if ($result===false) return false; + + } + + } + + return true; + + } + + /** + * Handles a http request, and execute a method based on its name + * + * @param string $method + * @param string $uri + * @return void + */ + public function invokeMethod($method, $uri) { + + $method = strtoupper($method); + + if (!$this->broadcastEvent('beforeMethod',array($method, $uri))) return; + + // Make sure this is a HTTP method we support + $internalMethods = array( + 'OPTIONS', + 'GET', + 'HEAD', + 'DELETE', + 'PROPFIND', + 'MKCOL', + 'PUT', + 'PROPPATCH', + 'COPY', + 'MOVE', + 'REPORT' + ); + + if (in_array($method,$internalMethods)) { + + call_user_func(array($this,'http' . $method), $uri); + + } else { + + if ($this->broadcastEvent('unknownMethod',array($method, $uri))) { + // Unsupported method + throw new Exception\NotImplemented('There was no handler found for this "' . $method . '" method'); + } + + } + + } + + // {{{ HTTP Method implementations + + /** + * HTTP OPTIONS + * + * @param string $uri + * @return void + */ + protected function httpOptions($uri) { + + $methods = $this->getAllowedMethods($uri); + + $this->httpResponse->setHeader('Allow',strtoupper(implode(', ',$methods))); + $features = array('1','3', 'extended-mkcol'); + + foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures()); + + $this->httpResponse->setHeader('DAV',implode(', ',$features)); + $this->httpResponse->setHeader('MS-Author-Via','DAV'); + $this->httpResponse->setHeader('Accept-Ranges','bytes'); + if (self::$exposeVersion) { + $this->httpResponse->setHeader('X-Sabre-Version',Version::VERSION); + } + $this->httpResponse->setHeader('Content-Length',0); + $this->httpResponse->sendStatus(200); + + } + + /** + * HTTP GET + * + * This method simply fetches the contents of a uri, like normal + * + * @param string $uri + * @return bool + */ + protected function httpGet($uri) { + + $node = $this->tree->getNodeForPath($uri,0); + + if (!$this->checkPreconditions(true)) return false; + if (!$node instanceof IFile) throw new Exception\NotImplemented('GET is only implemented on File objects'); + + $body = $node->get(); + + // Converting string into stream, if needed. + if (is_string($body)) { + $stream = fopen('php://temp','r+'); + fwrite($stream,$body); + rewind($stream); + $body = $stream; + } + + /* + * TODO: getetag, getlastmodified, getsize should also be used using + * this method + */ + $httpHeaders = $this->getHTTPHeaders($uri); + + /* ContentType needs to get a default, because many webservers will otherwise + * default to text/html, and we don't want this for security reasons. + */ + if (!isset($httpHeaders['Content-Type'])) { + $httpHeaders['Content-Type'] = 'application/octet-stream'; + } + + + if (isset($httpHeaders['Content-Length'])) { + + $nodeSize = $httpHeaders['Content-Length']; + + // Need to unset Content-Length, because we'll handle that during figuring out the range + unset($httpHeaders['Content-Length']); + + } else { + $nodeSize = null; + } + + $this->httpResponse->setHeaders($httpHeaders); + + $range = $this->getHTTPRange(); + $ifRange = $this->httpRequest->getHeader('If-Range'); + $ignoreRangeHeader = false; + + // If ifRange is set, and range is specified, we first need to check + // the precondition. + if ($nodeSize && $range && $ifRange) { + + // if IfRange is parsable as a date we'll treat it as a DateTime + // otherwise, we must treat it as an etag. + try { + $ifRangeDate = new \DateTime($ifRange); + + // It's a date. We must check if the entity is modified since + // the specified date. + if (!isset($httpHeaders['Last-Modified'])) $ignoreRangeHeader = true; + else { + $modified = new \DateTime($httpHeaders['Last-Modified']); + if($modified > $ifRangeDate) $ignoreRangeHeader = true; + } + + } catch (\Exception $e) { + + // It's an entity. We can do a simple comparison. + if (!isset($httpHeaders['ETag'])) $ignoreRangeHeader = true; + elseif ($httpHeaders['ETag']!==$ifRange) $ignoreRangeHeader = true; + } + } + + // We're only going to support HTTP ranges if the backend provided a filesize + if (!$ignoreRangeHeader && $nodeSize && $range) { + + // Determining the exact byte offsets + if (!is_null($range[0])) { + + $start = $range[0]; + $end = $range[1]?$range[1]:$nodeSize-1; + if($start >= $nodeSize) + throw new Exception\RequestedRangeNotSatisfiable('The start offset (' . $range[0] . ') exceeded the size of the entity (' . $nodeSize . ')'); + + if($end < $start) throw new Exception\RequestedRangeNotSatisfiable('The end offset (' . $range[1] . ') is lower than the start offset (' . $range[0] . ')'); + if($end >= $nodeSize) $end = $nodeSize-1; + + } else { + + $start = $nodeSize-$range[1]; + $end = $nodeSize-1; + + if ($start<0) $start = 0; + + } + + // New read/write stream + $newStream = fopen('php://temp','r+'); + + // stream_copy_to_stream() has a bug/feature: the `whence` argument + // is interpreted as SEEK_SET (count from absolute offset 0), while + // for a stream it should be SEEK_CUR (count from current offset). + // If a stream is nonseekable, the function fails. So we *emulate* + // the correct behaviour with fseek(): + if ($start > 0) { + if (($curOffs = ftell($body)) === false) $curOffs = 0; + fseek($body, $start - $curOffs, SEEK_CUR); + } + stream_copy_to_stream($body, $newStream, $end-$start+1); + rewind($newStream); + + $this->httpResponse->setHeader('Content-Length', $end-$start+1); + $this->httpResponse->setHeader('Content-Range','bytes ' . $start . '-' . $end . '/' . $nodeSize); + $this->httpResponse->sendStatus(206); + $this->httpResponse->sendBody($newStream); + + + } else { + + if ($nodeSize) $this->httpResponse->setHeader('Content-Length',$nodeSize); + $this->httpResponse->sendStatus(200); + $this->httpResponse->sendBody($body); + + } + + } + + /** + * HTTP HEAD + * + * This method is normally used to take a peak at a url, and only get the HTTP response headers, without the body + * This is used by clients to determine if a remote file was changed, so they can use a local cached version, instead of downloading it again + * + * @param string $uri + * @return void + */ + protected function httpHead($uri) { + + $node = $this->tree->getNodeForPath($uri); + /* This information is only collection for File objects. + * Ideally we want to throw 405 Method Not Allowed for every + * non-file, but MS Office does not like this + */ + if ($node instanceof IFile) { + $headers = $this->getHTTPHeaders($this->getRequestUri()); + if (!isset($headers['Content-Type'])) { + $headers['Content-Type'] = 'application/octet-stream'; + } + $this->httpResponse->setHeaders($headers); + } + $this->httpResponse->sendStatus(200); + + } + + /** + * HTTP Delete + * + * The HTTP delete method, deletes a given uri + * + * @param string $uri + * @return void + */ + protected function httpDelete($uri) { + + // Checking If-None-Match and related headers. + if (!$this->checkPreconditions()) return; + + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return; + $this->tree->delete($uri); + $this->broadcastEvent('afterUnbind',array($uri)); + + $this->httpResponse->sendStatus(204); + $this->httpResponse->setHeader('Content-Length','0'); + + } + + + /** + * WebDAV PROPFIND + * + * This WebDAV method requests information about an uri resource, or a list of resources + * If a client wants to receive the properties for a single resource it will add an HTTP Depth: header with a 0 value + * If the value is 1, it means that it also expects a list of sub-resources (e.g.: files in a directory) + * + * The request body contains an XML data structure that has a list of properties the client understands + * The response body is also an xml document, containing information about every uri resource and the requested properties + * + * It has to return a HTTP 207 Multi-status status code + * + * @param string $uri + * @return void + */ + protected function httpPropfind($uri) { + + $requestedProperties = $this->parsePropFindRequest($this->httpRequest->getBody(true)); + + $depth = $this->getHTTPDepth(1); + // The only two options for the depth of a propfind is 0 or 1 + if ($depth!=0) $depth = 1; + + $newProperties = $this->getPropertiesForPath($uri,$requestedProperties,$depth); + + // This is a multi-status response + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->httpResponse->setHeader('Vary','Brief,Prefer'); + + // Normally this header is only needed for OPTIONS responses, however.. + // iCal seems to also depend on these being set for PROPFIND. Since + // this is not harmful, we'll add it. + $features = array('1','3', 'extended-mkcol'); + foreach($this->plugins as $plugin) $features = array_merge($features,$plugin->getFeatures()); + $this->httpResponse->setHeader('DAV',implode(', ',$features)); + + $prefer = $this->getHTTPPrefer(); + $minimal = $prefer['return-minimal']; + + $data = $this->generateMultiStatus($newProperties, $minimal); + $this->httpResponse->sendBody($data); + + } + + /** + * WebDAV PROPPATCH + * + * This method is called to update properties on a Node. The request is an XML body with all the mutations. + * In this XML body it is specified which properties should be set/updated and/or deleted + * + * @param string $uri + * @return void + */ + protected function httpPropPatch($uri) { + + $newProperties = $this->parsePropPatchRequest($this->httpRequest->getBody(true)); + + $result = $this->updateProperties($uri, $newProperties); + + $prefer = $this->getHTTPPrefer(); + $this->httpResponse->setHeader('Vary','Brief,Prefer'); + + if ($prefer['return-minimal']) { + + // If return-minimal is specified, we only have to check if the + // request was succesful, and don't need to return the + // multi-status. + $ok = true; + foreach($result as $code=>$prop) { + if ((int)$code > 299) { + $ok = false; + } + } + + if ($ok) { + + $this->httpResponse->sendStatus(204); + return; + + } + + } + + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + + $this->httpResponse->sendBody( + $this->generateMultiStatus(array($result)) + ); + + } + + /** + * HTTP PUT method + * + * This HTTP method updates a file, or creates a new one. + * + * If a new resource was created, a 201 Created status code should be returned. If an existing resource is updated, it's a 204 No Content + * + * @param string $uri + * @return bool + */ + protected function httpPut($uri) { + + $body = $this->httpRequest->getBody(); + + // Intercepting Content-Range + if ($this->httpRequest->getHeader('Content-Range')) { + /** + Content-Range is dangerous for PUT requests: PUT per definition + stores a full resource. draft-ietf-httpbis-p2-semantics-15 says + in section 7.6: + An origin server SHOULD reject any PUT request that contains a + Content-Range header field, since it might be misinterpreted as + partial content (or might be partial content that is being mistakenly + PUT as a full representation). Partial content updates are possible + by targeting a separately identified resource with state that + overlaps a portion of the larger resource, or by using a different + method that has been specifically defined for partial updates (for + example, the PATCH method defined in [RFC5789]). + This clarifies RFC2616 section 9.6: + 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. + OTOH is a PUT request with a Content-Range currently the only way to + continue an aborted upload request and is supported by curl, mod_dav, + Tomcat and others. Since some clients do use this feature which results + in unexpected behaviour (cf PEAR::HTTP_WebDAV_Client 1.0.1), we reject + all PUT requests with a Content-Range for now. + */ + + throw new Exception\NotImplemented('PUT with Content-Range is not allowed.'); + } + + // Intercepting the Finder problem + if (($expected = $this->httpRequest->getHeader('X-Expected-Entity-Length')) && $expected > 0) { + + /** + Many webservers will not cooperate well with Finder PUT requests, + because it uses 'Chunked' transfer encoding for the request body. + + The symptom of this problem is that Finder sends files to the + server, but they arrive as 0-length files in PHP. + + If we don't do anything, the user might think they are uploading + files successfully, but they end up empty on the server. Instead, + we throw back an error if we detect this. + + The reason Finder uses Chunked, is because it thinks the files + might change as it's being uploaded, and therefore the + Content-Length can vary. + + Instead it sends the X-Expected-Entity-Length header with the size + of the file at the very start of the request. If this header is set, + but we don't get a request body we will fail the request to + protect the end-user. + */ + + // Only reading first byte + $firstByte = fread($body,1); + if (strlen($firstByte)!==1) { + throw new Exception\Forbidden('This server is not compatible with OS/X finder. Consider using a different WebDAV client or webserver.'); + } + + // The body needs to stay intact, so we copy everything to a + // temporary stream. + + $newBody = fopen('php://temp','r+'); + fwrite($newBody,$firstByte); + stream_copy_to_stream($body, $newBody); + rewind($newBody); + + $body = $newBody; + + } + + // Checking If-None-Match and related headers. + if (!$this->checkPreconditions()) return; + + if ($this->tree->nodeExists($uri)) { + + $node = $this->tree->getNodeForPath($uri); + + // If the node is a collection, we'll deny it + if (!($node instanceof IFile)) throw new Exception\Conflict('PUT is not allowed on non-files.'); + if (!$this->broadcastEvent('beforeWriteContent',array($uri, $node, &$body))) return false; + + $etag = $node->put($body); + + $this->broadcastEvent('afterWriteContent',array($uri, $node)); + + $this->httpResponse->setHeader('Content-Length','0'); + if ($etag) $this->httpResponse->setHeader('ETag',$etag); + $this->httpResponse->sendStatus(204); + + } else { + + $etag = null; + // If we got here, the resource didn't exist yet. + if (!$this->createFile($this->getRequestUri(),$body,$etag)) { + // For one reason or another the file was not created. + return; + } + + $this->httpResponse->setHeader('Content-Length','0'); + if ($etag) $this->httpResponse->setHeader('ETag', $etag); + $this->httpResponse->sendStatus(201); + + } + + } + + + /** + * WebDAV MKCOL + * + * The MKCOL method is used to create a new collection (directory) on the server + * + * @param string $uri + * @return void + */ + protected function httpMkcol($uri) { + + $requestBody = $this->httpRequest->getBody(true); + + if ($requestBody) { + + $contentType = $this->httpRequest->getHeader('Content-Type'); + if (strpos($contentType,'application/xml')!==0 && strpos($contentType,'text/xml')!==0) { + + // We must throw 415 for unsupported mkcol bodies + throw new Exception\UnsupportedMediaType('The request body for the MKCOL request must have an xml Content-Type'); + + } + + $dom = XMLUtil::loadDOMDocument($requestBody); + if (XMLUtil::toClarkNotation($dom->firstChild)!=='{DAV:}mkcol') { + + // We must throw 415 for unsupported mkcol bodies + throw new Exception\UnsupportedMediaType('The request body for the MKCOL request must be a {DAV:}mkcol request construct.'); + + } + + $properties = array(); + foreach($dom->firstChild->childNodes as $childNode) { + + if (XMLUtil::toClarkNotation($childNode)!=='{DAV:}set') continue; + $properties = array_merge($properties, XMLUtil::parseProperties($childNode, $this->propertyMap)); + + } + if (!isset($properties['{DAV:}resourcetype'])) + throw new Exception\BadRequest('The mkcol request must include a {DAV:}resourcetype property'); + + $resourceType = $properties['{DAV:}resourcetype']->getValue(); + unset($properties['{DAV:}resourcetype']); + + } else { + + $properties = array(); + $resourceType = array('{DAV:}collection'); + + } + + $result = $this->createCollection($uri, $resourceType, $properties); + + if (is_array($result)) { + $this->httpResponse->sendStatus(207); + $this->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + + $this->httpResponse->sendBody( + $this->generateMultiStatus(array($result)) + ); + + } else { + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus(201); + } + + } + + /** + * WebDAV HTTP MOVE method + * + * This method moves one uri to a different uri. A lot of the actual request processing is done in getCopyMoveInfo + * + * @param string $uri + * @return bool + */ + protected function httpMove($uri) { + + $moveInfo = $this->getCopyAndMoveInfo(); + + // If the destination is part of the source tree, we must fail + if ($moveInfo['destination']==$uri) + throw new Exception\Forbidden('Source and destination uri are identical.'); + + if ($moveInfo['destinationExists']) { + + if (!$this->broadcastEvent('beforeUnbind',array($moveInfo['destination']))) return false; + $this->tree->delete($moveInfo['destination']); + $this->broadcastEvent('afterUnbind',array($moveInfo['destination'])); + + } + + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return false; + if (!$this->broadcastEvent('beforeBind',array($moveInfo['destination']))) return false; + $this->tree->move($uri,$moveInfo['destination']); + $this->broadcastEvent('afterUnbind',array($uri)); + $this->broadcastEvent('afterBind',array($moveInfo['destination'])); + + // If a resource was overwritten we should send a 204, otherwise a 201 + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus($moveInfo['destinationExists']?204:201); + + } + + /** + * WebDAV HTTP COPY method + * + * This method copies one uri to a different uri, and works much like the MOVE request + * A lot of the actual request processing is done in getCopyMoveInfo + * + * @param string $uri + * @return bool + */ + protected function httpCopy($uri) { + + $copyInfo = $this->getCopyAndMoveInfo(); + // If the destination is part of the source tree, we must fail + if ($copyInfo['destination']==$uri) + throw new Exception\Forbidden('Source and destination uri are identical.'); + + if ($copyInfo['destinationExists']) { + if (!$this->broadcastEvent('beforeUnbind',array($copyInfo['destination']))) return false; + $this->tree->delete($copyInfo['destination']); + + } + if (!$this->broadcastEvent('beforeBind',array($copyInfo['destination']))) return false; + $this->tree->copy($uri,$copyInfo['destination']); + $this->broadcastEvent('afterBind',array($copyInfo['destination'])); + + // If a resource was overwritten we should send a 204, otherwise a 201 + $this->httpResponse->setHeader('Content-Length','0'); + $this->httpResponse->sendStatus($copyInfo['destinationExists']?204:201); + + } + + + + /** + * HTTP REPORT method implementation + * + * Although the REPORT method is not part of the standard WebDAV spec (it's from rfc3253) + * It's used in a lot of extensions, so it made sense to implement it into the core. + * + * @param string $uri + * @return void + */ + protected function httpReport($uri) { + + $body = $this->httpRequest->getBody(true); + $dom = XMLUtil::loadDOMDocument($body); + + $reportName = XMLUtil::toClarkNotation($dom->firstChild); + + if ($this->broadcastEvent('report',array($reportName,$dom, $uri))) { + + // If broadcastEvent returned true, it means the report was not supported + throw new Exception\ReportNotSupported(); + + } + + } + + // }}} + // {{{ HTTP/WebDAV protocol helpers + + /** + * Returns an array with all the supported HTTP methods for a specific uri. + * + * @param string $uri + * @return array + */ + public function getAllowedMethods($uri) { + + $methods = array( + 'OPTIONS', + 'GET', + 'HEAD', + 'DELETE', + 'PROPFIND', + 'PUT', + 'PROPPATCH', + 'COPY', + 'MOVE', + 'REPORT' + ); + + // The MKCOL is only allowed on an unmapped uri + try { + $this->tree->getNodeForPath($uri); + } catch (Exception\NotFound $e) { + $methods[] = 'MKCOL'; + } + + // We're also checking if any of the plugins register any new methods + foreach($this->plugins as $plugin) $methods = array_merge($methods, $plugin->getHTTPMethods($uri)); + array_unique($methods); + + return $methods; + + } + + /** + * Gets the uri for the request, keeping the base uri into consideration + * + * @return string + */ + public function getRequestUri() { + + return $this->calculateUri($this->httpRequest->getUri()); + + } + + /** + * Calculates the uri for a request, making sure that the base uri is stripped out + * + * @param string $uri + * @throws Exception\Forbidden A permission denied exception is thrown whenever there was an attempt to supply a uri outside of the base uri + * @return string + */ + public function calculateUri($uri) { + + if ($uri[0]!='/' && strpos($uri,'://')) { + + $uri = parse_url($uri,PHP_URL_PATH); + + } + + $uri = str_replace('//','/',$uri); + + if (strpos($uri,$this->getBaseUri())===0) { + + return trim(URLUtil::decodePath(substr($uri,strlen($this->getBaseUri()))),'/'); + + // A special case, if the baseUri was accessed without a trailing + // slash, we'll accept it as well. + } elseif ($uri.'/' === $this->getBaseUri()) { + + return ''; + + } else { + + throw new Exception\Forbidden('Requested uri (' . $uri . ') is out of base uri (' . $this->getBaseUri() . ')'); + + } + + } + + /** + * Returns the HTTP depth header + * + * This method returns the contents of the HTTP depth request header. If the depth header was 'infinity' it will return the Sabre\DAV\Server::DEPTH_INFINITY object + * It is possible to supply a default depth value, which is used when the depth header has invalid content, or is completely non-existent + * + * @param mixed $default + * @return int + */ + public function getHTTPDepth($default = self::DEPTH_INFINITY) { + + // If its not set, we'll grab the default + $depth = $this->httpRequest->getHeader('Depth'); + + if (is_null($depth)) return $default; + + if ($depth == 'infinity') return self::DEPTH_INFINITY; + + + // If its an unknown value. we'll grab the default + if (!ctype_digit($depth)) return $default; + + return (int)$depth; + + } + + /** + * Returns the HTTP range header + * + * This method returns null if there is no well-formed HTTP range request + * header or array($start, $end). + * + * The first number is the offset of the first byte in the range. + * The second number is the offset of the last byte in the range. + * + * If the second offset is null, it should be treated as the offset of the last byte of the entity + * If the first offset is null, the second offset should be used to retrieve the last x bytes of the entity + * + * @return array|null + */ + public function getHTTPRange() { + + $range = $this->httpRequest->getHeader('range'); + if (is_null($range)) return null; + + // Matching "Range: bytes=1234-5678: both numbers are optional + + if (!preg_match('/^bytes=([0-9]*)-([0-9]*)$/i',$range,$matches)) return null; + + if ($matches[1]==='' && $matches[2]==='') return null; + + return array( + $matches[1]!==''?$matches[1]:null, + $matches[2]!==''?$matches[2]:null, + ); + + } + + /** + * Returns the HTTP Prefer header information. + * + * The prefer header is defined in: + * http://tools.ietf.org/html/draft-snell-http-prefer-14 + * + * This method will return an array with options. + * + * Currently, the following options may be returned: + * array( + * 'return-asynch' => true, + * 'return-minimal' => true, + * 'return-representation' => true, + * 'wait' => 30, + * 'strict' => true, + * 'lenient' => true, + * ) + * + * This method also supports the Brief header, and will also return + * 'return-minimal' if the brief header was set to 't'. + * + * For the boolean options, false will be returned if the headers are not + * specified. For the integer options it will be 'null'. + * + * @return array + */ + public function getHTTPPrefer() { + + $result = array( + 'return-asynch' => false, + 'return-minimal' => false, + 'return-representation' => false, + 'wait' => null, + 'strict' => false, + 'lenient' => false, + ); + + if ($prefer = $this->httpRequest->getHeader('Prefer')) { + + $parameters = array_map('trim', + explode(',', $prefer) + ); + + foreach($parameters as $parameter) { + + // Right now our regex only supports the tokens actually + // specified in the draft. We may need to expand this if new + // tokens get registered. + if(!preg_match('/^(?P[a-z0-9-]+)(?:=(?P[0-9]+))?$/', $parameter, $matches)) { + continue; + } + + switch($matches['token']) { + + case 'return-asynch' : + case 'return-minimal' : + case 'return-representation' : + case 'strict' : + case 'lenient' : + $result[$matches['token']] = true; + break; + case 'wait' : + $result[$matches['token']] = $matches['value']; + break; + + } + + } + + } + + if ($this->httpRequest->getHeader('Brief')=='t') { + $result['return-minimal'] = true; + } + + return $result; + + } + + + /** + * Returns information about Copy and Move requests + * + * This function is created to help getting information about the source and the destination for the + * WebDAV MOVE and COPY HTTP request. It also validates a lot of information and throws proper exceptions + * + * The returned value is an array with the following keys: + * * destination - Destination path + * * destinationExists - Whether or not the destination is an existing url (and should therefore be overwritten) + * + * @return array + */ + public function getCopyAndMoveInfo() { + + // Collecting the relevant HTTP headers + if (!$this->httpRequest->getHeader('Destination')) throw new Exception\BadRequest('The destination header was not supplied'); + $destination = $this->calculateUri($this->httpRequest->getHeader('Destination')); + $overwrite = $this->httpRequest->getHeader('Overwrite'); + if (!$overwrite) $overwrite = 'T'; + if (strtoupper($overwrite)=='T') $overwrite = true; + elseif (strtoupper($overwrite)=='F') $overwrite = false; + // We need to throw a bad request exception, if the header was invalid + else throw new Exception\BadRequest('The HTTP Overwrite header should be either T or F'); + + list($destinationDir) = URLUtil::splitPath($destination); + + try { + $destinationParent = $this->tree->getNodeForPath($destinationDir); + if (!($destinationParent instanceof ICollection)) throw new Exception\UnsupportedMediaType('The destination node is not a collection'); + } catch (Exception\NotFound $e) { + + // If the destination parent node is not found, we throw a 409 + throw new Exception\Conflict('The destination node is not found'); + } + + try { + + $destinationNode = $this->tree->getNodeForPath($destination); + + // If this succeeded, it means the destination already exists + // we'll need to throw precondition failed in case overwrite is false + if (!$overwrite) throw new Exception\PreconditionFailed('The destination node already exists, and the overwrite header is set to false','Overwrite'); + + } catch (Exception\NotFound $e) { + + // Destination didn't exist, we're all good + $destinationNode = false; + + + + } + + // These are the three relevant properties we need to return + return array( + 'destination' => $destination, + 'destinationExists' => $destinationNode==true, + 'destinationNode' => $destinationNode, + ); + + } + + /** + * Returns a list of properties for a path + * + * This is a simplified version getPropertiesForPath. + * if you aren't interested in status codes, but you just + * want to have a flat list of properties. Use this method. + * + * @param string $path + * @param array $propertyNames + */ + public function getProperties($path, $propertyNames) { + + $result = $this->getPropertiesForPath($path,$propertyNames,0); + return $result[0][200]; + + } + + /** + * A kid-friendly way to fetch properties for a node's children. + * + * The returned array will be indexed by the path of the of child node. + * Only properties that are actually found will be returned. + * + * The parent node will not be returned. + * + * @param string $path + * @param array $propertyNames + * @return array + */ + public function getPropertiesForChildren($path, $propertyNames) { + + $result = array(); + foreach($this->getPropertiesForPath($path,$propertyNames,1) as $k=>$row) { + + // Skipping the parent path + if ($k === 0) continue; + + $result[$row['href']] = $row[200]; + + } + return $result; + + } + + /** + * Returns a list of HTTP headers for a particular resource + * + * The generated http headers are based on properties provided by the + * resource. The method basically provides a simple mapping between + * DAV property and HTTP header. + * + * The headers are intended to be used for HEAD and GET requests. + * + * @param string $path + * @return array + */ + public function getHTTPHeaders($path) { + + $propertyMap = array( + '{DAV:}getcontenttype' => 'Content-Type', + '{DAV:}getcontentlength' => 'Content-Length', + '{DAV:}getlastmodified' => 'Last-Modified', + '{DAV:}getetag' => 'ETag', + ); + + $properties = $this->getProperties($path,array_keys($propertyMap)); + + $headers = array(); + foreach($propertyMap as $property=>$header) { + if (!isset($properties[$property])) continue; + + if (is_scalar($properties[$property])) { + $headers[$header] = $properties[$property]; + + // GetLastModified gets special cased + } elseif ($properties[$property] instanceof Property\GetLastModified) { + $headers[$header] = HTTP\Util::toHTTPDate($properties[$property]->getTime()); + } + + } + + return $headers; + + } + + /** + * Returns a list of properties for a given path + * + * The path that should be supplied should have the baseUrl stripped out + * The list of properties should be supplied in Clark notation. If the list is empty + * 'allprops' is assumed. + * + * If a depth of 1 is requested child elements will also be returned. + * + * @param string $path + * @param array $propertyNames + * @param int $depth + * @return array + */ + public function getPropertiesForPath($path, $propertyNames = array(), $depth = 0) { + + if ($depth!=0) $depth = 1; + + $path = rtrim($path,'/'); + + // This event allows people to intercept these requests early on in the + // process. + // + // We're not doing anything with the result, but this can be helpful to + // pre-fetch certain expensive live properties. + $this->broadCastEvent('beforeGetPropertiesForPath', array($path, $propertyNames, $depth)); + + $returnPropertyList = array(); + + $parentNode = $this->tree->getNodeForPath($path); + $nodes = array( + $path => $parentNode + ); + if ($depth==1 && $parentNode instanceof ICollection) { + foreach($this->tree->getChildren($path) as $childNode) + $nodes[$path . '/' . $childNode->getName()] = $childNode; + } + + // If the propertyNames array is empty, it means all properties are requested. + // We shouldn't actually return everything we know though, and only return a + // sensible list. + $allProperties = count($propertyNames)==0; + + foreach($nodes as $myPath=>$node) { + + $currentPropertyNames = $propertyNames; + + $newProperties = array( + '200' => array(), + '404' => array(), + ); + + if ($allProperties) { + // Default list of propertyNames, when all properties were requested. + $currentPropertyNames = array( + '{DAV:}getlastmodified', + '{DAV:}getcontentlength', + '{DAV:}resourcetype', + '{DAV:}quota-used-bytes', + '{DAV:}quota-available-bytes', + '{DAV:}getetag', + '{DAV:}getcontenttype', + ); + } + + // If the resourceType was not part of the list, we manually add it + // and mark it for removal. We need to know the resourcetype in order + // to make certain decisions about the entry. + // WebDAV dictates we should add a / and the end of href's for collections + $removeRT = false; + if (!in_array('{DAV:}resourcetype',$currentPropertyNames)) { + $currentPropertyNames[] = '{DAV:}resourcetype'; + $removeRT = true; + } + + $result = $this->broadcastEvent('beforeGetProperties',array($myPath, $node, &$currentPropertyNames, &$newProperties)); + // If this method explicitly returned false, we must ignore this + // node as it is inaccessible. + if ($result===false) continue; + + if (count($currentPropertyNames) > 0) { + + if ($node instanceof IProperties) { + $nodeProperties = $node->getProperties($currentPropertyNames); + + // The getProperties method may give us too much, + // properties, in case the implementor was lazy. + // + // So as we loop through this list, we will only take the + // properties that were actually requested and discard the + // rest. + foreach($currentPropertyNames as $k=>$currentPropertyName) { + if (isset($nodeProperties[$currentPropertyName])) { + unset($currentPropertyNames[$k]); + $newProperties[200][$currentPropertyName] = $nodeProperties[$currentPropertyName]; + } + } + + } + + } + + foreach($currentPropertyNames as $prop) { + + if (isset($newProperties[200][$prop])) continue; + + switch($prop) { + case '{DAV:}getlastmodified' : if ($node->getLastModified()) $newProperties[200][$prop] = new Property\GetLastModified($node->getLastModified()); break; + case '{DAV:}getcontentlength' : + if ($node instanceof IFile) { + $size = $node->getSize(); + if (!is_null($size)) { + $newProperties[200][$prop] = (int)$node->getSize(); + } + } + break; + case '{DAV:}quota-used-bytes' : + if ($node instanceof IQuota) { + $quotaInfo = $node->getQuotaInfo(); + $newProperties[200][$prop] = $quotaInfo[0]; + } + break; + case '{DAV:}quota-available-bytes' : + if ($node instanceof IQuota) { + $quotaInfo = $node->getQuotaInfo(); + $newProperties[200][$prop] = $quotaInfo[1]; + } + break; + case '{DAV:}getetag' : if ($node instanceof IFile && $etag = $node->getETag()) $newProperties[200][$prop] = $etag; break; + case '{DAV:}getcontenttype' : if ($node instanceof IFile && $ct = $node->getContentType()) $newProperties[200][$prop] = $ct; break; + case '{DAV:}supported-report-set' : + $reports = array(); + foreach($this->plugins as $plugin) { + $reports = array_merge($reports, $plugin->getSupportedReportSet($myPath)); + } + $newProperties[200][$prop] = new Property\SupportedReportSet($reports); + break; + case '{DAV:}resourcetype' : + $newProperties[200]['{DAV:}resourcetype'] = new Property\ResourceType(); + foreach($this->resourceTypeMapping as $className => $resourceType) { + if ($node instanceof $className) $newProperties[200]['{DAV:}resourcetype']->add($resourceType); + } + break; + + } + + // If we were unable to find the property, we will list it as 404. + if (!$allProperties && !isset($newProperties[200][$prop])) $newProperties[404][$prop] = null; + + } + + $this->broadcastEvent('afterGetProperties',array(trim($myPath,'/'),&$newProperties, $node)); + + $newProperties['href'] = trim($myPath,'/'); + + // Its is a WebDAV recommendation to add a trailing slash to collectionnames. + // Apple's iCal also requires a trailing slash for principals (rfc 3744), though this is non-standard. + if ($myPath!='' && isset($newProperties[200]['{DAV:}resourcetype'])) { + $rt = $newProperties[200]['{DAV:}resourcetype']; + if ($rt->is('{DAV:}collection') || $rt->is('{DAV:}principal')) { + $newProperties['href'] .='/'; + } + } + + // If the resourcetype property was manually added to the requested property list, + // we will remove it again. + if ($removeRT) unset($newProperties[200]['{DAV:}resourcetype']); + + $returnPropertyList[] = $newProperties; + + } + + return $returnPropertyList; + + } + + /** + * This method is invoked by sub-systems creating a new file. + * + * Currently this is done by HTTP PUT and HTTP LOCK (in the Locks_Plugin). + * It was important to get this done through a centralized function, + * allowing plugins to intercept this using the beforeCreateFile event. + * + * This method will return true if the file was actually created + * + * @param string $uri + * @param resource $data + * @param string $etag + * @return bool + */ + public function createFile($uri,$data, &$etag = null) { + + list($dir,$name) = URLUtil::splitPath($uri); + + if (!$this->broadcastEvent('beforeBind',array($uri))) return false; + + $parent = $this->tree->getNodeForPath($dir); + if (!$parent instanceof ICollection) { + throw new Exception\Conflict('Files can only be created as children of collections'); + } + + if (!$this->broadcastEvent('beforeCreateFile',array($uri, &$data, $parent))) return false; + + $etag = $parent->createFile($name,$data); + $this->tree->markDirty($dir . '/' . $name); + + $this->broadcastEvent('afterBind',array($uri)); + $this->broadcastEvent('afterCreateFile',array($uri, $parent)); + + return true; + } + + /** + * This method is invoked by sub-systems creating a new directory. + * + * @param string $uri + * @return void + */ + public function createDirectory($uri) { + + $this->createCollection($uri,array('{DAV:}collection'),array()); + + } + + /** + * Use this method to create a new collection + * + * The {DAV:}resourcetype is specified using the resourceType array. + * At the very least it must contain {DAV:}collection. + * + * The properties array can contain a list of additional properties. + * + * @param string $uri The new uri + * @param array $resourceType The resourceType(s) + * @param array $properties A list of properties + * @return array|null + */ + public function createCollection($uri, array $resourceType, array $properties) { + + list($parentUri,$newName) = URLUtil::splitPath($uri); + + // Making sure {DAV:}collection was specified as resourceType + if (!in_array('{DAV:}collection', $resourceType)) { + throw new Exception\InvalidResourceType('The resourceType for this collection must at least include {DAV:}collection'); + } + + + // Making sure the parent exists + try { + + $parent = $this->tree->getNodeForPath($parentUri); + + } catch (Exception\NotFound $e) { + + throw new Exception\Conflict('Parent node does not exist'); + + } + + // Making sure the parent is a collection + if (!$parent instanceof ICollection) { + throw new Exception\Conflict('Parent node is not a collection'); + } + + + + // Making sure the child does not already exist + try { + $parent->getChild($newName); + + // If we got here.. it means there's already a node on that url, and we need to throw a 405 + throw new Exception\MethodNotAllowed('The resource you tried to create already exists'); + + } catch (Exception\NotFound $e) { + // This is correct + } + + + if (!$this->broadcastEvent('beforeBind',array($uri))) return; + + // There are 2 modes of operation. The standard collection + // creates the directory, and then updates properties + // the extended collection can create it directly. + if ($parent instanceof IExtendedCollection) { + + $parent->createExtendedCollection($newName, $resourceType, $properties); + + } else { + + // No special resourcetypes are supported + if (count($resourceType)>1) { + throw new Exception\InvalidResourceType('The {DAV:}resourcetype you specified is not supported here.'); + } + + $parent->createDirectory($newName); + $rollBack = false; + $exception = null; + $errorResult = null; + + if (count($properties)>0) { + + try { + + $errorResult = $this->updateProperties($uri, $properties); + if (!isset($errorResult[200])) { + $rollBack = true; + } + + } catch (Exception $e) { + + $rollBack = true; + $exception = $e; + + } + + } + + if ($rollBack) { + if (!$this->broadcastEvent('beforeUnbind',array($uri))) return; + $this->tree->delete($uri); + + // Re-throwing exception + if ($exception) throw $exception; + + return $errorResult; + } + + } + $this->tree->markDirty($parentUri); + $this->broadcastEvent('afterBind',array($uri)); + + } + + /** + * This method updates a resource's properties + * + * The properties array must be a list of properties. Array-keys are + * property names in clarknotation, array-values are it's values. + * If a property must be deleted, the value should be null. + * + * Note that this request should either completely succeed, or + * completely fail. + * + * The response is an array with statuscodes for keys, which in turn + * contain arrays with propertynames. This response can be used + * to generate a multistatus body. + * + * @param string $uri + * @param array $properties + * @return array + */ + public function updateProperties($uri, array $properties) { + + // we'll start by grabbing the node, this will throw the appropriate + // exceptions if it doesn't. + $node = $this->tree->getNodeForPath($uri); + + $result = array( + 200 => array(), + 403 => array(), + 424 => array(), + ); + $remainingProperties = $properties; + $hasError = false; + + // Running through all properties to make sure none of them are protected + if (!$hasError) foreach($properties as $propertyName => $value) { + if(in_array($propertyName, $this->protectedProperties)) { + $result[403][$propertyName] = null; + unset($remainingProperties[$propertyName]); + $hasError = true; + } + } + + if (!$hasError) { + // Allowing plugins to take care of property updating + $hasError = !$this->broadcastEvent('updateProperties',array( + &$remainingProperties, + &$result, + $node + )); + } + + // If the node is not an instance of Sabre\DAV\IProperties, every + // property is 403 Forbidden + if (!$hasError && count($remainingProperties) && !($node instanceof IProperties)) { + $hasError = true; + foreach($properties as $propertyName=> $value) { + $result[403][$propertyName] = null; + } + $remainingProperties = array(); + } + + // Only if there were no errors we may attempt to update the resource + if (!$hasError) { + + if (count($remainingProperties)>0) { + + $updateResult = $node->updateProperties($remainingProperties); + + if ($updateResult===true) { + // success + foreach($remainingProperties as $propertyName=>$value) { + $result[200][$propertyName] = null; + } + + } elseif ($updateResult===false) { + // The node failed to update the properties for an + // unknown reason + foreach($remainingProperties as $propertyName=>$value) { + $result[403][$propertyName] = null; + } + + } elseif (is_array($updateResult)) { + + // The node has detailed update information + // We need to merge the results with the earlier results. + foreach($updateResult as $status => $props) { + if (is_array($props)) { + if (!isset($result[$status])) + $result[$status] = array(); + + $result[$status] = array_merge($result[$status], $updateResult[$status]); + } + } + + } else { + throw new Exception('Invalid result from updateProperties'); + } + $remainingProperties = array(); + } + + } + + foreach($remainingProperties as $propertyName=>$value) { + // if there are remaining properties, it must mean + // there's a dependency failure + $result[424][$propertyName] = null; + } + + // Removing empty array values + foreach($result as $status=>$props) { + + if (count($props)===0) unset($result[$status]); + + } + $result['href'] = $uri; + return $result; + + } + + /** + * This method checks the main HTTP preconditions. + * + * Currently these are: + * * If-Match + * * If-None-Match + * * If-Modified-Since + * * If-Unmodified-Since + * + * The method will return true if all preconditions are met + * The method will return false, or throw an exception if preconditions + * failed. If false is returned the operation should be aborted, and + * the appropriate HTTP response headers are already set. + * + * Normally this method will throw 412 Precondition Failed for failures + * related to If-None-Match, If-Match and If-Unmodified Since. It will + * set the status to 304 Not Modified for If-Modified_since. + * + * If the $handleAsGET argument is set to true, it will also return 304 + * Not Modified for failure of the If-None-Match precondition. This is the + * desired behaviour for HTTP GET and HTTP HEAD requests. + * + * @param bool $handleAsGET + * @return bool + */ + public function checkPreconditions($handleAsGET = false) { + + $uri = $this->getRequestUri(); + $node = null; + $lastMod = null; + $etag = null; + + if ($ifMatch = $this->httpRequest->getHeader('If-Match')) { + + // If-Match contains an entity tag. Only if the entity-tag + // matches we are allowed to make the request succeed. + // If the entity-tag is '*' we are only allowed to make the + // request succeed if a resource exists at that url. + try { + $node = $this->tree->getNodeForPath($uri); + } catch (Exception\NotFound $e) { + throw new Exception\PreconditionFailed('An If-Match header was specified and the resource did not exist','If-Match'); + } + + // Only need to check entity tags if they are not * + if ($ifMatch!=='*') { + + // There can be multiple etags + $ifMatch = explode(',',$ifMatch); + $haveMatch = false; + foreach($ifMatch as $ifMatchItem) { + + // Stripping any extra spaces + $ifMatchItem = trim($ifMatchItem,' '); + + $etag = $node->getETag(); + if ($etag===$ifMatchItem) { + $haveMatch = true; + } else { + // Evolution has a bug where it sometimes prepends the " + // with a \. This is our workaround. + if (str_replace('\\"','"', $ifMatchItem) === $etag) { + $haveMatch = true; + } + } + + } + if (!$haveMatch) { + throw new Exception\PreconditionFailed('An If-Match header was specified, but none of the specified the ETags matched.','If-Match'); + } + } + } + + if ($ifNoneMatch = $this->httpRequest->getHeader('If-None-Match')) { + + // The If-None-Match header contains an etag. + // Only if the ETag does not match the current ETag, the request will succeed + // The header can also contain *, in which case the request + // will only succeed if the entity does not exist at all. + $nodeExists = true; + if (!$node) { + try { + $node = $this->tree->getNodeForPath($uri); + } catch (Exception\NotFound $e) { + $nodeExists = false; + } + } + if ($nodeExists) { + $haveMatch = false; + if ($ifNoneMatch==='*') $haveMatch = true; + else { + + // There might be multiple etags + $ifNoneMatch = explode(',', $ifNoneMatch); + $etag = $node->getETag(); + + foreach($ifNoneMatch as $ifNoneMatchItem) { + + // Stripping any extra spaces + $ifNoneMatchItem = trim($ifNoneMatchItem,' '); + + if ($etag===$ifNoneMatchItem) $haveMatch = true; + + } + + } + + if ($haveMatch) { + if ($handleAsGET) { + $this->httpResponse->sendStatus(304); + return false; + } else { + throw new Exception\PreconditionFailed('An If-None-Match header was specified, but the ETag matched (or * was specified).','If-None-Match'); + } + } + } + + } + + if (!$ifNoneMatch && ($ifModifiedSince = $this->httpRequest->getHeader('If-Modified-Since'))) { + + // The If-Modified-Since header contains a date. We + // will only return the entity if it has been changed since + // that date. If it hasn't been changed, we return a 304 + // header + // Note that this header only has to be checked if there was no If-None-Match header + // as per the HTTP spec. + $date = HTTP\Util::parseHTTPDate($ifModifiedSince); + + if ($date) { + if (is_null($node)) { + $node = $this->tree->getNodeForPath($uri); + } + $lastMod = $node->getLastModified(); + if ($lastMod) { + $lastMod = new \DateTime('@' . $lastMod); + if ($lastMod <= $date) { + $this->httpResponse->sendStatus(304); + $this->httpResponse->setHeader('Last-Modified', HTTP\Util::toHTTPDate($lastMod)); + return false; + } + } + } + } + + if ($ifUnmodifiedSince = $this->httpRequest->getHeader('If-Unmodified-Since')) { + + // The If-Unmodified-Since will allow allow the request if the + // entity has not changed since the specified date. + $date = HTTP\Util::parseHTTPDate($ifUnmodifiedSince); + + // We must only check the date if it's valid + if ($date) { + if (is_null($node)) { + $node = $this->tree->getNodeForPath($uri); + } + $lastMod = $node->getLastModified(); + if ($lastMod) { + $lastMod = new \DateTime('@' . $lastMod); + if ($lastMod > $date) { + throw new Exception\PreconditionFailed('An If-Unmodified-Since header was specified, but the entity has been changed since the specified date.','If-Unmodified-Since'); + } + } + } + + } + return true; + + } + + // }}} + // {{{ XML Readers & Writers + + + /** + * Generates a WebDAV propfind response body based on a list of nodes. + * + * If 'strip404s' is set to true, all 404 responses will be removed. + * + * @param array $fileProperties The list with nodes + * @param bool strip404s + * @return string + */ + public function generateMultiStatus(array $fileProperties, $strip404s = false) { + + $dom = new \DOMDocument('1.0','utf-8'); + //$dom->formatOutput = true; + $multiStatus = $dom->createElement('d:multistatus'); + $dom->appendChild($multiStatus); + + // Adding in default namespaces + foreach($this->xmlNamespaces as $namespace=>$prefix) { + + $multiStatus->setAttribute('xmlns:' . $prefix,$namespace); + + } + + foreach($fileProperties as $entry) { + + $href = $entry['href']; + unset($entry['href']); + + if ($strip404s && isset($entry[404])) { + unset($entry[404]); + } + + $response = new Property\Response($href,$entry); + $response->serialize($this,$multiStatus); + + } + + return $dom->saveXML(); + + } + + /** + * This method parses a PropPatch request + * + * PropPatch changes the properties for a resource. This method + * returns a list of properties. + * + * The keys in the returned array contain the property name (e.g.: {DAV:}displayname, + * and the value contains the property value. If a property is to be removed the value + * will be null. + * + * @param string $body xml body + * @return array list of properties in need of updating or deletion + */ + public function parsePropPatchRequest($body) { + + //We'll need to change the DAV namespace declaration to something else in order to make it parsable + $dom = XMLUtil::loadDOMDocument($body); + + $newProperties = array(); + + foreach($dom->firstChild->childNodes as $child) { + + if ($child->nodeType !== XML_ELEMENT_NODE) continue; + + $operation = XMLUtil::toClarkNotation($child); + + if ($operation!=='{DAV:}set' && $operation!=='{DAV:}remove') continue; + + $innerProperties = XMLUtil::parseProperties($child, $this->propertyMap); + + foreach($innerProperties as $propertyName=>$propertyValue) { + + if ($operation==='{DAV:}remove') { + $propertyValue = null; + } + + $newProperties[$propertyName] = $propertyValue; + + } + + } + + return $newProperties; + + } + + /** + * This method parses the PROPFIND request and returns its information + * + * This will either be a list of properties, or an empty array; in which case + * an {DAV:}allprop was requested. + * + * @param string $body + * @return array + */ + public function parsePropFindRequest($body) { + + // If the propfind body was empty, it means IE is requesting 'all' properties + if (!$body) return array(); + + $dom = XMLUtil::loadDOMDocument($body); + $elem = $dom->getElementsByTagNameNS('urn:DAV','propfind')->item(0); + return array_keys(XMLUtil::parseProperties($elem)); + + } + + // }}} + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/ServerPlugin.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/ServerPlugin.php new file mode 100644 index 00000000..c393f43f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/ServerPlugin.php @@ -0,0 +1,90 @@ +name = $name; + foreach($children as $child) { + + if (!($child instanceof INode)) throw new Exception('Only instances of Sabre\DAV\INode are allowed to be passed in the children argument'); + $this->addChild($child); + + } + + } + + /** + * Adds a new childnode to this collection + * + * @param INode $child + * @return void + */ + public function addChild(INode $child) { + + $this->children[$child->getName()] = $child; + + } + + /** + * Returns the name of the collection + * + * @return string + */ + public function getName() { + + return $this->name; + + } + + /** + * Returns a child object, by its name. + * + * This method makes use of the getChildren method to grab all the child nodes, and compares the name. + * Generally its wise to override this, as this can usually be optimized + * + * This method must throw Sabre\DAV\Exception\NotFound if the node does not + * exist. + * + * @param string $name + * @throws Exception\NotFound + * @return INode + */ + public function getChild($name) { + + if (isset($this->children[$name])) return $this->children[$name]; + throw new Exception\NotFound('File not found: ' . $name . ' in \'' . $this->getName() . '\''); + + } + + /** + * Returns a list of children for this collection + * + * @return array + */ + public function getChildren() { + + return array_values($this->children); + + } + + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/SimpleFile.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/SimpleFile.php new file mode 100644 index 00000000..b7413fdd --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/SimpleFile.php @@ -0,0 +1,121 @@ +name = $name; + $this->contents = $contents; + $this->mimeType = $mimeType; + + } + + /** + * Returns the node name for this file. + * + * This name is used to construct the url. + * + * @return string + */ + public function getName() { + + return $this->name; + + } + + /** + * Returns the data + * + * This method may either return a string or a readable stream resource + * + * @return mixed + */ + public function get() { + + return $this->contents; + + } + + /** + * Returns the size of the file, in bytes. + * + * @return int + */ + public function getSize() { + + return strlen($this->contents); + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * The ETag is an arbitrary string, but MUST be surrounded by double-quotes. + * + * Return null if the ETag can not effectively be determined + * @return string + */ + public function getETag() { + + return '"' . md5($this->contents) . '"'; + + } + + /** + * Returns the mime-type for a file + * + * If null is returned, we'll assume application/octet-stream + * @return string + */ + public function getContentType() { + + return $this->mimeType; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/StringUtil.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/StringUtil.php new file mode 100644 index 00000000..c71575f4 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/StringUtil.php @@ -0,0 +1,91 @@ +dataDir = $dataDir; + + } + + /** + * Initialize the plugin + * + * This is called automatically be the Server class after this plugin is + * added with Sabre\DAV\Server::addPlugin() + * + * @param Server $server + * @return void + */ + public function initialize(Server $server) { + + $this->server = $server; + $server->subscribeEvent('beforeMethod',array($this,'beforeMethod')); + $server->subscribeEvent('beforeCreateFile',array($this,'beforeCreateFile')); + + } + + /** + * This method is called before any HTTP method handler + * + * This method intercepts any GET, DELETE, PUT and PROPFIND calls to + * filenames that are known to match the 'temporary file' regex. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function beforeMethod($method, $uri) { + + if (!$tempLocation = $this->isTempFile($uri)) + return true; + + switch($method) { + case 'GET' : + return $this->httpGet($tempLocation); + case 'PUT' : + return $this->httpPut($tempLocation); + case 'PROPFIND' : + return $this->httpPropfind($tempLocation, $uri); + case 'DELETE' : + return $this->httpDelete($tempLocation); + } + return true; + + } + + /** + * This method is invoked if some subsystem creates a new file. + * + * This is used to deal with HTTP LOCK requests which create a new + * file. + * + * @param string $uri + * @param resource $data + * @return bool + */ + public function beforeCreateFile($uri,$data) { + + if ($tempPath = $this->isTempFile($uri)) { + + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + file_put_contents($tempPath,$data); + return false; + } + return true; + + } + + /** + * This method will check if the url matches the temporary file pattern + * if it does, it will return an path based on $this->dataDir for the + * temporary file storage. + * + * @param string $path + * @return boolean|string + */ + protected function isTempFile($path) { + + // We're only interested in the basename. + list(, $tempPath) = URLUtil::splitPath($path); + + foreach($this->temporaryFilePatterns as $tempFile) { + + if (preg_match($tempFile,$tempPath)) { + return $this->getDataDir() . '/sabredav_' . md5($path) . '.tempfile'; + } + + } + + return false; + + } + + + /** + * This method handles the GET method for temporary files. + * If the file doesn't exist, it will return false which will kick in + * the regular system for the GET method. + * + * @param string $tempLocation + * @return bool + */ + public function httpGet($tempLocation) { + + if (!file_exists($tempLocation)) return true; + + $hR = $this->server->httpResponse; + $hR->setHeader('Content-Type','application/octet-stream'); + $hR->setHeader('Content-Length',filesize($tempLocation)); + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(200); + $hR->sendBody(fopen($tempLocation,'r')); + return false; + + } + + /** + * This method handles the PUT method. + * + * @param string $tempLocation + * @return bool + */ + public function httpPut($tempLocation) { + + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + + $newFile = !file_exists($tempLocation); + + if (!$newFile && ($this->server->httpRequest->getHeader('If-None-Match'))) { + throw new Exception\PreconditionFailed('The resource already exists, and an If-None-Match header was supplied'); + } + + file_put_contents($tempLocation,$this->server->httpRequest->getBody()); + $hR->sendStatus($newFile?201:200); + return false; + + } + + /** + * This method handles the DELETE method. + * + * If the file didn't exist, it will return false, which will make the + * standard HTTP DELETE handler kick in. + * + * @param string $tempLocation + * @return bool + */ + public function httpDelete($tempLocation) { + + if (!file_exists($tempLocation)) return true; + + unlink($tempLocation); + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(204); + return false; + + } + + /** + * This method handles the PROPFIND method. + * + * It's a very lazy method, it won't bother checking the request body + * for which properties were requested, and just sends back a default + * set of properties. + * + * @param string $tempLocation + * @param string $uri + * @return bool + */ + public function httpPropfind($tempLocation, $uri) { + + if (!file_exists($tempLocation)) return true; + + $hR = $this->server->httpResponse; + $hR->setHeader('X-Sabre-Temp','true'); + $hR->sendStatus(207); + $hR->setHeader('Content-Type','application/xml; charset=utf-8'); + + $this->server->parsePropFindRequest($this->server->httpRequest->getBody(true)); + + $properties = array( + 'href' => $uri, + 200 => array( + '{DAV:}getlastmodified' => new Property\GetLastModified(filemtime($tempLocation)), + '{DAV:}getcontentlength' => filesize($tempLocation), + '{DAV:}resourcetype' => new Property\ResourceType(null), + '{'.Server::NS_SABREDAV.'}tempFile' => true, + + ), + ); + + $data = $this->server->generateMultiStatus(array($properties)); + $hR->sendBody($data); + return false; + + } + + + /** + * This method returns the directory where the temporary files should be stored. + * + * @return string + */ + protected function getDataDir() + { + return $this->dataDir; + } +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree.php new file mode 100644 index 00000000..ab94168b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree.php @@ -0,0 +1,193 @@ +getNodeForPath($path); + return true; + + } catch (Exception\NotFound $e) { + + return false; + + } + + } + + /** + * Copies a file from path to another + * + * @param string $sourcePath The source location + * @param string $destinationPath The full destination path + * @return void + */ + public function copy($sourcePath, $destinationPath) { + + $sourceNode = $this->getNodeForPath($sourcePath); + + // grab the dirname and basename components + list($destinationDir, $destinationName) = URLUtil::splitPath($destinationPath); + + $destinationParent = $this->getNodeForPath($destinationDir); + $this->copyNode($sourceNode,$destinationParent,$destinationName); + + $this->markDirty($destinationDir); + + } + + /** + * Moves a file from one location to another + * + * @param string $sourcePath The path to the file which should be moved + * @param string $destinationPath The full destination path, so not just the destination parent node + * @return int + */ + public function move($sourcePath, $destinationPath) { + + list($sourceDir, $sourceName) = URLUtil::splitPath($sourcePath); + list($destinationDir, $destinationName) = URLUtil::splitPath($destinationPath); + + if ($sourceDir===$destinationDir) { + $renameable = $this->getNodeForPath($sourcePath); + $renameable->setName($destinationName); + } else { + $this->copy($sourcePath,$destinationPath); + $this->getNodeForPath($sourcePath)->delete(); + } + $this->markDirty($sourceDir); + $this->markDirty($destinationDir); + + } + + /** + * Deletes a node from the tree + * + * @param string $path + * @return void + */ + public function delete($path) { + + $node = $this->getNodeForPath($path); + $node->delete(); + + list($parent) = URLUtil::splitPath($path); + $this->markDirty($parent); + + } + + /** + * Returns a list of childnodes for a given path. + * + * @param string $path + * @return array + */ + public function getChildren($path) { + + $node = $this->getNodeForPath($path); + return $node->getChildren(); + + } + + /** + * This method is called with every tree update + * + * Examples of tree updates are: + * * node deletions + * * node creations + * * copy + * * move + * * renaming nodes + * + * If Tree classes implement a form of caching, this will allow + * them to make sure caches will be expired. + * + * If a path is passed, it is assumed that the entire subtree is dirty + * + * @param string $path + * @return void + */ + public function markDirty($path) { + + + } + + /** + * copyNode + * + * @param INode $source + * @param ICollection $destinationParent + * @param string $destinationName + * @return void + */ + protected function copyNode(INode $source,ICollection $destinationParent,$destinationName = null) { + + if (!$destinationName) $destinationName = $source->getName(); + + if ($source instanceof IFile) { + + $data = $source->get(); + + // If the body was a string, we need to convert it to a stream + if (is_string($data)) { + $stream = fopen('php://temp','r+'); + fwrite($stream,$data); + rewind($stream); + $data = $stream; + } + $destinationParent->createFile($destinationName,$data); + $destination = $destinationParent->getChild($destinationName); + + } elseif ($source instanceof ICollection) { + + $destinationParent->createDirectory($destinationName); + + $destination = $destinationParent->getChild($destinationName); + foreach($source->getChildren() as $child) { + + $this->copyNode($child,$destination); + + } + + } + if ($source instanceof IProperties && $destination instanceof IProperties) { + + $props = $source->getProperties(array()); + $destination->updateProperties($props); + + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree/Filesystem.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree/Filesystem.php new file mode 100644 index 00000000..a477725a --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/Tree/Filesystem.php @@ -0,0 +1,133 @@ +basePath = $basePath; + + } + + /** + * Returns a new node for the given path + * + * @param string $path + * @return DAV\FS\Node + */ + public function getNodeForPath($path) { + + $realPath = $this->getRealPath($path); + if (!file_exists($realPath)) { + throw new DAV\Exception\NotFound('File at location ' . $realPath . ' not found'); + } + if (is_dir($realPath)) { + return new DAV\FS\Directory($realPath); + } else { + return new DAV\FS\File($realPath); + } + + } + + /** + * Returns the real filesystem path for a webdav url. + * + * @param string $publicPath + * @return string + */ + protected function getRealPath($publicPath) { + + return rtrim($this->basePath,'/') . '/' . trim($publicPath,'/'); + + } + + /** + * Copies a file or directory. + * + * This method must work recursively and delete the destination + * if it exists + * + * @param string $source + * @param string $destination + * @return void + */ + public function copy($source,$destination) { + + $source = $this->getRealPath($source); + $destination = $this->getRealPath($destination); + $this->realCopy($source,$destination); + + } + + /** + * Used by self::copy + * + * @param string $source + * @param string $destination + * @return void + */ + protected function realCopy($source,$destination) { + + if (is_file($source)) { + copy($source,$destination); + } else { + mkdir($destination); + foreach(scandir($source) as $subnode) { + + if ($subnode=='.' || $subnode=='..') continue; + $this->realCopy($source.'/'.$subnode,$destination.'/'.$subnode); + + } + } + + } + + /** + * Moves a file or directory recursively. + * + * If the destination exists, delete it first. + * + * @param string $source + * @param string $destination + * @return void + */ + public function move($source,$destination) { + + $source = $this->getRealPath($source); + $destination = $this->getRealPath($destination); + rename($source,$destination); + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAV/URLUtil.php b/sources/vendor/sabre/dav/lib/Sabre/DAV/URLUtil.php new file mode 100644 index 00000000..b7254e9a --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAV/URLUtil.php @@ -0,0 +1,124 @@ + + * will be returned as: + * {http://www.example.org}myelem + * + * This format is used throughout the SabreDAV sourcecode. + * Elements encoded with the urn:DAV namespace will + * be returned as if they were in the DAV: namespace. This is to avoid + * compatibility problems. + * + * This function will return null if a nodetype other than an Element is passed. + * + * @param \DOMNode $dom + * @return string + */ + static function toClarkNotation(\DOMNode $dom) { + + if ($dom->nodeType !== XML_ELEMENT_NODE) return null; + + // Mapping back to the real namespace, in case it was dav + if ($dom->namespaceURI=='urn:DAV') $ns = 'DAV:'; else $ns = $dom->namespaceURI; + + // Mapping to clark notation + return '{' . $ns . '}' . $dom->localName; + + } + + /** + * Parses a clark-notation string, and returns the namespace and element + * name components. + * + * If the string was invalid, it will throw an InvalidArgumentException. + * + * @param string $str + * @throws InvalidArgumentException + * @return array + */ + static function parseClarkNotation($str) { + + if (!preg_match('/^{([^}]*)}(.*)$/',$str,$matches)) { + throw new \InvalidArgumentException('\'' . $str . '\' is not a valid clark-notation formatted string'); + } + + return array( + $matches[1], + $matches[2] + ); + + } + + /** + * This method takes an XML document (as string) and converts all instances of the + * DAV: namespace to urn:DAV + * + * This is unfortunately needed, because the DAV: namespace violates the xml namespaces + * spec, and causes the DOM to throw errors + * + * @param string $xmlDocument + * @return array|string|null + */ + static function convertDAVNamespace($xmlDocument) { + + // This is used to map the DAV: namespace to urn:DAV. This is needed, because the DAV: + // namespace is actually a violation of the XML namespaces specification, and will cause errors + return preg_replace("/xmlns(:[A-Za-z0-9_]*)?=(\"|\')DAV:(\\2)/","xmlns\\1=\\2urn:DAV\\2",$xmlDocument); + + } + + /** + * This method provides a generic way to load a DOMDocument for WebDAV use. + * + * This method throws a Sabre\DAV\Exception\BadRequest exception for any xml errors. + * It does not preserve whitespace, and it converts the DAV: namespace to urn:DAV. + * + * @param string $xml + * @throws Sabre\DAV\Exception\BadRequest + * @return DOMDocument + */ + static function loadDOMDocument($xml) { + + if (empty($xml)) + throw new Exception\BadRequest('Empty XML document sent'); + + // The BitKinex client sends xml documents as UTF-16. PHP 5.3.1 (and presumably lower) + // does not support this, so we must intercept this and convert to UTF-8. + if (substr($xml,0,12) === "\x3c\x00\x3f\x00\x78\x00\x6d\x00\x6c\x00\x20\x00") { + + // Note: the preceeding byte sequence is "]*)encoding="UTF-16"([^>]*)>|u','',$xml); + + } + + // Retaining old error setting + $oldErrorSetting = libxml_use_internal_errors(true); + // Fixes an XXE vulnerability on PHP versions older than 5.3.23 or + // 5.4.13. + $oldEntityLoaderSetting = libxml_disable_entity_loader(true); + + // Clearing any previous errors + libxml_clear_errors(); + + $dom = new \DOMDocument(); + + // We don't generally care about any whitespace + $dom->preserveWhiteSpace = false; + + $dom->loadXML(self::convertDAVNamespace($xml),LIBXML_NOWARNING | LIBXML_NOERROR); + + if ($error = libxml_get_last_error()) { + libxml_clear_errors(); + throw new Exception\BadRequest('The request body had an invalid XML body. (message: ' . $error->message . ', errorcode: ' . $error->code . ', line: ' . $error->line . ')'); + } + + // Restoring old mechanism for error handling + if ($oldErrorSetting===false) libxml_use_internal_errors(false); + if ($oldEntityLoaderSetting===false) libxml_disable_entity_loader(false); + + return $dom; + + } + + /** + * Parses all WebDAV properties out of a DOM Element + * + * Generally WebDAV properties are enclosed in {DAV:}prop elements. This + * method helps by going through all these and pulling out the actual + * propertynames, making them array keys and making the property values, + * well.. the array values. + * + * If no value was given (self-closing element) null will be used as the + * value. This is used in for example PROPFIND requests. + * + * Complex values are supported through the propertyMap argument. The + * propertyMap should have the clark-notation properties as it's keys, and + * classnames as values. + * + * When any of these properties are found, the unserialize() method will be + * (statically) called. The result of this method is used as the value. + * + * @param \DOMElement $parentNode + * @param array $propertyMap + * @return array + */ + static function parseProperties(\DOMElement $parentNode, array $propertyMap = array()) { + + $propList = array(); + foreach($parentNode->childNodes as $propNode) { + + if (self::toClarkNotation($propNode)!=='{DAV:}prop') continue; + + foreach($propNode->childNodes as $propNodeData) { + + /* If there are no elements in here, we actually get 1 text node, this special case is dedicated to netdrive */ + if ($propNodeData->nodeType != XML_ELEMENT_NODE) continue; + + $propertyName = self::toClarkNotation($propNodeData); + if (isset($propertyMap[$propertyName])) { + $propList[$propertyName] = call_user_func(array($propertyMap[$propertyName],'unserialize'),$propNodeData); + } else { + $propList[$propertyName] = $propNodeData->textContent; + } + } + + + } + return $propList; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/AbstractPrincipalCollection.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/AbstractPrincipalCollection.php new file mode 100644 index 00000000..a116236f --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/AbstractPrincipalCollection.php @@ -0,0 +1,155 @@ +principalPrefix = $principalPrefix; + $this->principalBackend = $principalBackend; + + } + + /** + * This method returns a node for a principal. + * + * The passed array contains principal information, and is guaranteed to + * at least contain a uri item. Other properties may or may not be + * supplied by the authentication backend. + * + * @param array $principalInfo + * @return IPrincipal + */ + abstract function getChildForPrincipal(array $principalInfo); + + /** + * Returns the name of this collection. + * + * @return string + */ + public function getName() { + + list(,$name) = DAV\URLUtil::splitPath($this->principalPrefix); + return $name; + + } + + /** + * Return the list of users + * + * @return array + */ + public function getChildren() { + + if ($this->disableListing) + throw new DAV\Exception\MethodNotAllowed('Listing members of this collection is disabled'); + + $children = array(); + foreach($this->principalBackend->getPrincipalsByPrefix($this->principalPrefix) as $principalInfo) { + + $children[] = $this->getChildForPrincipal($principalInfo); + + + } + return $children; + + } + + /** + * Returns a child object, by its name. + * + * @param string $name + * @throws DAV\Exception\NotFound + * @return IPrincipal + */ + public function getChild($name) { + + $principalInfo = $this->principalBackend->getPrincipalByPath($this->principalPrefix . '/' . $name); + if (!$principalInfo) throw new DAV\Exception\NotFound('Principal with name ' . $name . ' not found'); + return $this->getChildForPrincipal($principalInfo); + + } + + /** + * This method is used to search for principals matching a set of + * properties. + * + * This search is specifically used by RFC3744's principal-property-search + * REPORT. You should at least allow searching on + * http://sabredav.org/ns}email-address. + * + * The actual search should be a unicode-non-case-sensitive search. The + * keys in searchProperties are the WebDAV property names, while the values + * are the property values to search on. + * + * If multiple properties are being searched on, the search should be + * AND'ed. + * + * This method should simply return a list of 'child names', which may be + * used to call $this->getChild in the future. + * + * @param array $searchProperties + * @return array + */ + public function searchPrincipals(array $searchProperties) { + + $result = $this->principalBackend->searchPrincipals($this->principalPrefix, $searchProperties); + $r = array(); + + foreach($result as $row) { + list(, $r[]) = DAV\URLUtil::splitPath($row); + } + + return $r; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/AceConflict.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/AceConflict.php new file mode 100644 index 00000000..6ee9afd7 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/AceConflict.php @@ -0,0 +1,35 @@ +ownerDocument; + + $np = $doc->createElementNS('DAV:','d:no-ace-conflict'); + $errorNode->appendChild($np); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NeedPrivileges.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NeedPrivileges.php new file mode 100644 index 00000000..f7e43588 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NeedPrivileges.php @@ -0,0 +1,83 @@ +uri = $uri; + $this->privileges = $privileges; + + parent::__construct('User did not have the required privileges (' . implode(',', $privileges) . ') for path "' . $uri . '"'); + + } + + /** + * Adds in extra information in the xml response. + * + * This method adds the {DAV:}need-privileges element as defined in rfc3744 + * + * @param DAV\Server $server + * @param \DOMElement $errorNode + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $errorNode) { + + $doc = $errorNode->ownerDocument; + + $np = $doc->createElementNS('DAV:','d:need-privileges'); + $errorNode->appendChild($np); + + foreach($this->privileges as $privilege) { + + $resource = $doc->createElementNS('DAV:','d:resource'); + $np->appendChild($resource); + + $resource->appendChild($doc->createElementNS('DAV:','d:href',$server->getBaseUri() . $this->uri)); + + $priv = $doc->createElementNS('DAV:','d:privilege'); + $resource->appendChild($priv); + + preg_match('/^{([^}]*)}(.*)$/',$privilege,$privilegeParts); + $priv->appendChild($doc->createElementNS($privilegeParts[1],'d:' . $privilegeParts[2])); + + + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NoAbstract.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NoAbstract.php new file mode 100644 index 00000000..ba6f76cd --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NoAbstract.php @@ -0,0 +1,35 @@ +ownerDocument; + + $np = $doc->createElementNS('DAV:','d:no-abstract'); + $errorNode->appendChild($np); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotRecognizedPrincipal.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotRecognizedPrincipal.php new file mode 100644 index 00000000..f61edef0 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotRecognizedPrincipal.php @@ -0,0 +1,35 @@ +ownerDocument; + + $np = $doc->createElementNS('DAV:','d:recognized-principal'); + $errorNode->appendChild($np); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotSupportedPrivilege.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotSupportedPrivilege.php new file mode 100644 index 00000000..6d30698c --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Exception/NotSupportedPrivilege.php @@ -0,0 +1,35 @@ +ownerDocument; + + $np = $doc->createElementNS('DAV:','d:not-supported-privilege'); + $errorNode->appendChild($np); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/IACL.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/IACL.php new file mode 100644 index 00000000..088ca3ee --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/IACL.php @@ -0,0 +1,74 @@ +getChild in the future. + * + * @param array $searchProperties + * @return array + */ + function searchPrincipals(array $searchProperties); + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Plugin.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Plugin.php new file mode 100644 index 00000000..f9bf4bb4 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Plugin.php @@ -0,0 +1,1402 @@ + 'Display name', + '{http://sabredav.org/ns}email-address' => 'Email address', + ); + + /** + * Any principal uri's added here, will automatically be added to the list + * of ACL's. They will effectively receive {DAV:}all privileges, as a + * protected privilege. + * + * @var array + */ + public $adminPrincipals = array(); + + /** + * Returns a list of features added by this plugin. + * + * This list is used in the response of a HTTP OPTIONS request. + * + * @return array + */ + public function getFeatures() { + + return array('access-control', 'calendarserver-principal-property-search'); + + } + + /** + * Returns a list of available methods for a given url + * + * @param string $uri + * @return array + */ + public function getMethods($uri) { + + return array('ACL'); + + } + + /** + * Returns a plugin name. + * + * Using this name other plugins will be able to access other plugins + * using Sabre\DAV\Server::getPlugin + * + * @return string + */ + public function getPluginName() { + + return 'acl'; + + } + + /** + * Returns a list of reports this plugin supports. + * + * This will be used in the {DAV:}supported-report-set property. + * Note that you still need to subscribe to the 'report' event to actually + * implement them + * + * @param string $uri + * @return array + */ + public function getSupportedReportSet($uri) { + + return array( + '{DAV:}expand-property', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set', + ); + + } + + + /** + * Checks if the current user has the specified privilege(s). + * + * You can specify a single privilege, or a list of privileges. + * This method will throw an exception if the privilege is not available + * and return true otherwise. + * + * @param string $uri + * @param array|string $privileges + * @param int $recursion + * @param bool $throwExceptions if set to false, this method won't throw exceptions. + * @throws Sabre\DAVACL\Exception\NeedPrivileges + * @return bool + */ + public function checkPrivileges($uri, $privileges, $recursion = self::R_PARENT, $throwExceptions = true) { + + if (!is_array($privileges)) $privileges = array($privileges); + + $acl = $this->getCurrentUserPrivilegeSet($uri); + + if (is_null($acl)) { + if ($this->allowAccessToNodesWithoutACL) { + return true; + } else { + if ($throwExceptions) + throw new Exception\NeedPrivileges($uri,$privileges); + else + return false; + + } + } + + $failed = array(); + foreach($privileges as $priv) { + + if (!in_array($priv, $acl)) { + $failed[] = $priv; + } + + } + + if ($failed) { + if ($throwExceptions) + throw new Exception\NeedPrivileges($uri,$failed); + else + return false; + } + return true; + + } + + /** + * Returns the standard users' principal. + * + * This is one authorative principal url for the current user. + * This method will return null if the user wasn't logged in. + * + * @return string|null + */ + public function getCurrentUserPrincipal() { + + $authPlugin = $this->server->getPlugin('auth'); + if (is_null($authPlugin)) return null; + /** @var $authPlugin Sabre\DAV\Auth\Plugin */ + + $userName = $authPlugin->getCurrentUser(); + if (!$userName) return null; + + return $this->defaultUsernamePath . '/' . $userName; + + } + + + /** + * Returns a list of principals that's associated to the current + * user, either directly or through group membership. + * + * @return array + */ + public function getCurrentUserPrincipals() { + + $currentUser = $this->getCurrentUserPrincipal(); + + if (is_null($currentUser)) return array(); + + return array_merge( + array($currentUser), + $this->getPrincipalMembership($currentUser) + ); + + } + + /** + * This array holds a cache for all the principals that are associated with + * a single principal. + * + * @var array + */ + protected $principalMembershipCache = array(); + + + /** + * Returns all the principal groups the specified principal is a member of. + * + * @param string $principal + * @return array + */ + public function getPrincipalMembership($mainPrincipal) { + + // First check our cache + if (isset($this->principalMembershipCache[$mainPrincipal])) { + return $this->principalMembershipCache[$mainPrincipal]; + } + + $check = array($mainPrincipal); + $principals = array(); + + while(count($check)) { + + $principal = array_shift($check); + + $node = $this->server->tree->getNodeForPath($principal); + if ($node instanceof IPrincipal) { + foreach($node->getGroupMembership() as $groupMember) { + + if (!in_array($groupMember, $principals)) { + + $check[] = $groupMember; + $principals[] = $groupMember; + + } + + } + + } + + } + + // Store the result in the cache + $this->principalMembershipCache[$mainPrincipal] = $principals; + + return $principals; + + } + + /** + * Returns the supported privilege structure for this ACL plugin. + * + * See RFC3744 for more details. Currently we default on a simple, + * standard structure. + * + * You can either get the list of privileges by a uri (path) or by + * specifying a Node. + * + * @param string|DAV\INode $node + * @return array + */ + public function getSupportedPrivilegeSet($node) { + + if (is_string($node)) { + $node = $this->server->tree->getNodeForPath($node); + } + + if ($node instanceof IACL) { + $result = $node->getSupportedPrivilegeSet(); + + if ($result) + return $result; + } + + return self::getDefaultSupportedPrivilegeSet(); + + } + + /** + * Returns a fairly standard set of privileges, which may be useful for + * other systems to use as a basis. + * + * @return array + */ + static function getDefaultSupportedPrivilegeSet() { + + return array( + 'privilege' => '{DAV:}all', + 'abstract' => true, + 'aggregates' => array( + array( + 'privilege' => '{DAV:}read', + 'aggregates' => array( + array( + 'privilege' => '{DAV:}read-acl', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}read-current-user-privilege-set', + 'abstract' => true, + ), + ), + ), // {DAV:}read + array( + 'privilege' => '{DAV:}write', + 'aggregates' => array( + array( + 'privilege' => '{DAV:}write-acl', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}write-properties', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}write-content', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}bind', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}unbind', + 'abstract' => true, + ), + array( + 'privilege' => '{DAV:}unlock', + 'abstract' => true, + ), + ), + ), // {DAV:}write + ), + ); // {DAV:}all + + } + + /** + * Returns the supported privilege set as a flat list + * + * This is much easier to parse. + * + * The returned list will be index by privilege name. + * The value is a struct containing the following properties: + * - aggregates + * - abstract + * - concrete + * + * @param string|DAV\INode $node + * @return array + */ + final public function getFlatPrivilegeSet($node) { + + $privs = $this->getSupportedPrivilegeSet($node); + + $flat = array(); + $this->getFPSTraverse($privs, null, $flat); + + return $flat; + + } + + /** + * Traverses the privilege set tree for reordering + * + * This function is solely used by getFlatPrivilegeSet, and would have been + * a closure if it wasn't for the fact I need to support PHP 5.2. + * + * @param array $priv + * @param $concrete + * @param array $flat + * @return void + */ + final private function getFPSTraverse($priv, $concrete, &$flat) { + + $myPriv = array( + 'privilege' => $priv['privilege'], + 'abstract' => isset($priv['abstract']) && $priv['abstract'], + 'aggregates' => array(), + 'concrete' => isset($priv['abstract']) && $priv['abstract']?$concrete:$priv['privilege'], + ); + + if (isset($priv['aggregates'])) + foreach($priv['aggregates'] as $subPriv) $myPriv['aggregates'][] = $subPriv['privilege']; + + $flat[$priv['privilege']] = $myPriv; + + if (isset($priv['aggregates'])) { + + foreach($priv['aggregates'] as $subPriv) { + + $this->getFPSTraverse($subPriv, $myPriv['concrete'], $flat); + + } + + } + + } + + /** + * Returns the full ACL list. + * + * Either a uri or a DAV\INode may be passed. + * + * null will be returned if the node doesn't support ACLs. + * + * @param string|DAV\INode $node + * @return array + */ + public function getACL($node) { + + if (is_string($node)) { + $node = $this->server->tree->getNodeForPath($node); + } + if (!$node instanceof IACL) { + return null; + } + $acl = $node->getACL(); + foreach($this->adminPrincipals as $adminPrincipal) { + $acl[] = array( + 'principal' => $adminPrincipal, + 'privilege' => '{DAV:}all', + 'protected' => true, + ); + } + return $acl; + + } + + /** + * Returns a list of privileges the current user has + * on a particular node. + * + * Either a uri or a DAV\INode may be passed. + * + * null will be returned if the node doesn't support ACLs. + * + * @param string|DAV\INode $node + * @return array + */ + public function getCurrentUserPrivilegeSet($node) { + + if (is_string($node)) { + $node = $this->server->tree->getNodeForPath($node); + } + + $acl = $this->getACL($node); + + if (is_null($acl)) return null; + + $principals = $this->getCurrentUserPrincipals(); + + $collected = array(); + + foreach($acl as $ace) { + + $principal = $ace['principal']; + + switch($principal) { + + case '{DAV:}owner' : + $owner = $node->getOwner(); + if ($owner && in_array($owner, $principals)) { + $collected[] = $ace; + } + break; + + + // 'all' matches for every user + case '{DAV:}all' : + + // 'authenticated' matched for every user that's logged in. + // Since it's not possible to use ACL while not being logged + // in, this is also always true. + case '{DAV:}authenticated' : + $collected[] = $ace; + break; + + // 'unauthenticated' can never occur either, so we simply + // ignore these. + case '{DAV:}unauthenticated' : + break; + + default : + if (in_array($ace['principal'], $principals)) { + $collected[] = $ace; + } + break; + + } + + + } + + // Now we deduct all aggregated privileges. + $flat = $this->getFlatPrivilegeSet($node); + + $collected2 = array(); + while(count($collected)) { + + $current = array_pop($collected); + $collected2[] = $current['privilege']; + + foreach($flat[$current['privilege']]['aggregates'] as $subPriv) { + $collected2[] = $subPriv; + $collected[] = $flat[$subPriv]; + } + + } + + return array_values(array_unique($collected2)); + + } + + /** + * Principal property search + * + * This method can search for principals matching certain values in + * properties. + * + * This method will return a list of properties for the matched properties. + * + * @param array $searchProperties The properties to search on. This is a + * key-value list. The keys are property + * names, and the values the strings to + * match them on. + * @param array $requestedProperties This is the list of properties to + * return for every match. + * @param string $collectionUri The principal collection to search on. + * If this is ommitted, the standard + * principal collection-set will be used. + * @return array This method returns an array structure similar to + * Sabre\DAV\Server::getPropertiesForPath. Returned + * properties are index by a HTTP status code. + * + */ + public function principalSearch(array $searchProperties, array $requestedProperties, $collectionUri = null) { + + if (!is_null($collectionUri)) { + $uris = array($collectionUri); + } else { + $uris = $this->principalCollectionSet; + } + + $lookupResults = array(); + foreach($uris as $uri) { + + $principalCollection = $this->server->tree->getNodeForPath($uri); + if (!$principalCollection instanceof IPrincipalCollection) { + // Not a principal collection, we're simply going to ignore + // this. + continue; + } + + $results = $principalCollection->searchPrincipals($searchProperties); + foreach($results as $result) { + $lookupResults[] = rtrim($uri,'/') . '/' . $result; + } + + } + + $matches = array(); + + foreach($lookupResults as $lookupResult) { + + list($matches[]) = $this->server->getPropertiesForPath($lookupResult, $requestedProperties, 0); + + } + + return $matches; + + } + + /** + * Sets up the plugin + * + * This method is automatically called by the server class. + * + * @param DAV\Server $server + * @return void + */ + public function initialize(DAV\Server $server) { + + $this->server = $server; + $server->subscribeEvent('beforeGetProperties',array($this,'beforeGetProperties')); + + $server->subscribeEvent('beforeMethod', array($this,'beforeMethod'),20); + $server->subscribeEvent('beforeBind', array($this,'beforeBind'),20); + $server->subscribeEvent('beforeUnbind', array($this,'beforeUnbind'),20); + $server->subscribeEvent('updateProperties',array($this,'updateProperties')); + $server->subscribeEvent('beforeUnlock', array($this,'beforeUnlock'),20); + $server->subscribeEvent('report',array($this,'report')); + $server->subscribeEvent('unknownMethod', array($this, 'unknownMethod')); + + array_push($server->protectedProperties, + '{DAV:}alternate-URI-set', + '{DAV:}principal-URL', + '{DAV:}group-membership', + '{DAV:}principal-collection-set', + '{DAV:}current-user-principal', + '{DAV:}supported-privilege-set', + '{DAV:}current-user-privilege-set', + '{DAV:}acl', + '{DAV:}acl-restrictions', + '{DAV:}inherited-acl-set', + '{DAV:}owner', + '{DAV:}group' + ); + + // Automatically mapping nodes implementing IPrincipal to the + // {DAV:}principal resourcetype. + $server->resourceTypeMapping['Sabre\\DAVACL\\IPrincipal'] = '{DAV:}principal'; + + // Mapping the group-member-set property to the HrefList property + // class. + $server->propertyMap['{DAV:}group-member-set'] = 'Sabre\\DAV\\Property\\HrefList'; + + } + + + /* {{{ Event handlers */ + + /** + * Triggered before any method is handled + * + * @param string $method + * @param string $uri + * @return void + */ + public function beforeMethod($method, $uri) { + + $exists = $this->server->tree->nodeExists($uri); + + // If the node doesn't exists, none of these checks apply + if (!$exists) return; + + switch($method) { + + case 'GET' : + case 'HEAD' : + case 'OPTIONS' : + // For these 3 we only need to know if the node is readable. + $this->checkPrivileges($uri,'{DAV:}read'); + break; + + case 'PUT' : + case 'LOCK' : + case 'UNLOCK' : + // This method requires the write-content priv if the node + // already exists, and bind on the parent if the node is being + // created. + // The bind privilege is handled in the beforeBind event. + $this->checkPrivileges($uri,'{DAV:}write-content'); + break; + + + case 'PROPPATCH' : + $this->checkPrivileges($uri,'{DAV:}write-properties'); + break; + + case 'ACL' : + $this->checkPrivileges($uri,'{DAV:}write-acl'); + break; + + case 'COPY' : + case 'MOVE' : + // Copy requires read privileges on the entire source tree. + // If the target exists write-content normally needs to be + // checked, however, we're deleting the node beforehand and + // creating a new one after, so this is handled by the + // beforeUnbind event. + // + // The creation of the new node is handled by the beforeBind + // event. + // + // If MOVE is used beforeUnbind will also be used to check if + // the sourcenode can be deleted. + $this->checkPrivileges($uri,'{DAV:}read',self::R_RECURSIVE); + + break; + + } + + } + + /** + * Triggered before a new node is created. + * + * This allows us to check permissions for any operation that creates a + * new node, such as PUT, MKCOL, MKCALENDAR, LOCK, COPY and MOVE. + * + * @param string $uri + * @return void + */ + public function beforeBind($uri) { + + list($parentUri,$nodeName) = DAV\URLUtil::splitPath($uri); + $this->checkPrivileges($parentUri,'{DAV:}bind'); + + } + + /** + * Triggered before a node is deleted + * + * This allows us to check permissions for any operation that will delete + * an existing node. + * + * @param string $uri + * @return void + */ + public function beforeUnbind($uri) { + + list($parentUri,$nodeName) = DAV\URLUtil::splitPath($uri); + $this->checkPrivileges($parentUri,'{DAV:}unbind',self::R_RECURSIVEPARENTS); + + } + + /** + * Triggered before a node is unlocked. + * + * @param string $uri + * @param DAV\Locks\LockInfo $lock + * @TODO: not yet implemented + * @return void + */ + public function beforeUnlock($uri, DAV\Locks\LockInfo $lock) { + + + } + + /** + * Triggered before properties are looked up in specific nodes. + * + * @param string $uri + * @param DAV\INode $node + * @param array $requestedProperties + * @param array $returnedProperties + * @TODO really should be broken into multiple methods, or even a class. + * @return bool + */ + public function beforeGetProperties($uri, DAV\INode $node, &$requestedProperties, &$returnedProperties) { + + // Checking the read permission + if (!$this->checkPrivileges($uri,'{DAV:}read',self::R_PARENT,false)) { + + // User is not allowed to read properties + if ($this->hideNodesFromListings) { + return false; + } + + // Marking all requested properties as '403'. + foreach($requestedProperties as $key=>$requestedProperty) { + unset($requestedProperties[$key]); + $returnedProperties[403][$requestedProperty] = null; + } + return; + + } + + /* Adding principal properties */ + if ($node instanceof IPrincipal) { + + if (false !== ($index = array_search('{DAV:}alternate-URI-set', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}alternate-URI-set'] = new DAV\Property\HrefList($node->getAlternateUriSet()); + + } + if (false !== ($index = array_search('{DAV:}principal-URL', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}principal-URL'] = new DAV\Property\Href($node->getPrincipalUrl() . '/'); + + } + if (false !== ($index = array_search('{DAV:}group-member-set', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}group-member-set'] = new DAV\Property\HrefList($node->getGroupMemberSet()); + + } + if (false !== ($index = array_search('{DAV:}group-membership', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}group-membership'] = new DAV\Property\HrefList($node->getGroupMembership()); + + } + + if (false !== ($index = array_search('{DAV:}displayname', $requestedProperties))) { + + $returnedProperties[200]['{DAV:}displayname'] = $node->getDisplayName(); + + } + + } + if (false !== ($index = array_search('{DAV:}principal-collection-set', $requestedProperties))) { + + unset($requestedProperties[$index]); + $val = $this->principalCollectionSet; + // Ensuring all collections end with a slash + foreach($val as $k=>$v) $val[$k] = $v . '/'; + $returnedProperties[200]['{DAV:}principal-collection-set'] = new DAV\Property\HrefList($val); + + } + if (false !== ($index = array_search('{DAV:}current-user-principal', $requestedProperties))) { + + unset($requestedProperties[$index]); + if ($url = $this->getCurrentUserPrincipal()) { + $returnedProperties[200]['{DAV:}current-user-principal'] = new Property\Principal(Property\Principal::HREF, $url . '/'); + } else { + $returnedProperties[200]['{DAV:}current-user-principal'] = new Property\Principal(Property\Principal::UNAUTHENTICATED); + } + + } + if (false !== ($index = array_search('{DAV:}supported-privilege-set', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}supported-privilege-set'] = new Property\SupportedPrivilegeSet($this->getSupportedPrivilegeSet($node)); + + } + if (false !== ($index = array_search('{DAV:}current-user-privilege-set', $requestedProperties))) { + + if (!$this->checkPrivileges($uri, '{DAV:}read-current-user-privilege-set', self::R_PARENT, false)) { + $returnedProperties[403]['{DAV:}current-user-privilege-set'] = null; + unset($requestedProperties[$index]); + } else { + $val = $this->getCurrentUserPrivilegeSet($node); + if (!is_null($val)) { + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}current-user-privilege-set'] = new Property\CurrentUserPrivilegeSet($val); + } + } + + } + + /* The ACL property contains all the permissions */ + if (false !== ($index = array_search('{DAV:}acl', $requestedProperties))) { + + if (!$this->checkPrivileges($uri, '{DAV:}read-acl', self::R_PARENT, false)) { + + unset($requestedProperties[$index]); + $returnedProperties[403]['{DAV:}acl'] = null; + + } else { + + $acl = $this->getACL($node); + if (!is_null($acl)) { + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}acl'] = new Property\Acl($this->getACL($node)); + } + + } + + } + + /* The acl-restrictions property contains information on how privileges + * must behave. + */ + if (false !== ($index = array_search('{DAV:}acl-restrictions', $requestedProperties))) { + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}acl-restrictions'] = new Property\AclRestrictions(); + } + + /* Adding ACL properties */ + if ($node instanceof IACL) { + + if (false !== ($index = array_search('{DAV:}owner', $requestedProperties))) { + + unset($requestedProperties[$index]); + $returnedProperties[200]['{DAV:}owner'] = new DAV\Property\Href($node->getOwner() . '/'); + + } + + } + + } + + /** + * This method intercepts PROPPATCH methods and make sure the + * group-member-set is updated correctly. + * + * @param array $propertyDelta + * @param array $result + * @param DAV\INode $node + * @return bool + */ + public function updateProperties(&$propertyDelta, &$result, DAV\INode $node) { + + if (!array_key_exists('{DAV:}group-member-set', $propertyDelta)) + return; + + if (is_null($propertyDelta['{DAV:}group-member-set'])) { + $memberSet = array(); + } elseif ($propertyDelta['{DAV:}group-member-set'] instanceof DAV\Property\HrefList) { + $memberSet = array_map( + array($this->server,'calculateUri'), + $propertyDelta['{DAV:}group-member-set']->getHrefs() + ); + } else { + throw new DAV\Exception('The group-member-set property MUST be an instance of Sabre\DAV\Property\HrefList or null'); + } + + if (!($node instanceof IPrincipal)) { + $result[403]['{DAV:}group-member-set'] = null; + unset($propertyDelta['{DAV:}group-member-set']); + + // Returning false will stop the updateProperties process + return false; + } + + $node->setGroupMemberSet($memberSet); + // We must also clear our cache, just in case + + $this->principalMembershipCache = array(); + + $result[200]['{DAV:}group-member-set'] = null; + unset($propertyDelta['{DAV:}group-member-set']); + + } + + /** + * This method handles HTTP REPORT requests + * + * @param string $reportName + * @param \DOMNode $dom + * @return bool + */ + public function report($reportName, $dom) { + + switch($reportName) { + + case '{DAV:}principal-property-search' : + $this->principalPropertySearchReport($dom); + return false; + case '{DAV:}principal-search-property-set' : + $this->principalSearchPropertySetReport($dom); + return false; + case '{DAV:}expand-property' : + $this->expandPropertyReport($dom); + return false; + + } + + } + + /** + * This event is triggered for any HTTP method that is not known by the + * webserver. + * + * @param string $method + * @param string $uri + * @return bool + */ + public function unknownMethod($method, $uri) { + + if ($method!=='ACL') return; + + $this->httpACL($uri); + return false; + + } + + /** + * This method is responsible for handling the 'ACL' event. + * + * @param string $uri + * @return void + */ + public function httpACL($uri) { + + $body = $this->server->httpRequest->getBody(true); + $dom = DAV\XMLUtil::loadDOMDocument($body); + + $newAcl = + Property\Acl::unserialize($dom->firstChild) + ->getPrivileges(); + + // Normalizing urls + foreach($newAcl as $k=>$newAce) { + $newAcl[$k]['principal'] = $this->server->calculateUri($newAce['principal']); + } + + $node = $this->server->tree->getNodeForPath($uri); + + if (!($node instanceof IACL)) { + throw new DAV\Exception\MethodNotAllowed('This node does not support the ACL method'); + } + + $oldAcl = $this->getACL($node); + + $supportedPrivileges = $this->getFlatPrivilegeSet($node); + + /* Checking if protected principals from the existing principal set are + not overwritten. */ + foreach($oldAcl as $oldAce) { + + if (!isset($oldAce['protected']) || !$oldAce['protected']) continue; + + $found = false; + foreach($newAcl as $newAce) { + if ( + $newAce['privilege'] === $oldAce['privilege'] && + $newAce['principal'] === $oldAce['principal'] && + $newAce['protected'] + ) + $found = true; + } + + if (!$found) + throw new Exception\AceConflict('This resource contained a protected {DAV:}ace, but this privilege did not occur in the ACL request'); + + } + + foreach($newAcl as $newAce) { + + // Do we recognize the privilege + if (!isset($supportedPrivileges[$newAce['privilege']])) { + throw new Exception\NotSupportedPrivilege('The privilege you specified (' . $newAce['privilege'] . ') is not recognized by this server'); + } + + if ($supportedPrivileges[$newAce['privilege']]['abstract']) { + throw new Exception\NoAbstract('The privilege you specified (' . $newAce['privilege'] . ') is an abstract privilege'); + } + + // Looking up the principal + try { + $principal = $this->server->tree->getNodeForPath($newAce['principal']); + } catch (DAV\Exception\NotFound $e) { + throw new Exception\NotRecognizedPrincipal('The specified principal (' . $newAce['principal'] . ') does not exist'); + } + if (!($principal instanceof IPrincipal)) { + throw new Exception\NotRecognizedPrincipal('The specified uri (' . $newAce['principal'] . ') is not a principal'); + } + + } + $node->setACL($newAcl); + + } + + /* }}} */ + + /* Reports {{{ */ + + /** + * The expand-property report is defined in RFC3253 section 3-8. + * + * This report is very similar to a standard PROPFIND. The difference is + * that it has the additional ability to look at properties containing a + * {DAV:}href element, follow that property and grab additional elements + * there. + * + * Other rfc's, such as ACL rely on this report, so it made sense to put + * it in this plugin. + * + * @param \DOMElement $dom + * @return void + */ + protected function expandPropertyReport($dom) { + + $requestedProperties = $this->parseExpandPropertyReportRequest($dom->firstChild->firstChild); + $depth = $this->server->getHTTPDepth(0); + $requestUri = $this->server->getRequestUri(); + + $result = $this->expandProperties($requestUri,$requestedProperties,$depth); + + $dom = new \DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + $multiStatus = $dom->createElement('d:multistatus'); + $dom->appendChild($multiStatus); + + // Adding in default namespaces + foreach($this->server->xmlNamespaces as $namespace=>$prefix) { + + $multiStatus->setAttribute('xmlns:' . $prefix,$namespace); + + } + + foreach($result as $response) { + $response->serialize($this->server, $multiStatus); + } + + $xml = $dom->saveXML(); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->sendBody($xml); + + } + + /** + * This method is used by expandPropertyReport to parse + * out the entire HTTP request. + * + * @param \DOMElement $node + * @return array + */ + protected function parseExpandPropertyReportRequest($node) { + + $requestedProperties = array(); + do { + + if (DAV\XMLUtil::toClarkNotation($node)!=='{DAV:}property') continue; + + if ($node->firstChild) { + + $children = $this->parseExpandPropertyReportRequest($node->firstChild); + + } else { + + $children = array(); + + } + + $namespace = $node->getAttribute('namespace'); + if (!$namespace) $namespace = 'DAV:'; + + $propName = '{'.$namespace.'}' . $node->getAttribute('name'); + $requestedProperties[$propName] = $children; + + } while ($node = $node->nextSibling); + + return $requestedProperties; + + } + + /** + * This method expands all the properties and returns + * a list with property values + * + * @param array $path + * @param array $requestedProperties the list of required properties + * @param int $depth + * @return array + */ + protected function expandProperties($path, array $requestedProperties, $depth) { + + $foundProperties = $this->server->getPropertiesForPath($path, array_keys($requestedProperties), $depth); + + $result = array(); + + foreach($foundProperties as $node) { + + foreach($requestedProperties as $propertyName=>$childRequestedProperties) { + + // We're only traversing if sub-properties were requested + if(count($childRequestedProperties)===0) continue; + + // We only have to do the expansion if the property was found + // and it contains an href element. + if (!array_key_exists($propertyName,$node[200])) continue; + + if ($node[200][$propertyName] instanceof DAV\Property\IHref) { + $hrefs = array($node[200][$propertyName]->getHref()); + } elseif ($node[200][$propertyName] instanceof DAV\Property\HrefList) { + $hrefs = $node[200][$propertyName]->getHrefs(); + } + + $childProps = array(); + foreach($hrefs as $href) { + $childProps = array_merge($childProps, $this->expandProperties($href, $childRequestedProperties, 0)); + } + $node[200][$propertyName] = new DAV\Property\ResponseList($childProps); + + } + $result[] = new DAV\Property\Response($node['href'], $node); + + } + + return $result; + + } + + /** + * principalSearchPropertySetReport + * + * This method responsible for handing the + * {DAV:}principal-search-property-set report. This report returns a list + * of properties the client may search on, using the + * {DAV:}principal-property-search report. + * + * @param \DOMDocument $dom + * @return void + */ + protected function principalSearchPropertySetReport(\DOMDocument $dom) { + + $httpDepth = $this->server->getHTTPDepth(0); + if ($httpDepth!==0) { + throw new DAV\Exception\BadRequest('This report is only defined when Depth: 0'); + } + + if ($dom->firstChild->hasChildNodes()) + throw new DAV\Exception\BadRequest('The principal-search-property-set report element is not allowed to have child elements'); + + $dom = new \DOMDocument('1.0','utf-8'); + $dom->formatOutput = true; + $root = $dom->createElement('d:principal-search-property-set'); + $dom->appendChild($root); + // Adding in default namespaces + foreach($this->server->xmlNamespaces as $namespace=>$prefix) { + + $root->setAttribute('xmlns:' . $prefix,$namespace); + + } + + $nsList = $this->server->xmlNamespaces; + + foreach($this->principalSearchPropertySet as $propertyName=>$description) { + + $psp = $dom->createElement('d:principal-search-property'); + $root->appendChild($psp); + + $prop = $dom->createElement('d:prop'); + $psp->appendChild($prop); + + $propName = null; + preg_match('/^{([^}]*)}(.*)$/',$propertyName,$propName); + + $currentProperty = $dom->createElement($nsList[$propName[1]] . ':' . $propName[2]); + $prop->appendChild($currentProperty); + + $descriptionElem = $dom->createElement('d:description'); + $descriptionElem->setAttribute('xml:lang','en'); + $descriptionElem->appendChild($dom->createTextNode($description)); + $psp->appendChild($descriptionElem); + + + } + + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->sendStatus(200); + $this->server->httpResponse->sendBody($dom->saveXML()); + + } + + /** + * principalPropertySearchReport + * + * This method is responsible for handing the + * {DAV:}principal-property-search report. This report can be used for + * clients to search for groups of principals, based on the value of one + * or more properties. + * + * @param \DOMDocument $dom + * @return void + */ + protected function principalPropertySearchReport(\DOMDocument $dom) { + + list($searchProperties, $requestedProperties, $applyToPrincipalCollectionSet) = $this->parsePrincipalPropertySearchReportRequest($dom); + + $uri = null; + if (!$applyToPrincipalCollectionSet) { + $uri = $this->server->getRequestUri(); + } + $result = $this->principalSearch($searchProperties, $requestedProperties, $uri); + + $prefer = $this->server->getHTTPPRefer(); + + $this->server->httpResponse->sendStatus(207); + $this->server->httpResponse->setHeader('Content-Type','application/xml; charset=utf-8'); + $this->server->httpResponse->setHeader('Vary','Brief,Prefer'); + $this->server->httpResponse->sendBody($this->server->generateMultiStatus($result, $prefer['return-minimal'])); + + } + + /** + * parsePrincipalPropertySearchReportRequest + * + * This method parses the request body from a + * {DAV:}principal-property-search report. + * + * This method returns an array with two elements: + * 1. an array with properties to search on, and their values + * 2. a list of propertyvalues that should be returned for the request. + * + * @param \DOMDocument $dom + * @return array + */ + protected function parsePrincipalPropertySearchReportRequest($dom) { + + $httpDepth = $this->server->getHTTPDepth(0); + if ($httpDepth!==0) { + throw new DAV\Exception\BadRequest('This report is only defined when Depth: 0'); + } + + $searchProperties = array(); + + $applyToPrincipalCollectionSet = false; + + // Parsing the search request + foreach($dom->firstChild->childNodes as $searchNode) { + + if (DAV\XMLUtil::toClarkNotation($searchNode) == '{DAV:}apply-to-principal-collection-set') { + $applyToPrincipalCollectionSet = true; + } + + if (DAV\XMLUtil::toClarkNotation($searchNode)!=='{DAV:}property-search') + continue; + + $propertyName = null; + $propertyValue = null; + + foreach($searchNode->childNodes as $childNode) { + + switch(DAV\XMLUtil::toClarkNotation($childNode)) { + + case '{DAV:}prop' : + $property = DAV\XMLUtil::parseProperties($searchNode); + reset($property); + $propertyName = key($property); + break; + + case '{DAV:}match' : + $propertyValue = $childNode->textContent; + break; + + } + + + } + + if (is_null($propertyName) || is_null($propertyValue)) + throw new DAV\Exception\BadRequest('Invalid search request. propertyname: ' . $propertyName . '. propertvvalue: ' . $propertyValue); + + $searchProperties[$propertyName] = $propertyValue; + + } + + return array($searchProperties, array_keys(DAV\XMLUtil::parseProperties($dom->firstChild)), $applyToPrincipalCollectionSet); + + } + + + /* }}} */ + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Principal.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Principal.php new file mode 100644 index 00000000..89277f85 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Principal.php @@ -0,0 +1,281 @@ +principalBackend = $principalBackend; + $this->principalProperties = $principalProperties; + + } + + /** + * Returns the full principal url + * + * @return string + */ + public function getPrincipalUrl() { + + return $this->principalProperties['uri']; + + } + + /** + * Returns a list of alternative urls for a principal + * + * This can for example be an email address, or ldap url. + * + * @return array + */ + public function getAlternateUriSet() { + + $uris = array(); + if (isset($this->principalProperties['{DAV:}alternate-URI-set'])) { + + $uris = $this->principalProperties['{DAV:}alternate-URI-set']; + + } + + if (isset($this->principalProperties['{http://sabredav.org/ns}email-address'])) { + $uris[] = 'mailto:' . $this->principalProperties['{http://sabredav.org/ns}email-address']; + } + + return array_unique($uris); + + } + + /** + * Returns the list of group members + * + * If this principal is a group, this function should return + * all member principal uri's for the group. + * + * @return array + */ + public function getGroupMemberSet() { + + return $this->principalBackend->getGroupMemberSet($this->principalProperties['uri']); + + } + + /** + * Returns the list of groups this principal is member of + * + * If this principal is a member of a (list of) groups, this function + * should return a list of principal uri's for it's members. + * + * @return array + */ + public function getGroupMembership() { + + return $this->principalBackend->getGroupMemberShip($this->principalProperties['uri']); + + } + + + /** + * Sets a list of group members + * + * If this principal is a group, this method sets all the group members. + * The list of members is always overwritten, never appended to. + * + * This method should throw an exception if the members could not be set. + * + * @param array $groupMembers + * @return void + */ + public function setGroupMemberSet(array $groupMembers) { + + $this->principalBackend->setGroupMemberSet($this->principalProperties['uri'], $groupMembers); + + } + + + /** + * Returns this principals name. + * + * @return string + */ + public function getName() { + + $uri = $this->principalProperties['uri']; + list(, $name) = DAV\URLUtil::splitPath($uri); + return $name; + + } + + /** + * Returns the name of the user + * + * @return string + */ + public function getDisplayName() { + + if (isset($this->principalProperties['{DAV:}displayname'])) { + return $this->principalProperties['{DAV:}displayname']; + } else { + return $this->getName(); + } + + } + + /** + * Returns a list of properties + * + * @param array $requestedProperties + * @return array + */ + public function getProperties($requestedProperties) { + + $newProperties = array(); + foreach($requestedProperties as $propName) { + + if (isset($this->principalProperties[$propName])) { + $newProperties[$propName] = $this->principalProperties[$propName]; + } + + } + + return $newProperties; + + } + + /** + * Updates this principals properties. + * + * @param array $mutations + * @see Sabre\DAV\IProperties::updateProperties + * @return bool|array + */ + public function updateProperties($mutations) { + + return $this->principalBackend->updatePrincipal($this->principalProperties['uri'], $mutations); + + } + + /** + * Returns the owner principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getOwner() { + + return $this->principalProperties['uri']; + + + } + + /** + * Returns a group principal + * + * This must be a url to a principal, or null if there's no owner + * + * @return string|null + */ + public function getGroup() { + + return null; + + } + + /** + * Returns a list of ACE's for this node. + * + * Each ACE has the following properties: + * * 'privilege', a string such as {DAV:}read or {DAV:}write. These are + * currently the only supported privileges + * * 'principal', a url to the principal who owns the node + * * 'protected' (optional), indicating that this ACE is not allowed to + * be updated. + * + * @return array + */ + public function getACL() { + + return array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->getPrincipalUrl(), + 'protected' => true, + ), + ); + + } + + /** + * Updates the ACL + * + * This method will receive a list of new ACE's. + * + * @param array $acl + * @return void + */ + public function setACL(array $acl) { + + throw new DAV\Exception\MethodNotAllowed('Updating ACLs is not allowed here'); + + } + + /** + * Returns the list of supported privileges for this node. + * + * The returned data structure is a list of nested privileges. + * See Sabre\DAVACL\Plugin::getDefaultSupportedPrivilegeSet for a simple + * standard structure. + * + * If null is returned from this method, the default privilege set is used, + * which is fine for most common usecases. + * + * @return array|null + */ + public function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/AbstractBackend.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/AbstractBackend.php new file mode 100644 index 00000000..984f9ad8 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/AbstractBackend.php @@ -0,0 +1,18 @@ + array( + * '{DAV:}prop1' => null, + * ), + * 201 => array( + * '{DAV:}prop2' => null, + * ), + * 403 => array( + * '{DAV:}prop3' => null, + * ), + * 424 => array( + * '{DAV:}prop4' => null, + * ), + * ); + * + * In this previous example prop1 was successfully updated or deleted, and + * prop2 was succesfully created. + * + * prop3 failed to update due to '403 Forbidden' and because of this prop4 + * also could not be updated with '424 Failed dependency'. + * + * This last example was actually incorrect. While 200 and 201 could appear + * in 1 response, if there's any error (403) the other properties should + * always fail with 423 (failed dependency). + * + * But anyway, if you don't want to scratch your head over this, just + * return true or false. + * + * @param string $path + * @param array $mutations + * @return array|bool + */ + function updatePrincipal($path, $mutations); + + /** + * This method is used to search for principals matching a set of + * properties. + * + * This search is specifically used by RFC3744's principal-property-search + * REPORT. You should at least allow searching on + * http://sabredav.org/ns}email-address. + * + * The actual search should be a unicode-non-case-sensitive search. The + * keys in searchProperties are the WebDAV property names, while the values + * are the property values to search on. + * + * If multiple properties are being searched on, the search should be + * AND'ed. + * + * This method should simply return an array with full principal uri's. + * + * If somebody attempted to search on a property the backend does not + * support, you should simply return 0 results. + * + * You can also just return 0 results if you choose to not support + * searching at all, but keep in mind that this may stop certain features + * from working. + * + * @param string $prefixPath + * @param array $searchProperties + * @return array + */ + function searchPrincipals($prefixPath, array $searchProperties); + + /** + * Returns the list of members for a group-principal + * + * @param string $principal + * @return array + */ + function getGroupMemberSet($principal); + + /** + * Returns the list of groups a principal is a member of + * + * @param string $principal + * @return array + */ + function getGroupMembership($principal); + + /** + * Updates the list of group members for a group principal. + * + * The principals should be passed as a list of uri's. + * + * @param string $principal + * @param array $members + * @return void + */ + function setGroupMemberSet($principal, array $members); + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/PDO.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/PDO.php new file mode 100644 index 00000000..0921768c --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalBackend/PDO.php @@ -0,0 +1,428 @@ + array( + 'dbField' => 'displayname', + ), + + /** + * This property is actually used by the CardDAV plugin, where it gets + * mapped to {http://calendarserver.orgi/ns/}me-card. + * + * The reason we don't straight-up use that property, is because + * me-card is defined as a property on the users' addressbook + * collection. + */ + '{http://sabredav.org/ns}vcard-url' => array( + 'dbField' => 'vcardurl', + ), + /** + * This is the users' primary email-address. + */ + '{http://sabredav.org/ns}email-address' => array( + 'dbField' => 'email', + ), + ); + + /** + * Sets up the backend. + * + * @param PDO $pdo + * @param string $tableName + * @param string $groupMembersTableName + */ + public function __construct(\PDO $pdo, $tableName = 'principals', $groupMembersTableName = 'groupmembers') { + + $this->pdo = $pdo; + $this->tableName = $tableName; + $this->groupMembersTableName = $groupMembersTableName; + + } + + + /** + * Returns a list of principals based on a prefix. + * + * This prefix will often contain something like 'principals'. You are only + * expected to return principals that are in this base path. + * + * You are expected to return at least a 'uri' for every user, you can + * return any additional properties if you wish so. Common properties are: + * {DAV:}displayname + * {http://sabredav.org/ns}email-address - This is a custom SabreDAV + * field that's actualy injected in a number of other properties. If + * you have an email address, use this property. + * + * @param string $prefixPath + * @return array + */ + public function getPrincipalsByPrefix($prefixPath) { + + $fields = array( + 'uri', + ); + + foreach($this->fieldMap as $key=>$value) { + $fields[] = $value['dbField']; + } + $result = $this->pdo->query('SELECT '.implode(',', $fields).' FROM '. $this->tableName); + + $principals = array(); + + while($row = $result->fetch(\PDO::FETCH_ASSOC)) { + + // Checking if the principal is in the prefix + list($rowPrefix) = DAV\URLUtil::splitPath($row['uri']); + if ($rowPrefix !== $prefixPath) continue; + + $principal = array( + 'uri' => $row['uri'], + ); + foreach($this->fieldMap as $key=>$value) { + if ($row[$value['dbField']]) { + $principal[$key] = $row[$value['dbField']]; + } + } + $principals[] = $principal; + + } + + return $principals; + + } + + /** + * Returns a specific principal, specified by it's path. + * The returned structure should be the exact same as from + * getPrincipalsByPrefix. + * + * @param string $path + * @return array + */ + public function getPrincipalByPath($path) { + + $fields = array( + 'id', + 'uri', + ); + + foreach($this->fieldMap as $key=>$value) { + $fields[] = $value['dbField']; + } + $stmt = $this->pdo->prepare('SELECT '.implode(',', $fields).' FROM '. $this->tableName . ' WHERE uri = ?'); + $stmt->execute(array($path)); + + $row = $stmt->fetch(\PDO::FETCH_ASSOC); + if (!$row) return; + + $principal = array( + 'id' => $row['id'], + 'uri' => $row['uri'], + ); + foreach($this->fieldMap as $key=>$value) { + if ($row[$value['dbField']]) { + $principal[$key] = $row[$value['dbField']]; + } + } + return $principal; + + } + + /** + * Updates one ore more webdav properties on a principal. + * + * The list of mutations is supplied as an array. Each key in the array is + * a propertyname, such as {DAV:}displayname. + * + * Each value is the actual value to be updated. If a value is null, it + * must be deleted. + * + * This method should be atomic. It must either completely succeed, or + * completely fail. Success and failure can simply be returned as 'true' or + * 'false'. + * + * It is also possible to return detailed failure information. In that case + * an array such as this should be returned: + * + * array( + * 200 => array( + * '{DAV:}prop1' => null, + * ), + * 201 => array( + * '{DAV:}prop2' => null, + * ), + * 403 => array( + * '{DAV:}prop3' => null, + * ), + * 424 => array( + * '{DAV:}prop4' => null, + * ), + * ); + * + * In this previous example prop1 was successfully updated or deleted, and + * prop2 was succesfully created. + * + * prop3 failed to update due to '403 Forbidden' and because of this prop4 + * also could not be updated with '424 Failed dependency'. + * + * This last example was actually incorrect. While 200 and 201 could appear + * in 1 response, if there's any error (403) the other properties should + * always fail with 423 (failed dependency). + * + * But anyway, if you don't want to scratch your head over this, just + * return true or false. + * + * @param string $path + * @param array $mutations + * @return array|bool + */ + public function updatePrincipal($path, $mutations) { + + $updateAble = array(); + foreach($mutations as $key=>$value) { + + // We are not aware of this field, we must fail. + if (!isset($this->fieldMap[$key])) { + + $response = array( + 403 => array( + $key => null, + ), + 424 => array(), + ); + + // Adding the rest to the response as a 424 + foreach($mutations as $subKey=>$subValue) { + if ($subKey !== $key) { + $response[424][$subKey] = null; + } + } + return $response; + } + + $updateAble[$this->fieldMap[$key]['dbField']] = $value; + + } + + // No fields to update + $query = "UPDATE " . $this->tableName . " SET "; + + $first = true; + foreach($updateAble as $key => $value) { + if (!$first) { + $query.= ', '; + } + $first = false; + $query.= "$key = :$key "; + } + $query.='WHERE uri = :uri'; + $stmt = $this->pdo->prepare($query); + $updateAble['uri'] = $path; + $stmt->execute($updateAble); + + return true; + + } + + /** + * This method is used to search for principals matching a set of + * properties. + * + * This search is specifically used by RFC3744's principal-property-search + * REPORT. You should at least allow searching on + * http://sabredav.org/ns}email-address. + * + * The actual search should be a unicode-non-case-sensitive search. The + * keys in searchProperties are the WebDAV property names, while the values + * are the property values to search on. + * + * If multiple properties are being searched on, the search should be + * AND'ed. + * + * This method should simply return an array with full principal uri's. + * + * If somebody attempted to search on a property the backend does not + * support, you should simply return 0 results. + * + * You can also just return 0 results if you choose to not support + * searching at all, but keep in mind that this may stop certain features + * from working. + * + * @param string $prefixPath + * @param array $searchProperties + * @return array + */ + public function searchPrincipals($prefixPath, array $searchProperties) { + + $query = 'SELECT uri FROM ' . $this->tableName . ' WHERE 1=1 '; + $values = array(); + foreach($searchProperties as $property => $value) { + + switch($property) { + + case '{DAV:}displayname' : + $query.=' AND displayname LIKE ?'; + $values[] = '%' . $value . '%'; + break; + case '{http://sabredav.org/ns}email-address' : + $query.=' AND email LIKE ?'; + $values[] = '%' . $value . '%'; + break; + default : + // Unsupported property + return array(); + + } + + } + $stmt = $this->pdo->prepare($query); + $stmt->execute($values); + + $principals = array(); + while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + + // Checking if the principal is in the prefix + list($rowPrefix) = DAV\URLUtil::splitPath($row['uri']); + if ($rowPrefix !== $prefixPath) continue; + + $principals[] = $row['uri']; + + } + + return $principals; + + } + + /** + * Returns the list of members for a group-principal + * + * @param string $principal + * @return array + */ + public function getGroupMemberSet($principal) { + + $principal = $this->getPrincipalByPath($principal); + if (!$principal) throw new DAV\Exception('Principal not found'); + + $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.member_id = principals.id WHERE groupmembers.principal_id = ?'); + $stmt->execute(array($principal['id'])); + + $result = array(); + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $result[] = $row['uri']; + } + return $result; + + } + + /** + * Returns the list of groups a principal is a member of + * + * @param string $principal + * @return array + */ + public function getGroupMembership($principal) { + + $principal = $this->getPrincipalByPath($principal); + if (!$principal) throw new DAV\Exception('Principal not found'); + + $stmt = $this->pdo->prepare('SELECT principals.uri as uri FROM '.$this->groupMembersTableName.' AS groupmembers LEFT JOIN '.$this->tableName.' AS principals ON groupmembers.principal_id = principals.id WHERE groupmembers.member_id = ?'); + $stmt->execute(array($principal['id'])); + + $result = array(); + while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + $result[] = $row['uri']; + } + return $result; + + } + + /** + * Updates the list of group members for a group principal. + * + * The principals should be passed as a list of uri's. + * + * @param string $principal + * @param array $members + * @return void + */ + public function setGroupMemberSet($principal, array $members) { + + // Grabbing the list of principal id's. + $stmt = $this->pdo->prepare('SELECT id, uri FROM '.$this->tableName.' WHERE uri IN (? ' . str_repeat(', ? ', count($members)) . ');'); + $stmt->execute(array_merge(array($principal), $members)); + + $memberIds = array(); + $principalId = null; + + while($row = $stmt->fetch(\PDO::FETCH_ASSOC)) { + if ($row['uri'] == $principal) { + $principalId = $row['id']; + } else { + $memberIds[] = $row['id']; + } + } + if (!$principalId) throw new DAV\Exception('Principal not found'); + + // Wiping out old members + $stmt = $this->pdo->prepare('DELETE FROM '.$this->groupMembersTableName.' WHERE principal_id = ?;'); + $stmt->execute(array($principalId)); + + foreach($memberIds as $memberId) { + + $stmt = $this->pdo->prepare('INSERT INTO '.$this->groupMembersTableName.' (principal_id, member_id) VALUES (?, ?);'); + $stmt->execute(array($principalId, $memberId)); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalCollection.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalCollection.php new file mode 100644 index 00000000..3aadf399 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/PrincipalCollection.php @@ -0,0 +1,33 @@ +principalBackend, $principal); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Acl.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Acl.php new file mode 100644 index 00000000..e6a70ce9 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Acl.php @@ -0,0 +1,211 @@ +privileges = $privileges; + $this->prefixBaseUrl = $prefixBaseUrl; + + } + + /** + * Returns the list of privileges for this property + * + * @return array + */ + public function getPrivileges() { + + return $this->privileges; + + } + + /** + * Serializes the property into a DOMElement + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + foreach($this->privileges as $ace) { + + $this->serializeAce($doc, $node, $ace, $server); + + } + + } + + /** + * Unserializes the {DAV:}acl xml element. + * + * @param \DOMElement $dom + * @return Acl + */ + static public function unserialize(\DOMElement $dom) { + + $privileges = array(); + $xaces = $dom->getElementsByTagNameNS('urn:DAV','ace'); + for($ii=0; $ii < $xaces->length; $ii++) { + + $xace = $xaces->item($ii); + $principal = $xace->getElementsByTagNameNS('urn:DAV','principal'); + if ($principal->length !== 1) { + throw new DAV\Exception\BadRequest('Each {DAV:}ace element must have one {DAV:}principal element'); + } + $principal = Principal::unserialize($principal->item(0)); + + switch($principal->getType()) { + case Principal::HREF : + $principal = $principal->getHref(); + break; + case Principal::AUTHENTICATED : + $principal = '{DAV:}authenticated'; + break; + case Principal::UNAUTHENTICATED : + $principal = '{DAV:}unauthenticated'; + break; + case Principal::ALL : + $principal = '{DAV:}all'; + break; + + } + + $protected = false; + + if ($xace->getElementsByTagNameNS('urn:DAV','protected')->length > 0) { + $protected = true; + } + + $grants = $xace->getElementsByTagNameNS('urn:DAV','grant'); + if ($grants->length < 1) { + throw new DAV\Exception\NotImplemented('Every {DAV:}ace element must have a {DAV:}grant element. {DAV:}deny is not yet supported'); + } + $grant = $grants->item(0); + + $xprivs = $grant->getElementsByTagNameNS('urn:DAV','privilege'); + for($jj=0; $jj<$xprivs->length; $jj++) { + + $xpriv = $xprivs->item($jj); + + $privilegeName = null; + + for ($kk=0;$kk<$xpriv->childNodes->length;$kk++) { + + $childNode = $xpriv->childNodes->item($kk); + if ($t = DAV\XMLUtil::toClarkNotation($childNode)) { + $privilegeName = $t; + break; + } + } + if (is_null($privilegeName)) { + throw new DAV\Exception\BadRequest('{DAV:}privilege elements must have a privilege element contained within them.'); + } + + $privileges[] = array( + 'principal' => $principal, + 'protected' => $protected, + 'privilege' => $privilegeName, + ); + + } + + } + + return new self($privileges); + + } + + /** + * Serializes a single access control entry. + * + * @param \DOMDocument $doc + * @param \DOMElement $node + * @param array $ace + * @param DAV\Server $server + * @return void + */ + private function serializeAce($doc,$node,$ace, DAV\Server $server) { + + $xace = $doc->createElementNS('DAV:','d:ace'); + $node->appendChild($xace); + + $principal = $doc->createElementNS('DAV:','d:principal'); + $xace->appendChild($principal); + switch($ace['principal']) { + case '{DAV:}authenticated' : + $principal->appendChild($doc->createElementNS('DAV:','d:authenticated')); + break; + case '{DAV:}unauthenticated' : + $principal->appendChild($doc->createElementNS('DAV:','d:unauthenticated')); + break; + case '{DAV:}all' : + $principal->appendChild($doc->createElementNS('DAV:','d:all')); + break; + default: + $principal->appendChild($doc->createElementNS('DAV:','d:href',($this->prefixBaseUrl?$server->getBaseUri():'') . $ace['principal'] . '/')); + } + + $grant = $doc->createElementNS('DAV:','d:grant'); + $xace->appendChild($grant); + + $privParts = null; + + preg_match('/^{([^}]*)}(.*)$/',$ace['privilege'],$privParts); + + $xprivilege = $doc->createElementNS('DAV:','d:privilege'); + $grant->appendChild($xprivilege); + + $xprivilege->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2])); + + if (isset($ace['protected']) && $ace['protected']) + $xace->appendChild($doc->createElement('d:protected')); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/AclRestrictions.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/AclRestrictions.php new file mode 100644 index 00000000..aa6fd17d --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/AclRestrictions.php @@ -0,0 +1,34 @@ +ownerDocument; + + $elem->appendChild($doc->createElementNS('DAV:','d:grant-only')); + $elem->appendChild($doc->createElementNS('DAV:','d:no-invert')); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/CurrentUserPrivilegeSet.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/CurrentUserPrivilegeSet.php new file mode 100644 index 00000000..e0501dbd --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/CurrentUserPrivilegeSet.php @@ -0,0 +1,124 @@ +privileges = $privileges; + + } + + /** + * Serializes the property in the DOM + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + foreach($this->privileges as $privName) { + + $this->serializePriv($doc,$node,$privName); + + } + + } + + /** + * Returns true or false, whether the specified principal appears in the + * list. + * + * @return bool + */ + public function has($privilegeName) { + + return in_array($privilegeName, $this->privileges); + + } + + /** + * Serializes one privilege + * + * @param \DOMDocument $doc + * @param \DOMElement $node + * @param string $privName + * @return void + */ + protected function serializePriv($doc,$node,$privName) { + + $xp = $doc->createElementNS('DAV:','d:privilege'); + $node->appendChild($xp); + + $privParts = null; + preg_match('/^{([^}]*)}(.*)$/',$privName,$privParts); + + $xp->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2])); + + } + + /** + * Unserializes the {DAV:}current-user-privilege-set element. + * + * @param DOMElement $node + * @return CurrentUserPrivilegeSet + */ + static public function unserialize(\DOMElement $node) { + + $result = array(); + + $xprivs = $node->getElementsByTagNameNS('urn:DAV','privilege'); + + for($jj=0; $jj<$xprivs->length; $jj++) { + + $xpriv = $xprivs->item($jj); + + $privilegeName = null; + + for ($kk=0;$kk<$xpriv->childNodes->length;$kk++) { + + $childNode = $xpriv->childNodes->item($kk); + if ($t = DAV\XMLUtil::toClarkNotation($childNode)) { + $privilegeName = $t; + break; + } + } + + $result[] = $privilegeName; + + } + + return new self($result); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Principal.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Principal.php new file mode 100644 index 00000000..6c644b02 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/Principal.php @@ -0,0 +1,161 @@ +type = $type; + + if ($type===self::HREF && is_null($href)) { + throw new DAV\Exception('The href argument must be specified for the HREF principal type.'); + } + $this->href = $href; + + } + + /** + * Returns the principal type + * + * @return int + */ + public function getType() { + + return $this->type; + + } + + /** + * Returns the principal uri. + * + * @return string + */ + public function getHref() { + + return $this->href; + + } + + /** + * Serializes the property into a DOMElement. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server, \DOMElement $node) { + + $prefix = $server->xmlNamespaces['DAV:']; + switch($this->type) { + + case self::UNAUTHENTICATED : + $node->appendChild( + $node->ownerDocument->createElement($prefix . ':unauthenticated') + ); + break; + case self::AUTHENTICATED : + $node->appendChild( + $node->ownerDocument->createElement($prefix . ':authenticated') + ); + break; + case self::HREF : + $href = $node->ownerDocument->createElement($prefix . ':href'); + $href->nodeValue = $server->getBaseUri() . DAV\URLUtil::encodePath($this->href); + $node->appendChild($href); + break; + + } + + } + + /** + * Deserializes a DOM element into a property object. + * + * @param \DOMElement $dom + * @return Principal + */ + static public function unserialize(\DOMElement $dom) { + + $parent = $dom->firstChild; + while(!DAV\XMLUtil::toClarkNotation($parent)) { + $parent = $parent->nextSibling; + } + + switch(DAV\XMLUtil::toClarkNotation($parent)) { + + case '{DAV:}unauthenticated' : + return new self(self::UNAUTHENTICATED); + case '{DAV:}authenticated' : + return new self(self::AUTHENTICATED); + case '{DAV:}href': + return new self(self::HREF, $parent->textContent); + case '{DAV:}all': + return new self(self::ALL); + default : + throw new DAV\Exception\BadRequest('Unexpected element (' . DAV\XMLUtil::toClarkNotation($parent) . '). Could not deserialize'); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/SupportedPrivilegeSet.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/SupportedPrivilegeSet.php new file mode 100644 index 00000000..5f152d9e --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Property/SupportedPrivilegeSet.php @@ -0,0 +1,94 @@ +privileges = $privileges; + + } + + /** + * Serializes the property into a domdocument. + * + * @param DAV\Server $server + * @param \DOMElement $node + * @return void + */ + public function serialize(DAV\Server $server,\DOMElement $node) { + + $doc = $node->ownerDocument; + $this->serializePriv($doc, $node, $this->privileges); + + } + + /** + * Serializes a property + * + * This is a recursive function. + * + * @param \DOMDocument $doc + * @param \DOMElement $node + * @param array $privilege + * @return void + */ + private function serializePriv($doc,$node,$privilege) { + + $xsp = $doc->createElementNS('DAV:','d:supported-privilege'); + $node->appendChild($xsp); + + $xp = $doc->createElementNS('DAV:','d:privilege'); + $xsp->appendChild($xp); + + $privParts = null; + preg_match('/^{([^}]*)}(.*)$/',$privilege['privilege'],$privParts); + + $xp->appendChild($doc->createElementNS($privParts[1],'d:'.$privParts[2])); + + if (isset($privilege['abstract']) && $privilege['abstract']) { + $xsp->appendChild($doc->createElementNS('DAV:','d:abstract')); + } + + if (isset($privilege['description'])) { + $xsp->appendChild($doc->createElementNS('DAV:','d:description',$privilege['description'])); + } + + if (isset($privilege['aggregates'])) { + foreach($privilege['aggregates'] as $subPrivilege) { + $this->serializePriv($doc,$xsp,$subPrivilege); + } + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Version.php b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Version.php new file mode 100644 index 00000000..344e22d7 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/DAVACL/Version.php @@ -0,0 +1,24 @@ +httpRequest->getHeader('Authorization'); + $authHeader = explode(' ',$authHeader); + + if ($authHeader[0]!='AWS' || !isset($authHeader[1])) { + $this->errorCode = self::ERR_NOAWSHEADER; + return false; + } + + list($this->accessKey,$this->signature) = explode(':',$authHeader[1]); + + return true; + + } + + /** + * Returns the username for the request + * + * @return string + */ + public function getAccessKey() { + + return $this->accessKey; + + } + + /** + * Validates the signature based on the secretKey + * + * @param string $secretKey + * @return bool + */ + public function validate($secretKey) { + + $contentMD5 = $this->httpRequest->getHeader('Content-MD5'); + + if ($contentMD5) { + // We need to validate the integrity of the request + $body = $this->httpRequest->getBody(true); + $this->httpRequest->setBody($body,true); + + if ($contentMD5!=base64_encode(md5($body,true))) { + // content-md5 header did not match md5 signature of body + $this->errorCode = self::ERR_MD5CHECKSUMWRONG; + return false; + } + + } + + if (!$requestDate = $this->httpRequest->getHeader('x-amz-date')) + $requestDate = $this->httpRequest->getHeader('Date'); + + if (!$this->validateRFC2616Date($requestDate)) + return false; + + $amzHeaders = $this->getAmzHeaders(); + + $signature = base64_encode( + $this->hmacsha1($secretKey, + $this->httpRequest->getMethod() . "\n" . + $contentMD5 . "\n" . + $this->httpRequest->getHeader('Content-type') . "\n" . + $requestDate . "\n" . + $amzHeaders . + $this->httpRequest->getURI() + ) + ); + + if ($this->signature != $signature) { + + $this->errorCode = self::ERR_INVALIDSIGNATURE; + return false; + + } + + return true; + + } + + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $this->httpResponse->setHeader('WWW-Authenticate','AWS'); + $this->httpResponse->sendStatus(401); + + } + + /** + * Makes sure the supplied value is a valid RFC2616 date. + * + * If we would just use strtotime to get a valid timestamp, we have no way of checking if a + * user just supplied the word 'now' for the date header. + * + * This function also makes sure the Date header is within 15 minutes of the operating + * system date, to prevent replay attacks. + * + * @param string $dateHeader + * @return bool + */ + protected function validateRFC2616Date($dateHeader) { + + $date = Util::parseHTTPDate($dateHeader); + + // Unknown format + if (!$date) { + $this->errorCode = self::ERR_INVALIDDATEFORMAT; + return false; + } + + $min = new \DateTime('-15 minutes'); + $max = new \DateTime('+15 minutes'); + + // We allow 15 minutes around the current date/time + if ($date > $max || $date < $min) { + $this->errorCode = self::ERR_REQUESTTIMESKEWED; + return false; + } + + return $date; + + } + + /** + * Returns a list of AMZ headers + * + * @return string + */ + protected function getAmzHeaders() { + + $amzHeaders = array(); + $headers = $this->httpRequest->getHeaders(); + foreach($headers as $headerName => $headerValue) { + if (strpos(strtolower($headerName),'x-amz-')===0) { + $amzHeaders[strtolower($headerName)] = str_replace(array("\r\n"),array(' '),$headerValue) . "\n"; + } + } + ksort($amzHeaders); + + $headerStr = ''; + foreach($amzHeaders as $h=>$v) { + $headerStr.=$h.':'.$v; + } + + return $headerStr; + + } + + /** + * Generates an HMAC-SHA1 signature + * + * @param string $key + * @param string $message + * @return string + */ + private function hmacsha1($key, $message) { + + $blocksize=64; + if (strlen($key)>$blocksize) + $key=pack('H*', sha1($key)); + $key=str_pad($key,$blocksize,chr(0x00)); + $ipad=str_repeat(chr(0x36),$blocksize); + $opad=str_repeat(chr(0x5c),$blocksize); + $hmac = pack('H*',sha1(($key^$opad).pack('H*',sha1(($key^$ipad).$message)))); + return $hmac; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/AbstractAuth.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/AbstractAuth.php new file mode 100644 index 00000000..1ddf412b --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/AbstractAuth.php @@ -0,0 +1,111 @@ +httpResponse = new Response(); + $this->httpRequest = new Request(); + + } + + /** + * Sets an alternative HTTP response object + * + * @param Response $response + * @return void + */ + public function setHTTPResponse(Response $response) { + + $this->httpResponse = $response; + + } + + /** + * Sets an alternative HTTP request object + * + * @param Request $request + * @return void + */ + public function setHTTPRequest(Request $request) { + + $this->httpRequest = $request; + + } + + + /** + * Sets the realm + * + * The realm is often displayed in authentication dialog boxes + * Commonly an application name displayed here + * + * @param string $realm + * @return void + */ + public function setRealm($realm) { + + $this->realm = $realm; + + } + + /** + * Returns the realm + * + * @return string + */ + public function getRealm() { + + return $this->realm; + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + abstract public function requireLogin(); + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/BasicAuth.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/BasicAuth.php new file mode 100644 index 00000000..659964fa --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/BasicAuth.php @@ -0,0 +1,67 @@ +httpRequest->getRawServerValue('PHP_AUTH_USER')) && ($pass = $this->httpRequest->getRawServerValue('PHP_AUTH_PW'))) { + + return array($user,$pass); + + } + + // Most other webservers + $auth = $this->httpRequest->getHeader('Authorization'); + + // Apache could prefix environment variables with REDIRECT_ when urls + // are passed through mod_rewrite + if (!$auth) { + $auth = $this->httpRequest->getRawServerValue('REDIRECT_HTTP_AUTHORIZATION'); + } + + if (!$auth) return false; + + if (strpos(strtolower($auth),'basic')!==0) return false; + + return explode(':', base64_decode(substr($auth, 6)),2); + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $this->httpResponse->setHeader('WWW-Authenticate','Basic realm="' . $this->realm . '"'); + $this->httpResponse->sendStatus(401); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/DigestAuth.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/DigestAuth.php new file mode 100644 index 00000000..aae6d84d --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/DigestAuth.php @@ -0,0 +1,240 @@ +nonce = uniqid(); + $this->opaque = md5($this->realm); + parent::__construct(); + + } + + /** + * Gathers all information from the headers + * + * This method needs to be called prior to anything else. + * + * @return void + */ + public function init() { + + $digest = $this->getDigest(); + $this->digestParts = $this->parseDigest($digest); + + } + + /** + * Sets the quality of protection value. + * + * Possible values are: + * Sabre\HTTP\DigestAuth::QOP_AUTH + * Sabre\HTTP\DigestAuth::QOP_AUTHINT + * + * Multiple values can be specified using logical OR. + * + * QOP_AUTHINT ensures integrity of the request body, but this is not + * supported by most HTTP clients. QOP_AUTHINT also requires the entire + * request body to be md5'ed, which can put strains on CPU and memory. + * + * @param int $qop + * @return void + */ + public function setQOP($qop) { + + $this->qop = $qop; + + } + + /** + * Validates the user. + * + * The A1 parameter should be md5($username . ':' . $realm . ':' . $password); + * + * @param string $A1 + * @return bool + */ + public function validateA1($A1) { + + $this->A1 = $A1; + return $this->validate(); + + } + + /** + * Validates authentication through a password. The actual password must be provided here. + * It is strongly recommended not store the password in plain-text and use validateA1 instead. + * + * @param string $password + * @return bool + */ + public function validatePassword($password) { + + $this->A1 = md5($this->digestParts['username'] . ':' . $this->realm . ':' . $password); + return $this->validate(); + + } + + /** + * Returns the username for the request + * + * @return string + */ + public function getUsername() { + + return $this->digestParts['username']; + + } + + /** + * Validates the digest challenge + * + * @return bool + */ + protected function validate() { + + $A2 = $this->httpRequest->getMethod() . ':' . $this->digestParts['uri']; + + if ($this->digestParts['qop']=='auth-int') { + // Making sure we support this qop value + if (!($this->qop & self::QOP_AUTHINT)) return false; + // We need to add an md5 of the entire request body to the A2 part of the hash + $body = $this->httpRequest->getBody(true); + $this->httpRequest->setBody($body,true); + $A2 .= ':' . md5($body); + } else { + + // We need to make sure we support this qop value + if (!($this->qop & self::QOP_AUTH)) return false; + } + + $A2 = md5($A2); + + $validResponse = md5("{$this->A1}:{$this->digestParts['nonce']}:{$this->digestParts['nc']}:{$this->digestParts['cnonce']}:{$this->digestParts['qop']}:{$A2}"); + + return $this->digestParts['response']==$validResponse; + + + } + + /** + * Returns an HTTP 401 header, forcing login + * + * This should be called when username and password are incorrect, or not supplied at all + * + * @return void + */ + public function requireLogin() { + + $qop = ''; + switch($this->qop) { + case self::QOP_AUTH : $qop = 'auth'; break; + case self::QOP_AUTHINT : $qop = 'auth-int'; break; + case self::QOP_AUTH | self::QOP_AUTHINT : $qop = 'auth,auth-int'; break; + } + + $this->httpResponse->setHeader('WWW-Authenticate','Digest realm="' . $this->realm . '",qop="'.$qop.'",nonce="' . $this->nonce . '",opaque="' . $this->opaque . '"'); + $this->httpResponse->sendStatus(401); + + } + + + /** + * This method returns the full digest string. + * + * It should be compatibile with mod_php format and other webservers. + * + * If the header could not be found, null will be returned + * + * @return mixed + */ + public function getDigest() { + + // mod_php + $digest = $this->httpRequest->getRawServerValue('PHP_AUTH_DIGEST'); + if ($digest) return $digest; + + // most other servers + $digest = $this->httpRequest->getHeader('Authorization'); + + // Apache could prefix environment variables with REDIRECT_ when urls + // are passed through mod_rewrite + if (!$digest) { + $digest = $this->httpRequest->getRawServerValue('REDIRECT_HTTP_AUTHORIZATION'); + } + + if ($digest && strpos(strtolower($digest),'digest')===0) { + return substr($digest,7); + } else { + return null; + } + + } + + + /** + * Parses the different pieces of the digest string into an array. + * + * This method returns false if an incomplete digest was supplied + * + * @param string $digest + * @return mixed + */ + protected function parseDigest($digest) { + + // protect against missing data + $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); + $data = array(); + + preg_match_all('@(\w+)=(?:(?:")([^"]+)"|([^\s,$]+))@', $digest, $matches, PREG_SET_ORDER); + + foreach ($matches as $m) { + $data[$m[1]] = $m[2] ? $m[2] : $m[3]; + unset($needed_parts[$m[1]]); + } + + return $needed_parts ? false : $data; + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/Request.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Request.php new file mode 100644 index 00000000..a71a52b4 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Request.php @@ -0,0 +1,284 @@ +_SERVER = $serverData; + else $this->_SERVER =& $_SERVER; + + if ($postData) $this->_POST = $postData; + else $this->_POST =& $_POST; + + } + + /** + * Returns the value for a specific http header. + * + * This method returns null if the header did not exist. + * + * @param string $name + * @return string + */ + public function getHeader($name) { + + $name = strtoupper(str_replace(array('-'),array('_'),$name)); + if (isset($this->_SERVER['HTTP_' . $name])) { + return $this->_SERVER['HTTP_' . $name]; + } + + // There's a few headers that seem to end up in the top-level + // server array. + switch($name) { + case 'CONTENT_TYPE' : + case 'CONTENT_LENGTH' : + if (isset($this->_SERVER[$name])) { + return $this->_SERVER[$name]; + } + break; + + } + return; + + } + + /** + * Returns all (known) HTTP headers. + * + * All headers are converted to lower-case, and additionally all underscores + * are automatically converted to dashes + * + * @return array + */ + public function getHeaders() { + + $hdrs = array(); + foreach($this->_SERVER as $key=>$value) { + + switch($key) { + case 'CONTENT_LENGTH' : + case 'CONTENT_TYPE' : + $hdrs[strtolower(str_replace('_','-',$key))] = $value; + break; + default : + if (strpos($key,'HTTP_')===0) { + $hdrs[substr(strtolower(str_replace('_','-',$key)),5)] = $value; + } + break; + } + + } + + return $hdrs; + + } + + /** + * Returns the HTTP request method + * + * This is for example POST or GET + * + * @return string + */ + public function getMethod() { + + return $this->_SERVER['REQUEST_METHOD']; + + } + + /** + * Returns the requested uri + * + * @return string + */ + public function getUri() { + + return $this->_SERVER['REQUEST_URI']; + + } + + /** + * Will return protocol + the hostname + the uri + * + * @return string + */ + public function getAbsoluteUri() { + + // Checking if the request was made through HTTPS. The last in line is for IIS + $protocol = isset($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']) && ($this->_SERVER['HTTPS']!='off'); + return ($protocol?'https':'http') . '://' . $this->getHeader('Host') . $this->getUri(); + + } + + /** + * Returns everything after the ? from the current url + * + * @return string + */ + public function getQueryString() { + + return isset($this->_SERVER['QUERY_STRING'])?$this->_SERVER['QUERY_STRING']:''; + + } + + /** + * Returns the HTTP request body body + * + * This method returns a readable stream resource. + * If the asString parameter is set to true, a string is sent instead. + * + * @param bool $asString + * @return resource + */ + public function getBody($asString = false) { + + if (is_null($this->body)) { + if (!is_null(self::$defaultInputStream)) { + $this->body = self::$defaultInputStream; + } else { + $this->body = fopen('php://input','r'); + self::$defaultInputStream = $this->body; + } + } + if ($asString) { + $body = stream_get_contents($this->body); + return $body; + } else { + return $this->body; + } + + } + + /** + * Sets the contents of the HTTP request body + * + * This method can either accept a string, or a readable stream resource. + * + * If the setAsDefaultInputStream is set to true, it means for this run of the + * script the supplied body will be used instead of php://input. + * + * @param mixed $body + * @param bool $setAsDefaultInputStream + * @return void + */ + public function setBody($body,$setAsDefaultInputStream = false) { + + if(is_resource($body)) { + $this->body = $body; + } else { + + $stream = fopen('php://temp','r+'); + fputs($stream,$body); + rewind($stream); + // String is assumed + $this->body = $stream; + } + if ($setAsDefaultInputStream) { + self::$defaultInputStream = $this->body; + } + + } + + /** + * Returns PHP's _POST variable. + * + * The reason this is in a method is so it can be subclassed and + * overridden. + * + * @return array + */ + public function getPostVars() { + + return $this->_POST; + + } + + /** + * Returns a specific item from the _SERVER array. + * + * Do not rely on this feature, it is for internal use only. + * + * @param string $field + * @return string + */ + public function getRawServerValue($field) { + + return isset($this->_SERVER[$field])?$this->_SERVER[$field]:null; + + } + + /** + * Returns the HTTP version specified within the request. + * + * @return string + */ + public function getHTTPVersion() { + + $protocol = $this->getRawServerValue('SERVER_PROTOCOL'); + if ($protocol==='HTTP/1.0') { + return '1.0'; + } else { + return '1.1'; + } + + } + +} + diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/Response.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Response.php new file mode 100644 index 00000000..a7fc0da1 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Response.php @@ -0,0 +1,175 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authorative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', // RFC 4918 + 208 => 'Already Reported', // RFC 5842 + 226 => 'IM Used', // RFC 3229 + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 306 => 'Reserved', + 307 => 'Temporary Redirect', + 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', + 418 => 'I\'m a teapot', // RFC 2324 + 422 => 'Unprocessable Entity', // RFC 4918 + 423 => 'Locked', // RFC 4918 + 424 => 'Failed Dependency', // RFC 4918 + 426 => 'Upgrade required', + 428 => 'Precondition required', // draft-nottingham-http-new-status + 429 => 'Too Many Requests', // draft-nottingham-http-new-status + 431 => 'Request Header Fields Too Large', // draft-nottingham-http-new-status + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version not supported', + 506 => 'Variant Also Negotiates', + 507 => 'Insufficient Storage', // RFC 4918 + 508 => 'Loop Detected', // RFC 5842 + 509 => 'Bandwidth Limit Exceeded', // non-standard + 510 => 'Not extended', + 511 => 'Network Authentication Required', // draft-nottingham-http-new-status + ); + + return 'HTTP/' . $httpVersion . ' ' . $code . ' ' . $msg[$code]; + + } + + // @codeCoverageIgnoreStart + // We cannot reasonably test header() related methods. + + /** + * Sends an HTTP status header to the client. + * + * @param int $code HTTP status code + * @return bool + */ + public function sendStatus($code) { + + if (!headers_sent()) + return header($this->getStatusMessage($code, $this->defaultHttpVersion)); + else return false; + + } + + /** + * Sets an HTTP header for the response + * + * @param string $name + * @param string $value + * @param bool $replace + * @return bool + */ + public function setHeader($name, $value, $replace = true) { + + $value = str_replace(array("\r","\n"),array('\r','\n'),$value); + if (!headers_sent()) + return header($name . ': ' . $value, $replace); + else return false; + + + } + // @codeCoverageIgnoreEnd + + /** + * Sets a bunch of HTTP Headers + * + * headersnames are specified as keys, value in the array value + * + * @param array $headers + * @return void + */ + public function setHeaders(array $headers) { + + foreach($headers as $key=>$value) + $this->setHeader($key, $value); + + } + + /** + * Sends the entire response body + * + * This method can accept either an open filestream, or a string. + * + * @param mixed $body + * @return void + */ + public function sendBody($body) { + + if (is_resource($body)) { + + file_put_contents('php://output', $body); + + } else { + + // We assume a string + echo $body; + + } + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/Util.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Util.php new file mode 100644 index 00000000..14724625 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Util.php @@ -0,0 +1,82 @@ += 0) + return new \DateTime('@' . $realDate, new \DateTimeZone('UTC')); + + } + + /** + * Transforms a DateTime object to HTTP's most common date format. + * + * We're serializing it as the RFC 1123 date, which, for HTTP must be + * specified as GMT. + * + * @param \DateTime $dateTime + * @return string + */ + static function toHTTPDate(\DateTime $dateTime) { + + // We need to clone it, as we don't want to affect the existing + // DateTime. + $dateTime = clone $dateTime; + $dateTime->setTimeZone(new \DateTimeZone('GMT')); + return $dateTime->format('D, d M Y H:i:s \G\M\T'); + + } + +} diff --git a/sources/vendor/sabre/dav/lib/Sabre/HTTP/Version.php b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Version.php new file mode 100644 index 00000000..0e913835 --- /dev/null +++ b/sources/vendor/sabre/dav/lib/Sabre/HTTP/Version.php @@ -0,0 +1,24 @@ +pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testGetCalendarsForUserNoCalendars() { + + $backend = new PDO($this->pdo); + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals(array(),$calendars); + + } + + /** + * @depends testConstruct + */ + function testCreateCalendarAndFetch() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array( + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')), + '{DAV:}displayname' => 'Hello!', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('transparent'), + )); + $calendars = $backend->getCalendarsForUser('principals/user2'); + + $elementCheck = array( + 'id' => $returnedId, + 'uri' => 'somerandomid', + '{DAV:}displayname' => 'Hello!', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => '', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('transparent'), + ); + + $this->assertInternalType('array',$calendars); + $this->assertEquals(1,count($calendars)); + + foreach($elementCheck as $name=>$value) { + + $this->assertArrayHasKey($name, $calendars[0]); + $this->assertEquals($value,$calendars[0][$name]); + + } + + } + + /** + * @depends testConstruct + */ + function testUpdateCalendarAndFetch() { + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2','somerandomid',array()); + + // Updating the calendar + $result = $backend->updateCalendar($newId,array( + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('transparent'), + )); + + // Verifying the result of the update + $this->assertEquals(true, $result); + + // Fetching all calendars from this user + $calendars = $backend->getCalendarsForUser('principals/user2'); + + // Checking if all the information is still correct + $elementCheck = array( + 'id' => $newId, + 'uri' => 'somerandomid', + '{DAV:}displayname' => 'myCalendar', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => '', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => '', + '{http://calendarserver.org/ns/}getctag' => '2', + '{urn:ietf:params:xml:ns:caldav}schedule-calendar-transp' => new CalDAV\Property\ScheduleCalendarTransp('transparent'), + ); + + $this->assertInternalType('array',$calendars); + $this->assertEquals(1,count($calendars)); + + foreach($elementCheck as $name=>$value) { + + $this->assertArrayHasKey($name, $calendars[0]); + $this->assertEquals($value,$calendars[0][$name]); + + } + + } + + /** + * @depends testUpdateCalendarAndFetch + */ + function testUpdateCalendarUnknownProperty() { + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2','somerandomid',array()); + + // Updating the calendar + $result = $backend->updateCalendar($newId,array( + '{DAV:}displayname' => 'myCalendar', + '{DAV:}yourmom' => 'wittycomment', + )); + + // Verifying the result of the update + $this->assertEquals(array( + '403' => array('{DAV:}yourmom' => null), + '424' => array('{DAV:}displayname' => null), + ), $result); + + } + + /** + * @depends testCreateCalendarAndFetch + */ + function testDeleteCalendar() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array( + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT')), + '{DAV:}displayname' => 'Hello!', + )); + + $backend->deleteCalendar($returnedId); + + $calendars = $backend->getCalendarsForUser('principals/user2'); + $this->assertEquals(array(),$calendars); + + } + + /** + * @depends testCreateCalendarAndFetch + * @expectedException \Sabre\DAV\Exception + */ + function testCreateCalendarIncorrectComponentSet() {; + + $backend = new PDO($this->pdo); + + //Creating a new calendar + $newId = $backend->createCalendar('principals/user2','somerandomid',array( + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => 'blabla', + )); + + } + + function testCreateCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('20120101'), + 'lastoccurence' => strtotime('20120101')+(3600*24), + 'componenttype' => 'VEVENT', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectNoComponent() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectDuration() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nDURATION:P2D\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('20120101'), + 'lastoccurence' => strtotime('20120101')+(3600*48), + 'componenttype' => 'VEVENT', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectNoDTEND() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime('2012-01-01 10:00:00'), + 'componenttype' => 'VEVENT', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectInfiniteReccurence() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nRRULE:FREQ=DAILY\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime(PDO::MAX_DATE), + 'componenttype' => 'VEVENT', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectEndingReccurence() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE-TIME:20120101T100000Z\r\nDTEND;VALUE=DATE-TIME:20120101T110000Z\r\nRRULE:FREQ=DAILY;COUNT=1000\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => strtotime('2012-01-01 10:00:00'), + 'lastoccurence' => strtotime('2012-01-01 11:00:00') + (3600 * 24 * 999), + 'componenttype' => 'VEVENT', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @depends testCreateCalendarObject + */ + function testCreateCalendarObjectTask() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nDUE;VALUE=DATE-TIME:20120101T100000Z\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"; + + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $result = $this->pdo->query('SELECT etag, size, calendardata, firstoccurence, lastoccurence, componenttype FROM calendarobjects WHERE uri = "random-id"'); + $this->assertEquals(array( + 'etag' => md5($object), + 'size' => strlen($object), + 'calendardata' => $object, + 'firstoccurence' => null, + 'lastoccurence' => null, + 'componenttype' => 'VTODO', + ), $result->fetch(\PDO::FETCH_ASSOC)); + + } + + /** + * @depends testCreateCalendarObject + */ + function testGetCalendarObjects() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + + $data = $backend->getCalendarObjects($returnedId,'random-id'); + + $this->assertEquals(1, count($data)); + $data = $data[0]; + + $this->assertEquals($returnedId, $data['calendarid']); + $this->assertEquals('random-id', $data['uri']); + $this->assertEquals(strlen($object),$data['size']); + + + } + + /** + * @depends testCreateCalendarObject + */ + function testUpdateCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $object2 = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20130101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->updateCalendarObject($returnedId, 'random-id', $object2); + + $data = $backend->getCalendarObject($returnedId,'random-id'); + + $this->assertEquals($object2, $data['calendardata']); + $this->assertEquals($returnedId, $data['calendarid']); + $this->assertEquals('random-id', $data['uri']); + + + } + + /** + * @depends testCreateCalendarObject + */ + function testDeleteCalendarObject() { + + $backend = new PDO($this->pdo); + $returnedId = $backend->createCalendar('principals/user2','somerandomid',array()); + + $object = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $backend->createCalendarObject($returnedId, 'random-id', $object); + $backend->deleteCalendarObject($returnedId, 'random-id'); + + $data = $backend->getCalendarObject($returnedId,'random-id'); + $this->assertNull($data); + + } + + function testCalendarQueryNoResult() { + + $abstract = new PDO($this->pdo); + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VJOURNAL', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + ), $abstract->calendarQuery(1, $filters)); + + } + + function testCalendarQueryTodo() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VTODO', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + "todo", + ), $backend->calendarQuery(1, $filters)); + + } + function testCalendarQueryTodoNotMatch() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VTODO', + 'comp-filters' => array(), + 'prop-filters' => array( + array( + 'name' => 'summary', + 'text-match' => null, + 'time-range' => null, + 'param-filters' => array(), + 'is-not-defined' => false, + ), + ), + 'is-not-defined' => false, + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + ), $backend->calendarQuery(1, $filters)); + + } + + function testCalendarQueryNoFilter() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $result = $backend->calendarQuery(1, $filters); + $this->assertTrue(in_array('todo', $result)); + $this->assertTrue(in_array('event', $result)); + + } + + function testCalendarQueryTimeRange() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART;VALUE=DATE:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('20120103'), + 'end' => new \DateTime('20120104'), + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + "event2", + ), $backend->calendarQuery(1, $filters)); + + } + function testCalendarQueryTimeRangeNoEnd() { + + $backend = new PDO($this->pdo); + $backend->createCalendarObject(1, "todo", "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120101\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + $backend->createCalendarObject(1, "event2", "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nDTSTART:20120103\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('20120102'), + 'end' => null, + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + "event2", + ), $backend->calendarQuery(1, $filters)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php new file mode 100644 index 00000000..04fb16df --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/AbstractTest.php @@ -0,0 +1,88 @@ +assertEquals(false, $abstract->updateCalendar('randomid', array('{DAV:}displayname' => 'anything'))); + + } + + function testCalendarQuery() { + + $abstract = new AbstractMock(); + $filters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $this->assertEquals(array( + 'event1.ics', + ), $abstract->calendarQuery(1, $filters)); + + } + +} + +class AbstractMock extends AbstractBackend { + + function getCalendarsForUser($principalUri) { } + function createCalendar($principalUri,$calendarUri,array $properties) { } + function deleteCalendar($calendarId) { } + function getCalendarObjects($calendarId) { + + return array( + array( + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + ), + array( + 'id' => 2, + 'calendarid' => 1, + 'uri' => 'task1.ics', + ), + ); + + } + function getCalendarObject($calendarId,$objectUri) { + + switch($objectUri) { + + case 'event1.ics' : + return array( + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + ); + case 'task1.ics' : + return array( + 'id' => 1, + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", + ); + + } + + } + function createCalendarObject($calendarId,$objectUri,$calendarData) { } + function updateCalendarObject($calendarId,$objectUri,$calendarData) { } + function deleteCalendarObject($calendarId,$objectUri) { } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php new file mode 100644 index 00000000..d196297f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/Mock.php @@ -0,0 +1,400 @@ +calendars = $calendars; + $this->calendarData = $calendarData; + $this->notifications = $notifications; + + } + + /** + * Returns a list of calendars for a principal. + * + * Every project is an array with the following keys: + * * id, a unique id that will be used by other functions to modify the + * calendar. This can be the same as the uri or a database key. + * * uri, which the basename of the uri with which the calendar is + * accessed. + * * principalUri. The owner of the calendar. Almost always the same as + * principalUri passed to this method. + * + * Furthermore it can contain webdav properties in clark notation. A very + * common one is '{DAV:}displayname'. + * + * @param string $principalUri + * @return array + */ + function getCalendarsForUser($principalUri) { + + $r = array(); + foreach($this->calendars as $row) { + if ($row['principaluri'] == $principalUri) { + $r[] = $row; + } + } + + return $r; + + } + + /** + * Creates a new calendar for a principal. + * + * If the creation was a success, an id must be returned that can be used to reference + * this calendar in other methods, such as updateCalendar. + * + * This function must return a server-wide unique id that can be used + * later to reference the calendar. + * + * @param string $principalUri + * @param string $calendarUri + * @param array $properties + * @return string|int + */ + function createCalendar($principalUri,$calendarUri,array $properties) { + + $id = DAV\UUIDUtil::getUUID(); + $this->calendars[] = array_merge(array( + 'id' => $id, + 'principaluri' => $principalUri, + 'uri' => $calendarUri, + '{' . CalDAV\Plugin::NS_CALDAV . '}supported-calendar-component-set' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')), + ), $properties); + + return $id; + + } + + /** + * Updates properties on this node, + * + * The properties array uses the propertyName in clark-notation as key, + * and the array value for the property value. In the case a property + * should be deleted, the property value will be null. + * + * This method must be atomic. If one property cannot be changed, the + * entire operation must fail. + * + * If the operation was successful, true can be returned. + * If the operation failed, false can be returned. + * + * Deletion of a non-existent property is always successful. + * + * Lastly, it is optional to return detailed information about any + * failures. In this case an array should be returned with the following + * structure: + * + * array( + * 403 => array( + * '{DAV:}displayname' => null, + * ), + * 424 => array( + * '{DAV:}owner' => null, + * ) + * ) + * + * In this example it was forbidden to update {DAV:}displayname. + * (403 Forbidden), which in turn also caused {DAV:}owner to fail + * (424 Failed Dependency) because the request needs to be atomic. + * + * @param string $calendarId + * @param array $properties + * @return bool|array + */ + public function updateCalendar($calendarId, array $properties) { + + return false; + + } + + /** + * Delete a calendar and all it's objects + * + * @param string $calendarId + * @return void + */ + public function deleteCalendar($calendarId) { + + foreach($this->calendars as $k=>$calendar) { + if ($calendar['id'] === $calendarId) { + unset($this->calendars[$k]); + } + } + + } + + /** + * Returns all calendar objects within a calendar object. + * + * Every item contains an array with the following keys: + * * id - unique identifier which will be used for subsequent updates + * * calendardata - The iCalendar-compatible calendar data + * * uri - a unique key which will be used to construct the uri. This can be any arbitrary string. + * * lastmodified - a timestamp of the last modification time + * * etag - An arbitrary string, surrounded by double-quotes. (e.g.: + * ' "abcdef"') + * * calendarid - The calendarid as it was passed to this function. + * + * Note that the etag is optional, but it's highly encouraged to return for + * speed reasons. + * + * The calendardata is also optional. If it's not returned + * 'getCalendarObject' will be called later, which *is* expected to return + * calendardata. + * + * @param string $calendarId + * @return array + */ + public function getCalendarObjects($calendarId) { + + if (!isset($this->calendarData[$calendarId])) + return array(); + + $objects = $this->calendarData[$calendarId]; + + foreach($objects as $uri => &$object) { + $object['calendarid'] = $calendarId; + $object['uri'] = $uri; + + } + return $objects; + + } + + /** + * Returns information from a single calendar object, based on it's object + * uri. + * + * The returned array must have the same keys as getCalendarObjects. The + * 'calendardata' object is required here though, while it's not required + * for getCalendarObjects. + * + * @param string $calendarId + * @param string $objectUri + * @return array + */ + function getCalendarObject($calendarId,$objectUri) { + + if (!isset($this->calendarData[$calendarId][$objectUri])) { + throw new DAV\Exception\NotFound('Object could not be found'); + } + $object = $this->calendarData[$calendarId][$objectUri]; + $object['calendarid'] = $calendarId; + $object['uri'] = $objectUri; + return $object; + + } + + /** + * Creates a new calendar object. + * + * @param string $calendarId + * @param string $objectUri + * @param string $calendarData + * @return void + */ + function createCalendarObject($calendarId,$objectUri,$calendarData) { + + $this->calendarData[$calendarId][$objectUri] = array( + 'calendardata' => $calendarData, + 'calendarid' => $calendarId, + 'uri' => $objectUri, + ); + + } + + /** + * Updates an existing calendarobject, based on it's uri. + * + * @param string $calendarId + * @param string $objectUri + * @param string $calendarData + * @return void + */ + function updateCalendarObject($calendarId,$objectUri,$calendarData) { + + $this->calendarData[$calendarId][$objectUri] = array( + 'calendardata' => $calendarData, + 'calendarid' => $calendarId, + 'uri' => $objectUri, + ); + + } + + /** + * Deletes an existing calendar object. + * + * @param string $calendarId + * @param string $objectUri + * @return void + */ + function deleteCalendarObject($calendarId,$objectUri) { + + throw new Exception('Not implemented'); + + + } + + /** + * Returns a list of notifications for a given principal url. + * + * The returned array should only consist of implementations of + * Sabre\CalDAV\Notifications\INotificationType. + * + * @param string $principalUri + * @return array + */ + public function getNotificationsForPrincipal($principalUri) { + + if (isset($this->notifications[$principalUri])) { + return $this->notifications[$principalUri]; + } + return array(); + + } + + /** + * This deletes a specific notifcation. + * + * This may be called by a client once it deems a notification handled. + * + * @param string $principalUri + * @param Sabre\CalDAV\Notifications\INotificationType $notification + * @return void + */ + public function deleteNotification($principalUri, CalDAV\Notifications\INotificationType $notification) { + + foreach($this->notifications[$principalUri] as $key=>$value) { + if ($notification === $value) { + unset($this->notifications[$principalUri][$key]); + } + } + + } + + /** + * Updates the list of shares. + * + * The first array is a list of people that are to be added to the + * calendar. + * + * Every element in the add array has the following properties: + * * href - A url. Usually a mailto: address + * * commonName - Usually a first and last name, or false + * * summary - A description of the share, can also be false + * * readOnly - A boolean value + * + * Every element in the remove array is just the address string. + * + * Note that if the calendar is currently marked as 'not shared' by and + * this method is called, the calendar should be 'upgraded' to a shared + * calendar. + * + * @param mixed $calendarId + * @param array $add + * @param array $remove + * @return void + */ + public function updateShares($calendarId, array $add, array $remove) { + + if (!isset($this->shares[$calendarId])) { + $this->shares[$calendarId] = array(); + } + + foreach($add as $val) { + $val['status'] = CalDAV\SharingPlugin::STATUS_NORESPONSE; + $this->shares[$calendarId][] = $val; + } + + foreach($this->shares[$calendarId] as $k=>$share) { + + if (in_array($share['href'], $remove)) { + unset($this->shares[$calendarId][$k]); + } + + } + + // Re-numbering keys + $this->shares[$calendarId] = array_values($this->shares[$calendarId]); + + } + + /** + * Returns the list of people whom this calendar is shared with. + * + * Every element in this array should have the following properties: + * * href - Often a mailto: address + * * commonName - Optional, for example a first + last name + * * status - See the Sabre\CalDAV\SharingPlugin::STATUS_ constants. + * * readOnly - boolean + * * summary - Optional, a description for the share + * + * @param mixed $calendarId + * @return array + */ + public function getShares($calendarId) { + + if (!isset($this->shares[$calendarId])) { + return array(); + } + + return $this->shares[$calendarId]; + + } + + /** + * This method is called when a user replied to a request to share. + * + * @param string href The sharee who is replying (often a mailto: address) + * @param int status One of the SharingPlugin::STATUS_* constants + * @param string $calendarUri The url to the calendar thats being shared + * @param string $inReplyTo The unique id this message is a response to + * @param string $summary A description of the reply + * @return void + */ + public function shareReply($href, $status, $calendarUri, $inReplyTo, $summary = null) { + + // This operation basically doesn't do anything yet + if ($status === CalDAV\SharingPlugin::STATUS_ACCEPTED) { + return 'calendars/blabla/calendar'; + } + + } + + /** + * Publishes a calendar + * + * @param mixed $calendarId + * @param bool $value + * @return void + */ + public function setPublishStatus($calendarId, $value) { + + foreach($this->calendars as $k=>$cal) { + if ($cal['id'] === $calendarId) { + if (!$value) { + unset($cal['{http://calendarserver.org/ns/}publish-url']); + } else { + $cal['{http://calendarserver.org/ns/}publish-url'] = 'http://example.org/public/ ' . $calendarId . '.ics'; + } + return; + } + } + + throw new DAV\Exception('Calendar with id "' . $calendarId . '" not found'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php new file mode 100644 index 00000000..15c1d91f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOMySQLTest.php @@ -0,0 +1,39 @@ +markTestSkipped('MySQL driver is not available, or not properly configured'); + $pdo = \Sabre\TestUtil::getMySQLDB(); + if (!$pdo) $this->markTestSkipped('Could not connect to mysql database'); + + $pdo->query('DROP TABLE IF EXISTS calendarobjects, calendars'); + + $queries = explode( + ';', + file_get_contents(__DIR__ . '/../../../../examples/sql/mysql.calendars.sql') + ); + + foreach($queries as $query) { + $query = trim($query," \r\n\t"); + if ($query) + $pdo->exec($query); + } + $this->pdo = $pdo; + + } + + function teardown() { + + $this->pdo = null; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOSqliteTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOSqliteTest.php new file mode 100644 index 00000000..c50f0698 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Backend/PDOSqliteTest.php @@ -0,0 +1,25 @@ +markTestSkipped('SQLite driver is not available'); + $this->pdo = CalDAV\TestUtil::getSQLiteDB(); + + } + + function teardown() { + + $this->pdo = null; + unlink(SABRE_TEMPDIR . '/testdb.sqlite'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php new file mode 100644 index 00000000..eab10eae --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarObjectTest.php @@ -0,0 +1,359 @@ +markTestSkipped('SQLite driver is not available'); + $this->backend = TestUtil::getBackend(); + + $calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(2,count($calendars)); + $this->calendar = new Calendar($this->backend, $calendars[0]); + + } + + function teardown() { + + unset($this->calendar); + unset($this->backend); + + } + + function testSetup() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $this->assertInternalType('string',$children[0]->getName()); + $this->assertInternalType('string',$children[0]->get()); + $this->assertInternalType('string',$children[0]->getETag()); + $this->assertEquals('text/calendar; charset=utf-8', $children[0]->getContentType()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg1() { + + $obj = new CalendarObject( + new Backend\Mock(array(),array()), + array(), + array() + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg2() { + + $obj = new CalendarObject( + new Backend\Mock(array(),array()), + array(), + array('calendarid' => '1') + ); + + } + + /** + * @depends testSetup + */ + function testPut() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + $newData = TestUtil::getTestCalendarData(); + + $children[0]->put($newData); + $this->assertEquals($newData, $children[0]->get()); + + } + + /** + * @depends testSetup + */ + function testPutStream() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + $newData = TestUtil::getTestCalendarData(); + + $stream = fopen('php://temp','r+'); + fwrite($stream, $newData); + rewind($stream); + $children[0]->put($stream); + $this->assertEquals($newData, $children[0]->get()); + + } + + + /** + * @depends testSetup + */ + function testDelete() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $obj->delete(); + + $children2 = $this->calendar->getChildren(); + $this->assertEquals(count($children)-1, count($children2)); + + } + + /** + * @depends testSetup + */ + function testGetLastModified() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $lastMod = $obj->getLastModified(); + $this->assertTrue(is_int($lastMod) || ctype_digit($lastMod)); + + } + + /** + * @depends testSetup + */ + function testGetSize() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $size = $obj->getSize(); + $this->assertInternalType('int', $size); + + } + + function testGetOwner() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertEquals('principals/user1', $obj->getOwner()); + + } + + function testGetGroup() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertNull($obj->getGroup()); + + } + + function testGetACL() { + + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ), + ); + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $this->assertEquals($expected, $obj->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + $obj->setACL(array()); + + } + + function testGet() { + + $children = $this->calendar->getChildren(); + $this->assertTrue($children[0] instanceof CalendarObject); + + $obj = $children[0]; + + $expected = "BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 4.0.1//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Asia/Seoul +BEGIN:DAYLIGHT +TZOFFSETFROM:+0900 +RRULE:FREQ=YEARLY;UNTIL=19880507T150000Z;BYMONTH=5;BYDAY=2SU +DTSTART:19870510T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+1000 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1000 +DTSTART:19881009T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+0900 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20100225T154229Z +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +TRANSP:TRANSPARENT +SUMMARY:Something here +DTSTAMP:20100228T130202Z +DTSTART;TZID=Asia/Seoul:20100223T060000 +DTEND;TZID=Asia/Seoul:20100223T070000 +ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com +SEQUENCE:2 +END:VEVENT +END:VCALENDAR"; + + + + $this->assertEquals($expected, $obj->get()); + + } + + function testGetRefetch() { + + $backend = new Backend\Mock(array(), array( + 1 => array( + 'foo' => array( + 'calendardata' => 'foo', + 'uri' => 'foo' + ), + ) + )); + $obj = new CalendarObject($backend, array(), array('calendarid' => 1, 'uri' => 'foo')); + + $this->assertEquals('foo', $obj->get()); + + } + + function testGetEtag1() { + + $objectInfo = array( + 'calendardata' => 'foo', + 'uri' => 'foo', + 'etag' => 'bar', + 'calendarid' => 1 + ); + + $backend = new Backend\Mock(array(), array()); + $obj = new CalendarObject($backend, array(), $objectInfo); + + $this->assertEquals('bar', $obj->getETag()); + + } + + function testGetEtag2() { + + $objectInfo = array( + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ); + + $backend = new Backend\Mock(array(), array()); + $obj = new CalendarObject($backend, array(), $objectInfo); + + $this->assertEquals('"' . md5('foo') . '"', $obj->getETag()); + + } + + function testGetSupportedPrivilegesSet() { + + $objectInfo = array( + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ); + + $backend = new Backend\Mock(array(), array()); + $obj = new CalendarObject($backend, array(), $objectInfo); + $this->assertNull($obj->getSupportedPrivilegeSet()); + + } + + function testGetSize1() { + + $objectInfo = array( + 'calendardata' => 'foo', + 'uri' => 'foo', + 'calendarid' => 1 + ); + + $backend = new Backend\Mock(array(), array()); + $obj = new CalendarObject($backend, array(), $objectInfo); + $this->assertEquals(3, $obj->getSize()); + + } + + function testGetSize2() { + + $objectInfo = array( + 'uri' => 'foo', + 'calendarid' => 1, + 'size' => 4, + ); + + $backend = new Backend\Mock(array(), array()); + $obj = new CalendarObject($backend, array(), $objectInfo); + $this->assertEquals(4, $obj->getSize()); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryParserTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryParserTest.php new file mode 100644 index 00000000..fdfe4de8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryParserTest.php @@ -0,0 +1,540 @@ + + +' . implode("\n", $xml) . ' +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $q = new CalendarQueryParser($dom); + $q->parse(); + return $q->filters; + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoFilter() { + + $xml = array(); + $this->parse($xml); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testTwoCompFilter() { + + $xml = array( + '', + ' ', + ' ', + '' + ); + $this->parse($xml); + + } + + function testBasicFilter() { + + $xml = array( + '', + ' ', + '' + ); + $result = $this->parse($xml); + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $result + ); + + } + + function testCompIsNotDefined() { + + $xml = array( + '', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + $result = $this->parse($xml); + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => true, + 'time-range' => false + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $result + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testCompTimeRangeOnVCALENDAR() { + + $xml = array( + '', + ' ', + ' ', + ' ', + '' + ); + $result = $this->parse($xml); + + } + + function testCompTimeRange() { + + $xml = array( + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + $result = $this->parse($xml); + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 00:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-12-31 23:59:59', new \DateTimeZone('GMT')), + ), + ), + array( + 'name' => 'VTODO', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 00:00:00', new \DateTimeZone('GMT')), + 'end' => null, + ), + ), + array( + 'name' => 'VJOURNAL', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => null, + 'end' => new \DateTime('2011-12-31 23:59:59', new \DateTimeZone('GMT')), + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $result + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testCompTimeRangeBadRange() { + + $xml = array( + '', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + $this->parse($xml); + + } + + function testProp() { + + $xml = array( + '', + ' ', + ' ', + ' ', + ' vacation', + ' ', + ' ', + ' ', + '' + ); + $result = $this->parse($xml); + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'comp-filters' => array(), + 'prop-filters' => array( + array( + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-match' => array( + 'negate-condition' => false, + 'collation' => 'i;ascii-casemap', + 'value' => 'vacation', + ), + 'time-range' => null, + ), + ), + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $result + ); + + } + + function testComplex() { + + $xml = array( + '', + ' ', + ' ', + ' ', + ' vacation', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' DATE', + ' ', + ' ', + ' ', + ' ', + '' + ); + $result = $this->parse($xml); + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'comp-filters' => array(), + 'prop-filters' => array( + array( + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-match' => array( + 'negate-condition' => false, + 'collation' => 'i;unicode-casemap', + 'value' => 'vacation', + ), + 'time-range' => null, + ), + array( + 'name' => 'DTSTAMP', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-match' => null, + 'time-range' => array( + 'start' => new \DateTime('2011-07-04 00:00:00', new \DateTimeZone('GMT')), + 'end' => null, + ), + ), + array( + 'name' => 'ORGANIZER', + 'is-not-defined' => true, + 'param-filters' => array(), + 'text-match' => null, + 'time-range' => null, + ), + array( + 'name' => 'DTSTART', + 'is-not-defined' => false, + 'param-filters' => array( + array( + 'name' => 'VALUE', + 'is-not-defined' => false, + 'text-match' => array( + 'negate-condition' => true, + 'value' => 'DATE', + 'collation' => 'i;ascii-casemap', + ), + ), + ), + 'text-match' => null, + 'time-range' => null, + ), + ), + 'time-range' => null, + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $result + ); + + } + + function testOther1() { + + // This body was exactly sent to us from the sabredav mailing list. Checking if this parses correctly. + + $body = << + + + + + + + + + + + + + +BLA; + + $dom = DAV\XMLUtil::loadDOMDocument($body); + + $q = new CalendarQueryParser($dom); + $q->parse(); + + $this->assertEquals(array( + '{urn:ietf:params:xml:ns:caldav}calendar-data', + '{DAV:}getetag', + ), $q->requestedProperties); + + $expectedFilters = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2009-01-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-12-02 00:00:00', new \DateTimeZone('UTC')), + ), + 'is-not-defined' => false, + ), + ), + 'prop-filters' => array(), + 'time-range' => null, + 'is-not-defined' => false, + ); + + $this->assertEquals($expectedFilters, $q->filters); + + } + + function testExpand() { + + $xml = array( + '', + ' ', + ' ', + ' ', + '', + '', + ' ', + '' + ); + + $xml = +' + +' . implode("\n", $xml) . ' +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + $q = new CalendarQueryParser($dom); + $q->parse(); + + + $expected = array( + 'name' => 'VCALENDAR', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => false + ); + + $this->assertEquals( + $expected, + $q->filters + ); + + $this->assertEquals(array( + '{urn:ietf:params:xml:ns:caldav}calendar-data', + ), $q->requestedProperties); + + $this->assertEquals( + array( + 'start' => new \DateTime('2011-01-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-01-01 00:00:00', new \DateTimeZone('UTC')), + ), + $q->expand + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testExpandNoStart() { + + $xml = array( + '', + ' ', + ' ', + ' ', + '', + '', + ' ', + '' + ); + + $xml = +' + +' . implode("\n", $xml) . ' +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + $q = new CalendarQueryParser($dom); + $q->parse(); + + } + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testExpandNoEnd() { + + $xml = array( + '', + ' ', + ' ', + ' ', + '', + '', + ' ', + '' + ); + + $xml = +' + +' . implode("\n", $xml) . ' +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + $q = new CalendarQueryParser($dom); + $q->parse(); + + } + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testExpandBadTimes() { + + $xml = array( + '', + ' ', + ' ', + ' ', + '', + '', + ' ', + '' + ); + + $xml = +' + +' . implode("\n", $xml) . ' +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + $q = new CalendarQueryParser($dom); + $q->parse(); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php new file mode 100644 index 00000000..9de24d3a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryVAlarmTest.php @@ -0,0 +1,122 @@ +createComponent('VEVENT'); + $vevent->RRULE = 'FREQ=MONTHLY'; + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P15D'; + $vevent->add($valarm); + + + $vcalendar->add($vevent); + + $filter = array( + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => array(), + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => array(), + 'comp-filters' => array( + array( + 'name' => 'VALARM', + 'is-not-defined' => false, + 'prop-filters' => array(), + 'comp-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2012-05-10'), + 'end' => new \DateTime('2012-05-20'), + ), + ), + ), + ), + ), + ); + + $validator = new CalendarQueryValidator(); + $this->assertTrue($validator->validate($vcalendar, $filter)); + + $vcalendar = new VObject\Component\VCalendar(); + + // A limited recurrence rule, should return false + $vevent = $vcalendar->createComponent('VEVENT'); + $vevent->RRULE = 'FREQ=MONTHLY;COUNT=1'; + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P15D'; + $vevent->add($valarm); + + $vcalendar->add($vevent); + + $this->assertFalse($validator->validate($vcalendar, $filter)); + } + + function testAlarmWayBefore() { + + $vcalendar = new VObject\Component\VCalendar(); + + $vevent = $vcalendar->createComponent('VEVENT'); + $vevent->DTSTART = '20120101T120000Z'; + $vevent->UID = 'bla'; + + $valarm = $vcalendar->createComponent('VALARM'); + $valarm->TRIGGER = '-P2W1D'; + $vevent->add($valarm); + + $vcalendar->add($vevent); + + $filter = array( + 'name' => 'VCALENDAR', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => array(), + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'is-not-defined' => false, + 'time-range' => null, + 'prop-filters' => array(), + 'comp-filters' => array( + array( + 'name' => 'VALARM', + 'is-not-defined' => false, + 'prop-filters' => array(), + 'comp-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2011-12-10'), + 'end' => new \DateTime('2011-12-20'), + ), + ), + ), + ), + ), + ); + + $validator = new CalendarQueryValidator(); + $this->assertTrue($validator->validate($vcalendar, $filter)); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php new file mode 100644 index 00000000..deb70d20 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarQueryValidatorTest.php @@ -0,0 +1,804 @@ + 'VCALENDAR', + 'comp-filters' => array($filters), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $vObject = VObject\Reader::read($icalObject); + + switch($outcome) { + case 0 : + $this->assertFalse($validator->validate($vObject, $filters)); + break; + case 1 : + $this->assertTrue($validator->validate($vObject, $filters)); + break; + case -1 : + try { + $validator->validate($vObject, $filters); + } catch (DAV\Exception $e) { + // Success + } catch (\LogicException $e) { + // Success + } + break; + + } + + } + + function provider() { + + $blob1 = << 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + $filter2 = $filter1; + $filter2['name'] = 'VTODO'; + + $filter3 = $filter1; + $filter3['is-not-defined'] = true; + + $filter4 = $filter1; + $filter4['name'] = 'VTODO'; + $filter4['is-not-defined'] = true; + + $filter5 = $filter1; + $filter5['comp-filters'] = array( + array( + 'name' => 'VALARM', + 'is-not-defined' => false, + 'comp-filters' => array(), + 'prop-filters' => array(), + 'time-range' => null, + ), + ); + $filter6 = $filter1; + $filter6['prop-filters'] = array( + array( + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => array(), + 'time-range' => null, + 'text-match' => null, + ), + ); + $filter7 = $filter6; + $filter7['prop-filters'][0]['name'] = 'DESCRIPTION'; + + $filter8 = $filter6; + $filter8['prop-filters'][0]['is-not-defined'] = true; + + $filter9 = $filter7; + $filter9['prop-filters'][0]['is-not-defined'] = true; + + $filter10 = $filter5; + $filter10['prop-filters'] = $filter6['prop-filters']; + + // Param filters + $filter11 = $filter1; + $filter11['prop-filters'] = array( + array( + 'name' => 'DTSTART', + 'is-not-defined' => false, + 'param-filters' => array( + array( + 'name' => 'VALUE', + 'is-not-defined' => false, + 'text-match' => null, + ), + ), + 'time-range' => null, + 'text-match' => null, + ), + ); + + $filter12 = $filter11; + $filter12['prop-filters'][0]['param-filters'][0]['name'] = 'TZID'; + + $filter13 = $filter11; + $filter13['prop-filters'][0]['param-filters'][0]['is-not-defined'] = true; + + $filter14 = $filter12; + $filter14['prop-filters'][0]['param-filters'][0]['is-not-defined'] = true; + + // Param text filter + $filter15 = $filter11; + $filter15['prop-filters'][0]['param-filters'][0]['text-match'] = array( + 'collation' => 'i;ascii-casemap', + 'value' => 'dAtE', + 'negate-condition' => false, + ); + $filter16 = $filter15; + $filter16['prop-filters'][0]['param-filters'][0]['text-match']['collation'] = 'i;octet'; + + $filter17 = $filter15; + $filter17['prop-filters'][0]['param-filters'][0]['text-match']['negate-condition'] = true; + + $filter18 = $filter15; + $filter18['prop-filters'][0]['param-filters'][0]['text-match']['negate-condition'] = true; + $filter18['prop-filters'][0]['param-filters'][0]['text-match']['collation'] = 'i;octet'; + + // prop + text + $filter19 = $filter5; + $filter19['comp-filters'][0]['prop-filters'] = array( + array( + 'name' => 'action', + 'is-not-defined' => false, + 'time-range' => null, + 'param-filters' => array(), + 'text-match' => array( + 'collation' => 'i;ascii-casemap', + 'value' => 'display', + 'negate-condition' => false, + ), + ), + ); + + // Time range + $filter20 = array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ), + ); + // Time range, no end date + $filter21 = $filter20; + $filter21['time-range']['end'] = null; + + // Time range, no start date + $filter22 = $filter20; + $filter22['time-range']['start'] = null; + + // Time range, other dates + $filter23 = $filter20; + $filter23['time-range'] = array( + 'start' => new \DateTime('2011-02-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-02-01 13:00:00', new \DateTimeZone('GMT')), + ); + // Time range + $filter24 = array( + 'name' => 'VTODO', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ), + ); + // Time range, other dates (1 month in the future) + $filter25 = $filter24; + $filter25['time-range'] = array( + 'start' => new \DateTime('2011-02-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-02-01 13:00:00', new \DateTimeZone('GMT')), + ); + $filter26 = $filter24; + $filter26['time-range'] = array( + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ); + + // Time range for VJOURNAL + $filter27 = array( + 'name' => 'VJOURNAL', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ), + ); + $filter28 = $filter27; + $filter28['time-range'] = array( + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ); + // Time range for VFREEBUSY + $filter29 = array( + 'name' => 'VFREEBUSY', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 12:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:15:00', new \DateTimeZone('GMT')), + ), + ); + // Time range filter on property + $filter30 = array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array( + array( + 'name' => 'DTSTART', + 'is-not-defined' => false, + 'param-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ), + 'text-match' => null, + ), + ), + 'is-not-defined' => false, + 'time-range' => null, + ); + + // Time range for alarm + $filter31 = array( + 'name' => 'VEVENT', + 'prop-filters' => array(), + 'comp-filters' => array( + array( + 'name' => 'VALARM', + 'is-not-defined' => false, + 'comp-filters' => array(), + 'prop-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 10:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 11:15:00', new \DateTimeZone('GMT')), + ), + 'text-match' => null, + ), + ), + 'is-not-defined' => false, + 'time-range' => null, + ); + $filter32 = $filter31; + $filter32['comp-filters'][0]['time-range'] = array( + 'start' => new \DateTime('2011-01-01 11:45:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 12:15:00', new \DateTimeZone('GMT')), + ); + + $filter33 = $filter31; + $filter33['name'] = 'VTODO'; + $filter34 = $filter32; + $filter34['name'] = 'VTODO'; + $filter35 = $filter31; + $filter35['name'] = 'VJOURNAL'; + $filter36 = $filter32; + $filter36['name'] = 'VJOURNAL'; + + // Time range filter on non-datetime property + $filter37 = array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array( + array( + 'name' => 'SUMMARY', + 'is-not-defined' => false, + 'param-filters' => array(), + 'time-range' => array( + 'start' => new \DateTime('2011-01-01 10:00:00', new \DateTimeZone('GMT')), + 'end' => new \DateTime('2011-01-01 13:00:00', new \DateTimeZone('GMT')), + ), + 'text-match' => null, + ), + ), + 'is-not-defined' => false, + 'time-range' => null, + ); + + $filter38 = array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2012-07-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-08-01 00:00:00', new \DateTimeZone('UTC')), + ) + ); + $filter39 = array( + 'name' => 'VEVENT', + 'comp-filters' => array( + array( + 'name' => 'VALARM', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2012-09-01 00:00:00', new \DateTimeZone('UTC')), + 'end' => new \DateTime('2012-10-01 00:00:00', new \DateTimeZone('UTC')), + ) + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + + return array( + + // Component check + + array($blob1, $filter1, 1), + array($blob1, $filter2, 0), + array($blob1, $filter3, 0), + array($blob1, $filter4, 1), + + // Subcomponent check + array($blob1, $filter5, 0), + array($blob2, $filter5, 1), + + // Property check + array($blob1, $filter6, 1), + array($blob1, $filter7, 0), + array($blob1, $filter8, 0), + array($blob1, $filter9, 1), + + // Subcomponent + property + array($blob2, $filter10, 1), + + // Param filter + array($blob3, $filter11, 1), + array($blob3, $filter12, 0), + array($blob3, $filter13, 0), + array($blob3, $filter14, 1), + + // Param + text + array($blob3, $filter15, 1), + array($blob3, $filter16, 0), + array($blob3, $filter17, 0), + array($blob3, $filter18, 1), + + // Prop + text + array($blob2, $filter19, 1), + + // Incorrect object (vcard) + array($blob4, $filter1, -1), + + // Time-range for event + array($blob5, $filter20, 1), + array($blob6, $filter20, 1), + array($blob7, $filter20, 1), + array($blob8, $filter20, 1), + + array($blob5, $filter21, 1), + array($blob5, $filter22, 1), + + array($blob5, $filter23, 0), + array($blob6, $filter23, 0), + array($blob7, $filter23, 0), + array($blob8, $filter23, 0), + + // Time-range for todo + array($blob9, $filter24, 1), + array($blob9, $filter25, 0), + array($blob9, $filter26, 1), + array($blob10, $filter24, 1), + array($blob10, $filter25, 0), + array($blob10, $filter26, 1), + + array($blob11, $filter24, 0), + array($blob11, $filter25, 0), + array($blob11, $filter26, 1), + + array($blob12, $filter24, 1), + array($blob12, $filter25, 0), + array($blob12, $filter26, 0), + + array($blob13, $filter24, 1), + array($blob13, $filter25, 0), + array($blob13, $filter26, 1), + + array($blob14, $filter24, 1), + array($blob14, $filter25, 0), + array($blob14, $filter26, 0), + + array($blob15, $filter24, 1), + array($blob15, $filter25, 1), + array($blob15, $filter26, 1), + + array($blob16, $filter24, 1), + array($blob16, $filter25, 1), + array($blob16, $filter26, 1), + + // Time-range for journals + array($blob17, $filter27, 0), + array($blob17, $filter28, 0), + array($blob18, $filter27, 0), + array($blob18, $filter28, 1), + array($blob19, $filter27, 1), + array($blob19, $filter28, 1), + + // Time-range for free-busy + array($blob20, $filter29, -1), + + // Time-range on property + array($blob5, $filter30, 1), + array($blob3, $filter37, -1), + array($blob3, $filter30, 0), + + // Time-range on alarm in vevent + array($blob21, $filter31, 1), + array($blob21, $filter32, 0), + array($blob22, $filter31, 1), + array($blob22, $filter32, 0), + array($blob23, $filter31, 1), + array($blob23, $filter32, 0), + array($blob24, $filter31, 1), + array($blob24, $filter32, 0), + array($blob25, $filter31, 1), + array($blob25, $filter32, 0), + array($blob26, $filter31, 1), + array($blob26, $filter32, 0), + + // Time-range on alarm for vtodo + array($blob27, $filter33, 1), + array($blob27, $filter34, 0), + + // Time-range on alarm for vjournal + array($blob28, $filter35, -1), + array($blob28, $filter36, -1), + + // Time-range on alarm with duration + array($blob29, $filter31, 1), + array($blob29, $filter32, 0), + array($blob30, $filter31, 0), + array($blob30, $filter32, 0), + + // Time-range with RRULE + array($blob31, $filter20, 1), + array($blob32, $filter20, 0), + + // Bug reported on mailing list, related to all-day events. + array($blob33, $filter38, 1), + + // Event in timerange, but filtered alarm is in the far future. + array($blob34, $filter39, 0), + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php new file mode 100644 index 00000000..2b2690d4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/CalendarTest.php @@ -0,0 +1,255 @@ +markTestSkipped('SQLite driver is not available'); + + $this->backend = TestUtil::getBackend(); + + $this->calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(2, count($this->calendars)); + $this->calendar = new Calendar($this->backend, $this->calendars[0]); + + + } + + function teardown() { + + unset($this->backend); + + } + + function testSimple() { + + $this->assertEquals($this->calendars[0]['uri'], $this->calendar->getName()); + + } + + /** + * @depends testSimple + */ + function testUpdateProperties() { + + $result = $this->calendar->updateProperties(array( + '{DAV:}displayname' => 'NewName', + )); + + $this->assertEquals(true, $result); + + $calendars2 = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals('NewName',$calendars2[0]['{DAV:}displayname']); + + } + + /** + * @depends testSimple + */ + function testGetProperties() { + + $question = array( + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-data', + '{urn:ietf:params:xml:ns:caldav}supported-collation-set', + '{DAV:}owner', + ); + + $result = $this->calendar->getProperties($question); + + foreach($question as $q) $this->assertArrayHasKey($q,$result); + + $this->assertEquals(array('VEVENT','VTODO'), $result['{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set']->getValue()); + + $this->assertTrue($result['{urn:ietf:params:xml:ns:caldav}supported-collation-set'] instanceof Property\SupportedCollationSet); + + $this->assertTrue($result['{DAV:}owner'] instanceof DAVACL\Property\Principal); + $this->assertEquals('principals/user1', $result['{DAV:}owner']->getHref()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + * @depends testSimple + */ + function testGetChildNotFound() { + + $this->calendar->getChild('randomname'); + + } + + /** + * @depends testSimple + */ + function testGetChildren() { + + $children = $this->calendar->getChildren(); + $this->assertEquals(1,count($children)); + + $this->assertTrue($children[0] instanceof CalendarObject); + + } + + /** + * @depends testGetChildren + */ + function testChildExists() { + + $this->assertFalse($this->calendar->childExists('foo')); + + $children = $this->calendar->getChildren(); + $this->assertTrue($this->calendar->childExists($children[0]->getName())); + } + + + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->calendar->createDirectory('hello'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->calendar->setName('hello'); + + } + + function testGetLastModified() { + + $this->assertNull($this->calendar->getLastModified()); + + } + + function testCreateFile() { + + $file = fopen('php://memory','r+'); + fwrite($file,TestUtil::getTestCalendarData()); + rewind($file); + + $this->calendar->createFile('hello',$file); + + $file = $this->calendar->getChild('hello'); + $this->assertTrue($file instanceof CalendarObject); + + } + + function testCreateFileNoSupportedComponents() { + + $file = fopen('php://memory','r+'); + fwrite($file,TestUtil::getTestCalendarData()); + rewind($file); + + $calendar = new Calendar($this->backend, $this->calendars[1]); + $calendar->createFile('hello',$file); + + $file = $calendar->getChild('hello'); + $this->assertTrue($file instanceof CalendarObject); + + } + + function testDelete() { + + $this->calendar->delete(); + + $calendars = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(1, count($calendars)); + } + + function testGetOwner() { + + $this->assertEquals('principals/user1',$this->calendar->getOwner()); + + } + + function testGetGroup() { + + $this->assertNull($this->calendar->getGroup()); + + } + + function testGetACL() { + + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ), + array( + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ), + ); + $this->assertEquals($expected, $this->calendar->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $this->calendar->setACL(array()); + + } + + function testGetSupportedPrivilegesSet() { + + $result = $this->calendar->getSupportedPrivilegeSet(); + + $this->assertEquals( + '{' . Plugin::NS_CALDAV . '}read-free-busy', + $result['aggregates'][0]['aggregates'][2]['privilege'] + ); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php new file mode 100644 index 00000000..2767b5f8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDTest.php @@ -0,0 +1,110 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3 +SUMMARY:RecurringEvents 3 times +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +BEGIN:VEVENT +CREATED:20120207T111900Z +UID:foobar +DTEND;TZID=Europe/Berlin:20120208T191500 +SUMMARY:RecurringEvents 3 times OVERWRITTEN +DTSTART;TZID=Europe/Berlin:20120208T181500 +RECURRENCE-ID;TZID=Europe/Berlin:20120208T181500 +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testExpand() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children as $child) { + /** @var $child Sabre\VObject\Property */ + + if ($child->name == 'DTSTART') { + // DTSTART has to be one of three valid values + $this->assertContains($child->getValue(), array('20120207T171500Z', '20120208T171500Z', '20120209T171500Z'), 'DTSTART is not a valid value: '.$child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND has to be one of three valid values + $this->assertContains($child->getValue(), array('20120207T181500Z', '20120208T181500Z', '20120209T181500Z'), 'DTEND is not a valid value: '.$child->getValue()); + } + } + } + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php new file mode 100644 index 00000000..3793cadc --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDTSTARTandDTENDbyDayTest.php @@ -0,0 +1,103 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=WEEKLY;INTERVAL=1;BYDAY=TU,TH +SUMMARY:RecurringEvents on tuesday and thursday +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testExpandRecurringByDayEvent() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(2, count($vObject->VEVENT)); + + // check if DTSTARTs and DTENDs are correct + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + foreach ($vevent->children as $child) { + /** @var $child Sabre\VObject\Property */ + + if ($child->name == 'DTSTART') { + // DTSTART has to be one of two valid values + $this->assertContains($child->getValue(), array('20120214T171500Z', '20120216T171500Z'), 'DTSTART is not a valid value: '.$child->getValue()); + } elseif ($child->name == 'DTEND') { + // DTEND has to be one of two valid values + $this->assertContains($child->getValue(), array('20120214T181500Z', '20120216T181500Z'), 'DTEND is not a valid value: '.$child->getValue()); + } + } + } + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php new file mode 100644 index 00000000..09eea527 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ExpandEventsDoubleEventsTest.php @@ -0,0 +1,104 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:foobar +DTEND;TZID=Europe/Berlin:20120207T191500 +RRULE:FREQ=DAILY;INTERVAL=1;COUNT=3 +SUMMARY:RecurringEvents 3 times +DTSTART;TZID=Europe/Berlin:20120207T181500 +END:VEVENT +BEGIN:VEVENT +CREATED:20120207T111900Z +UID:foobar +DTEND;TZID=Europe/Berlin:20120208T191500 +SUMMARY:RecurringEvents 3 times OVERWRITTEN +DTSTART;TZID=Europe/Berlin:20120208T181500 +RECURRENCE-ID;TZID=Europe/Berlin:20120208T181500 +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testExpand() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + // We only expect 3 events + $this->assertEquals(3, count($vObject->VEVENT),'We got 6 events instead of 3. Output: ' . $body); + + // TZID should be gone + $this->assertFalse(isset($vObject->VEVENT->DTSTART['TZID'])); + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php new file mode 100644 index 00000000..93eca9ee --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyReportTest.php @@ -0,0 +1,159 @@ + array( + 'obj1' => array( + 'calendarid' => 1, + 'uri' => 'event1.ics', + 'calendardata' => $obj1, + ), + 'obj2' => array( + 'calendarid' => 1, + 'uri' => 'event2.ics', + 'calendardata' => $obj2 + ) + ), + ); + + + $caldavBackend = new Backend\Mock(array(), $calendarData); + + $calendar = new Calendar($caldavBackend, array( + 'id' => 1, + 'uri' => 'calendar', + 'principaluri' => 'principals/user1', + )); + + $this->server = new DAV\Server(array($calendar)); + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/calendar', + )); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + $this->server->addPlugin(new DAVACL\Plugin()); + + } + + function testFreeBusyReport() { + + $reportXML = << + + + +XML; + + $dom = DAV\XMLUtil::loadDOMDocument($reportXML); + $this->plugin->report('{urn:ietf:params:xml:ns:caldav}free-busy-query', $dom); + + $this->assertEquals('HTTP/1.1 200 OK', $this->server->httpResponse->status); + $this->assertEquals('text/calendar', $this->server->httpResponse->headers['Content-Type']); + $this->assertTrue(strpos($this->server->httpResponse->body,'BEGIN:VFREEBUSY')!==false); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testFreeBusyReportNoTimeRange() { + + $reportXML = << + + +XML; + + $dom = DAV\XMLUtil::loadDOMDocument($reportXML); + $this->plugin->report('{urn:ietf:params:xml:ns:caldav}free-busy-query', $dom); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testFreeBusyReportWrongNode() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/', + )); + $this->server->httpRequest = $request; + + $reportXML = << + + + +XML; + + $dom = DAV\XMLUtil::loadDOMDocument($reportXML); + $this->plugin->report('{urn:ietf:params:xml:ns:caldav}free-busy-query', $dom); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testFreeBusyReportNoACLPlugin() { + + $this->server = new DAV\Server(); + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + $reportXML = << + + + +XML; + + $dom = DAV\XMLUtil::loadDOMDocument($reportXML); + $this->plugin->report('{urn:ietf:params:xml:ns:caldav}free-busy-query', $dom); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyRequestTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyRequestTest.php new file mode 100644 index 00000000..62252e6a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/FreeBusyRequestTest.php @@ -0,0 +1,282 @@ + 'principals/user2', + 'id' => 1, + 'uri' => 'calendar1', + ), + ); + $calendarobjects = array( + 1 => array( '1.ics' => array( + 'uri' => '1.ics', + 'calendardata' => 'BEGIN:VCALENDAR +BEGIN:VEVENT +DTSTART:20110101T130000 +DURATION:PT1H +END:VEVENT +END:VCALENDAR', + 'calendarid' => 1, + )) + + ); + + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + $caldavBackend = new Backend\Mock($calendars, $calendarobjects); + + $tree = array( + new DAVACL\PrincipalCollection($principalBackend), + new CalendarRootNode($principalBackend, $caldavBackend), + ); + + $this->request = new HTTP\Request(array( + 'CONTENT_TYPE' => 'text/calendar', + )); + $this->response = new HTTP\ResponseMock(); + + $this->server = new DAV\Server($tree); + $this->server->httpRequest = $this->request; + $this->server->httpResponse = $this->response; + + $this->aclPlugin = new DAVACL\Plugin(); + $this->server->addPlugin($this->aclPlugin); + + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->setCurrentUser('user1'); + $this->authPlugin = new DAV\Auth\Plugin($authBackend,'SabreDAV'); + $this->server->addPlugin($this->authPlugin); + + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + } + + function testWrongMethod() { + + $this->assertNull( + $this->plugin->unknownMethod('PUT','calendars/user1/outbox') + ); + + } + + function testWrongContentType() { + + $this->server->httpRequest = new HTTP\Request(array( + 'CONTENT_TYPE' => 'text/plain', + )); + + $this->assertNull( + $this->plugin->unknownMethod('POST','calendars/user1/outbox') + ); + + } + + function testNotFound() { + + $this->assertNull( + $this->plugin->unknownMethod('POST','calendars/user1/blabla') + ); + + } + + function testNotOutbox() { + + $this->assertNull( + $this->plugin->unknownMethod('POST','calendars/user1/inbox') + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoItipMethod() { + + $body = <<request->setBody($body); + $this->plugin->unknownMethod('POST','calendars/user1/outbox'); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoVFreeBusy() { + + $body = <<request->setBody($body); + $this->plugin->unknownMethod('POST','calendars/user1/outbox'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testIncorrectOrganizer() { + + $body = <<request->setBody($body); + $this->plugin->unknownMethod('POST','calendars/user1/outbox'); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoAttendees() { + + $body = <<request->setBody($body); + $this->plugin->unknownMethod('POST','calendars/user1/outbox'); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testNoDTStart() { + + $body = <<request->setBody($body); + $this->plugin->unknownMethod('POST','calendars/user1/outbox'); + + } + + function testSucceed() { + + $body = <<aclPlugin->adminPrincipals[] = 'principals/user1'; + + $this->request->setBody($body); + $this->assertFalse($this->plugin->unknownMethod('POST','calendars/user1/outbox')); + + $this->assertEquals('HTTP/1.1 200 OK' , $this->response->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $this->response->headers); + + $strings = array( + 'mailto:user2.sabredav@sabredav.org', + 'mailto:user3.sabredav@sabredav.org', + '2.0;Success', + '3.7;Could not find principal', + 'FREEBUSY;FBTYPE=BUSY:20110101T130000Z/20110101T140000Z', + ); + + foreach($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string)!==false, + 'The response body did not contain: ' . $string .'Full response: ' . $this->response->body + ); + } + + + } + + function testNoPrivilege() { + + $body = <<request->setBody($body); + $this->assertFalse($this->plugin->unknownMethod('POST','calendars/user1/outbox')); + + $this->assertEquals('HTTP/1.1 200 OK' , $this->response->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $this->response->headers); + + $strings = array( + 'mailto:user2.sabredav@sabredav.org', + '3.7;No calendar-home-set property found', + ); + + foreach($strings as $string) { + $this->assertTrue( + strpos($this->response->body, $string)!==false, + 'The response body did not contain: ' . $string .'Full response: ' . $this->response->body + ); + } + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php new file mode 100644 index 00000000..6c9a0990 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/GetEventsByTimerangeTest.php @@ -0,0 +1,96 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +CREATED:20120313T142342Z +UID:171EBEFC-C951-499D-B234-7BA7D677B45D +DTEND;TZID=Europe/Berlin:20120227T000000 +TRANSP:OPAQUE +SUMMARY:Monday 0h +DTSTART;TZID=Europe/Berlin:20120227T000000 +DTSTAMP:20120313T142416Z +SEQUENCE:4 +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testQueryTimerange() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + if (strpos($response->body, 'BEGIN:VCALENDAR') === false) { + $this->fail('Got no events instead of 1. Output: '.$response->body); + } + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + // We expect 1 event + $this->assertEquals(1, count($vObject->VEVENT), 'We got 0 events instead of 1. Output: ' . $body); + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php new file mode 100644 index 00000000..be21796d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ICSExportPluginTest.php @@ -0,0 +1,227 @@ +addPlugin($p); + + } + + function testBeforeMethod() { + + if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available'); + $cbackend = TestUtil::getBackend(); + + $props = array( + 'uri'=>'UUID-123467', + 'principaluri' => 'admin', + 'id' => 1, + ); + $tree = array( + new Calendar($cbackend,$props), + ); + + $p = new ICSExportPlugin(); + + $s = new DAV\Server($tree); + $s->addPlugin($p); + $s->addPlugin(new Plugin()); + + $h = new HTTP\Request(array( + 'QUERY_STRING' => 'export', + )); + + $s->httpRequest = $h; + $s->httpResponse = new HTTP\ResponseMock(); + + $this->assertFalse($p->beforeMethod('GET','UUID-123467?export')); + + $this->assertEquals('HTTP/1.1 200 OK',$s->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'text/calendar', + ), $s->httpResponse->headers); + + $obj = VObject\Reader::read($s->httpResponse->body); + + $this->assertEquals(5,count($obj->children())); + $this->assertEquals(1,count($obj->VERSION)); + $this->assertEquals(1,count($obj->CALSCALE)); + $this->assertEquals(1,count($obj->PRODID)); + $this->assertTrue(strpos((string)$obj->PRODID, DAV\Version::VERSION)!==false); + $this->assertEquals(1,count($obj->VTIMEZONE)); + $this->assertEquals(1,count($obj->VEVENT)); + + } + function testBeforeMethodNoVersion() { + + if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available'); + $cbackend = TestUtil::getBackend(); + + $props = array( + 'uri'=>'UUID-123467', + 'principaluri' => 'admin', + 'id' => 1, + ); + $tree = array( + new Calendar($cbackend,$props), + ); + + $p = new ICSExportPlugin(); + + $s = new DAV\Server($tree); + + $s->addPlugin($p); + $s->addPlugin(new Plugin()); + + $h = new HTTP\Request(array( + 'QUERY_STRING' => 'export', + )); + + $s->httpRequest = $h; + $s->httpResponse = new HTTP\ResponseMock(); + + DAV\Server::$exposeVersion = false; + $this->assertFalse($p->beforeMethod('GET','UUID-123467?export')); + DAV\Server::$exposeVersion = true; + + $this->assertEquals('HTTP/1.1 200 OK',$s->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'text/calendar', + ), $s->httpResponse->headers); + + $obj = VObject\Reader::read($s->httpResponse->body); + + $this->assertEquals(5,count($obj->children())); + $this->assertEquals(1,count($obj->VERSION)); + $this->assertEquals(1,count($obj->CALSCALE)); + $this->assertEquals(1,count($obj->PRODID)); + $this->assertFalse(strpos((string)$obj->PRODID, DAV\Version::VERSION)!==false); + $this->assertEquals(1,count($obj->VTIMEZONE)); + $this->assertEquals(1,count($obj->VEVENT)); + + } + + function testBeforeMethodNoGET() { + + $p = new ICSExportPlugin(); + + $s = new DAV\Server(); + $s->addPlugin($p); + + $this->assertNull($p->beforeMethod('POST','UUID-123467?export')); + + } + + function testBeforeMethodNoExport() { + + $p = new ICSExportPlugin(); + + $s = new DAV\Server(); + $s->addPlugin($p); + + $this->assertNull($p->beforeMethod('GET','UUID-123467')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testACLIntegrationBlocked() { + + if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available'); + $cbackend = TestUtil::getBackend(); + + $props = array( + 'uri'=>'UUID-123467', + 'principaluri' => 'admin', + 'id' => 1, + ); + $tree = array( + new Calendar($cbackend,$props), + ); + + $p = new ICSExportPlugin(); + + $s = new DAV\Server($tree); + $s->addPlugin($p); + $s->addPlugin(new Plugin()); + $s->addPlugin(new DAVACL\Plugin()); + + $h = new HTTP\Request(array( + 'QUERY_STRING' => 'export', + )); + + $s->httpRequest = $h; + $s->httpResponse = new HTTP\ResponseMock(); + + $p->beforeMethod('GET','UUID-123467?export'); + + } + + function testACLIntegrationNotBlocked() { + + if (!SABRE_HASSQLITE) $this->markTestSkipped('SQLite driver is not available'); + $cbackend = TestUtil::getBackend(); + $pbackend = new DAVACL\PrincipalBackend\Mock(); + + $props = array( + 'uri'=>'UUID-123467', + 'principaluri' => 'admin', + 'id' => 1, + ); + $tree = array( + new Calendar($cbackend,$props), + new DAVACL\PrincipalCollection($pbackend), + ); + + $p = new ICSExportPlugin(); + + $s = new DAV\Server($tree); + $s->addPlugin($p); + $s->addPlugin(new Plugin()); + $s->addPlugin(new DAVACL\Plugin()); + $s->addPlugin(new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'SabreDAV')); + + // Forcing login + $s->getPlugin('acl')->adminPrincipals = array('principals/admin'); + + $h = new HTTP\Request(array( + 'QUERY_STRING' => 'export', + 'REQUEST_URI' => '/UUID-123467', + 'REQUEST_METHOD' => 'GET', + )); + + $s->httpRequest = $h; + $s->httpResponse = new HTTP\ResponseMock(); + + $s->exec(); + + $this->assertEquals('HTTP/1.1 200 OK',$s->httpResponse->status,'Invalid status received. Response body: '. $s->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'text/calendar', + ), $s->httpResponse->headers); + + $obj = VObject\Reader::read($s->httpResponse->body); + + $this->assertEquals(5,count($obj->children())); + $this->assertEquals(1,count($obj->VERSION)); + $this->assertEquals(1,count($obj->CALSCALE)); + $this->assertEquals(1,count($obj->PRODID)); + $this->assertEquals(1,count($obj->VTIMEZONE)); + $this->assertEquals(1,count($obj->VEVENT)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php new file mode 100644 index 00000000..f925224f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue166Test.php @@ -0,0 +1,63 @@ + 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2011-12-01'), + 'end' => new \DateTime('2012-02-01'), + ), + ), + ), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => null, + ); + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input,$filters)); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php new file mode 100644 index 00000000..ce6d364f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue172Test.php @@ -0,0 +1,135 @@ + 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2012-01-18 21:00:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-18 21:00:00 GMT-08:00'), + ), + ), + ), + 'prop-filters' => array(), + ); + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input,$filters)); + } + + // Pacific Standard Time, translates to America/Los_Angeles (GMT-8 in January) + function testOutlookTimezoneName() { + $input = << 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + ), + ), + ), + 'prop-filters' => array(), + ); + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input,$filters)); + } + + // X-LIC-LOCATION, translates to America/Los_Angeles (GMT-8 in January) + function testLibICalLocationName() { + $input = << 'VCALENDAR', + 'comp-filters' => array( + array( + 'name' => 'VEVENT', + 'comp-filters' => array(), + 'prop-filters' => array(), + 'is-not-defined' => false, + 'time-range' => array( + 'start' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + 'end' => new \DateTime('2012-01-13 10:30:00 GMT-08:00'), + ), + ), + ), + 'prop-filters' => array(), + ); + $input = VObject\Reader::read($input); + $this->assertTrue($validator->validate($input,$filters)); + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php new file mode 100644 index 00000000..21ee2f55 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue203Test.php @@ -0,0 +1,139 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135305Z +DTSTART;TZID=Europe/Berlin:20120326T155200 +DTEND;TZID=Europe/Berlin:20120326T165200 +RRULE:FREQ=DAILY;COUNT=2;INTERVAL=1 +SUMMARY:original summary +TRANSP:OPAQUE +END:VEVENT +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135352Z +DESCRIPTION: +DTSTART;TZID=Europe/Berlin:20120328T155200 +DTEND;TZID=Europe/Berlin:20120328T165200 +RECURRENCE-ID;TZID=Europe/Berlin:20120327T155200 +SEQUENCE:1 +SUMMARY:overwritten summary +TRANSP:OPAQUE +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testIssue203() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(2, count($vObject->VEVENT)); + + + $expectedEvents = array( + array( + 'DTSTART' => '20120326T135200Z', + 'DTEND' => '20120326T145200Z', + 'SUMMARY' => 'original summary', + ), + array( + 'DTSTART' => '20120328T135200Z', + 'DTEND' => '20120328T145200Z', + 'SUMMARY' => 'overwritten summary', + 'RECURRENCE-ID' => '20120327T135200Z', + ) + ); + + // try to match agains $expectedEvents array + foreach ($expectedEvents as $expectedEvent) { + + $matching = false; + + foreach ($vObject->VEVENT as $vevent) { + /** @var $vevent Sabre\VObject\Component\VEvent */ + + foreach ($vevent->children as $child) { + /** @var $child Sabre\VObject\Property */ + + if (isset($expectedEvent[$child->name])) { + if ($expectedEvent[$child->name] != $child->getValue()) { + continue 2; + } + } + } + + $matching = true; + break; + } + + $this->assertTrue($matching, 'Did not find the following event in the response: '.var_export($expectedEvent, true)); + } + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php new file mode 100644 index 00000000..cd6820b5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue205Test.php @@ -0,0 +1,97 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120330T155305CEST-6585fBUVgV +DTSTAMP:20120330T135305Z +DTSTART;TZID=Europe/Berlin:20120326T155200 +DTEND;TZID=Europe/Berlin:20120326T165200 +SUMMARY:original summary +TRANSP:OPAQUE +BEGIN:VALARM +ACTION:AUDIO +ATTACH;VALUE=URI:Basso +TRIGGER:PT0S +END:VALARM +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testIssue205() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + $this->assertFalse(strpos($response->body, 'Exception'), 'Exception occurred: ' . $response->body); + $this->assertFalse(strpos($response->body, 'Unknown or bad format'), 'DateTime unknown format Exception: ' . $response->body); + + // Everts super awesome xml parser. + $body = substr( + $response->body, + $start = strpos($response->body, 'BEGIN:VCALENDAR'), + strpos($response->body, 'END:VCALENDAR') - $start + 13 + ); + $body = str_replace(' ','',$body); + + $vObject = VObject\Reader::read($body); + + $this->assertEquals(1, count($vObject->VEVENT)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php new file mode 100644 index 00000000..cc700e50 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue211Test.php @@ -0,0 +1,89 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120418T172519CEST-3510gh1hVw +DTSTAMP:20120418T152519Z +DTSTART;VALUE=DATE:20120330 +DTEND;VALUE=DATE:20120531 +EXDATE;TZID=Europe/Berlin:20120330T000000 +RRULE:FREQ=YEARLY;INTERVAL=1 +SEQUENCE:1 +SUMMARY:Birthday +TRANSP:TRANSPARENT +BEGIN:VALARM +ACTION:EMAIL +ATTENDEE:MAILTO:xxx@domain.de +DESCRIPTION:Dies ist eine Kalender Erinnerung +SUMMARY:Kalender Alarm Erinnerung +TRIGGER;VALUE=DATE-TIME:20120329T060000Z +END:VALARM +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testIssue211() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // if this assert is reached, the endless loop is gone + // There should be no matching events + $this->assertFalse(strpos('BEGIN:VEVENT', $response->body)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php new file mode 100644 index 00000000..ce66b6a5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue220Test.php @@ -0,0 +1,99 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20120601T180000 +SUMMARY:Brot backen +RRULE:FREQ=DAILY;INTERVAL=1;WKST=MO +TRANSP:OPAQUE +DURATION:PT20M +LAST-MODIFIED:20120601T064634Z +CREATED:20120601T064634Z +DTSTAMP:20120601T064634Z +UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd +BEGIN:VALARM +TRIGGER;VALUE=DURATION:-PT5M +ACTION:DISPLAY +DESCRIPTION:Default Event Notification +X-WR-ALARMUID:cd952c1b-b3d6-41fb-b0a6-ec3a1a5bdd58 +END:VALARM +END:VEVENT +BEGIN:VEVENT +DTSTART;TZID=Europe/Berlin:20120606T180000 +SUMMARY:Brot backen +TRANSP:OPAQUE +STATUS:CANCELLED +DTEND;TZID=Europe/Berlin:20120606T182000 +LAST-MODIFIED:20120605T094310Z +SEQUENCE:1 +RECURRENCE-ID:20120606T160000Z +UID:b64f14c5-dccc-4eda-947f-bdb1f763fbcd +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testIssue220() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + $this->assertFalse(strpos($response->body, 'PHPUnit_Framework_Error_Warning'), 'Error Warning occurred: ' . $response->body); + $this->assertFalse(strpos($response->body, 'Invalid argument supplied for foreach()'), 'Invalid argument supplied for foreach(): ' . $response->body); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status); + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php new file mode 100644 index 00000000..23371a05 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Issue228Test.php @@ -0,0 +1,78 @@ + 1, + 'name' => 'Calendar', + 'principaluri' => 'principals/user1', + 'uri' => 'calendar1', + ) + ); + + protected $caldavCalendarObjects = array( + 1 => array( + 'event.ics' => array( + 'calendardata' => 'BEGIN:VCALENDAR +VERSION:2.0 +BEGIN:VEVENT +UID:20120730T113415CEST-6804EGphkd@xxxxxx.de +DTSTAMP:20120730T093415Z +DTSTART;VALUE=DATE:20120729 +DTEND;VALUE=DATE:20120730 +SUMMARY:sunday event +TRANSP:TRANSPARENT +END:VEVENT +END:VCALENDAR +', + ), + ), + ); + + function testIssue228() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/calendars/user1/calendar1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody(' + + + + + + + + + + + + + + +'); + + $response = $this->request($request); + + // We must check if absolutely nothing was returned from this query. + $this->assertFalse(strpos($response->body, 'BEGIN:VCALENDAR')); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php new file mode 100644 index 00000000..eaed4f50 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/CollectionTest.php @@ -0,0 +1,90 @@ +principalUri = 'principals/user1'; + + $this->notification = new Notification\SystemStatus(1,'"1"'); + + $this->caldavBackend = new CalDAV\Backend\Mock(array(),array(), array( + 'principals/user1' => array( + $this->notification + ) + )); + + return new Collection($this->caldavBackend, $this->principalUri); + + } + + function testGetChildren() { + + $col = $this->getInstance(); + $this->assertEquals('notifications', $col->getName()); + + $this->assertEquals(array( + new Node($this->caldavBackend, $this->principalUri, $this->notification) + ), $col->getChildren()); + + } + + function testGetOwner() { + + $col = $this->getInstance(); + $this->assertEquals('principals/user1', $col->getOwner()); + + } + + function testGetGroup() { + + $col = $this->getInstance(); + $this->assertNull($col->getGroup()); + + } + + function testGetACL() { + + $col = $this->getInstance(); + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => $this->principalUri, + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => $this->principalUri, + 'protected' => true, + ), + ); + + $this->assertEquals($expected, $col->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testSetACL() { + + $col = $this->getInstance(); + $col->setACL(array()); + + } + + function testGetSupportedPrivilegeSet() { + + $col = $this->getInstance(); + $this->assertNull($col->getSupportedPrivilegeSet()); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php new file mode 100644 index 00000000..28e43ce0 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/NodeTest.php @@ -0,0 +1,101 @@ +systemStatus = new Notification\SystemStatus(1,'"1"'); + + $this->caldavBackend = new CalDAV\Backend\Mock(array(),array(), array( + 'principals/user1' => array( + $this->systemStatus + ) + )); + + $node = new Node($this->caldavBackend, 'principals/user1', $this->systemStatus); + return $node; + + } + + function testGetId() { + + $node = $this->getInstance(); + $this->assertEquals($this->systemStatus->getId() . '.xml', $node->getName()); + + } + + function testGetEtag() { + + $node = $this->getInstance(); + $this->assertEquals('"1"', $node->getETag()); + + } + + function testGetNotificationType() { + + $node = $this->getInstance(); + $this->assertEquals($this->systemStatus, $node->getNotificationType()); + + } + + function testDelete() { + + $node = $this->getInstance(); + $node->delete(); + $this->assertEquals(array(), $this->caldavBackend->getNotificationsForPrincipal('principals/user1')); + + } + + function testGetGroup() { + + $node = $this->getInstance(); + $this->assertNull($node->getGroup()); + + } + + function testGetACL() { + + $node = $this->getInstance(); + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + ); + + $this->assertEquals($expected, $node->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testSetACL() { + + $node = $this->getInstance(); + $node->setACL(array()); + + } + + function testGetSupportedPrivilegeSet() { + + $node = $this->getInstance(); + $this->assertNull($node->getSupportedPrivilegeSet()); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteReplyTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteReplyTest.php new file mode 100644 index 00000000..c53f68ce --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteReplyTest.php @@ -0,0 +1,134 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + $simpleExpected = '' . "\n" . '' . "\n"; + + $dom = new \DOMDocument('1.0','UTF-8'); + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $dom->appendChild($elem); + $notification->serialize(new DAV\Server(), $elem); + $this->assertEquals($simpleExpected, $dom->saveXML()); + + $dom = new \DOMDocument('1.0','UTF-8'); + $dom->formatOutput = true; + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $elem->setAttribute('xmlns:d','DAV:'); + $dom->appendChild($elem); + $notification->serializeBody(new DAV\Server(), $elem); + $this->assertEquals($expected, $dom->saveXML()); + + + } + + function dataProvider() { + + $dtStamp = new \DateTime('2012-01-01 00:00:00 GMT'); + return array( + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'inReplyTo' => 'bar', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_ACCEPTED, + 'hostUrl' => 'calendar' + ), +<< + + 20120101T000000Z + + foo + bar + mailto:foo@example.org + + + /calendar + + + + +FOO + ), + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'inReplyTo' => 'bar', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_DECLINED, + 'hostUrl' => 'calendar', + 'summary' => 'Summary!' + ), +<< + + 20120101T000000Z + + foo + bar + mailto:foo@example.org + + + /calendar + + Summary! + + + +FOO + ), + + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testMissingArg() { + + new InviteReply(array()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testUnknownArg() { + + new InviteReply(array( + 'foo-i-will-break' => true, + + 'id' => 1, + 'etag' => '"bla"', + 'href' => 'abc', + 'dtStamp' => 'def', + 'inReplyTo' => 'qrs', + 'type' => 'ghi', + 'hostUrl' => 'jkl', + )); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteTest.php new file mode 100644 index 00000000..d2c114f4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/InviteTest.php @@ -0,0 +1,230 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + $simpleExpected = '' . "\n" . '' . "\n"; + + $dom = new \DOMDocument('1.0','UTF-8'); + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $dom->appendChild($elem); + $notification->serialize(new DAV\Server(), $elem); + $this->assertEquals($simpleExpected, $dom->saveXML()); + + $dom = new \DOMDocument('1.0','UTF-8'); + $dom->formatOutput = true; + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $elem->setAttribute('xmlns:d','DAV:'); + $elem->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + $dom->appendChild($elem); + $notification->serializeBody(new DAV\Server(), $elem); + $this->assertEquals($expected, $dom->saveXML()); + + + } + + function dataProvider() { + + $dtStamp = new \DateTime('2012-01-01 00:00:00', new \DateTimeZone('GMT')); + return array( + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_ACCEPTED, + 'readOnly' => true, + 'hostUrl' => 'calendar', + 'organizer' => 'principal/user1', + 'commonName' => 'John Doe', + 'summary' => 'Awesome stuff!' + ), +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + + + + John Doe + + /principal/user1 + John Doe + + Awesome stuff! + + + +FOO + ), + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_DECLINED, + 'readOnly' => true, + 'hostUrl' => 'calendar', + 'organizer' => 'principal/user1', + 'commonName' => 'John Doe', + ), +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + + + + John Doe + + /principal/user1 + John Doe + + + + +FOO + ), + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_NORESPONSE, + 'readOnly' => true, + 'hostUrl' => 'calendar', + 'organizer' => 'principal/user1', + 'firstName' => 'Foo', + 'lastName' => 'Bar', + ), +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + + + + Foo + Bar + + /principal/user1 + Foo + Bar + + + + +FOO + ), + array( + array( + 'id' => 'foo', + 'dtStamp' => $dtStamp, + 'etag' => '"1"', + 'href' => 'mailto:foo@example.org', + 'type' => CalDAV\SharingPlugin::STATUS_DELETED, + 'readOnly' => false, + 'hostUrl' => 'calendar', + 'organizer' => 'mailto:user1@fruux.com', + 'supportedComponents' => new CalDAV\Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')), + ), +<< + + 20120101T000000Z + + foo + mailto:foo@example.org + + + /calendar + + + + + + mailto:user1@fruux.com + + + + + + + + +FOO + ), + + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testMissingArg() { + + new Invite(array()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testUnknownArg() { + + new Invite(array( + 'foo-i-will-break' => true, + + 'id' => 1, + 'etag' => '"bla"', + 'href' => 'abc', + 'dtStamp' => 'def', + 'type' => 'ghi', + 'readOnly' => true, + 'hostUrl' => 'jkl', + 'organizer' => 'mno', + )); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/SystemStatusTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/SystemStatusTest.php new file mode 100644 index 00000000..8dc49493 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Notifications/Notification/SystemStatusTest.php @@ -0,0 +1,61 @@ +assertEquals('foo', $notification->getId()); + $this->assertEquals('"1"', $notification->getETag()); + + + $dom = new \DOMDocument('1.0','UTF-8'); + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $dom->appendChild($elem); + $notification->serialize(new DAV\Server(), $elem); + $this->assertEquals($expected1, $dom->saveXML()); + + $dom = new \DOMDocument('1.0','UTF-8'); + $elem = $dom->createElement('cs:root'); + $elem->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + $dom->appendChild($elem); + $notification->serializeBody(new DAV\Server(), $elem); + $this->assertEquals($expected2, $dom->saveXML()); + + + } + + function dataProvider() { + + return array( + + array( + new SystemStatus('foo', '"1"'), + '' . "\n" . '' . "\n", + '' . "\n" . '' . "\n", + ), + + array( + new SystemStatus('foo', '"1"', SystemStatus::TYPE_MEDIUM,'bar'), + '' . "\n" . '' . "\n", + '' . "\n" . 'bar' . "\n", + ), + + array( + new SystemStatus('foo', '"1"', SystemStatus::TYPE_LOW,null,'http://example.org/'), + '' . "\n" . '' . "\n", + '' . "\n" . 'http://example.org/' . "\n", + ) + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/OutboxPostTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/OutboxPostTest.php new file mode 100644 index 00000000..5a5a4e75 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/OutboxPostTest.php @@ -0,0 +1,545 @@ + 'POST', + 'REQUEST_URI' => '/notfound', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $this->assertHTTPStatus(501, $req); + + } + + function testPostPassThruNotTextCalendar() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + )); + + $this->assertHTTPStatus(501, $req); + + } + + function testPostPassThruNoOutBox() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $this->assertHTTPStatus(501, $req); + + } + + function testNoOriginator() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testNoRecipient() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + 'HTTP_ORIGINATOR' => 'mailto:orig@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testBadOriginator() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + 'HTTP_ORIGINATOR' => 'nomailto:orig@example.org', + 'HTTP_RECIPIENT' => 'mailto:user1@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(403, $req); + + } + + function testBadRecipient() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + 'HTTP_ORIGINATOR' => 'mailto:orig@example.org', + 'HTTP_RECIPIENT' => 'http://user1@example.org, mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testIncorrectOriginator() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/admin/outbox', + 'HTTP_ORIGINATOR' => 'mailto:orig@example.org', + 'HTTP_RECIPIENT' => 'mailto:user1@example.org, mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(403, $req); + + } + + function testInvalidIcalBody() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + $req->setBody('foo'); + + $this->assertHTTPStatus(400, $req); + + } + + function testNoVEVENT() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'BEGIN:VTIMEZONE', + 'END:VTIMEZONE', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testNoMETHOD() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(400, $req); + + } + + function testUnsupportedMethod() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:PUBLISH', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $this->assertHTTPStatus(501, $req); + + } + + function testNoIMIPHandler() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + + $response = $this->request($req); + $this->assertEquals('HTTP/1.1 200 OK', $response->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $response->headers); + + // Lazily checking the body for a few expected values. + $this->assertTrue(strpos($response->body, '5.2;')!==false); + $this->assertTrue(strpos($response->body,'user2@example.org')!==false); + + + } + + function testSuccessRequest() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + + $response = $this->request($req); + $this->assertEquals('HTTP/1.1 200 OK', $response->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $response->headers); + + // Lazily checking the body for a few expected values. + $this->assertTrue(strpos($response->body, '2.0;')!==false); + $this->assertTrue(strpos($response->body,'user2@example.org')!==false); + + $this->assertEquals(array( + array( + 'to' => 'user2@example.org', + 'subject' => 'Invitation for: An invitation', + 'body' => implode("\r\n", $body) . "\r\n", + 'headers' => array( + 'Reply-To: user1.sabredav@sabredav.org', + 'From: server@example.org', + 'Content-Type: text/calendar; method=REQUEST; charset=utf-8', + 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY, + ), + ) + ), $handler->getSentEmails()); + + } + + function testSuccessRequestUseRelativePrincipal() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => '/principals/user1/', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'ORGANIZER:mailto:user1.sabredav@sabredav.org', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + + $response = $this->request($req); + $this->assertEquals('HTTP/1.1 200 OK', $response->status, 'Full body: ' . $response->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $response->headers); + + // Lazily checking the body for a few expected values. + $this->assertTrue(strpos($response->body, '2.0;')!==false); + $this->assertTrue(strpos($response->body,'user2@example.org')!==false); + + $this->assertEquals(array( + array( + 'to' => 'user2@example.org', + 'subject' => 'Invitation for: An invitation', + 'body' => implode("\r\n", $body) . "\r\n", + 'headers' => array( + 'Reply-To: user1.sabredav@sabredav.org', + 'From: server@example.org', + 'Content-Type: text/calendar; method=REQUEST; charset=utf-8', + 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY, + ), + ) + ), $handler->getSentEmails()); + + } + + function testSuccessRequestUpperCased() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'MAILTO:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'MAILTO:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + + $response = $this->request($req); + $this->assertEquals('HTTP/1.1 200 OK', $response->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + ), $response->headers); + + // Lazily checking the body for a few expected values. + $this->assertTrue(strpos($response->body, '2.0;')!==false); + $this->assertTrue(strpos($response->body,'user2@example.org')!==false); + + $this->assertEquals(array( + array( + 'to' => 'user2@example.org', + 'subject' => 'Invitation for: An invitation', + 'body' => implode("\r\n", $body) . "\r\n", + 'headers' => array( + 'Reply-To: user1.sabredav@sabredav.org', + 'From: server@example.org', + 'Content-Type: text/calendar; method=REQUEST; charset=utf-8', + 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY, + ), + ) + ), $handler->getSentEmails()); + + } + + function testSuccessReply() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REPLY', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + $this->assertHTTPStatus(200, $req); + + $this->assertEquals(array( + array( + 'to' => 'user2@example.org', + 'subject' => 'Response for: An invitation', + 'body' => implode("\r\n", $body) . "\r\n", + 'headers' => array( + 'Reply-To: user1.sabredav@sabredav.org', + 'From: server@example.org', + 'Content-Type: text/calendar; method=REPLY; charset=utf-8', + 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY, + ), + ) + ), $handler->getSentEmails()); + + } + + function testSuccessCancel() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => 'mailto:user1.sabredav@sabredav.org', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:CANCEL', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + $this->assertHTTPStatus(200, $req); + + $this->assertEquals(array( + array( + 'to' => 'user2@example.org', + 'subject' => 'Cancelled event: An invitation', + 'body' => implode("\r\n", $body) . "\r\n", + 'headers' => array( + 'Reply-To: user1.sabredav@sabredav.org', + 'From: server@example.org', + 'Content-Type: text/calendar; method=CANCEL; charset=utf-8', + 'X-Sabre-Version: ' . DAV\Version::VERSION . '-' . DAV\Version::STABILITY, + ), + ) + ), $handler->getSentEmails()); + + + } + + function testUseRelativePrincipalNoFallback() { + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/outbox', + 'HTTP_ORIGINATOR' => '/principals/user1/', + 'HTTP_RECIPIENT' => 'mailto:user2@example.org', + 'HTTP_CONTENT_TYPE' => 'text/calendar', + )); + + $body = array( + 'BEGIN:VCALENDAR', + 'METHOD:REQUEST', + 'BEGIN:VEVENT', + 'SUMMARY:An invitation', + 'ORGANIZER:rrrrrr', + 'END:VEVENT', + 'END:VCALENDAR', + ); + + $req->setBody(implode("\r\n",$body)); + + $handler = new Schedule\IMip\Mock('server@example.org'); + + $this->caldavPlugin->setIMIPhandler($handler); + + $response = $this->request($req); + $this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Full body: ' . $response->body); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php new file mode 100644 index 00000000..fb7dc316 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/PluginTest.php @@ -0,0 +1,1126 @@ +caldavBackend = new Backend\Mock(array( + array( + 'id' => 1, + 'uri' => 'UUID-123467', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'user1 calendar', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')), + ), + array( + 'id' => 2, + 'uri' => 'UUID-123468', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'user1 calendar2', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet(array('VEVENT','VTODO')), + ) + ), array( + 1 => array( + 'UUID-2345' => array( + 'calendardata' => TestUtil::getTestCalendarData(), + ) + ) + )); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-read',array('principals/user1')); + $principalBackend->setGroupMemberSet('principals/admin/calendar-proxy-write',array('principals/user1')); + $principalBackend->addPrincipal(array( + 'uri' => 'principals/admin/calendar-proxy-read', + )); + $principalBackend->addPrincipal(array( + 'uri' => 'principals/admin/calendar-proxy-write', + )); + + $calendars = new CalendarRootNode($principalBackend,$this->caldavBackend); + $principals = new Principal\Collection($principalBackend); + + $root = new DAV\SimpleCollection('root'); + $root->addChild($calendars); + $root->addChild($principals); + + $objectTree = new DAV\ObjectTree($root); + $this->server = new DAV\Server($objectTree); + $this->server->debugExceptions = true; + $this->server->setBaseUri('/'); + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + // Adding ACL plugin + $this->server->addPlugin(new DAVACL\Plugin()); + + // Adding Auth plugin, and ensuring that we are logged in. + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->defaultUser = 'user1'; + $authPlugin = new DAV\Auth\Plugin($authBackend, 'SabreDAV'); + $this->server->addPlugin($authPlugin); + + $authPlugin->beforeMethod('GET', '/'); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + } + + function testSimple() { + + $this->assertEquals(array('MKCALENDAR'), $this->plugin->getHTTPMethods('calendars/user1/randomnewcalendar')); + $this->assertEquals(array('calendar-access','calendar-proxy'), $this->plugin->getFeatures()); + $this->assertArrayHasKey('urn:ietf:params:xml:ns:caldav', $this->server->xmlNamespaces); + + } + + function testUnknownMethodPassThrough() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKBREAKFAST', + 'REQUEST_URI' => '/', + )); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $this->response->status,'Incorrect status returned. Full response body:' . $this->response->body); + + } + + function testReportPassThrough() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/', + )); + $request->setBody(''); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $this->response->status); + + } + + function testMkCalendarBadLocation() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/blabla', + )); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $this->response->status); + + } + + function testMkCalendarNoParentNode() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/doesntexist/calendar', + )); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 409 Conflict', $this->response->status); + + } + + function testMkCalendarExistingCalendar() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/calendars/user1/UUID-123467', + )); + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 405 Method Not Allowed', $this->response->status); + + } + + function testMkCalendarSucceed() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/calendars/user1/NEWCALENDAR', + )); + + $timezone = 'BEGIN:VCALENDAR +PRODID:-//Example Corp.//CalDAV Client//EN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:US-Eastern +LAST-MODIFIED:19870101T000000Z +BEGIN:STANDARD +DTSTART:19671029T020000 +RRULE:FREQ=YEARLY;BYDAY=-1SU;BYMONTH=10 +TZOFFSETFROM:-0400 +TZOFFSETTO:-0500 +TZNAME:Eastern Standard Time (US & Canada) +END:STANDARD +BEGIN:DAYLIGHT +DTSTART:19870405T020000 +RRULE:FREQ=YEARLY;BYDAY=1SU;BYMONTH=4 +TZOFFSETFROM:-0500 +TZOFFSETTO:-0400 +TZNAME:Eastern Daylight Time (US & Canada) +END:DAYLIGHT +END:VTIMEZONE +END:VCALENDAR'; + + $body = ' + + + + Lisa\'s Events + Calendar restricted to events. + + + + + + + '; + + $request->setBody($body); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created', $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body); + + $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($calendars)); + + $newCalendar = null; + foreach($calendars as $calendar) { + if ($calendar['uri'] === 'NEWCALENDAR') { + $newCalendar = $calendar; + break; + } + } + + $this->assertInternalType('array',$newCalendar); + + $keys = array( + 'uri' => 'NEWCALENDAR', + 'id' => null, + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar restricted to events.', + '{urn:ietf:params:xml:ns:caldav}calendar-timezone' => $timezone, + '{DAV:}displayname' => 'Lisa\'s Events', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null, + ); + + foreach($keys as $key=>$value) { + + $this->assertArrayHasKey($key, $newCalendar); + + if (is_null($value)) continue; + $this->assertEquals($value, $newCalendar[$key]); + + } + $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'; + $this->assertTrue($newCalendar[$sccs] instanceof Property\SupportedCalendarComponentSet); + $this->assertEquals(array('VEVENT'),$newCalendar[$sccs]->getValue()); + + } + + function testMkCalendarEmptyBodySucceed() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'MKCALENDAR', + 'REQUEST_URI' => '/calendars/user1/NEWCALENDAR', + )); + + $request->setBody(''); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created', $this->response->status,'Invalid response code received. Full response body: ' .$this->response->body); + + $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($calendars)); + + $newCalendar = null; + foreach($calendars as $calendar) { + if ($calendar['uri'] === 'NEWCALENDAR') { + $newCalendar = $calendar; + break; + } + } + + $this->assertInternalType('array',$newCalendar); + + $keys = array( + 'uri' => 'NEWCALENDAR', + 'id' => null, + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => null, + ); + + foreach($keys as $key=>$value) { + + $this->assertArrayHasKey($key, $newCalendar); + + if (is_null($value)) continue; + $this->assertEquals($value, $newCalendar[$key]); + + } + $sccs = '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set'; + $this->assertTrue($newCalendar[$sccs] instanceof Property\SupportedCalendarComponentSet); + $this->assertEquals(array('VEVENT','VTODO'),$newCalendar[$sccs]->getValue()); + + } + + function testPrincipalProperties() { + + $httpRequest = new HTTP\Request(array( + 'HTTP_HOST' => 'sabredav.org', + )); + $this->server->httpRequest = $httpRequest; + + $props = $this->server->getPropertiesForPath('/principals/user1',array( + '{urn:ietf:params:xml:ns:caldav}calendar-home-set', + '{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL', + '{urn:ietf:params:xml:ns:caldav}calendar-user-address-set', + '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-read-for', + '{' . Plugin::NS_CALENDARSERVER . '}calendar-proxy-write-for', + '{' . Plugin::NS_CALENDARSERVER . '}notification-URL', + )); + + $this->assertArrayHasKey(0,$props); + $this->assertArrayHasKey(200,$props[0]); + + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-home-set',$props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-home-set']; + $this->assertTrue($prop instanceof DAV\Property\Href); + $this->assertEquals('calendars/user1/',$prop->getHref()); + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL',$props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}schedule-outbox-URL']; + $this->assertTrue($prop instanceof DAV\Property\Href); + $this->assertEquals('calendars/user1/outbox',$prop->getHref()); + + $this->assertArrayHasKey('{'.Plugin::NS_CALENDARSERVER .'}notification-URL',$props[0][200]); + $prop = $props[0][200]['{'.Plugin::NS_CALENDARSERVER .'}notification-URL']; + $this->assertTrue($prop instanceof DAV\Property\Href); + $this->assertEquals('calendars/user1/notifications/',$prop->getHref()); + + + $this->assertArrayHasKey('{urn:ietf:params:xml:ns:caldav}calendar-user-address-set',$props[0][200]); + $prop = $props[0][200]['{urn:ietf:params:xml:ns:caldav}calendar-user-address-set']; + $this->assertTrue($prop instanceof DAV\Property\HrefList); + $this->assertEquals(array('mailto:user1.sabredav@sabredav.org','/principals/user1/'),$prop->getHrefs()); + + $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-read-for', $props[0][200]); + $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-read-for']; + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $prop); + $this->assertEquals(array('principals/admin'), $prop->getHrefs()); + + $this->assertArrayHasKey('{http://calendarserver.org/ns/}calendar-proxy-write-for', $props[0][200]); + $prop = $props[0][200]['{http://calendarserver.org/ns/}calendar-proxy-write-for']; + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $prop); + $this->assertEquals(array('principals/admin'), $prop->getHrefs()); + + + } + + function testSupportedReportSetPropertyNonCalendar() { + + $props = $this->server->getPropertiesForPath('/calendars/user1',array( + '{DAV:}supported-report-set', + )); + + $this->assertArrayHasKey(0,$props); + $this->assertArrayHasKey(200,$props[0]); + $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]); + + $prop = $props[0][200]['{DAV:}supported-report-set']; + + $this->assertInstanceOf('\\Sabre\\DAV\\Property\\SupportedReportSet', $prop); + $value = array( + '{DAV:}expand-property', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set' + ); + $this->assertEquals($value,$prop->getValue()); + + } + + /** + * @depends testSupportedReportSetPropertyNonCalendar + */ + function testSupportedReportSetProperty() { + + $props = $this->server->getPropertiesForPath('/calendars/user1/UUID-123467',array( + '{DAV:}supported-report-set', + )); + + $this->assertArrayHasKey(0,$props); + $this->assertArrayHasKey(200,$props[0]); + $this->assertArrayHasKey('{DAV:}supported-report-set',$props[0][200]); + + $prop = $props[0][200]['{DAV:}supported-report-set']; + + $this->assertTrue($prop instanceof \Sabre\DAV\Property\SupportedReportSet); + $value = array( + '{urn:ietf:params:xml:ns:caldav}calendar-multiget', + '{urn:ietf:params:xml:ns:caldav}calendar-query', + '{urn:ietf:params:xml:ns:caldav}free-busy-query', + '{DAV:}expand-property', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set' + ); + $this->assertEquals($value,$prop->getValue()); + + } + + /** + * @depends testSupportedReportSetProperty + */ + function testCalendarMultiGetReport() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result)); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + + // The response object should have a reference to the Asia/Seoul + // timezone. + $this->assertTrue(strpos($this->response->body,'Asia/Seoul')!==false); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportExpand() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result)); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + // The response object should no longer hold references to timezones. + $this->assertTrue(strpos($this->response->body,'Asia/Seoul')===false); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1/UUID-123467', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + + } + + /** + * @depends testCalendarQueryReport + */ + function testCalendarQueryReportNoCalData() { + + $body = + '' . + '' . + '' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1//UUID-123467', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + + } + + /** + * @depends testCalendarQueryReport + */ + function testCalendarQueryReportNoFilters() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1//UUID-123467', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body); + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport1Object() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1/UUID-123467/UUID-2345', + 'HTTP_DEPTH' => '0', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:prop/c:calendar-data', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + + } + + /** + * @depends testSupportedReportSetProperty + * @depends testCalendarMultiGetReport + */ + function testCalendarQueryReport1ObjectNoCalData() { + + $body = + '' . + '' . + '' . + ' ' . + '' . + '' . + ' ' . + ' ' . + ' ' . + '' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1/UUID-123467/UUID-2345', + 'HTTP_DEPTH' => '0', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Received an unexpected status. Full response body: ' . $this->response->body); + + $xml = simplexml_load_string(DAV\XMLUtil::convertDAVNamespace($this->response->body)); + + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('c','urn:ietf:params:xml:ns:caldav'); + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:href', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:getetag', + '/d:multistatus/d:response/d:propstat/d:status' => 'HTTP/1.1 200 OK', + ); + + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result), 'We expected 1 ' . $xpath . ' elements. We\'ve found ' . count($result) . '. Full result: ' . $this->response->body); + + if (!is_int($v1)) $this->assertEquals($v2,(string)$result[0]); + + } + + } + + function testHTMLActionsPanel() { + + $output = ''; + $r = $this->server->broadcastEvent('onHTMLActionsPanel', array($this->server->tree->getNodeForPath('calendars/user1'), &$output)); + $this->assertFalse($r); + + $this->assertTrue(!!strpos($output,'Display name')); + + } + + function testBrowserPostAction() { + + $r = $this->server->broadcastEvent('onBrowserPostAction', array('calendars/user1', 'mkcalendar', array( + 'name' => 'NEWCALENDAR', + '{DAV:}displayname' => 'foo', + ))); + $this->assertFalse($r); + + $calendars = $this->caldavBackend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3, count($calendars)); + + $newCalendar = null; + foreach($calendars as $calendar) { + if ($calendar['uri'] === 'NEWCALENDAR') { + $newCalendar = $calendar; + break; + } + } + if (!$newCalendar) + $this->fail('Could not find newly created calendar'); + + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportNoEnd() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportNoStart() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + /** + * @depends testCalendarMultiGetReport + */ + function testCalendarMultiGetReportEndBeforeStart() { + + $body = + '' . + '' . + '' . + ' ' . + ' ' . + ' ' . + ' ' . + '' . + '/calendars/user1/UUID-123467/UUID-2345' . + ''; + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/calendars/user1', + 'HTTP_DEPTH' => '1', + )); + $request->setBody($body); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Invalid HTTP status received. Full response body: ' . $this->response->body); + + } + + function testNotificationProperties() { + + $request = array( + '{' . Plugin::NS_CALENDARSERVER . '}notificationtype', + ); + $result = array(); + $notification = new Notifications\Node( + $this->caldavBackend, + 'principals/user1', + new Notifications\Notification\SystemStatus('foo','"1"') + ); + $this->plugin->beforeGetProperties('foo', $notification, $request, $result); + + $this->assertEquals( + array( + 200 => array( + '{' . Plugin::NS_CALENDARSERVER . '}notificationtype' => $notification->getNotificationType() + ) + ), $result); + + } + + function testNotificationGet() { + + $notification = new Notifications\Node( + $this->caldavBackend, + 'principals/user1', + new Notifications\Notification\SystemStatus('foo','"1"') + ); + + $server = new DAV\Server(array($notification)); + $caldav = new Plugin(); + + $server->httpRequest = new HTTP\Request(array( + 'REQUEST_URI' => '/foo.xml', + )); + $httpResponse = new HTTP\ResponseMock(); + $server->httpResponse = $httpResponse; + + $server->addPlugin($caldav); + + $caldav->beforeMethod('GET','foo.xml'); + + $this->assertEquals('HTTP/1.1 200 OK', $httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml', + 'ETag' => '"1"', + ), $httpResponse->headers); + + $expected = +' + + + +'; + + $this->assertEquals($expected, $httpResponse->body); + + } + + function testGETPassthrough() { + + $server = new DAV\Server(); + $caldav = new Plugin(); + + $httpResponse = new HTTP\ResponseMock(); + $server->httpResponse = $httpResponse; + + $server->addPlugin($caldav); + + $caldav->beforeMethod('GET','foo'); + + $this->assertNull($caldav->beforeMethod('GET','foozz')); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php new file mode 100644 index 00000000..625f6421 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/CollectionTest.php @@ -0,0 +1,19 @@ +getChildForPrincipal(array( + 'uri' => 'principals/admin', + )); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\User', $r); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php new file mode 100644 index 00000000..1ee999a9 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyReadTest.php @@ -0,0 +1,101 @@ + 'principal/user', + )); + $this->backend = $backend; + return $principal; + + } + + function testGetName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-read', $i->getName()); + + } + function testGetDisplayName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-read', $i->getDisplayName()); + + } + + function testGetLastModified() { + + $i = $this->getInstance(); + $this->assertNull($i->getLastModified()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testDelete() { + + $i = $this->getInstance(); + $i->delete(); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testSetName() { + + $i = $this->getInstance(); + $i->setName('foo'); + + } + + function testGetAlternateUriSet() { + + $i = $this->getInstance(); + $this->assertEquals(array(), $i->getAlternateUriSet()); + + } + + function testGetPrincipalUri() { + + $i = $this->getInstance(); + $this->assertEquals('principal/user/calendar-proxy-read', $i->getPrincipalUrl()); + + } + + function testGetGroupMemberSet() { + + $i = $this->getInstance(); + $this->assertEquals(array(), $i->getGroupMemberSet()); + + } + + function testGetGroupMembership() { + + $i = $this->getInstance(); + $this->assertEquals(array(), $i->getGroupMembership()); + + } + + function testSetGroupMemberSet() { + + $i = $this->getInstance(); + $i->setGroupMemberSet(array('principals/foo')); + + $expected = array( + $i->getPrincipalUrl() => array('principals/foo') + ); + + $this->assertEquals($expected, $this->backend->groupMembers); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php new file mode 100644 index 00000000..c0186ff0 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/ProxyWriteTest.php @@ -0,0 +1,39 @@ + 'principal/user', + )); + $this->backend = $backend; + return $principal; + + } + + function testGetName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-write', $i->getName()); + + } + function testGetDisplayName() { + + $i = $this->getInstance(); + $this->assertEquals('calendar-proxy-write', $i->getDisplayName()); + + } + + function testGetPrincipalUri() { + + $i = $this->getInstance(); + $this->assertEquals('principal/user/calendar-proxy-write', $i->getPrincipalUrl()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php new file mode 100644 index 00000000..d41692f2 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Principal/UserTest.php @@ -0,0 +1,126 @@ +addPrincipal(array( + 'uri' => 'principals/user/calendar-proxy-read', + )); + $backend->addPrincipal(array( + 'uri' => 'principals/user/calendar-proxy-write', + )); + $backend->addPrincipal(array( + 'uri' => 'principals/user/random', + )); + return new User($backend, array( + 'uri' => 'principals/user', + )); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateFile() { + + $u = $this->getInstance(); + $u->createFile('test'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + function testCreateDirectory() { + + $u = $this->getInstance(); + $u->createDirectory('test'); + + } + + function testGetChildProxyRead() { + + $u = $this->getInstance(); + $child = $u->getChild('calendar-proxy-read'); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyRead', $child); + + } + + function testGetChildProxyWrite() { + + $u = $this->getInstance(); + $child = $u->getChild('calendar-proxy-write'); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyWrite', $child); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound() { + + $u = $this->getInstance(); + $child = $u->getChild('foo'); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound2() { + + $u = $this->getInstance(); + $child = $u->getChild('random'); + + } + + function testGetChildren() { + + $u = $this->getInstance(); + $children = $u->getChildren(); + $this->assertEquals(2, count($children)); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyRead', $children[0]); + $this->assertInstanceOf('Sabre\\CalDAV\\Principal\\ProxyWrite', $children[1]); + + } + + function testChildExist() { + + $u = $this->getInstance(); + $this->assertTrue($u->childExists('calendar-proxy-read')); + $this->assertTrue($u->childExists('calendar-proxy-write')); + $this->assertFalse($u->childExists('foo')); + + } + + function testGetACL() { + + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user/calendar-proxy-read', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user/calendar-proxy-write', + 'protected' => true, + ), + ); + + $u = $this->getInstance(); + $this->assertEquals($expected, $u->getACL()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/AllowedSharingModesTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/AllowedSharingModesTest.php new file mode 100644 index 00000000..733ea110 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/AllowedSharingModesTest.php @@ -0,0 +1,46 @@ +createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + $root->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'' . +' +', $xml); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/InviteTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/InviteTest.php new file mode 100644 index 00000000..349a6e08 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/InviteTest.php @@ -0,0 +1,196 @@ + 'mailto:user1@example.org', + 'status' => CalDAV\SharingPlugin::STATUS_ACCEPTED, + 'readOnly' => false, + ), + array( + 'href' => 'mailto:user2@example.org', + 'commonName' => 'John Doe', + 'status' => CalDAV\SharingPlugin::STATUS_DECLINED, + 'readOnly' => true, + ), + array( + 'href' => 'mailto:user3@example.org', + 'commonName' => 'Joe Shmoe', + 'status' => CalDAV\SharingPlugin::STATUS_NORESPONSE, + 'readOnly' => true, + 'summary' => 'Something, something', + ), + array( + 'href' => 'mailto:user4@example.org', + 'commonName' => 'Hoe Boe', + 'status' => CalDAV\SharingPlugin::STATUS_INVALID, + 'readOnly' => true, + ), + ), array( + 'href' => 'mailto:thedoctor@example.org', + 'commonName' => 'The Doctor', + 'firstName' => 'The', + 'lastName' => 'Doctor', + )); + + $doc = new \DOMDocument(); + $doc->formatOutput = true; + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + $root->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' + + + mailto:thedoctor@example.org + The Doctor + The + Doctor + + + mailto:user1@example.org + + + + + + + mailto:user2@example.org + John Doe + + + + + + + mailto:user3@example.org + Joe Shmoe + + + + + Something, something + + + mailto:user4@example.org + Hoe Boe + + + + + + +', $xml); + + } + + /** + * @depends testSerialize + */ + public function testUnserialize() { + + $input = array( + array( + 'href' => 'mailto:user1@example.org', + 'status' => CalDAV\SharingPlugin::STATUS_ACCEPTED, + 'readOnly' => false, + 'commonName' => '', + 'summary' => '', + ), + array( + 'href' => 'mailto:user2@example.org', + 'commonName' => 'John Doe', + 'status' => CalDAV\SharingPlugin::STATUS_DECLINED, + 'readOnly' => true, + 'summary' => '', + ), + array( + 'href' => 'mailto:user3@example.org', + 'commonName' => 'Joe Shmoe', + 'status' => CalDAV\SharingPlugin::STATUS_NORESPONSE, + 'readOnly' => true, + 'summary' => 'Something, something', + ), + array( + 'href' => 'mailto:user4@example.org', + 'commonName' => 'Hoe Boe', + 'status' => CalDAV\SharingPlugin::STATUS_INVALID, + 'readOnly' => true, + 'summary' => '', + ), + ); + + // Creating the xml + $doc = new \DOMDocument(); + $doc->formatOutput = true; + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + $root->setAttribute('xmlns:cs',CalDAV\Plugin::NS_CALENDARSERVER); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $inputProperty = new Invite($input); + $inputProperty->serialize($server, $root); + + $xml = $doc->saveXML(); + + // Parsing it again + + $doc2 = DAV\XMLUtil::loadDOMDocument($xml); + + $outputProperty = Invite::unserialize($doc2->firstChild); + + $this->assertEquals($input, $outputProperty->getValue()); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testUnserializeNoStatus() { + +$xml = ' + + + mailto:user1@example.org + + + + + +'; + + $doc2 = DAV\XMLUtil::loadDOMDocument($xml); + $outputProperty = Invite::unserialize($doc2->firstChild); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/ScheduleCalendarTranspTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/ScheduleCalendarTranspTest.php new file mode 100644 index 00000000..1ace0b18 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/ScheduleCalendarTranspTest.php @@ -0,0 +1,99 @@ +assertEquals('transparent', $sccs->getValue()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testBadArg() { + + $sccs = new ScheduleCalendarTransp('foo'); + + } + + function values() { + + return array( + array('transparent'), + array('opaque'), + ); + + } + + /** + * @depends testSimple + * @dataProvider values + */ + function testSerialize($value) { + + $property = new ScheduleCalendarTransp($value); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +' +', $xml); + + } + + /** + * @depends testSimple + * @dataProvider values + */ + function testUnserializer($value) { + + $xml = ' +' . +'' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $property = ScheduleCalendarTransp::unserialize($dom->firstChild); + + $this->assertTrue($property instanceof ScheduleCalendarTransp); + $this->assertEquals($value, $property->getValue()); + + } + + /** + * @depends testSimple + */ + function testUnserializerBadData() { + + $xml = ' +' . +'' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $this->assertNull(ScheduleCalendarTransp::unserialize($dom->firstChild)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarComponentSetTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarComponentSetTest.php new file mode 100644 index 00000000..3e5d5f5f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarComponentSetTest.php @@ -0,0 +1,67 @@ +assertEquals(array('VEVENT'), $sccs->getValue()); + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $property = new SupportedCalendarComponentSet(array('VEVENT','VJOURNAL')); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',\Sabre\CalDAV\Plugin::NS_CALDAV); + + $doc->appendChild($root); + $server = new \Sabre\DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'' . +' +', $xml); + + } + + /** + * @depends testSimple + */ + function testUnserializer() { + + $xml = ' +' . +'' . +'' . +''; + + $dom = \Sabre\DAV\XMLUtil::loadDOMDocument($xml); + + $property = SupportedCalendarComponentSet::unserialize($dom->firstChild); + + $this->assertTrue($property instanceof SupportedCalendarComponentSet); + $this->assertEquals(array( + 'VEVENT', + 'VJOURNAL', + ), + $property->getValue()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarDataTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarDataTest.php new file mode 100644 index 00000000..3e016368 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCalendarDataTest.php @@ -0,0 +1,44 @@ +createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +' +', $xml); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCollationSetTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCollationSetTest.php new file mode 100644 index 00000000..669e3155 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Property/SupportedCollationSetTest.php @@ -0,0 +1,46 @@ +createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $root->setAttribute('xmlns:cal',CalDAV\Plugin::NS_CALDAV); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'i;ascii-casemap' . +'i;octet' . +'i;unicode-casemap' . +' +', $xml); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/Mock.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/Mock.php new file mode 100644 index 00000000..ce0946dc --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/IMip/Mock.php @@ -0,0 +1,50 @@ +emails[] = array( + 'to' => $to, + 'subject' => $subject, + 'body' => $body, + 'headers' => $headers, + ); + + } + + public function getSentEmails() { + + return $this->emails; + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php new file mode 100644 index 00000000..60ce9a2a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/Schedule/OutboxTest.php @@ -0,0 +1,68 @@ +assertEquals('outbox', $outbox->getName()); + $this->assertEquals(array(), $outbox->getChildren()); + $this->assertEquals('principals/user1', $outbox->getOwner()); + $this->assertEquals(null, $outbox->getGroup()); + + $this->assertEquals(array( + array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + ), $outbox->getACL()); + + $ok = false; + try { + $outbox->setACL(array()); + } catch (DAV\Exception\MethodNotAllowed $e) { + $ok = true; + } + if (!$ok) { + $this->fail('Exception was not emitted'); + } + + } + + function testGetSupportedPrivilegeSet() { + + $outbox = new Outbox('principals/user1'); + $r = $outbox->getSupportedPrivilegeSet(); + + $ok = 0; + foreach($r['aggregates'] as $priv) { + + if ($priv['privilege'] == '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-query-freebusy') { + $ok++; + } + if ($priv['privilege'] == '{' . CalDAV\Plugin::NS_CALDAV . '}schedule-post-vevent') { + $ok++; + } + } + + $this->assertEquals(2, $ok, "We're missing one or more privileges"); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ShareableCalendarTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ShareableCalendarTest.php new file mode 100644 index 00000000..2f79351f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ShareableCalendarTest.php @@ -0,0 +1,62 @@ + 1, + ); + + $this->backend = new Backend\Mock( + array($props), + array(), + array() + ); + $this->backend->updateShares(1, array( + array( + 'href' => 'mailto:removeme@example.org', + 'commonName' => 'To be removed', + 'readOnly' => true, + ), + ), array()); + + $this->instance = new ShareableCalendar($this->backend, $props); + + } + + function testUpdateShares() { + + $this->instance->updateShares(array( + array( + 'href' => 'mailto:test@example.org', + 'commonName' => 'Foo Bar', + 'summary' => 'Booh', + 'readOnly' => false, + ), + ), array('mailto:removeme@example.org')); + + $this->assertEquals(array(array( + 'href' => 'mailto:test@example.org', + 'commonName' => 'Foo Bar', + 'summary' => 'Booh', + 'readOnly' => false, + 'status' => SharingPlugin::STATUS_NORESPONSE, + )), $this->instance->getShares()); + + } + + function testPublish() { + + $this->instance->setPublishStatus(true); + $this->instance->setPublishStatus(false); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php new file mode 100644 index 00000000..95583191 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharedCalendarTest.php @@ -0,0 +1,122 @@ + 1, + '{http://calendarserver.org/ns/}shared-url' => 'calendars/owner/original', + '{http://sabredav.org/ns}owner-principal' => 'principals/owner', + '{http://sabredav.org/ns}read-only' => false, + 'principaluri' => 'principals/sharee', + ); + } + + $this->backend = new Backend\Mock( + array($props), + array(), + array() + ); + $this->backend->updateShares(1, array( + array( + 'href' => 'mailto:removeme@example.org', + 'commonName' => 'To be removed', + 'readOnly' => true, + ), + ), array()); + + return new SharedCalendar($this->backend, $props); + + } + + function testGetSharedUrl() { + $this->assertEquals('calendars/owner/original', $this->getInstance()->getSharedUrl()); + } + + function testGetShares() { + + $this->assertEquals(array(array( + 'href' => 'mailto:removeme@example.org', + 'commonName' => 'To be removed', + 'readOnly' => true, + 'status' => SharingPlugin::STATUS_NORESPONSE, + )), $this->getInstance()->getShares()); + + } + + function testGetOwner() { + $this->assertEquals('principals/owner', $this->getInstance()->getOwner()); + } + + function testGetACL() { + + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/owner', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/owner', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/owner/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/owner/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/owner/calendar-proxy-read', + 'protected' => true, + ), + array( + 'privilege' => '{' . Plugin::NS_CALDAV . '}read-free-busy', + 'principal' => '{DAV:}authenticated', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/sharee', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/sharee', + 'protected' => true, + ), + ); + + $this->assertEquals($expected, $this->getInstance()->getACL()); + + } + + /** + * @expectedException InvalidArgumentException + */ + public function testCreateInstanceMissingArg() { + + $this->getInstance(array( + 'id' => 1, + '{http://calendarserver.org/ns/}shared-url' => 'calendars/owner/original', + '{http://sabredav.org/ns}read-only' => false, + 'principaluri' => 'principals/sharee', + )); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php new file mode 100644 index 00000000..60a71fd7 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/SharingPluginTest.php @@ -0,0 +1,391 @@ +caldavCalendars = array( + array( + 'principaluri' => 'principals/user1', + 'id' => 1, + 'uri' => 'cal1', + ), + array( + 'principaluri' => 'principals/user1', + 'id' => 2, + 'uri' => 'cal2', + '{' . Plugin::NS_CALENDARSERVER . '}shared-url' => 'calendars/user1/cal2', + '{http://sabredav.org/ns}owner-principal' => 'principals/user2', + '{http://sabredav.org/ns}read-only' => 'true', + ), + array( + 'principaluri' => 'principals/user1', + 'id' => 3, + 'uri' => 'cal3', + ), + ); + + parent::setUp(); + + // Making the logged in user an admin, for full access: + $this->aclPlugin->adminPrincipals[] = 'principals/user1'; + $this->aclPlugin->adminPrincipals[] = 'principals/user2'; + + } + + function testSimple() { + + $this->assertInstanceOf('Sabre\\CalDAV\\SharingPlugin', $this->server->getPlugin('caldav-sharing')); + + } + + function testGetFeatures() { + + $this->assertEquals(array('calendarserver-sharing'), $this->caldavSharingPlugin->getFeatures()); + + } + + function testBeforeGetShareableCalendar() { + + // Forcing the server to authenticate: + $this->authPlugin->beforeMethod('GET',''); + $props = $this->server->getProperties('calendars/user1/cal1', array( + '{' . Plugin::NS_CALENDARSERVER . '}invite', + '{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes', + )); + + $this->assertInstanceOf('Sabre\\CalDAV\\Property\\Invite', $props['{' . Plugin::NS_CALENDARSERVER . '}invite']); + $this->assertInstanceOf('Sabre\\CalDAV\\Property\\AllowedSharingModes', $props['{' . Plugin::NS_CALENDARSERVER . '}allowed-sharing-modes']); + + } + + function testBeforeGetSharedCalendar() { + + $props = $this->server->getProperties('calendars/user1/cal2', array( + '{' . Plugin::NS_CALENDARSERVER . '}shared-url', + '{' . Plugin::NS_CALENDARSERVER . '}invite', + )); + + $this->assertInstanceOf('Sabre\\CalDAV\\Property\\Invite', $props['{' . Plugin::NS_CALENDARSERVER . '}invite']); + $this->assertInstanceOf('Sabre\\DAV\\Property\\IHref', $props['{' . Plugin::NS_CALENDARSERVER . '}shared-url']); + + } + + function testUpdateProperties() { + + $this->caldavBackend->updateShares(1, + array( + array( + 'href' => 'mailto:joe@example.org', + ), + ), + array() + ); + $result = $this->server->updateProperties('calendars/user1/cal1', array( + '{DAV:}resourcetype' => new DAV\Property\ResourceType(array('{DAV:}collection')) + )); + + $this->assertEquals(array( + 200 => array( + '{DAV:}resourcetype' => null, + ), + 'href' => 'calendars/user1/cal1', + ), $result); + + $this->assertEquals(0, count($this->caldavBackend->getShares(1))); + + } + + function testUpdatePropertiesPassThru() { + + $result = $this->server->updateProperties('calendars/user1/cal3', array( + '{DAV:}foo' => 'bar', + )); + + $this->assertEquals(array( + 403 => array( + '{DAV:}foo' => null, + ), + 'href' => 'calendars/user1/cal3', + ), $result); + + } + + function testUnknownMethodNoPOST() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testUnknownMethodNoXML() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/', + 'CONTENT_TYPE' => 'text/plain', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testUnknownMethodNoNode() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/foo', + 'CONTENT_TYPE' => 'text/xml', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testShareRequest() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = << + + + mailto:joe@example.org + Joe Shmoe + + + + mailto:nancy@example.org + + +RRR; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 200 OK', $response->status, $response->body); + + $this->assertEquals(array(array( + 'href' => 'mailto:joe@example.org', + 'commonName' => 'Joe Shmoe', + 'readOnly' => false, + 'status' => SharingPlugin::STATUS_NORESPONSE, + 'summary' => '', + )), $this->caldavBackend->getShares(1)); + + // Verifying that the calendar is now marked shared. + $props = $this->server->getProperties('calendars/user1/cal1', array('{DAV:}resourcetype')); + $this->assertTrue( + $props['{DAV:}resourcetype']->is('{http://calendarserver.org/ns/}shared-owner') + ); + + } + + function testShareRequestNoShareableCalendar() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal2', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + + + mailto:joe@example.org + Joe Shmoe + + + + mailto:nancy@example.org + + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testInviteReply() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + + /principals/owner + + +'; + + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 200 OK', $response->status, $response->body); + + } + + function testInviteBadXML() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + + +'; + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, $response->body); + + } + + function testInviteWrongUrl() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + + /principals/owner + +'; + $request->setBody($xml); + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + // If the plugin did not handle this request, it must ensure that the + // body is still accessible by other plugins. + $this->assertEquals($xml, $request->getBody(true)); + + } + + function testPublish() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 202 Accepted', $response->status, $response->body); + + } + + function testUnpublish() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal1', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 200 OK', $response->status, $response->body); + + } + + function testPublishWrongUrl() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal2', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testUnpublishWrongUrl() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal2', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' + +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } + + function testUnknownXmlDoc() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'POST', + 'REQUEST_URI' => '/calendars/user1/cal2', + 'CONTENT_TYPE' => 'text/xml', + )); + + $xml = ' +'; + + $request->setBody($xml); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status, $response->body); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php new file mode 100644 index 00000000..19acea20 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/TestUtil.php @@ -0,0 +1,208 @@ +setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + + // Yup this is definitely not 'fool proof', but good enough for now. + $queries = explode(';', file_get_contents(__DIR__ . '/../../../examples/sql/sqlite.calendars.sql')); + foreach($queries as $query) { + $pdo->exec($query); + } + // Inserting events through a backend class. + $backend = new Backend\PDO($pdo); + $calendarId = $backend->createCalendar( + 'principals/user1', + 'UUID-123467', + array( + '{DAV:}displayname' => 'user1 calendar', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + ) + ); + $backend->createCalendar( + 'principals/user1', + 'UUID-123468', + array( + '{DAV:}displayname' => 'user1 calendar2', + '{urn:ietf:params:xml:ns:caldav}calendar-description' => 'Calendar description', + '{http://apple.com/ns/ical/}calendar-order' => '1', + '{http://apple.com/ns/ical/}calendar-color' => '#FF0000', + ) + ); + $backend->createCalendarObject($calendarId, 'UUID-2345', self::getTestCalendarData()); + return $pdo; + + } + + static function getTestCalendarData($type = 1) { + + $calendarData = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Apple Inc.//iCal 4.0.1//EN +CALSCALE:GREGORIAN +BEGIN:VTIMEZONE +TZID:Asia/Seoul +BEGIN:DAYLIGHT +TZOFFSETFROM:+0900 +RRULE:FREQ=YEARLY;UNTIL=19880507T150000Z;BYMONTH=5;BYDAY=2SU +DTSTART:19870510T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+1000 +END:DAYLIGHT +BEGIN:STANDARD +TZOFFSETFROM:+1000 +DTSTART:19881009T000000 +TZNAME:GMT+09:00 +TZOFFSETTO:+0900 +END:STANDARD +END:VTIMEZONE +BEGIN:VEVENT +CREATED:20100225T154229Z +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +TRANSP:TRANSPARENT +SUMMARY:Something here +DTSTAMP:20100228T130202Z'; + + switch($type) { + case 1 : + $calendarData.="\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDTEND;TZID=Asia/Seoul:20100223T070000\n"; + break; + case 2 : + $calendarData.="\nDTSTART:20100223T060000\nDTEND:20100223T070000\n"; + break; + case 3 : + $calendarData.="\nDTSTART;VALUE=DATE:20100223\nDTEND;VALUE=DATE:20100223\n"; + break; + case 4 : + $calendarData.="\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDURATION:PT1H\n"; + break; + case 5 : + $calendarData.="\nDTSTART;TZID=Asia/Seoul:20100223T060000\nDURATION:-P5D\n"; + break; + case 6 : + $calendarData.="\nDTSTART;VALUE=DATE:20100223\n"; + break; + case 7 : + $calendarData.="\nDTSTART;VALUE=DATETIME:20100223T060000\n"; + break; + + // No DTSTART, so intentionally broken + case 'X' : + $calendarData.="\n"; + break; + } + + + $calendarData.='ATTENDEE;PARTSTAT=NEEDS-ACTION:mailto:lisa@example.com +SEQUENCE:2 +END:VEVENT +END:VCALENDAR'; + + return $calendarData; + + } + + static function getTestTODO($type = 'due') { + + switch($type) { + + case 'due' : + $extra = "DUE:20100104T000000Z"; + break; + case 'due2' : + $extra = "DUE:20060104T000000Z"; + break; + case 'due_date' : + $extra = "DUE;VALUE=DATE:20060104"; + break; + case 'due_tz' : + $extra = "DUE;TZID=Asia/Seoul:20060104T000000Z"; + break; + case 'due_dtstart' : + $extra = "DTSTART:20050223T060000Z\nDUE:20060104T000000Z"; + break; + case 'due_dtstart2' : + $extra = "DTSTART:20090223T060000Z\nDUE:20100104T000000Z"; + break; + case 'dtstart' : + $extra = 'DTSTART:20100223T060000Z'; + break; + case 'dtstart2' : + $extra = 'DTSTART:20060223T060000Z'; + break; + case 'dtstart_date' : + $extra = 'DTSTART;VALUE=DATE:20100223'; + break; + case 'dtstart_tz' : + $extra = 'DTSTART;TZID=Asia/Seoul:20100223T060000Z'; + break; + case 'dtstart_duration' : + $extra = "DTSTART:20061023T060000Z\nDURATION:PT1H"; + break; + case 'dtstart_duration2' : + $extra = "DTSTART:20101023T060000Z\nDURATION:PT1H"; + break; + case 'completed' : + $extra = 'COMPLETED:20060601T000000Z'; + break; + case 'completed2' : + $extra = 'COMPLETED:20090601T000000Z'; + break; + case 'created' : + $extra = 'CREATED:20060601T000000Z'; + break; + case 'created2' : + $extra = 'CREATED:20090601T000000Z'; + break; + case 'completedcreated' : + $extra = "CREATED:20060601T000000Z\nCOMPLETED:20070101T000000Z"; + break; + case 'completedcreated2' : + $extra = "CREATED:20090601T000000Z\nCOMPLETED:20100101T000000Z"; + break; + case 'notime' : + $extra = 'X-FILLER:oh hello'; + break; + default : + throw new Exception('Unknown type: ' . $type); + + } + + $todo = 'BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Example Corp.//CalDAV Client//EN +BEGIN:VTODO +DTSTAMP:20060205T235335Z +' . $extra . ' +STATUS:NEEDS-ACTION +SUMMARY:Task #1 +UID:DDDEEB7915FA61233B861457@example.com +BEGIN:VALARM +ACTION:AUDIO +TRIGGER;RELATED=START:-PT10M +END:VALARM +END:VTODO +END:VCALENDAR'; + + return $todo; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php new file mode 100644 index 00000000..4c3bae3a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsSharedCalendarsTest.php @@ -0,0 +1,93 @@ + 1, + 'principaluri' => 'principals/user1', + ), + array( + 'id' => 2, + '{http://calendarserver.org/ns/}shared-url' => 'calendars/owner/cal1', + '{http://sabredav.org/ns}owner-principal' => 'principal/owner', + '{http://sabredav.org/ns}read-only' => false, + 'principaluri' => 'principals/user1', + ), + ); + + $this->backend = new Backend\Mock( + $calendars, + array(), + array() + ); + + return new UserCalendars($this->backend, array( + 'uri' => 'principals/user1' + )); + + } + + function testSimple() { + + $instance = $this->getInstance(); + $this->assertEquals('user1', $instance->getName()); + + } + + function testGetChildren() { + + $instance = $this->getInstance(); + $children = $instance->getChildren(); + $this->assertEquals(4, count($children)); + + // Testing if we got all the objects back. + $hasShareable = false; + $hasShared = false; + $hasOutbox = false; + $hasNotifications = false; + + foreach($children as $child) { + + if ($child instanceof IShareableCalendar) { + $hasShareable = true; + } + if ($child instanceof ISharedCalendar) { + $hasShared = true; + } + if ($child instanceof Schedule\IOutbox) { + $hasOutbox = true; + } + if ($child instanceof Notifications\ICollection) { + $hasNotifications = true; + } + + } + if (!$hasShareable) $this->fail('Missing node!'); + if (!$hasShared) $this->fail('Missing node!'); + if (!$hasOutbox) $this->fail('Missing node!'); + if (!$hasNotifications) $this->fail('Missing node!'); + + } + + function testShareReply() { + + $instance = $this->getInstance(); + $instance->shareReply('uri', SharingPlugin::STATUS_DECLINED, 'curi', '1'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsTest.php new file mode 100644 index 00000000..453c872e --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/UserCalendarsTest.php @@ -0,0 +1,207 @@ +markTestSkipped('SQLite driver is not available'); + $this->backend = TestUtil::getBackend(); + $this->usercalendars = new UserCalendars($this->backend, array( + 'uri' => 'principals/user1' + )); + + } + + function testSimple() { + + $this->assertEquals('user1',$this->usercalendars->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + * @depends testSimple + */ + function testGetChildNotFound() { + + $this->usercalendars->getChild('randomname'); + + } + + function testChildExists() { + + $this->assertFalse($this->usercalendars->childExists('foo')); + $this->assertTrue($this->usercalendars->childExists('UUID-123467')); + + } + + function testGetOwner() { + + $this->assertEquals('principals/user1', $this->usercalendars->getOwner()); + + } + + function testGetGroup() { + + $this->assertNull($this->usercalendars->getGroup()); + + } + + function testGetACL() { + + $expected = array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1/calendar-proxy-write', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1/calendar-proxy-read', + 'protected' => true, + ), + ); + $this->assertEquals($expected, $this->usercalendars->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $this->usercalendars->setACL(array()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + * @depends testSimple + */ + function testSetName() { + + $this->usercalendars->setName('bla'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + * @depends testSimple + */ + function testDelete() { + + $this->usercalendars->delete(); + + } + + /** + * @depends testSimple + */ + function testGetLastModified() { + + $this->assertNull($this->usercalendars->getLastModified()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + * @depends testSimple + */ + function testCreateFile() { + + $this->usercalendars->createFile('bla'); + + } + + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + * @depends testSimple + */ + function testCreateDirectory() { + + $this->usercalendars->createDirectory('bla'); + + } + + /** + * @depends testSimple + */ + function testCreateExtendedCollection() { + + $result = $this->usercalendars->createExtendedCollection('newcalendar', array('{DAV:}collection', '{urn:ietf:params:xml:ns:caldav}calendar'), array()); + $this->assertNull($result); + $cals = $this->backend->getCalendarsForUser('principals/user1'); + $this->assertEquals(3,count($cals)); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + * @depends testSimple + */ + function testCreateExtendedCollectionBadResourceType() { + + $this->usercalendars->createExtendedCollection('newcalendar', array('{DAV:}collection','{DAV:}blabla'), array()); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + * @depends testSimple + */ + function testCreateExtendedCollectionNotACalendar() { + + $this->usercalendars->createExtendedCollection('newcalendar', array('{DAV:}collection'), array()); + + } + + function testGetSupportedPrivilegesSet() { + + $this->assertNull($this->usercalendars->getSupportedPrivilegeSet()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testShareReplyFail() { + + $this->usercalendars->shareReply('uri', SharingPlugin::STATUS_DECLINED, 'curi', '1'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php new file mode 100644 index 00000000..6634b9c3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/ValidateICalTest.php @@ -0,0 +1,250 @@ + 'calendar1', + 'principaluri' => 'principals/admin', + 'uri' => 'calendar1', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet( array('VEVENT','VTODO','VJOURNAL') ), + ), + array( + 'id' => 'calendar2', + 'principaluri' => 'principals/admin', + 'uri' => 'calendar2', + '{urn:ietf:params:xml:ns:caldav}supported-calendar-component-set' => new Property\SupportedCalendarComponentSet( array('VTODO','VJOURNAL') ), + ) + ); + + $this->calBackend = new Backend\Mock($calendars,array()); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = array( + new CalendarRootNode($principalBackend, $this->calBackend), + ); + + $this->server = new DAV\Server($tree); + $this->server->debugExceptions = true; + + $plugin = new Plugin(); + $this->server->addPlugin($plugin); + + $response = new HTTP\ResponseMock(); + $this->server->httpResponse = $response; + + } + + function request(HTTP\Request $request) { + + $this->server->httpRequest = $request; + $this->server->exec(); + + return $this->server->httpResponse; + + } + + function testCreateFile() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status); + + } + + function testCreateFileValid() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + $expected = array( + 'uri' => 'blabla.ics', + 'calendardata' => "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", + 'calendarid' => 'calendar1', + ); + + $this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1','blabla.ics')); + + } + + function testCreateFileNoComponents() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileNoUID() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileVCard() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFile2Components() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nBEGIN:VJOURNAL\r\nUID:foo\r\nEND:VJOURNAL\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFile2UIDS() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nBEGIN:VEVENT\r\nUID:bar\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testCreateFileWrongComponent() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VFREEBUSY\r\nUID:foo\r\nEND:VFREEBUSY\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFile() { + + $this->calBackend->createCalendarObject('calendar1','blabla.ics','foo'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status); + + } + + function testUpdateFileParsableBody() { + + $this->calBackend->createCalendarObject('calendar1','blabla.ics','foo'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar1/blabla.ics', + )); + $body = "BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"; + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + $expected = array( + 'uri' => 'blabla.ics', + 'calendardata' => $body, + 'calendarid' => 'calendar1', + ); + + $this->assertEquals($expected, $this->calBackend->getCalendarObject('calendar1','blabla.ics')); + + } + + function testCreateFileInvalidComponent() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFileInvalidComponent() { + + $this->calBackend->createCalendarObject('calendar2','blabla.ics','foo'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/calendars/admin/calendar2/blabla.ics', + )); + $request->setBody("BEGIN:VCALENDAR\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nUID:foo\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CalDAV/VersionTest.php b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/VersionTest.php new file mode 100644 index 00000000..a4e093e3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CalDAV/VersionTest.php @@ -0,0 +1,17 @@ +assertEquals(-1, version_compare('1.0.0',$v)); + + $s = Version::STABILITY; + $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php new file mode 100644 index 00000000..94081fc8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AbstractPluginTest.php @@ -0,0 +1,41 @@ +backend = new Backend\Mock(); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = array( + new AddressBookRoot($principalBackend, $this->backend), + new DAVACL\PrincipalCollection($principalBackend) + ); + + $this->plugin = new Plugin(); + $this->plugin->directories = array('directory'); + $this->server = new DAV\Server($tree); + $this->server->addPlugin($this->plugin); + $this->server->debugExceptions = true; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryParserTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryParserTest.php new file mode 100644 index 00000000..51bea6c6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryParserTest.php @@ -0,0 +1,329 @@ +parse(); + return $q; + + } + + function testFilterBasic() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + $this->assertEquals( + array('{DAV:}foo'), + $q->requestedProperties + ); + + $this->assertEquals( + array( + array( + 'name' => 'NICKNAME', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-matches' => array(), + ), + ), + $q->filters + ); + + $this->assertNull($q->limit); + $this->assertEquals('anyof', $q->test); + + } + + function testNoFilter() { + + // This is non-standard, but helps working around a KDE bug + $xml = array( + '', + '', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + $this->assertEquals( + array('{DAV:}foo'), + $q->requestedProperties + ); + + $this->assertEquals( + array(), + $q->filters + ); + + $this->assertNull($q->limit); + $this->assertEquals('anyof', $q->test); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testFilterDoubleFilter() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + } + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testFilterCorruptTest() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + } + + function testPropFilter() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' 4', + '' + ); + + $q = $this->parse($xml); + + $this->assertEquals( + array( + array( + 'name' => 'NICKNAME', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-matches' => array(), + ), + array( + 'name' => 'EMAIL', + 'test' => 'allof', + 'is-not-defined' => false, + 'param-filters' => array(), + 'text-matches' => array(), + ), + array( + 'name' => 'FN', + 'test' => 'anyof', + 'is-not-defined' => true, + 'param-filters' => array(), + 'text-matches' => array(), + ), + ), + $q->filters + ); + + $this->assertEquals(4,$q->limit); + $this->assertEquals('allof', $q->test); + + } + + function testParamFilter() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + $this->assertEquals( + array( + array( + 'name' => 'NICKNAME', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => array( + array( + 'name' => 'BLA', + 'is-not-defined' => false, + 'text-match' => null + ), + array( + 'name' => 'BLA2', + 'is-not-defined' => true, + 'text-match' => null + ), + ), + 'text-matches' => array(), + ), + ), + $q->filters + ); + + } + + function testTextMatch() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' evert', + ' evert', + ' rene', + ' e', + ' ', + ' foo', + ' ', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + $this->assertEquals( + array( + array( + 'name' => 'NICKNAME', + 'test' => 'anyof', + 'is-not-defined' => false, + 'param-filters' => array( + array( + 'name' => 'BLA', + 'is-not-defined' => false, + 'text-match' => array( + 'negate-condition' => false, + 'collation' => 'i;unicode-casemap', + 'match-type' => 'contains', + 'value' => 'foo', + ), + ), + ), + 'text-matches' => array( + array( + 'negate-condition' => false, + 'collation' => 'i;unicode-casemap', + 'match-type' => 'contains', + 'value' => 'evert', + ), + array( + 'negate-condition' => false, + 'collation' => 'i;octet', + 'match-type' => 'contains', + 'value' => 'evert', + ), + array( + 'negate-condition' => true, + 'collation' => 'i;unicode-casemap', + 'match-type' => 'contains', + 'value' => 'rene', + ), + array( + 'negate-condition' => false, + 'collation' => 'i;unicode-casemap', + 'match-type' => 'starts-with', + 'value' => 'e', + ), + ), + ), + ), + $q->filters + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testBadTextMatch() { + + $xml = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + ' ', + ' evert', + ' ', + ' ', + '' + ); + + $q = $this->parse($xml); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php new file mode 100644 index 00000000..c79f7e87 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookQueryTest.php @@ -0,0 +1,192 @@ + 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(array('baseUri'=>'/')); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals(array( + '/addressbooks/user1/book1/card1' => array( + 200 => array( + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + ), + ), + '/addressbooks/user1/book1/card2' => array( + 404 => array( + '{DAV:}getetag' => null, + ), + ) + ), $result); + + + } + + function testQueryDepth0() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1/card1', + 'HTTP_DEPTH' => '0', + )); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(array('baseUri'=>'/')); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals(array( + '/addressbooks/user1/book1/card1' => array( + 200 => array( + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + ), + ), + ), $result); + + + } + + function testQueryNoMatch() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody( +' + + + + + + + +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(array('baseUri'=>'/')); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals(array(), $result); + + } + + function testQueryLimit() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + 'HTTP_DEPTH' => '1', + )); + + $request->setBody( +' + + + + + + + + 1 +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(array('baseUri'=>'/')); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals(array( + '/addressbooks/user1/book1/card1' => array( + 200 => array( + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD"). '"', + ), + ), + ), $result); + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php new file mode 100644 index 00000000..6eaff5db --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookRootTest.php @@ -0,0 +1,31 @@ +assertEquals('addressbooks', $root->getName()); + + } + + function testGetChildForPrincipal() { + + $pBackend = new DAVACL\PrincipalBackend\Mock(); + $cBackend = new Backend\Mock(); + $root = new AddressBookRoot($pBackend, $cBackend); + + $children = $root->getChildren(); + $this->assertEquals(3, count($children)); + + $this->assertInstanceOf('Sabre\\CardDAV\\UserAddressBooks', $children[0]); + $this->assertEquals('user1', $children[0]->getName()); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php new file mode 100644 index 00000000..aac749b3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/AddressBookTest.php @@ -0,0 +1,162 @@ +backend = new Backend\Mock(); + $this->ab = new AddressBook( + $this->backend, + array( + 'uri' => 'book1', + 'id' => 'foo', + '{DAV:}displayname' => 'd-name', + 'principaluri' => 'principals/user1', + ) + ); + + } + + function testGetName() { + + $this->assertEquals('book1', $this->ab->getName()); + + } + + function testGetChild() { + + $card = $this->ab->getChild('card1'); + $this->assertInstanceOf('Sabre\\CardDAV\\Card', $card); + $this->assertEquals('card1', $card->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChildNotFound() { + + $card = $this->ab->getChild('card3'); + + } + + function testGetChildren() { + + $cards = $this->ab->getChildren(); + $this->assertEquals(2, count($cards)); + + $this->assertEquals('card1', $cards[0]->getName()); + $this->assertEquals('card2', $cards[1]->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->ab->createDirectory('name'); + + } + + function testCreateFile() { + + $file = fopen('php://memory','r+'); + fwrite($file,'foo'); + rewind($file); + $this->ab->createFile('card2',$file); + + $this->assertEquals('foo', $this->backend->cards['foo']['card2']); + + } + + function testDelete() { + + $this->ab->delete(); + $this->assertEquals(array(), $this->backend->addressBooks); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->ab->setName('foo'); + + } + + function testGetLastModified() { + + $this->assertNull($this->ab->getLastModified()); + + } + + function testUpdateProperties() { + + $this->assertTrue( + $this->ab->updateProperties(array('{DAV:}displayname' => 'barrr')) + ); + + $this->assertEquals('barrr', $this->backend->addressBooks[0]['{DAV:}displayname']); + + } + + function testGetProperties() { + + $props = $this->ab->getProperties(array('{DAV:}displayname')); + $this->assertEquals(array( + '{DAV:}displayname' => 'd-name', + ), $props); + + } + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->ab->getOwner()); + $this->assertNull($this->ab->getGroup()); + $this->assertEquals(array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + ), $this->ab->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $this->ab->setACL(array()); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->ab->getSupportedPrivilegeSet() + ); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php new file mode 100644 index 00000000..623188d3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/AbstractPDOTest.php @@ -0,0 +1,249 @@ +backend = new PDO($this->getPDO()); + + } + + public function testGetAddressBooksForUser() { + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ) + ); + + $this->assertEquals($expected, $result); + + } + + public function testUpdateAddressBookInvalidProp() { + + $result = $this->backend->updateAddressBook(1, array( + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + '{DAV:}foo' => 'bar', + )); + + $this->assertFalse($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ) + ); + + $this->assertEquals($expected, $result); + + } + + public function testUpdateAddressBookNoProps() { + + $result = $this->backend->updateAddressBook(1, array()); + + $this->assertFalse($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ) + ); + + $this->assertEquals($expected, $result); + + + } + + public function testUpdateAddressBookSuccess() { + + $result = $this->backend->updateAddressBook(1, array( + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + )); + + $this->assertTrue($result); + + $result = $this->backend->getAddressBooksForUser('principals/user1'); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'updated', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'updated', + '{http://calendarserver.org/ns/}getctag' => 2, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ) + ); + + $this->assertEquals($expected, $result); + + + } + + public function testDeleteAddressBook() { + + $this->backend->deleteAddressBook(1); + + $this->assertEquals(array(), $this->backend->getAddressBooksForUser('principals/user1')); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testCreateAddressBookUnsupportedProp() { + + $this->backend->createAddressBook('principals/user1','book2', array( + '{DAV:}foo' => 'bar', + )); + + } + + public function testCreateAddressBookSuccess() { + + $this->backend->createAddressBook('principals/user1','book2', array( + '{DAV:}displayname' => 'book2', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 2', + )); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book1', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 1', + '{http://calendarserver.org/ns/}getctag' => 1, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ), + array( + 'id' => 2, + 'uri' => 'book2', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'book2', + '{' . CardDAV\Plugin::NS_CARDDAV . '}addressbook-description' => 'addressbook 2', + '{http://calendarserver.org/ns/}getctag' => 1, + '{' . CardDAV\Plugin::NS_CARDDAV . '}supported-address-data' => new CardDAV\Property\SupportedAddressData(), + ) + ); + $result = $this->backend->getAddressBooksForUser('principals/user1'); + $this->assertEquals($expected, $result); + + } + + public function testGetCards() { + + $result = $this->backend->getCards(1); + + $expected = array( + array( + 'id' => 1, + 'uri' => 'card1', + 'carddata' => 'card1', + 'lastmodified' => 0, + ) + ); + + $this->assertEquals($expected, $result); + + } + + public function testGetCard() { + + $result = $this->backend->getCard(1,'card1'); + + $expected = array( + 'id' => 1, + 'uri' => 'card1', + 'carddata' => 'card1', + 'lastmodified' => 0, + ); + + $this->assertEquals($expected, $result); + + } + + /** + * @depends testGetCard + */ + public function testCreateCard() { + + $result = $this->backend->createCard(1, 'card2', 'data2'); + $this->assertEquals('"' . md5('data2') . '"', $result); + $result = $this->backend->getCard(1,'card2'); + $this->assertEquals(2, $result['id']); + $this->assertEquals('card2', $result['uri']); + $this->assertEquals('data2', $result['carddata']); + + } + + /** + * @depends testGetCard + */ + public function testUpdateCard() { + + $result = $this->backend->updateCard(1, 'card1', 'newdata'); + $this->assertEquals('"' . md5('newdata') . '"', $result); + + $result = $this->backend->getCard(1,'card1'); + $this->assertEquals(1, $result['id']); + $this->assertEquals('newdata', $result['carddata']); + + } + + /** + * @depends testGetCard + */ + public function testDeleteCard() { + + $this->backend->deleteCard(1, 'card1'); + $result = $this->backend->getCard(1,'card1'); + $this->assertFalse($result); + + } +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php new file mode 100644 index 00000000..ab7ac4e6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/Mock.php @@ -0,0 +1,130 @@ +addressBooks = $addressBooks; + $this->cards = $cards; + + if (is_null($this->addressBooks)) { + $this->addressBooks = array( + array( + 'id' => 'foo', + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + '{DAV:}displayname' => 'd-name', + ), + ); + + $card2 = fopen('php://memory','r+'); + fwrite($card2,"BEGIN:VCARD\nVERSION:3.0\nUID:45678\nEND:VCARD"); + rewind($card2); + $this->cards = array( + 'foo' => array( + 'card1' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + 'card2' => $card2, + ), + ); + } + + } + + + function getAddressBooksForUser($principalUri) { + + $books = array(); + foreach($this->addressBooks as $book) { + if ($book['principaluri'] === $principalUri) { + $books[] = $book; + } + } + return $books; + + } + + function updateAddressBook($addressBookId, array $mutations) { + + foreach($this->addressBooks as &$book) { + if ($book['id'] !== $addressBookId) + continue; + + foreach($mutations as $key=>$value) { + $book[$key] = $value; + } + return true; + } + return false; + + } + + function createAddressBook($principalUri, $url, array $properties) { + + $this->addressBooks[] = array_merge($properties, array( + 'id' => $url, + 'uri' => $url, + 'principaluri' => $principalUri, + )); + + } + + function deleteAddressBook($addressBookId) { + + foreach($this->addressBooks as $key=>$value) { + if ($value['id'] === $addressBookId) + unset($this->addressBooks[$key]); + } + unset($this->cards[$addressBookId]); + + } + + function getCards($addressBookId) { + + $cards = array(); + foreach($this->cards[$addressBookId] as $uri=>$data) { + $cards[] = array( + 'uri' => $uri, + 'carddata' => $data, + ); + } + return $cards; + + } + + function getCard($addressBookId, $cardUri) { + + if (!isset($this->cards[$addressBookId][$cardUri])) { + return false; + } + + return array( + 'uri' => $cardUri, + 'carddata' => $this->cards[$addressBookId][$cardUri], + ); + + } + + function createCard($addressBookId, $cardUri, $cardData) { + + $this->cards[$addressBookId][$cardUri] = $cardData; + + } + + function updateCard($addressBookId, $cardUri, $cardData) { + + $this->cards[$addressBookId][$cardUri] = $cardData; + + } + + function deleteCard($addressBookId, $cardUri) { + + unset($this->cards[$addressBookId][$cardUri]); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php new file mode 100644 index 00000000..b2f871f6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOMySQLTest.php @@ -0,0 +1,60 @@ +markTestSkipped('MySQL driver is not available, or not properly configured'); + + $pdo = \Sabre\TestUtil::getMySQLDB(); + if (!$pdo) $this->markTestSkipped('Could not connect to MySQL database'); + + $pdo->query("DROP TABLE IF EXISTS addressbooks"); + $pdo->query("DROP TABLE IF EXISTS cards"); + $pdo->query(" +CREATE TABLE addressbooks ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principaluri VARCHAR(255), + displayname VARCHAR(255), + uri VARCHAR(100), + description TEXT, + ctag INT(11) UNSIGNED NOT NULL DEFAULT '1' +); +"); + + $pdo->query(" +INSERT INTO addressbooks + (principaluri, displayname, uri, description, ctag) +VALUES + ('principals/user1', 'book1', 'book1', 'addressbook 1', 1); +"); + + $pdo->query(" +CREATE TABLE cards ( + id INT(11) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + addressbookid INT(11) UNSIGNED NOT NULL, + carddata TEXT, + uri VARCHAR(100), + lastmodified INT(11) UNSIGNED +); +"); + + $pdo->query(" +INSERT INTO cards + (addressbookid, carddata, uri, lastmodified) +VALUES + (1, 'card1', 'card1', 0); +"); + return $pdo; + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOSqliteTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOSqliteTest.php new file mode 100644 index 00000000..a9bbb0bd --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Backend/PDOSqliteTest.php @@ -0,0 +1,69 @@ +markTestSkipped('SQLite driver is not available'); + $pdo = new \PDO('sqlite:'.SABRE_TEMPDIR.'/pdobackend'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + + $pdo->query("DROP TABLE IF EXISTS addressbooks"); + $pdo->query("DROP TABLE IF EXISTS cards"); + $pdo->query(" +CREATE TABLE addressbooks ( + id integer primary key asc, + principaluri text, + displayname text, + uri text, + description text, + ctag integer +); + +"); + + $pdo->query(" +INSERT INTO addressbooks + (principaluri, displayname, uri, description, ctag) +VALUES + ('principals/user1', 'book1', 'book1', 'addressbook 1', 1); +"); + + $pdo->query(" + +CREATE TABLE cards ( + id integer primary key asc, + addressbookid integer, + carddata text, + uri text, + lastmodified integer +); + +"); + $pdo->query(" +INSERT INTO cards + (addressbookid, carddata, uri, lastmodified) +VALUES + (1, 'card1', 'card1', 0); +"); + + return $pdo; + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/CardTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/CardTest.php new file mode 100644 index 00000000..438bd2ea --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/CardTest.php @@ -0,0 +1,184 @@ +backend = new Backend\Mock(); + $this->card = new Card( + $this->backend, + array( + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ), + array( + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'carddata' => 'card', + ) + ); + + } + + function testGet() { + + $result = $this->card->get(); + $this->assertEquals('card', $result); + + } + function testGet2() { + + $this->card = new Card( + $this->backend, + array( + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ), + array( + 'uri' => 'card1', + 'addressbookid' => 'foo', + ) + ); + $result = $this->card->get(); + $this->assertEquals("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", $result); + + } + + + /** + * @depends testGet + */ + function testPut() { + + $file = fopen('php://memory','r+'); + fwrite($file, 'newdata'); + rewind($file); + $this->card->put($file); + $result = $this->card->get(); + $this->assertEquals('newdata', $result); + + } + + + function testDelete() { + + $this->card->delete(); + $this->assertEquals(1, count($this->backend->cards['foo'])); + + } + + function testGetContentType() { + + $this->assertEquals('text/x-vcard; charset=utf-8', $this->card->getContentType()); + + } + + function testGetETag() { + + $this->assertEquals('"' . md5('card') . '"' , $this->card->getETag()); + + } + + function testGetETag2() { + + $card = new Card( + $this->backend, + array( + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ), + array( + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'carddata' => 'card', + 'etag' => '"blabla"', + ) + ); + $this->assertEquals('"blabla"' , $card->getETag()); + + } + + function testGetLastModified() { + + $this->assertEquals(null, $this->card->getLastModified()); + + } + + function testGetSize() { + + $this->assertEquals(4, $this->card->getSize()); + $this->assertEquals(4, $this->card->getSize()); + + } + + function testGetSize2() { + + $card = new Card( + $this->backend, + array( + 'uri' => 'book1', + 'id' => 'foo', + 'principaluri' => 'principals/user1', + ), + array( + 'uri' => 'card1', + 'addressbookid' => 'foo', + 'etag' => '"blabla"', + 'size' => 4, + ) + ); + $this->assertEquals(4, $card->getSize()); + + } + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->card->getOwner()); + $this->assertNull($this->card->getGroup()); + $this->assertEquals(array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + ), $this->card->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $this->card->setACL(array()); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->card->getSupportedPrivilegeSet() + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php new file mode 100644 index 00000000..431cd252 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/IDirectoryTest.php @@ -0,0 +1,30 @@ +addPlugin($plugin); + + $props = $server->getProperties('directory', array('{DAV:}resourcetype')); + $this->assertTrue($props['{DAV:}resourcetype']->is('{' . Plugin::NS_CARDDAV . '}directory')); + + } + +} + +class DirectoryMock extends DAV\SimpleCollection implements IDirectory { + + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php new file mode 100644 index 00000000..12922c6f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/MultiGetTest.php @@ -0,0 +1,55 @@ + 'REPORT', + 'REQUEST_URI' => '/addressbooks/user1/book1', + )); + + $request->setBody( +' + + + + + + /addressbooks/user1/book1/card1 +' + ); + + $response = new HTTP\ResponseMock(); + + $this->server->httpRequest = $request; + $this->server->httpResponse = $response; + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status, 'Incorrect status code. Full response body:' . $response->body); + + // using the client for parsing + $client = new DAV\Client(array('baseUri'=>'/')); + + $result = $client->parseMultiStatus($response->body); + + $this->assertEquals(array( + '/addressbooks/user1/book1/card1' => array( + 200 => array( + '{DAV:}getetag' => '"' . md5("BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD") . '"', + '{urn:ietf:params:xml:ns:carddav}address-data' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + ) + ) + ), $result); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php new file mode 100644 index 00000000..297ebf49 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/PluginTest.php @@ -0,0 +1,149 @@ +assertEquals('card', $this->server->xmlNamespaces[Plugin::NS_CARDDAV]); + $this->assertEquals('{' . Plugin::NS_CARDDAV . '}addressbook', $this->server->resourceTypeMapping['Sabre\\CardDAV\\IAddressBook']); + + $this->assertTrue(in_array('addressbook', $this->plugin->getFeatures())); + + } + + function testSupportedReportSet() { + + $this->assertEquals(array( + '{' . Plugin::NS_CARDDAV . '}addressbook-multiget', + '{' . Plugin::NS_CARDDAV . '}addressbook-query', + ), $this->plugin->getSupportedReportSet('addressbooks/user1/book1')); + + } + + function testSupportedReportSetEmpty() { + + $this->assertEquals(array( + ), $this->plugin->getSupportedReportSet('')); + + } + + function testAddressBookHomeSet() { + + $result = $this->server->getProperties('principals/user1', array('{' . Plugin::NS_CARDDAV . '}addressbook-home-set')); + + $this->assertEquals(1, count($result)); + $this->assertTrue(isset($result['{' . Plugin::NS_CARDDAV . '}addressbook-home-set'])); + $this->assertEquals('addressbooks/user1/', $result['{' . Plugin::NS_CARDDAV . '}addressbook-home-set']->getHref()); + + } + + function testMeCardTest() { + + $result = $this->server->getProperties( + 'addressbooks/user1', + array( + '{http://calendarserver.org/ns/}me-card', + ) + ); + + $this->assertEquals( + array( + '{http://calendarserver.org/ns/}me-card' => + new DAV\Property\Href('addressbooks/user1/book1/vcard1.vcf') + ), + $result + ); + + } + + function testDirectoryGateway() { + + $result = $this->server->getProperties('principals/user1', array('{' . Plugin::NS_CARDDAV . '}directory-gateway')); + + $this->assertEquals(1, count($result)); + $this->assertTrue(isset($result['{' . Plugin::NS_CARDDAV . '}directory-gateway'])); + $this->assertEquals(array('directory'), $result['{' . Plugin::NS_CARDDAV . '}directory-gateway']->getHrefs()); + + } + + function testReportPassThrough() { + + $this->assertNull($this->plugin->report('{DAV:}foo', new \DomDocument())); + + } + + function testHTMLActionsPanel() { + + $output = ''; + $r = $this->server->broadcastEvent('onHTMLActionsPanel', array($this->server->tree->getNodeForPath('addressbooks/user1'), &$output)); + $this->assertFalse($r); + + $this->assertTrue(!!strpos($output,'Display name')); + + } + + function testBrowserPostAction() { + + $r = $this->server->broadcastEvent('onBrowserPostAction', array('addressbooks/user1', 'mkaddressbook', array( + 'name' => 'NEWADDRESSBOOK', + '{DAV:}displayname' => 'foo', + ))); + $this->assertFalse($r); + + $addressbooks = $this->backend->getAddressBooksforUser('principals/user1'); + $this->assertEquals(2, count($addressbooks)); + + $newAddressBook = null; + foreach($addressbooks as $addressbook) { + if ($addressbook['uri'] === 'NEWADDRESSBOOK') { + $newAddressBook = $addressbook; + break; + } + } + if (!$newAddressBook) + $this->fail('Could not find newly created addressbook'); + + } + + function testUpdatePropertiesMeCard() { + + $result = $this->server->updateProperties('addressbooks/user1', array( + '{http://calendarserver.org/ns/}me-card' => new DAV\Property\Href('/addressbooks/user1/book1/vcard2',true), + )); + + $this->assertEquals( + array( + 'href' => 'addressbooks/user1', + 200 => array( + '{http://calendarserver.org/ns/}me-card' => null, + ), + ), + $result + ); + + } + + function testUpdatePropertiesMeCardBadValue() { + + $result = $this->server->updateProperties('addressbooks/user1', array( + '{http://calendarserver.org/ns/}me-card' => new DAV\Property\HrefList(array()), + )); + + $this->assertEquals( + array( + 'href' => 'addressbooks/user1', + 400 => array( + '{http://calendarserver.org/ns/}me-card' => null, + ), + ), + $result + ); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Property/SupportedAddressDataTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Property/SupportedAddressDataTest.php new file mode 100644 index 00000000..a0e4130d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/Property/SupportedAddressDataTest.php @@ -0,0 +1,44 @@ +createElementNS(CardDAV\Plugin::NS_CARDDAV, 'card:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +//'' . +' +', $xml); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php new file mode 100644 index 00000000..2a62bd2f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/SogoStripContentTypeTest.php @@ -0,0 +1,43 @@ + 1, + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + ), + ); + protected $carddavCards = array( + 1 => array( + 'card1.vcf' => "BEGIN:VCARD\nVERSION:3.0\nUID:12345\nEND:VCARD", + ), + ); + + function testDontStrip() { + + $result = $this->server->getProperties('addressbooks/user1/book1/card1.vcf',array('{DAV:}getcontenttype')); + $this->assertEquals(array( + '{DAV:}getcontenttype' => 'text/x-vcard; charset=utf-8' + ), $result); + + } + function testStrip() { + + $this->server->httpRequest = new HTTP\Request(array( + 'HTTP_USER_AGENT' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 Lightning/1.2.1', + )); + $result = $this->server->getProperties('addressbooks/user1/book1/card1.vcf',array('{DAV:}getcontenttype')); + $this->assertEquals(array( + '{DAV:}getcontenttype' => 'text/x-vcard' + ), $result); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php new file mode 100644 index 00000000..9f84566a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/TestUtil.php @@ -0,0 +1,68 @@ +setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION); + + // Yup this is definitely not 'fool proof', but good enough for now. + $queries = explode(';', file_get_contents(__DIR__ . '/../../../examples/sql/sqlite.addressbooks.sql')); + foreach($queries as $query) { + $pdo->exec($query); + } + // Inserting events through a backend class. + $backend = new Backend\PDO($pdo); + $addressbookId = $backend->createAddressBook( + 'principals/user1', + 'UUID-123467', + array( + '{DAV:}displayname' => 'user1 addressbook', + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'AddressBook description', + ) + ); + $backend->createAddressBook( + 'principals/user1', + 'UUID-123468', + array( + '{DAV:}displayname' => 'user1 addressbook2', + '{urn:ietf:params:xml:ns:carddav}addressbook-description' => 'AddressBook description', + ) + ); + $backend->createCard($addressbookId, 'UUID-2345', self::getTestCardData()); + return $pdo; + + } + + static function getTestCardData($type = 1) { + + $addressbookData = 'BEGIN:VCARD +VERSION:3.0 +PRODID:-//Acme Inc.//RoadRunner 1.0//EN +FN:Wile E. Coyote +N:Coyote;Wile;Erroll;; +ORG:Acme Inc. +UID:39A6B5ED-DD51-4AFE-A683-C35EE3749627 +REV:2012-06-20T07:00:39+00:00 +END:VCARD'; + + return $addressbookData; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/UserAddressBooksTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/UserAddressBooksTest.php new file mode 100644 index 00000000..a6ecf3e4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/UserAddressBooksTest.php @@ -0,0 +1,162 @@ +backend = new Backend\Mock(); + $this->s = new UserAddressBooks( + $this->backend, + 'principals/user1' + ); + + } + + function testGetName() { + + $this->assertEquals('user1', $this->s->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetName() { + + $this->s->setName('user2'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testDelete() { + + $this->s->delete(); + + } + + function testGetLastModified() { + + $this->assertNull($this->s->getLastModified()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateFile() { + + $this->s->createFile('bla'); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testCreateDirectory() { + + $this->s->createDirectory('bla'); + + } + + function testGetChild() { + + $child = $this->s->getChild('book1'); + $this->assertInstanceOf('Sabre\\CardDAV\\AddressBook', $child); + $this->assertEquals('book1', $child->getName()); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + function testGetChild404() { + + $this->s->getChild('book2'); + + } + + function testGetChildren() { + + $children = $this->s->getChildren(); + $this->assertEquals(1, count($children)); + $this->assertInstanceOf('Sabre\\CardDAV\\AddressBook', $children[0]); + $this->assertEquals('book1', $children[0]->getName()); + + } + + function testCreateExtendedCollection() { + + $resourceType = array( + '{' . Plugin::NS_CARDDAV . '}addressbook', + '{DAV:}collection', + ); + $this->s->createExtendedCollection('book2', $resourceType, array('{DAV:}displayname' => 'a-book 2')); + + $this->assertEquals(array( + 'id' => 'book2', + 'uri' => 'book2', + '{DAV:}displayname' => 'a-book 2', + 'principaluri' => 'principals/user1', + ), $this->backend->addressBooks[1]); + + } + + /** + * @expectedException Sabre\DAV\Exception\InvalidResourceType + */ + function testCreateExtendedCollectionInvalid() { + + $resourceType = array( + '{DAV:}collection', + ); + $this->s->createExtendedCollection('book2', $resourceType, array('{DAV:}displayname' => 'a-book 2')); + + } + + + function testACLMethods() { + + $this->assertEquals('principals/user1', $this->s->getOwner()); + $this->assertNull($this->s->getGroup()); + $this->assertEquals(array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/user1', + 'protected' => true, + ), + array( + 'privilege' => '{DAV:}write', + 'principal' => 'principals/user1', + 'protected' => true, + ), + ), $this->s->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testSetACL() { + + $this->s->setACL(array()); + + } + + function testGetSupportedPrivilegeSet() { + + $this->assertNull( + $this->s->getSupportedPrivilegeSet() + ); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php new file mode 100644 index 00000000..84da5931 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VCFExportTest.php @@ -0,0 +1,75 @@ + 'book1', + 'uri' => 'book1', + 'principaluri' => 'principals/user1', + ) + ); + protected $carddavCards = array( + 'book1' => array( + "card1" => "BEGIN:VCARD\r\nFN:Person1\r\nEND:VCARD\r\n", + "card2" => "BEGIN:VCARD\r\nFN:Person2\r\nEND:VCARD", + "card3" => "BEGIN:VCARD\r\nFN:Person3\r\nEND:VCARD\r\n", + "card4" => "BEGIN:VCARD\nFN:Person4\nEND:VCARD\n", + ) + ); + + function setUp() { + + parent::setUp(); + $this->server->addPlugin( + new VCFExportPlugin() + ); + + } + + function testSimple() { + + $this->assertInstanceOf('Sabre\\CardDAV\\VCFExportPlugin', $this->server->getPlugin('Sabre\\CardDAV\\VCFExportPlugin')); + + } + + function testExport() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/addressbooks/user1/book1?export', + 'QUERY_STRING' => 'export', + 'REQUEST_METHOD' => 'GET', + )); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 200 OK', $response->status, $response->body); + + $expected = "BEGIN:VCARD +FN:Person1 +END:VCARD +BEGIN:VCARD +FN:Person2 +END:VCARD +BEGIN:VCARD +FN:Person3 +END:VCARD +BEGIN:VCARD +FN:Person4 +END:VCARD +"; + // We actually expected windows line endings + $expected = str_replace("\n","\r\n", $expected); + + $this->assertEquals($expected, $response->body); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php new file mode 100644 index 00000000..c87716c1 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateFilterTest.php @@ -0,0 +1,204 @@ +assertTrue($this->plugin->validateFilters($input, $filters, $test), $message); + } else { + $this->assertFalse($this->plugin->validateFilters($input, $filters, $test), $message); + } + + } + + function data() { + + $body1 = << 'title', 'is-not-defined' => false, 'param-filters' => array(), 'text-matches' => array()); + + // Check if FOO is defined + $filter2 = + array('name' => 'foo', 'is-not-defined' => false, 'param-filters' => array(), 'text-matches' => array()); + + // Check if TITLE is not defined + $filter3 = + array('name' => 'title', 'is-not-defined' => true, 'param-filters' => array(), 'text-matches' => array()); + + // Check if FOO is not defined + $filter4 = + array('name' => 'foo', 'is-not-defined' => true, 'param-filters' => array(), 'text-matches' => array()); + + // Check if TEL[TYPE] is defined + $filter5 = + array( + 'name' => 'tel', + 'is-not-defined' => false, + 'test' => 'anyof', + 'param-filters' => array( + array( + 'name' => 'type', + 'is-not-defined' => false, + 'text-match' => null + ), + ), + 'text-matches' => array(), + ); + + // Check if TEL[FOO] is defined + $filter6 = $filter5; + $filter6['param-filters'][0]['name'] = 'FOO'; + + // Check if TEL[TYPE] is not defined + $filter7 = $filter5; + $filter7['param-filters'][0]['is-not-defined'] = true; + + // Check if TEL[FOO] is not defined + $filter8 = $filter5; + $filter8['param-filters'][0]['name'] = 'FOO'; + $filter8['param-filters'][0]['is-not-defined'] = true; + + // Combining property filters + $filter9 = $filter5; + $filter9['param-filters'][] = $filter6['param-filters'][0]; + + $filter10 = $filter5; + $filter10['param-filters'][] = $filter6['param-filters'][0]; + $filter10['test'] = 'allof'; + + // Check if URL contains 'google' + $filter11 = + array( + 'name' => 'url', + 'is-not-defined' => false, + 'test' => 'anyof', + 'param-filters' => array(), + 'text-matches' => array( + array( + 'match-type' => 'contains', + 'value' => 'google', + 'negate-condition' => false, + 'collation' => 'i;octet', + ), + ), + ); + + // Check if URL contains 'bing' + $filter12 = $filter11; + $filter12['text-matches'][0]['value'] = 'bing'; + + // Check if URL does not contain 'google' + $filter13 = $filter11; + $filter13['text-matches'][0]['negate-condition'] = true; + + // Check if URL does not contain 'bing' + $filter14 = $filter11; + $filter14['text-matches'][0]['value'] = 'bing'; + $filter14['text-matches'][0]['negate-condition'] = true; + + // Param filter with text + $filter15 = $filter5; + $filter15['param-filters'][0]['text-match'] = array( + 'match-type' => 'contains', + 'value' => 'WORK', + 'collation' => 'i;octet', + 'negate-condition' => false, + ); + $filter16 = $filter15; + $filter16['param-filters'][0]['text-match']['negate-condition'] = true; + + + // Param filter + text filter + $filter17 = $filter5; + $filter17['test'] = 'anyof'; + $filter17['text-matches'][] = array( + 'match-type' => 'contains', + 'value' => '444', + 'collation' => 'i;octet', + 'negate-condition' => false, + ); + + $filter18 = $filter17; + $filter18['text-matches'][0]['negate-condition'] = true; + + $filter18['test'] = 'allof'; + + return array( + + // Basic filters + array($body1, array($filter1), 'anyof',true), + array($body1, array($filter2), 'anyof',false), + array($body1, array($filter3), 'anyof',false), + array($body1, array($filter4), 'anyof',true), + + // Combinations + array($body1, array($filter1, $filter2), 'anyof',true), + array($body1, array($filter1, $filter2), 'allof',false), + array($body1, array($filter1, $filter4), 'anyof',true), + array($body1, array($filter1, $filter4), 'allof',true), + array($body1, array($filter2, $filter3), 'anyof',false), + array($body1, array($filter2, $filter3), 'allof',false), + + // Basic parameters + array($body1, array($filter5), 'anyof', true, 'TEL;TYPE is defined, so this should return true'), + array($body1, array($filter6), 'anyof', false, 'TEL;FOO is not defined, so this should return false'), + + array($body1, array($filter7), 'anyof', false, 'TEL;TYPE is defined, so this should return false'), + array($body1, array($filter8), 'anyof', true, 'TEL;TYPE is not defined, so this should return true'), + + // Combined parameters + array($body1, array($filter9), 'anyof', true), + array($body1, array($filter10), 'anyof', false), + + // Text-filters + array($body1, array($filter11), 'anyof', true), + array($body1, array($filter12), 'anyof', false), + array($body1, array($filter13), 'anyof', false), + array($body1, array($filter14), 'anyof', true), + + // Param filter with text-match + array($body1, array($filter15), 'anyof', true), + array($body1, array($filter16), 'anyof', false), + + // Param filter + text filter + array($body1, array($filter17), 'anyof', true), + array($body1, array($filter18), 'anyof', false), + array($body1, array($filter18), 'anyof', false), + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php new file mode 100644 index 00000000..1f52f30a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/ValidateVCardTest.php @@ -0,0 +1,155 @@ + 'addressbook1', + 'principaluri' => 'principals/admin', + 'uri' => 'addressbook1', + ) + ); + + $this->cardBackend = new Backend\Mock($addressbooks,array()); + $principalBackend = new DAVACL\PrincipalBackend\Mock(); + + $tree = array( + new AddressBookRoot($principalBackend, $this->cardBackend), + ); + + $this->server = new DAV\Server($tree); + $this->server->debugExceptions = true; + + $plugin = new Plugin(); + $this->server->addPlugin($plugin); + + $response = new HTTP\ResponseMock(); + $this->server->httpResponse = $response; + + } + + function request(HTTP\Request $request) { + + $this->server->httpRequest = $request; + $this->server->exec(); + + return $this->server->httpResponse; + + } + + function testCreateFile() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status); + + } + + function testCreateFileValid() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + $request->setBody("BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + $expected = array( + 'uri' => 'blabla.vcf', + 'carddata' => "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n", + ); + + $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1','blabla.vcf')); + + } + + function testCreateFileNoUID() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + $request->setBody("BEGIN:VCARD\r\nEND:VCARD\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + $foo = $this->cardBackend->getCard('addressbook1','blabla.vcf'); + $this->assertTrue(strpos($foo['carddata'],'UID')!==false); + } + + + function testCreateFileVCalendar() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + $request->setBody("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n"); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status, 'Incorrect status returned! Full response body: ' . $response->body); + + } + + function testUpdateFile() { + + $this->cardBackend->createCard('addressbook1','blabla.vcf','foo'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status); + + } + + function testUpdateFileParsableBody() { + + $this->cardBackend->createCard('addressbook1','blabla.vcf','foo'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/addressbooks/admin/addressbook1/blabla.vcf', + )); + $body = "BEGIN:VCARD\r\nUID:foo\r\nEND:VCARD\r\n"; + $request->setBody($body); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + $expected = array( + 'uri' => 'blabla.vcf', + 'carddata' => $body, + ); + + $this->assertEquals($expected, $this->cardBackend->getCard('addressbook1','blabla.vcf')); + + } +} + +?> diff --git a/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VersionTest.php b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VersionTest.php new file mode 100644 index 00000000..02943b2d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/CardDAV/VersionTest.php @@ -0,0 +1,17 @@ +assertEquals(-1, version_compare('0.1',$v)); + + $s = Version::STABILITY; + $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php new file mode 100644 index 00000000..4bf5b343 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/AbstractServer.php @@ -0,0 +1,65 @@ +response = new HTTP\ResponseMock(); + $this->server = new Server($this->getRootNode()); + $this->server->httpResponse = $this->response; + $this->server->debugExceptions = true; + $this->deleteTree(SABRE_TEMPDIR,false); + file_put_contents(SABRE_TEMPDIR . '/test.txt', 'Test contents'); + mkdir(SABRE_TEMPDIR . '/dir'); + file_put_contents(SABRE_TEMPDIR . '/dir/child.txt', 'Child contents'); + + + } + + function tearDown() { + + $this->deleteTree(SABRE_TEMPDIR,false); + + } + + protected function getRootNode() { + + return new FS\Directory(SABRE_TEMPDIR); + + } + + private function deleteTree($path,$deleteRoot = true) { + + foreach(scandir($path) as $node) { + + if ($node=='.' || $node=='.svn' || $node=='..') continue; + $myPath = $path.'/'. $node; + if (is_file($myPath)) { + unlink($myPath); + } else { + $this->deleteTree($myPath); + } + + } + if ($deleteRoot) rmdir($path); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php new file mode 100644 index 00000000..36d23c5c --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractBasicTest.php @@ -0,0 +1,91 @@ +httpResponse = $response; + + $backend = new AbstractBasicMock(); + $backend->authenticate($server,'myRealm'); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotAuthenticated + */ + public function testAuthenticateUnknownUser() { + + $response = new HTTP\ResponseMock(); + $tree = new DAV\ObjectTree(new DAV\SimpleCollection('bla')); + $server = new DAV\Server($tree); + $server->httpResponse = $response; + + $request = new HTTP\Request(array( + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'wrongpassword', + )); + $server->httpRequest = $request; + + $backend = new AbstractBasicMock(); + $backend->authenticate($server,'myRealm'); + + } + + public function testAuthenticate() { + + $response = new HTTP\ResponseMock(); + $tree = new DAV\ObjectTree(new DAV\SimpleCollection('bla')); + $server = new DAV\Server($tree); + $server->httpResponse = $response; + + $request = new HTTP\Request(array( + 'PHP_AUTH_USER' => 'username', + 'PHP_AUTH_PW' => 'password', + )); + $server->httpRequest = $request; + + $backend = new AbstractBasicMock(); + $this->assertTrue($backend->authenticate($server,'myRealm')); + + $result = $backend->getCurrentUser(); + + $this->assertEquals('username', $result); + + } + + +} + + +class AbstractBasicMock extends AbstractBasic { + + /** + * Validates a username and password + * + * This method should return true or false depending on if login + * succeeded. + * + * @param string $username + * @param string $password + * @return bool + */ + function validateUserPass($username, $password) { + + return ($username == 'username' && $password == 'password'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php new file mode 100644 index 00000000..495690c4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractDigestTest.php @@ -0,0 +1,149 @@ +httpResponse = $response; + + $backend = new AbstractDigestMock(); + $backend->authenticate($server,'myRealm'); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + public function testAuthenticateBadGetUserInfoResponse() { + + $response = new HTTP\ResponseMock(); + $server = new DAV\Server(); + $server->httpResponse = $response; + + $header = 'username=null, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = new HTTP\Request(array( + 'PHP_AUTH_DIGEST' => $header, + )); + $server->httpRequest = $request; + + $backend = new AbstractDigestMock(); + $backend->authenticate($server,'myRealm'); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + public function testAuthenticateBadGetUserInfoResponse2() { + + $response = new HTTP\ResponseMock(); + $server = new DAV\Server(); + $server->httpResponse = $response; + + $header = 'username=array, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = new HTTP\Request(array( + 'PHP_AUTH_DIGEST' => $header, + )); + $server->httpRequest = $request; + + $backend = new AbstractDigestMock(); + $backend->authenticate($server,'myRealm'); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotAuthenticated + */ + public function testAuthenticateUnknownUser() { + + $response = new HTTP\ResponseMock(); + $server = new DAV\Server(); + $server->httpResponse = $response; + + $header = 'username=false, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = new HTTP\Request(array( + 'PHP_AUTH_DIGEST' => $header, + )); + $server->httpRequest = $request; + + $backend = new AbstractDigestMock(); + $backend->authenticate($server,'myRealm'); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotAuthenticated + */ + public function testAuthenticateBadPassword() { + + $response = new HTTP\ResponseMock(); + $server = new DAV\Server(); + $server->httpResponse = $response; + + $header = 'username=user, realm=myRealm, nonce=12345, uri=/, response=HASH, opaque=1, qop=auth, nc=1, cnonce=1'; + $request = new HTTP\Request(array( + 'PHP_AUTH_DIGEST' => $header, + 'REQUEST_METHOD' => 'PUT', + )); + $server->httpRequest = $request; + + $backend = new AbstractDigestMock(); + $backend->authenticate($server,'myRealm'); + + } + + public function testAuthenticate() { + + $response = new HTTP\ResponseMock(); + $server = new DAV\Server(); + $server->httpResponse = $response; + + $digestHash = md5('HELLO:12345:1:1:auth:' . md5('GET:/')); + $header = 'username=user, realm=myRealm, nonce=12345, uri=/, response='.$digestHash.', opaque=1, qop=auth, nc=1, cnonce=1'; + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_DIGEST' => $header, + 'REQUEST_URI' => '/', + )); + $server->httpRequest = $request; + + $backend = new AbstractDigestMock(); + $this->assertTrue($backend->authenticate($server,'myRealm')); + + $result = $backend->getCurrentUser(); + + $this->assertEquals('user', $result); + $this->assertEquals('HELLO', $backend->getDigestHash('myRealm', $result)); + + } + + +} + + +class AbstractDigestMock extends AbstractDigest { + + function getDigestHash($realm, $userName) { + + switch($userName) { + case 'null' : return null; + case 'false' : return false; + case 'array' : return array(); + case 'user' : return 'HELLO'; + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php new file mode 100644 index 00000000..d22923d5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/AbstractPDOTest.php @@ -0,0 +1,35 @@ +getPDO(); + $backend = new PDO($pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testUserInfo() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $this->assertNull($backend->getDigestHash('realm','blabla')); + + $expected = 'hash'; + + $this->assertEquals($expected, $backend->getDigestHash('realm','user')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php new file mode 100644 index 00000000..b1ed555d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/ApacheTest.php @@ -0,0 +1,45 @@ +authenticate($server,'Realm'); + + } + + function testRemoteUser() { + + $backend = new Apache(); + + $server = new DAV\Server(); + $request = new HTTP\Request(array( + 'REMOTE_USER' => 'username', + )); + $server->httpRequest = $request; + + $this->assertTrue($backend->authenticate($server, 'Realm')); + + $userInfo = 'username'; + + $this->assertEquals($userInfo, $backend->getCurrentUser()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php new file mode 100644 index 00000000..72f150ab --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/FileTest.php @@ -0,0 +1,42 @@ +assertTrue($file instanceof File); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testLoadFileBroken() { + + file_put_contents(SABRE_TEMPDIR . '/backend','user:realm:hash'); + $file = new File(); + $file->loadFile(SABRE_TEMPDIR .'/backend'); + + } + + function testLoadFile() { + + file_put_contents(SABRE_TEMPDIR . '/backend','user:realm:' . md5('user:realm:password')); + $file = new File(); + $file->loadFile(SABRE_TEMPDIR . '/backend'); + + $this->assertFalse($file->getDigestHash('realm','blabla')); + $this->assertEquals(md5('user:realm:password'), $file->getDigesthash('realm','user')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php new file mode 100644 index 00000000..fdad8a60 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/Mock.php @@ -0,0 +1,37 @@ +currentUser = $this->defaultUser; + + } + + function setCurrentUser($user) { + + $this->currentUser = $user; + + } + + function getCurrentUser() { + + return $this->currentUser; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php new file mode 100644 index 00000000..ede432de --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOMySQLTest.php @@ -0,0 +1,31 @@ +markTestSkipped('MySQL driver is not available, or not properly configured'); + $pdo = \Sabre\TestUtil::getMySQLDB(); + if (!$pdo) $this->markTestSkipped('Could not connect to MySQL database'); + $pdo->query("DROP TABLE IF EXISTS users"); + $pdo->query(" +create table users ( + id integer unsigned not null primary key auto_increment, + username varchar(50), + digesta1 varchar(32), + email varchar(80), + displayname varchar(80), + unique(username) +);"); + + $pdo->query("INSERT INTO users (username,digesta1,email,displayname) VALUES ('user','hash','user@example.org','User')"); + + return $pdo; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOSqliteTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOSqliteTest.php new file mode 100644 index 00000000..abfb031b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/Backend/PDOSqliteTest.php @@ -0,0 +1,28 @@ +markTestSkipped('SQLite driver is not available'); + $pdo = new \PDO('sqlite:'.SABRE_TEMPDIR.'/pdobackend'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + $pdo->query('CREATE TABLE users (username TEXT, digesta1 TEXT, email VARCHAR(80), displayname VARCHAR(80))'); + $pdo->query('INSERT INTO users VALUES ("user","hash","user@example.org","User")'); + + return $pdo; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php new file mode 100644 index 00000000..2096a04d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Auth/PluginTest.php @@ -0,0 +1,84 @@ +assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('auth')); + + } + + /** + * @depends testInit + */ + function testAuthenticate() { + + $fakeServer = new DAV\Server( new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock(),'realm'); + $fakeServer->addPlugin($plugin); + $fakeServer->broadCastEvent('beforeMethod',array('GET','/')); + + } + + + + /** + * @depends testInit + * @expectedException Sabre\DAV\Exception\NotAuthenticated + */ + function testAuthenticateFail() { + + $fakeServer = new DAV\Server( new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock(),'failme'); + $fakeServer->addPlugin($plugin); + $fakeServer->broadCastEvent('beforeMethod',array('GET','/')); + + } + + function testReportPassThrough() { + + $fakeServer = new DAV\Server(new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock(),'realm'); + $fakeServer->addPlugin($plugin); + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'REQUEST_URI' => '/', + )); + $request->setBody(''); + + $fakeServer->httpRequest = $request; + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $fakeServer->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $fakeServer->httpResponse->status); + + } + + /** + * @depends testInit + */ + function testGetCurrentUserPrincipal() { + + $fakeServer = new DAV\Server( new DAV\SimpleCollection('bla')); + $plugin = new Plugin(new Backend\Mock(),'realm'); + $fakeServer->addPlugin($plugin); + $fakeServer->broadCastEvent('beforeMethod',array('GET','/')); + $this->assertEquals('admin', $plugin->getCurrentUser()); + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php new file mode 100644 index 00000000..fdc2403d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/BasicNodeTest.php @@ -0,0 +1,234 @@ +put('hi'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testGet() { + + $file = new FileMock(); + $file->get(); + + } + + public function testGetSize() { + + $file = new FileMock(); + $this->assertEquals(0,$file->getSize()); + + } + + + public function testGetETag() { + + $file = new FileMock(); + $this->assertNull($file->getETag()); + + } + + public function testGetContentType() { + + $file = new FileMock(); + $this->assertNull($file->getContentType()); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testDelete() { + + $file = new FileMock(); + $file->delete(); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testSetName() { + + $file = new FileMock(); + $file->setName('hi'); + + } + + public function testGetLastModified() { + + $file = new FileMock(); + // checking if lastmod is within the range of a few seconds + $lastMod = $file->getLastModified(); + $compareTime = ($lastMod + 1)-time(); + $this->assertTrue($compareTime < 3); + + } + + public function testGetChild() { + + $dir = new DirectoryMock(); + $file = $dir->getChild('mockfile'); + $this->assertTrue($file instanceof FileMock); + + } + + public function testChildExists() { + + $dir = new DirectoryMock(); + $this->assertTrue($dir->childExists('mockfile')); + + } + + public function testChildExistsFalse() { + + $dir = new DirectoryMock(); + $this->assertFalse($dir->childExists('mockfile2')); + + } + + /** + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testGetChild404() { + + $dir = new DirectoryMock(); + $file = $dir->getChild('blabla'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testCreateFile() { + + $dir = new DirectoryMock(); + $dir->createFile('hello','data'); + + } + + /** + * @expectedException Sabre\DAV\Exception\Forbidden + */ + public function testCreateDirectory() { + + $dir = new DirectoryMock(); + $dir->createDirectory('hello'); + + } + + public function testSimpleDirectoryConstruct() { + + $dir = new SimpleCollection('simpledir',array()); + + } + + /** + * @depends testSimpleDirectoryConstruct + */ + public function testSimpleDirectoryConstructChild() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir',array($file)); + $file2 = $dir->getChild('mockfile'); + + $this->assertEquals($file,$file2); + + } + + /** + * @expectedException Sabre\DAV\Exception + * @depends testSimpleDirectoryConstruct + */ + public function testSimpleDirectoryBadParam() { + + $dir = new SimpleCollection('simpledir',array('string shouldn\'t be here')); + + } + + /** + * @depends testSimpleDirectoryConstruct + */ + public function testSimpleDirectoryAddChild() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir'); + $dir->addChild($file); + $file2 = $dir->getChild('mockfile'); + + $this->assertEquals($file,$file2); + + } + + /** + * @depends testSimpleDirectoryConstruct + * @depends testSimpleDirectoryAddChild + */ + public function testSimpleDirectoryGetChildren() { + + $file = new FileMock(); + $dir = new SimpleCollection('simpledir'); + $dir->addChild($file); + + $this->assertEquals(array($file),$dir->getChildren()); + + } + + /* + * @depends testSimpleDirectoryConstruct + */ + public function testSimpleDirectoryGetName() { + + $dir = new SimpleCollection('simpledir'); + $this->assertEquals('simpledir',$dir->getName()); + + } + + /** + * @depends testSimpleDirectoryConstruct + * @expectedException Sabre\DAV\Exception\NotFound + */ + public function testSimpleDirectoryGetChild404() { + + $dir = new SimpleCollection('simpledir'); + $dir->getChild('blabla'); + + } +} + +class DirectoryMock extends Collection { + + function getName() { + + return 'mockdir'; + + } + + function getChildren() { + + return array(new FileMock()); + + } + +} + +class FileMock extends File { + + function getName() { + + return 'mockfile'; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php new file mode 100644 index 00000000..6fc65f9e --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/GuessContentTypeTest.php @@ -0,0 +1,68 @@ +server->getPropertiesForPath('/somefile.jpg',$properties); + $this->assertArrayHasKey(0,$result); + $this->assertArrayHasKey(404,$result[0]); + $this->assertArrayHasKey('{DAV:}getcontenttype',$result[0][404]); + + } + + /** + * @depends testGetProperties + */ + function testGetPropertiesPluginEnabled() { + + $this->server->addPlugin(new GuessContentType()); + $properties = array( + '{DAV:}getcontenttype', + ); + $result = $this->server->getPropertiesForPath('/somefile.jpg',$properties); + $this->assertArrayHasKey(0,$result); + $this->assertArrayHasKey(200,$result[0]); + $this->assertArrayHasKey('{DAV:}getcontenttype',$result[0][200]); + $this->assertEquals('image/jpeg',$result[0][200]['{DAV:}getcontenttype']); + + } + + /** + * @depends testGetPropertiesPluginEnabled + */ + function testGetPropertiesUnknown() { + + $this->server->addPlugin(new GuessContentType()); + $properties = array( + '{DAV:}getcontenttype', + ); + $result = $this->server->getPropertiesForPath('/somefile.hoi',$properties); + $this->assertArrayHasKey(0,$result); + $this->assertArrayHasKey(404,$result[0]); + $this->assertArrayHasKey('{DAV:}getcontenttype',$result[0][404]); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php new file mode 100644 index 00000000..169675e7 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/MapGetToPropFindTest.php @@ -0,0 +1,44 @@ +server->addPlugin(new MapGetToPropFind()); + + } + + function testCollectionGet() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'DAV' => '1, 3, extended-mkcol', + 'Vary' => 'Brief,Prefer', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Incorrect status response received. Full response body: ' . $this->response->body); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php new file mode 100644 index 00000000..c3c4bdeb --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Browser/PluginTest.php @@ -0,0 +1,114 @@ +server->addPlugin(new Plugin()); + + } + + function testCollectionGet() { + + $serverVars = array( + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals(array( + 'Content-Type' => 'text/html; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertTrue(strpos($this->response->body, 'Index for dir/') !== false); + $this->assertTrue(strpos($this->response->body, '')!==false); + + } + + function testNotFound() { + + $serverVars = array( + 'REQUEST_URI' => '/random', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 404 Not Found',$this->response->status); + + } + + function testPostOtherContentType() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'text/xml', + ); + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $this->response->status); + + } + + function testPostNoSabreAction() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + ); + $postVars = array(); + + $request = new HTTP\Request($serverVars,$postVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 501 Not Implemented', $this->response->status); + + } + + function testPostMkCol() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'POST', + 'CONTENT_TYPE' => 'application/x-www-form-urlencoded', + ); + $postVars = array( + 'sabreAction' => 'mkcol', + 'name' => 'new_collection', + ); + + $request = new HTTP\Request($serverVars,$postVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 302 Found', $this->response->status); + $this->assertEquals(array( + 'Location' => '/', + ), $this->response->headers); + + $this->assertTrue(is_dir(SABRE_TEMPDIR . '/new_collection')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php new file mode 100644 index 00000000..6e74e6ec --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientMock.php @@ -0,0 +1,32 @@ +url = $url; + $this->curlSettings = $curlSettings; + return $this->response; + + } + + /** + * Just making this method public + * + * @param string $url + * @return string + */ + public function getAbsoluteUrl($url) { + + return parent::getAbsoluteUrl($url); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php new file mode 100644 index 00000000..9c3532a4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ClientTest.php @@ -0,0 +1,949 @@ + '/', + )); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testConstructNoBaseUri() { + + $client = new ClientMock(array()); + + } + + function testRequest() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + ), $client->curlSettings); + + $this->assertEquals(array( + 'statusCode' => 200, + 'headers' => array( + 'content-type' => 'text/plain', + ), + 'body' => 'Hello there!' + ), $result); + + + } + + + function testRequestProxy() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + 'proxy' => 'http://localhost:8000/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + CURLOPT_PROXY => 'http://localhost:8000/', + ), $client->curlSettings); + + $this->assertEquals(array( + 'statusCode' => 200, + 'headers' => array( + 'content-type' => 'text/plain', + ), + 'body' => 'Hello there!' + ), $result); + + } + + function testRequestCAInfo() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $client->addTrustedCertificates('bla'); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_CAINFO => 'bla', + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + ), $client->curlSettings); + + } + + function testRequestSslPeer() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $client->setVerifyPeer(true); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + CURLOPT_SSL_VERIFYPEER => true + ), $client->curlSettings); + + } + + function testRequestAuth() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + 'userName' => 'user', + 'password' => 'password', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + CURLOPT_HTTPAUTH => CURLAUTH_BASIC | CURLAUTH_DIGEST, + CURLOPT_USERPWD => 'user:password' + ), $client->curlSettings); + + $this->assertEquals(array( + 'statusCode' => 200, + 'headers' => array( + 'content-type' => 'text/plain', + ), + 'body' => 'Hello there!' + ), $result); + + } + + function testRequestAuthBasic() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + 'userName' => 'user', + 'password' => 'password', + 'authType' => Client::AUTH_BASIC, + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + CURLOPT_HTTPAUTH => CURLAUTH_BASIC, + CURLOPT_USERPWD => 'user:password' + ), $client->curlSettings); + + $this->assertEquals(array( + 'statusCode' => 200, + 'headers' => array( + 'content-type' => 'text/plain', + ), + 'body' => 'Hello there!' + ), $result); + + } + + function testRequestAuthDigest() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + 'userName' => 'user', + 'password' => 'password', + 'authType' => Client::AUTH_DIGEST, + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'POST', + CURLOPT_POSTFIELDS => 'sillybody', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array('Content-Type: text/plain'), + CURLOPT_HTTPAUTH => CURLAUTH_DIGEST, + CURLOPT_USERPWD => 'user:password' + ), $client->curlSettings); + + $this->assertEquals(array( + 'statusCode' => 200, + 'headers' => array( + 'content-type' => 'text/plain', + ), + 'body' => 'Hello there!' + ), $result); + + } + function testRequestError() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + CURLE_COULDNT_CONNECT, + "Could not connect, or something" + ); + + $caught = false; + try { + $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + } catch (Exception $e) { + $caught = true; + } + if (!$caught) { + $this->markTestFailed('Exception was not thrown'); + } + + } + + function testRequestHTTPError() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 400 Bad Request", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 400, + ), + 0, + "" + ); + + $caught = false; + try { + $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + } catch (Exception $e) { + $caught = true; + } + if (!$caught) { + $this->fail('Exception was not thrown'); + } + + } + + function testRequestHTTP404() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 404 Not Found", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 404, + ), + 0, + "" + ); + + $caught = false; + try { + $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + } catch (Exception\NotFound $e) { + $caught = true; + } + if (!$caught) { + $this->fail('Exception was not thrown'); + } + + } + + /** + * @dataProvider supportedHTTPCodes + */ + function testSpecificHTTPErrors($error) { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 $error blabla", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 42, + 'http_code' => $error, + ), + 0, + "" + ); + + try { + $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + $this->fail('Exception was not thrown'); + } catch (Exception $e) { + $this->assertEquals($e->getHTTPCode(), $error); + } + + + } + + public function supportedHTTPCodes() { + + return array( + array(400), + array(401), + array(402), + array(403), + array(404), + array(405), + array(409), + array(412), + array(416), + array(500), + array(501), + array(507), + ); + + } + + function testUnsupportedHTTPError() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 580 blabla", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 42, + 'http_code' => "580" + ), + 0, + "" + ); + + try { + $client->request('POST', 'baz', 'sillybody', array('Content-Type' => 'text/plain')); + $this->fail('Exception was not thrown'); + } catch (Exception $e) { + $this->assertEquals(500, $e->getHTTPCode()); + } + + + } + + function testGetAbsoluteUrl() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/', + )); + + $this->assertEquals( + 'http://example.org/foo/bar', + $client->getAbsoluteUrl('bar') + ); + + $this->assertEquals( + 'http://example.org/bar', + $client->getAbsoluteUrl('/bar') + ); + + $this->assertEquals( + 'http://example.com/bar', + $client->getAbsoluteUrl('http://example.com/bar') + ); + + } + + function testOptions() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "DAV: feature1, feature2", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 40, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->options(); + $this->assertEquals( + array('feature1', 'feature2'), + $result + ); + + } + + function testOptionsNoDav() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 20, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->options(); + $this->assertEquals( + array(), + $result + ); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testPropFindNoXML() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 20, + 'http_code' => 200, + ), + 0, + "" + ); + + $client->propfind('', array('{DAV:}foo','{DAV:}bar')); + + } + + function testPropFind() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + "", + "", + " ", + " /foo/bar/", + " ", + " ", + " hello", + " ", + " HTTP/1.1 200 OK", + " ", + " ", + " ", + " ", + " ", + " HTTP/1.1 404 Not Found", + " ", + " ", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 19, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->propfind('', array('{DAV:}foo','{DAV:}bar')); + + $this->assertEquals(array( + '{DAV:}foo' => 'hello', + ), $result); + + $requestBody = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + '' + ); + $requestBody = implode("\n", $requestBody); + + $this->assertEquals($requestBody, $client->curlSettings[CURLOPT_POSTFIELDS]); + + } + + /** + * This was reported in Issue 235. + * + * If no '200 Ok' properties are returned, the client will throw an + * E_NOTICE. + */ + function testPropFindNo200s() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + "", + "", + " ", + " /foo/bar/", + " ", + " ", + " ", + " ", + " HTTP/1.1 404 Not Found", + " ", + " ", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 19, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->propfind('', array('{DAV:}foo','{DAV:}bar')); + + $this->assertEquals(array( + ), $result); + + } + + function testPropFindDepth1CustomProp() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + "", + "", + " ", + " /foo/bar/", + " ", + " ", + " hello", + " world", + " ", + " HTTP/1.1 200 OK", + " ", + " ", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 19, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->propfind('', array('{DAV:}foo','{urn:custom}bar'),1); + + $this->assertEquals(array( + "/foo/bar/" => array( + '{DAV:}foo' => 'hello', + '{urn:custom}bar' => 'world', + ), + ), $result); + + $requestBody = array( + '', + '', + ' ', + ' ', + ' ', + ' ', + '' + ); + $requestBody = implode("\n", $requestBody); + + $this->assertEquals($requestBody, $client->curlSettings[CURLOPT_POSTFIELDS]); + + } + + function testPropPatch() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "", + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 20, + 'http_code' => 200, + ), + 0, + "" + ); + + $client->proppatch('', array( + '{DAV:}foo' => 'newvalue', + '{urn:custom}foo' => 'newvalue2', + '{DAV:}bar' => null, + '{urn:custom}bar' => null, + )); + + $requestBody = array( + '', + '', + '', + ' newvalue', + '', + '', + ' newvalue2', + '', + '', + ' ', + '', + '', + ' ', + '', + '' + ); + $requestBody = implode("\n", $requestBody); + + $this->assertEquals($requestBody, $client->curlSettings[CURLOPT_POSTFIELDS]); + + } + + function testHEADRequest() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('HEAD', 'baz'); + + $this->assertEquals('http://example.org/foo/bar/baz', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => 'HEAD', + CURLOPT_NOBODY => true, + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array(), + CURLOPT_POSTFIELDS => null, + ), $client->curlSettings); + + } + + function testPUTRequest() { + + $client = new ClientMock(array( + 'baseUri' => 'http://example.org/foo/bar/', + )); + + $responseBlob = array( + "HTTP/1.1 200 OK", + "Content-Type: text/plain", + "", + "Hello there!" + ); + + $client->response = array( + implode("\r\n", $responseBlob), + array( + 'header_size' => 45, + 'http_code' => 200, + ), + 0, + "" + ); + + $result = $client->request('PUT', 'bar','newcontent'); + + $this->assertEquals('http://example.org/foo/bar/bar', $client->url); + $this->assertEquals(array( + CURLOPT_RETURNTRANSFER => true, + CURLOPT_FOLLOWLOCATION => true, + CURLOPT_MAXREDIRS => 5, + CURLOPT_CUSTOMREQUEST => "PUT", + CURLOPT_POSTFIELDS => 'newcontent', + CURLOPT_HEADER => true, + CURLOPT_HTTPHEADER => array(), + ), $client->curlSettings); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php new file mode 100644 index 00000000..c06d6aa1 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/LockedTest.php @@ -0,0 +1,68 @@ +formatOutput = true; + $root = $dom->createElement('d:root'); + + $dom->appendChild($root); + $root->setAttribute('xmlns:d','DAV:'); + + $lockInfo = new DAV\Locks\LockInfo(); + $lockInfo->uri = '/foo'; + $locked = new Locked($lockInfo); + + $locked->serialize(new DAV\Server(), $root); + + $output = $dom->saveXML(); + + $expected = ' + + + /foo + + +'; + + $this->assertEquals($expected, $output); + + } + + function testSerializeAmpersand() { + + $dom = new DOMDocument('1.0'); + $dom->formatOutput = true; + $root = $dom->createElement('d:root'); + + $dom->appendChild($root); + $root->setAttribute('xmlns:d','DAV:'); + + $lockInfo = new DAV\Locks\LockInfo(); + $lockInfo->uri = '/foo&bar'; + $locked = new Locked($lockInfo); + + $locked->serialize(new DAV\Server(), $root); + + $output = $dom->saveXML(); + + $expected = ' + + + /foo&bar + + +'; + + $this->assertEquals($expected, $output); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php new file mode 100644 index 00000000..7142937b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Exception/PaymentRequiredTest.php @@ -0,0 +1,14 @@ +assertEquals(402, $ex->getHTTPCode()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php new file mode 100644 index 00000000..6d6bf566 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ExceptionTest.php @@ -0,0 +1,30 @@ +assertEquals(500,$e->getHTTPCode()); + + } + + function testExceptionStatuses() { + + $c = array( + 'Sabre\\DAV\\Exception\\NotAuthenticated' => 401, + 'Sabre\\DAV\\Exception\\InsufficientStorage' => 507, + ); + + foreach($c as $class=>$status) { + + $obj = new $class(); + $this->assertEquals($status, $obj->getHTTPCode()); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php new file mode 100644 index 00000000..8947c668 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/FileTest.php @@ -0,0 +1,95 @@ +put('New contents'); + + $this->assertEquals('New contents',file_get_contents(SABRE_TEMPDIR . '/file.txt')); + $this->assertEquals('"' . md5('New contents') . '"', $result); + + } + + function testRange() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->put('0000000'); + $file->patch('111', 2, 3); + + $this->assertEquals('0001110',file_get_contents(SABRE_TEMPDIR . '/file.txt')); + + } + + function testRangeStream() { + + $stream = fopen('php://memory','r+'); + fwrite($stream, "222"); + rewind($stream); + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->put('0000000'); + $file->patch($stream, 2, 3); + + $this->assertEquals('0002220',file_get_contents(SABRE_TEMPDIR . '/file.txt')); + + } + + + function testGet() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertEquals('Contents',stream_get_contents($file->get())); + + } + + function testDelete() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $file->delete(); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/file.txt')); + + } + + function testGetETag() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertEquals('"' . md5('Contents') . '"',$file->getETag()); + + } + + function testGetContentType() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertNull($file->getContentType()); + + } + + function testGetSize() { + + $file = new File(SABRE_TEMPDIR . '/file.txt'); + $this->assertEquals(8,$file->getSize()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/NodeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/NodeTest.php new file mode 100644 index 00000000..275075b4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/NodeTest.php @@ -0,0 +1,178 @@ + 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ); + + $result = $file->updateProperties($properties); + $expected = true; + + $this->assertEquals($expected, $result); + + $getProperties = $file->getProperties(array_keys($properties)); + + $this->assertEquals($properties, $getProperties); + + } + + /** + * @depends testUpdateProperties + */ + function testUpdatePropertiesAgain() { + + $file = new File(SABRE_TEMPDIR . '/dir/file.txt'); + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test3' => 'baz', + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + } + + /** + * @depends testUpdateProperties + */ + function testUpdatePropertiesDelete() { + + $file = new File(SABRE_TEMPDIR . '/dir/file.txt'); + + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => null, + '{http://sabredav.org/NS/2010}test3' => null + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + + $properties = $file->getProperties(array('http://sabredav.org/NS/2010}test1','{http://sabredav.org/NS/2010}test2','{http://sabredav.org/NS/2010}test3')); + + $this->assertEquals(array( + '{http://sabredav.org/NS/2010}test2' => 'bar', + ), $properties); + } + + /** + * @depends testUpdateProperties + */ + function testUpdatePropertiesMove() { + + $file = new File(SABRE_TEMPDIR . '/dir/file.txt'); + + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + + $properties = $file->getProperties(array('{http://sabredav.org/NS/2010}test1','{http://sabredav.org/NS/2010}test2','{http://sabredav.org/NS/2010}test3')); + + $this->assertEquals(array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ), $properties); + + // Renaming + $file->setName('file3.txt'); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/dir/file.txt')); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/dir/file3.txt')); + $this->assertEquals('file3.txt',$file->getName()); + + $newFile = new File(SABRE_TEMPDIR . '/dir/file3.txt'); + $this->assertEquals('file3.txt',$newFile->getName()); + + $properties = $newFile->getProperties(array('{http://sabredav.org/NS/2010}test1','{http://sabredav.org/NS/2010}test2','{http://sabredav.org/NS/2010}test3')); + + $this->assertEquals(array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ), $properties); + } + + /** + * @depends testUpdatePropertiesMove + */ + function testUpdatePropertiesDeleteBleed() { + + $file = new File(SABRE_TEMPDIR . '/dir/file.txt'); + $mutations = array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ); + + $result = $file->updateProperties($mutations); + + $this->assertEquals(true, $result); + + $properties = $file->getProperties(array('{http://sabredav.org/NS/2010}test1','{http://sabredav.org/NS/2010}test2','{http://sabredav.org/NS/2010}test3')); + + $this->assertEquals(array( + '{http://sabredav.org/NS/2010}test1' => 'foo', + '{http://sabredav.org/NS/2010}test2' => 'bar', + ), $properties); + + // Deleting + $file->delete(); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/dir/file.txt')); + + // Creating it again + file_put_contents(SABRE_TEMPDIR . '/dir/file.txt','New Contents'); + $file = new File(SABRE_TEMPDIR . '/dir/file.txt'); + + $properties = $file->getProperties(array('http://sabredav.org/NS/2010}test1','{http://sabredav.org/NS/2010}test2','{http://sabredav.org/NS/2010}test3')); + + $this->assertEquals(array(), $properties); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php new file mode 100644 index 00000000..907ede40 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/FSExt/ServerTest.php @@ -0,0 +1,224 @@ +tempDir); + + } + + function testGet() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' .md5_file($this->tempDir . '/test.txt') . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + function testHEAD() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'HEAD', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5_file($this->tempDir . '/test.txt') . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testPut() { + + $serverVars = array( + 'REQUEST_URI' => '/testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => 0, + 'ETag' => '"' . md5('Testing new file') . '"', + ), $this->response->headers); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('Testing new file',file_get_contents($this->tempDir . '/testput.txt')); + + } + + function testPutAlreadyExists() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_NONE_MATCH' => '*', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + $this->assertNotEquals('Testing new file',file_get_contents($this->tempDir . '/test.txt')); + + } + + function testMkcol() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(""); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertTrue(is_dir($this->tempDir . '/testcol')); + + } + + function testPutUpdate() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing updated file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('0', $this->response->headers['Content-Length']); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('Testing updated file',file_get_contents($this->tempDir . '/test.txt')); + + } + + function testDelete() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'DELETE', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertFalse(file_exists($this->tempDir . '/test.txt')); + + } + + function testDeleteDirectory() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'DELETE', + ); + + mkdir($this->tempDir.'/testcol'); + file_put_contents($this->tempDir.'/testcol/test.txt','Hi! I\'m a file with a short lifespan'); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertFalse(file_exists($this->tempDir . '/col')); + + } + + function testOptions() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'OPTIONS', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'DAV' => '1, 3, extended-mkcol', + 'MS-Author-Via' => 'DAV', + 'Allow' => 'OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT', + 'Accept-Ranges' => 'bytes', + 'Content-Length' => '0', + 'X-Sabre-Version'=> DAV\Version::VERSION, + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('', $this->response->body); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php new file mode 100644 index 00000000..45865b2a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/HTTPPreferParsingTest.php @@ -0,0 +1,200 @@ + 'return-asynch', + )); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals(array( + 'return-asynch' => true, + 'return-minimal' => false, + 'return-representation' => false, + 'strict' => false, + 'lenient' => false, + 'wait' => null, + ), $server->getHTTPPrefer()); + + } + + function testParseValue() { + + $httpRequest = new HTTP\Request(array( + 'HTTP_PREFER' => 'wait=10', + )); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals(array( + 'return-asynch' => false, + 'return-minimal' => false, + 'return-representation' => false, + 'strict' => false, + 'lenient' => false, + 'wait' => 10, + ), $server->getHTTPPrefer()); + + } + + function testParseMultiple() { + + $httpRequest = new HTTP\Request(array( + 'HTTP_PREFER' => 'return-minimal, strict,lenient', + )); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals(array( + 'return-asynch' => false, + 'return-minimal' => true, + 'return-representation' => false, + 'strict' => true, + 'lenient' => true, + 'wait' => null, + ), $server->getHTTPPrefer()); + + } + + function testParseWeirdValue() { + + $httpRequest = new HTTP\Request(array( + 'HTTP_PREFER' => 'BOOOH', + )); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals(array( + 'strict' => false, + 'lenient' => false, + 'wait' => null, + 'return-asynch' => false, + 'return-minimal' => false, + 'return-representation' => false, + ), $server->getHTTPPrefer()); + + } + + function testBrief() { + + $httpRequest = new HTTP\Request(array( + 'HTTP_BRIEF' => 't', + )); + + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals(array( + 'strict' => false, + 'lenient' => false, + 'wait' => null, + 'return-asynch' => false, + 'return-minimal' => true, + 'return-representation' => false, + ), $server->getHTTPPrefer()); + + } + + /** + * propfindMinimal + * + * @return void + */ + function testpropfindMinimal() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PROPFIND', + 'REQUEST_URI' => '/', + 'HTTP_PREFER' => 'return-minimal', + )); + $request->setBody(<< + + + + + + +BLA + ); + + $response = $this->request($request); + + $this->assertTrue(strpos($response->body, 'resourcetype')!==false); + $this->assertTrue(strpos($response->body, 'something')===false); + + } + + function testproppatchMinimal() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PROPPATCH', + 'REQUEST_URI' => '/', + 'HTTP_PREFER' => 'return-minimal', + )); + $request->setBody(<< + + + + nope! + + + +BLA + ); + + $this->server->subscribeEvent('updateProperties', function(&$props, &$result) { + + if (isset($props['{DAV:}something'])) { + unset($props['{DAV:}something']); + $result[200]['{DAV:}something'] = null; + } + + }); + + $response = $this->request($request); + + $this->assertEquals(0, strlen($response->body), 'Expected empty body: ' . $response->body); + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + } + + function testproppatchMinimalError() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PROPPATCH', + 'REQUEST_URI' => '/', + 'HTTP_PREFER' => 'return-minimal', + )); + $request->setBody(<< + + + + nope! + + + +BLA + ); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $response->status); + $this->assertTrue(strpos($response->body, 'something')!==false); + $this->assertTrue(strpos($response->body, 'HTTP/1.1 403 Forbidden')!==false); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php new file mode 100644 index 00000000..da28b697 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpDeleteTest.php @@ -0,0 +1,149 @@ +tree = new Mock\Collection('root', array( + 'file1' => 'foo', + 'dir' => array( + 'subfile' => 'bar', + 'subfile2' => 'baz', + ), + )); + + } + + /** + * A successful DELETE + */ + public function testDelete() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'DELETE', + )); + + $response = $this->request($request); + + $this->assertEquals( + 'HTTP/1.1 204 No Content', + $response->status, + "Incorrect status code. Response body: " . $response->body + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + ), + $response->headers + ); + + } + + /** + * Deleting a Directory + */ + public function testDeleteDirectory() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'DELETE', + )); + + $response = $this->request($request); + + $this->assertEquals( + 'HTTP/1.1 204 No Content', + $response->status, + "Incorrect status code. Response body: " . $response->body + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + ), + $response->headers + ); + + } + + /** + * DELETE on a node that does not exist + */ + public function testDeleteNotFound() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'DELETE', + )); + + $response = $this->request($request); + + $this->assertEquals( + 'HTTP/1.1 404 Not Found', + $response->status, + "Incorrect status code. Response body: " . $response->body + ); + + } + + /** + * DELETE with preconditions + */ + public function testDeletePreconditions() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF_MATCH' => '"' . md5('foo') . '"', + )); + + $response = $this->request($request); + + $this->assertEquals( + 'HTTP/1.1 204 No Content', + $response->status, + "Incorrect status code. Response body: " . $response->body + ); + + } + + /** + * DELETE with incorrect preconditions + */ + public function testDeletePreconditionsFailed() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF_MATCH' => '"' . md5('bar') . '"', + )); + + $response = $this->request($request); + + $this->assertEquals( + 'HTTP/1.1 412 Precondition failed', + $response->status, + "Incorrect status code. Response body: " . $response->body + ); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php new file mode 100644 index 00000000..b1455459 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/HttpPutTest.php @@ -0,0 +1,362 @@ +tree = new Mock\Collection('root', array( + 'file1' => 'foo', + )); + + } + + /** + * A successful PUT of a new file. + */ + public function testPut() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('hello') . '"' + ), + $response->headers + ); + + } + + /** + * A successful PUT on an existing file. + * + * @depends testPut + */ + public function testPutExisting() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'PUT', + )); + $request->setBody('bar'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + $this->assertEquals( + 'bar', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('bar') . '"' + ), + $response->headers + ); + + } + + /** + * PUT on existing file with If-Match: * + * + * @depends testPutExisting + */ + public function testPutExistingIfMatchStar() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_MATCH' => '*', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('hello') . '"' + ), + $response->headers + ); + + } + + /** + * PUT on existing file with If-Match: with a correct etag + * + * @depends testPutExisting + */ + public function testPutExistingIfMatchCorrect() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_MATCH' => '"' . md5('foo') . '"', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file1')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('hello') . '"' + ), + $response->headers + ); + + } + + /** + * PUT with Content-Range should be rejected. + * + * @depends testPut + */ + public function testPutContentRange() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_CONTENT_RANGE' => 'bytes/100-200', + )); + $request->setBody('hello'); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 501 Not Implemented', $response->status); + + } + + /** + * PUT on non-existing file with If-None-Match: * should work. + * + * @depends testPut + */ + public function testPutIfNoneMatchStar() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_NONE_MATCH' => '*', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('hello') . '"' + ), + $response->headers + ); + + } + + /** + * PUT on non-existing file with If-Match: * should fail. + * + * @depends testPut + */ + public function testPutIfMatchStar() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_MATCH' => '*', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 412 Precondition failed', $response->status); + + } + + /** + * PUT on existing file with If-None-Match: * should fail. + * + * @depends testPut + */ + public function testPutExistingIfNoneMatchStar() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_NONE_MATCH' => '*', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 412 Precondition failed', $response->status); + + } + + /** + * PUT thats created in a non-collection should be rejected. + * + * @depends testPut + */ + public function testPutNoParent() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file1/file2', + 'REQUEST_METHOD' => 'PUT', + )); + $request->setBody('hello'); + + $response = $this->request($request); + $this->assertEquals('HTTP/1.1 409 Conflict', $response->status); + + } + + /** + * Finder may sometimes make a request, which gets its content-body + * stripped. We can't always prevent this from happening, but in some cases + * we can detected this and return an error instead. + * + * @depends testPut + */ + public function testFinderPutSuccess() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_X_EXPECTED_ENTITY_LENGTH' => '5', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 201 Created', $response->status); + + $this->assertEquals( + 'hello', + $this->server->tree->getNodeForPath('file2')->get() + ); + + $this->assertEquals( + array( + 'Content-Length' => '0', + 'ETag' => '"' . md5('hello') . '"' + ), + $response->headers + ); + + } + + /** + * Same as the last one, but in this case we're mimicing a failed request. + * + * @depends testFinderPutSuccess + */ + public function testFinderPutFail() { + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_X_EXPECTED_ENTITY_LENGTH' => '5', + )); + $request->setBody(''); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $response->status); + + } + + /** + * Plugins can intercept PUT. We need to make sure that works. + */ + public function testPutIntercept() { + + $this->server->subscribeEvent('beforeBind', array($this, 'beforeBind')); + + $request = new HTTP\Request(array( + 'REQUEST_URI' => '/file2', + 'REQUEST_METHOD' => 'PUT', + )); + $request->setBody('hello'); + + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 418 I\'m a teapot', $response->status); + + $this->assertFalse( + $this->server->tree->nodeExists('file2') + ); + + $this->assertEquals( + array( + ), + $response->headers + ); + + } + + public function beforeBind() { + + $this->server->httpResponse->sendStatus(418); + return false; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php new file mode 100644 index 00000000..c3fba4aa --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Issue33Test.php @@ -0,0 +1,105 @@ +setBaseUri('/webdav/'); + + $serverVars = array( + 'REQUEST_URI' => '/webdav/bar', + 'HTTP_DESTINATION' => 'http://dev2.tribalos.com/webdav/%C3%A0fo%C3%B3', + 'HTTP_OVERWRITE' => 'F', + ); + + $request = new HTTP\Request($serverVars); + + $server->httpRequest = $request; + + $info = $server->getCopyAndMoveInfo(); + + $this->assertEquals('%C3%A0fo%C3%B3', urlencode($info['destination'])); + $this->assertFalse($info['destinationExists']); + $this->assertFalse($info['destinationNode']); + + } + + function testTreeMove() { + + mkdir(SABRE_TEMPDIR . '/issue33'); + $dir = new FS\Directory(SABRE_TEMPDIR . '/issue33'); + + $dir->createDirectory('bar'); + + $tree = new ObjectTree($dir); + $tree->move('bar',urldecode('%C3%A0fo%C3%B3')); + + $node = $tree->getNodeForPath(urldecode('%C3%A0fo%C3%B3')); + $this->assertEquals(urldecode('%C3%A0fo%C3%B3'),$node->getName()); + + } + + function testDirName() { + + $dirname1 = 'bar'; + $dirname2 = urlencode('%C3%A0fo%C3%B3');; + + $this->assertTrue(dirname($dirname1)==dirname($dirname2)); + + } + + /** + * @depends testTreeMove + * @depends testCopyMoveInfo + */ + function testEverything() { + + // Request object + $serverVars = array( + 'REQUEST_METHOD' => 'MOVE', + 'REQUEST_URI' => '/webdav/bar', + 'HTTP_DESTINATION' => 'http://dev2.tribalos.com/webdav/%C3%A0fo%C3%B3', + 'HTTP_OVERWRITE' => 'F', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + + $response = new HTTP\ResponseMock(); + + // Server setup + mkdir(SABRE_TEMPDIR . '/issue33'); + $dir = new FS\Directory(SABRE_TEMPDIR . '/issue33'); + + $dir->createDirectory('bar'); + + $tree = new ObjectTree($dir); + + $server = new Server($tree); + $server->setBaseUri('/webdav/'); + + $server->httpRequest = $request; + $server->httpResponse = $response; + $server->exec(); + + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/issue33/' . urldecode('%C3%A0fo%C3%B3'))); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php new file mode 100644 index 00000000..f39e9a03 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/AbstractTest.php @@ -0,0 +1,196 @@ +getBackend(); + $this->assertInstanceOf('Sabre\\DAV\\Locks\\Backend\\AbstractBackend', $backend); + + } + + /** + * @depends testSetup + */ + function testGetLocks() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + $lock->uri ='someuri'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + + $this->assertEquals(1,count($locks)); + $this->assertEquals('Sinterklaas',$locks[0]->owner); + $this->assertEquals('someuri',$locks[0]->uri); + + } + + /** + * @depends testGetLocks + */ + function testGetLocksParent() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = DAV\Server::DEPTH_INFINITY; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + + $this->assertEquals(1,count($locks)); + $this->assertEquals('Sinterklaas',$locks[0]->owner); + $this->assertEquals('someuri',$locks[0]->uri); + + } + + + /** + * @depends testGetLocks + */ + function testGetLocksParentDepth0() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = 0; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + + $this->assertEquals(0,count($locks)); + + } + + function testGetLocksChildren() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->depth = 0; + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri/child', $lock)); + + $locks = $backend->getLocks('someuri/child', false); + $this->assertEquals(1,count($locks)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(0,count($locks)); + + $locks = $backend->getLocks('someuri', true); + $this->assertEquals(1,count($locks)); + + } + + /** + * @depends testGetLocks + */ + function testLockRefresh() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + /* Second time */ + + $lock->owner = 'Santa Clause'; + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + + $this->assertEquals(1,count($locks)); + + $this->assertEquals('Santa Clause',$locks[0]->owner); + $this->assertEquals('someuri',$locks[0]->uri); + + } + + /** + * @depends testGetLocks + */ + function testUnlock() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1,count($locks)); + + $this->assertTrue($backend->unlock('someuri',$lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(0,count($locks)); + + } + + /** + * @depends testUnlock + */ + function testUnlockUnknownToken() { + + $backend = $this->getBackend(); + + $lock = new DAV\Locks\LockInfo(); + $lock->owner = 'Sinterklaas'; + $lock->timeout = 60; + $lock->created = time(); + $lock->token = 'MY-UNIQUE-TOKEN'; + + $this->assertTrue($backend->lock('someuri', $lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1,count($locks)); + + $lock->token = 'SOME-OTHER-TOKEN'; + $this->assertFalse($backend->unlock('someuri',$lock)); + + $locks = $backend->getLocks('someuri', false); + $this->assertEquals(1,count($locks)); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FSTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FSTest.php new file mode 100644 index 00000000..651abf78 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/FSTest.php @@ -0,0 +1,31 @@ +markTestSkipped('MySQL driver is not available, or it was not properly configured'); + $pdo = \Sabre\TestUtil::getMySQLDB(); + if (!$pdo) $this->markTestSkipped('Could not connect to MySQL database'); + $pdo->query('DROP TABLE IF EXISTS locks;'); + $pdo->query(" +CREATE TABLE locks ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + owner VARCHAR(100), + timeout INTEGER UNSIGNED, + created INTEGER, + token VARCHAR(100), + scope TINYINT, + depth TINYINT, + uri text +);"); + + $backend = new PDO($pdo); + return $backend; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php new file mode 100644 index 00000000..d6336c7b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/Backend/PDOTest.php @@ -0,0 +1,29 @@ +markTestSkipped('SQLite driver is not available'); + \Sabre\TestUtil::clearTempDir(); + mkdir(SABRE_TEMPDIR . '/pdolocks'); + $pdo = new \PDO('sqlite:' . SABRE_TEMPDIR . '/pdolocks/db.sqlite'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + $pdo->query('CREATE TABLE locks ( id integer primary key asc, owner text, timeout text, created integer, token text, scope integer, depth integer, uri text)'); + $backend = new PDO($pdo); + return $backend; + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/GetIfConditionsTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/GetIfConditionsTest.php new file mode 100644 index 00000000..7b2cd0db --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/GetIfConditionsTest.php @@ -0,0 +1,375 @@ +server->addPlugin($locksPlugin); + $this->locksPlugin = $locksPlugin; + + } + + function testNoConditions() { + + $serverVars = array( + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + $this->assertEquals(array(),$conditions); + + } + + function testLockToken() { + + $serverVars = array( + 'HTTP_IF' => '()', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => '', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + '', + ), + ), + + ), + + ); + + $this->assertEquals($compare,$conditions); + + } + + function testNotLockToken() { + + $serverVars = array( + 'HTTP_IF' => '(Not )', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => '', + 'tokens' => array( + array( + 0, + 'opaquelocktoken:token1', + '', + ), + ), + + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function testLockTokenUrl() { + + $serverVars = array( + 'HTTP_IF' => ' ()', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => 'http://www.example.com/', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + '', + ), + ), + + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function test2LockTokens() { + + $serverVars = array( + 'HTTP_IF' => '() (Not )', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => '', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + '', + ), + array( + 0, + 'opaquelocktoken:token2', + '', + ), + ), + + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function test2UriLockTokens() { + + $serverVars = array( + 'HTTP_IF' => ' () (Not )', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => 'http://www.example.org/node1', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + '', + ), + ), + ), + array( + 'uri' => 'http://www.example.org/node2', + 'tokens' => array( + array( + 0, + 'opaquelocktoken:token2', + '', + ), + ), + + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function test2UriMultiLockTokens() { + + $serverVars = array( + 'HTTP_IF' => ' () () (Not )', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => 'http://www.example.org/node1', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + '', + ), + array( + 1, + 'opaquelocktoken:token2', + '', + ), + ), + ), + array( + 'uri' => 'http://www.example.org/node2', + 'tokens' => array( + array( + 0, + 'opaquelocktoken:token3', + '', + ), + ), + + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function testEtag() { + + $serverVars = array( + 'HTTP_IF' => '([etag1])', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => '', + 'tokens' => array( + array( + 1, + '', + 'etag1', + ), + ), + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function test2Etags() { + + $serverVars = array( + 'HTTP_IF' => ' ([etag1]) ([etag2])', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => 'http://www.example.org/', + 'tokens' => array( + array( + 1, + '', + 'etag1', + ), + array( + 1, + '', + 'etag2', + ), + ), + ), + + ); + $this->assertEquals($compare,$conditions); + + } + + function testComplexIf() { + + $serverVars = array( + 'HTTP_IF' => ' ( [etag1]) ' . + '(Not ) ([etag2]) ' . + '() (Not ) ([etag3])', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + + $conditions = $this->locksPlugin->getIfConditions(); + + $compare = array( + + array( + 'uri' => 'http://www.example.org/node1', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token1', + 'etag1', + ), + array( + 0, + 'opaquelocktoken:token2', + '', + ), + array( + 1, + '', + 'etag2', + ), + ), + ), + array( + 'uri' => 'http://www.example.org/node2', + 'tokens' => array( + array( + 1, + 'opaquelocktoken:token3', + '', + ), + array( + 0, + 'opaquelocktoken:token4', + '', + ), + array( + 1, + '', + 'etag3', + ), + ), + ), + + ); + $this->assertEquals($compare,$conditions); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php new file mode 100644 index 00000000..b3d7d447 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/MSWordTest.php @@ -0,0 +1,123 @@ +debugExceptions = true; + $locksBackend = new Backend\File(SABRE_TEMPDIR . '/locksdb'); + $locksPlugin = new Plugin($locksBackend); + $server->addPlugin($locksPlugin); + + $response1 = new HTTP\ResponseMock(); + + $server->httpRequest = $this->getLockRequest(); + $server->httpResponse = $response1; + $server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created', $server->httpResponse->status); + $this->assertTrue(isset($server->httpResponse->headers['Lock-Token'])); + $lockToken = $server->httpResponse->headers['Lock-Token']; + + //sleep(10); + + $response2 = new HTTP\ResponseMock(); + + $server->httpRequest = $this->getLockRequest2(); + $server->httpResponse = $response2; + $server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created', $server->httpResponse->status); + $this->assertTrue(isset($server->httpResponse->headers['Lock-Token'])); + + //sleep(10); + + $response3 = new HTTP\ResponseMock(); + $server->httpRequest = $this->getPutRequest($lockToken); + $server->httpResponse = $response3; + $server->exec(); + + $this->assertEquals('HTTP/1.1 204 No Content', $server->httpResponse->status); + + } + + function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function getLockRequest() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'HTTP_TIMEOUT' => 'Second-3600', + 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + )); + + $request->setBody(' + + + + + + + + PC-Vista\User + +'); + + return $request; + + } + function getLockRequest2() { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_CONTENT_TYPE' => 'application/xml', + 'HTTP_TIMEOUT' => 'Second-3600', + 'REQUEST_URI' => '/~$Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + )); + + $request->setBody(' + + + + + + + + PC-Vista\User + +'); + + return $request; + + } + + function getPutRequest($lockToken) { + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/Nouveau%20Microsoft%20Office%20Excel%20Worksheet.xlsx', + 'HTTP_IF' => 'If: ('.$lockToken.')', + )); + $request->setBody('FAKE BODY'); + return $request; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php new file mode 100644 index 00000000..caa1d011 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Locks/PluginTest.php @@ -0,0 +1,982 @@ +server->addPlugin($locksPlugin); + $this->locksPlugin = $locksPlugin; + + } + + function testGetFeatures() { + + $this->assertEquals(array(2),$this->locksPlugin->getFeatures()); + + } + + function testGetHTTPMethods() { + + $this->assertEquals(array('LOCK','UNLOCK'),$this->locksPlugin->getHTTPMethods('')); + + } + + function testGetHTTPMethodsNoBackend() { + + $locksPlugin = new Plugin(); + $this->server->addPlugin($locksPlugin); + $this->assertEquals(array(),$locksPlugin->getHTTPMethods('')); + + } + + function testUnknownMethodPassthough() { + + $this->assertNull($this->locksPlugin->unknownMethod('BLA','/')); + + } + + function testLockNoBody() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status); + + } + + function testLock() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status,'Got an incorrect status back. Response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + $elements = array( + '/d:prop', + '/d:prop/d:lockdiscovery', + '/d:prop/d:lockdiscovery/d:activelock', + '/d:prop/d:lockdiscovery/d:activelock/d:locktype', + '/d:prop/d:lockdiscovery/d:activelock/d:lockroot', + '/d:prop/d:lockdiscovery/d:activelock/d:lockroot/d:href', + '/d:prop/d:lockdiscovery/d:activelock/d:locktype/d:write', + '/d:prop/d:lockdiscovery/d:activelock/d:lockscope', + '/d:prop/d:lockdiscovery/d:activelock/d:lockscope/d:exclusive', + '/d:prop/d:lockdiscovery/d:activelock/d:depth', + '/d:prop/d:lockdiscovery/d:activelock/d:owner', + '/d:prop/d:lockdiscovery/d:activelock/d:timeout', + '/d:prop/d:lockdiscovery/d:activelock/d:locktoken', + '/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href', + ); + + foreach($elements as $elem) { + $data = $xml->xpath($elem); + $this->assertEquals(1,count($data),'We expected 1 match for the xpath expression "' . $elem . '". ' . count($data) . ' were found. Full response body: ' . $this->response->body); + } + + $depth = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:depth'); + $this->assertEquals('infinity',(string)$depth[0]); + + $token = $xml->xpath('/d:prop/d:lockdiscovery/d:activelock/d:locktoken/d:href'); + $this->assertEquals($this->response->headers['Lock-Token'],'<' . (string)$token[0] . '>','Token in response body didn\'t match token in response header.'); + + } + + /** + * @depends testLock + */ + function testDoubleLock() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status); + + } + + /** + * @depends testLock + */ + function testLockRefresh() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $lockToken = $this->response->headers['Lock-Token']; + + $this->response = new HTTP\ResponseMock(); + $this->server->httpResponse = $this->response; + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_IF' => '(' . $lockToken . ')', + ); + $request = new HTTP\Request($serverVars); + $request->setBody(''); + $this->server->httpRequest = $request; + + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status,'We received an incorrect status code. Full response body: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockNoFile() { + + $serverVars = array( + 'REQUEST_URI' => '/notfound.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlockNoToken() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'UNLOCK', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlockBadToken() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'UNLOCK', + 'HTTP_LOCK_TOKEN' => '', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 409 Conflict',$this->response->status,'Got an incorrect status code. Full response body: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockPutNoToken() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status); + + } + + /** + * @depends testLock + */ + function testUnlock() { + + $request = new HTTP\Request(array()); + $this->server->httpRequest = $request; + + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->invokeMethod('LOCK','test.txt'); + $lockToken = $this->server->httpResponse->headers['Lock-Token']; + + $serverVars = array( + 'HTTP_LOCK_TOKEN' => $lockToken, + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->invokeMethod('UNLOCK', 'test.txt'); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->server->httpResponse->status,'Got an incorrect status code. Full response body: ' . $this->response->body); + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->server->httpResponse->headers + ); + + + } + + /** + * @depends testLock + */ + function testUnlockWindowsBug() { + + $request = new HTTP\Request(array()); + $this->server->httpRequest = $request; + + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->invokeMethod('LOCK','test.txt'); + $lockToken = $this->server->httpResponse->headers['Lock-Token']; + + // See Issue 123 + $lockToken = trim($lockToken,'<>'); + + $serverVars = array( + 'HTTP_LOCK_TOKEN' => $lockToken, + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->invokeMethod('UNLOCK', 'test.txt'); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->server->httpResponse->status,'Got an incorrect status code. Full response body: ' . $this->response->body); + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->server->httpResponse->headers + ); + + + } + + /** + * @depends testLock + */ + function testLockRetainOwner() { + + $request = new HTTP\Request(array()); + $this->server->httpRequest = $request; + + $request->setBody(' + + + + Evert +'); + + $this->server->invokeMethod('LOCK','test.txt'); + $lockToken = $this->server->httpResponse->headers['Lock-Token']; + + $locks = $this->locksPlugin->getLocks('test.txt'); + $this->assertEquals(1,count($locks)); + $this->assertEquals('Evert',$locks[0]->owner); + + + } + + /** + * @depends testLock + */ + function testLockPutBadToken() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '()', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + + } + + /** + * @depends testLock + */ + function testLockDeleteParent() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'DELETE', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + /** + * @depends testLock + */ + function testLockDeleteSucceed() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF' => '(' . $this->response->headers['Lock-Token'] . ')', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + + /** + * @depends testLock + */ + function testLockCopyLockSource() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + /** + * @depends testLock + */ + function testLockCopyLockDestination() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child2.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status,'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + + /** + * @depends testLock + */ + function testLockMoveLockSourceLocked() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status,'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + + /** + * @depends testLock + */ + function testLockMoveLockSourceSucceed() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + 'HTTP_IF' => '(' . $this->response->headers['Lock-Token'] . ')', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'A valid lock-token was provided for the source, so this MOVE operation must succeed. Full response body: ' . $this->response->body); + + } + + /** + * @depends testLock + */ + function testLockMoveLockDestination() { + + $serverVars = array( + 'REQUEST_URI' => '/dir/child2.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 423 Locked',$this->response->status,'Copy must succeed if only the source is locked, but not the destination'); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + /** + * @depends testLock + */ + function testLockMoveLockParent() { + + $serverVars = array( + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'LOCK', + 'HTTP_DEPTH' => 'infinite', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/dir/child.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/dir/child2.txt', + 'HTTP_IF' => ' (' . $this->response->headers['Lock-Token'] . ')', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'We locked the parent of both the source and destination, but the move didn\'t succeed.'); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + + } + + /** + * @depends testLock + */ + function testLockPutGoodToken() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '('.$this->response->headers['Lock-Token'].')', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + + } + + function testPutWithIncorrectETag() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(["etag1"])', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + + } + + /** + * @depends testPutWithIncorrectETag + */ + function testPutWithCorrectETag() { + + // We need an etag-enabled file node. + $tree = new DAV\ObjectTree(new DAV\FSExt\Directory(SABRE_TEMPDIR)); + $this->server->tree = $tree; + + $etag = md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')); + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF' => '(["'.$etag.'"])', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status, 'Incorrect status received. Full response body:' . $this->response->body); + + } + + function testDeleteWithETagOnCollection() { + + $serverVars = array( + 'REQUEST_URI' => '/dir', + 'REQUEST_METHOD' => 'DELETE', + 'HTTP_IF' => '(["etag1"])', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('newbody'); + $this->server->httpRequest = $request; + $this->server->exec(); + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + + } + + function testGetTimeoutHeader() { + + $request = new HTTP\Request(array( + 'HTTP_TIMEOUT' => 'second-100', + )); + + $this->server->httpRequest = $request; + $this->assertEquals(100, $this->locksPlugin->getTimeoutHeader()); + + } + + + function testGetTimeoutHeaderNotSet() { + + $request = new HTTP\Request(array( + )); + + $this->server->httpRequest = $request; + $this->assertEquals(0, $this->locksPlugin->getTimeoutHeader()); + + } + + + function testGetTimeoutHeaderInfinite() { + + $request = new HTTP\Request(array( + 'HTTP_TIMEOUT' => 'infinite', + )); + + $this->server->httpRequest = $request; + $this->assertEquals(LockInfo::TIMEOUT_INFINITE, $this->locksPlugin->getTimeoutHeader()); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testGetTimeoutHeaderInvalid() { + + $request = new HTTP\Request(array( + 'HTTP_TIMEOUT' => 'yourmom', + )); + + $this->server->httpRequest = $request; + $this->locksPlugin->getTimeoutHeader(); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php new file mode 100644 index 00000000..b2613ec9 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/Collection.php @@ -0,0 +1,164 @@ +name = $name; + $this->children = $children; + $this->parent = $parent; + + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + public function getName() { + + return $this->name; + + } + + /** + * Creates a new file in the directory + * + * Data will either be supplied as a stream resource, or in certain cases + * as a string. Keep in mind that you may have to support either. + * + * After successful creation of the file, you may choose to return the ETag + * of the new file here. + * + * The returned ETag must be surrounded by double-quotes (The quotes should + * be part of the actual string). + * + * If you cannot accurately determine the ETag, you should not return it. + * If you don't store the file exactly as-is (you're transforming it + * somehow) you should also not return an ETag. + * + * This means that if a subsequent GET to this new file does not exactly + * return the same contents of what was submitted here, you are strongly + * recommended to omit the ETag. + * + * @param string $name Name of the file + * @param resource|string $data Initial payload + * @return null|string + */ + public function createFile($name, $data = null) { + + if (is_resource($data)) { + $data = stream_get_contents($data); + } + $this->children[$name] = $data; + return '"' . md5($data) . '"'; + + } + + /** + * Creates a new subdirectory + * + * @param string $name + * @return void + */ + public function createDirectory($name) { + + $this->children[$name] = array(); + + } + + /** + * Returns an array with all the child nodes + * + * @return \Sabre\DAV\INode[] + */ + public function getChildren() { + + $result = array(); + foreach($this->children as $key=>$value) { + + if ($value instanceof DAV\INode) { + $result[] = $value; + } elseif (is_array($value)) { + $result[] = new Collection($key, $value, $this); + } else { + $result[] = new File($key, $value, $this); + } + + } + + return $result; + + } + + /** + * Removes a childnode from this node. + * + * @param string $name + * @return void + */ + public function deleteChild($name) { + + foreach($this->children as $key=>$value) { + + if ($value instanceof DAV\INode) { + if ($value->getName() == $name) { + unset($this->children[$key]); + return; + } + } elseif ($key === $name) { + unset($this->children[$key]); + return; + } + + } + + } + + /** + * Deletes this collection and all its children,. + * + * @return void + */ + public function delete() { + + foreach($this->getChildren() as $child) { + $this->deleteChild($child->getName()); + } + $this->parent->deleteChild($this->getName()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php new file mode 100644 index 00000000..2b25bbb8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mock/File.php @@ -0,0 +1,130 @@ +name = $name; + $this->put($contents); + $this->parent = $parent; + + } + + /** + * Returns the name of the node. + * + * This is used to generate the url. + * + * @return string + */ + public function getName() { + + return $this->name; + + } + + /** + * Updates the data + * + * The data argument is a readable stream resource. + * + * After a succesful put operation, you may choose to return an ETag. The + * etag must always be surrounded by double-quotes. These quotes must + * appear in the actual string you're returning. + * + * Clients may use the ETag from a PUT request to later on make sure that + * when they update the file, the contents haven't changed in the mean + * time. + * + * If you don't plan to store the file byte-by-byte, and you return a + * different object on a subsequent GET you are strongly recommended to not + * return an ETag, and just return null. + * + * @param resource $data + * @return string|null + */ + public function put($data) { + + if (is_resource($data)) { + $data = stream_get_contents($data); + } + $this->contents = $data; + return '"' . md5($data) . '"'; + + } + + /** + * Returns the data + * + * This method may either return a string or a readable stream resource + * + * @return mixed + */ + public function get() { + + return $this->contents; + + } + + /** + * Returns the ETag for a file + * + * An ETag is a unique identifier representing the current version of the file. If the file changes, the ETag MUST change. + * + * Return null if the ETag can not effectively be determined + * + * @return void + */ + public function getETag() { + + return '"' . md5($this->contents) . '"'; + + } + + /** + * Returns the size of the node, in bytes + * + * @return int + */ + public function getSize() { + + return strlen($this->contents); + + } + + /** + * Delete the node + * + * @return void + */ + public function delete() { + + $this->parent->deleteChild($this->name); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php new file mode 100644 index 00000000..e818fe04 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Mount/PluginTest.php @@ -0,0 +1,58 @@ +server->addPlugin(new Plugin()); + + } + + function testPassThrough() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 501 Not Implemented',$this->response->status,'We expected GET to not be implemented for Directories. Response body: ' . $this->response->body); + + } + + function testMountResponse() { + + $serverVars = array( + 'REQUEST_URI' => '/?mount', + 'REQUEST_METHOD' => 'GET', + 'QUERY_STRING' => 'mount', + 'HTTP_HOST' => 'example.org', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + $xml = simplexml_load_string($this->response->body); + $this->assertTrue($xml==true,'Response was not a valid xml document'); + + $xml->registerXPathNamespace('dm','http://purl.org/NET/webdav/mount'); + $url = $xml->xpath('//dm:url'); + $this->assertEquals('http://example.org/',(string)$url[0]); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php new file mode 100644 index 00000000..330058b6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ObjectTreeTest.php @@ -0,0 +1,100 @@ +tree = new ObjectTree($rootNode); + + } + + function teardown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + function testGetRootNode() { + + $root = $this->tree->getNodeForPath(''); + $this->assertInstanceOf('Sabre\\DAV\\FSExt\\Directory',$root); + + } + + function testGetSubDir() { + + $root = $this->tree->getNodeForPath('subdir'); + $this->assertInstanceOf('Sabre\\DAV\\FSExt\\Directory',$root); + + } + + function testCopyFile() { + + $this->tree->copy('file.txt','file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/file2.txt')); + $this->assertEquals('contents',file_get_contents(SABRE_TEMPDIR.'/root/file2.txt')); + + } + + /** + * @depends testCopyFile + */ + function testCopyDirectory() { + + $this->tree->copy('subdir','subdir2'); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/subdir2')); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/subdir2/subfile.txt')); + $this->assertEquals('subcontents',file_get_contents(SABRE_TEMPDIR.'/root/subdir2/subfile.txt')); + + } + + /** + * @depends testCopyFile + */ + function testMoveFile() { + + $this->tree->move('file.txt','file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/file2.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR.'/root/file.txt')); + $this->assertEquals('contents',file_get_contents(SABRE_TEMPDIR.'/root/file2.txt')); + + } + + /** + * @depends testMoveFile + */ + function testMoveFileNewParent() { + + $this->tree->move('file.txt','subdir/file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/subdir/file2.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR.'/root/file.txt')); + $this->assertEquals('contents',file_get_contents(SABRE_TEMPDIR.'/root/subdir/file2.txt')); + + } + + /** + * @depends testCopyDirectory + */ + function testMoveDirectory() { + + $this->tree->move('subdir','subdir2'); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/subdir2')); + $this->assertTrue(file_exists(SABRE_TEMPDIR.'/root/subdir2/subfile.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR.'/root/subdir')); + $this->assertEquals('subcontents',file_get_contents(SABRE_TEMPDIR.'/root/subdir2/subfile.txt')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php new file mode 100644 index 00000000..e8cdc166 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/FileMock.php @@ -0,0 +1,79 @@ +data = $str; + + } + + function putRange($str,$start) { + + if (is_resource($str)) { + $str = stream_get_contents($str); + } + $this->data = substr($this->data, 0, $start) . $str . substr($this->data, $start + strlen($str)); + + + + } + + function get() { + + return $this->data; + + } + + function getContentType() { + + return 'text/plain'; + + } + + function getSize() { + + return strlen($this->data); + + } + + function getETag() { + + return '"' . $this->data . '"'; + + } + + function delete() { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + function setName($name) { + + throw new DAV\Exception\MethodNotAllowed(); + + } + + function getName() { + + return 'partial'; + + } + + function getLastModified() { + + return null; + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php new file mode 100644 index 00000000..32f7e4e2 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/PluginTest.php @@ -0,0 +1,150 @@ +node = new FileMock(); + $this->tree[] = $this->node; + + parent::setUp(); + + $this->plugin = new Plugin(); + $this->server->addPlugin($this->plugin); + + + + } + + public function testInit() { + + $this->assertEquals('partialupdate', $this->plugin->getPluginName()); + $this->assertEquals(array('sabredav-partialupdate'), $this->plugin->getFeatures()); + $this->assertEquals(array( + 'PATCH' + ), $this->plugin->getHTTPMethods('partial')); + $this->assertEquals(array( + ), $this->plugin->getHTTPMethods('')); + + $this->assertNull($this->plugin->unknownMethod('FOO','partial')); + + } + + public function testPatchNoRange() { + + $this->node->put('00000000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + )); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 400 Bad request', $response->status, 'Full response body:' . $response->body); + + } + + public function testPatchNotSupported() { + + $this->node->put('00000000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/', + 'X_UPDATE_RANGE' => '3-4', + + )); + $request->setBody( + '111' + ); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 405 Method Not Allowed', $response->status, 'Full response body:' . $response->body); + + } + + public function testPatchNoContentType() { + + $this->node->put('00000000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + 'HTTP_X_UPDATE_RANGE' => 'bytes=3-4', + + )); + $request->setBody( + '111' + ); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type', $response->status, 'Full response body:' . $response->body); + + } + + public function testPatchBadRange() { + + $this->node->put('00000000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + 'HTTP_X_UPDATE_RANGE' => 'bytes=3-4', + 'HTTP_CONTENT_TYPE' => 'application/x-sabredav-partialupdate', + )); + $request->setBody( + '111' + ); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 411 Length Required', $response->status, 'Full response body:' . $response->body); + + } + + public function testPatchSuccess() { + + $this->node->put('00000000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + 'HTTP_X_UPDATE_RANGE' => 'bytes=3-5', + 'HTTP_CONTENT_TYPE' => 'application/x-sabredav-partialupdate', + 'HTTP_CONTENT_LENGTH' => 3, + )); + $request->setBody( + '111' + ); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status, 'Full response body:' . $response->body); + $this->assertEquals('00011100', $this->node->get()); + + } + + public function testPatchNoEndRange() { + + $this->node->put('00000'); + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PATCH', + 'REQUEST_URI' => '/partial', + 'HTTP_X_UPDATE_RANGE' => 'bytes=3-', + 'HTTP_CONTENT_TYPE' => 'application/x-sabredav-partialupdate', + 'HTTP_CONTENT_LENGTH' => 3, + )); + $request->setBody( + '111' + ); + $response = $this->request($request); + + $this->assertEquals('HTTP/1.1 204 No Content', $response->status, 'Full response body:' . $response->body); + $this->assertEquals('00111', $this->node->get()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php new file mode 100644 index 00000000..7abe69c5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/PartialUpdate/SpecificationTest.php @@ -0,0 +1,89 @@ +debugExceptions = true; + $server->addPlugin(new Plugin()); + + $tree[0]->put('1234567890'); + + $this->server = $server; + + } + + public function tearDown() { + + \Sabre\TestUtil::clearTempDir(); + + } + + /** + * @dataProvider data + */ + public function testUpdateRange($headerValue, $httpStatus, $endResult, $contentLength = 4) { + + $vars = array( + 'REQUEST_METHOD' => 'PATCH', + 'HTTP_CONTENT_TYPE' => 'application/x-sabredav-partialupdate', + 'HTTP_X_UPDATE_RANGE' => $headerValue, + 'REQUEST_URI' => '/foobar.txt', + ); + if ($contentLength) { + $vars['HTTP_CONTENT_LENGTH'] = (string)$contentLength; + } + + $request = new HTTP\Request($vars); + + $request->setBody('----'); + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->exec(); + + $this->assertEquals($httpStatus, $this->server->httpResponse->status, 'Incorrect http status received: ' . $this->server->httpResponse->body); + if (!is_null($endResult)) { + $this->assertEquals($endResult, file_get_contents(SABRE_TEMPDIR . '/foobar.txt')); + } + + } + + public function data() { + + return array( + // Problems + array('foo', 'HTTP/1.1 400 Bad request', null), + array('bytes=0-3', 'HTTP/1.1 411 Length Required', null, 0), + array('bytes=4-1', 'HTTP/1.1 416 Requested Range Not Satisfiable', null), + + array('bytes=0-3', 'HTTP/1.1 204 No Content', '----567890'), + array('bytes=1-4', 'HTTP/1.1 204 No Content', '1----67890'), + array('bytes=0-', 'HTTP/1.1 204 No Content', '----567890'), + array('bytes=-4', 'HTTP/1.1 204 No Content', '123456----'), + array('bytes=-2', 'HTTP/1.1 204 No Content', '12345678----'), + array('bytes=2-', 'HTTP/1.1 204 No Content', '12----7890'), + array('append', 'HTTP/1.1 204 No Content', '1234567890----'), + + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/GetLastModifiedTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/GetLastModifiedTest.php new file mode 100644 index 00000000..de8ca128 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/GetLastModifiedTest.php @@ -0,0 +1,75 @@ +assertEquals($dt->format(\DateTime::ATOM), $lastMod->getTime()->format(\DateTime::ATOM)); + + } + + function testConstructString() { + + $dt = new \DateTime('2010-03-14 16:35', new \DateTimeZone('UTC')); + $lastMod = new GetLastModified('2010-03-14 16:35'); + $this->assertEquals($dt->format(\DateTime::ATOM), $lastMod->getTime()->format(\DateTime::ATOM)); + + } + + function testConstructInt() { + + $dt = new \DateTime('2010-03-14 16:35', new \DateTimeZone('UTC')); + $lastMod = new GetLastModified((int)$dt->format('U')); + $this->assertEquals($dt->format(\DateTime::ATOM), $lastMod->getTime()->format(\DateTime::ATOM)); + + } + + function testSerialize() { + + $dt = new \DateTime('2010-03-14 16:35', new \DateTimeZone('UTC')); + $lastMod = new GetLastModified($dt); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:getlastmodified'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $lastMod->serialize($server, $root); + + $xml = $doc->saveXML(); + + /* + $this->assertEquals( +' +' . +HTTP\Util::toHTTPDate($dt) . +' +', $xml); + */ + $this->assertEquals( +' +' . +HTTP\Util::toHTTPDate($dt) . +' +', $xml); + + $ok = false; + try { + GetLastModified::unserialize(DAV\XMLUtil::loadDOMDocument($xml)->firstChild); + } catch (DAV\Exception $e) { + $ok = true; + } + if (!$ok) $this->markTestFailed('Unserialize should not be supported'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefListTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefListTest.php new file mode 100644 index 00000000..fe2bc81f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefListTest.php @@ -0,0 +1,91 @@ +assertEquals(array('foo','bar'),$href->getHrefs()); + + } + + function testSerialize() { + + $href = new HrefList(array('foo','bar')); + $this->assertEquals(array('foo','bar'),$href->getHrefs()); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $server->setBaseUri('/bla/'); + + $href->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +/bla/foo/bla/bar +', $xml); + + } + + function testSerializeNoPrefix() { + + $href = new HrefList(array('foo','bar'), false); + $this->assertEquals(array('foo','bar'),$href->getHrefs()); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $server->setBaseUri('/bla/'); + + $href->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +foobar +', $xml); + + } + + function testUnserialize() { + + $xml = ' +/bla/foo/bla/bar +'; + + $dom = new \DOMDocument(); + $dom->loadXML($xml); + + $href = HrefList::unserialize($dom->firstChild); + $this->assertEquals(array('/bla/foo','/bla/bar'),$href->getHrefs()); + + } + + function testUnserializeIncompatible() { + + $xml = ' +/bla/foo +'; + + $dom = new \DOMDocument(); + $dom->loadXML($xml); + + $href = HrefList::unserialize($dom->firstChild); + $this->assertEquals(array(), $href->getHrefs()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefTest.php new file mode 100644 index 00000000..e5607f51 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/HrefTest.php @@ -0,0 +1,119 @@ +assertEquals('path',$href->getHref()); + + } + + function testSerialize() { + + $href = new Href('path'); + $this->assertEquals('path',$href->getHref()); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $server->setBaseUri('/bla/'); + + $href->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +/bla/path +', $xml); + + } + + function testSerializeNoPrefix() { + + $href = new Href('path',false); + $this->assertEquals('path',$href->getHref()); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $server->setBaseUri('/bla/'); + + $href->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +path +', $xml); + + } + + function testUnserialize() { + + $xml = ' +/bla/path +'; + + $dom = new \DOMDocument(); + $dom->loadXML($xml); + + $href = Href::unserialize($dom->firstChild); + $this->assertEquals('/bla/path',$href->getHref()); + + } + + function testUnserializeIncompatible() { + + $xml = ' +/bla/path +'; + + $dom = new \DOMDocument(); + $dom->loadXML($xml); + + $href = Href::unserialize($dom->firstChild); + $this->assertNull($href); + + } + + /** + * This method tests if hrefs containing & are correctly encoded. + */ + function testSerializeEntity() { + + $href = new Href('http://example.org/?a&b', false); + $this->assertEquals('http://example.org/?a&b',$href->getHref()); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $server->setBaseUri('/bla/'); + + $href->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +http://example.org/?a&b +', $xml); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResourceTypeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResourceTypeTest.php new file mode 100644 index 00000000..8a579bae --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResourceTypeTest.php @@ -0,0 +1,111 @@ +assertEquals(array('{DAV:}collection'),$resourceType->getValue()); + + $resourceType = new ResourceType(DAV\Server::NODE_FILE); + $this->assertEquals(array(),$resourceType->getValue()); + + $resourceType = new ResourceType(DAV\Server::NODE_DIRECTORY); + $this->assertEquals(array('{DAV:}collection'),$resourceType->getValue()); + + $resourceType = new ResourceType('{DAV:}principal'); + $this->assertEquals(array('{DAV:}principal'),$resourceType->getValue()); + + } + + /** + * @depends testConstruct + */ + function testSerialize() { + + $resourceType = new ResourceType(array('{DAV:}collection','{DAV:}principal')); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $resourceType->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' + +', $xml); + + } + + /** + * @depends testSerialize + */ + function testSerializeCustomNS() { + + $resourceType = new ResourceType(array('{http://example.org/NS}article')); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:anything'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + $resourceType->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' + +', $xml); + + } + + /** + * @depends testConstruct + */ + function testIs() { + + $resourceType = new ResourceType(array('{DAV:}collection','{DAV:}principal')); + $this->assertTrue($resourceType->is('{DAV:}collection')); + $this->assertFalse($resourceType->is('{DAV:}blabla')); + + } + + /** + * @depends testConstruct + */ + function testAdd() { + + $resourceType = new ResourceType(array('{DAV:}collection','{DAV:}principal')); + $resourceType->add('{DAV:}foo'); + $this->assertEquals(array('{DAV:}collection','{DAV:}principal','{DAV:}foo'), $resourceType->getValue()); + + } + + /** + * @depends testConstruct + */ + function testUnserialize() { + + $xml =' + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $resourceType = ResourceType::unserialize($dom->firstChild); + $this->assertEquals(array('{DAV:}collection','{DAV:}principal'),$resourceType->getValue()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResponseListTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResponseListTest.php new file mode 100644 index 00000000..d13066b8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/ResponseListTest.php @@ -0,0 +1,19 @@ + array( + '{DAV:}displayname' => 'my file', + ), + 404 => array( + '{DAV:}owner' => null, + ) + ); + + $property = new Response('uri',$innerProps); + + $this->assertEquals('uri',$property->getHref()); + $this->assertEquals($innerProps,$property->getResponseProperties()); + + + } + + /** + * @depends testSimple + */ + function testSerialize() { + + $innerProps = array( + 200 => array( + '{DAV:}displayname' => 'my file', + ), + 404 => array( + '{DAV:}owner' => null, + ) + ); + + $property = new Response('uri',$innerProps); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'/uri' . +'' . +'' . +'my file' . +'' . +'HTTP/1.1 200 OK' . +'' . +'' . +'' . +'' . +'' . +'HTTP/1.1 404 Not Found' . +'' . +'' . +' +', $xml); + + } + + /** + * This one is specifically for testing properties with no namespaces, which is legal xml + * + * @depends testSerialize + */ + function testSerializeEmptyNamespace() { + + $innerProps = array( + 200 => array( + '{}propertyname' => 'value', + ), + ); + + $property = new Response('uri',$innerProps); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'/uri' . +'' . +'' . +'value' . +'' . +'HTTP/1.1 200 OK' . +'' . +'' . +' +', $xml); + + } + + /** + * This one is specifically for testing properties with no namespaces, which is legal xml + * + * @depends testSerialize + */ + function testSerializeCustomNamespace() { + + $innerProps = array( + 200 => array( + '{http://sabredav.org/NS/example}propertyname' => 'value', + ), + ); + + $property = new Response('uri',$innerProps); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'/uri' . +'' . +'' . +'value' . +'' . +'HTTP/1.1 200 OK' . +'' . +'' . +' +', $xml); + + } + + /** + * @depends testSerialize + */ + function testSerializeComplexProperty() { + + $innerProps = array( + 200 => array( + '{DAV:}link' => new Href('http://sabredav.org/', false) + ), + ); + + $property = new Response('uri',$innerProps); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'/uri' . +'' . +'' . +'http://sabredav.org/' . +'' . +'HTTP/1.1 200 OK' . +'' . +'' . +' +', $xml); + + } + + /** + * @depends testSerialize + * @expectedException Sabre\DAV\Exception + */ + function testSerializeBreak() { + + $innerProps = array( + 200 => array( + '{DAV:}link' => new \STDClass() + ), + ); + + $property = new Response('uri',$innerProps); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $server = new DAV\Server(); + + $property->serialize($server, $root); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/SupportedReportSetTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/SupportedReportSetTest.php new file mode 100644 index 00000000..445e22ab --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Property/SupportedReportSetTest.php @@ -0,0 +1,128 @@ + '/', + 'REQUEST_METHOD' => 'PROPFIND', + 'HTTP_DEPTH' => '0', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($body); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + } + + /** + * @covers Sabre\DAV\Property\SupportedReportSet + */ + function testNoReports() { + + $xml = ' + + + + +'; + + $this->sendPROPFIND($xml); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We expected a multi-status response. Full response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop'); + $this->assertEquals(1,count($data),'We expected 1 \'d:prop\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set'); + $this->assertEquals(1,count($data),'We expected 1 \'d:supported-report-set\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1,count($data),'We expected 1 \'d:status\' element'); + + $this->assertEquals('HTTP/1.1 200 OK',(string)$data[0],'The status for this property should have been 200'); + + } + + /** + * @covers Sabre\DAV\Property\SupportedReportSet + * @depends testNoReports + */ + function testCustomReport() { + + // Intercepting the report property + $this->server->subscribeEvent('afterGetProperties',array($this,'addProp')); + + $xml = ' + + + + +'; + + $this->sendPROPFIND($xml); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We expected a multi-status response. Full response body: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('x','http://www.rooftopsolutions.nl/testnamespace'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop'); + $this->assertEquals(1,count($data),'We expected 1 \'d:prop\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set'); + $this->assertEquals(1,count($data),'We expected 1 \'d:supported-report-set\' element'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report'); + $this->assertEquals(2,count($data),'We expected 2 \'d:supported-report\' elements'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report'); + $this->assertEquals(2,count($data),'We expected 2 \'d:report\' elements'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report/x:myreport'); + $this->assertEquals(1,count($data),'We expected 1 \'x:myreport\' element. Full body: ' . $this->response->body); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supported-report-set/d:supported-report/d:report/d:anotherreport'); + $this->assertEquals(1,count($data),'We expected 1 \'d:anotherreport\' element. Full body: ' . $this->response->body); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1,count($data),'We expected 1 \'d:status\' element'); + + $this->assertEquals('HTTP/1.1 200 OK',(string)$data[0],'The status for this property should have been 200'); + + } + + /** + * This method is used as a callback for afterGetProperties + */ + function addProp($path, &$properties) { + + if (isset($properties[200]['{DAV:}supported-report-set'])) { + $properties[200]['{DAV:}supported-report-set']->addReport('{http://www.rooftopsolutions.nl/testnamespace}myreport'); + $properties[200]['{DAV:}supported-report-set']->addReport('{DAV:}anotherreport'); + } + + } + + + +} + +?> diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerCopyMoveTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerCopyMoveTest.php new file mode 100644 index 00000000..88e107c1 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerCopyMoveTest.php @@ -0,0 +1,268 @@ +response = new HTTP\ResponseMock(); + $dir = new FS\Directory(SABRE_TEMPDIR); + $tree = new ObjectTree($dir); + $this->server = new Server($tree); + $this->server->debugExceptions = true; + $this->server->httpResponse = $this->response; + file_put_contents(SABRE_TEMPDIR . '/test.txt', 'Test contents'); + file_put_contents(SABRE_TEMPDIR . '/test2.txt', 'Test contents2'); + mkdir(SABRE_TEMPDIR . '/col'); + file_put_contents(SABRE_TEMPDIR . 'col/test.txt', 'Test contents'); + + } + + function tearDown() { + + $cleanUp = array('test.txt','testput.txt','testcol','test2.txt','test3.txt','col/test.txt','col','col2/test.txt','col2'); + foreach($cleanUp as $file) { + $tmpFile = SABRE_TEMPDIR . '/' . $file; + if (file_exists($tmpFile)) { + + if (is_dir($tmpFile)) { + rmdir($tmpFile); + } else { + unlink($tmpFile); + } + + } + } + + } + + + function testCopyOverWrite() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/test2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status,'Received an incorrect HTTP status. Full body inspection: ' . $this->response->body); + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->response->headers + ); + + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR. '/test2.txt')); + + } + + function testCopyToSelf() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/test.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden',$this->response->status,'Received an incorrect HTTP status. Full body inspection: ' . $this->response->body); + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR. '/test.txt')); + + } + + function testMoveToSelf() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/test.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden',$this->response->status,'Received an incorrect HTTP status. Full body inspection: ' . $this->response->body); + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR. '/test.txt')); + + } + + function testMoveOverWrite() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'MOVE', + 'HTTP_DESTINATION' => '/test2.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => 0, + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status); + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR . '/test2.txt')); + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/test.txt'),'The sourcefile test.txt should no longer exist at this point'); + + } + + function testBlockedOverWrite() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/test2.txt', + 'HTTP_OVERWRITE' => 'F', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + $this->assertEquals('Test contents2',file_get_contents(SABRE_TEMPDIR . '/test2.txt')); + + + } + + function testNonExistantParent() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/testcol2/test2.txt', + 'HTTP_OVERWRITE' => 'F', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 409 Conflict',$this->response->status); + + } + + function testRandomOverwriteHeader() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/testcol2/test2.txt', + 'HTTP_OVERWRITE' => 'SURE!', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status); + + } + + function testCopyDirectory() { + + $serverVars = array( + 'REQUEST_URI' => '/col', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/col2', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR . '/col2/test.txt')); + + } + + function testSimpleCopyFile() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/test3.txt', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR . '/test3.txt')); + + } + + function testSimpleCopyCollection() { + + $serverVars = array( + 'REQUEST_URI' => '/col', + 'REQUEST_METHOD' => 'COPY', + 'HTTP_DESTINATION' => '/col2', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'Incorrect status received. Full response body: ' . $this->response->body); + + $this->assertEquals(array( + 'Content-Length' => '0', + ), + $this->response->headers + ); + + + $this->assertEquals('Test contents',file_get_contents(SABRE_TEMPDIR . '/col2/test.txt')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php new file mode 100644 index 00000000..2c7a074d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerEventsTest.php @@ -0,0 +1,76 @@ +server->subscribeEvent('afterBind',array($this,'afterBindHandler')); + $newPath = 'afterBind'; + + $this->tempPath = ''; + $this->server->createFile($newPath,'body'); + $this->assertEquals($newPath, $this->tempPath); + + } + + function afterBindHandler($path) { + + $this->tempPath = $path; + + } + + function testBeforeBindCancel() { + + $this->server->subscribeEvent('beforeBind', array($this,'beforeBindCancelHandler')); + $this->assertFalse($this->server->createFile('bla','body')); + + // Also testing put() + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/barbar', + )); + + $this->server->httpRequest = $req; + $this->server->exec(); + + $this->assertEquals('',$this->server->httpResponse->status); + + } + + function beforeBindCancelHandler() { + + return false; + + } + + function testException() { + + $this->server->subscribeEvent('exception', array($this, 'exceptionHandler')); + + $req = new HTTP\Request(array( + 'REQUEST_METHOD' => 'GET', + 'REQUEST_URI' => '/not/exisitng', + )); + $this->server->httpRequest = $req; + $this->server->exec(); + + $this->assertInstanceOf('Sabre\\DAV\\Exception\\NotFound', $this->exception); + + } + + function exceptionHandler(Exception $exception) { + + $this->exception = $exception; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php new file mode 100644 index 00000000..34b084dc --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerMKCOLTest.php @@ -0,0 +1,371 @@ + '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(""); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertTrue(is_dir($this->tempDir . '/testcol')); + + } + + /** + * @depends testMkcol + */ + function testMKCOLUnknownBody() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody("Hello"); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type',$this->response->status); + + } + + /** + * @depends testMkcol + */ + function testMKCOLBrokenXML() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody("Hello"); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status); + + } + + /** + * @depends testMkcol + */ + function testMKCOLUnknownXML() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 415 Unsupported Media Type',$this->response->status); + + } + + /** + * @depends testMkcol + */ + function testMKCOLNoResourceType() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + Evert + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 400 Bad request',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLNoResourceType + */ + function testMKCOLIncorrectResourceType() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 403 Forbidden',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType + */ + function testMKCOLIncorrectResourceType2() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 403 Forbidden',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType2 + */ + function testMKCOLSuccess() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType2 + */ + function testMKCOLWhiteSpaceResourceType() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + + + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Length' => '0', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType2 + */ + function testMKCOLNoParent() { + + $serverVars = array( + 'REQUEST_URI' => '/testnoparent/409me', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 409 Conflict',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType2 + */ + function testMKCOLParentIsNoCollection() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt/409me', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 409 Conflict',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLIncorrectResourceType2 + */ + function testMKCOLAlreadyExists() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'MKCOL', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'Allow' => 'OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 405 Method Not Allowed',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + } + + /** + * @depends testMKCOLSuccess + * @depends testMKCOLAlreadyExists + */ + function testMKCOLAndProps() { + + $serverVars = array( + 'REQUEST_URI' => '/testcol', + 'REQUEST_METHOD' => 'MKCOL', + 'HTTP_CONTENT_TYPE' => 'application/xml', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(' + + + + + my new collection + + +'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Wrong statuscode received. Full response body: ' .$this->response->body); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php new file mode 100644 index 00000000..8f1451b4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPluginTest.php @@ -0,0 +1,98 @@ +server->addPlugin($testPlugin); + $this->testPlugin = $testPlugin; + + } + + /** + * @covers \Sabre\DAV\ServerPlugin + */ + function testBaseClass() { + + $p = new ServerPluginMock(); + $this->assertEquals(array(),$p->getFeatures()); + $this->assertEquals(array(),$p->getHTTPMethods('')); + + } + + function testOptions() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'OPTIONS', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'DAV' => '1, 3, extended-mkcol, drinking', + 'MS-Author-Via' => 'DAV', + 'Allow' => 'OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT, BEER, WINE', + 'Accept-Ranges' => 'bytes', + 'Content-Length' => '0', + 'X-Sabre-Version' => Version::VERSION, + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('', $this->response->body); + $this->assertEquals('OPTIONS',$this->testPlugin->beforeMethod); + + + } + + function testGetPlugin() { + + $this->assertEquals($this->testPlugin,$this->server->getPlugin(get_class($this->testPlugin))); + + } + + function testUnknownPlugin() { + + $this->assertNull($this->server->getPlugin('SomeRandomClassName')); + + } + + function testGetSupportedReportSet() { + + $this->assertEquals(array(), $this->testPlugin->getSupportedReportSet('/')); + + } + + function testGetPlugins() { + + $this->assertEquals( + array(get_class($this->testPlugin) => $this->testPlugin), + $this->server->getPlugins() + ); + + } + + +} + +class ServerPluginMock extends ServerPlugin { + + function initialize(Server $s) { } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php new file mode 100644 index 00000000..ea09852a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPreconditionTest.php @@ -0,0 +1,395 @@ + '*', + 'REQUEST_URI' => '/bar' + )); + $server->httpRequest = $httpRequest; + + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfMatchHasNode() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MATCH' => '*', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfMatchWrongEtag() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MATCH' => '1234', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfMatchCorrectEtag() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MATCH' => '"abc123"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * Evolution sometimes uses \" instead of " for If-Match headers. + * + * @covers \Sabre\DAV\Server::checkPreconditions + * @depends testIfMatchCorrectEtag + */ + function testIfMatchEvolutionEtag() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MATCH' => '\\"abc123\\"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfMatchMultiple() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MATCH' => '"hellothere", "abc123"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfNoneMatchNoNode() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '*', + 'REQUEST_URI' => '/bar' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + function testIfNoneMatchHasNode() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '*', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfNoneMatchWrongEtag() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '"1234"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + function testIfNoneMatchWrongEtagMultiple() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '"1234", "5678"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testIfNoneMatchCorrectEtag() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '"abc123"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testIfNoneMatchCorrectEtagMultiple() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '"1234", "abc123"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfNoneMatchCorrectEtagAsGet() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_NONE_MATCH' => '"abc123"', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + + $this->assertFalse($server->checkPreconditions(true)); + $this->assertEquals('HTTP/1.1 304 Not Modified',$server->httpResponse->status); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfModifiedSinceUnModified() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + $this->assertFalse($server->checkPreconditions()); + + $this->assertEquals('HTTP/1.1 304 Not Modified',$server->httpResponse->status); + $this->assertEquals(array( + 'Last-Modified' => 'Sat, 06 Apr 1985 23:30:00 GMT', + ), $server->httpResponse->headers); + + } + + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfModifiedSinceModified() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MODIFIED_SINCE' => 'Tue, 06 Nov 1984 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfModifiedSinceInvalidDate() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MODIFIED_SINCE' => 'Your mother', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + + // Invalid dates must be ignored, so this should return true + $this->assertTrue($server->checkPreconditions()); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfModifiedSinceInvalidDate2() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 EST', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions()); + + } + + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfUnmodifiedSinceUnModified() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 06 Nov 1994 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $this->assertTrue($server->checkPreconditions()); + + } + + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + * @expectedException Sabre\DAV\Exception\PreconditionFailed + */ + public function testIfUnmodifiedSinceModified() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_UNMODIFIED_SINCE' => 'Tue, 06 Nov 1984 08:49:37 GMT', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + $server->checkPreconditions(); + + } + + /** + * @covers \Sabre\DAV\Server::checkPreconditions + */ + public function testIfUnmodifiedSinceInvalidDate() { + + $root = new SimpleCollection('root',array(new ServerPreconditionsNode())); + $server = new Server($root); + $httpRequest = new HTTP\Request(array( + 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 06 Nov 1984 08:49:37 CET', + 'REQUEST_URI' => '/foo' + )); + $server->httpRequest = $httpRequest; + $server->httpResponse = new HTTP\ResponseMock(); + $this->assertTrue($server->checkPreconditions()); + + } + + +} + +class ServerPreconditionsNode extends File { + + function getETag() { + + return '"abc123"'; + + } + + function getLastModified() { + + /* my birthday & time, I believe */ + return strtotime('1985-04-07 01:30 +02:00'); + + } + + function getName() { + + return 'foo'; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php new file mode 100644 index 00000000..859a9107 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerPropsTest.php @@ -0,0 +1,413 @@ +server->addPlugin(new Locks\Plugin(new Locks\Backend\File(SABRE_TEMPDIR . '/.locksdb'))); + + } + + function tearDown() { + + parent::tearDown(); + if (file_exists(SABRE_TEMPDIR.'../.locksdb')) unlink(SABRE_TEMPDIR.'../.locksdb'); + + } + + private function sendRequest($body) { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'PROPFIND', + 'HTTP_DEPTH' => '0', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($body); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + } + + public function testPropFindEmptyBody() { + + $hasFired = false; + + $self = $this; + // Also testing the beforeGetPropertiesForPath event. + $this->server->subscribeEvent('beforeGetPropertiesForPath', function($path, $properties, $depth) use ($self, &$hasFired) { + + $hasFired = true; + $self->assertEquals('', $path); + $self->assertEquals(array(), $properties); + $self->assertEquals(0, $depth); + + }); + + $this->sendRequest(""); + + $this->assertTrue($hasFired); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'DAV' => '1, 3, extended-mkcol, 2', + 'Vary' => 'Brief,Prefer', + ), + $this->response->headers + ); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/',(string)$data,'href element should have been /'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype'); + $this->assertEquals(1,count($data)); + + } + + function testSupportedLocks() { + + $xml = ' + + + + +'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry'); + $this->assertEquals(2,count($data),'We expected two \'d:lockentry\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope'); + $this->assertEquals(2,count($data),'We expected two \'d:lockscope\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype'); + $this->assertEquals(2,count($data),'We expected two \'d:locktype\' tags'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:shared'); + $this->assertEquals(1,count($data),'We expected a \'d:shared\' tag'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:lockscope/d:exclusive'); + $this->assertEquals(1,count($data),'We expected a \'d:exclusive\' tag'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:supportedlock/d:lockentry/d:locktype/d:write'); + $this->assertEquals(2,count($data),'We expected two \'d:write\' tags'); + } + + function testLockDiscovery() { + + $xml = ' + + + + +'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:lockdiscovery'); + $this->assertEquals(1,count($data),'We expected a \'d:lockdiscovery\' tag'); + + } + + function testUnknownProperty() { + + $xml = ' + + + + +'; + + $this->sendRequest($xml); + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + $pathTests = array( + '/d:multistatus', + '/d:multistatus/d:response', + '/d:multistatus/d:response/d:propstat', + '/d:multistatus/d:response/d:propstat/d:status', + '/d:multistatus/d:response/d:propstat/d:prop', + '/d:multistatus/d:response/d:propstat/d:prop/d:macaroni', + ); + foreach($pathTests as $test) { + $this->assertTrue(count($xml->xpath($test))==true,'We expected the ' . $test . ' element to appear in the response, we got: ' . $body); + } + + $val = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1,count($val),$body); + $this->assertEquals('HTTP/1.1 404 Not Found',(string)$val[0]); + + } + + /** + * @covers Sabre\DAV\Server::parsePropPatchRequest + */ + public function testParsePropPatchRequest() { + + $body = ' + + somevalue + + removeme + +'; + + $result = $this->server->parsePropPatchRequest($body); + $this->assertEquals(array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + '{http://sabredav.org/NS/test}someprop2' => null, + '{http://sabredav.org/NS/test}someprop3' => null, + ), $result); + + } + + /** + * @covers Sabre\DAV\Server::updateProperties + */ + public function testUpdateProperties() { + + $props = array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + ); + + $result = $this->server->updateProperties('/test2.txt',$props); + + $this->assertEquals(array( + '200' => array('{http://sabredav.org/NS/test}someprop' => null), + 'href' => '/test2.txt', + ), $result); + + } + + /** + * @covers Sabre\DAV\Server::updateProperties + * @depends testUpdateProperties + */ + public function testUpdatePropertiesProtected() { + + $props = array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + '{DAV:}getcontentlength' => 50, + ); + + $result = $this->server->updateProperties('/test2.txt',$props); + + $this->assertEquals(array( + '424' => array('{http://sabredav.org/NS/test}someprop' => null), + '403' => array('{DAV:}getcontentlength' => null), + 'href' => '/test2.txt', + ), $result); + + } + + /** + * @covers Sabre\DAV\Server::updateProperties + * @depends testUpdateProperties + */ + public function testUpdatePropertiesFail1() { + + $dir = new PropTestDirMock('updatepropsfalse'); + $objectTree = new ObjectTree($dir); + $this->server->tree = $objectTree; + + $props = array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + ); + + $result = $this->server->updateProperties('/',$props); + + $this->assertEquals(array( + '403' => array('{http://sabredav.org/NS/test}someprop' => null), + 'href' => '/', + ), $result); + + } + + /** + * @covers Sabre\DAV\Server::updateProperties + * @depends testUpdateProperties + */ + public function testUpdatePropertiesFail2() { + + $dir = new PropTestDirMock('updatepropsarray'); + $objectTree = new ObjectTree($dir); + $this->server->tree = $objectTree; + + $props = array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + ); + + $result = $this->server->updateProperties('/',$props); + + $this->assertEquals(array( + '402' => array('{http://sabredav.org/NS/test}someprop' => null), + 'href' => '/', + ), $result); + + } + + /** + * @covers Sabre\DAV\Server::updateProperties + * @depends testUpdateProperties + * @expectedException Sabre\DAV\Exception + */ + public function testUpdatePropertiesFail3() { + + $dir = new PropTestDirMock('updatepropsobj'); + $objectTree = new ObjectTree($dir); + $this->server->tree = $objectTree; + + $props = array( + '{http://sabredav.org/NS/test}someprop' => 'somevalue', + ); + + $result = $this->server->updateProperties('/',$props); + + } + + /** + * @depends testParsePropPatchRequest + * @depends testUpdateProperties + * @covers Sabre\DAV\Server::httpPropPatch + */ + public function testPropPatch() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'PROPPATCH', + ); + + $body = ' + + somevalue +'; + + $request = new HTTP\Request($serverVars); + $request->setBody($body); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'Vary' => 'Brief,Prefer', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'We got the wrong status. Full XML response: ' . $this->response->body); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('bla','http://www.rooftopsolutions.nl/testnamespace'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop'); + $this->assertEquals(1,count($data),'We expected one \'d:prop\' element. Response body: ' . $body); + + $data = $xml->xpath('//bla:someprop'); + $this->assertEquals(1,count($data),'We expected one \'s:someprop\' element. Response body: ' . $body); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:status'); + $this->assertEquals(1,count($data),'We expected one \'s:status\' element. Response body: ' . $body); + + $this->assertEquals('HTTP/1.1 200 OK',(string)$data[0]); + + } + + /** + * @depends testPropPatch + */ + public function testPropPatchAndFetch() { + + $this->testPropPatch(); + $xml = ' + + + + +'; + + $this->sendRequest($xml); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + $xml->registerXPathNamespace('bla','http://www.rooftopsolutions.nl/testnamespace'); + + $xpath='//bla:someprop'; + $result = $xml->xpath($xpath); + $this->assertEquals(1,count($result),'We couldn\'t find our new property in the response. Full response body:' . "\n" . $body); + $this->assertEquals('somevalue',(string)$result[0],'We couldn\'t find our new property in the response. Full response body:' . "\n" . $body); + + } + +} + +class PropTestDirMock extends SimpleCollection implements IProperties { + + public $type; + + function __construct($type) { + + $this->type =$type; + parent::__construct('root'); + + } + + function updateProperties($updateProperties) { + + switch($this->type) { + case 'updatepropsfalse' : return false; + case 'updatepropsarray' : + $r = array(402 => array()); + foreach($updateProperties as $k=>$v) $r[402][$k] = null; + return $r; + case 'updatepropsobj' : + return new \STDClass(); + } + + } + + function getProperties($requestedPropeties) { + + return array(); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php new file mode 100644 index 00000000..a06fcb0b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerRangeTest.php @@ -0,0 +1,274 @@ + '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-5', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 4, + 'Content-Range' => 'bytes 2-5/13', + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')). '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 206 Partial Content',$this->response->status); + $this->assertEquals('st c', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + */ + function testStartRange() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 11, + 'Content-Range' => 'bytes 2-12/13', + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')) . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 206 Partial Content',$this->response->status); + $this->assertEquals('st contents', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + */ + function testEndRange() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=-8', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 8, + 'Content-Range' => 'bytes 5-12/13', + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')). '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 206 Partial Content',$this->response->status); + $this->assertEquals('contents', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + */ + function testTooHighRange() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=100-200', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 416 Requested Range Not Satisfiable',$this->response->status); + + } + + /** + * @depends testRange + */ + function testCrazyRange() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=8-4', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 416 Requested Range Not Satisfiable',$this->response->status); + + } + + /** + * @depends testRange + * @covers \Sabre\DAV\Server::httpGet + */ + function testIfRangeEtag() { + + $node = $this->server->tree->getNodeForPath('test.txt'); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-5', + 'HTTP_IF_RANGE' => $node->getETag(), + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 4, + 'Content-Range' => 'bytes 2-5/13', + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')) . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 206 Partial Content',$this->response->status); + $this->assertEquals('st c', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + * @covers \Sabre\DAV\Server::httpGet + */ + function testIfRangeEtagIncorrect() { + + $node = $this->server->tree->getNodeForPath('test.txt'); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-5', + 'HTTP_IF_RANGE' => $node->getETag() . 'blabla', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')) . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + * @covers \Sabre\DAV\Server::httpGet + */ + function testIfRangeModificationDate() { + + $node = $this->server->tree->getNodeForPath('test.txt'); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-5', + 'HTTP_IF_RANGE' => 'tomorrow', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 4, + 'Content-Range' => 'bytes 2-5/13', + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')) . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 206 Partial Content',$this->response->status); + $this->assertEquals('st c', stream_get_contents($this->response->body)); + + } + + /** + * @depends testRange + * @covers \Sabre\DAV\Server::httpGet + */ + function testIfRangeModificationDateModified() { + + $node = $this->server->tree->getNodeForPath('test.txt'); + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'HTTP_RANGE' => 'bytes=2-5', + 'HTTP_IF_RANGE' => '-2 years', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + 'ETag' => '"' . md5(file_get_contents(SABRE_TEMPDIR . '/test.txt')) . '"', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php new file mode 100644 index 00000000..21e0ab2e --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerSimpleTest.php @@ -0,0 +1,625 @@ +assertEquals($nodes[0], $server->tree->getNodeForPath('hello')); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testConstructIncorrectObj() { + + $nodes = array( + new SimpleCollection('hello'), + new \STDClass(), + ); + + $server = new Server($nodes); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + function testConstructInvalidArg() { + + $server = new Server(1); + + } + + function testGet() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + function testGetHttp10() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'GET', + 'SERVER_PROTOCOL' => 'HTTP/1.0', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.0 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + function testGetDoesntExist() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt_randomblbla', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + $this->assertEquals('HTTP/1.1 404 Not Found',$this->response->status); + + } + + function testGetDoesntExist2() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt/randomblbla', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + $this->assertEquals('HTTP/1.1 404 Not Found',$this->response->status); + + } + + /** + * This test should have the exact same result as testGet. + * + * The idea is that double slashes // are converted to single ones / + * + */ + function testGetDoubleSlash() { + + $serverVars = array( + 'REQUEST_URI' => '//test.txt', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + + function testHEAD() { + + $serverVars = array( + 'REQUEST_URI' => '/test.txt', + 'REQUEST_METHOD' => 'HEAD', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('', $this->response->body); + + } + + function testOptions() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'OPTIONS', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'DAV' => '1, 3, extended-mkcol', + 'MS-Author-Via' => 'DAV', + 'Allow' => 'OPTIONS, GET, HEAD, DELETE, PROPFIND, PUT, PROPPATCH, COPY, MOVE, REPORT', + 'Accept-Ranges' => 'bytes', + 'Content-Length' => '0', + 'X-Sabre-Version' => Version::VERSION, + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('', $this->response->body); + + + } + function testNonExistantMethod() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'BLABLA', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 501 Not Implemented',$this->response->status); + + + } + + function testGETOnCollection() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 501 Not Implemented',$this->response->status); + + } + + function testHEADOnCollection() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'HEAD', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + + } + + function testBaseUri() { + + $serverVars = array( + 'REQUEST_URI' => '/blabla/test.txt', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->setBaseUri('/blabla/'); + $this->assertEquals('/blabla/',$this->server->getBaseUri()); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/octet-stream', + 'Content-Length' => 13, + 'Last-Modified' => HTTP\Util::toHTTPDate(new \DateTime('@' . filemtime($this->tempDir . '/test.txt'))), + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals('Test contents', stream_get_contents($this->response->body)); + + } + + function testBaseUriAddSlash() { + + $tests = array( + '/' => '/', + '/foo' => '/foo/', + '/foo/' => '/foo/', + '/foo/bar' => '/foo/bar/', + '/foo/bar/' => '/foo/bar/', + ); + + foreach($tests as $test=>$result) { + $this->server->setBaseUri($test); + + $this->assertEquals($result, $this->server->getBaseUri()); + + } + + } + + function testCalculateUri() { + + $uris = array( + 'http://www.example.org/root/somepath', + '/root/somepath', + '/root/somepath/', + ); + + $this->server->setBaseUri('/root/'); + + foreach($uris as $uri) { + + $this->assertEquals('somepath',$this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/root'); + + foreach($uris as $uri) { + + $this->assertEquals('somepath',$this->server->calculateUri($uri)); + + } + + $this->assertEquals('', $this->server->calculateUri('/root')); + + } + + function testCalculateUriSpecialChars() { + + $uris = array( + 'http://www.example.org/root/%C3%A0fo%C3%B3', + '/root/%C3%A0fo%C3%B3', + '/root/%C3%A0fo%C3%B3/' + ); + + $this->server->setBaseUri('/root/'); + + foreach($uris as $uri) { + + $this->assertEquals("\xc3\xa0fo\xc3\xb3",$this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/root'); + + foreach($uris as $uri) { + + $this->assertEquals("\xc3\xa0fo\xc3\xb3",$this->server->calculateUri($uri)); + + } + + $this->server->setBaseUri('/'); + + foreach($uris as $uri) { + + $this->assertEquals("root/\xc3\xa0fo\xc3\xb3",$this->server->calculateUri($uri)); + + } + + } + + function testBaseUriCheck() { + + $uris = array( + 'http://www.example.org/root/somepath', + '/root/somepath', + '/root/somepath/' + ); + + try { + + $this->server->setBaseUri('root/'); + $this->server->calculateUri('/root/testuri'); + + $this->fail('Expected an exception'); + + } catch (Exception\Forbidden $e) { + + // This was expected + + } + + } + + /** + * @covers \Sabre\DAV\Server::guessBaseUri + */ + function testGuessBaseUri() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/root', + 'PATH_INFO' => '/root', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @depends testGuessBaseUri + * @covers Sabre\DAV\Server::guessBaseUri + */ + function testGuessBaseUriPercentEncoding() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/dir/path2/path%20with%20spaces', + 'PATH_INFO' => '/dir/path2/path with spaces', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @depends testGuessBaseUri + * @covers \Sabre\DAV\Server::guessBaseUri + */ + /* + function testGuessBaseUriPercentEncoding2() { + + $this->markTestIncomplete('This behaviour is not yet implemented'); + $serverVars = array( + 'REQUEST_URI' => '/some%20directory+mixed/index.php/dir/path2/path%20with%20spaces', + 'PATH_INFO' => '/dir/path2/path with spaces', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/some%20directory+mixed/index.php/', $server->guessBaseUri()); + + }*/ + + function testGuessBaseUri2() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/root/', + 'PATH_INFO' => '/root/', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + function testGuessBaseUriNoPathInfo() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/root', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/', $server->guessBaseUri()); + + } + + function testGuessBaseUriNoPathInfo2() { + + $serverVars = array( + 'REQUEST_URI' => '/a/b/c/test.php', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/', $server->guessBaseUri()); + + } + + + /** + * @covers \Sabre\DAV\Server::guessBaseUri + * @depends testGuessBaseUri + */ + function testGuessBaseUriQueryString() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/root?query_string=blabla', + 'PATH_INFO' => '/root', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $this->assertEquals('/index.php/', $server->guessBaseUri()); + + } + + /** + * @covers \Sabre\DAV\Server::guessBaseUri + * @depends testGuessBaseUri + * @expectedException \Sabre\DAV\Exception + */ + function testGuessBaseUriBadConfig() { + + $serverVars = array( + 'REQUEST_URI' => '/index.php/root/heyyy', + 'PATH_INFO' => '/root', + ); + + $httpRequest = new HTTP\Request($serverVars); + $server = new Server(); + $server->httpRequest = $httpRequest; + + $server->guessBaseUri(); + + } + + function testTriggerException() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'FOO', + ); + + $httpRequest = new HTTP\Request($serverVars); + $this->server->httpRequest = $httpRequest; + $this->server->subscribeEvent('beforeMethod',array($this,'exceptionTrigger')); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $this->assertEquals('HTTP/1.1 500 Internal Server Error',$this->response->status); + + } + + function exceptionTrigger() { + + throw new Exception('Hola'); + + } + + function testReportNotFound() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'REPORT', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpRequest->setBody(''); + $this->server->exec(); + + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 403 Forbidden',$this->response->status,'We got an incorrect status back. Full response body follows: ' . $this->response->body); + + } + + function testReportIntercepted() { + + $serverVars = array( + 'REQUEST_URI' => '/', + 'REQUEST_METHOD' => 'REPORT', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->httpRequest->setBody(''); + $this->server->subscribeEvent('report',array($this,'reportHandler')); + $this->server->exec(); + + $this->assertEquals(array( + 'testheader' => 'testvalue', + ), + $this->response->headers + ); + + $this->assertEquals('HTTP/1.1 418 I\'m a teapot',$this->response->status,'We got an incorrect status back. Full response body follows: ' . $this->response->body); + + } + + function reportHandler($reportName) { + + if ($reportName=='{http://www.rooftopsolutions.nl/NS}myreport') { + $this->server->httpResponse->sendStatus(418); + $this->server->httpResponse->setHeader('testheader','testvalue'); + return false; + } + else return; + + } + + function testGetPropertiesForChildren() { + + $result = $this->server->getPropertiesForChildren('',array( + '{DAV:}getcontentlength', + )); + + $expected = array( + 'test.txt' => array('{DAV:}getcontentlength' => 13), + 'dir/' => array(), + ); + + $this->assertEquals($expected,$result); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php new file mode 100644 index 00000000..a73e8d13 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/ServerUpdatePropertiesTest.php @@ -0,0 +1,130 @@ +updateProperties('foo', array( + '{DAV:}foo' => 'bar' + )); + + $expected = array( + 'href' => 'foo', + '403' => array( + '{DAV:}foo' => null, + ), + ); + $this->assertEquals($expected, $result); + + } + + function testUpdatePropertiesProtected() { + + $tree = array( + new SimpleCollection('foo'), + ); + $server = new Server($tree); + + $result = $server->updateProperties('foo', array( + '{DAV:}getetag' => 'bla', + '{DAV:}foo' => 'bar' + )); + + $expected = array( + 'href' => 'foo', + '403' => array( + '{DAV:}getetag' => null, + ), + '424' => array( + '{DAV:}foo' => null, + ), + ); + $this->assertEquals($expected, $result); + + } + + function testUpdatePropertiesEventFail() { + + $tree = array( + new SimpleCollection('foo'), + ); + $server = new Server($tree); + $server->subscribeEvent('updateProperties', array($this,'updatepropfail')); + + $result = $server->updateProperties('foo', array( + '{DAV:}foo' => 'bar', + '{DAV:}foo2' => 'bla', + )); + + $expected = array( + 'href' => 'foo', + '404' => array( + '{DAV:}foo' => null, + ), + '424' => array( + '{DAV:}foo2' => null, + ), + ); + $this->assertEquals($expected, $result); + + } + + function updatePropFail(&$propertyDelta, &$result, $node) { + + $result[404] = array( + '{DAV:}foo' => null, + ); + unset($propertyDelta['{DAV:}foo']); + return false; + + } + + + function testUpdatePropertiesEventSuccess() { + + $tree = array( + new SimpleCollection('foo'), + ); + $server = new Server($tree); + $server->subscribeEvent('updateProperties', array($this,'updatepropsuccess')); + + $result = $server->updateProperties('foo', array( + '{DAV:}foo' => 'bar', + '{DAV:}foo2' => 'bla', + )); + + $expected = array( + 'href' => 'foo', + '200' => array( + '{DAV:}foo' => null, + ), + '201' => array( + '{DAV:}foo2' => null, + ), + ); + $this->assertEquals($expected, $result); + + } + + function updatePropSuccess(&$propertyDelta, &$result, $node) { + + $result[200] = array( + '{DAV:}foo' => null, + ); + $result[201] = array( + '{DAV:}foo2' => null, + ); + unset($propertyDelta['{DAV:}foo']); + unset($propertyDelta['{DAV:}foo2']); + return; + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php new file mode 100644 index 00000000..de8b0573 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/SimpleFileTest.php @@ -0,0 +1,19 @@ +assertEquals('filename.txt', $file->getName()); + $this->assertEquals('contents', $file->get()); + $this->assertEquals('8', $file->getSize()); + $this->assertEquals('"' . md5('contents') . '"', $file->getETag()); + $this->assertEquals('text/plain', $file->getContentType()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php new file mode 100644 index 00000000..941d1f91 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/StringUtilTest.php @@ -0,0 +1,122 @@ +assertEquals($result, StringUtil::textMatch($haystack, $needle, $collation, $matchType)); + + } + + function dataset() { + + return array( + array('FOOBAR', 'FOO', 'i;octet', 'contains', true), + array('FOOBAR', 'foo', 'i;octet', 'contains', false), + array('FÖÖBAR', 'FÖÖ', 'i;octet', 'contains', true), + array('FÖÖBAR', 'föö', 'i;octet', 'contains', false), + array('FOOBAR', 'FOOBAR', 'i;octet', 'equals', true), + array('FOOBAR', 'fooBAR', 'i;octet', 'equals', false), + array('FOOBAR', 'FOO', 'i;octet', 'starts-with', true), + array('FOOBAR', 'foo', 'i;octet', 'starts-with', false), + array('FOOBAR', 'BAR', 'i;octet', 'starts-with', false), + array('FOOBAR', 'bar', 'i;octet', 'starts-with', false), + array('FOOBAR', 'FOO', 'i;octet', 'ends-with', false), + array('FOOBAR', 'foo', 'i;octet', 'ends-with', false), + array('FOOBAR', 'BAR', 'i;octet', 'ends-with', true), + array('FOOBAR', 'bar', 'i;octet', 'ends-with', false), + + array('FOOBAR', 'FOO', 'i;ascii-casemap', 'contains', true), + array('FOOBAR', 'foo', 'i;ascii-casemap', 'contains', true), + array('FÖÖBAR', 'FÖÖ', 'i;ascii-casemap', 'contains', true), + array('FÖÖBAR', 'föö', 'i;ascii-casemap', 'contains', false), + array('FOOBAR', 'FOOBAR', 'i;ascii-casemap', 'equals', true), + array('FOOBAR', 'fooBAR', 'i;ascii-casemap', 'equals', true), + array('FOOBAR', 'FOO', 'i;ascii-casemap', 'starts-with', true), + array('FOOBAR', 'foo', 'i;ascii-casemap', 'starts-with', true), + array('FOOBAR', 'BAR', 'i;ascii-casemap', 'starts-with', false), + array('FOOBAR', 'bar', 'i;ascii-casemap', 'starts-with', false), + array('FOOBAR', 'FOO', 'i;ascii-casemap', 'ends-with', false), + array('FOOBAR', 'foo', 'i;ascii-casemap', 'ends-with', false), + array('FOOBAR', 'BAR', 'i;ascii-casemap', 'ends-with', true), + array('FOOBAR', 'bar', 'i;ascii-casemap', 'ends-with', true), + + array('FOOBAR', 'FOO', 'i;unicode-casemap', 'contains', true), + array('FOOBAR', 'foo', 'i;unicode-casemap', 'contains', true), + array('FÖÖBAR', 'FÖÖ', 'i;unicode-casemap', 'contains', true), + array('FÖÖBAR', 'föö', 'i;unicode-casemap', 'contains', true), + array('FOOBAR', 'FOOBAR', 'i;unicode-casemap', 'equals', true), + array('FOOBAR', 'fooBAR', 'i;unicode-casemap', 'equals', true), + array('FOOBAR', 'FOO', 'i;unicode-casemap', 'starts-with', true), + array('FOOBAR', 'foo', 'i;unicode-casemap', 'starts-with', true), + array('FOOBAR', 'BAR', 'i;unicode-casemap', 'starts-with', false), + array('FOOBAR', 'bar', 'i;unicode-casemap', 'starts-with', false), + array('FOOBAR', 'FOO', 'i;unicode-casemap', 'ends-with', false), + array('FOOBAR', 'foo', 'i;unicode-casemap', 'ends-with', false), + array('FOOBAR', 'BAR', 'i;unicode-casemap', 'ends-with', true), + array('FOOBAR', 'bar', 'i;unicode-casemap', 'ends-with', true), + ); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testBadCollation() { + + StringUtil::textMatch('foobar','foo','blabla','contains'); + + } + + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + public function testBadMatchType() { + + StringUtil::textMatch('foobar','foo','i;octet','booh'); + + } + + public function testEnsureUTF8_ascii() { + + $inputString = "harkema"; + $outputString = "harkema"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + + public function testEnsureUTF8_latin1() { + + $inputString = "m\xfcnster"; + $outputString = "münster"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + + public function testEnsureUTF8_utf8() { + + $inputString = "m\xc3\xbcnster"; + $outputString = "münster"; + + $this->assertEquals( + $outputString, + StringUtil::ensureUTF8($inputString) + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php new file mode 100644 index 00000000..d136eeb1 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/TemporaryFileFilterTest.php @@ -0,0 +1,252 @@ +server->addPlugin($plugin); + + } + + function testPutNormal() { + + $serverVars = array( + 'REQUEST_URI' => '/testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('0', $this->response->headers['Content-Length']); + + $this->assertEquals('Testing new file',file_get_contents(SABRE_TEMPDIR . '/testput.txt')); + + } + + function testPutTemp() { + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testput.txt'),'._testput.txt should not exist in the regular file structure.'); + + } + + function testPutTempIfNoneMatch() { + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PUT', + 'HTTP_IF_NONE_MATCH' => '*', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testput.txt'),'._testput.txt should not exist in the regular file structure.'); + + + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 412 Precondition failed',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + } + + function testPutGet() { + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'GET', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 200 OK',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + 'Content-Length' => 16, + 'Content-Type' => 'application/octet-stream', + ),$this->response->headers); + + $this->assertEquals('Testing new file',stream_get_contents($this->response->body)); + + } + + function testLockNonExistant() { + + mkdir(SABRE_TEMPDIR . '/locksdir'); + $locksBackend = new Locks\Backend\FS(SABRE_TEMPDIR . '/locksdir'); + $locksPlugin = new Locks\Plugin($locksBackend); + $this->server->addPlugin($locksPlugin); + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testlock.txt', + 'REQUEST_METHOD' => 'LOCK', + ); + + $request = new HTTP\Request($serverVars); + + $request->setBody(' + + + + + http://example.org/~ejw/contact.html + +'); + + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals('application/xml; charset=utf-8',$this->response->headers['Content-Type']); + $this->assertTrue(preg_match('/^$/',$this->response->headers['Lock-Token'])===1,'We did not get a valid Locktoken back (' . $this->response->headers['Lock-Token'] . ')'); + $this->assertEquals('true',$this->response->headers['X-Sabre-Temp']); + + $this->assertFalse(file_exists(SABRE_TEMPDIR . '/._testlock.txt'),'._testlock.txt should not exist in the regular file structure.'); + + } + + function testPutDelete() { + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'DELETE', + ); + + $request = new HTTP\Request($serverVars); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 204 No Content',$this->response->status, "Incorrect status code received. Full body:\n". $this->response->body); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $this->assertEquals('',$this->response->body); + + } + + function testPutPropfind() { + + // mimicking an OS/X resource fork + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PUT', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody('Testing new file'); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('', $this->response->body); + $this->assertEquals('HTTP/1.1 201 Created',$this->response->status); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + ),$this->response->headers); + + $serverVars = array( + 'REQUEST_URI' => '/._testput.txt', + 'REQUEST_METHOD' => 'PROPFIND', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody(''); + $this->server->httpRequest = ($request); + $this->server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status',$this->response->status,'Incorrect status code returned. Body: ' . $this->response->body); + $this->assertEquals(array( + 'X-Sabre-Temp' => 'true', + 'Content-Type' => 'application/xml; charset=utf-8', + ),$this->response->headers); + + $body = preg_replace("/xmlns(:[A-Za-z0-9_])?=(\"|\')DAV:(\"|\')/","xmlns\\1=\"urn:DAV\"",$this->response->body); + $xml = simplexml_load_string($body); + $xml->registerXPathNamespace('d','urn:DAV'); + + list($data) = $xml->xpath('/d:multistatus/d:response/d:href'); + $this->assertEquals('/._testput.txt',(string)$data,'href element should have been /._testput.txt'); + + $data = $xml->xpath('/d:multistatus/d:response/d:propstat/d:prop/d:resourcetype'); + $this->assertEquals(1,count($data)); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php new file mode 100644 index 00000000..9cf5edbb --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/TestPlugin.php @@ -0,0 +1,34 @@ +subscribeEvent('beforeMethod',array($this,'beforeMethod')); + + } + + function beforeMethod($method) { + + $this->beforeMethod = $method; + return true; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/Tree/FilesystemTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/Tree/FilesystemTest.php new file mode 100644 index 00000000..19b08460 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/Tree/FilesystemTest.php @@ -0,0 +1,88 @@ +getNodeForPath('file.txt'); + $this->assertTrue($node instanceof DAV\FS\File); + + } + + /** + * @expectedException \Sabre\DAV\Exception\NotFound + */ + function testGetNodeForPath_DoesntExist() { + + $fs = new Filesystem(SABRE_TEMPDIR); + $node = $fs->getNodeForPath('whoop/file.txt'); + + } + + function testGetNodeForPath_Directory() { + + $fs = new Filesystem(SABRE_TEMPDIR); + $node = $fs->getNodeForPath('dir'); + $this->assertTrue($node instanceof DAV\FS\Directory); + $this->assertEquals('dir', $node->getName()); + $this->assertInternalType('array', $node->getChildren()); + + } + + function testCopy() { + + $fs = new Filesystem(SABRE_TEMPDIR); + $fs->copy('file.txt','file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/file2.txt')); + $this->assertEquals('Body',file_get_contents(SABRE_TEMPDIR . '/file2.txt')); + + } + + function testCopyDir() { + + $fs = new Filesystem(SABRE_TEMPDIR); + $fs->copy('dir','dir2'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/dir2')); + $this->assertEquals('Body',file_get_contents(SABRE_TEMPDIR . '/dir2/subfile.txt')); + + } + + function testMove() { + + $fs = new Filesystem(SABRE_TEMPDIR); + $fs->move('file.txt','file2.txt'); + $this->assertTrue(file_exists(SABRE_TEMPDIR . '/file2.txt')); + $this->assertTrue(!file_exists(SABRE_TEMPDIR . '/file.txt')); + $this->assertEquals('Body',file_get_contents(SABRE_TEMPDIR . '/file2.txt')); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php new file mode 100644 index 00000000..90df6427 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/TreeTest.php @@ -0,0 +1,175 @@ +assertTrue($tree->nodeExists('hi')); + $this->assertFalse($tree->nodeExists('hello')); + + } + + function testCopy() { + + $tree = new TreeMock(); + $tree->copy('hi','hi2'); + + $this->assertArrayHasKey('hi2', $tree->getNodeForPath('')->newDirectories); + $this->assertEquals('foobar', $tree->getNodeForPath('hi/file')->get()); + $this->assertEquals(array('test1'=>'value'), $tree->getNodeForPath('hi/file')->getProperties(array())); + + } + + function testMove() { + + $tree = new TreeMock(); + $tree->move('hi','hi2'); + + $this->assertEquals('hi2', $tree->getNodeForPath('hi')->getName()); + $this->assertTrue($tree->getNodeForPath('hi')->isRenamed); + + } + + function testDeepMove() { + + $tree = new TreeMock(); + $tree->move('hi/sub','hi2'); + + $this->assertArrayHasKey('hi2', $tree->getNodeForPath('')->newDirectories); + $this->assertTrue($tree->getNodeForPath('hi/sub')->isDeleted); + + } + + function testDelete() { + + $tree = new TreeMock(); + $tree->delete('hi'); + $this->assertTrue($tree->getNodeForPath('hi')->isDeleted); + + } + + function testGetChildren() { + + $tree = new TreeMock(); + $children = $tree->getChildren(''); + $this->assertEquals(1,count($children)); + $this->assertEquals('hi', $children[0]->getName()); + + } + +} + +class TreeMock extends Tree { + + private $nodes = array(); + + function __construct() { + + $this->nodes['hi/sub'] = new TreeDirectoryTester('sub'); + $this->nodes['hi/file'] = new TreeFileTester('file'); + $this->nodes['hi/file']->properties = array('test1' => 'value'); + $this->nodes['hi/file']->data = 'foobar'; + $this->nodes['hi'] = new TreeDirectoryTester('hi',array($this->nodes['hi/sub'], $this->nodes['hi/file'])); + $this->nodes[''] = new TreeDirectoryTester('hi', array($this->nodes['hi'])); + + } + + function getNodeForPath($path) { + + if (isset($this->nodes[$path])) return $this->nodes[$path]; + throw new Exception\NotFound('item not found'); + + } + +} + +class TreeDirectoryTester extends SimpleCollection { + + public $newDirectories = array(); + public $newFiles = array(); + public $isDeleted = false; + public $isRenamed = false; + + function createDirectory($name) { + + $this->newDirectories[$name] = true; + + } + + function createFile($name,$data = null) { + + $this->newFiles[$name] = $data; + + } + + function getChild($name) { + + if (isset($this->newDirectories[$name])) return new TreeDirectoryTester($name); + if (isset($this->newFiles[$name])) return new TreeFileTester($name, $this->newFiles[$name]); + return parent::getChild($name); + + } + + function delete() { + + $this->isDeleted = true; + + } + + function setName($name) { + + $this->isRenamed = true; + $this->name = $name; + + } + +} + +class TreeFileTester extends File implements IProperties { + + public $name; + public $data; + public $properties; + + function __construct($name, $data = null) { + + $this->name = $name; + if (is_null($data)) $data = 'bla'; + $this->data = $data; + + } + + function getName() { + + return $this->name; + + } + + function get() { + + return $this->data; + + } + + function getProperties($properties) { + + return $this->properties; + + } + + function updateProperties($properties) { + + $this->properties = $properties; + return true; + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/URLUtilTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/URLUtilTest.php new file mode 100644 index 00000000..5d138086 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/URLUtilTest.php @@ -0,0 +1,131 @@ +assertEquals( + '%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f'. + '%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f'. + '%20%21%22%23%24%25%26%27()%2a%2b%2c-./'. + '0123456789:%3b%3c%3d%3e%3f'. + '%40ABCDEFGHIJKLMNO' . + 'PQRSTUVWXYZ%5b%5c%5d%5e_' . + '%60abcdefghijklmno' . + 'pqrstuvwxyz%7b%7c%7d~%7f', + $newStr); + + $this->assertEquals($str,URLUtil::decodePath($newStr)); + + } + + function testEncodePathSegment() { + + $str = ''; + for($i=0;$i<128;$i++) $str.=chr($i); + + $newStr = URLUtil::encodePathSegment($str); + + // Note: almost exactly the same as the last test, with the + // exception of the encoding of / (ascii code 2f) + $this->assertEquals( + '%00%01%02%03%04%05%06%07%08%09%0a%0b%0c%0d%0e%0f'. + '%10%11%12%13%14%15%16%17%18%19%1a%1b%1c%1d%1e%1f'. + '%20%21%22%23%24%25%26%27()%2a%2b%2c-.%2f'. + '0123456789:%3b%3c%3d%3e%3f'. + '%40ABCDEFGHIJKLMNO' . + 'PQRSTUVWXYZ%5b%5c%5d%5e_' . + '%60abcdefghijklmno' . + 'pqrstuvwxyz%7b%7c%7d~%7f', + $newStr); + + $this->assertEquals($str,URLUtil::decodePathSegment($newStr)); + + } + + function testDecode() { + + $str = 'Hello%20Test+Test2.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals('Hello Test+Test2.txt',$newStr); + + } + + /** + * @depends testDecode + */ + function testDecodeUmlaut() { + + $str = 'Hello%C3%BC.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals("Hello\xC3\xBC.txt",$newStr); + + } + + /** + * @depends testDecodeUmlaut + */ + function testDecodeUmlautLatin1() { + + $str = 'Hello%FC.txt'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals("Hello\xC3\xBC.txt",$newStr); + + } + + /** + * This testcase was sent by a bug reporter + * + * @depends testDecode + */ + function testDecodeAccentsWindows7() { + + $str = '/webdav/%C3%A0fo%C3%B3'; + $newStr = URLUtil::decodePath($str); + $this->assertEquals(strtolower($str),URLUtil::encodePath($newStr)); + + } + + function testSplitPath() { + + $strings = array( + + // input // expected result + '/foo/bar' => array('/foo','bar'), + '/foo/bar/' => array('/foo','bar'), + 'foo/bar/' => array('foo','bar'), + 'foo/bar' => array('foo','bar'), + 'foo/bar/baz' => array('foo/bar','baz'), + 'foo/bar/baz/' => array('foo/bar','baz'), + 'foo' => array('','foo'), + 'foo/' => array('','foo'), + '/foo/' => array('','foo'), + '/foo' => array('','foo'), + '' => array(null,null), + + // UTF-8 + "/\xC3\xA0fo\xC3\xB3/bar" => array("/\xC3\xA0fo\xC3\xB3",'bar'), + "/\xC3\xA0foo/b\xC3\xBCr/" => array("/\xC3\xA0foo","b\xC3\xBCr"), + "foo/\xC3\xA0\xC3\xBCr" => array("foo","\xC3\xA0\xC3\xBCr"), + + ); + + foreach($strings as $input => $expected) { + + $output = URLUtil::splitPath($input); + $this->assertEquals($expected, $output, 'The expected output for \'' . $input . '\' was incorrect'); + + + } + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php new file mode 100644 index 00000000..f005ecc7 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/UUIDUtilTest.php @@ -0,0 +1,25 @@ +assertTrue( + UUIDUtil::validateUUID('11111111-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID(' 11111111-2222-3333-4444-555555555555') + ); + $this->assertTrue( + UUIDUtil::validateUUID('ffffffff-2222-3333-4444-555555555555') + ); + $this->assertFalse( + UUIDUtil::validateUUID('fffffffg-2222-3333-4444-555555555555') + ); + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAV/XMLUtilTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAV/XMLUtilTest.php new file mode 100644 index 00000000..1d2bfd13 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAV/XMLUtilTest.php @@ -0,0 +1,284 @@ +loadXML('Testdoc'); + + $this->assertEquals( + '{http://www.example.org/}test1', + XMLUtil::toClarkNotation($dom->firstChild) + ); + + } + + function testToClarkNotation2() { + + $dom = new \DOMDocument(); + $dom->loadXML('Testdoc'); + + $this->assertEquals( + '{http://www.example.org/}test1', + XMLUtil::toClarkNotation($dom->firstChild) + ); + + } + + function testToClarkNotationDAVNamespace() { + + $dom = new \DOMDocument(); + $dom->loadXML('Testdoc'); + + $this->assertEquals( + '{DAV:}test1', + XMLUtil::toClarkNotation($dom->firstChild) + ); + + } + + function testToClarkNotationNoElem() { + + $dom = new \DOMDocument(); + $dom->loadXML('Testdoc'); + + $this->assertNull( + XMLUtil::toClarkNotation($dom->firstChild->firstChild) + ); + + } + + function testConvertDAVNamespace() { + + $xml='blablabla'; + $this->assertEquals( + 'blablabla', + XMLUtil::convertDAVNamespace($xml) + ); + + } + + function testConvertDAVNamespace2() { + + $xml='blablabla'; + $this->assertEquals( + 'blablabla', + XMLUtil::convertDAVNamespace($xml) + ); + + } + + function testConvertDAVNamespace3() { + + $xml='blablabla'; + $this->assertEquals( + 'blablabla', + XMLUtil::convertDAVNamespace($xml) + ); + + } + + function testConvertDAVNamespace4() { + + $xml='blablabla'; + $this->assertEquals( + 'blablabla', + XMLUtil::convertDAVNamespace($xml) + ); + + } + + function testConvertDAVNamespaceMixedQuotes() { + + $xml=''; + $dom = XMLUtil::loadDOMDocument($xml); + $this->assertTrue($dom instanceof \DOMDocument); + + } + + /** + * @depends testLoadDOMDocument + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testLoadDOMDocumentEmpty() { + + XMLUtil::loadDOMDocument(''); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + * @depends testConvertDAVNamespace + */ + function testLoadDOMDocumentInvalid() { + + $xml='assertEquals('blabla',$dom->firstChild->nodeValue); + + } + + + function testParseProperties() { + + $xml=' + + + Calendars + +'; + + $dom = XMLUtil::loadDOMDocument($xml); + $properties = XMLUtil::parseProperties($dom->firstChild); + + $this->assertEquals(array( + '{DAV:}displayname' => 'Calendars', + ), $properties); + + + + } + + /** + * @depends testParseProperties + */ + function testParsePropertiesEmpty() { + + $xml=' + + + Calendars + + + + +'; + + $dom = XMLUtil::loadDOMDocument($xml); + $properties = XMLUtil::parseProperties($dom->firstChild); + + $this->assertEquals(array( + '{DAV:}displayname' => 'Calendars', + '{http://www.rooftopsolutions.nl/example}example' => null + ), $properties); + + } + + + /** + * @depends testParseProperties + */ + function testParsePropertiesComplex() { + + $xml=' + + + Calendars + + + Complex value right here + +'; + + $dom = XMLUtil::loadDOMDocument($xml); + $properties = XMLUtil::parseProperties($dom->firstChild); + + $this->assertEquals(array( + '{DAV:}displayname' => 'Calendars', + '{DAV:}someprop' => 'Complex value right here', + ), $properties); + + } + + + /** + * @depends testParseProperties + */ + function testParsePropertiesNoProperties() { + + $xml=' + + + +'; + + $dom = XMLUtil::loadDOMDocument($xml); + $properties = XMLUtil::parseProperties($dom->firstChild); + + $this->assertEquals(array(), $properties); + + } + + function testParsePropertiesMapHref() { + + $xml=' + + + Calendars + + + http://sabredav.org/ + +'; + + $dom = XMLUtil::loadDOMDocument($xml); + $properties = XMLUtil::parseProperties($dom->firstChild,array('{DAV:}someprop'=>'Sabre\\DAV\\Property\\Href')); + + $this->assertEquals(array( + '{DAV:}displayname' => 'Calendars', + '{DAV:}someprop' => new Property\Href('http://sabredav.org/',false), + ), $properties); + + } + + function testParseClarkNotation() { + + $this->assertEquals(array( + 'DAV:', + 'foo', + ), XMLUtil::parseClarkNotation('{DAV:}foo')); + + $this->assertEquals(array( + 'http://example.org/ns/bla', + 'bar-soap', + ), XMLUtil::parseClarkNotation('{http://example.org/ns/bla}bar-soap')); + } + + /** + * @expectedException InvalidArgumentException + */ + function testParseClarkNotationFail() { + + XMLUtil::parseClarkNotation('}foo'); + + } + +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php new file mode 100644 index 00000000..9960180a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ACLMethodTest.php @@ -0,0 +1,331 @@ +addPlugin($acl); + + $acl->unknownMethod('ACL','test'); + + } + + function testCallbackPassthru() { + + $acl = new Plugin(); + $server = new DAV\Server(); + $server->addPlugin($acl); + + $this->assertNull($acl->unknownMethod('FOO','test')); + + } + + /** + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + function testNotSupportedByNode() { + + $tree = array( + new DAV\SimpleCollection('test'), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + function testSuccessSimple() { + + $tree = array( + new MockACLNode('test',array()), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $this->assertNull($acl->httpACL('test')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotRecognizedPrincipal + */ + function testUnrecognizedPrincipal() { + + $tree = array( + new MockACLNode('test',array()), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notfound + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotRecognizedPrincipal + */ + function testUnrecognizedPrincipal2() { + + $tree = array( + new MockACLNode('test',array()), + new DAV\SimpleCollection('principals',array( + new DAV\SimpleCollection('notaprincipal'), + )), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notaprincipal + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NotSupportedPrivilege + */ + function testUnknownPrivilege() { + + $tree = array( + new MockACLNode('test',array()), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notfound + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NoAbstract + */ + function testAbstractPrivilege() { + + $tree = array( + new MockACLNode('test',array()), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notfound + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege() { + + $oldACL = array( + array( + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ), + ); + + $tree = array( + new MockACLNode('test',$oldACL), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notfound + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege2() { + + $oldACL = array( + array( + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ), + ); + + $tree = array( + new MockACLNode('test',$oldACL), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/foo + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\AceConflict + */ + function testUpdateProtectedPrivilege3() { + + $oldACL = array( + array( + 'principal' => 'principals/notfound', + 'privilege' => '{DAV:}write', + 'protected' => true, + ), + ); + + $tree = array( + new MockACLNode('test',$oldACL), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/notfound + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $acl->httpACL('test'); + + } + + function testSuccessComplex () { + + $oldACL = array( + array( + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}write', + 'protected' => true, + ), + array( + 'principal' => 'principals/bar', + 'privilege' => '{DAV:}read', + ), + ); + + $tree = array( + $node = new MockACLNode('test',$oldACL), + new DAV\SimpleCollection('principals', array( + new MockPrincipal('foo','principals/foo'), + new MockPrincipal('baz','principals/baz'), + )), + ); + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->httpRequest = new HTTP\Request(); + $body = ' + + + + /principals/foo + + + + + /principals/baz + +'; + $server->httpRequest->setBody($body); + $server->addPlugin($acl); + + $this->assertFalse($acl->unknownMethod('ACL','test')); + + $this->assertEquals(array( + array( + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}write', + 'protected' => true, + ), + array( + 'principal' => 'principals/baz', + 'privilege' => '{DAV:}write', + 'protected' => false, + ), + ), $node->getACL()); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php new file mode 100644 index 00000000..3a9b35b4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/AllowAccessTest.php @@ -0,0 +1,139 @@ +server = new DAV\Server($nodes); + $aclPlugin = new Plugin(); + $aclPlugin->allowAccessToNodesWithoutACL = true; + $this->server->addPlugin($aclPlugin); + + } + + function testGet() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('GET','testdir'))); + + } + + function testGetDoesntExist() { + + $r = $this->server->broadcastEvent('beforeMethod',array('GET','foo')); + $this->assertTrue($r); + + } + + function testHEAD() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('HEAD','testdir'))); + + } + + function testOPTIONS() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('OPTIONS','testdir'))); + + } + + function testPUT() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('PUT','testdir'))); + + } + + function testACL() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('ACL','testdir'))); + + } + + function testPROPPATCH() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('PROPPATCH','testdir'))); + + } + + function testCOPY() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('COPY','testdir'))); + + } + + function testMOVE() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('MOVE','testdir'))); + + } + + function testLOCK() { + + $this->assertTrue($this->server->broadcastEvent('beforeMethod',array('LOCK','testdir'))); + + } + + function testBeforeBind() { + + $this->assertTrue($this->server->broadcastEvent('beforeBind',array('testdir/file'))); + + } + + + function testBeforeUnbind() { + + $this->assertTrue($this->server->broadcastEvent('beforeUnbind',array('testdir'))); + + } + + function testAfterGetProperties() { + + $properties = array( + 'href' => 'foo', + '200' => array( + '{DAV:}displayname' => 'foo', + '{DAV:}getcontentlength' => 500, + ), + '404' => array( + '{DAV:}bar' => null, + ), + '403' => array( + '{DAV:}owner' => null, + ), + ); + + $expected = array( + 'href' => 'foo', + '200' => array( + '{DAV:}displayname' => 'foo', + '{DAV:}getcontentlength' => 500, + ), + '404' => array( + '{DAV:}bar' => null, + ), + '403' => array( + '{DAV:}owner' => null, + ), + ); + + $r = $this->server->broadcastEvent('afterGetProperties',array('testdir',&$properties)); + $this->assertTrue($r); + + $this->assertEquals($expected, $properties); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php new file mode 100644 index 00000000..345d2cc5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/BlockAccessTest.php @@ -0,0 +1,190 @@ +server = new DAV\Server($nodes); + $this->plugin = new Plugin(); + $this->plugin->allowAccessToNodesWithoutACL = false; + $this->server->addPlugin($this->plugin); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testGet() { + + $this->server->broadcastEvent('beforeMethod',array('GET','testdir')); + + } + + function testGetDoesntExist() { + + $r = $this->server->broadcastEvent('beforeMethod',array('GET','foo')); + $this->assertTrue($r); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testHEAD() { + + $this->server->broadcastEvent('beforeMethod',array('HEAD','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testOPTIONS() { + + $this->server->broadcastEvent('beforeMethod',array('OPTIONS','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testPUT() { + + $this->server->broadcastEvent('beforeMethod',array('PUT','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testPROPPATCH() { + + $this->server->broadcastEvent('beforeMethod',array('PROPPATCH','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testCOPY() { + + $this->server->broadcastEvent('beforeMethod',array('COPY','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testMOVE() { + + $this->server->broadcastEvent('beforeMethod',array('MOVE','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testACL() { + + $this->server->broadcastEvent('beforeMethod',array('ACL','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testLOCK() { + + $this->server->broadcastEvent('beforeMethod',array('LOCK','testdir')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testBeforeBind() { + + $this->server->broadcastEvent('beforeBind',array('testdir/file')); + + } + + /** + * @expectedException Sabre\DAVACL\Exception\NeedPrivileges + */ + function testBeforeUnbind() { + + $this->server->broadcastEvent('beforeUnbind',array('testdir')); + + } + + function testBeforeGetProperties() { + + $requestedProperties = array( + '{DAV:}displayname', + '{DAV:}getcontentlength', + '{DAV:}bar', + '{DAV:}owner', + ); + $returnedProperties = array(); + + $arguments = array( + 'testdir', + new DAV\SimpleCollection('testdir'), + &$requestedProperties, + &$returnedProperties + ); + $r = $this->server->broadcastEvent('beforeGetProperties',$arguments); + $this->assertTrue($r); + + $expected = array( + '403' => array( + '{DAV:}displayname' => null, + '{DAV:}getcontentlength' => null, + '{DAV:}bar' => null, + '{DAV:}owner' => null, + ), + ); + + $this->assertEquals($expected, $returnedProperties); + $this->assertEquals(array(), $requestedProperties); + + } + + function testBeforeGetPropertiesNoListing() { + + $this->plugin->hideNodesFromListings = true; + + $requestedProperties = array( + '{DAV:}displayname', + '{DAV:}getcontentlength', + '{DAV:}bar', + '{DAV:}owner', + ); + $returnedProperties = array(); + + $arguments = array( + 'testdir', + new DAV\SimpleCollection('testdir'), + &$requestedProperties, + &$returnedProperties + ); + $r = $this->server->broadcastEvent('beforeGetProperties',$arguments); + $this->assertFalse($r); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php new file mode 100644 index 00000000..fc48af67 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/AceConflictTest.php @@ -0,0 +1,39 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:no-ace-conflict' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php new file mode 100644 index 00000000..7e66adab --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NeedPrivilegesExceptionTest.php @@ -0,0 +1,49 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:need-privileges' => 1, + '/d:root/d:need-privileges/d:resource' => 2, + '/d:root/d:need-privileges/d:resource/d:href' => 2, + '/d:root/d:need-privileges/d:resource/d:privilege' => 2, + '/d:root/d:need-privileges/d:resource/d:privilege/d:read' => 1, + '/d:root/d:need-privileges/d:resource/d:privilege/d:write' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php new file mode 100644 index 00000000..2406c1c3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NoAbstractTest.php @@ -0,0 +1,39 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:no-abstract' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php new file mode 100644 index 00000000..6077b0ba --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotRecognizedPrincipalTest.php @@ -0,0 +1,39 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:recognized-principal' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php new file mode 100644 index 00000000..8e7b3685 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Exception/NotSupportedPrivilegeTest.php @@ -0,0 +1,39 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $ex->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:not-supported-privilege' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php new file mode 100644 index 00000000..324788d4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/ExpandPropertiesTest.php @@ -0,0 +1,358 @@ + 'foo', + '{http://sabredav.org/ns}href' => new DAV\Property\Href('node2'), + '{DAV:}displayname' => 'Node 1', + )), + new MockPropertyNode('node2', array( + '{http://sabredav.org/ns}simple' => 'simple', + '{http://sabredav.org/ns}hreflist' => new DAV\Property\HrefList(array('node1','node3')), + '{DAV:}displayname' => 'Node 2', + )), + new MockPropertyNode('node3', array( + '{http://sabredav.org/ns}simple' => 'simple', + '{DAV:}displayname' => 'Node 3', + )), + ); + + $fakeServer = new DAV\Server($tree); + $fakeServer->debugExceptions = true; + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $plugin = new Plugin(); + $plugin->allowAccessToNodesWithoutACL = true; + + $this->assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testSimple() { + + $xml = ' + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node1', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status,'Incorrect status code received. Full body: ' . $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 2, + '/d:multistatus/d:response/d:propstat/d:prop' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:simple' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:href' => 1, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + $xml->registerXPathNamespace('s','http://sabredav.org/ns'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response: ' . $server->httpResponse->body); + + } + + } + + /** + * @depends testSimple + */ + function testExpand() { + + $xml = ' + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node1', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status, 'Incorrect response status received. Full response body: ' . $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop/d:displayname' => 1, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + $xml->registerXPathNamespace('s','http://sabredav.org/ns'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result)); + + } + + } + + /** + * @depends testSimple + */ + function testExpandHrefList() { + + $xml = ' + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node2', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/d:displayname' => 2, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + $xml->registerXPathNamespace('s','http://sabredav.org/ns'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result)); + + } + + } + + /** + * @depends testExpand + */ + function testExpandDeep() { + + $xml = ' + + + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/node2', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 1, + '/d:multistatus/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat' => 3, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop' => 3, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/d:displayname' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:href' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop' => 1, + '/d:multistatus/d:response/d:propstat/d:prop/s:hreflist/d:response/d:propstat/d:prop/s:href/d:response/d:propstat/d:prop/d:displayname' => 1, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + $xml->registerXPathNamespace('s','http://sabredav.org/ns'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result)); + + } + + } +} +class MockPropertyNode implements DAV\INode, DAV\IProperties { + + function __construct($name, array $properties) { + + $this->name = $name; + $this->properties = $properties; + + } + + function getName() { + + return $this->name; + + } + + function getProperties($requestedProperties) { + + $returnedProperties = array(); + foreach($requestedProperties as $requestedProperty) { + if (isset($this->properties[$requestedProperty])) { + $returnedProperties[$requestedProperty] = + $this->properties[$requestedProperty]; + } + } + return $returnedProperties; + + } + + function delete() { + + throw new DAV\Exception('Not implemented'); + + } + + function setName($name) { + + throw new DAV\Exception('Not implemented'); + + } + + function getLastModified() { + + return null; + + } + + function updateProperties($properties) { + + throw new DAV\Exception('Not implemented'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php new file mode 100644 index 00000000..7b3e8fc1 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockACLNode.php @@ -0,0 +1,56 @@ +name = $name; + $this->acl = $acl; + + } + + function getName() { + + return $this->name; + + } + + function getOwner() { + + return null; + + } + + function getGroup() { + + return null; + + } + + function getACL() { + + return $this->acl; + + } + + function setACL(array $acl) { + + $this->acl = $acl; + + } + + function getSupportedPrivilegeSet() { + + return null; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php new file mode 100644 index 00000000..dd8542b8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/MockPrincipal.php @@ -0,0 +1,66 @@ +name = $name; + $this->principalUrl = $principalUrl; + $this->groupMembership = $groupMembership; + $this->groupMemberSet = $groupMemberSet; + + } + + function getName() { + + return $this->name; + + } + + function getDisplayName() { + + return $this->getName(); + + } + + function getAlternateUriSet() { + + return array(); + + } + + function getPrincipalUrl() { + + return $this->principalUrl; + + } + + function getGroupMemberSet() { + + return $this->groupMemberSet; + + } + + function getGroupMemberShip() { + + return $this->groupMembership; + + } + + function setGroupMemberSet(array $groupMemberSet) { + + $this->groupMemberSet = $groupMemberSet; + + } +} + diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php new file mode 100644 index 00000000..23c4b6e8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginAdminTest.php @@ -0,0 +1,83 @@ +addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'OPTIONS', + 'HTTP_DEPTH' => 1, + 'REQUEST_URI' => '/adminonly', + )); + + $response = new HTTP\ResponseMock(); + + $fakeServer->httpRequest = $request; + $fakeServer->httpResponse = $response; + + $fakeServer->exec(); + + $this->assertEquals('HTTP/1.1 403 Forbidden', $response->status); + + } + + /** + * @depends testNoAdminAccess + */ + function testAdminAccess() { + + $principalBackend = new PrincipalBackend\Mock(); + + $tree = array( + new MockACLNode('adminonly', array()), + new PrincipalCollection($principalBackend), + ); + + $fakeServer = new DAV\Server($tree); + $plugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'realm'); + $fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $plugin->adminPrincipals = array( + 'principals/admin', + ); + $fakeServer->addPlugin($plugin); + + $request = new HTTP\Request(array( + 'REQUEST_METHOD' => 'OPTIONS', + 'HTTP_DEPTH' => 1, + 'REQUEST_URI' => '/adminonly', + )); + + $response = new HTTP\ResponseMock(); + + $fakeServer->httpRequest = $request; + $fakeServer->httpResponse = $response; + + $fakeServer->exec(); + + $this->assertEquals('HTTP/1.1 200 OK', $response->status); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php new file mode 100644 index 00000000..8c0626e5 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginPropertiesTest.php @@ -0,0 +1,407 @@ +principalCollectionSet = array( + 'principals1', + 'principals2', + ); + + $requestedProperties = array( + '{DAV:}principal-collection-set', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + $server = new DAV\Server(); + $server->addPlugin($plugin); + + $this->assertNull($plugin->beforeGetProperties('', new DAV\SimpleCollection('root'), $requestedProperties, $returnedProperties)); + + $this->assertEquals(1,count($returnedProperties[200])); + $this->assertArrayHasKey('{DAV:}principal-collection-set',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $returnedProperties[200]['{DAV:}principal-collection-set']); + + $expected = array( + 'principals1/', + 'principals2/', + ); + + + $this->assertEquals($expected, $returnedProperties[200]['{DAV:}principal-collection-set']->getHrefs()); + + + } + + function testCurrentUserPrincipal() { + + $fakeServer = new DAV\Server(); + $plugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'realm'); + $fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + + $requestedProperties = array( + '{DAV:}current-user-principal', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + $this->assertNull($plugin->beforeGetProperties('', new DAV\SimpleCollection('root'), $requestedProperties, $returnedProperties)); + + $this->assertEquals(1,count($returnedProperties[200])); + $this->assertArrayHasKey('{DAV:}current-user-principal',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\DAVACL\Property\Principal', $returnedProperties[200]['{DAV:}current-user-principal']); + $this->assertEquals(Property\Principal::UNAUTHENTICATED, $returnedProperties[200]['{DAV:}current-user-principal']->getType()); + + // This will force the login + $fakeServer->broadCastEvent('beforeMethod',array('GET','')); + + + $requestedProperties = array( + '{DAV:}current-user-principal', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + + $this->assertNull($plugin->beforeGetProperties('', new DAV\SimpleCollection('root'), $requestedProperties, $returnedProperties)); + + + $this->assertEquals(1,count($returnedProperties[200])); + $this->assertArrayHasKey('{DAV:}current-user-principal',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\DAVACL\Property\Principal', $returnedProperties[200]['{DAV:}current-user-principal']); + $this->assertEquals(Property\Principal::HREF, $returnedProperties[200]['{DAV:}current-user-principal']->getType()); + $this->assertEquals('principals/admin/', $returnedProperties[200]['{DAV:}current-user-principal']->getHref()); + + } + + function testSupportedPrivilegeSet() { + + $plugin = new Plugin(); + $server = new DAV\Server(); + $server->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}supported-privilege-set', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + + $this->assertNull($plugin->beforeGetProperties('', new DAV\SimpleCollection('root'), $requestedProperties, $returnedProperties)); + + $this->assertEquals(1,count($returnedProperties[200])); + $this->assertArrayHasKey('{DAV:}supported-privilege-set',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Property\\SupportedPrivilegeSet', $returnedProperties[200]['{DAV:}supported-privilege-set']); + + $server = new DAV\Server(); + $prop = $returnedProperties[200]['{DAV:}supported-privilege-set']; + + $dom = new \DOMDocument('1.0', 'utf-8'); + $root = $dom->createElement('d:root'); + $root->setAttribute('xmlns:d','DAV:'); + $dom->appendChild($root); + $prop->serialize($server, $root); + + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:supported-privilege' => 1, + '/d:root/d:supported-privilege/d:privilege' => 1, + '/d:root/d:supported-privilege/d:privilege/d:all' => 1, + '/d:root/d:supported-privilege/d:abstract' => 1, + '/d:root/d:supported-privilege/d:supported-privilege' => 2, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege' => 2, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege/d:read' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:privilege/d:write' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege' => 8, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege' => 8, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:read-acl' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:read-current-user-privilege-set' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:write-content' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:write-properties' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:write-acl' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:bind' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:unbind' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:privilege/d:unlock' => 1, + '/d:root/d:supported-privilege/d:supported-privilege/d:supported-privilege/d:abstract' => 8, + ); + + + // reloading because php dom sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + + function testACL() { + + $plugin = new Plugin(); + + $nodes = array( + new MockACLNode('foo', array( + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ) + )), + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('admin','principals/admin'), + )), + + ); + + $server = new DAV\Server($nodes); + $server->addPlugin($plugin); + $authPlugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'realm'); + $server->addPlugin($authPlugin); + + // Force login + $authPlugin->beforeMethod('BLA','foo'); + + $requestedProperties = array( + '{DAV:}acl', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + + $this->assertNull($plugin->beforeGetProperties('foo', $nodes[0], $requestedProperties, $returnedProperties)); + + $this->assertEquals(1,count($returnedProperties[200]),'The {DAV:}acl property did not return from the list. Full list: ' . print_r($returnedProperties,true)); + $this->assertArrayHasKey('{DAV:}acl',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Property\\ACL', $returnedProperties[200]['{DAV:}acl']); + + } + + function testACLRestrictions() { + + $plugin = new Plugin(); + + $nodes = array( + new MockACLNode('foo', array( + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ) + )), + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('admin','principals/admin'), + )), + + ); + + $server = new DAV\Server($nodes); + $server->addPlugin($plugin); + $authPlugin = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'realm'); + $server->addPlugin($authPlugin); + + // Force login + $authPlugin->beforeMethod('BLA','foo'); + + $requestedProperties = array( + '{DAV:}acl-restrictions', + ); + + $returnedProperties = array( + 200 => array(), + 404 => array(), + ); + + + $this->assertNull($plugin->beforeGetProperties('foo', $nodes[0], $requestedProperties, $returnedProperties)); + + $this->assertEquals(1,count($returnedProperties[200]),'The {DAV:}acl-restrictions property did not return from the list. Full list: ' . print_r($returnedProperties,true)); + $this->assertArrayHasKey('{DAV:}acl-restrictions',$returnedProperties[200]); + $this->assertInstanceOf('Sabre\\DAVACL\\Property\\ACLRestrictions', $returnedProperties[200]['{DAV:}acl-restrictions']); + + } + + function testAlternateUriSet() { + + $tree = array( + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('user','principals/user'), + )), + ); + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend(),'realm'); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}alternate-URI-set', + ); + $returnedProperties = array(); + + $result = $plugin->beforeGetProperties('principals/user',$principal,$requestedProperties,$returnedProperties); + + $this->assertNull($result); + + $this->assertTrue(isset($returnedProperties[200])); + $this->assertTrue(isset($returnedProperties[200]['{DAV:}alternate-URI-set'])); + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $returnedProperties[200]['{DAV:}alternate-URI-set']); + + $this->assertEquals(array(), $returnedProperties[200]['{DAV:}alternate-URI-set']->getHrefs()); + + } + + function testPrincipalURL() { + + $tree = array( + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('user','principals/user'), + )), + ); + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend(),'realm'); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}principal-URL', + ); + $returnedProperties = array(); + + $result = $plugin->beforeGetProperties('principals/user',$principal,$requestedProperties,$returnedProperties); + + $this->assertNull($result); + + $this->assertTrue(isset($returnedProperties[200])); + $this->assertTrue(isset($returnedProperties[200]['{DAV:}principal-URL'])); + $this->assertInstanceOf('Sabre\\DAV\\Property\\Href', $returnedProperties[200]['{DAV:}principal-URL']); + + $this->assertEquals('principals/user/', $returnedProperties[200]['{DAV:}principal-URL']->getHref()); + + } + + function testGroupMemberSet() { + + $tree = array( + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('user','principals/user'), + )), + ); + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend(),'realm'); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}group-member-set', + ); + $returnedProperties = array(); + + $result = $plugin->beforeGetProperties('principals/user',$principal,$requestedProperties,$returnedProperties); + + $this->assertNull($result); + + $this->assertTrue(isset($returnedProperties[200])); + $this->assertTrue(isset($returnedProperties[200]['{DAV:}group-member-set'])); + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $returnedProperties[200]['{DAV:}group-member-set']); + + $this->assertEquals(array(), $returnedProperties[200]['{DAV:}group-member-set']->getHrefs()); + + } + + function testGroupMemberShip() { + + $tree = array( + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('user','principals/user'), + )), + ); + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend(),'realm'); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}group-membership', + ); + $returnedProperties = array(); + + $result = $plugin->beforeGetProperties('principals/user',$principal,$requestedProperties,$returnedProperties); + + $this->assertNull($result); + + $this->assertTrue(isset($returnedProperties[200])); + $this->assertTrue(isset($returnedProperties[200]['{DAV:}group-membership'])); + $this->assertInstanceOf('Sabre\\DAV\\Property\\HrefList', $returnedProperties[200]['{DAV:}group-membership']); + + $this->assertEquals(array(), $returnedProperties[200]['{DAV:}group-membership']->getHrefs()); + + } + + function testGetDisplayName() { + + $tree = array( + new DAV\SimpleCollection('principals', array( + $principal = new MockPrincipal('user','principals/user'), + )), + ); + + $fakeServer = new DAV\Server($tree); + //$plugin = new DAV\Auth\Plugin(new DAV\Auth\MockBackend(),'realm'); + //$fakeServer->addPlugin($plugin); + $plugin = new Plugin(); + $fakeServer->addPlugin($plugin); + + $requestedProperties = array( + '{DAV:}displayname', + ); + $returnedProperties = array(); + + $result = $plugin->beforeGetProperties('principals/user',$principal,$requestedProperties,$returnedProperties); + + $this->assertNull($result); + + $this->assertTrue(isset($returnedProperties[200])); + $this->assertTrue(isset($returnedProperties[200]['{DAV:}displayname'])); + + $this->assertEquals('user', $returnedProperties[200]['{DAV:}displayname']); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php new file mode 100644 index 00000000..53568654 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PluginUpdatePropertiesTest.php @@ -0,0 +1,127 @@ +addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', array( + '{DAV:}foo' => 'bar', + )); + + $expected = array( + 'href' => 'foo', + '403' => array( + '{DAV:}foo' => null, + ), + ); + + $this->assertEquals($expected, $result); + + } + + public function testRemoveGroupMembers() { + + $tree = array( + new MockPrincipal('foo','foo'), + ); + $server = new DAV\Server($tree); + $server->addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', array( + '{DAV:}group-member-set' => null, + )); + + $expected = array( + 'href' => 'foo', + '200' => array( + '{DAV:}group-member-set' => null, + ), + ); + + $this->assertEquals($expected, $result); + $this->assertEquals(array(),$tree[0]->getGroupMemberSet()); + + } + + public function testSetGroupMembers() { + + $tree = array( + new MockPrincipal('foo','foo'), + ); + $server = new DAV\Server($tree); + $server->addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', array( + '{DAV:}group-member-set' => new DAV\Property\HrefList(array('/bar','/baz'), true), + )); + + $expected = array( + 'href' => 'foo', + '200' => array( + '{DAV:}group-member-set' => null, + ), + ); + + $this->assertEquals($expected, $result); + $this->assertEquals(array('bar','baz'),$tree[0]->getGroupMemberSet()); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + public function testSetBadValue() { + + $tree = array( + new MockPrincipal('foo','foo'), + ); + $server = new DAV\Server($tree); + $server->addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', array( + '{DAV:}group-member-set' => new \StdClass(), + )); + + } + + public function testSetBadNode() { + + $tree = array( + new DAV\SimpleCollection('foo'), + ); + $server = new DAV\Server($tree); + $server->addPlugin(new Plugin()); + + $result = $server->updateProperties('foo', array( + '{DAV:}group-member-set' => new DAV\Property\HrefList(array('/bar','/baz'),false), + '{DAV:}bar' => 'baz', + )); + + $expected = array( + 'href' => 'foo', + '403' => array( + '{DAV:}group-member-set' => null, + ), + '424' => array( + '{DAV:}bar' => null, + ), + ); + + $this->assertEquals($expected, $result); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php new file mode 100644 index 00000000..3fe75ca0 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/AbstractPDOTest.php @@ -0,0 +1,178 @@ +getPDO(); + $backend = new PDO($pdo); + $this->assertTrue($backend instanceof PDO); + + } + + /** + * @depends testConstruct + */ + function testGetPrincipalsByPrefix() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $expected = array( + array( + 'uri' => 'principals/user', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + '{DAV:}displayname' => 'User', + ), + array( + 'uri' => 'principals/group', + '{http://sabredav.org/ns}email-address' => 'group@example.org', + '{DAV:}displayname' => 'Group', + ), + ); + + $this->assertEquals($expected, $backend->getPrincipalsByPrefix('principals')); + $this->assertEquals(array(), $backend->getPrincipalsByPrefix('foo')); + + } + + /** + * @depends testConstruct + */ + function testGetPrincipalByPath() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $expected = array( + 'id' => 1, + 'uri' => 'principals/user', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + '{DAV:}displayname' => 'User', + ); + + $this->assertEquals($expected, $backend->getPrincipalByPath('principals/user')); + $this->assertEquals(null, $backend->getPrincipalByPath('foo')); + + } + + function testGetGroupMemberSet() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $expected = array('principals/user'); + + $this->assertEquals($expected,$backend->getGroupMemberSet('principals/group')); + + } + + function testGetGroupMembership() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + $expected = array('principals/group'); + + $this->assertEquals($expected,$backend->getGroupMembership('principals/user')); + + } + + function testSetGroupMemberSet() { + + $pdo = $this->getPDO(); + + // Start situation + $backend = new PDO($pdo); + $this->assertEquals(array('principals/user'), $backend->getGroupMemberSet('principals/group')); + + // Removing all principals + $backend->setGroupMemberSet('principals/group', array()); + $this->assertEquals(array(), $backend->getGroupMemberSet('principals/group')); + + // Adding principals again + $backend->setGroupMemberSet('principals/group', array('principals/user')); + $this->assertEquals(array('principals/user'), $backend->getGroupMemberSet('principals/group')); + + + } + + function testSearchPrincipals() { + + $pdo = $this->getPDO(); + + $backend = new PDO($pdo); + + $result = $backend->searchPrincipals('principals', array('{DAV:}blabla' => 'foo')); + $this->assertEquals(array(), $result); + + $result = $backend->searchPrincipals('principals', array('{DAV:}displayname' => 'ou')); + $this->assertEquals(array('principals/group'), $result); + + $result = $backend->searchPrincipals('principals', array('{DAV:}displayname' => 'UsEr', '{http://sabredav.org/ns}email-address' => 'USER@EXAMPLE')); + $this->assertEquals(array('principals/user'), $result); + + $result = $backend->searchPrincipals('mom', array('{DAV:}displayname' => 'UsEr', '{http://sabredav.org/ns}email-address' => 'USER@EXAMPLE')); + $this->assertEquals(array(), $result); + + } + + function testUpdatePrincipal() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $result = $backend->updatePrincipal('principals/user', array( + '{DAV:}displayname' => 'pietje', + '{http://sabredav.org/ns}vcard-url' => 'blabla', + )); + + $this->assertTrue($result); + + $this->assertEquals(array( + 'id' => 1, + 'uri' => 'principals/user', + '{DAV:}displayname' => 'pietje', + '{http://sabredav.org/ns}vcard-url' => 'blabla', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + ), $backend->getPrincipalByPath('principals/user')); + + } + + function testUpdatePrincipalUnknownField() { + + $pdo = $this->getPDO(); + $backend = new PDO($pdo); + + $result = $backend->updatePrincipal('principals/user', array( + '{DAV:}displayname' => 'pietje', + '{http://sabredav.org/ns}vcard-url' => 'blabla', + '{DAV:}unknown' => 'foo', + )); + + $this->assertEquals(array( + 424 => array( + '{DAV:}displayname' => null, + '{http://sabredav.org/ns}vcard-url' => null, + ), + 403 => array( + '{DAV:}unknown' => null, + ), + ), $result); + + $this->assertEquals(array( + 'id' => '1', + 'uri' => 'principals/user', + '{DAV:}displayname' => 'User', + '{http://sabredav.org/ns}email-address' => 'user@example.org', + ), $backend->getPrincipalByPath('principals/user')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php new file mode 100644 index 00000000..354446e3 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/Mock.php @@ -0,0 +1,184 @@ +principals = array( + array( + 'uri' => 'principals/user1', + '{DAV:}displayname' => 'User 1', + '{http://sabredav.org/ns}email-address' => 'user1.sabredav@sabredav.org', + '{http://sabredav.org/ns}vcard-url' => 'addressbooks/user1/book1/vcard1.vcf', + ), + array( + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Admin', + ), + array( + 'uri' => 'principals/user2', + '{DAV:}displayname' => 'User 2', + '{http://sabredav.org/ns}email-address' => 'user2.sabredav@sabredav.org', + ), + ); + + + } + + function getPrincipalsByPrefix($prefix) { + + $prefix = trim($prefix,'/') . '/'; + $return = array(); + + foreach($this->principals as $principal) { + + if (strpos($principal['uri'], $prefix)!==0) continue; + + $return[] = $principal; + + } + + return $return; + + } + + function addPrincipal(array $principal) { + + $this->principals[] = $principal; + + } + + function getPrincipalByPath($path) { + + foreach($this->getPrincipalsByPrefix('principals') as $principal) { + if ($principal['uri'] === $path) return $principal; + } + + } + + function searchPrincipals($prefixPath, array $searchProperties) { + + $matches = array(); + foreach($this->getPrincipalsByPrefix($prefixPath) as $principal) { + + foreach($searchProperties as $key=>$value) { + + if (!isset($principal[$key])) { + continue 2; + } + if (mb_stripos($principal[$key],$value, 0, 'UTF-8')===false) { + continue 2; + } + + } + $matches[] = $principal['uri']; + + } + return $matches; + + } + + function getGroupMemberSet($path) { + + return isset($this->groupMembers[$path]) ? $this->groupMembers[$path] : array(); + + } + + function getGroupMembership($path) { + + $membership = array(); + foreach($this->groupMembers as $group=>$members) { + if (in_array($path, $members)) $membership[] = $group; + } + return $membership; + + } + + function setGroupMemberSet($path, array $members) { + + $this->groupMembers[$path] = $members; + + } + + /** + * Updates one ore more webdav properties on a principal. + * + * The list of mutations is supplied as an array. Each key in the array is + * a propertyname, such as {DAV:}displayname. + * + * Each value is the actual value to be updated. If a value is null, it + * must be deleted. + * + * This method should be atomic. It must either completely succeed, or + * completely fail. Success and failure can simply be returned as 'true' or + * 'false'. + * + * It is also possible to return detailed failure information. In that case + * an array such as this should be returned: + * + * array( + * 200 => array( + * '{DAV:}prop1' => null, + * ), + * 201 => array( + * '{DAV:}prop2' => null, + * ), + * 403 => array( + * '{DAV:}prop3' => null, + * ), + * 424 => array( + * '{DAV:}prop4' => null, + * ), + * ); + * + * In this previous example prop1 was successfully updated or deleted, and + * prop2 was succesfully created. + * + * prop3 failed to update due to '403 Forbidden' and because of this prop4 + * also could not be updated with '424 Failed dependency'. + * + * This last example was actually incorrect. While 200 and 201 could appear + * in 1 response, if there's any error (403) the other properties should + * always fail with 423 (failed dependency). + * + * But anyway, if you don't want to scratch your head over this, just + * return true or false. + * + * @param string $path + * @param array $mutations + * @return array|bool + */ + public function updatePrincipal($path, $mutations) { + + $value = null; + foreach($this->principals as $principalIndex=>$value) { + if ($value['uri'] === $path) { + $principal = $value; + break; + } + } + if (!$principal) return false; + + foreach($mutations as $prop=>$value) { + + if (is_null($value) && isset($principal[$prop])) { + unset($principal[$prop]); + } else { + $principal[$prop] = $value; + } + + } + + $this->principals[$principalIndex] = $principal; + + return true; + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php new file mode 100644 index 00000000..84ba062c --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOMySQLTest.php @@ -0,0 +1,45 @@ +markTestSkipped('MySQL driver is not available, or not properly configured'); + $pdo = \Sabre\TestUtil::getMySQLDB(); + if (!$pdo) $this->markTestSkipped('Could not connect to MySQL database'); + $pdo->query("DROP TABLE IF EXISTS principals"); + $pdo->query(" +create table principals ( + id integer unsigned not null primary key auto_increment, + uri varchar(50), + email varchar(80), + displayname VARCHAR(80), + vcardurl VARCHAR(80), + unique(uri) +);"); + + $pdo->query("INSERT INTO principals (uri,email,displayname) VALUES ('principals/user','user@example.org','User')"); + $pdo->query("INSERT INTO principals (uri,email,displayname) VALUES ('principals/group','group@example.org','Group')"); + $pdo->query("DROP TABLE IF EXISTS groupmembers"); + $pdo->query("CREATE TABLE groupmembers ( + id INTEGER UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, + principal_id INTEGER UNSIGNED NOT NULL, + member_id INTEGER UNSIGNED NOT NULL, + UNIQUE(principal_id, member_id) + );"); + + $pdo->query("INSERT INTO groupmembers (principal_id,member_id) VALUES (2,1)"); + + return $pdo; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php new file mode 100644 index 00000000..192e188f --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalBackend/PDOSqliteTest.php @@ -0,0 +1,42 @@ +markTestSkipped('SQLite driver is not available'); + $pdo = new \PDO('sqlite:'.SABRE_TEMPDIR.'/pdobackend'); + $pdo->setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + $pdo->query('CREATE TABLE principals (id INTEGER PRIMARY KEY ASC, uri TEXT, email VARCHAR(80), displayname VARCHAR(80), vcardurl VARCHAR(80))'); + $pdo->query('INSERT INTO principals VALUES (1, "principals/user","user@example.org","User",null)'); + $pdo->query('INSERT INTO principals VALUES (2, "principals/group","group@example.org","Group",null)'); + + $pdo->query("CREATE TABLE groupmembers ( + id INTEGER PRIMARY KEY ASC, + principal_id INT, + member_id INT, + UNIQUE(principal_id, member_id) + );"); + + $pdo->query("INSERT INTO groupmembers (principal_id,member_id) VALUES (2,1)"); + + return $pdo; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php new file mode 100644 index 00000000..10b0c04d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalCollectionTest.php @@ -0,0 +1,52 @@ +assertTrue($pc instanceof PrincipalCollection); + + $this->assertEquals('principals',$pc->getName()); + + } + + /** + * @depends testBasic + */ + public function testGetChildren() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + + $children = $pc->getChildren(); + $this->assertTrue(is_array($children)); + + foreach($children as $child) { + $this->assertTrue($child instanceof IPrincipal); + } + + } + + /** + * @depends testBasic + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testGetChildrenDisable() { + + $backend = new PrincipalBackend\Mock(); + $pc = new PrincipalCollection($backend); + $pc->disableListing = true; + + $children = $pc->getChildren(); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php new file mode 100644 index 00000000..9c3be4f9 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalPropertySearchTest.php @@ -0,0 +1,246 @@ +addChild($principals); + + $fakeServer = new DAV\Server(new DAV\ObjectTree($dir)); + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $fakeServer->debugExceptions = true; + $plugin = new MockPlugin($backend,'realm'); + $plugin->allowAccessToNodesWithoutACL = true; + + $this->assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testDepth1() { + + $xml = ' + + + + + + user + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '1', + 'REQUEST_URI' => '/principals', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request', $server->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + } + + + function testUnknownSearchField() { + + $xml = ' + + + + + + user + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'Vary' => 'Brief,Prefer', + ), $server->httpResponse->headers); + + } + + function testCorrect() { + + $xml = ' + + + + + + + user + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'Vary' => 'Brief,Prefer', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 2, + '/d:multistatus/d:response/d:href' => 2, + '/d:multistatus/d:response/d:propstat' => 4, + '/d:multistatus/d:response/d:propstat/d:prop' => 4, + '/d:multistatus/d:response/d:propstat/d:prop/d:displayname' => 2, + '/d:multistatus/d:response/d:propstat/d:prop/d:getcontentlength' => 2, + '/d:multistatus/d:response/d:propstat/d:status' => 4, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + function testWrongUri() { + + $xml = ' + + + + + + user + + + + + +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 207 Multi-Status', $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + 'Vary' => 'Brief,Prefer', + ), $server->httpResponse->headers); + + + $check = array( + '/d:multistatus', + '/d:multistatus/d:response' => 0, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } +} + +class MockPlugin extends Plugin { + + function getCurrentUserPrivilegeSet($node) { + + return array( + '{DAV:}read', + '{DAV:}write', + ); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php new file mode 100644 index 00000000..412389e8 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalSearchPropertySetTest.php @@ -0,0 +1,135 @@ +addChild($principals); + + $fakeServer = new DAV\Server(new DAV\ObjectTree($dir)); + $fakeServer->httpResponse = new HTTP\ResponseMock(); + $plugin = new Plugin($backend,'realm'); + $this->assertTrue($plugin instanceof Plugin); + $fakeServer->addPlugin($plugin); + $this->assertEquals($plugin, $fakeServer->getPlugin('acl')); + + return $fakeServer; + + } + + function testDepth1() { + + $xml = ' +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '1', + 'REQUEST_URI' => '/principals', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request', $server->httpResponse->status); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + } + + function testDepthIncorrectXML() { + + $xml = ' +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 400 Bad request', $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + } + + function testCorrect() { + + $xml = ' +'; + + $serverVars = array( + 'REQUEST_METHOD' => 'REPORT', + 'HTTP_DEPTH' => '0', + 'REQUEST_URI' => '/principals', + ); + + $request = new HTTP\Request($serverVars); + $request->setBody($xml); + + $server = $this->getServer(); + $server->httpRequest = $request; + + $server->exec(); + + $this->assertEquals('HTTP/1.1 200 OK', $server->httpResponse->status, $server->httpResponse->body); + $this->assertEquals(array( + 'Content-Type' => 'application/xml; charset=utf-8', + ), $server->httpResponse->headers); + + + $check = array( + '/d:principal-search-property-set', + '/d:principal-search-property-set/d:principal-search-property' => 2, + '/d:principal-search-property-set/d:principal-search-property/d:prop' => 2, + '/d:principal-search-property-set/d:principal-search-property/d:prop/d:displayname' => 1, + '/d:principal-search-property-set/d:principal-search-property/d:prop/s:email-address' => 1, + '/d:principal-search-property-set/d:principal-search-property/d:description' => 2, + ); + + $xml = simplexml_load_string($server->httpResponse->body); + $xml->registerXPathNamespace('d','DAV:'); + $xml->registerXPathNamespace('s','http://sabredav.org/ns'); + foreach($check as $v1=>$v2) { + + $xpath = is_int($v1)?$v2:$v1; + + $result = $xml->xpath($xpath); + + $count = 1; + if (!is_int($v1)) $count = $v2; + + $this->assertEquals($count,count($result), 'we expected ' . $count . ' appearances of ' . $xpath . ' . We found ' . count($result) . '. Full response body: ' . $server->httpResponse->body); + + } + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php new file mode 100644 index 00000000..2d437113 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/PrincipalTest.php @@ -0,0 +1,204 @@ + 'principals/admin')); + $this->assertTrue($principal instanceof Principal); + + } + + /** + * @expectedException Sabre\DAV\Exception + */ + public function testConstructNoUri() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array()); + + } + + public function testGetName() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals('admin',$principal->getName()); + + } + + public function testGetDisplayName() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals('admin',$principal->getDisplayname()); + + $principal = new Principal($principalBackend, array( + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin' + )); + $this->assertEquals('Mr. Admin',$principal->getDisplayname()); + + } + + public function testGetProperties() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array( + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin', + '{http://www.example.org/custom}custom' => 'Custom', + '{http://sabredav.org/ns}email-address' => 'admin@example.org', + )); + + $keys = array( + '{DAV:}displayname', + '{http://www.example.org/custom}custom', + '{http://sabredav.org/ns}email-address', + ); + $props = $principal->getProperties($keys); + + foreach($keys as $key) $this->assertArrayHasKey($key,$props); + + $this->assertEquals('Mr. Admin',$props['{DAV:}displayname']); + + $this->assertEquals('admin@example.org', $props['{http://sabredav.org/ns}email-address']); + } + + public function testUpdateProperties() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $result = $principal->updateProperties(array('{DAV:}yourmom'=>'test')); + $this->assertEquals(true,$result); + + } + + public function testGetPrincipalUrl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals('principals/admin',$principal->getPrincipalUrl()); + + } + + public function testGetAlternateUriSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array( + 'uri' => 'principals/admin', + '{DAV:}displayname' => 'Mr. Admin', + '{http://www.example.org/custom}custom' => 'Custom', + '{http://sabredav.org/ns}email-address' => 'admin@example.org', + '{DAV:}alternate-URI-set' => array( + 'mailto:admin+1@example.org', + 'mailto:admin+2@example.org', + 'mailto:admin@example.org', + ), + )); + + $expected = array( + 'mailto:admin+1@example.org', + 'mailto:admin+2@example.org', + 'mailto:admin@example.org', + ); + + $this->assertEquals($expected,$principal->getAlternateUriSet()); + + } + public function testGetAlternateUriSetEmpty() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array( + 'uri' => 'principals/admin', + )); + + $expected = array(); + + $this->assertEquals($expected,$principal->getAlternateUriSet()); + + } + + public function testGetGroupMemberSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals(array(),$principal->getGroupMemberSet()); + + } + public function testGetGroupMembership() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals(array(),$principal->getGroupMembership()); + + } + + public function testSetGroupMemberSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $principal->setGroupMemberSet(array('principals/foo')); + + $this->assertEquals(array( + 'principals/admin' => array('principals/foo'), + ), $principalBackend->groupMembers); + + } + + public function testGetOwner() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals('principals/admin',$principal->getOwner()); + + } + + public function testGetGroup() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertNull($principal->getGroup()); + + } + + public function testGetACl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertEquals(array( + array( + 'privilege' => '{DAV:}read', + 'principal' => 'principals/admin', + 'protected' => true, + ) + ),$principal->getACL()); + + } + + /** + * @expectedException Sabre\DAV\Exception\MethodNotAllowed + */ + public function testSetACl() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $principal->setACL(array()); + + } + + public function testGetSupportedPrivilegeSet() { + + $principalBackend = new PrincipalBackend\Mock(); + $principal = new Principal($principalBackend, array('uri' => 'principals/admin')); + $this->assertNull($principal->getSupportedPrivilegeSet()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLRestrictionsTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLRestrictionsTest.php new file mode 100644 index 00000000..72a2f36a --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLRestrictionsTest.php @@ -0,0 +1,35 @@ +createElementNS('DAV:','d:root'); + + $dom->appendChild($root); + + $acl = new AclRestrictions(); + $acl->serialize(new DAV\Server(), $root); + + $xml = $dom->saveXML(); + $expected = ' + +'; + $this->assertEquals($expected, $xml); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLTest.php new file mode 100644 index 00000000..7f2014df --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/ACLTest.php @@ -0,0 +1,335 @@ +createElementNS('DAV:','d:root'); + + $dom->appendChild($root); + + $acl = new Acl(array()); + $acl->serialize(new DAV\Server(), $root); + + $xml = $dom->saveXML(); + $expected = ' + +'; + $this->assertEquals($expected, $xml); + + } + + function testSerialize() { + + $dom = new \DOMDocument('1.0'); + $root = $dom->createElementNS('DAV:','d:root'); + + $dom->appendChild($root); + + $privileges = array( + array( + 'principal' => 'principals/evert', + 'privilege' => '{DAV:}write', + 'uri' => 'articles', + ), + array( + 'principal' => 'principals/foo', + 'privilege' => '{DAV:}read', + 'uri' => 'articles', + 'protected' => true, + ), + ); + + $acl = new Acl($privileges); + $acl->serialize(new DAV\Server(), $root); + + $dom->formatOutput = true; + + $xml = $dom->saveXML(); + $expected = ' + + + + /principals/evert/ + + + + + + + + + + /principals/foo/ + + + + + + + + + +'; + $this->assertEquals($expected, $xml); + + } + + function testSerializeSpecialPrincipals() { + + $dom = new \DOMDocument('1.0'); + $root = $dom->createElementNS('DAV:','d:root'); + + $dom->appendChild($root); + + $privileges = array( + array( + 'principal' => '{DAV:}authenticated', + 'privilege' => '{DAV:}write', + 'uri' => 'articles', + ), + array( + 'principal' => '{DAV:}unauthenticated', + 'privilege' => '{DAV:}write', + 'uri' => 'articles', + ), + array( + 'principal' => '{DAV:}all', + 'privilege' => '{DAV:}write', + 'uri' => 'articles', + ), + + ); + + $acl = new Acl($privileges); + $acl->serialize(new DAV\Server(), $root); + + $dom->formatOutput = true; + + $xml = $dom->saveXML(); + $expected = ' + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +'; + $this->assertEquals($expected, $xml); + + } + + function testUnserialize() { + + $source = ' + + + + /principals/evert/ + + + + + + + + + + /principals/foo/ + + + + + + + + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + $result = Acl::unserialize($dom->firstChild); + + $this->assertInstanceOf('Sabre\\DAVACL\\Property\\ACL', $result); + + $expected = array( + array( + 'principal' => '/principals/evert/', + 'protected' => false, + 'privilege' => '{DAV:}write', + ), + array( + 'principal' => '/principals/foo/', + 'protected' => true, + 'privilege' => '{DAV:}read', + ), + ); + + $this->assertEquals($expected, $result->getPrivileges()); + + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testUnserializeNoPrincipal() { + + $source = ' + + + + + + + + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + Acl::unserialize($dom->firstChild); + + } + + function testUnserializeOtherPrincipal() { + + $source = ' + + + + + + + + + + + + + + + + + + + + + + + + + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + $result = Acl::unserialize($dom->firstChild); + + $this->assertInstanceOf('Sabre\\DAVACL\\Property\\Acl', $result); + + $expected = array( + array( + 'principal' => '{DAV:}authenticated', + 'protected' => false, + 'privilege' => '{DAV:}write', + ), + array( + 'principal' => '{DAV:}unauthenticated', + 'protected' => false, + 'privilege' => '{DAV:}write', + ), + array( + 'principal' => '{DAV:}all', + 'protected' => false, + 'privilege' => '{DAV:}write', + ), + ); + + $this->assertEquals($expected, $result->getPrivileges()); + + + } + + /** + * @expectedException Sabre\DAV\Exception\NotImplemented + */ + function testUnserializeDeny() { + + $source = ' + + + + + + + + /principals/evert + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + Acl::unserialize($dom->firstChild); + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testUnserializeMissingPriv() { + + $source = ' + + + + + + /principals/evert + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + Acl::unserialize($dom->firstChild); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/CurrentUserPrivilegeSetTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/CurrentUserPrivilegeSetTest.php new file mode 100644 index 00000000..e71addb6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/CurrentUserPrivilegeSetTest.php @@ -0,0 +1,68 @@ +createElementNS('DAV:','d:root'); + $dom->appendChild($root); + + $prop->serialize($server, $root); + + $xpaths = array( + '/d:root' => 1, + '/d:root/d:privilege' => 2, + '/d:root/d:privilege/d:read' => 1, + '/d:root/d:privilege/d:write' => 1, + ); + + // Reloading because PHP DOM sucks + $dom2 = new \DOMDocument('1.0', 'utf-8'); + $dom2->loadXML($dom->saveXML()); + + $dxpath = new \DOMXPath($dom2); + $dxpath->registerNamespace('d','DAV:'); + foreach($xpaths as $xpath=>$count) { + + $this->assertEquals($count, $dxpath->query($xpath)->length, 'Looking for : ' . $xpath . ', we could only find ' . $dxpath->query($xpath)->length . ' elements, while we expected ' . $count); + + } + + } + + function testUnserialize() { + + $source = ' + + + + + + + + +'; + + $dom = DAV\XMLUtil::loadDOMDocument($source); + $result = CurrentUserPrivilegeSet::unserialize($dom->firstChild, array()); + $this->assertTrue($result->has('{DAV:}read')); + $this->assertTrue($result->has('{DAV:}write-properties')); + $this->assertFalse($result->has('{DAV:}bind')); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/PrincipalTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/PrincipalTest.php new file mode 100644 index 00000000..be12c79e --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/PrincipalTest.php @@ -0,0 +1,181 @@ +assertEquals(Principal::UNAUTHENTICATED, $principal->getType()); + $this->assertNull($principal->getHref()); + + $principal = new Principal(Principal::AUTHENTICATED); + $this->assertEquals(Principal::AUTHENTICATED, $principal->getType()); + $this->assertNull($principal->getHref()); + + $principal = new Principal(Principal::HREF,'admin'); + $this->assertEquals(Principal::HREF, $principal->getType()); + $this->assertEquals('admin',$principal->getHref()); + + } + + /** + * @depends testSimple + * @expectedException Sabre\DAV\Exception + */ + function testNoHref() { + + $principal = new Principal(Principal::HREF); + + } + + /** + * @depends testSimple + */ + function testSerializeUnAuthenticated() { + + $prin = new Principal(Principal::UNAUTHENTICATED); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:principal'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $objectTree = new DAV\ObjectTree(new DAV\SimpleCollection('rootdir')); + $server = new DAV\Server($objectTree); + + $prin->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +' +', $xml); + + } + + + /** + * @depends testSerializeUnAuthenticated + */ + function testSerializeAuthenticated() { + + $prin = new Principal(Principal::AUTHENTICATED); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:principal'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $objectTree = new DAV\ObjectTree(new DAV\SimpleCollection('rootdir')); + $server = new DAV\Server($objectTree); + + $prin->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +' +', $xml); + + } + + + /** + * @depends testSerializeUnAuthenticated + */ + function testSerializeHref() { + + $prin = new Principal(Principal::HREF,'principals/admin'); + + $doc = new \DOMDocument(); + $root = $doc->createElement('d:principal'); + $root->setAttribute('xmlns:d','DAV:'); + + $doc->appendChild($root); + $objectTree = new DAV\ObjectTree(new DAV\SimpleCollection('rootdir')); + $server = new DAV\Server($objectTree); + + $prin->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'/principals/admin' . +' +', $xml); + + } + + function testUnserializeHref() { + + $xml = ' +' . +'/principals/admin' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $principal = Principal::unserialize($dom->firstChild); + $this->assertEquals(Principal::HREF, $principal->getType()); + $this->assertEquals('/principals/admin', $principal->getHref()); + + } + + function testUnserializeAuthenticated() { + + $xml = ' +' . +' ' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $principal = Principal::unserialize($dom->firstChild); + $this->assertEquals(Principal::AUTHENTICATED, $principal->getType()); + + } + + function testUnserializeUnauthenticated() { + + $xml = ' +' . +' ' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + $principal = Principal::unserialize($dom->firstChild); + $this->assertEquals(Principal::UNAUTHENTICATED, $principal->getType()); + + } + + /** + * @expectedException Sabre\DAV\Exception\BadRequest + */ + function testUnserializeUnknown() { + + $xml = ' +' . +' ' . +''; + + $dom = DAV\XMLUtil::loadDOMDocument($xml); + + Principal::unserialize($dom->firstChild); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/SupportedPrivilegeSetTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/SupportedPrivilegeSetTest.php new file mode 100644 index 00000000..94331633 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/Property/SupportedPrivilegeSetTest.php @@ -0,0 +1,106 @@ + '{DAV:}all', + )); + + } + + + /** + * @depends testSimple + */ + function testSerializeSimple() { + + $prop = new SupportedPrivilegeSet(array( + 'privilege' => '{DAV:}all', + )); + + $doc = new \DOMDocument(); + $root = $doc->createElementNS('DAV:', 'd:supported-privilege-set'); + + $doc->appendChild($root); + + $server = new DAV\Server(); + $prop->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'' . +'' . +'' . +'' . +' +', $xml); + + } + + /** + * @depends testSimple + */ + function testSerializeAggregate() { + + $prop = new SupportedPrivilegeSet(array( + 'privilege' => '{DAV:}all', + 'abstract' => true, + 'aggregates' => array( + array( + 'privilege' => '{DAV:}read', + ), + array( + 'privilege' => '{DAV:}write', + 'description' => 'booh', + ), + ), + )); + + $doc = new \DOMDocument(); + $root = $doc->createElementNS('DAV:', 'd:supported-privilege-set'); + + $doc->appendChild($root); + + $server = new DAV\Server(); + $prop->serialize($server, $root); + + $xml = $doc->saveXML(); + + $this->assertEquals( +' +' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'' . +'booh' . +'' . +'' . +' +', $xml); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php new file mode 100644 index 00000000..04ed5c33 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/SimplePluginTest.php @@ -0,0 +1,322 @@ +assertEquals('acl',$aclPlugin->getPluginName()); + $this->assertEquals( + array('access-control', 'calendarserver-principal-property-search'), + $aclPlugin->getFeatures() + ); + + $this->assertEquals( + array( + '{DAV:}expand-property', + '{DAV:}principal-property-search', + '{DAV:}principal-search-property-set' + ), + $aclPlugin->getSupportedReportSet('')); + + $this->assertEquals(array('ACL'), $aclPlugin->getMethods('')); + + } + + function testGetFlatPrivilegeSet() { + + $expected = array( + '{DAV:}all' => array( + 'privilege' => '{DAV:}all', + 'abstract' => true, + 'aggregates' => array( + '{DAV:}read', + '{DAV:}write', + ), + 'concrete' => null, + ), + '{DAV:}read' => array( + 'privilege' => '{DAV:}read', + 'abstract' => false, + 'aggregates' => array( + '{DAV:}read-acl', + '{DAV:}read-current-user-privilege-set', + ), + 'concrete' => '{DAV:}read', + ), + '{DAV:}read-acl' => array( + 'privilege' => '{DAV:}read-acl', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}read', + ), + '{DAV:}read-current-user-privilege-set' => array( + 'privilege' => '{DAV:}read-current-user-privilege-set', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}read', + ), + '{DAV:}write' => array( + 'privilege' => '{DAV:}write', + 'abstract' => false, + 'aggregates' => array( + '{DAV:}write-acl', + '{DAV:}write-properties', + '{DAV:}write-content', + '{DAV:}bind', + '{DAV:}unbind', + '{DAV:}unlock', + ), + 'concrete' => '{DAV:}write', + ), + '{DAV:}write-acl' => array( + 'privilege' => '{DAV:}write-acl', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + '{DAV:}write-properties' => array( + 'privilege' => '{DAV:}write-properties', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + '{DAV:}write-content' => array( + 'privilege' => '{DAV:}write-content', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + '{DAV:}unlock' => array( + 'privilege' => '{DAV:}unlock', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + '{DAV:}bind' => array( + 'privilege' => '{DAV:}bind', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + '{DAV:}unbind' => array( + 'privilege' => '{DAV:}unbind', + 'abstract' => true, + 'aggregates' => array(), + 'concrete' => '{DAV:}write', + ), + + ); + + $plugin = new Plugin(); + $server = new DAV\Server(); + $server->addPlugin($plugin); + $this->assertEquals($expected, $plugin->getFlatPrivilegeSet('')); + + } + + function testCurrentUserPrincipalsNotLoggedIn() { + + $acl = new Plugin(); + $server = new DAV\Server(); + $server->addPlugin($acl); + + $this->assertEquals(array(),$acl->getCurrentUserPrincipals()); + + } + + function testCurrentUserPrincipalsSimple() { + + $tree = array( + + new DAV\SimpleCollection('principals', array( + new MockPrincipal('admin','principals/admin'), + )) + + ); + + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->addPlugin($acl); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'SabreDAV'); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod('GET','/'); + + $this->assertEquals(array('principals/admin'),$acl->getCurrentUserPrincipals()); + + } + + function testCurrentUserPrincipalsGroups() { + + $tree = array( + + new DAV\SimpleCollection('principals', array( + new MockPrincipal('admin','principals/admin',array('principals/administrators', 'principals/everyone')), + new MockPrincipal('administrators','principals/administrators',array('principals/groups'), array('principals/admin')), + new MockPrincipal('everyone','principals/everyone',array(), array('principals/admin')), + new MockPrincipal('groups','principals/groups',array(), array('principals/administrators')), + )) + + ); + + $acl = new Plugin(); + $server = new DAV\Server($tree); + $server->addPlugin($acl); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'SabreDAV'); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod('GET','/'); + + $expected = array( + 'principals/admin', + 'principals/administrators', + 'principals/everyone', + 'principals/groups', + ); + + $this->assertEquals($expected,$acl->getCurrentUserPrincipals()); + + // The second one should trigger the cache and be identical + $this->assertEquals($expected,$acl->getCurrentUserPrincipals()); + + } + + function testGetACL() { + + $acl = array( + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ), + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ), + ); + + + $tree = array( + new MockACLNode('foo',$acl), + ); + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $server->addPlugin($aclPlugin); + + $this->assertEquals($acl,$aclPlugin->getACL('foo')); + + } + + function testGetCurrentUserPrivilegeSet() { + + $acl = array( + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ), + array( + 'principal' => 'principals/user1', + 'privilege' => '{DAV:}read', + ), + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ), + ); + + + $tree = array( + new MockACLNode('foo',$acl), + + new DAV\SimpleCollection('principals', array( + new MockPrincipal('admin','principals/admin'), + )), + + ); + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $server->addPlugin($aclPlugin); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'SabreDAV'); + $server->addPlugin($auth); + + //forcing login + $auth->beforeMethod('GET','/'); + + $expected = array( + '{DAV:}write', + '{DAV:}write-acl', + '{DAV:}write-properties', + '{DAV:}write-content', + '{DAV:}bind', + '{DAV:}unbind', + '{DAV:}unlock', + '{DAV:}read', + '{DAV:}read-acl', + '{DAV:}read-current-user-privilege-set', + ); + + $this->assertEquals($expected,$aclPlugin->getCurrentUserPrivilegeSet('foo')); + + } + + function testCheckPrivileges() { + + $acl = array( + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}read', + ), + array( + 'principal' => 'principals/user1', + 'privilege' => '{DAV:}read', + ), + array( + 'principal' => 'principals/admin', + 'privilege' => '{DAV:}write', + ), + ); + + + $tree = array( + new MockACLNode('foo',$acl), + + new DAV\SimpleCollection('principals', array( + new MockPrincipal('admin','principals/admin'), + )), + + ); + + $server = new DAV\Server($tree); + $aclPlugin = new Plugin(); + $server->addPlugin($aclPlugin); + + $auth = new DAV\Auth\Plugin(new DAV\Auth\Backend\Mock(),'SabreDAV'); + $server->addPlugin($auth); + + //forcing login + //$auth->beforeMethod('GET','/'); + + $this->assertFalse($aclPlugin->checkPrivileges('foo', array('{DAV:}read'), Plugin::R_PARENT, false)); + + } +} + + + + diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVACL/VersionTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/VersionTest.php new file mode 100644 index 00000000..c432527d --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVACL/VersionTest.php @@ -0,0 +1,17 @@ +assertEquals(-1, version_compare('1.0.0',$v)); + + $s = Version::STABILITY; + $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/DAVServerTest.php b/sources/vendor/sabre/dav/tests/Sabre/DAVServerTest.php new file mode 100644 index 00000000..207687d9 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/DAVServerTest.php @@ -0,0 +1,184 @@ +setUpBackends(); + $this->setUpTree(); + + $this->server = new DAV\Server($this->tree); + $this->server->debugExceptions = true; + + if ($this->setupCalDAV) { + $this->caldavPlugin = new CalDAV\Plugin(); + $this->server->addPlugin($this->caldavPlugin); + } + if ($this->setupCalDAVSharing) { + $this->caldavSharingPlugin = new CalDAV\SharingPlugin(); + $this->server->addPlugin($this->caldavSharingPlugin); + } + if ($this->setupCardDAV) { + $this->carddavPlugin = new CardDAV\Plugin(); + $this->server->addPlugin($this->carddavPlugin); + } + if ($this->setupACL) { + $this->aclPlugin = new DAVACL\Plugin(); + $this->server->addPlugin($this->aclPlugin); + } + if ($this->autoLogin) { + $authBackend = new DAV\Auth\Backend\Mock(); + $authBackend->defaultUser = $this->autoLogin; + $this->authPlugin = new DAV\Auth\Plugin($authBackend, 'SabreDAV'); + $this->server->addPlugin($this->authPlugin); + + // This will trigger the actual login procedure + $this->authPlugin->beforeMethod('OPTIONS','/'); + } + + } + + /** + * Makes a request, and returns a response object. + * + * You can either pass an instance of Sabre\HTTP\Request, or an array, + * which will then be used as the _SERVER array. + * + * @param array|\Sabre\HTTP\Request $request + * @return \Sabre\HTTP\Response + */ + function request($request) { + + if (is_array($request)) { + $request = new HTTP\Request($request); + } + $this->server->httpRequest = $request; + $this->server->httpResponse = new HTTP\ResponseMock(); + $this->server->exec(); + + return $this->server->httpResponse; + + } + + function setUpTree() { + + if ($this->setupCalDAV) { + $this->tree[] = new CalDAV\CalendarRootNode( + $this->principalBackend, + $this->caldavBackend + ); + } + if ($this->setupCardDAV) { + $this->tree[] = new CardDAV\AddressBookRoot( + $this->principalBackend, + $this->carddavBackend + ); + } + + if ($this->setupCardDAV || $this->setupCalDAV) { + $this->tree[] = new DAVACL\PrincipalCollection( + $this->principalBackend + ); + } + + } + + function setUpBackends() { + + if ($this->setupCalDAV && is_null($this->caldavBackend)) { + $this->caldavBackend = new CalDAV\Backend\Mock($this->caldavCalendars, $this->caldavCalendarObjects); + } + if ($this->setupCardDAV && is_null($this->carddavBackend)) { + $this->carddavBackend = new CardDAV\Backend\Mock($this->carddavAddressBooks, $this->carddavCards); + } + if ($this->setupCardDAV || $this->setupCalDAV) { + $this->principalBackend = new DAVACL\PrincipalBackend\Mock(); + } + + } + + + function assertHTTPStatus($expectedStatus, HTTP\Request $req) { + + $resp = $this->request($req); + $this->assertEquals($resp->getStatusMessage($expectedStatus), $resp->status,'Incorrect HTTP status received: ' . $resp->body); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/AWSAuthTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/AWSAuthTest.php new file mode 100644 index 00000000..569ec2e7 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/AWSAuthTest.php @@ -0,0 +1,242 @@ +response = new ResponseMock(); + $this->auth = new AWSAuth(); + $this->auth->setRealm(self::REALM); + $this->auth->setHTTPResponse($this->response); + + } + + public function testNoHeader() { + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + )); + + $this->auth->setHTTPRequest($request); + + $result = $this->auth->init(); + + $this->assertFalse($result,'No AWS Authorization header was supplied, so we should have gotten false'); + $this->assertEquals(AWSAuth::ERR_NOAWSHEADER,$this->auth->errorCode); + + } + + public function testIncorrectContentMD5() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:sig", + 'HTTP_CONTENT_MD5' => 'garbage', + 'REQUEST_URI' => '/', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWSAuth::ERR_MD5CHECKSUMWRONG,$this->auth->errorCode); + + } + + public function testNoDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content,true)); + + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:sig", + 'HTTP_CONTENT_MD5' => $contentMD5, + )); + + $request->setBody($content); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWSAuth::ERR_INVALIDDATEFORMAT,$this->auth->errorCode); + + } + + public function testFutureDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content,true)); + + $date = new \DateTime('@' . (time() + (60*20))); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:sig", + 'HTTP_CONTENT_MD5' => $contentMD5, + 'HTTP_DATE' => $date, + )); + + $request->setBody($content); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWSAuth::ERR_REQUESTTIMESKEWED,$this->auth->errorCode); + + } + + public function testPastDate() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content,true)); + + $date = new \DateTime('@' . (time() - (60*20))); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:sig", + 'HTTP_CONTENT_MD5' => $contentMD5, + 'HTTP_X_AMZ_DATE' => $date, + )); + + $request->setBody($content); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWSAuth::ERR_REQUESTTIMESKEWED,$this->auth->errorCode); + + } + + public function testIncorrectSignature() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + + $contentMD5 = base64_encode(md5($content,true)); + + $date = new \DateTime('now'); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:sig", + 'HTTP_CONTENT_MD5' => $contentMD5, + 'HTTP_X_AMZ_DATE' => $date, + 'REQUEST_URI' => '/', + )); + + $request->setBody($content); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertFalse($result); + $this->assertEquals(AWSAuth::ERR_INVALIDSIGNATURE,$this->auth->errorCode); + + } + + public function testValidRequest() { + + $accessKey = 'accessKey'; + $secretKey = 'secretKey'; + $content = 'thisisthebody'; + $contentMD5 = base64_encode(md5($content,true)); + + $date = new \DateTime('now'); + $date->setTimeZone(new \DateTimeZone('GMT')); + $date = $date->format('D, d M Y H:i:s \\G\\M\\T'); + + + $sig = base64_encode($this->hmacsha1($secretKey, + "POST\n$contentMD5\n\n$date\nx-amz-date:$date\n/evert" + )); + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'HTTP_AUTHORIZATION' => "AWS $accessKey:$sig", + 'HTTP_CONTENT_MD5' => $contentMD5, + 'HTTP_X_AMZ_DATE' => $date, + 'REQUEST_URI' => '/evert', + )); + + $request->setBody($content); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + $result = $this->auth->validate($secretKey); + + $this->assertTrue($result,'Signature did not validate, got errorcode ' . $this->auth->errorCode); + $this->assertEquals($accessKey,$this->auth->getAccessKey()); + + } + + public function test401() { + + $this->auth->requireLogin(); + $test = preg_match('/^AWS$/',$this->response->headers['WWW-Authenticate'],$matches); + $this->assertTrue($test==true,'The WWW-Authenticate response didn\'t match our pattern'); + + } + + /** + * Generates an HMAC-SHA1 signature + * + * @param string $key + * @param string $message + * @return string + */ + private function hmacsha1($key, $message) { + + $blocksize=64; + if (strlen($key)>$blocksize) + $key=pack('H*', sha1($key)); + $key=str_pad($key,$blocksize,chr(0x00)); + $ipad=str_repeat(chr(0x36),$blocksize); + $opad=str_repeat(chr(0x5c),$blocksize); + $hmac = pack('H*',sha1(($key^$opad).pack('H*',sha1(($key^$ipad).$message)))); + return $hmac; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/BasicAuthTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/BasicAuthTest.php new file mode 100644 index 00000000..77c5c717 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/BasicAuthTest.php @@ -0,0 +1,132 @@ +response = new ResponseMock(); + $this->basicAuth = new BasicAuth(); + $this->basicAuth->setHTTPResponse($this->response); + + } + + function testGetUserPassApache() { + + $server = array( + 'PHP_AUTH_USER' => 'admin', + 'PHP_AUTH_PW' => '1234', + ); + + $request = new Request($server); + $this->basicAuth->setHTTPRequest($request); + + $userPass = $this->basicAuth->getUserPass(); + + $this->assertEquals( + array('admin','1234'), + $userPass, + 'We did not get the username and password we expected' + ); + + } + + function testGetUserPassIIS() { + + $server = array( + 'HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('admin:1234'), + ); + + $request = new Request($server); + $this->basicAuth->setHTTPRequest($request); + + $userPass = $this->basicAuth->getUserPass(); + + $this->assertEquals( + array('admin','1234'), + $userPass, + 'We did not get the username and password we expected' + ); + + } + + function testGetUserPassWithColon() { + + $server = array( + 'HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('admin:1234:5678'), + ); + + $request = new Request($server); + $this->basicAuth->setHTTPRequest($request); + + $userPass = $this->basicAuth->getUserPass(); + + $this->assertEquals( + array('admin','1234:5678'), + $userPass, + 'We did not get the username and password we expected' + ); + + } + + function testGetUserPassApacheEdgeCase() { + + $server = array( + 'REDIRECT_HTTP_AUTHORIZATION' => 'Basic ' . base64_encode('admin:1234'), + ); + + $request = new Request($server); + $this->basicAuth->setHTTPRequest($request); + + $userPass = $this->basicAuth->getUserPass(); + + $this->assertEquals( + array('admin','1234'), + $userPass, + 'We did not get the username and password we expected' + ); + + } + + function testGetUserPassNothing() { + + $this->assertEquals( + false, + $this->basicAuth->getUserPass() + ); + + } + + function testRequireLogin() { + + $this->basicAuth->requireLogin(); + $this->assertEquals('SabreDAV',$this->basicAuth->getRealm()); + $this->assertEquals( + 'HTTP/1.1 401 Unauthorized', + $this->response->status, + 'We expected a 401 status to be set' + ); + + $this->assertEquals( + 'Basic realm="SabreDAV"', + $this->response->headers['WWW-Authenticate'], + 'The WWW-Autenticate header was not set!' + ); + + + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/DigestAuthTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/DigestAuthTest.php new file mode 100644 index 00000000..576a00d4 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/DigestAuthTest.php @@ -0,0 +1,228 @@ +response = new ResponseMock(); + $this->auth = new DigestAuth(); + $this->auth->setRealm(self::REALM); + $this->auth->setHTTPResponse($this->response); + + } + + public function testDigest() { + + list($nonce,$opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + + $this->assertEquals($username,$this->auth->getUserName()); + $this->assertEquals(self::REALM,$this->auth->getRealm()); + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1'); + $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword'); + + } + + public function testDigestCGIFormat() { + + list($nonce,$opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'HTTP_AUTHORIZATION' => 'Digest username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1'); + $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword'); + + } + + public function testDigestApacheEdgeCase() { + + list($nonce,$opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'REDIRECT_HTTP_AUTHORIZATION' => 'Digest username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1'); + $this->assertTrue($this->auth->validatePassword($password),'Authentication is deemed invalid through validatePassword'); + + } + + public function testInvalidDigest() { + + list($nonce,$opaque) = $this->getServerTokens(); + + $username = 'admin'; + $password = 12345; + $nc = '00002'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth:' . + md5('GET' . ':' . '/') + ); + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth,nc='.$nc.',cnonce="' . $cnonce . '"', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + + $this->assertFalse($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . ($password . 'randomness'))),'Authentication is deemed invalid through validateA1'); + + } + + public function testInvalidDigest2() { + + $request = new Request(array( + 'REQUEST_METHOD' => 'GET', + 'HTTP_AUTHORIZATION' => 'basic blablabla', + )); + + $this->auth->setHTTPRequest($request); + $this->auth->init(); + + $this->assertFalse($this->auth->validateA1(md5('user:realm:password'))); + + } + + + public function testDigestAuthInt() { + + $this->auth->setQOP(DigestAuth::QOP_AUTHINT | DigestAuth::QOP_AUTH); + list($nonce,$opaque) = $this->getServerTokens(DigestAuth::QOP_AUTHINT| DigestAuth::QOP_AUTH); + + $username = 'admin'; + $password = 12345; + $nc = '00003'; + $cnonce = uniqid(); + + $digestHash = md5( + md5($username . ':' . self::REALM . ':' . $password) . ':' . + $nonce . ':' . + $nc . ':' . + $cnonce . ':' . + 'auth-int:' . + md5('POST' . ':' . '/' . ':' . md5('body')) + ); + + $request = new Request(array( + 'REQUEST_METHOD' => 'POST', + 'PHP_AUTH_DIGEST' => 'username="'.$username.'", realm="' . self::REALM . '", nonce="' . $nonce . '", uri="/", response="' . $digestHash . '", opaque="' . $opaque . '", qop=auth-int,nc='.$nc.',cnonce="' . $cnonce . '"', + )); + $request->setBody('body'); + + $this->auth->setHTTPRequest($request); + + $this->auth->init(); + + $this->assertTrue($this->auth->validateA1(md5($username . ':' . self::REALM . ':' . $password)),'Authentication is deemed invalid through validateA1'); + + } + + private function getServerTokens($qop = DigestAuth::QOP_AUTH) { + + $this->auth->requireLogin(); + + switch($qop) { + case DigestAuth::QOP_AUTH : $qopstr='auth'; break; + case DigestAuth::QOP_AUTHINT : $qopstr='auth-int'; break; + default : $qopstr='auth,auth-int'; break; + } + + $test = preg_match('/Digest realm="'.self::REALM.'",qop="'.$qopstr.'",nonce="([0-9a-f]*)",opaque="([0-9a-f]*)"/', + $this->response->headers['WWW-Authenticate'],$matches); + + $this->assertTrue($test==true,'The WWW-Authenticate response didn\'t match our pattern. We received: ' . $this->response->headers['WWW-Authenticate']); + + $nonce = $matches[1]; + $opaque = $matches[2]; + + // Reset our environment + $this->setUp(); + $this->auth->setQOP($qop); + + return array($nonce,$opaque); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/RequestTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/RequestTest.php new file mode 100644 index 00000000..c52ce351 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/RequestTest.php @@ -0,0 +1,150 @@ + 'www.example.org', + 'REQUEST_METHOD' => 'PUT', + 'REQUEST_URI' => '/testuri/', + 'CONTENT_TYPE' => 'text/xml', + ); + + $this->request = new Request($server); + + } + + function testGetHeader() { + + $this->assertEquals('www.example.org', $this->request->getHeader('Host')); + $this->assertEquals('text/xml', $this->request->getHeader('Content-Type')); + + } + + function testGetNonExistantHeader() { + + $this->assertNull($this->request->getHeader('doesntexist')); + $this->assertNull($this->request->getHeader('Content-Length')); + + } + + function testGetHeaders() { + + $expected = array( + 'host' => 'www.example.org', + 'content-type' => 'text/xml', + ); + + $this->assertEquals($expected, $this->request->getHeaders()); + + } + + function testGetMethod() { + + $this->assertEquals('PUT', $this->request->getMethod(), 'It seems as if we didn\'t get a valid HTTP Request method back'); + + } + + function testGetUri() { + + $this->assertEquals('/testuri/', $this->request->getUri(), 'We got an invalid uri back'); + + } + + function testSetGetBody() { + + $h = fopen('php://memory','r+'); + fwrite($h,'testing'); + rewind($h); + $this->request->setBody($h); + $this->assertEquals('testing',$this->request->getBody(true),'We didn\'t get our testbody back'); + + } + + function testSetGetBodyStream() { + + $h = fopen('php://memory','r+'); + fwrite($h,'testing'); + rewind($h); + $this->request->setBody($h); + $this->assertEquals('testing',stream_get_contents($this->request->getBody()),'We didn\'t get our testbody back'); + + } + + + function testDefaultInputStream() { + + $h = fopen('php://memory','r+'); + fwrite($h,'testing'); + rewind($h); + + $previousValue = Request::$defaultInputStream; + Request::$defaultInputStream = $h; + + $this->assertEquals('testing',$this->request->getBody(true),'We didn\'t get our testbody back'); + Request::$defaultInputStream = $previousValue; + + } + + function testGetAbsoluteUri() { + + $s = array( + 'HTTP_HOST' => 'sabredav.org', + 'REQUEST_URI' => '/foo' + ); + + $r = new Request($s); + + $this->assertEquals('http://sabredav.org/foo', $r->getAbsoluteUri()); + + $s = array( + 'HTTP_HOST' => 'sabredav.org', + 'REQUEST_URI' => '/foo', + 'HTTPS' => 'on', + ); + + $r = new Request($s); + + $this->assertEquals('https://sabredav.org/foo', $r->getAbsoluteUri()); + + } + + function testGetQueryString() { + + $s = array( + 'QUERY_STRING' => 'bla', + ); + + $r = new Request($s); + $this->assertEquals('bla', $r->getQueryString()); + + $s = array(); + + $r = new Request($s); + $this->assertEquals('', $r->getQueryString()); + + } + + function testGetPostVars() { + + $post = array( + 'bla' => 'foo', + ); + $r = new Request(array(),$post); + $this->assertEquals($post, $r->getPostVars('bla')); + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php new file mode 100644 index 00000000..16c03409 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseMock.php @@ -0,0 +1,29 @@ +headers[$name] = $value; + + } + + function sendStatus($code) { + + $this->status = $this->getStatusMessage($code, $this->defaultHttpVersion); + + } + + function sendBody($body) { + + $this->body = $body; + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseTest.php new file mode 100644 index 00000000..f5302c99 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/ResponseTest.php @@ -0,0 +1,70 @@ +response = new ResponseMock(); + + } + + function testGetStatusMessage() { + + $msg = $this->response->getStatusMessage(200); + $this->assertEquals('HTTP/1.1 200 OK',$msg); + + } + + function testSetHeader() { + + $this->response->setHeader('Content-Type','text/html'); + $this->assertEquals('text/html', $this->response->headers['Content-Type']); + + + } + function testSetHeaders() { + + $this->response->setHeaders(array('Content-Type'=>'text/html')); + $this->assertEquals('text/html', $this->response->headers['Content-Type']); + + + } + + function testSendStatus() { + + $this->response->sendStatus(404); + $this->assertEquals('HTTP/1.1 404 Not Found', $this->response->status); + + } + + function testSendBody() { + + ob_start(); + $response = new Response(); + $response->sendBody('hello'); + $this->assertEquals('hello',ob_get_clean()); + + } + + function testSendBodyStream() { + + ob_start(); + $stream = fopen('php://memory','r+'); + fwrite($stream,'hello'); + rewind($stream); + $response = new Response(); + $response->sendBody($stream); + $this->assertEquals('hello',ob_get_clean()); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/UtilTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/UtilTest.php new file mode 100644 index 00000000..47a7b98b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/UtilTest.php @@ -0,0 +1,78 @@ +assertEquals($expected, $result->format('U')); + } + + $result = Util::parseHTTPDate('Wed Oct 6 10:26:00 2010'); + $this->assertEquals(1286360760, $result->format('U')); + + } + + function testParseHTTPDateFail() { + + $times = array( + //random string + 'NOW', + // not-GMT timezone + 'Wednesday, 13-Oct-10 10:26:00 UTC', + // No space before the 6 + 'Wed Oct 6 10:26:00 2010', + ); + + foreach($times as $time) { + $this->assertFalse(Util::parseHTTPDate($time), 'We used the string: ' . $time); + } + + } + + function testTimezones() { + + $default = date_default_timezone_get(); + date_default_timezone_set('Europe/Amsterdam'); + + $this->testParseHTTPDate(); + + date_default_timezone_set($default); + + } + + function testToHTTPDate() { + + $dt = new \DateTime('2011-12-10 12:00:00 +0200'); + + $this->assertEquals( + 'Sat, 10 Dec 2011 10:00:00 GMT', + Util::toHTTPDate($dt) + ); + + } + + function testStrtotimeFail() { + + // Strtotime may return -1 when the date cannot be parsed. + // We are simulating this situation by testing a date that actually + // results in -1. (because I have found no other way to break this + // code) + + $time = 'Wed, 13 Oct 1960 10:26:00 GMT'; + + $this->assertNull(Util::parseHTTPDate($time)); + + } +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/HTTP/VersionTest.php b/sources/vendor/sabre/dav/tests/Sabre/HTTP/VersionTest.php new file mode 100644 index 00000000..c7094b3b --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/HTTP/VersionTest.php @@ -0,0 +1,17 @@ +assertEquals(-1, version_compare('1.0.0',$v)); + + $s = Version::STABILITY; + $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable'); + + } + +} diff --git a/sources/vendor/sabre/dav/tests/Sabre/TestUtil.php b/sources/vendor/sabre/dav/tests/Sabre/TestUtil.php new file mode 100644 index 00000000..5a906249 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/Sabre/TestUtil.php @@ -0,0 +1,51 @@ +setAttribute(\PDO::ATTR_ERRMODE,\PDO::ERRMODE_EXCEPTION); + return $pdo; + } catch (\PDOException $e) { + return null; + } + + } + + +} diff --git a/sources/vendor/sabre/dav/tests/bootstrap.php b/sources/vendor/sabre/dav/tests/bootstrap.php new file mode 100644 index 00000000..a6493ce6 --- /dev/null +++ b/sources/vendor/sabre/dav/tests/bootstrap.php @@ -0,0 +1,23 @@ + + + Sabre/ + + + ../vendor/sabre/vobject/tests/Sabre/VObject + + + + + ../lib/ + + ../lib/Sabre/autoload.php + ../lib/Sabre/CalDAV/includes.php + ../lib/Sabre/CardDAV/includes.php + ../lib/Sabre/DAVACL/includes.php + ../lib/Sabre/HTTP/includes.php + ../lib/Sabre/DAV/includes.php + ../lib/Sabre/VObject/includes.php + + + + diff --git a/sources/vendor/sabre/vobject/.gitignore b/sources/vendor/sabre/vobject/.gitignore new file mode 100644 index 00000000..a46b19e2 --- /dev/null +++ b/sources/vendor/sabre/vobject/.gitignore @@ -0,0 +1,4 @@ +# Composer stuff +vendor/ +composer.lock +tests/cov/ diff --git a/sources/vendor/sabre/vobject/.travis.yml b/sources/vendor/sabre/vobject/.travis.yml new file mode 100644 index 00000000..5bd15086 --- /dev/null +++ b/sources/vendor/sabre/vobject/.travis.yml @@ -0,0 +1,17 @@ +language: php +php: + - 5.3 + - 5.4 + - 5.5 + - 5.5.9 + - 5.5.10 + - 5.6 + +matrix: + allow_failures: + - php: 5.5.10 + - php: 5.6 + +script: phpunit --configuration tests/phpunit.xml + +before_script: composer install diff --git a/sources/vendor/sabre/vobject/ChangeLog b/sources/vendor/sabre/vobject/ChangeLog new file mode 100644 index 00000000..96e1fb66 --- /dev/null +++ b/sources/vendor/sabre/vobject/ChangeLog @@ -0,0 +1,88 @@ +2.1.4-stable (2014-03-30) + * Fixed: Issue #87: Several compatibility fixes related to timezone + handling changes in PHP 5.5.10. + +2.1.3-stable (2013-10-02) + * Fixed: Issue #55. \r must be stripped from property values. + * Fixed: Issue #65. Putting quotes around parameter values that contain a + colon. + +2.1.2-stable (2013-08-02) + * Fixed: Issue #53. A regression in RecurrenceIterator. + +2.1.1-stable (2013-07-27) + * Fixed: Issue #50. RecurrenceIterator gives incorrect result when + exception events are out of order in the iCalendar file. + * Fixed: Issue #48. Overridden events in the recurrence iterator that were + past the UNTIL date were ignored. + +2.1.0-stable (2013-06-17) + * This version is fully backwards compatible with 2.0.*. However, it + contains a few new API's that mimic the VObject 3 API. This allows it to + be used a 'bridge' version. + Specifically, this new version exists so SabreDAV 1.7 and 1.8 can run with + both the 2 and 3 versions of this library. + * Added: Property\DateTime::hasTime(). + * Added: Property\MultiDateTime::hasTime(). + * Added: Property::getValue(). + * Added: Document class. + * Added: Document::createComponent and Document::createProperty. + * Added: Parameter::getValue(). + + +2.0.7-stable (2013-03-05) + * Fixed: Microsoft re-uses their magic numbers for different timezones, + specifically id 2 for both Sarajevo and Lisbon). A workaround was added + to deal with this. + +2.0.6-stable (2013-02-17) + * Fixed: The reader now properly parses parameters without a value. + +2.0.5-stable (2012-11-05) + * Fixed: The FreeBusyGenerator is now properly using the factory methods + for creation of components and properties. + +2.0.4-stable (2012-11-02) + * Added: Known Lotus Notes / Domino timezone id's. + +2.0.3-stable (2012-10-29) + * Added: Support for 'GMT+????' format in TZID's. + * Added: Support for formats like SystemV/EST5EDT in TZID's. + * Fixed: RecurrenceIterator now repairs recurrence rules where UNTIL < DTSTART. + * Added: Support for BYHOUR in FREQ=DAILY (@hollodk). + * Added: Support for BYHOUR and BYDAY in FREQ=WEEKLY. + +2.0.2-stable (2012-10-06) + * Added: includes.php file, to load the entire library in one go. + * Fixed: A problem with determining alarm triggers for TODO's. + +2.0.1-stable (2012-09-22) + * Removed: Element class. It wasn't used. + * Added: Basic validation and repair methods for broken input data. + * Fixed: RecurrenceIterator could infinitely loop when an INTERVAL of 0 + was specified. + * Added: A cli script that can validate and automatically repair vcards + and iCalendar objects. + * Added: A new 'Compound' property, that can automatically split up parts + for properties such as N, ADR, ORG and CATEGORIES. + * Added: Splitter classes, that can split up large objects (such as exports) + into individual objects (thanks @DominikTO and @armin-hackmann). + * Added: VFREEBUSY component, which allows easily checking wether + timeslots are available. + * Added: The Reader class now has a 'FORGIVING' option, which allows it to + parse properties with incorrect characters in the name (at this time, it + just allows underscores). + * Added: Also added the 'IGNORE_INVALID_LINES' option, to completely + disregard any invalid lines. + * Fixed: A bug in Windows timezone-id mappings for times created in + Greenlands timezone (sorry Greenlanders! I do care!). + * Fixed: DTEND was not generated correctly for VFREEBUSY reports. + * Fixed: Parser is at least 25% faster with real-world data. + +2.0.0-stable (2012-08-08) + * VObject is now a separate project from SabreDAV. See the SabreDAV + changelog for version information before 2.0. + * New: VObject library now uses PHP 5.3 namespaces. + * New: It's possible to specify lists of parameters when constructing + properties. + * New: made it easier to construct the FreeBusyGenerator. diff --git a/sources/vendor/sabre/vobject/LICENSE b/sources/vendor/sabre/vobject/LICENSE new file mode 100644 index 00000000..628c60c7 --- /dev/null +++ b/sources/vendor/sabre/vobject/LICENSE @@ -0,0 +1,27 @@ +Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/) + +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 Sabre nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. diff --git a/sources/vendor/sabre/vobject/README.md b/sources/vendor/sabre/vobject/README.md new file mode 100644 index 00000000..c7541eac --- /dev/null +++ b/sources/vendor/sabre/vobject/README.md @@ -0,0 +1,384 @@ +SabreTooth VObject library +========================== + +[![Build Status](https://secure.travis-ci.org/fruux/sabre-vobject.png?branch=master)](http://travis-ci.org/fruux/sabre-vobject) + +The VObject library allows you to easily parse and manipulate [iCalendar](https://tools.ietf.org/html/rfc5545) +and [vCard](https://tools.ietf.org/html/rfc6350) objects using PHP. +The goal of the VObject library is to create a very complete library, with an easy to use API. + +This project is a spin-off from [SabreDAV](http://code.google.com/p/sabredav/), where it has +been used for several years. The VObject library has 100% unittest coverage. + +Installation +------------ + +VObject requires PHP 5.3, and should be installed using composer. +The general composer instructions can be found on the [composer website](http://getcomposer.org/doc/00-intro.md composer website). + +After that, just declare the vobject dependency as follows: + +``` +"require" : { + "sabre/vobject" : "2.0.*" +} +``` + +Then, run `composer.phar update` and you should be good. + +Usage +----- + +### Parsing + +For our example, we will be using the following vcard: + +``` +BEGIN:VCARD +VERSION:3.0 +PRODID:-//Sabre//Sabre VObject 2.0//EN +N:Planck;Max;;; +FN:Max Planck +EMAIL;TYPE=WORK:mplanck@example.org +item1.TEL;TYPE=CELL:(+49)3144435678 +item1.X-ABLabel:Private cell +item2.TEL;TYPE=WORK:(+49)5554564744 +item2.X-ABLabel:Work +END:VCARD +``` + + +If we want to just print out Max' full name, you can just use property access: + + +```php +use Sabre\VObject; + +$card = VObject\Reader::read($data); +echo $card->FN; +``` + +### Changing properties + +Creating properties is pretty similar. If we like to add his birthday, we just +set the property: + +```php +$card->BDAY = '1858-04-23'; +``` + +Note that in the previous example, we're actually updating any existing BDAY that +may already exist. If we want to add a new property, without overwriting the previous +we can do this with the `add` method. + +```php +$card->add('EMAIL','max@example.org'); +``` + +### Parameters + +If we want to also specify that this is max' home email addresses, we can do this with +a third parameter: + +``` +$card->add('EMAIL', 'max@example'org', array('type' => 'HOME')); +``` + +If we want to read out all the email addresses and their type, this would look something +like this: + +``` +foreach($card->EMAIL as $email) { + + echo $email['TYPE'], ' - ', $email; + +} +``` + +### Groups + +In our example, you can see that the TEL properties are prefixed. These are 'groups' and +allow you to group multiple related properties together. The group can be any user-defined +name. + +This particular example as generated by the OS X addressbook, which uses the `X-ABLabel` +to allow the user to specify custom labels for properties. OS X addressbook uses groups +to tie the label to the property. + +The VObject library simply ignores the group if you don't specify it, so this will work: + +```php +foreach($card->TEL as $tel) { + echo $tel, "\n"; +} +``` + +But if you would like to target a specific group + property, this is possible too: + +```php +echo $card->{'ITEM1.TEL'}; +``` + +So if you would like to show all the phone numbers, along with their custom label, the +following syntax is used: + +```php +foreach($card->TEL as $tel) { + + echo $card->{$tel->group . '.X-ABLABEL'}, ": "; + echo $tel, "\n"; + +} +``` + +### Serializing / Saving + +If you want to generate your updated VObject, you can simply call the serialize() method. + +```php +echo $card->serialize(); +``` + +### Components + +iCalendar, unlike vCards always have sub-components. Where vCards are often just a flat +list, iCalendar objects tend to have a tree-like structure. For the following paragraphs, +we will use the following object as the example: + +``` +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 2.0//EN +BEGIN:VEVENT +SUMMARY:Curiosity landing +DTSTART:20120806T051439Z +LOCATION:Mars +END:VEVENT +END:VCALENDAR +``` + +Since events, tasks and journals are always in a sub component, this is also how we +access them. + +```php +use Sabre\VObject; + +$calendar = VObject\Reader::read($data); +echo $calendar->VEVENT->SUMMARY; +``` + +Adding components to a calendar is done with a factory method: + +```php +$event = VObject\Component::create('VEVENT'); +$calendar->add($event); + +$event->SUMMARY = 'Curiosity launch'; +$event->DTSTART = '20111126T150202Z'; +$event->LOCATION = 'Cape Carnival'; +``` + +By the way.. cloning also works as expected, as the entire structure is cloned along with it: + +```php +$clonedEvent = clone $calendar->VEVENT[0]; +$calendar->add($clonedEvent); +``` + +### Date and time handling + +If you ever had to deal with iCalendar timezones, you know it can be complicated. +The way timezones are specified is flawed, which is something I may write an essay about some +day. VObject does its best to determine the correct timezone. Many standard formats +have been tested and verified, and special code has been implemented for special-casing +microsoft generated timezone information, and others. + +To get a real php `DateTime` object, you can request this as follows: + +```php +$event = $calendar->VEVENT; +$start = $event->DTSTART->getDateTime(); +echo $start->format(\DateTime::W3C); +``` + +To set the property with a DateTime object, you can use the following syntax: + +```php +$dateTime = new \DateTime('2012-08-07 23:53:00', new DateTimeZone('Europe/Amsterdam')); +$event->DTSTART->setDateTime($dateTime, VObject\Property\DateTime::DATE); +``` + +The second argument specifies the type of date you're setting. The following three +options exist: + +1. `LOCAL` This is a floating time, with no timezone information. This basically specifies that the event happens in whatever the timezone's currently in. This would be encoded as `DTSTART;VALUE=DATE-TIME:20120807235300` +2. `UTC` This specifies that the time should be encoded as a UTC time. This is encoded as `DTSTART;VALUE=DATE-TIME:20120807205300Z`. Note the extra Z and the fact that it's two hours 'earlier'. +3. `LOCALTZ` specifies that it's supposed to be encoded in its local timezone. For example `DTSTART;VALUE=DATE-TIME;TZID=Europe/Amsterdam:20120807235300`. +4. `DATE` This is a date-only, and does not contain the time. In this case this would be encoded as `DTSTART;VALUE=DATE:20120807`. + +A few important notes: + +* When a `TZID` is specified, there should also be a matching `VTIMEZONE` object with all the timezone information. VObject cannot currently automatically embed this. However, in reality other clients seem to do fine without this information. Yet, for completeness, this will be added in the future. +* As mentioned, the timezone-determination process may sometimes fail. Report any issues you find, and I'll be quick to add workarounds! + +### Recurrence rules + +Recurrence rules allow events to recur, for example for a weekly meeting, or an anniversary. +This is done with the `RRULE` property. The `RRULE` property allows for a LOT of different +rules. VObject only implements the ones that actually appear in calendar software. + +To read more about `RRULE` and all the options, check out [RFC5545](https://tools.ietf.org/html/rfc5545#section-3.8.5). +VObject supports the following options: + +1. `UNTIL` for an end date. +2. `INTERVAL` for for example "every 2 days". +3. `COUNT` to stop recurring after x items. +4. `FREQ=DAILY` to recur every day, and `BYDAY` to limit it to certain days. +5. `FREQ=WEEKLY` to recur every week, `BYDAY` to expand this to multiple weekdays in every week and `WKST` to specify on which day the week starts. +6. `FREQ=MONTHLY` to recur every month, `BYMONTHDAY` to expand this to certain days in a month, `BYDAY` to expand it to certain weekdays occuring in a month, and `BYSETPOS` to limit the last two expansions. +7. `FREQ=YEARLY` to recur every year, `BYMONTH` to expand that to certain months in a year, and `BYDAY` and `BYWEEKDAY` to expand the `BYMONTH` rule even further. + +VObject supports the `EXDATE` property for exclusions, but not yet the `RDATE` and `EXRULE` +properties. If you're interested in this, please file a github issue, as this will put it +on my radar. + +This is a bit of a complex subject to go in excruciating detail. The +[RFC](https://tools.ietf.org/html/rfc5545#section-3.8.5) has a lot of examples though. + +The hard part is not to write the RRULE, it is to expand them. The most complex and +hard-to-read code is hidden in this component. Dragons be here. + +So, if we have a meeting every 2nd monday of the month, this would be specified as such: + +``` +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 2.0//EN +BEGIN:VEVENT +UID:1102c450-e0d7-11e1-9b23-0800200c9a66 +DTSTART:20120109T140000Z +RRULE:FREQ=MONTHLY;BYDAY=MO;BYSETPOS=2 +END:VEVENT +END:VCALENDAR +``` + +Note that normally it's not allowed to indent the object like this, but it does make +it easier to read. This is also the first time I added in a UID, which is required +for all VEVENT, VTODO and VJOURNAL objects! + +To figure out all the meetings for this year, we can use the following syntax: + +```php +use Sabre\VObject; + +$calendar = VObject\Reader::read($data); +$calendar->expand(new DateTime('2012-01-01'), new DateTime('2012-12-31')); +``` + +What the expand method does, is look at its inner events, and expand the recurring +rule. Our calendar now contains 12 events. The first will have its RRULE stripped, +and every subsequent VEVENT has the correct meeting date and a `RECURRENCE-ID` set. + +This results in something like this: + +``` +BEGIN:VCALENDAR + VERSION:2.0 + PRODID:-//Sabre//Sabre VObject 2.0//EN + BEGIN:VEVENT + UID:1102c450-e0d7-11e1-9b23-0800200c9a66 + DTSTART:20120109T140000Z + END:VEVENT + BEGIN:VEVENT + UID:1102c450-e0d7-11e1-9b23-0800200c9a66 + RECURRENCE-ID:20120213T140000Z + DTSTART:20120213T140000Z + END:VEVENT + BEGIN:VEVENT + UID:1102c450-e0d7-11e1-9b23-0800200c9a66 + RECURRENCE-ID:20120312T140000Z + DTSTART:20120312T140000Z + END:VEVENT + ..etc.. +END:VCALENDAR +``` + +To show the list of dates, we would do this as such: + +```php +foreach($calendar->VEVENT as $event) { + echo $event->DTSTART->getDateTime()->format(\DateTime::ATOM); +} +``` + +In a recurring event, single instances can also be overriden. VObject also takes these +into consideration. The reason we needed to specify a start and end-date, is because +some recurrence rules can be 'never ending'. + +You should make sure you pick a sane date-range. Because if you pick a 50 year +time-range, for a daily recurring event; this would result in over 18K objects. + +Free-busy report generation +--------------------------- + +Some calendaring software can make use of FREEBUSY reports to show when people are +available. + +You can automatically generate these reports from calendars using the `FreeBusyGenerator`. + +Example based on our last event: + +```php +// We're giving it the calendar object. It's also possible to specify multiple objects, +// by setting them as an array. +// +// We must also specify a start and end date, because recurring events are expanded. +$fbGenerator = new VObject\FreeBusyGenerator( + new DateTime('2012-01-01'), + new DateTime('2012-12-31'), + $calendar +); + +// Grabbing the report +$freebusy = $fbGenerator->result(); + +// The freebusy report is another VCALENDAR object, so we can serialize it as usual: +echo $freebusy->serialize(); +``` + +The output of this script will look like this: + +``` +BEGIN:VCALENDAR +VERSION:2.0 +PRODID:-//Sabre//Sabre VObject 2.0//EN +CALSCALE:GREGORIAN +BEGIN:VFREEBUSY +DTSTART;VALUE=DATE-TIME:20111231T230000Z +DTEND;VALUE=DATE-TIME:20111231T230000Z +DTSTAMP;VALUE=DATE-TIME:20120808T131628Z +FREEBUSY;FBTYPE=BUSY:20120109T140000Z/20120109T140000Z +FREEBUSY;FBTYPE=BUSY:20120213T140000Z/20120213T140000Z +FREEBUSY;FBTYPE=BUSY:20120312T140000Z/20120312T140000Z +FREEBUSY;FBTYPE=BUSY:20120409T140000Z/20120409T140000Z +FREEBUSY;FBTYPE=BUSY:20120514T140000Z/20120514T140000Z +FREEBUSY;FBTYPE=BUSY:20120611T140000Z/20120611T140000Z +FREEBUSY;FBTYPE=BUSY:20120709T140000Z/20120709T140000Z +FREEBUSY;FBTYPE=BUSY:20120813T140000Z/20120813T140000Z +FREEBUSY;FBTYPE=BUSY:20120910T140000Z/20120910T140000Z +FREEBUSY;FBTYPE=BUSY:20121008T140000Z/20121008T140000Z +FREEBUSY;FBTYPE=BUSY:20121112T140000Z/20121112T140000Z +FREEBUSY;FBTYPE=BUSY:20121210T140000Z/20121210T140000Z +END:VFREEBUSY +END:VCALENDAR +``` + +Support +------- + +Head over to the [SabreDAV mailing list](http://groups.google.com/group/sabredav-discuss) for any questions. + +Made at fruux +------------- + +This library is being developed by [fruux](https://fruux.com/). Drop us a line for commercial services or enterprise support. diff --git a/sources/vendor/sabre/vobject/bin/bench.php b/sources/vendor/sabre/vobject/bin/bench.php new file mode 100755 index 00000000..b949c8ea --- /dev/null +++ b/sources/vendor/sabre/vobject/bin/bench.php @@ -0,0 +1,12 @@ +#!/usr/bin/env php +version = '2.0'; +$calendar->calscale = 'GREGORIAN'; + +$ii=0; + +while($ii < $events) { + + $ii++; + + $event = VObject\Component::create('VEVENT'); + $event->DTSTART = 'bla'; + $event->SUMMARY = 'Event #' . $ii; + $event->UID = md5(microtime(true)); + + $doctorRandom = mt_rand(1,1000); + + switch($doctorRandom) { + // All-day event + case 1 : + $event->DTEND = 'bla'; + $dtStart = clone $currentDate; + $dtEnd = clone $currentDate; + $dtEnd->modify('+' . mt_rand(1,3) . ' days'); + $event->DTSTART->setDateTime($dtStart, VObject\Property\DateTime::DATE); + $event->DTEND->setDateTime($dtEnd, VObject\Property\DateTime::DATE); + break; + case 2 : + $event->RRULE = 'FREQ=DAILY;COUNT=' . mt_rand(1,10); + // No break intentional + default : + $dtStart = clone $currentDate; + $dtStart->setTime(mt_rand(1,23), mt_rand(0,59), mt_rand(0,59)); + $event->DTSTART->setDateTime($dtStart, VObject\Property\DateTime::UTC); + $event->DURATION = 'PT'.mt_rand(1,3).'H'; + break; + + } + + $calendar->add($event); + $currentDate->modify('+ ' . mt_rand(0,3) . ' days'); + +} +fwrite(STDERR, "Validating\n"); + +$result = $calendar->validate(); +if ($result) { + fwrite(STDERR, "Errors!\n"); + fwrite(STDERR, print_r($result,true)); + die(-1); +} + +fwrite(STDERR, "Serializing this beast\n"); + +echo $calendar->serialize(); + +fwrite(STDERR, "done.\n"); + diff --git a/sources/vendor/sabre/vobject/bin/vobjectvalidate.php b/sources/vendor/sabre/vobject/bin/vobjectvalidate.php new file mode 100755 index 00000000..e0b2a479 --- /dev/null +++ b/sources/vendor/sabre/vobject/bin/vobjectvalidate.php @@ -0,0 +1,139 @@ +#!/usr/bin/env php +$v) { + + if ($k===0) { + continue; + } + if (substr($v,0,2)==='--') { + switch($v) { + case '--repair' : + $repair = true; + break; + default : + throw new InvalidArgumentException('Unknown option: ' . $v); + break; + } + continue; + } + $posArgs[] = $v; + +} + +function help() { + + global $argv; + + fwrite(STDERR, <<children(); + +foreach($objects as $child) { + + switch($child->name) { + case 'VCALENDAR' : + fwrite(STDERR, "iCalendar: " . (string)$child->VERSION . "\n"); + break; + case 'VCARD' : + fwrite(STDERR, "vCard: " . (string)$child->VERSION . "\n"); + break; + default : + fwrite(STDERR, "This was an unknown object, but it did parse. It's likely that validation will give you unexpected results.\n"); + break; + } + + $options = 0; + if ($repair) $options |= Node::REPAIR; + + $warnings = $child->validate($options); + + if (!count($warnings)) { + fwrite(STDERR, "[GOOD NEWS] No warnings!\n"); + } else { + foreach($warnings as $warn) { + + fwrite(STDERR, $warn['message'] . "\n"); + + } + + } + + if ($repair) { + fwrite($output, $child->serialize()); + } + +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component.php new file mode 100644 index 00000000..1c1d9244 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component.php @@ -0,0 +1,405 @@ + 'Sabre\\VObject\\Component\\VAlarm', + 'VCALENDAR' => 'Sabre\\VObject\\Component\\VCalendar', + 'VCARD' => 'Sabre\\VObject\\Component\\VCard', + 'VEVENT' => 'Sabre\\VObject\\Component\\VEvent', + 'VJOURNAL' => 'Sabre\\VObject\\Component\\VJournal', + 'VTODO' => 'Sabre\\VObject\\Component\\VTodo', + 'VFREEBUSY' => 'Sabre\\VObject\\Component\\VFreeBusy', + ); + + /** + * Creates the new component by name, but in addition will also see if + * there's a class mapped to the property name. + * + * @param string $name + * @param string $value + * @return Component + */ + static public function create($name, $value = null) { + + $name = strtoupper($name); + + if (isset(self::$classMap[$name])) { + return new self::$classMap[$name]($name, $value); + } else { + return new self($name, $value); + } + + } + + /** + * Creates a new component. + * + * By default this object will iterate over its own children, but this can + * be overridden with the iterator argument + * + * @param string $name + * @param ElementList $iterator + */ + public function __construct($name, ElementList $iterator = null) { + + $this->name = strtoupper($name); + if (!is_null($iterator)) $this->iterator = $iterator; + + } + + /** + * Turns the object back into a serialized blob. + * + * @return string + */ + public function serialize() { + + $str = "BEGIN:" . $this->name . "\r\n"; + + /** + * Gives a component a 'score' for sorting purposes. + * + * This is solely used by the childrenSort method. + * + * A higher score means the item will be lower in the list. + * To avoid score collisions, each "score category" has a reasonable + * space to accomodate elements. The $key is added to the $score to + * preserve the original relative order of elements. + * + * @param int $key + * @param array $array + * @return int + */ + $sortScore = function($key, $array) { + + if ($array[$key] instanceof Component) { + + // We want to encode VTIMEZONE first, this is a personal + // preference. + if ($array[$key]->name === 'VTIMEZONE') { + $score=300000000; + return $score+$key; + } else { + $score=400000000; + return $score+$key; + } + } else { + // Properties get encoded first + // VCARD version 4.0 wants the VERSION property to appear first + if ($array[$key] instanceof Property) { + if ($array[$key]->name === 'VERSION') { + $score=100000000; + return $score+$key; + } else { + // All other properties + $score=200000000; + return $score+$key; + } + } + } + + }; + + $tmp = $this->children; + uksort($this->children, function($a, $b) use ($sortScore, $tmp) { + + $sA = $sortScore($a, $tmp); + $sB = $sortScore($b, $tmp); + + if ($sA === $sB) return 0; + + return ($sA < $sB) ? -1 : 1; + + }); + + foreach($this->children as $child) $str.=$child->serialize(); + $str.= "END:" . $this->name . "\r\n"; + + return $str; + + } + + /** + * Adds a new component or element + * + * You can call this method with the following syntaxes: + * + * add(Node $node) + * add(string $name, $value, array $parameters = array()) + * + * The first version adds an Element + * The second adds a property as a string. + * + * @param mixed $item + * @param mixed $itemValue + * @return void + */ + public function add($item, $itemValue = null, array $parameters = array()) { + + if ($item instanceof Node) { + if (!is_null($itemValue)) { + throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject Node'); + } + $item->parent = $this; + $this->children[] = $item; + } elseif(is_string($item)) { + + $item = Property::create($item,$itemValue, $parameters); + $item->parent = $this; + $this->children[] = $item; + + } else { + + throw new \InvalidArgumentException('The first argument must either be a \\Sabre\\VObject\\Node or a string'); + + } + + } + + /** + * Returns an iterable list of children + * + * @return ElementList + */ + public function children() { + + return new ElementList($this->children); + + } + + /** + * Returns an array with elements that match the specified name. + * + * This function is also aware of MIME-Directory groups (as they appear in + * vcards). This means that if a property is grouped as "HOME.EMAIL", it + * will also be returned when searching for just "EMAIL". If you want to + * search for a property in a specific group, you can select on the entire + * string ("HOME.EMAIL"). If you want to search on a specific property that + * has not been assigned a group, specify ".EMAIL". + * + * Keys are retained from the 'children' array, which may be confusing in + * certain cases. + * + * @param string $name + * @return array + */ + public function select($name) { + + $group = null; + $name = strtoupper($name); + if (strpos($name,'.')!==false) { + list($group,$name) = explode('.', $name, 2); + } + + $result = array(); + foreach($this->children as $key=>$child) { + + if ( + strtoupper($child->name) === $name && + (is_null($group) || ( $child instanceof Property && strtoupper($child->group) === $group)) + ) { + + $result[$key] = $child; + + } + } + + reset($result); + return $result; + + } + + /** + * This method only returns a list of sub-components. Properties are + * ignored. + * + * @return array + */ + public function getComponents() { + + $result = array(); + foreach($this->children as $child) { + if ($child instanceof Component) { + $result[] = $child; + } + } + + return $result; + + } + + /** + * Validates the node for correctness. + * + * The following options are supported: + * - Node::REPAIR - If something is broken, and automatic repair may + * be attempted. + * + * An array is returned with warnings. + * + * Every item in the array has the following properties: + * * level - (number between 1 and 3 with severity information) + * * message - (human readable message) + * * node - (reference to the offending node) + * + * @param int $options + * @return array + */ + public function validate($options = 0) { + + $result = array(); + foreach($this->children as $child) { + $result = array_merge($result, $child->validate($options)); + } + return $result; + + } + + /* Magic property accessors {{{ */ + + /** + * Using 'get' you will either get a property or component, + * + * If there were no child-elements found with the specified name, + * null is returned. + * + * @param string $name + * @return Property + */ + public function __get($name) { + + $matches = $this->select($name); + if (count($matches)===0) { + return null; + } else { + $firstMatch = current($matches); + /** @var $firstMatch Property */ + $firstMatch->setIterator(new ElementList(array_values($matches))); + return $firstMatch; + } + + } + + /** + * This method checks if a sub-element with the specified name exists. + * + * @param string $name + * @return bool + */ + public function __isset($name) { + + $matches = $this->select($name); + return count($matches)>0; + + } + + /** + * Using the setter method you can add properties or subcomponents + * + * You can either pass a Component, Property + * object, or a string to automatically create a Property. + * + * If the item already exists, it will be removed. If you want to add + * a new item with the same name, always use the add() method. + * + * @param string $name + * @param mixed $value + * @return void + */ + public function __set($name, $value) { + + $matches = $this->select($name); + $overWrite = count($matches)?key($matches):null; + + if ($value instanceof Component || $value instanceof Property) { + $value->parent = $this; + if (!is_null($overWrite)) { + $this->children[$overWrite] = $value; + } else { + $this->children[] = $value; + } + } elseif (is_scalar($value)) { + $property = Property::create($name,$value); + $property->parent = $this; + if (!is_null($overWrite)) { + $this->children[$overWrite] = $property; + } else { + $this->children[] = $property; + } + } else { + throw new \InvalidArgumentException('You must pass a \\Sabre\\VObject\\Component, \\Sabre\\VObject\\Property or scalar type'); + } + + } + + /** + * Removes all properties and components within this component. + * + * @param string $name + * @return void + */ + public function __unset($name) { + + $matches = $this->select($name); + foreach($matches as $k=>$child) { + + unset($this->children[$k]); + $child->parent = null; + + } + + } + + /* }}} */ + + /** + * This method is automatically called when the object is cloned. + * Specifically, this will ensure all child elements are also cloned. + * + * @return void + */ + public function __clone() { + + foreach($this->children as $key=>$child) { + $this->children[$key] = clone $child; + $this->children[$key]->parent = $this; + } + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php new file mode 100644 index 00000000..2f86c44f --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VAlarm.php @@ -0,0 +1,108 @@ +TRIGGER; + if(!isset($trigger['VALUE']) || strtoupper($trigger['VALUE']) === 'DURATION') { + $triggerDuration = VObject\DateTimeParser::parseDuration($this->TRIGGER); + $related = (isset($trigger['RELATED']) && strtoupper($trigger['RELATED']) == 'END') ? 'END' : 'START'; + + $parentComponent = $this->parent; + if ($related === 'START') { + + if ($parentComponent->name === 'VTODO') { + $propName = 'DUE'; + } else { + $propName = 'DTSTART'; + } + + $effectiveTrigger = clone $parentComponent->$propName->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } else { + if ($parentComponent->name === 'VTODO') { + $endProp = 'DUE'; + } elseif ($parentComponent->name === 'VEVENT') { + $endProp = 'DTEND'; + } else { + throw new \LogicException('time-range filters on VALARM components are only supported when they are a child of VTODO or VEVENT'); + } + + if (isset($parentComponent->$endProp)) { + $effectiveTrigger = clone $parentComponent->$endProp->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } elseif (isset($parentComponent->DURATION)) { + $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime(); + $duration = VObject\DateTimeParser::parseDuration($parentComponent->DURATION); + $effectiveTrigger->add($duration); + $effectiveTrigger->add($triggerDuration); + } else { + $effectiveTrigger = clone $parentComponent->DTSTART->getDateTime(); + $effectiveTrigger->add($triggerDuration); + } + } + } else { + $effectiveTrigger = $trigger->getDateTime(); + } + return $effectiveTrigger; + + } + + /** + * Returns true or false depending on if the event falls in the specified + * time-range. This is used for filtering purposes. + * + * The rules used to determine if an event falls within the specified + * time-range is based on the CalDAV specification. + * + * @param \DateTime $start + * @param \DateTime $end + * @return bool + */ + public function isInTimeRange(\DateTime $start, \DateTime $end) { + + $effectiveTrigger = $this->getEffectiveTriggerTime(); + + if (isset($this->DURATION)) { + $duration = VObject\DateTimeParser::parseDuration($this->DURATION); + $repeat = (string)$this->repeat; + if (!$repeat) { + $repeat = 1; + } + + $period = new \DatePeriod($effectiveTrigger, $duration, (int)$repeat); + + foreach($period as $occurrence) { + + if ($start <= $occurrence && $end > $occurrence) { + return true; + } + } + return false; + } else { + return ($start <= $effectiveTrigger && $end > $effectiveTrigger); + } + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php new file mode 100644 index 00000000..9de67982 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCalendar.php @@ -0,0 +1,244 @@ +children as $component) { + + if (!$component instanceof VObject\Component) + continue; + + if (isset($component->{'RECURRENCE-ID'})) + continue; + + if ($componentName && $component->name !== strtoupper($componentName)) + continue; + + if ($component->name === 'VTIMEZONE') + continue; + + $components[] = $component; + + } + + return $components; + + } + + /** + * If this calendar object, has events with recurrence rules, this method + * can be used to expand the event into multiple sub-events. + * + * Each event will be stripped from it's recurrence information, and only + * the instances of the event in the specified timerange will be left + * alone. + * + * In addition, this method will cause timezone information to be stripped, + * and normalized to UTC. + * + * This method will alter the VCalendar. This cannot be reversed. + * + * This functionality is specifically used by the CalDAV standard. It is + * possible for clients to request expand events, if they are rather simple + * clients and do not have the possibility to calculate recurrences. + * + * @param DateTime $start + * @param DateTime $end + * @return void + */ + public function expand(\DateTime $start, \DateTime $end) { + + $newEvents = array(); + + foreach($this->select('VEVENT') as $key=>$vevent) { + + if (isset($vevent->{'RECURRENCE-ID'})) { + unset($this->children[$key]); + continue; + } + + + if (!$vevent->rrule) { + unset($this->children[$key]); + if ($vevent->isInTimeRange($start, $end)) { + $newEvents[] = $vevent; + } + continue; + } + + $uid = (string)$vevent->uid; + if (!$uid) { + throw new \LogicException('Event did not have a UID!'); + } + + $it = new VObject\RecurrenceIterator($this, $vevent->uid); + $it->fastForward($start); + + while($it->valid() && $it->getDTStart() < $end) { + + if ($it->getDTEnd() > $start) { + + $newEvents[] = $it->getEventObject(); + + } + $it->next(); + + } + unset($this->children[$key]); + + } + + foreach($newEvents as $newEvent) { + + foreach($newEvent->children as $child) { + if ($child instanceof VObject\Property\DateTime && + $child->getDateType() == VObject\Property\DateTime::LOCALTZ) { + $child->setDateTime($child->getDateTime(),VObject\Property\DateTime::UTC); + } + } + + $this->add($newEvent); + + } + + // Removing all VTIMEZONE components + unset($this->VTIMEZONE); + + } + + /** + * Validates the node for correctness. + * An array is returned with warnings. + * + * Every item in the array has the following properties: + * * level - (number between 1 and 3 with severity information) + * * message - (human readable message) + * * node - (reference to the offending node) + * + * @return array + */ + /* + public function validate() { + + $warnings = array(); + + $version = $this->select('VERSION'); + if (count($version)!==1) { + $warnings[] = array( + 'level' => 1, + 'message' => 'The VERSION property must appear in the VCALENDAR component exactly 1 time', + 'node' => $this, + ); + } else { + if ((string)$this->VERSION !== '2.0') { + $warnings[] = array( + 'level' => 1, + 'message' => 'Only iCalendar version 2.0 as defined in rfc5545 is supported.', + 'node' => $this, + ); + } + } + $version = $this->select('PRODID'); + if (count($version)!==1) { + $warnings[] = array( + 'level' => 2, + 'message' => 'The PRODID property must appear in the VCALENDAR component exactly 1 time', + 'node' => $this, + ); + } + if (count($this->CALSCALE) > 1) { + $warnings[] = array( + 'level' => 2, + 'message' => 'The CALSCALE property must not be specified more than once.', + 'node' => $this, + ); + } + if (count($this->METHOD) > 1) { + $warnings[] = array( + 'level' => 2, + 'message' => 'The METHOD property must not be specified more than once.', + 'node' => $this, + ); + } + + $allowedComponents = array( + 'VEVENT', + 'VTODO', + 'VJOURNAL', + 'VFREEBUSY', + 'VTIMEZONE', + ); + $allowedProperties = array( + 'PRODID', + 'VERSION', + 'CALSCALE', + 'METHOD', + ); + $componentsFound = 0; + foreach($this->children as $child) { + if($child instanceof Component) { + $componentsFound++; + if (!in_array($child->name, $allowedComponents)) { + $warnings[] = array( + 'level' => 1, + 'message' => 'The ' . $child->name . " component is not allowed in the VCALENDAR component", + 'node' => $this, + ); + } + } + if ($child instanceof Property) { + if (!in_array($child->name, $allowedProperties)) { + $warnings[] = array( + 'level' => 2, + 'message' => 'The ' . $child->name . " property is not allowed in the VCALENDAR component", + 'node' => $this, + ); + } + } + } + + if ($componentsFound===0) { + $warnings[] = array( + 'level' => 1, + 'message' => 'An iCalendar object must have at least 1 component.', + 'node' => $this, + ); + } + + return array_merge( + $warnings, + parent::validate() + ); + + } + */ + +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php new file mode 100644 index 00000000..0fc8b702 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VCard.php @@ -0,0 +1,107 @@ +select('VERSION'); + if (count($version)!==1) { + $warnings[] = array( + 'level' => 1, + 'message' => 'The VERSION property must appear in the VCARD component exactly 1 time', + 'node' => $this, + ); + if ($options & self::REPAIR) { + $this->VERSION = self::DEFAULT_VERSION; + } + } else { + $version = (string)$this->VERSION; + if ($version!=='2.1' && $version!=='3.0' && $version!=='4.0') { + $warnings[] = array( + 'level' => 1, + 'message' => 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.', + 'node' => $this, + ); + if ($options & self::REPAIR) { + $this->VERSION = '4.0'; + } + } + + } + $fn = $this->select('FN'); + if (count($fn)!==1) { + $warnings[] = array( + 'level' => 1, + 'message' => 'The FN property must appear in the VCARD component exactly 1 time', + 'node' => $this, + ); + if (($options & self::REPAIR) && count($fn) === 0) { + // We're going to try to see if we can use the contents of the + // N property. + if (isset($this->N)) { + $value = explode(';', (string)$this->N); + if (isset($value[1]) && $value[1]) { + $this->FN = $value[1] . ' ' . $value[0]; + } else { + $this->FN = $value[0]; + } + + // Otherwise, the ORG property may work + } elseif (isset($this->ORG)) { + $this->FN = (string)$this->ORG; + } + + } + } + + return array_merge( + parent::validate($options), + $warnings + ); + + } + +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php new file mode 100644 index 00000000..2375c531 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VEvent.php @@ -0,0 +1,70 @@ +RRULE) { + $it = new VObject\RecurrenceIterator($this); + $it->fastForward($start); + + // We fast-forwarded to a spot where the end-time of the + // recurrence instance exceeded the start of the requested + // time-range. + // + // If the starttime of the recurrence did not exceed the + // end of the time range as well, we have a match. + return ($it->getDTStart() < $end && $it->getDTEnd() > $start); + + } + + $effectiveStart = $this->DTSTART->getDateTime(); + if (isset($this->DTEND)) { + + // The DTEND property is considered non inclusive. So for a 3 day + // event in july, dtstart and dtend would have to be July 1st and + // July 4th respectively. + // + // See: + // http://tools.ietf.org/html/rfc5545#page-54 + $effectiveEnd = $this->DTEND->getDateTime(); + + } elseif (isset($this->DURATION)) { + $effectiveEnd = clone $effectiveStart; + $effectiveEnd->add( VObject\DateTimeParser::parseDuration($this->DURATION) ); + } elseif ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) { + $effectiveEnd = clone $effectiveStart; + $effectiveEnd->modify('+1 day'); + } else { + $effectiveEnd = clone $effectiveStart; + } + return ( + ($start <= $effectiveEnd) && ($end > $effectiveStart) + ); + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php new file mode 100644 index 00000000..7afe9fdb --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VFreeBusy.php @@ -0,0 +1,68 @@ +select('FREEBUSY') as $freebusy) { + + // We are only interested in FBTYPE=BUSY (the default), + // FBTYPE=BUSY-TENTATIVE or FBTYPE=BUSY-UNAVAILABLE. + if (isset($freebusy['FBTYPE']) && strtoupper(substr((string)$freebusy['FBTYPE'],0,4))!=='BUSY') { + continue; + } + + // The freebusy component can hold more than 1 value, separated by + // commas. + $periods = explode(',', (string)$freebusy); + + foreach($periods as $period) { + // Every period is formatted as [start]/[end]. The start is an + // absolute UTC time, the end may be an absolute UTC time, or + // duration (relative) value. + list($busyStart, $busyEnd) = explode('/', $period); + + $busyStart = VObject\DateTimeParser::parse($busyStart); + $busyEnd = VObject\DateTimeParser::parse($busyEnd); + if ($busyEnd instanceof \DateInterval) { + $tmp = clone $busyStart; + $tmp->add($busyEnd); + $busyEnd = $tmp; + } + + if($start < $busyEnd && $end > $busyStart) { + return false; + } + + } + + } + + return true; + + } + +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php new file mode 100644 index 00000000..23288787 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VJournal.php @@ -0,0 +1,46 @@ +DTSTART)?$this->DTSTART->getDateTime():null; + if ($dtstart) { + $effectiveEnd = clone $dtstart; + if ($this->DTSTART->getDateType() == VObject\Property\DateTime::DATE) { + $effectiveEnd->modify('+1 day'); + } + + return ($start <= $effectiveEnd && $end > $dtstart); + + } + return false; + + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php new file mode 100644 index 00000000..b1579cf7 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Component/VTodo.php @@ -0,0 +1,68 @@ +DTSTART)?$this->DTSTART->getDateTime():null; + $duration = isset($this->DURATION)?VObject\DateTimeParser::parseDuration($this->DURATION):null; + $due = isset($this->DUE)?$this->DUE->getDateTime():null; + $completed = isset($this->COMPLETED)?$this->COMPLETED->getDateTime():null; + $created = isset($this->CREATED)?$this->CREATED->getDateTime():null; + + if ($dtstart) { + if ($duration) { + $effectiveEnd = clone $dtstart; + $effectiveEnd->add($duration); + return $start <= $effectiveEnd && $end > $dtstart; + } elseif ($due) { + return + ($start < $due || $start <= $dtstart) && + ($end > $dtstart || $end >= $due); + } else { + return $start <= $dtstart && $end > $dtstart; + } + } + if ($due) { + return ($start < $due && $end >= $due); + } + if ($completed && $created) { + return + ($start <= $created || $start <= $completed) && + ($end >= $created || $end >= $completed); + } + if ($completed) { + return ($start <= $completed && $end >= $completed); + } + if ($created) { + return ($end > $created); + } + return true; + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php new file mode 100644 index 00000000..03600506 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/DateTimeParser.php @@ -0,0 +1,181 @@ +setTimeZone(new \DateTimeZone('UTC')); + return $date; + + } + + /** + * Parses an iCalendar (rfc5545) formatted date and returns a DateTime object + * + * @param string $date + * @return DateTime + */ + static public function parseDate($date) { + + // Format is YYYYMMDD + $result = preg_match('/^([1-4][0-9]{3})([0-1][0-9])([0-3][0-9])$/',$date,$matches); + + if (!$result) { + throw new \LogicException('The supplied iCalendar date value is incorrect: ' . $date); + } + + $date = new \DateTime($matches[1] . '-' . $matches[2] . '-' . $matches[3], new \DateTimeZone('UTC')); + return $date; + + } + + /** + * Parses an iCalendar (RFC5545) formatted duration value. + * + * This method will either return a DateTimeInterval object, or a string + * suitable for strtotime or DateTime::modify. + * + * @param string $duration + * @param bool $asString + * @return DateInterval|string + */ + static public function parseDuration($duration, $asString = false) { + + $result = preg_match('/^(?P\+|-)?P((?P\d+)W)?((?P\d+)D)?(T((?P\d+)H)?((?P\d+)M)?((?P\d+)S)?)?$/', $duration, $matches); + if (!$result) { + throw new \LogicException('The supplied iCalendar duration value is incorrect: ' . $duration); + } + + if (!$asString) { + $invert = false; + if ($matches['plusminus']==='-') { + $invert = true; + } + + + $parts = array( + 'week', + 'day', + 'hour', + 'minute', + 'second', + ); + foreach($parts as $part) { + $matches[$part] = isset($matches[$part])&&$matches[$part]?(int)$matches[$part]:0; + } + + + // We need to re-construct the $duration string, because weeks and + // days are not supported by DateInterval in the same string. + $duration = 'P'; + $days = $matches['day']; + if ($matches['week']) { + $days+=$matches['week']*7; + } + if ($days) + $duration.=$days . 'D'; + + if ($matches['minute'] || $matches['second'] || $matches['hour']) { + $duration.='T'; + + if ($matches['hour']) + $duration.=$matches['hour'].'H'; + + if ($matches['minute']) + $duration.=$matches['minute'].'M'; + + if ($matches['second']) + $duration.=$matches['second'].'S'; + + } + + if ($duration==='P') { + $duration = 'PT0S'; + } + $iv = new \DateInterval($duration); + if ($invert) $iv->invert = true; + + return $iv; + + } + + + + $parts = array( + 'week', + 'day', + 'hour', + 'minute', + 'second', + ); + + $newDur = ''; + foreach($parts as $part) { + if (isset($matches[$part]) && $matches[$part]) { + $newDur.=' '.$matches[$part] . ' ' . $part . 's'; + } + } + + $newDur = ($matches['plusminus']==='-'?'-':'+') . trim($newDur); + if ($newDur === '+') { $newDur = '+0 seconds'; }; + return $newDur; + + } + + /** + * Parses either a Date or DateTime, or Duration value. + * + * @param string $date + * @param DateTimeZone|string $referenceTZ + * @return DateTime|DateInterval + */ + static public function parse($date, $referenceTZ = null) { + + if ($date[0]==='P' || ($date[0]==='-' && $date[1]==='P')) { + return self::parseDuration($date); + } elseif (strlen($date)===8) { + return self::parseDate($date); + } else { + return self::parseDateTime($date, $referenceTZ); + } + + } + + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Document.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Document.php new file mode 100644 index 00000000..50a662ee --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Document.php @@ -0,0 +1,109 @@ +value syntax, in which case + * properties will automatically be created, or you can just pass a list of + * Component and Property object. + * + * @param string $name + * @param array $children + * @return Component + */ + public function createComponent($name, array $children = array()) { + + $component = Component::create($name); + foreach($children as $k=>$v) { + + if ($v instanceof Node) { + $component->add($v); + } else { + $component->add($k, $v); + } + + } + return $component; + + } + + /** + * Factory method for creating new properties + * + * This method automatically searches for the correct property class, based + * on its name. + * + * You can specify the parameters either in key=>value syntax, in which case + * parameters will automatically be created, or you can just pass a list of + * Parameter objects. + * + * @param string $name + * @param mixed $value + * @param array $parameters + * @return Property + */ + public function createProperty($name, $value = null, array $parameters = array()) { + + return Property::create($name, $value, $parameters); + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php new file mode 100644 index 00000000..1c203708 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/ElementList.php @@ -0,0 +1,172 @@ +vevent where there's multiple VEVENT objects. + * + * @copyright Copyright (C) 2007-2013 fruux GmbH (https://fruux.com/). + * @author Evert Pot (http://evertpot.com/) + * @license http://code.google.com/p/sabredav/wiki/License Modified BSD License + */ +class ElementList implements \Iterator, \Countable, \ArrayAccess { + + /** + * Inner elements + * + * @var array + */ + protected $elements = array(); + + /** + * Creates the element list. + * + * @param array $elements + */ + public function __construct(array $elements) { + + $this->elements = $elements; + + } + + /* {{{ Iterator interface */ + + /** + * Current position + * + * @var int + */ + private $key = 0; + + /** + * Returns current item in iteration + * + * @return Element + */ + public function current() { + + return $this->elements[$this->key]; + + } + + /** + * To the next item in the iterator + * + * @return void + */ + public function next() { + + $this->key++; + + } + + /** + * Returns the current iterator key + * + * @return int + */ + public function key() { + + return $this->key; + + } + + /** + * Returns true if the current position in the iterator is a valid one + * + * @return bool + */ + public function valid() { + + return isset($this->elements[$this->key]); + + } + + /** + * Rewinds the iterator + * + * @return void + */ + public function rewind() { + + $this->key = 0; + + } + + /* }}} */ + + /* {{{ Countable interface */ + + /** + * Returns the number of elements + * + * @return int + */ + public function count() { + + return count($this->elements); + + } + + /* }}} */ + + /* {{{ ArrayAccess Interface */ + + + /** + * Checks if an item exists through ArrayAccess. + * + * @param int $offset + * @return bool + */ + public function offsetExists($offset) { + + return isset($this->elements[$offset]); + + } + + /** + * Gets an item through ArrayAccess. + * + * @param int $offset + * @return mixed + */ + public function offsetGet($offset) { + + return $this->elements[$offset]; + + } + + /** + * Sets an item through ArrayAccess. + * + * @param int $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset,$value) { + + throw new \LogicException('You can not add new objects to an ElementList'); + + } + + /** + * Sets an item through ArrayAccess. + * + * This method just forwards the request to the inner iterator + * + * @param int $offset + * @return void + */ + public function offsetUnset($offset) { + + throw new \LogicException('You can not remove objects from an ElementList'); + + } + + /* }}} */ + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php new file mode 100644 index 00000000..96d0be5a --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/FreeBusyGenerator.php @@ -0,0 +1,322 @@ +setTimeRange($start, $end); + } + + if ($objects) { + $this->setObjects($objects); + } + + } + + /** + * Sets the VCALENDAR object. + * + * If this is set, it will not be generated for you. You are responsible + * for setting things like the METHOD, CALSCALE, VERSION, etc.. + * + * The VFREEBUSY object will be automatically added though. + * + * @param Component $vcalendar + * @return void + */ + public function setBaseObject(Component $vcalendar) { + + $this->baseObject = $vcalendar; + + } + + /** + * Sets the input objects + * + * You must either specify a valendar object as a strong, or as the parse + * Component. + * It's also possible to specify multiple objects as an array. + * + * @param mixed $objects + * @return void + */ + public function setObjects($objects) { + + if (!is_array($objects)) { + $objects = array($objects); + } + + $this->objects = array(); + foreach($objects as $object) { + + if (is_string($object)) { + $this->objects[] = Reader::read($object); + } elseif ($object instanceof Component) { + $this->objects[] = $object; + } else { + throw new \InvalidArgumentException('You can only pass strings or \\Sabre\\VObject\\Component arguments to setObjects'); + } + + } + + } + + /** + * Sets the time range + * + * Any freebusy object falling outside of this time range will be ignored. + * + * @param DateTime $start + * @param DateTime $end + * @return void + */ + public function setTimeRange(\DateTime $start = null, \DateTime $end = null) { + + $this->start = $start; + $this->end = $end; + + } + + /** + * Parses the input data and returns a correct VFREEBUSY object, wrapped in + * a VCALENDAR. + * + * @return Component + */ + public function getResult() { + + $busyTimes = array(); + + foreach($this->objects as $object) { + + foreach($object->getBaseComponents() as $component) { + + switch($component->name) { + + case 'VEVENT' : + + $FBTYPE = 'BUSY'; + if (isset($component->TRANSP) && (strtoupper($component->TRANSP) === 'TRANSPARENT')) { + break; + } + if (isset($component->STATUS)) { + $status = strtoupper($component->STATUS); + if ($status==='CANCELLED') { + break; + } + if ($status==='TENTATIVE') { + $FBTYPE = 'BUSY-TENTATIVE'; + } + } + + $times = array(); + + if ($component->RRULE) { + + $iterator = new RecurrenceIterator($object, (string)$component->uid); + if ($this->start) { + $iterator->fastForward($this->start); + } + + $maxRecurrences = 200; + + while($iterator->valid() && --$maxRecurrences) { + + $startTime = $iterator->getDTStart(); + if ($this->end && $startTime > $this->end) { + break; + } + $times[] = array( + $iterator->getDTStart(), + $iterator->getDTEnd(), + ); + + $iterator->next(); + + } + + } else { + + $startTime = $component->DTSTART->getDateTime(); + if ($this->end && $startTime > $this->end) { + break; + } + $endTime = null; + if (isset($component->DTEND)) { + $endTime = $component->DTEND->getDateTime(); + } elseif (isset($component->DURATION)) { + $duration = DateTimeParser::parseDuration((string)$component->DURATION); + $endTime = clone $startTime; + $endTime->add($duration); + } elseif ($component->DTSTART->getDateType() === Property\DateTime::DATE) { + $endTime = clone $startTime; + $endTime->modify('+1 day'); + } else { + // The event had no duration (0 seconds) + break; + } + + $times[] = array($startTime, $endTime); + + } + + foreach($times as $time) { + + if ($this->end && $time[0] > $this->end) break; + if ($this->start && $time[1] < $this->start) break; + + $busyTimes[] = array( + $time[0], + $time[1], + $FBTYPE, + ); + } + break; + + case 'VFREEBUSY' : + foreach($component->FREEBUSY as $freebusy) { + + $fbType = isset($freebusy['FBTYPE'])?strtoupper($freebusy['FBTYPE']):'BUSY'; + + // Skipping intervals marked as 'free' + if ($fbType==='FREE') + continue; + + $values = explode(',', $freebusy); + foreach($values as $value) { + list($startTime, $endTime) = explode('/', $value); + $startTime = DateTimeParser::parseDateTime($startTime); + + if (substr($endTime,0,1)==='P' || substr($endTime,0,2)==='-P') { + $duration = DateTimeParser::parseDuration($endTime); + $endTime = clone $startTime; + $endTime->add($duration); + } else { + $endTime = DateTimeParser::parseDateTime($endTime); + } + + if($this->start && $this->start > $endTime) continue; + if($this->end && $this->end < $startTime) continue; + $busyTimes[] = array( + $startTime, + $endTime, + $fbType + ); + + } + + + } + break; + + + + } + + + } + + } + + if ($this->baseObject) { + $calendar = $this->baseObject; + } else { + $calendar = Component::create('VCALENDAR'); + $calendar->version = '2.0'; + $calendar->prodid = '-//Sabre//Sabre VObject ' . Version::VERSION . '//EN'; + $calendar->calscale = 'GREGORIAN'; + } + + $vfreebusy = Component::create('VFREEBUSY'); + $calendar->add($vfreebusy); + + if ($this->start) { + $dtstart = Property::create('DTSTART'); + $dtstart->setDateTime($this->start,Property\DateTime::UTC); + $vfreebusy->add($dtstart); + } + if ($this->end) { + $dtend = Property::create('DTEND'); + $dtend->setDateTime($this->end,Property\DateTime::UTC); + $vfreebusy->add($dtend); + } + $dtstamp = Property::create('DTSTAMP'); + $dtstamp->setDateTime(new \DateTime('now'), Property\DateTime::UTC); + $vfreebusy->add($dtstamp); + + foreach($busyTimes as $busyTime) { + + $busyTime[0]->setTimeZone(new \DateTimeZone('UTC')); + $busyTime[1]->setTimeZone(new \DateTimeZone('UTC')); + + $prop = Property::create( + 'FREEBUSY', + $busyTime[0]->format('Ymd\\THis\\Z') . '/' . $busyTime[1]->format('Ymd\\THis\\Z') + ); + $prop['FBTYPE'] = $busyTime[2]; + $vfreebusy->add($prop); + + } + + return $calendar; + + } + +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Node.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Node.php new file mode 100644 index 00000000..bee68ec2 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Node.php @@ -0,0 +1,187 @@ +iterator)) + return $this->iterator; + + return new ElementList(array($this)); + + } + + /** + * Sets the overridden iterator + * + * Note that this is not actually part of the iterator interface + * + * @param ElementList $iterator + * @return void + */ + public function setIterator(ElementList $iterator) { + + $this->iterator = $iterator; + + } + + /* }}} */ + + /* {{{ Countable interface */ + + /** + * Returns the number of elements + * + * @return int + */ + public function count() { + + $it = $this->getIterator(); + return $it->count(); + + } + + /* }}} */ + + /* {{{ ArrayAccess Interface */ + + + /** + * Checks if an item exists through ArrayAccess. + * + * This method just forwards the request to the inner iterator + * + * @param int $offset + * @return bool + */ + public function offsetExists($offset) { + + $iterator = $this->getIterator(); + return $iterator->offsetExists($offset); + + } + + /** + * Gets an item through ArrayAccess. + * + * This method just forwards the request to the inner iterator + * + * @param int $offset + * @return mixed + */ + public function offsetGet($offset) { + + $iterator = $this->getIterator(); + return $iterator->offsetGet($offset); + + } + + /** + * Sets an item through ArrayAccess. + * + * This method just forwards the request to the inner iterator + * + * @param int $offset + * @param mixed $value + * @return void + */ + public function offsetSet($offset,$value) { + + $iterator = $this->getIterator(); + $iterator->offsetSet($offset,$value); + + // @codeCoverageIgnoreStart + // + // This method always throws an exception, so we ignore the closing + // brace + } + // @codeCoverageIgnoreEnd + + /** + * Sets an item through ArrayAccess. + * + * This method just forwards the request to the inner iterator + * + * @param int $offset + * @return void + */ + public function offsetUnset($offset) { + + $iterator = $this->getIterator(); + $iterator->offsetUnset($offset); + + // @codeCoverageIgnoreStart + // + // This method always throws an exception, so we ignore the closing + // brace + } + // @codeCoverageIgnoreEnd + + /* }}} */ + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php new file mode 100644 index 00000000..72bf03b4 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Parameter.php @@ -0,0 +1,104 @@ +name = strtoupper($name); + $this->value = $value; + + } + + /** + * Returns the parameter's internal value. + * + * @return string + */ + public function getValue() { + + return $this->value; + + } + + + /** + * Turns the object back into a serialized blob. + * + * @return string + */ + public function serialize() { + + if (is_null($this->value)) { + return $this->name; + } + $src = array( + '\\', + "\n", + ';', + ',', + ); + $out = array( + '\\\\', + '\n', + '\;', + '\,', + ); + + $value = str_replace($src, $out, $this->value); + if (strpos($value,":")!==false) { + $value = '"' . $value . '"'; + } + return $this->name . '=' . $value; + + } + + /** + * Called when this object is being cast to a string + * + * @return string + */ + public function __toString() { + + return $this->value; + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php new file mode 100644 index 00000000..66b49c60 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/ParseException.php @@ -0,0 +1,12 @@ + 'Sabre\\VObject\\Property\\DateTime', + 'CREATED' => 'Sabre\\VObject\\Property\\DateTime', + 'DTEND' => 'Sabre\\VObject\\Property\\DateTime', + 'DTSTAMP' => 'Sabre\\VObject\\Property\\DateTime', + 'DTSTART' => 'Sabre\\VObject\\Property\\DateTime', + 'DUE' => 'Sabre\\VObject\\Property\\DateTime', + 'EXDATE' => 'Sabre\\VObject\\Property\\MultiDateTime', + 'LAST-MODIFIED' => 'Sabre\\VObject\\Property\\DateTime', + 'RECURRENCE-ID' => 'Sabre\\VObject\\Property\\DateTime', + 'TRIGGER' => 'Sabre\\VObject\\Property\\DateTime', + 'N' => 'Sabre\\VObject\\Property\\Compound', + 'ORG' => 'Sabre\\VObject\\Property\\Compound', + 'ADR' => 'Sabre\\VObject\\Property\\Compound', + 'CATEGORIES' => 'Sabre\\VObject\\Property\\Compound', + ); + + /** + * Creates the new property by name, but in addition will also see if + * there's a class mapped to the property name. + * + * Parameters can be specified with the optional third argument. Parameters + * must be a key->value map of the parameter name, and value. If the value + * is specified as an array, it is assumed that multiple parameters with + * the same name should be added. + * + * @param string $name + * @param string $value + * @param array $parameters + * @return Property + */ + static public function create($name, $value = null, array $parameters = array()) { + + $name = strtoupper($name); + $shortName = $name; + $group = null; + if (strpos($shortName,'.')!==false) { + list($group, $shortName) = explode('.', $shortName); + } + + if (isset(self::$classMap[$shortName])) { + return new self::$classMap[$shortName]($name, $value, $parameters); + } else { + return new self($name, $value, $parameters); + } + + } + + /** + * Creates a new property object + * + * Parameters can be specified with the optional third argument. Parameters + * must be a key->value map of the parameter name, and value. If the value + * is specified as an array, it is assumed that multiple parameters with + * the same name should be added. + * + * @param string $name + * @param string $value + * @param array $parameters + */ + public function __construct($name, $value = null, array $parameters = array()) { + + if (!is_scalar($value) && !is_null($value)) { + throw new \InvalidArgumentException('The value argument must be scalar or null'); + } + + $name = strtoupper($name); + $group = null; + if (strpos($name,'.')!==false) { + list($group, $name) = explode('.', $name); + } + $this->name = $name; + $this->group = $group; + $this->setValue($value); + + foreach($parameters as $paramName => $paramValues) { + + if (!is_array($paramValues)) { + $paramValues = array($paramValues); + } + + foreach($paramValues as $paramValue) { + $this->add($paramName, $paramValue); + } + + } + + } + + /** + * Updates the internal value + * + * @param string $value + * @return void + */ + public function setValue($value) { + + $this->value = $value; + + } + + /** + * Returns the internal value + * + * @param string $value + * @return string + */ + public function getValue() { + + return $this->value; + + } + + /** + * Turns the object back into a serialized blob. + * + * @return string + */ + public function serialize() { + + $str = $this->name; + if ($this->group) $str = $this->group . '.' . $this->name; + + foreach($this->parameters as $param) { + + $str.=';' . $param->serialize(); + + } + + $src = array( + '\\', + "\n", + "\r", + ); + $out = array( + '\\\\', + '\n', + '', + ); + $str.=':' . str_replace($src, $out, $this->value); + + $out = ''; + while(strlen($str)>0) { + if (strlen($str)>75) { + $out.= mb_strcut($str,0,75,'utf-8') . "\r\n"; + $str = ' ' . mb_strcut($str,75,strlen($str),'utf-8'); + } else { + $out.=$str . "\r\n"; + $str=''; + break; + } + } + + return $out; + + } + + /** + * Adds a new componenten or element + * + * You can call this method with the following syntaxes: + * + * add(Parameter $element) + * add(string $name, $value) + * + * The first version adds an Parameter + * The second adds a property as a string. + * + * @param mixed $item + * @param mixed $itemValue + * @return void + */ + public function add($item, $itemValue = null) { + + if ($item instanceof Parameter) { + if (!is_null($itemValue)) { + throw new \InvalidArgumentException('The second argument must not be specified, when passing a VObject'); + } + $item->parent = $this; + $this->parameters[] = $item; + } elseif(is_string($item)) { + + $parameter = new Parameter($item,$itemValue); + $parameter->parent = $this; + $this->parameters[] = $parameter; + + } else { + + throw new \InvalidArgumentException('The first argument must either be a Node a string'); + + } + + } + + /* ArrayAccess interface {{{ */ + + /** + * Checks if an array element exists + * + * @param mixed $name + * @return bool + */ + public function offsetExists($name) { + + if (is_int($name)) return parent::offsetExists($name); + + $name = strtoupper($name); + + foreach($this->parameters as $parameter) { + if ($parameter->name == $name) return true; + } + return false; + + } + + /** + * Returns a parameter, or parameter list. + * + * @param string $name + * @return Node + */ + public function offsetGet($name) { + + if (is_int($name)) return parent::offsetGet($name); + $name = strtoupper($name); + + $result = array(); + foreach($this->parameters as $parameter) { + if ($parameter->name == $name) + $result[] = $parameter; + } + + if (count($result)===0) { + return null; + } elseif (count($result)===1) { + return $result[0]; + } else { + $result[0]->setIterator(new ElementList($result)); + return $result[0]; + } + + } + + /** + * Creates a new parameter + * + * @param string $name + * @param mixed $value + * @return void + */ + public function offsetSet($name, $value) { + + if (is_int($name)) parent::offsetSet($name, $value); + + if (is_scalar($value)) { + if (!is_string($name)) + throw new \InvalidArgumentException('A parameter name must be specified. This means you cannot use the $array[]="string" to add parameters.'); + + $this->offsetUnset($name); + $parameter = new Parameter($name, $value); + $parameter->parent = $this; + $this->parameters[] = $parameter; + + } elseif ($value instanceof Parameter) { + if (!is_null($name)) + throw new \InvalidArgumentException('Don\'t specify a parameter name if you\'re passing a \\Sabre\\VObject\\Parameter. Add using $array[]=$parameterObject.'); + + $value->parent = $this; + $this->parameters[] = $value; + } else { + throw new \InvalidArgumentException('You can only add parameters to the property object'); + } + + } + + /** + * Removes one or more parameters with the specified name + * + * @param string $name + * @return void + */ + public function offsetUnset($name) { + + if (is_int($name)) parent::offsetUnset($name); + $name = strtoupper($name); + + foreach($this->parameters as $key=>$parameter) { + if ($parameter->name == $name) { + $parameter->parent = null; + unset($this->parameters[$key]); + } + + } + + } + + /* }}} */ + + /** + * Called when this object is being cast to a string + * + * @return string + */ + public function __toString() { + + return (string)$this->value; + + } + + /** + * This method is automatically called when the object is cloned. + * Specifically, this will ensure all child elements are also cloned. + * + * @return void + */ + public function __clone() { + + foreach($this->parameters as $key=>$child) { + $this->parameters[$key] = clone $child; + $this->parameters[$key]->parent = $this; + } + + } + + /** + * Validates the node for correctness. + * + * The following options are supported: + * - Node::REPAIR - If something is broken, and automatic repair may + * be attempted. + * + * An array is returned with warnings. + * + * Every item in the array has the following properties: + * * level - (number between 1 and 3 with severity information) + * * message - (human readable message) + * * node - (reference to the offending node) + * + * @param int $options + * @return array + */ + public function validate($options = 0) { + + $warnings = array(); + + // Checking if our value is UTF-8 + if (!StringUtil::isUTF8($this->value)) { + $warnings[] = array( + 'level' => 1, + 'message' => 'Property is not valid UTF-8!', + 'node' => $this, + ); + if ($options & self::REPAIR) { + $this->value = StringUtil::convertToUTF8($this->value); + } + } + + // Checking if the propertyname does not contain any invalid bytes. + if (!preg_match('/^([A-Z0-9-]+)$/', $this->name)) { + $warnings[] = array( + 'level' => 1, + 'message' => 'The propertyname: ' . $this->name . ' contains invalid characters. Only A-Z, 0-9 and - are allowed', + 'node' => $this, + ); + if ($options & self::REPAIR) { + // Uppercasing and converting underscores to dashes. + $this->name = strtoupper( + str_replace('_', '-', $this->name) + ); + // Removing every other invalid character + $this->name = preg_replace('/([^A-Z0-9-])/u', '', $this->name); + + } + + } + + // Validating inner parameters + foreach($this->parameters as $param) { + $warnings = array_merge($warnings, $param->validate($options)); + } + + return $warnings; + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php new file mode 100644 index 00000000..26f09006 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/Compound.php @@ -0,0 +1,125 @@ + ';', + 'ADR' => ';', + 'ORG' => ';', + 'CATEGORIES' => ',', + ); + + /** + * The currently used delimiter. + * + * @var string + */ + protected $delimiter = null; + + /** + * Get a compound value as an array. + * + * @param $name string + * @return array + */ + public function getParts() { + + if (is_null($this->value)) { + return array(); + } + + $delimiter = $this->getDelimiter(); + + // split by any $delimiter which is NOT prefixed by a slash. + // Note that this is not a a perfect solution. If a value is prefixed + // by two slashes, it should actually be split anyway. + // + // Hopefully we can fix this better in a future version, where we can + // break compatibility a bit. + $compoundValues = preg_split("/(?value); + + // remove slashes from any semicolon and comma left escaped in the single values + $compoundValues = array_map( + function($val) { + return strtr($val, array('\,' => ',', '\;' => ';')); + }, $compoundValues); + + return $compoundValues; + + } + + /** + * Returns the delimiter for this property. + * + * @return string + */ + public function getDelimiter() { + + if (!$this->delimiter) { + if (isset(self::$delimiterMap[$this->name])) { + $this->delimiter = self::$delimiterMap[$this->name]; + } else { + // To be a bit future proof, we are going to default the + // delimiter to ; + $this->delimiter = ';'; + } + } + return $this->delimiter; + + } + + /** + * Set a compound value as an array. + * + * + * @param $name string + * @return array + */ + public function setParts(array $values) { + + // add slashes to all semicolons and commas in the single values + $values = array_map( + function($val) { + return strtr($val, array(',' => '\,', ';' => '\;')); + }, $values); + + $this->setValue( + implode($this->getDelimiter(), $values) + ); + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php new file mode 100644 index 00000000..95e9b020 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/DateTime.php @@ -0,0 +1,245 @@ +setValue($dt->format('Ymd\\THis')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case self::UTC : + $dt->setTimeZone(new \DateTimeZone('UTC')); + $this->setValue($dt->format('Ymd\\THis\\Z')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case self::LOCALTZ : + $this->setValue($dt->format('Ymd\\THis')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE-TIME'); + $this->offsetSet('TZID', $dt->getTimeZone()->getName()); + break; + case self::DATE : + $this->setValue($dt->format('Ymd')); + $this->offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + $this->offsetSet('VALUE','DATE'); + break; + default : + throw new \InvalidArgumentException('You must pass a valid dateType constant'); + + } + $this->dateTime = $dt; + $this->dateType = $dateType; + + } + + /** + * Returns the current DateTime value. + * + * If no value was set, this method returns null. + * + * @return \DateTime|null + */ + public function getDateTime() { + + if ($this->dateTime) + return $this->dateTime; + + list( + $this->dateType, + $this->dateTime + ) = self::parseData($this->value, $this); + return $this->dateTime; + + } + + /** + * Returns the type of Date format. + * + * This method returns one of the format constants. If no date was set, + * this method will return null. + * + * @return int|null + */ + public function getDateType() { + + if ($this->dateType) + return $this->dateType; + + list( + $this->dateType, + $this->dateTime, + ) = self::parseData($this->value, $this); + return $this->dateType; + + } + + /** + * This method will return true, if the property had a date and a time, as + * opposed to only a date. + * + * @return bool + */ + public function hasTime() { + + return $this->getDateType()!==self::DATE; + + } + + /** + * Parses the internal data structure to figure out what the current date + * and time is. + * + * The returned array contains two elements: + * 1. A 'DateType' constant (as defined on this class), or null. + * 2. A DateTime object (or null) + * + * @param string|null $propertyValue The string to parse (yymmdd or + * ymmddThhmmss, etc..) + * @param \Sabre\VObject\Property|null $property The instance of the + * property we're parsing. + * @return array + */ + static public function parseData($propertyValue, VObject\Property $property = null) { + + if (is_null($propertyValue)) { + return array(null, null); + } + + $date = '(?P[1-2][0-9]{3})(?P[0-1][0-9])(?P[0-3][0-9])'; + $time = '(?P[0-2][0-9])(?P[0-5][0-9])(?P[0-5][0-9])'; + $regex = "/^$date(T$time(?PZ)?)?$/"; + + if (!preg_match($regex, $propertyValue, $matches)) { + throw new \InvalidArgumentException($propertyValue . ' is not a valid \DateTime or Date string'); + } + + if (!isset($matches['hour'])) { + // Date-only + return array( + self::DATE, + new \DateTime($matches['year'] . '-' . $matches['month'] . '-' . $matches['date'] . ' 00:00:00', new \DateTimeZone('UTC')), + ); + } + + $dateStr = + $matches['year'] .'-' . + $matches['month'] . '-' . + $matches['date'] . ' ' . + $matches['hour'] . ':' . + $matches['minute'] . ':' . + $matches['second']; + + if (isset($matches['isutc'])) { + $dt = new \DateTime($dateStr,new \DateTimeZone('UTC')); + $dt->setTimeZone(new \DateTimeZone('UTC')); + return array( + self::UTC, + $dt + ); + } + + // Finding the timezone. + $tzid = $property['TZID']; + if (!$tzid) { + // This was a floating time string. This implies we use the + // timezone from date_default_timezone_set / date.timezone ini + // setting. + return array( + self::LOCAL, + new \DateTime($dateStr) + ); + } + + // To look up the timezone, we must first find the VCALENDAR component. + $root = $property; + while($root->parent) { + $root = $root->parent; + } + if ($root->name === 'VCALENDAR') { + $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid, $root); + } else { + $tz = VObject\TimeZoneUtil::getTimeZone((string)$tzid); + } + + $dt = new \DateTime($dateStr, $tz); + $dt->setTimeZone($tz); + + return array( + self::LOCALTZ, + $dt + ); + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php new file mode 100644 index 00000000..f01491b6 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Property/MultiDateTime.php @@ -0,0 +1,180 @@ +offsetUnset('VALUE'); + $this->offsetUnset('TZID'); + switch($dateType) { + + case DateTime::LOCAL : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd\\THis'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case DateTime::UTC : + $val = array(); + foreach($dt as $i) { + $i->setTimeZone(new \DateTimeZone('UTC')); + $val[] = $i->format('Ymd\\THis\\Z'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + break; + case DateTime::LOCALTZ : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd\\THis'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE-TIME'); + $this->offsetSet('TZID', $dt[0]->getTimeZone()->getName()); + break; + case DateTime::DATE : + $val = array(); + foreach($dt as $i) { + $val[] = $i->format('Ymd'); + } + $this->setValue(implode(',',$val)); + $this->offsetSet('VALUE','DATE'); + break; + default : + throw new \InvalidArgumentException('You must pass a valid dateType constant'); + + } + $this->dateTimes = $dt; + $this->dateType = $dateType; + + } + + /** + * Returns the current DateTime value. + * + * If no value was set, this method returns null. + * + * @return array|null + */ + public function getDateTimes() { + + if ($this->dateTimes) + return $this->dateTimes; + + $dts = array(); + + if (!$this->value) { + $this->dateTimes = null; + $this->dateType = null; + return null; + } + + foreach(explode(',',$this->value) as $val) { + list( + $type, + $dt + ) = DateTime::parseData($val, $this); + $dts[] = $dt; + $this->dateType = $type; + } + $this->dateTimes = $dts; + return $this->dateTimes; + + } + + /** + * Returns the type of Date format. + * + * This method returns one of the format constants. If no date was set, + * this method will return null. + * + * @return int|null + */ + public function getDateType() { + + if ($this->dateType) + return $this->dateType; + + if (!$this->value) { + $this->dateTimes = null; + $this->dateType = null; + return null; + } + + $dts = array(); + foreach(explode(',',$this->value) as $val) { + list( + $type, + $dt + ) = DateTime::parseData($val, $this); + $dts[] = $dt; + $this->dateType = $type; + } + $this->dateTimes = $dts; + return $this->dateType; + + } + + /** + * This method will return true, if the property had a date and a time, as + * opposed to only a date. + * + * @return bool + */ + public function hasTime() { + + return $this->getDateType()!==DateTime::DATE; + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php new file mode 100644 index 00000000..a001b2bf --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Reader.php @@ -0,0 +1,223 @@ +add($parsedLine); + + if ($nextLine===false) + throw new ParseException('Invalid VObject. Document ended prematurely.'); + + } + + // Checking component name of the 'END:' line. + if (substr($nextLine,4)!==$obj->name) { + throw new ParseException('Invalid VObject, expected: "END:' . $obj->name . '" got: "' . $nextLine . '"'); + } + next($lines); + + return $obj; + + } + + // Properties + //$result = preg_match('/(?P[A-Z0-9-]+)(?:;(?P^(?([^:^\"]|\"([^\"]*)\")*))?"; + $regex = "/^(?P$token)$parameters:(?P.*)$/i"; + + $result = preg_match($regex,$line,$matches); + + if (!$result) { + if ($options & self::OPTION_IGNORE_INVALID_LINES) { + return null; + } else { + throw new ParseException('Invalid VObject, line ' . ($lineNr+1) . ' did not follow the icalendar/vcard format'); + } + } + + $propertyName = strtoupper($matches['name']); + $propertyValue = preg_replace_callback('#(\\\\(\\\\|N|n))#',function($matches) { + if ($matches[2]==='n' || $matches[2]==='N') { + return "\n"; + } else { + return $matches[2]; + } + }, $matches['value']); + + $obj = Property::create($propertyName, $propertyValue); + + if ($matches['parameters']) { + + foreach(self::readParameters($matches['parameters']) as $param) { + $obj->add($param); + } + + } + + return $obj; + + + } + + /** + * Reads a parameter list from a property + * + * This method returns an array of Parameter + * + * @param string $parameters + * @return array + */ + static private function readParameters($parameters) { + + $token = '[A-Z0-9-]+'; + + $paramValue = '(?P[^\"^;]*|"[^"]*")'; + + $regex = "/(?<=^|;)(?P$token)(=$paramValue(?=$|;))?/i"; + preg_match_all($regex, $parameters, $matches, PREG_SET_ORDER); + + $params = array(); + foreach($matches as $match) { + + if (!isset($match['paramValue'])) { + + $value = null; + + } else { + + $value = $match['paramValue']; + + if (isset($value[0]) && $value[0]==='"') { + // Stripping quotes, if needed + $value = substr($value,1,strlen($value)-2); + } + + $value = preg_replace_callback('#(\\\\(\\\\|N|n|;|,))#',function($matches) { + if ($matches[2]==='n' || $matches[2]==='N') { + return "\n"; + } else { + return $matches[2]; + } + }, $value); + + } + + $params[] = new Parameter($match['paramName'], $value); + + } + + return $params; + + } + + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php new file mode 100644 index 00000000..8bd4ed22 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/RecurrenceIterator.php @@ -0,0 +1,1144 @@ + 0, + 'MO' => 1, + 'TU' => 2, + 'WE' => 3, + 'TH' => 4, + 'FR' => 5, + 'SA' => 6, + ); + + /** + * Mappings between the day number and english day name. + * + * @var array + */ + private $dayNames = array( + 0 => 'Sunday', + 1 => 'Monday', + 2 => 'Tuesday', + 3 => 'Wednesday', + 4 => 'Thursday', + 5 => 'Friday', + 6 => 'Saturday', + ); + + /** + * If the current iteration of the event is an overriden event, this + * property will hold the VObject + * + * @var Component + */ + private $currentOverriddenEvent; + + /** + * This property may contain the date of the next not-overridden event. + * This date is calculated sometimes a bit early, before overridden events + * are evaluated. + * + * @var DateTime + */ + private $nextDate; + + /** + * This counts the number of overridden events we've handled so far + * + * @var int + */ + private $handledOverridden = 0; + + /** + * Creates the iterator + * + * You should pass a VCALENDAR component, as well as the UID of the event + * we're going to traverse. + * + * @param Component $vcal + * @param string|null $uid + */ + public function __construct(Component $vcal, $uid=null) { + + if (is_null($uid)) { + if ($vcal->name === 'VCALENDAR') { + throw new \InvalidArgumentException('If you pass a VCALENDAR object, you must pass a uid argument as well'); + } + $components = array($vcal); + $uid = (string)$vcal->uid; + } else { + $components = $vcal->select('VEVENT'); + } + foreach($components as $component) { + if ((string)$component->uid == $uid) { + if (isset($component->{'RECURRENCE-ID'})) { + $this->overriddenEvents[$component->DTSTART->getDateTime()->getTimeStamp()] = $component; + $this->overriddenDates[] = $component->{'RECURRENCE-ID'}->getDateTime(); + } else { + $this->baseEvent = $component; + } + } + } + + ksort($this->overriddenEvents); + + if (!$this->baseEvent) { + throw new \InvalidArgumentException('Could not find a base event with uid: ' . $uid); + } + + $this->startDate = clone $this->baseEvent->DTSTART->getDateTime(); + + $this->endDate = null; + if (isset($this->baseEvent->DTEND)) { + $this->endDate = clone $this->baseEvent->DTEND->getDateTime(); + } else { + $this->endDate = clone $this->startDate; + if (isset($this->baseEvent->DURATION)) { + $this->endDate->add(DateTimeParser::parse($this->baseEvent->DURATION->value)); + } elseif ($this->baseEvent->DTSTART->getDateType()===Property\DateTime::DATE) { + $this->endDate->modify('+1 day'); + } + } + $this->currentDate = clone $this->startDate; + + $rrule = (string)$this->baseEvent->RRULE; + + $parts = explode(';', $rrule); + + // If no rrule was specified, we create a default setting + if (!$rrule) { + $this->frequency = 'daily'; + $this->count = 1; + } else foreach($parts as $part) { + + list($key, $value) = explode('=', $part, 2); + + switch(strtoupper($key)) { + + case 'FREQ' : + if (!in_array( + strtolower($value), + array('secondly','minutely','hourly','daily','weekly','monthly','yearly') + )) { + throw new \InvalidArgumentException('Unknown value for FREQ=' . strtoupper($value)); + + } + $this->frequency = strtolower($value); + break; + + case 'UNTIL' : + $this->until = DateTimeParser::parse($value); + + // In some cases events are generated with an UNTIL= + // parameter before the actual start of the event. + // + // Not sure why this is happening. We assume that the + // intention was that the event only recurs once. + // + // So we are modifying the parameter so our code doesn't + // break. + if($this->until < $this->baseEvent->DTSTART->getDateTime()) { + $this->until = $this->baseEvent->DTSTART->getDateTime(); + } + break; + + case 'COUNT' : + $this->count = (int)$value; + break; + + case 'INTERVAL' : + $this->interval = (int)$value; + if ($this->interval < 1) { + throw new \InvalidArgumentException('INTERVAL in RRULE must be a positive integer!'); + } + break; + + case 'BYSECOND' : + $this->bySecond = explode(',', $value); + break; + + case 'BYMINUTE' : + $this->byMinute = explode(',', $value); + break; + + case 'BYHOUR' : + $this->byHour = explode(',', $value); + break; + + case 'BYDAY' : + $this->byDay = explode(',', strtoupper($value)); + break; + + case 'BYMONTHDAY' : + $this->byMonthDay = explode(',', $value); + break; + + case 'BYYEARDAY' : + $this->byYearDay = explode(',', $value); + break; + + case 'BYWEEKNO' : + $this->byWeekNo = explode(',', $value); + break; + + case 'BYMONTH' : + $this->byMonth = explode(',', $value); + break; + + case 'BYSETPOS' : + $this->bySetPos = explode(',', $value); + break; + + case 'WKST' : + $this->weekStart = strtoupper($value); + break; + + } + + } + + // Parsing exception dates + if (isset($this->baseEvent->EXDATE)) { + foreach($this->baseEvent->EXDATE as $exDate) { + + foreach(explode(',', (string)$exDate) as $exceptionDate) { + + $this->exceptionDates[] = + DateTimeParser::parse($exceptionDate, $this->startDate->getTimeZone()); + + } + + } + + } + + } + + /** + * Returns the current item in the list + * + * @return DateTime + */ + public function current() { + + if (!$this->valid()) return null; + return clone $this->currentDate; + + } + + /** + * This method returns the startdate for the current iteration of the + * event. + * + * @return DateTime + */ + public function getDtStart() { + + if (!$this->valid()) return null; + return clone $this->currentDate; + + } + + /** + * This method returns the enddate for the current iteration of the + * event. + * + * @return DateTime + */ + public function getDtEnd() { + + if (!$this->valid()) return null; + $dtEnd = clone $this->currentDate; + $dtEnd->add( $this->startDate->diff( $this->endDate ) ); + return clone $dtEnd; + + } + + /** + * Returns a VEVENT object with the updated start and end date. + * + * Any recurrence information is removed, and this function may return an + * 'overridden' event instead. + * + * This method always returns a cloned instance. + * + * @return Component\VEvent + */ + public function getEventObject() { + + if ($this->currentOverriddenEvent) { + return clone $this->currentOverriddenEvent; + } + $event = clone $this->baseEvent; + unset($event->RRULE); + unset($event->EXDATE); + unset($event->RDATE); + unset($event->EXRULE); + + $event->DTSTART->setDateTime($this->getDTStart(), $event->DTSTART->getDateType()); + if (isset($event->DTEND)) { + $event->DTEND->setDateTime($this->getDtEnd(), $event->DTSTART->getDateType()); + } + if ($this->counter > 0) { + $event->{'RECURRENCE-ID'} = (string)$event->DTSTART; + } + + return $event; + + } + + /** + * Returns the current item number + * + * @return int + */ + public function key() { + + return $this->counter; + + } + + /** + * Whether or not there is a 'next item' + * + * @return bool + */ + public function valid() { + + if (!is_null($this->count)) { + return $this->counter < $this->count; + } + if (!is_null($this->until) && $this->currentDate > $this->until) { + + // Need to make sure there's no overridden events past the + // until date. + foreach($this->overriddenEvents as $overriddenEvent) { + + if ($overriddenEvent->DTSTART->getDateTime() >= $this->currentDate) { + + return true; + } + } + return false; + } + return true; + + } + + /** + * Resets the iterator + * + * @return void + */ + public function rewind() { + + $this->currentDate = clone $this->startDate; + $this->counter = 0; + + } + + /** + * This method allows you to quickly go to the next occurrence after the + * specified date. + * + * Note that this checks the current 'endDate', not the 'stardDate'. This + * means that if you forward to January 1st, the iterator will stop at the + * first event that ends *after* January 1st. + * + * @param DateTime $dt + * @return void + */ + public function fastForward(\DateTime $dt) { + + while($this->valid() && $this->getDTEnd() <= $dt) { + $this->next(); + } + + } + + /** + * Returns true if this recurring event never ends. + * + * @return bool + */ + public function isInfinite() { + + return !$this->count && !$this->until; + + } + + /** + * Goes on to the next iteration + * + * @return void + */ + public function next() { + + $previousStamp = $this->currentDate->getTimeStamp(); + + // Finding the next overridden event in line, and storing that for + // later use. + $overriddenEvent = null; + $overriddenDate = null; + $this->currentOverriddenEvent = null; + + foreach($this->overriddenEvents as $index=>$event) { + if ($index > $previousStamp) { + $overriddenEvent = $event; + $overriddenDate = clone $event->DTSTART->getDateTime(); + break; + } + } + + // If we have a stored 'next date', we will use that. + if ($this->nextDate) { + if (!$overriddenDate || $this->nextDate < $overriddenDate) { + $this->currentDate = $this->nextDate; + $currentStamp = $this->currentDate->getTimeStamp(); + $this->nextDate = null; + } else { + $this->currentDate = clone $overriddenDate; + $this->currentOverriddenEvent = $overriddenEvent; + } + $this->counter++; + return; + } + + while(true) { + + // Otherwise, we find the next event in the normal RRULE + // sequence. + switch($this->frequency) { + + case 'hourly' : + $this->nextHourly(); + break; + + case 'daily' : + $this->nextDaily(); + break; + + case 'weekly' : + $this->nextWeekly(); + break; + + case 'monthly' : + $this->nextMonthly(); + break; + + case 'yearly' : + $this->nextYearly(); + break; + + } + $currentStamp = $this->currentDate->getTimeStamp(); + + + // Checking exception dates + foreach($this->exceptionDates as $exceptionDate) { + if ($this->currentDate == $exceptionDate) { + $this->counter++; + continue 2; + } + } + foreach($this->overriddenDates as $check) { + if ($this->currentDate == $check) { + continue 2; + } + } + break; + + } + + + + // Is the date we have actually higher than the next overiddenEvent? + if ($overriddenDate && $this->currentDate > $overriddenDate) { + $this->nextDate = clone $this->currentDate; + $this->currentDate = clone $overriddenDate; + $this->currentOverriddenEvent = $overriddenEvent; + $this->handledOverridden++; + } + $this->counter++; + + + /* + * If we have overridden events left in the queue, but our counter is + * running out, we should grab one of those. + */ + if (!is_null($overriddenEvent) && !is_null($this->count) && count($this->overriddenEvents) - $this->handledOverridden >= ($this->count - $this->counter)) { + + $this->currentOverriddenEvent = $overriddenEvent; + $this->currentDate = clone $overriddenDate; + $this->handledOverridden++; + + } + + } + + /** + * Does the processing for advancing the iterator for hourly frequency. + * + * @return void + */ + protected function nextHourly() { + + if (!$this->byHour) { + $this->currentDate->modify('+' . $this->interval . ' hours'); + return; + } + } + + /** + * Does the processing for advancing the iterator for daily frequency. + * + * @return void + */ + protected function nextDaily() { + + if (!$this->byHour && !$this->byDay) { + $this->currentDate->modify('+' . $this->interval . ' days'); + return; + } + + if (isset($this->byHour)) { + $recurrenceHours = $this->getHours(); + } + + if (isset($this->byDay)) { + $recurrenceDays = $this->getDays(); + } + + do { + + if ($this->byHour) { + if ($this->currentDate->format('G') == '23') { + // to obey the interval rule + $this->currentDate->modify('+' . $this->interval-1 . ' days'); + } + + $this->currentDate->modify('+1 hours'); + + } else { + $this->currentDate->modify('+' . $this->interval . ' days'); + + } + + // Current day of the week + $currentDay = $this->currentDate->format('w'); + + // Current hour of the day + $currentHour = $this->currentDate->format('G'); + + } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours))); + + } + + /** + * Does the processing for advancing the iterator for weekly frequency. + * + * @return void + */ + protected function nextWeekly() { + + if (!$this->byHour && !$this->byDay) { + $this->currentDate->modify('+' . $this->interval . ' weeks'); + return; + } + + if ($this->byHour) { + $recurrenceHours = $this->getHours(); + } + + if ($this->byDay) { + $recurrenceDays = $this->getDays(); + } + + // First day of the week: + $firstDay = $this->dayMap[$this->weekStart]; + + do { + + if ($this->byHour) { + $this->currentDate->modify('+1 hours'); + } else { + $this->currentDate->modify('+1 days'); + } + + // Current day of the week + $currentDay = (int) $this->currentDate->format('w'); + + // Current hour of the day + $currentHour = (int) $this->currentDate->format('G'); + + // We need to roll over to the next week + if ($currentDay === $firstDay && (!$this->byHour || $currentHour == '0')) { + $this->currentDate->modify('+' . $this->interval-1 . ' weeks'); + + // We need to go to the first day of this week, but only if we + // are not already on this first day of this week. + if($this->currentDate->format('w') != $firstDay) { + $this->currentDate->modify('last ' . $this->dayNames[$this->dayMap[$this->weekStart]]); + } + } + + // We have a match + } while (($this->byDay && !in_array($currentDay, $recurrenceDays)) || ($this->byHour && !in_array($currentHour, $recurrenceHours))); + } + + /** + * Does the processing for advancing the iterator for monthly frequency. + * + * @return void + */ + protected function nextMonthly() { + + $currentDayOfMonth = $this->currentDate->format('j'); + if (!$this->byMonthDay && !$this->byDay) { + + // If the current day is higher than the 28th, rollover can + // occur to the next month. We Must skip these invalid + // entries. + if ($currentDayOfMonth < 29) { + $this->currentDate->modify('+' . $this->interval . ' months'); + } else { + $increase = 0; + do { + $increase++; + $tempDate = clone $this->currentDate; + $tempDate->modify('+ ' . ($this->interval*$increase) . ' months'); + } while ($tempDate->format('j') != $currentDayOfMonth); + $this->currentDate = $tempDate; + } + return; + } + + while(true) { + + $occurrences = $this->getMonthlyOccurrences(); + + foreach($occurrences as $occurrence) { + + // The first occurrence thats higher than the current + // day of the month wins. + if ($occurrence > $currentDayOfMonth) { + break 2; + } + + } + + // If we made it all the way here, it means there were no + // valid occurrences, and we need to advance to the next + // month. + $this->currentDate->modify('first day of this month'); + $this->currentDate->modify('+ ' . $this->interval . ' months'); + + // This goes to 0 because we need to start counting at hte + // beginning. + $currentDayOfMonth = 0; + + } + + $this->currentDate->setDate($this->currentDate->format('Y'), $this->currentDate->format('n'), $occurrence); + + } + + /** + * Does the processing for advancing the iterator for yearly frequency. + * + * @return void + */ + protected function nextYearly() { + + $currentMonth = $this->currentDate->format('n'); + $currentYear = $this->currentDate->format('Y'); + $currentDayOfMonth = $this->currentDate->format('j'); + + // No sub-rules, so we just advance by year + if (!$this->byMonth) { + + // Unless it was a leap day! + if ($currentMonth==2 && $currentDayOfMonth==29) { + + $counter = 0; + do { + $counter++; + // Here we increase the year count by the interval, until + // we hit a date that's also in a leap year. + // + // We could just find the next interval that's dividable by + // 4, but that would ignore the rule that there's no leap + // year every year that's dividable by a 100, but not by + // 400. (1800, 1900, 2100). So we just rely on the datetime + // functions instead. + $nextDate = clone $this->currentDate; + $nextDate->modify('+ ' . ($this->interval*$counter) . ' years'); + } while ($nextDate->format('n')!=2); + $this->currentDate = $nextDate; + + return; + + } + + // The easiest form + $this->currentDate->modify('+' . $this->interval . ' years'); + return; + + } + + $currentMonth = $this->currentDate->format('n'); + $currentYear = $this->currentDate->format('Y'); + $currentDayOfMonth = $this->currentDate->format('j'); + + $advancedToNewMonth = false; + + // If we got a byDay or getMonthDay filter, we must first expand + // further. + if ($this->byDay || $this->byMonthDay) { + + while(true) { + + $occurrences = $this->getMonthlyOccurrences(); + + foreach($occurrences as $occurrence) { + + // The first occurrence that's higher than the current + // day of the month wins. + // If we advanced to the next month or year, the first + // occurrence is always correct. + if ($occurrence > $currentDayOfMonth || $advancedToNewMonth) { + break 2; + } + + } + + // If we made it here, it means we need to advance to + // the next month or year. + $currentDayOfMonth = 1; + $advancedToNewMonth = true; + do { + + $currentMonth++; + if ($currentMonth>12) { + $currentYear+=$this->interval; + $currentMonth = 1; + } + } while (!in_array($currentMonth, $this->byMonth)); + + $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth); + + } + + // If we made it here, it means we got a valid occurrence + $this->currentDate->setDate($currentYear, $currentMonth, $occurrence); + return; + + } else { + + // These are the 'byMonth' rules, if there are no byDay or + // byMonthDay sub-rules. + do { + + $currentMonth++; + if ($currentMonth>12) { + $currentYear+=$this->interval; + $currentMonth = 1; + } + } while (!in_array($currentMonth, $this->byMonth)); + $this->currentDate->setDate($currentYear, $currentMonth, $currentDayOfMonth); + + return; + + } + + } + + /** + * Returns all the occurrences for a monthly frequency with a 'byDay' or + * 'byMonthDay' expansion for the current month. + * + * The returned list is an array of integers with the day of month (1-31). + * + * @return array + */ + protected function getMonthlyOccurrences() { + + $startDate = clone $this->currentDate; + + $byDayResults = array(); + + // Our strategy is to simply go through the byDays, advance the date to + // that point and add it to the results. + if ($this->byDay) foreach($this->byDay as $day) { + + $dayName = $this->dayNames[$this->dayMap[substr($day,-2)]]; + + // Dayname will be something like 'wednesday'. Now we need to find + // all wednesdays in this month. + $dayHits = array(); + + $checkDate = clone $startDate; + $checkDate->modify('first day of this month'); + $checkDate->modify($dayName); + + do { + $dayHits[] = $checkDate->format('j'); + $checkDate->modify('next ' . $dayName); + } while ($checkDate->format('n') === $startDate->format('n')); + + // So now we have 'all wednesdays' for month. It is however + // possible that the user only really wanted the 1st, 2nd or last + // wednesday. + if (strlen($day)>2) { + $offset = (int)substr($day,0,-2); + + if ($offset>0) { + // It is possible that the day does not exist, such as a + // 5th or 6th wednesday of the month. + if (isset($dayHits[$offset-1])) { + $byDayResults[] = $dayHits[$offset-1]; + } + } else { + + // if it was negative we count from the end of the array + $byDayResults[] = $dayHits[count($dayHits) + $offset]; + } + } else { + // There was no counter (first, second, last wednesdays), so we + // just need to add the all to the list). + $byDayResults = array_merge($byDayResults, $dayHits); + + } + + } + + $byMonthDayResults = array(); + if ($this->byMonthDay) foreach($this->byMonthDay as $monthDay) { + + // Removing values that are out of range for this month + if ($monthDay > $startDate->format('t') || + $monthDay < 0-$startDate->format('t')) { + continue; + } + if ($monthDay>0) { + $byMonthDayResults[] = $monthDay; + } else { + // Negative values + $byMonthDayResults[] = $startDate->format('t') + 1 + $monthDay; + } + } + + // If there was just byDay or just byMonthDay, they just specify our + // (almost) final list. If both were provided, then byDay limits the + // list. + if ($this->byMonthDay && $this->byDay) { + $result = array_intersect($byMonthDayResults, $byDayResults); + } elseif ($this->byMonthDay) { + $result = $byMonthDayResults; + } else { + $result = $byDayResults; + } + $result = array_unique($result); + sort($result, SORT_NUMERIC); + + // The last thing that needs checking is the BYSETPOS. If it's set, it + // means only certain items in the set survive the filter. + if (!$this->bySetPos) { + return $result; + } + + $filteredResult = array(); + foreach($this->bySetPos as $setPos) { + + if ($setPos<0) { + $setPos = count($result)-($setPos+1); + } + if (isset($result[$setPos-1])) { + $filteredResult[] = $result[$setPos-1]; + } + } + + sort($filteredResult, SORT_NUMERIC); + return $filteredResult; + + } + + protected function getHours() + { + $recurrenceHours = array(); + foreach($this->byHour as $byHour) { + $recurrenceHours[] = $byHour; + } + + return $recurrenceHours; + } + + protected function getDays() + { + $recurrenceDays = array(); + foreach($this->byDay as $byDay) { + + // The day may be preceeded with a positive (+n) or + // negative (-n) integer. However, this does not make + // sense in 'weekly' so we ignore it here. + $recurrenceDays[] = $this->dayMap[substr($byDay,-2)]; + + } + + return $recurrenceDays; + } +} + diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php new file mode 100644 index 00000000..657cfb81 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/ICalendar.php @@ -0,0 +1,111 @@ +children as $component) { + if (!$component instanceof VObject\Component) { + continue; + } + + // Get all timezones + if ($component->name === 'VTIMEZONE') { + $this->vtimezones[(string)$component->TZID] = $component; + continue; + } + + // Get component UID for recurring Events search + if($component->UID) { + $uid = (string)$component->UID; + } else { + // Generating a random UID + $uid = sha1(microtime()) . '-vobjectimport'; + } + + // Take care of recurring events + if (!array_key_exists($uid, $this->objects)) { + $this->objects[$uid] = VObject\Component::create('VCALENDAR'); + } + + $this->objects[$uid]->add(clone $component); + } + + } + + /** + * Every time getNext() is called, a new object will be parsed, until we + * hit the end of the stream. + * + * When the end is reached, null will be returned. + * + * @return Sabre\VObject\Component|null + */ + public function getNext() { + + if($object=array_shift($this->objects)) { + + // create our baseobject + $object->version = '2.0'; + $object->prodid = '-//Sabre//Sabre VObject ' . VObject\Version::VERSION . '//EN'; + $object->calscale = 'GREGORIAN'; + + // add vtimezone information to obj (if we have it) + foreach ($this->vtimezones as $vtimezone) { + $object->add($vtimezone); + } + + return $object; + + } else { + + return null; + + } + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php new file mode 100644 index 00000000..c0126883 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Splitter/SplitterInterface.php @@ -0,0 +1,39 @@ +input = $input; + + } + + /** + * Every time getNext() is called, a new object will be parsed, until we + * hit the end of the stream. + * + * When the end is reached, null will be returned. + * + * @return Sabre\VObject\Component|null + */ + public function getNext() { + + $vcard = ''; + + do { + + if (feof($this->input)) { + return false; + } + + $line = fgets($this->input); + $vcard .= $line; + + } while(strtoupper(substr($line,0,4))!=="END:"); + + $object = VObject\Reader::read($vcard); + + if($object->name !== 'VCARD') { + throw new \InvalidArgumentException("Thats no vCard!", 1); + } + + return $object; + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php new file mode 100644 index 00000000..ea88e1e8 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/StringUtil.php @@ -0,0 +1,61 @@ +'Australia/Darwin', + 'AUS Eastern Standard Time'=>'Australia/Sydney', + 'Afghanistan Standard Time'=>'Asia/Kabul', + 'Alaskan Standard Time'=>'America/Anchorage', + 'Arab Standard Time'=>'Asia/Riyadh', + 'Arabian Standard Time'=>'Asia/Dubai', + 'Arabic Standard Time'=>'Asia/Baghdad', + 'Argentina Standard Time'=>'America/Buenos_Aires', + 'Armenian Standard Time'=>'Asia/Yerevan', + 'Atlantic Standard Time'=>'America/Halifax', + 'Azerbaijan Standard Time'=>'Asia/Baku', + 'Azores Standard Time'=>'Atlantic/Azores', + 'Bangladesh Standard Time'=>'Asia/Dhaka', + 'Canada Central Standard Time'=>'America/Regina', + 'Cape Verde Standard Time'=>'Atlantic/Cape_Verde', + 'Caucasus Standard Time'=>'Asia/Yerevan', + 'Cen. Australia Standard Time'=>'Australia/Adelaide', + 'Central America Standard Time'=>'America/Guatemala', + 'Central Asia Standard Time'=>'Asia/Almaty', + 'Central Brazilian Standard Time'=>'America/Cuiaba', + 'Central Europe Standard Time'=>'Europe/Budapest', + 'Central European Standard Time'=>'Europe/Warsaw', + 'Central Pacific Standard Time'=>'Pacific/Guadalcanal', + 'Central Standard Time'=>'America/Chicago', + 'Central Standard Time (Mexico)'=>'America/Mexico_City', + 'China Standard Time'=>'Asia/Shanghai', + 'Dateline Standard Time'=>'Etc/GMT+12', + 'E. Africa Standard Time'=>'Africa/Nairobi', + 'E. Australia Standard Time'=>'Australia/Brisbane', + 'E. Europe Standard Time'=>'Europe/Minsk', + 'E. South America Standard Time'=>'America/Sao_Paulo', + 'Eastern Standard Time'=>'America/New_York', + 'Egypt Standard Time'=>'Africa/Cairo', + 'Ekaterinburg Standard Time'=>'Asia/Yekaterinburg', + 'FLE Standard Time'=>'Europe/Kiev', + 'Fiji Standard Time'=>'Pacific/Fiji', + 'GMT Standard Time'=>'Europe/London', + 'GTB Standard Time'=>'Europe/Istanbul', + 'Georgian Standard Time'=>'Asia/Tbilisi', + 'Greenland Standard Time'=>'America/Godthab', + 'Greenwich Standard Time'=>'Atlantic/Reykjavik', + 'Hawaiian Standard Time'=>'Pacific/Honolulu', + 'India Standard Time'=>'Asia/Calcutta', + 'Iran Standard Time'=>'Asia/Tehran', + 'Israel Standard Time'=>'Asia/Jerusalem', + 'Jordan Standard Time'=>'Asia/Amman', + 'Kamchatka Standard Time'=>'Asia/Kamchatka', + 'Korea Standard Time'=>'Asia/Seoul', + 'Magadan Standard Time'=>'Asia/Magadan', + 'Mauritius Standard Time'=>'Indian/Mauritius', + 'Mexico Standard Time'=>'America/Mexico_City', + 'Mexico Standard Time 2'=>'America/Chihuahua', + 'Mid-Atlantic Standard Time'=>'Etc/GMT-2', + 'Middle East Standard Time'=>'Asia/Beirut', + 'Montevideo Standard Time'=>'America/Montevideo', + 'Morocco Standard Time'=>'Africa/Casablanca', + 'Mountain Standard Time'=>'America/Denver', + 'Mountain Standard Time (Mexico)'=>'America/Chihuahua', + 'Myanmar Standard Time'=>'Asia/Rangoon', + 'N. Central Asia Standard Time'=>'Asia/Novosibirsk', + 'Namibia Standard Time'=>'Africa/Windhoek', + 'Nepal Standard Time'=>'Asia/Katmandu', + 'New Zealand Standard Time'=>'Pacific/Auckland', + 'Newfoundland Standard Time'=>'America/St_Johns', + 'North Asia East Standard Time'=>'Asia/Irkutsk', + 'North Asia Standard Time'=>'Asia/Krasnoyarsk', + 'Pacific SA Standard Time'=>'America/Santiago', + 'Pacific Standard Time'=>'America/Los_Angeles', + 'Pacific Standard Time (Mexico)'=>'America/Santa_Isabel', + 'Pakistan Standard Time'=>'Asia/Karachi', + 'Paraguay Standard Time'=>'America/Asuncion', + 'Romance Standard Time'=>'Europe/Paris', + 'Russian Standard Time'=>'Europe/Moscow', + 'SA Eastern Standard Time'=>'America/Cayenne', + 'SA Pacific Standard Time'=>'America/Bogota', + 'SA Western Standard Time'=>'America/La_Paz', + 'SE Asia Standard Time'=>'Asia/Bangkok', + 'Samoa Standard Time'=>'Pacific/Apia', + 'Singapore Standard Time'=>'Asia/Singapore', + 'South Africa Standard Time'=>'Africa/Johannesburg', + 'Sri Lanka Standard Time'=>'Asia/Colombo', + 'Syria Standard Time'=>'Asia/Damascus', + 'Taipei Standard Time'=>'Asia/Taipei', + 'Tasmania Standard Time'=>'Australia/Hobart', + 'Tokyo Standard Time'=>'Asia/Tokyo', + 'Tonga Standard Time'=>'Pacific/Tongatapu', + 'US Eastern Standard Time'=>'America/Indianapolis', + 'US Mountain Standard Time'=>'America/Phoenix', + 'UTC+12'=>'Etc/GMT-12', + 'UTC-02'=>'Etc/GMT+2', + 'UTC-11'=>'Etc/GMT+11', + 'Ulaanbaatar Standard Time'=>'Asia/Ulaanbaatar', + 'Venezuela Standard Time'=>'America/Caracas', + 'Vladivostok Standard Time'=>'Asia/Vladivostok', + 'W. Australia Standard Time'=>'Australia/Perth', + 'W. Central Africa Standard Time'=>'Africa/Lagos', + 'W. Europe Standard Time'=>'Europe/Berlin', + 'West Asia Standard Time'=>'Asia/Tashkent', + 'West Pacific Standard Time'=>'Pacific/Port_Moresby', + 'Yakutsk Standard Time'=>'Asia/Yakutsk', + + // Microsoft exchange timezones + // Source: + // http://msdn.microsoft.com/en-us/library/ms988620%28v=exchg.65%29.aspx + // + // Correct timezones deduced with help from: + // http://en.wikipedia.org/wiki/List_of_tz_database_time_zones + 'Universal Coordinated Time' => 'UTC', + 'Casablanca, Monrovia' => 'Africa/Casablanca', + 'Greenwich Mean Time: Dublin, Edinburgh, Lisbon, London' => 'Europe/Lisbon', + 'Greenwich Mean Time; Dublin, Edinburgh, London' => 'Europe/London', + 'Amsterdam, Berlin, Bern, Rome, Stockholm, Vienna' => 'Europe/Berlin', + 'Belgrade, Pozsony, Budapest, Ljubljana, Prague' => 'Europe/Prague', + 'Brussels, Copenhagen, Madrid, Paris' => 'Europe/Paris', + 'Paris, Madrid, Brussels, Copenhagen' => 'Europe/Paris', + 'Prague, Central Europe' => 'Europe/Prague', + 'Sarajevo, Skopje, Sofija, Vilnius, Warsaw, Zagreb' => 'Europe/Sarajevo', + 'West Central Africa' => 'Africa/Luanda', // This was a best guess + 'Athens, Istanbul, Minsk' => 'Europe/Athens', + 'Bucharest' => 'Europe/Bucharest', + 'Cairo' => 'Africa/Cairo', + 'Harare, Pretoria' => 'Africa/Harare', + 'Helsinki, Riga, Tallinn' => 'Europe/Helsinki', + 'Israel, Jerusalem Standard Time' => 'Asia/Jerusalem', + 'Baghdad' => 'Asia/Baghdad', + 'Arab, Kuwait, Riyadh' => 'Asia/Kuwait', + 'Moscow, St. Petersburg, Volgograd' => 'Europe/Moscow', + 'East Africa, Nairobi' => 'Africa/Nairobi', + 'Tehran' => 'Asia/Tehran', + 'Abu Dhabi, Muscat' => 'Asia/Muscat', // Best guess + 'Baku, Tbilisi, Yerevan' => 'Asia/Baku', + 'Kabul' => 'Asia/Kabul', + 'Ekaterinburg' => 'Asia/Yekaterinburg', + 'Islamabad, Karachi, Tashkent' => 'Asia/Karachi', + 'Kolkata, Chennai, Mumbai, New Delhi, India Standard Time' => 'Asia/Calcutta', + 'Kathmandu, Nepal' => 'Asia/Kathmandu', + 'Almaty, Novosibirsk, North Central Asia' => 'Asia/Almaty', + 'Astana, Dhaka' => 'Asia/Dhaka', + 'Sri Jayawardenepura, Sri Lanka' => 'Asia/Colombo', + 'Rangoon' => 'Asia/Rangoon', + 'Bangkok, Hanoi, Jakarta' => 'Asia/Bangkok', + 'Krasnoyarsk' => 'Asia/Krasnoyarsk', + 'Beijing, Chongqing, Hong Kong SAR, Urumqi' => 'Asia/Shanghai', + 'Irkutsk, Ulaan Bataar' => 'Asia/Irkutsk', + 'Kuala Lumpur, Singapore' => 'Asia/Singapore', + 'Perth, Western Australia' => 'Australia/Perth', + 'Taipei' => 'Asia/Taipei', + 'Osaka, Sapporo, Tokyo' => 'Asia/Tokyo', + 'Seoul, Korea Standard time' => 'Asia/Seoul', + 'Yakutsk' => 'Asia/Yakutsk', + 'Adelaide, Central Australia' => 'Australia/Adelaide', + 'Darwin' => 'Australia/Darwin', + 'Brisbane, East Australia' => 'Australia/Brisbane', + 'Canberra, Melbourne, Sydney, Hobart (year 2000 only)' => 'Australia/Sydney', + 'Guam, Port Moresby' => 'Pacific/Guam', + 'Hobart, Tasmania' => 'Australia/Hobart', + 'Vladivostok' => 'Asia/Vladivostok', + 'Magadan, Solomon Is., New Caledonia' => 'Asia/Magadan', + 'Auckland, Wellington' => 'Pacific/Auckland', + 'Fiji Islands, Kamchatka, Marshall Is.' => 'Pacific/Fiji', + 'Nuku\'alofa, Tonga' => 'Pacific/Tongatapu', + 'Azores' => 'Atlantic/Azores', + 'Cape Verde Is.' => 'Atlantic/Cape_Verde', + 'Mid-Atlantic' => 'America/Noronha', + 'Brasilia' => 'America/Sao_Paulo', // Best guess + 'Buenos Aires' => 'America/Argentina/Buenos_Aires', + 'Greenland' => 'America/Godthab', + 'Newfoundland' => 'America/St_Johns', + 'Atlantic Time (Canada)' => 'America/Halifax', + 'Caracas, La Paz' => 'America/Caracas', + 'Santiago' => 'America/Santiago', + 'Bogota, Lima, Quito' => 'America/Bogota', + 'Eastern Time (US & Canada)' => 'America/New_York', + 'Indiana (East)' => 'America/Indiana/Indianapolis', + 'Central America' => 'America/Guatemala', + 'Central Time (US & Canada)' => 'America/Chicago', + 'Mexico City, Tegucigalpa' => 'America/Mexico_City', + 'Saskatchewan' => 'America/Edmonton', + 'Arizona' => 'America/Phoenix', + 'Mountain Time (US & Canada)' => 'America/Denver', // Best guess + 'Pacific Time (US & Canada); Tijuana' => 'America/Los_Angeles', // Best guess + 'Alaska' => 'America/Anchorage', + 'Hawaii' => 'Pacific/Honolulu', + 'Midway Island, Samoa' => 'Pacific/Midway', + 'Eniwetok, Kwajalein, Dateline Time' => 'Pacific/Kwajalein', + + // The following list are timezone names that could be generated by + // Lotus / Domino + 'Dateline' => 'Etc/GMT-12', + 'Samoa' => 'Pacific/Apia', + 'Hawaiian' => 'Pacific/Honolulu', + 'Alaskan' => 'America/Anchorage', + 'Pacific' => 'America/Los_Angeles', + 'Pacific Standard Time' => 'America/Los_Angeles', + 'Mexico Standard Time 2' => 'America/Chihuahua', + 'Mountain' => 'America/Denver', + 'Mountain Standard Time' => 'America/Chihuahua', + 'US Mountain' => 'America/Phoenix', + 'Canada Central' => 'America/Edmonton', + 'Central America' => 'America/Guatemala', + 'Central' => 'America/Chicago', + 'Central Standard Time' => 'America/Mexico_City', + 'Mexico' => 'America/Mexico_City', + 'Eastern' => 'America/New_York', + 'SA Pacific' => 'America/Bogota', + 'US Eastern' => 'America/Indiana/Indianapolis', + 'Venezuela' => 'America/Caracas', + 'Atlantic' => 'America/Halifax', + 'Central Brazilian' => 'America/Manaus', + 'Pacific SA' => 'America/Santiago', + 'SA Western' => 'America/La_Paz', + 'Newfoundland' => 'America/St_Johns', + 'Argentina' => 'America/Argentina/Buenos_Aires', + 'E. South America' => 'America/Belem', + 'Greenland' => 'America/Godthab', + 'Montevideo' => 'America/Montevideo', + 'SA Eastern' => 'America/Belem', + 'Mid-Atlantic' => 'Etc/GMT-2', + 'Azores' => 'Atlantic/Azores', + 'Cape Verde' => 'Atlantic/Cape_Verde', + 'Greenwich' => 'Atlantic/Reykjavik', // No I'm serious.. Greenwich is not GMT. + 'Morocco' => 'Africa/Casablanca', + 'Central Europe' => 'Europe/Prague', + 'Central European' => 'Europe/Sarajevo', + 'Romance' => 'Europe/Paris', + 'W. Central Africa' => 'Africa/Lagos', // Best guess + 'W. Europe' => 'Europe/Amsterdam', + 'E. Europe' => 'Europe/Minsk', + 'Egypt' => 'Africa/Cairo', + 'FLE' => 'Europe/Helsinki', + 'GTB' => 'Europe/Athens', + 'Israel' => 'Asia/Jerusalem', + 'Jordan' => 'Asia/Amman', + 'Middle East' => 'Asia/Beirut', + 'Namibia' => 'Africa/Windhoek', + 'South Africa' => 'Africa/Harare', + 'Arab' => 'Asia/Kuwait', + 'Arabic' => 'Asia/Baghdad', + 'E. Africa' => 'Africa/Nairobi', + 'Georgian' => 'Asia/Tbilisi', + 'Russian' => 'Europe/Moscow', + 'Iran' => 'Asia/Tehran', + 'Arabian' => 'Asia/Muscat', + 'Armenian' => 'Asia/Yerevan', + 'Azerbijan' => 'Asia/Baku', + 'Caucasus' => 'Asia/Yerevan', + 'Mauritius' => 'Indian/Mauritius', + 'Afghanistan' => 'Asia/Kabul', + 'Ekaterinburg' => 'Asia/Yekaterinburg', + 'Pakistan' => 'Asia/Karachi', + 'West Asia' => 'Asia/Tashkent', + 'India' => 'Asia/Calcutta', + 'Sri Lanka' => 'Asia/Colombo', + 'Nepal' => 'Asia/Kathmandu', + 'Central Asia' => 'Asia/Dhaka', + 'N. Central Asia' => 'Asia/Almaty', + 'Myanmar' => 'Asia/Rangoon', + 'North Asia' => 'Asia/Krasnoyarsk', + 'SE Asia' => 'Asia/Bangkok', + 'China' => 'Asia/Shanghai', + 'North Asia East' => 'Asia/Irkutsk', + 'Singapore' => 'Asia/Singapore', + 'Taipei' => 'Asia/Taipei', + 'W. Australia' => 'Australia/Perth', + 'Korea' => 'Asia/Seoul', + 'Tokyo' => 'Asia/Tokyo', + 'Yakutsk' => 'Asia/Yakutsk', + 'AUS Central' => 'Australia/Darwin', + 'Cen. Australia' => 'Australia/Adelaide', + 'AUS Eastern' => 'Australia/Sydney', + 'E. Australia' => 'Australia/Brisbane', + 'Tasmania' => 'Australia/Hobart', + 'Vladivostok' => 'Asia/Vladivostok', + 'West Pacific' => 'Pacific/Guam', + 'Central Pacific' => 'Asia/Magadan', + 'Fiji' => 'Pacific/Fiji', + 'New Zealand' => 'Pacific/Auckland', + 'Tonga' => 'Pacific/Tongatapu', + + // PHP 5.5.10 failed on a few timezones that were valid before. We're + // normalizing them here. + 'CST6CDT' => 'America/Chicago', + 'Cuba' => 'America/Havana', + 'Egypt' => 'Africa/Cairo', + 'Eire' => 'Europe/Dublin', + 'EST5EDT' => 'America/New_York', + 'Factory' => 'UTC', + 'GB-Eire' => 'Europe/London', + 'GMT0' => 'UTC', + 'Greenwich' => 'UTC', + 'Hongkong' => 'Asia/Hong_Kong', + 'Iceland' => 'Atlantic/Reykjavik', + 'Iran' => 'Asia/Tehran', + 'Israel' => 'Asia/Jerusalem', + 'Jamaica' => 'America/Jamaica', + 'Japan' => 'Asia/Tokyo', + 'Kwajalein' => 'Pacific/Kwajalein', + 'Libya' => 'Africa/Tripoli', + 'MST7MDT' => 'America/Denver', + 'Navajo' => 'America/Denver', + 'NZ-CHAT' => 'Pacific/Chatham', + 'Poland' => 'Europe/Warsaw', + 'Portugal' => 'Europe/Lisbon', + 'PST8PDT' => 'America/Los_Angeles', + 'Singapore' => 'Asia/Singapore', + 'Turkey' => 'Europe/Istanbul', + 'Universal' => 'UTC', + 'W-SU' => 'Europe/Moscow', + ); + + /** + * List of microsoft exchange timezone ids. + * + * Source: http://msdn.microsoft.com/en-us/library/aa563018(loband).aspx + */ + public static $microsoftExchangeMap = array( + 0 => 'UTC', + 31 => 'Africa/Casablanca', + + // Insanely, id #2 is used for both Europe/Lisbon, and Europe/Sarajevo. + // I'm not even kidding.. We handle this special case in the + // getTimeZone method. + 2 => 'Europe/Lisbon', + 1 => 'Europe/London', + 4 => 'Europe/Berlin', + 6 => 'Europe/Prague', + 3 => 'Europe/Paris', + 69 => 'Africa/Luanda', // This was a best guess + 7 => 'Europe/Athens', + 5 => 'Europe/Bucharest', + 49 => 'Africa/Cairo', + 50 => 'Africa/Harare', + 59 => 'Europe/Helsinki', + 27 => 'Asia/Jerusalem', + 26 => 'Asia/Baghdad', + 74 => 'Asia/Kuwait', + 51 => 'Europe/Moscow', + 56 => 'Africa/Nairobi', + 25 => 'Asia/Tehran', + 24 => 'Asia/Muscat', // Best guess + 54 => 'Asia/Baku', + 48 => 'Asia/Kabul', + 58 => 'Asia/Yekaterinburg', + 47 => 'Asia/Karachi', + 23 => 'Asia/Calcutta', + 62 => 'Asia/Kathmandu', + 46 => 'Asia/Almaty', + 71 => 'Asia/Dhaka', + 66 => 'Asia/Colombo', + 61 => 'Asia/Rangoon', + 22 => 'Asia/Bangkok', + 64 => 'Asia/Krasnoyarsk', + 45 => 'Asia/Shanghai', + 63 => 'Asia/Irkutsk', + 21 => 'Asia/Singapore', + 73 => 'Australia/Perth', + 75 => 'Asia/Taipei', + 20 => 'Asia/Tokyo', + 72 => 'Asia/Seoul', + 70 => 'Asia/Yakutsk', + 19 => 'Australia/Adelaide', + 44 => 'Australia/Darwin', + 18 => 'Australia/Brisbane', + 76 => 'Australia/Sydney', + 43 => 'Pacific/Guam', + 42 => 'Australia/Hobart', + 68 => 'Asia/Vladivostok', + 41 => 'Asia/Magadan', + 17 => 'Pacific/Auckland', + 40 => 'Pacific/Fiji', + 67 => 'Pacific/Tongatapu', + 29 => 'Atlantic/Azores', + 53 => 'Atlantic/Cape_Verde', + 30 => 'America/Noronha', + 8 => 'America/Sao_Paulo', // Best guess + 32 => 'America/Argentina/Buenos_Aires', + 60 => 'America/Godthab', + 28 => 'America/St_Johns', + 9 => 'America/Halifax', + 33 => 'America/Caracas', + 65 => 'America/Santiago', + 35 => 'America/Bogota', + 10 => 'America/New_York', + 34 => 'America/Indiana/Indianapolis', + 55 => 'America/Guatemala', + 11 => 'America/Chicago', + 37 => 'America/Mexico_City', + 36 => 'America/Edmonton', + 38 => 'America/Phoenix', + 12 => 'America/Denver', // Best guess + 13 => 'America/Los_Angeles', // Best guess + 14 => 'America/Anchorage', + 15 => 'Pacific/Honolulu', + 16 => 'Pacific/Midway', + 39 => 'Pacific/Kwajalein', + ); + + /** + * This method will try to find out the correct timezone for an iCalendar + * date-time value. + * + * You must pass the contents of the TZID parameter, as well as the full + * calendar. + * + * If the lookup fails, this method will return the default PHP timezone + * (as configured using date_default_timezone_set, or the date.timezone ini + * setting). + * + * Alternatively, if $failIfUncertain is set to true, it will throw an + * exception if we cannot accurately determine the timezone. + * + * @param string $tzid + * @param Sabre\VObject\Component $vcalendar + * @return DateTimeZone + */ + static public function getTimeZone($tzid, Component $vcalendar = null, $failIfUncertain = false) { + + // First we will just see if the tzid is a support timezone identifier. + // + // The only exception is if the timezone starts with (. This is to + // handle cases where certain microsoft products generate timezone + // identifiers that for instance look like: + // + // (GMT+01.00) Sarajevo/Warsaw/Zagreb + // + // Since PHP 5.5.10, the first bit will be used as the timezone and + // this method will return just GMT+01:00. This is wrong, because it + // doesn't take DST into account. + if ($tzid[0]!=='(') { + try { + return new \DateTimeZone($tzid); + } catch (\Exception $e) { + } + } + + // Next, we check if the tzid is somewhere in our tzid map. + if (isset(self::$map[$tzid])) { + return new \DateTimeZone(self::$map[$tzid]); + } + + // Maybe the author was hyper-lazy and just included an offset. We + // support it, but we aren't happy about it. + // + // Note that the path in the source will never be taken from PHP 5.5.10 + // onwards. PHP 5.5.10 supports the "GMT+0100" style of format, so it + // already gets returned early in this function. Once we drop support + // for versions under PHP 5.5.10, this bit can be taken out of the + // source. + if (preg_match('/^GMT(\+|-)([0-9]{4})$/', $tzid, $matches)) { + return new \DateTimeZone('Etc/GMT' . $matches[1] . ltrim(substr($matches[2],0,2),'0')); + } + + if ($vcalendar) { + + // If that didn't work, we will scan VTIMEZONE objects + foreach($vcalendar->select('VTIMEZONE') as $vtimezone) { + + if ((string)$vtimezone->TZID === $tzid) { + + // Some clients add 'X-LIC-LOCATION' with the olson name. + if (isset($vtimezone->{'X-LIC-LOCATION'})) { + + $lic = (string)$vtimezone->{'X-LIC-LOCATION'}; + + // Libical generators may specify strings like + // "SystemV/EST5EDT". For those we must remove the + // SystemV part. + if (substr($lic,0,8)==='SystemV/') { + $lic = substr($lic,8); + } + + return self::getTimeZone($lic, null, $failIfUncertain); + + } + // Microsoft may add a magic number, which we also have an + // answer for. + if (isset($vtimezone->{'X-MICROSOFT-CDO-TZID'})) { + $cdoId = (int)$vtimezone->{'X-MICROSOFT-CDO-TZID'}->value; + + // 2 can mean both Europe/Lisbon and Europe/Sarajevo. + if ($cdoId===2 && strpos((string)$vtimezone->TZID, 'Sarajevo')!==false) { + return new \DateTimeZone('Europe/Sarajevo'); + } + + if (isset(self::$microsoftExchangeMap[$cdoId])) { + return new \DateTimeZone(self::$microsoftExchangeMap[$cdoId]); + } + } + + } + + } + + } + + if ($failIfUncertain) { + throw new \InvalidArgumentException('We were unable to determine the correct PHP timezone for tzid: ' . $tzid); + } + + // If we got all the way here, we default to UTC. + return new \DateTimeZone(date_default_timezone_get()); + + } + +} diff --git a/sources/vendor/sabre/vobject/lib/Sabre/VObject/Version.php b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Version.php new file mode 100644 index 00000000..5b04d0b7 --- /dev/null +++ b/sources/vendor/sabre/vobject/lib/Sabre/VObject/Version.php @@ -0,0 +1,24 @@ +assertEquals($outcome, $valarm->isInTimeRange($start, $end)); + + } + + public function timeRangeTestData() { + + $tests = array(); + + // Hard date and time + $valarm1 = Component::create('VALARM'); + $valarm1->TRIGGER = '20120312T130000Z'; + $valarm1->TRIGGER['VALUE'] = 'DATE-TIME'; + + $tests[] = array($valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true); + $tests[] = array($valarm1, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false); + + // Relation to start time of event + $valarm2 = Component::create('VALARM'); + $valarm2->TRIGGER = '-P1D'; + $valarm2->TRIGGER['VALUE'] = 'DURATION'; + + $vevent2 = Component::create('VEVENT'); + $vevent2->DTSTART = '20120313T130000Z'; + $vevent2->add($valarm2); + + $tests[] = array($valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true); + $tests[] = array($valarm2, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false); + + // Relation to end time of event + $valarm3 = Component::create('VALARM'); + $valarm3->TRIGGER = '-P1D'; + $valarm3->TRIGGER['VALUE'] = 'DURATION'; + $valarm3->TRIGGER['RELATED']= 'END'; + + $vevent3 = Component::create('VEVENT'); + $vevent3->DTSTART = '20120301T130000Z'; + $vevent3->DTEND = '20120401T130000Z'; + $vevent3->add($valarm3); + + $tests[] = array($valarm3, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false); + $tests[] = array($valarm3, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true); + + // Relation to end time of todo + $valarm4 = Component::create('VALARM'); + $valarm4->TRIGGER = '-P1D'; + $valarm4->TRIGGER['VALUE'] = 'DURATION'; + $valarm4->TRIGGER['RELATED']= 'END'; + + $vtodo4 = Component::create('VTODO'); + $vtodo4->DTSTART = '20120301T130000Z'; + $vtodo4->DUE = '20120401T130000Z'; + $vtodo4->add($valarm4); + + $tests[] = array($valarm4, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false); + $tests[] = array($valarm4, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true); + + // Relation to start time of event + repeat + $valarm5 = Component::create('VALARM'); + $valarm5->TRIGGER = '-P1D'; + $valarm5->TRIGGER['VALUE'] = 'DURATION'; + $valarm5->REPEAT = 10; + $valarm5->DURATION = 'P1D'; + + $vevent5 = Component::create('VEVENT'); + $vevent5->DTSTART = '20120301T130000Z'; + $vevent5->add($valarm5); + + $tests[] = array($valarm5, new DateTime('2012-03-09 01:00:00'), new DateTime('2012-03-10 01:00:00'), true); + + // Relation to start time of event + duration, but no repeat + $valarm6 = Component::create('VALARM'); + $valarm6->TRIGGER = '-P1D'; + $valarm6->TRIGGER['VALUE'] = 'DURATION'; + $valarm6->DURATION = 'P1D'; + + $vevent6 = Component::create('VEVENT'); + $vevent6->DTSTART = '20120313T130000Z'; + $vevent6->add($valarm6); + + $tests[] = array($valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-04-01 01:00:00'), true); + $tests[] = array($valarm6, new DateTime('2012-03-01 01:00:00'), new DateTime('2012-03-10 01:00:00'), false); + + + // Relation to end time of event (DURATION instead of DTEND) + $valarm7 = Component::create('VALARM'); + $valarm7->TRIGGER = '-P1D'; + $valarm7->TRIGGER['VALUE'] = 'DURATION'; + $valarm7->TRIGGER['RELATED']= 'END'; + + $vevent7 = Component::create('VEVENT'); + $vevent7->DTSTART = '20120301T130000Z'; + $vevent7->DURATION = 'P30D'; + $vevent7->add($valarm7); + + $tests[] = array($valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), false); + $tests[] = array($valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), true); + + // Relation to end time of event (No DTEND or DURATION) + $valarm7 = Component::create('VALARM'); + $valarm7->TRIGGER = '-P1D'; + $valarm7->TRIGGER['VALUE'] = 'DURATION'; + $valarm7->TRIGGER['RELATED']= 'END'; + + $vevent7 = Component::create('VEVENT'); + $vevent7->DTSTART = '20120301T130000Z'; + $vevent7->add($valarm7); + + $tests[] = array($valarm7, new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00'), true); + $tests[] = array($valarm7, new DateTime('2012-03-25 01:00:00'), new DateTime('2012-04-05 01:00:00'), false); + + + return $tests; + } + + /** + * @expectedException LogicException + */ + public function testInTimeRangeInvalidComponent() { + + $valarm = Component::create('VALARM'); + $valarm->TRIGGER = '-P1D'; + $valarm->TRIGGER['RELATED'] = 'END'; + + $vjournal = Component::create('VJOURNAL'); + $vjournal->add($valarm); + + $valarm->isInTimeRange(new DateTime('2012-02-25 01:00:00'), new DateTime('2012-03-05 01:00:00')); + + } + + /** + * This bug was found and reported on the mailing list. + */ + public function testInTimeRangeBuggy() { + +$input = <<assertTrue($vobj->VTODO->VALARM->isInTimeRange(new \DateTime('2012-10-01 00:00:00'), new \DateTime('2012-11-01 00:00:00'))); + + } +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php new file mode 100644 index 00000000..1d7e0c60 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCalendarTest.php @@ -0,0 +1,244 @@ +expand( + new \DateTime('2011-12-01'), + new \DateTime('2011-12-31') + ); + + // This will normalize the output + $output = VObject\Reader::read($output)->serialize(); + + $this->assertEquals($output, $vcal->serialize()); + + } + + public function expandData() { + + $tests = array(); + + // No data + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +END:VCALENDAR +'; + + $output = $input; + $tests[] = array($input,$output); + + + // Simple events + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla +SUMMARY:InExpand +DTSTART;VALUE=DATE:20111202 +END:VEVENT +BEGIN:VEVENT +UID:bla2 +SUMMARY:NotInExpand +DTSTART;VALUE=DATE:20120101 +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla +SUMMARY:InExpand +DTSTART;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + + $tests[] = array($input, $output); + + // Removing timezone info + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VTIMEZONE +TZID:Europe/Paris +END:VTIMEZONE +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART;TZID=Europe/Paris:20111203T130102 +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla4 +SUMMARY:RemoveTZ info +DTSTART;VALUE=DATE-TIME:20111203T120102Z +END:VEVENT +END:VCALENDAR +'; + + $tests[] = array($input, $output); + + // Recurrence rule + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART:20111125T120000Z +DTEND:20111125T130000Z +RRULE:FREQ=WEEKLY +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART;VALUE=DATE-TIME:20111202T120000Z +DTEND;VALUE=DATE-TIME:20111202T130000Z +RECURRENCE-ID:20111202T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART;VALUE=DATE-TIME:20111209T120000Z +DTEND;VALUE=DATE-TIME:20111209T130000Z +RECURRENCE-ID:20111209T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART;VALUE=DATE-TIME:20111216T120000Z +DTEND;VALUE=DATE-TIME:20111216T130000Z +RECURRENCE-ID:20111216T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART;VALUE=DATE-TIME:20111223T120000Z +DTEND;VALUE=DATE-TIME:20111223T130000Z +RECURRENCE-ID:20111223T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule +DTSTART;VALUE=DATE-TIME:20111230T120000Z +DTEND;VALUE=DATE-TIME:20111230T130000Z +RECURRENCE-ID:20111230T120000Z +END:VEVENT +END:VCALENDAR +'; + + // Recurrence rule + override + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART:20111125T120000Z +DTEND:20111125T130000Z +RRULE:FREQ=WEEKLY +END:VEVENT +BEGIN:VEVENT +UID:bla6 +RECURRENCE-ID:20111209T120000Z +DTSTART:20111209T140000Z +DTEND:20111209T150000Z +SUMMARY:Override! +END:VEVENT +END:VCALENDAR +'; + + $output = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART;VALUE=DATE-TIME:20111202T120000Z +DTEND;VALUE=DATE-TIME:20111202T130000Z +RECURRENCE-ID:20111202T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +RECURRENCE-ID:20111209T120000Z +DTSTART:20111209T140000Z +DTEND:20111209T150000Z +SUMMARY:Override! +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART;VALUE=DATE-TIME:20111216T120000Z +DTEND;VALUE=DATE-TIME:20111216T130000Z +RECURRENCE-ID:20111216T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART;VALUE=DATE-TIME:20111223T120000Z +DTEND;VALUE=DATE-TIME:20111223T130000Z +RECURRENCE-ID:20111223T120000Z +END:VEVENT +BEGIN:VEVENT +UID:bla6 +SUMMARY:Testing RRule2 +DTSTART;VALUE=DATE-TIME:20111230T120000Z +DTEND;VALUE=DATE-TIME:20111230T130000Z +RECURRENCE-ID:20111230T120000Z +END:VEVENT +END:VCALENDAR +'; + + $tests[] = array($input, $output); + return $tests; + + } + + /** + * @expectedException LogicException + */ + public function testBrokenEventExpand() { + + $input = 'BEGIN:VCALENDAR +CALSCALE:GREGORIAN +VERSION:2.0 +BEGIN:VEVENT +RRULE:FREQ=WEEKLY +DTSTART;VALUE=DATE:20111202 +END:VEVENT +END:VCALENDAR +'; + $vcal = VObject\Reader::read($input); + $vcal->expand( + new \DateTime('2011-12-01'), + new \DateTime('2011-12-31') + ); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php new file mode 100644 index 00000000..584a007d --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VCardTest.php @@ -0,0 +1,100 @@ +validate(); + + $warnMsg = array(); + foreach($warnings as $warning) { + $warnMsg[] = $warning['message']; + } + + $this->assertEquals($expectedWarnings, $warnMsg); + + $vcard->validate(VObject\Component::REPAIR); + + $this->assertEquals( + $expectedRepairedOutput, + $vcard->serialize() + ); + + } + + public function validateData() { + + $tests = array(); + + // Correct + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n", + array(), + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n", + ); + + // No VERSION + $tests[] = array( + "BEGIN:VCARD\r\nFN:John Doe\r\nEND:VCARD\r\n", + array( + 'The VERSION property must appear in the VCARD component exactly 1 time', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n", + ); + + // Unknown version + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:2.2\r\nFN:John Doe\r\nEND:VCARD\r\n", + array( + 'Only vcard version 4.0 (RFC6350), version 3.0 (RFC2426) or version 2.1 (icm-vcard-2.1) are supported.', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nFN:John Doe\r\nEND:VCARD\r\n", + ); + + // No FN + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:4.0\r\nEND:VCARD\r\n", + array( + 'The FN property must appear in the VCARD component exactly 1 time', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nEND:VCARD\r\n", + ); + // No FN, N fallback + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;John;;;;;\r\nEND:VCARD\r\n", + array( + 'The FN property must appear in the VCARD component exactly 1 time', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;John;;;;;\r\nFN:John Doe\r\nEND:VCARD\r\n", + ); + // No FN, N fallback, no first name + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;;;;;;\r\nEND:VCARD\r\n", + array( + 'The FN property must appear in the VCARD component exactly 1 time', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nN:Doe;;;;;;\r\nFN:Doe\r\nEND:VCARD\r\n", + ); + + // No FN, ORG fallback + $tests[] = array( + "BEGIN:VCARD\r\nVERSION:4.0\r\nORG:Acme Co.\r\nEND:VCARD\r\n", + array( + 'The FN property must appear in the VCARD component exactly 1 time', + ), + "BEGIN:VCARD\r\nVERSION:4.0\r\nORG:Acme Co.\r\nFN:Acme Co.\r\nEND:VCARD\r\n", + ); + return $tests; + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php new file mode 100644 index 00000000..616da4ac --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VEventTest.php @@ -0,0 +1,74 @@ +assertEquals($outcome, $vevent->isInTimeRange($start, $end)); + + } + + public function timeRangeTestData() { + + $tests = array(); + + $vevent = new VEvent('VEVENT'); + $vevent->DTSTART = '20111223T120000Z'; + $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vevent2 = clone $vevent; + $vevent2->DTEND = '20111225T120000Z'; + $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vevent3 = clone $vevent; + $vevent3->DURATION = 'P1D'; + $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vevent4 = clone $vevent; + $vevent4->DTSTART = '20111225'; + $vevent4->DTSTART['VALUE'] = 'DATE'; + $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + // Event with no end date should be treated as lasting the entire day. + $tests[] = array($vevent4, new \DateTime('2011-12-25 16:00:00'), new \DateTime('2011-12-25 17:00:00'), true); + + + $vevent5 = clone $vevent; + $vevent5->DURATION = 'P1D'; + $vevent5->RRULE = 'FREQ=YEARLY'; + $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + $tests[] = array($vevent5, new \DateTime('2013-12-01'), new \DateTime('2013-12-31'), true); + + $vevent6 = clone $vevent; + $vevent6->DTSTART = '20111225'; + $vevent6->DTSTART['VALUE'] = 'DATE'; + $vevent6->DTEND = '20111225'; + $vevent6->DTEND['VALUE'] = 'DATE'; + + $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vevent6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + // Added this test to ensure that recurrence rules with no DTEND also + // get checked for the entire day. + $vevent7 = clone $vevent; + $vevent7->DTSTART = '20120101'; + $vevent7->DTSTART['VALUE'] = 'DATE'; + $vevent7->RRULE = 'FREQ=MONTHLY'; + $tests[] = array($vevent7, new \DateTime('2012-02-01 15:00:00'), new \DateTime('2012-02-02'), true); + return $tests; + + } + +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php new file mode 100644 index 00000000..031c3c68 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VFreeBusyTest.php @@ -0,0 +1,39 @@ +VFREEBUSY; + + $tz = new \DateTimeZone('UTC'); + + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 01:15:00', $tz), new \DateTime('2012-09-12 01:45:00', $tz))); + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 08:05:00', $tz), new \DateTime('2012-09-12 08:10:00', $tz))); + $this->assertFalse($vfb->isFree(new \DateTime('2012-09-12 10:15:00', $tz), new \DateTime('2012-09-12 10:45:00', $tz))); + + // Checking whether the end time is treated as non-inclusive + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:00:00', $tz), new \DateTime('2012-09-12 09:15:00', $tz))); + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 09:45:00', $tz), new \DateTime('2012-09-12 10:00:00', $tz))); + $this->assertTrue($vfb->isFree(new \DateTime('2012-09-12 11:00:00', $tz), new \DateTime('2012-09-12 12:00:00', $tz))); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php new file mode 100644 index 00000000..46ecb992 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VJournalTest.php @@ -0,0 +1,41 @@ +assertEquals($outcome, $vtodo->isInTimeRange($start, $end)); + + } + + public function timeRangeTestData() { + + $tests = array(); + + $vjournal = Component::create('VJOURNAL'); + $vjournal->DTSTART = '20111223T120000Z'; + $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vjournal, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vjournal2 = Component::create('VJOURNAL'); + $vjournal2->DTSTART = '20111223'; + $vjournal2->DTSTART['VALUE'] = 'DATE'; + $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vjournal2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vjournal3 = Component::create('VJOURNAL'); + $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), false); + $tests[] = array($vjournal3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + return $tests; + } + +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php new file mode 100644 index 00000000..a84da5cd --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Component/VTodoTest.php @@ -0,0 +1,67 @@ +assertEquals($outcome, $vtodo->isInTimeRange($start, $end)); + + } + + public function timeRangeTestData() { + + $tests = array(); + + $vtodo = Component::create('VTODO'); + $vtodo->DTSTART = '20111223T120000Z'; + $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo2 = clone $vtodo; + $vtodo2->DURATION = 'P1D'; + $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo2, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo3 = clone $vtodo; + $vtodo3->DUE = '20111225'; + $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo3, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo4 = Component::create('VTODO'); + $vtodo4->DUE = '20111225'; + $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo4, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo5 = Component::create('VTODO'); + $vtodo5->COMPLETED = '20111225'; + $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo5, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo6 = Component::create('VTODO'); + $vtodo6->CREATED = '20111225'; + $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo6, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo7 = Component::create('VTODO'); + $vtodo7->CREATED = '20111225'; + $vtodo7->COMPLETED = '20111226'; + $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), false); + + $vtodo7 = Component::create('VTODO'); + $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2012-01-01'), true); + $tests[] = array($vtodo7, new \DateTime('2011-01-01'), new \DateTime('2011-11-01'), true); + + return $tests; + + } + +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php new file mode 100644 index 00000000..07000bda --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ComponentTest.php @@ -0,0 +1,413 @@ +children[] = $sub; + + $sub = new Component('VTODO'); + $comp->children[] = $sub; + + $count = 0; + foreach($comp->children() as $key=>$subcomponent) { + + $count++; + $this->assertInstanceOf('Sabre\\VObject\\Component',$subcomponent); + + } + $this->assertEquals(2,$count); + $this->assertEquals(1,$key); + + } + + function testMagicGet() { + + $comp = new Component('VCALENDAR'); + + $sub = new Component('VEVENT'); + $comp->children[] = $sub; + + $sub = new Component('VTODO'); + $comp->children[] = $sub; + + $event = $comp->vevent; + $this->assertInstanceOf('Sabre\\VObject\\Component', $event); + $this->assertEquals('VEVENT', $event->name); + + $this->assertInternalType('null', $comp->vjournal); + + } + + function testMagicGetGroups() { + + $comp = new Component('VCARD'); + + $sub = new Property('GROUP1.EMAIL','1@1.com'); + $comp->children[] = $sub; + + $sub = new Property('GROUP2.EMAIL','2@2.com'); + $comp->children[] = $sub; + + $sub = new Property('EMAIL','3@3.com'); + $comp->children[] = $sub; + + $emails = $comp->email; + $this->assertEquals(3, count($emails)); + + $email1 = $comp->{"group1.email"}; + $this->assertEquals('EMAIL', $email1[0]->name); + $this->assertEquals('GROUP1', $email1[0]->group); + + $email3 = $comp->{".email"}; + $this->assertEquals('EMAIL', $email3[0]->name); + $this->assertEquals(null, $email3[0]->group); + + } + + function testMagicIsset() { + + $comp = new Component('VCALENDAR'); + + $sub = new Component('VEVENT'); + $comp->children[] = $sub; + + $sub = new Component('VTODO'); + $comp->children[] = $sub; + + $this->assertTrue(isset($comp->vevent)); + $this->assertTrue(isset($comp->vtodo)); + $this->assertFalse(isset($comp->vjournal)); + + } + + function testMagicSetScalar() { + + $comp = new Component('VCALENDAR'); + $comp->myProp = 'myValue'; + + $this->assertInstanceOf('Sabre\\VObject\\Property',$comp->MYPROP); + $this->assertEquals('myValue',$comp->MYPROP->value); + + + } + + function testMagicSetScalarTwice() { + + $comp = new Component('VCALENDAR'); + $comp->myProp = 'myValue'; + $comp->myProp = 'myValue'; + + $this->assertEquals(1,count($comp->children)); + $this->assertInstanceOf('Sabre\\VObject\\Property',$comp->MYPROP); + $this->assertEquals('myValue',$comp->MYPROP->value); + + } + + function testMagicSetComponent() { + + $comp = new Component('VCALENDAR'); + + // Note that 'myProp' is ignored here. + $comp->myProp = new Component('VEVENT'); + + $this->assertEquals(1, count($comp->children)); + + $this->assertEquals('VEVENT',$comp->VEVENT->name); + + } + + function testMagicSetTwice() { + + $comp = new Component('VCALENDAR'); + + $comp->VEVENT = new Component('VEVENT'); + $comp->VEVENT = new Component('VEVENT'); + + $this->assertEquals(1, count($comp->children)); + + $this->assertEquals('VEVENT',$comp->VEVENT->name); + + } + + function testArrayAccessGet() { + + $comp = new Component('VCALENDAR'); + + $event = new Component('VEVENT'); + $event->summary = 'Event 1'; + + $comp->add($event); + + $event2 = clone $event; + $event2->summary = 'Event 2'; + + $comp->add($event2); + + $this->assertEquals(2,count($comp->children())); + $this->assertTrue($comp->vevent[1] instanceof Component); + $this->assertEquals('Event 2', (string)$comp->vevent[1]->summary); + + } + + function testArrayAccessExists() { + + $comp = new Component('VCALENDAR'); + + $event = new Component('VEVENT'); + $event->summary = 'Event 1'; + + $comp->add($event); + + $event2 = clone $event; + $event2->summary = 'Event 2'; + + $comp->add($event2); + + $this->assertTrue(isset($comp->vevent[0])); + $this->assertTrue(isset($comp->vevent[1])); + + } + + /** + * @expectedException LogicException + */ + function testArrayAccessSet() { + + $comp = new Component('VCALENDAR'); + $comp['hey'] = 'hi there'; + + } + /** + * @expectedException LogicException + */ + function testArrayAccessUnset() { + + $comp = new Component('VCALENDAR'); + unset($comp[0]); + + } + + function testAddScalar() { + + $comp = new Component('VCALENDAR'); + + $comp->add('myprop','value'); + + $this->assertEquals(1, count($comp->children)); + + $this->assertTrue($comp->children[0] instanceof Property); + $this->assertEquals('MYPROP',$comp->children[0]->name); + $this->assertEquals('value',$comp->children[0]->value); + + } + + function testAddScalarParams() { + + $comp = Component::create('VCALENDAR'); + + $comp->add('myprop','value',array('param1'=>'value1')); + + $this->assertEquals(1, count($comp->children)); + + $this->assertTrue($comp->children[0] instanceof Property); + $this->assertEquals('MYPROP',$comp->children[0]->name); + $this->assertEquals('value',$comp->children[0]->value); + + $this->assertEquals(1, count($comp->children[0]->parameters)); + + $this->assertTrue($comp->children[0]->parameters[0] instanceof Parameter); + $this->assertEquals('PARAM1',$comp->children[0]->parameters[0]->name); + $this->assertEquals('value1',$comp->children[0]->parameters[0]->value); + + } + + + function testAddComponent() { + + $comp = new Component('VCALENDAR'); + + $comp->add(new Component('VEVENT')); + + $this->assertEquals(1, count($comp->children)); + + $this->assertEquals('VEVENT',$comp->VEVENT->name); + + } + + function testAddComponentTwice() { + + $comp = new Component('VCALENDAR'); + + $comp->add(new Component('VEVENT')); + $comp->add(new Component('VEVENT')); + + $this->assertEquals(2, count($comp->children)); + + $this->assertEquals('VEVENT',$comp->VEVENT->name); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail() { + + $comp = new Component('VCALENDAR'); + $comp->add(new Component('VEVENT'),'hello'); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail2() { + + $comp = new Component('VCALENDAR'); + $comp->add(array()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail3() { + + $comp = new Component('VCALENDAR'); + $comp->add('hello',array()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testMagicSetInvalid() { + + $comp = new Component('VCALENDAR'); + + // Note that 'myProp' is ignored here. + $comp->myProp = new \StdClass(); + + $this->assertEquals(1, count($comp->children)); + + $this->assertEquals('VEVENT',$comp->VEVENT->name); + + } + + function testMagicUnset() { + + $comp = new Component('VCALENDAR'); + $comp->add(new Component('VEVENT')); + + unset($comp->vevent); + + $this->assertEquals(array(), $comp->children); + + } + + + function testCount() { + + $comp = new Component('VCALENDAR'); + $this->assertEquals(1,$comp->count()); + + } + + function testChildren() { + + $comp = new Component('VCALENDAR'); + + // Note that 'myProp' is ignored here. + $comp->children = array( + new Component('VEVENT'), + new Component('VTODO') + ); + + $r = $comp->children(); + $this->assertTrue($r instanceof ElementList); + $this->assertEquals(2,count($r)); + } + + function testGetComponents() { + + $comp = new Component('VCALENDAR'); + + // Note that 'myProp' is ignored here. + $comp->children = array( + new Property('FOO','BAR'), + new Component('VTODO') + ); + + $r = $comp->getComponents(); + $this->assertInternalType('array', $r); + $this->assertEquals(1, count($r)); + $this->assertEquals('VTODO', $r[0]->name); + } + + function testSerialize() { + + $comp = new Component('VCALENDAR'); + $this->assertEquals("BEGIN:VCALENDAR\r\nEND:VCALENDAR\r\n", $comp->serialize()); + + } + + function testSerializeChildren() { + + $comp = new Component('VCALENDAR'); + $comp->children = array( + new Component('VEVENT'), + new Component('VTODO') + ); + + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nBEGIN:VTODO\r\nEND:VTODO\r\nEND:VCALENDAR\r\n", $str); + + } + + function testSerializeOrderCompAndProp() { + + $comp = new Component('VCALENDAR'); + $comp->add(new Component('VEVENT')); + $comp->add('PROP1','BLABLA'); + $comp->add('VERSION','2.0'); + $comp->add(new Component('VTIMEZONE')); + + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPROP1:BLABLA\r\nBEGIN:VTIMEZONE\r\nEND:VTIMEZONE\r\nBEGIN:VEVENT\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $str); + + } + + function testAnotherSerializeOrderProp() { + + $prop4s=array('1', '2', '3', '4', '5', '6', '7', '8', '9', '10'); + + $comp = new Component('VCARD'); + $comp->__set('SOMEPROP','FOO'); + $comp->__set('ANOTHERPROP','FOO'); + $comp->__set('THIRDPROP','FOO'); + foreach ($prop4s as $prop4) { + $comp->add('PROP4', 'FOO '.$prop4); + } + $comp->__set('PROPNUMBERFIVE', 'FOO'); + $comp->__set('PROPNUMBERSIX', 'FOO'); + $comp->__set('PROPNUMBERSEVEN', 'FOO'); + $comp->__set('PROPNUMBEREIGHT', 'FOO'); + $comp->__set('PROPNUMBERNINE', 'FOO'); + $comp->__set('PROPNUMBERTEN', 'FOO'); + $comp->__set('VERSION','2.0'); + $comp->__set('UID', 'FOO'); + + $str = $comp->serialize(); + + $this->assertEquals("BEGIN:VCARD\r\nVERSION:2.0\r\nSOMEPROP:FOO\r\nANOTHERPROP:FOO\r\nTHIRDPROP:FOO\r\nPROP4:FOO 1\r\nPROP4:FOO 2\r\nPROP4:FOO 3\r\nPROP4:FOO 4\r\nPROP4:FOO 5\r\nPROP4:FOO 6\r\nPROP4:FOO 7\r\nPROP4:FOO 8\r\nPROP4:FOO 9\r\nPROP4:FOO 10\r\nPROPNUMBERFIVE:FOO\r\nPROPNUMBERSIX:FOO\r\nPROPNUMBERSEVEN:FOO\r\nPROPNUMBEREIGHT:FOO\r\nPROPNUMBERNINE:FOO\r\nPROPNUMBERTEN:FOO\r\nUID:FOO\r\nEND:VCARD\r\n", $str); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php new file mode 100644 index 00000000..6ea2faed --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/DateTimeParserTest.php @@ -0,0 +1,153 @@ +assertEquals('+1 weeks', DateTimeParser::parseDuration('P1W',true)); + $this->assertEquals('+5 days', DateTimeParser::parseDuration('P5D',true)); + $this->assertEquals('+5 days 3 hours 50 minutes 12 seconds', DateTimeParser::parseDuration('P5DT3H50M12S',true)); + $this->assertEquals('-1 weeks 50 minutes', DateTimeParser::parseDuration('-P1WT50M',true)); + $this->assertEquals('+50 days 3 hours 2 seconds', DateTimeParser::parseDuration('+P50DT3H2S',true)); + $this->assertEquals(new DateInterval('PT0S'), DateTimeParser::parseDuration('PT0S')); + + } + + function testParseICalendarDurationDateInterval() { + + $expected = new DateInterval('P7D'); + $this->assertEquals($expected, DateTimeParser::parseDuration('P1W')); + $this->assertEquals($expected, DateTimeParser::parse('P1W')); + + $expected = new DateInterval('PT3M'); + $expected->invert = true; + $this->assertEquals($expected, DateTimeParser::parseDuration('-PT3M')); + + } + + /** + * @expectedException LogicException + */ + function testParseICalendarDurationFail() { + + DateTimeParser::parseDuration('P1X',true); + + } + + function testParseICalendarDateTime() { + + $dateTime = DateTimeParser::parseDateTime('20100316T141405'); + + $compare = new DateTime('2010-03-16 14:14:05',new DateTimeZone('UTC')); + + $this->assertEquals($compare, $dateTime); + + } + + /** + * @depends testParseICalendarDateTime + * @expectedException LogicException + */ + function testParseICalendarDateTimeBadFormat() { + + $dateTime = DateTimeParser::parseDateTime('20100316T141405 '); + + } + + /** + * @depends testParseICalendarDateTime + */ + function testParseICalendarDateTimeUTC() { + + $dateTime = DateTimeParser::parseDateTime('20100316T141405Z'); + + $compare = new DateTime('2010-03-16 14:14:05',new DateTimeZone('UTC')); + $this->assertEquals($compare, $dateTime); + + } + + /** + * @depends testParseICalendarDateTime + */ + function testParseICalendarDateTimeUTC2() { + + $dateTime = DateTimeParser::parseDateTime('20101211T160000Z'); + + $compare = new DateTime('2010-12-11 16:00:00',new DateTimeZone('UTC')); + $this->assertEquals($compare, $dateTime); + + } + + /** + * @depends testParseICalendarDateTime + */ + function testParseICalendarDateTimeCustomTimeZone() { + + $dateTime = DateTimeParser::parseDateTime('20100316T141405', new DateTimeZone('Europe/Amsterdam')); + + $compare = new DateTime('2010-03-16 13:14:05',new DateTimeZone('UTC')); + $this->assertEquals($compare, $dateTime); + + } + + function testParseICalendarDate() { + + $dateTime = DateTimeParser::parseDate('20100316'); + + $expected = new DateTime('2010-03-16 00:00:00',new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('20100316'); + $this->assertEquals($expected, $dateTime); + + } + + /** + * TCheck if a date with year > 4000 will not throw an exception. iOS seems to use 45001231 in yearly recurring events + */ + function testParseICalendarDateGreaterThan4000() { + + $dateTime = DateTimeParser::parseDate('45001231'); + + $expected = new DateTime('4500-12-31 00:00:00',new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('45001231'); + $this->assertEquals($expected, $dateTime); + + } + + /** + * Check if a datetime with year > 4000 will not throw an exception. iOS seems to use 45001231T235959 in yearly recurring events + */ + function testParseICalendarDateTimeGreaterThan4000() { + + $dateTime = DateTimeParser::parseDateTime('45001231T235959'); + + $expected = new DateTime('4500-12-31 23:59:59',new DateTimeZone('UTC')); + + $this->assertEquals($expected, $dateTime); + + $dateTime = DateTimeParser::parse('45001231T235959'); + $this->assertEquals($expected, $dateTime); + + } + + /** + * @depends testParseICalendarDate + * @expectedException LogicException + */ + function testParseICalendarDateBadFormat() { + + $dateTime = DateTimeParser::parseDate('20100316T141405'); + + } +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php new file mode 100644 index 00000000..5fd2a2a7 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/DocumentTest.php @@ -0,0 +1,26 @@ +createComponent('VEVENT'); + + $this->assertInstanceOf('Sabre\VObject\Component\VEvent', $event); + $vcal->add($event); + + $prop = $vcal->createProperty('X-PROP','1234256',array('X-PARAM' => '3')); + $this->assertInstanceOf('Sabre\VObject\Property', $prop); + + $event->add($prop); + + $out = $vcal->serialize(); + $this->assertEquals("BEGIN:VCALENDAR\r\nBEGIN:VEVENT\r\nX-PROP;X-PARAM=3:1234256\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n", $out); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php new file mode 100644 index 00000000..84e1bcbe --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ElementListTest.php @@ -0,0 +1,32 @@ +$subcomponent) { + + $count++; + $this->assertInstanceOf('Sabre\\VObject\\Component',$subcomponent); + + } + $this->assertEquals(3,$count); + $this->assertEquals(2,$key); + + } + + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php new file mode 100644 index 00000000..69d410fe --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/EmClientTest.php @@ -0,0 +1,55 @@ +VEVENT->DTSTART->getDateTime(); + $this->assertEquals(new \DateTime('2011-10-08 19:30:00', new \DateTimeZone('America/Chicago')), $dt); + + } + +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php new file mode 100644 index 00000000..1f79e0a4 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/FreeBusyGeneratorTest.php @@ -0,0 +1,246 @@ +getInput() + ); + + $result = $gen->getResult(); + + $expected = array( + '20110101T120000Z/20110101T130000Z', + '20110101T130000Z/20110101T140000Z', + '20110101T180000Z/20110101T190000Z', + '20110101T190000Z/20110101T200000Z', + '20110102T000000Z/20110103T000000Z', + '20110101T210000Z/20110101T220000Z', + + '20110103T010000Z/20110103T020000Z', + '20110103T030000Z/20110103T040000Z', + '20110103T040000Z/20110103T050000Z', + '20110103T050000Z/20110103T060000Z', + + '20110101T220000Z/20110101T230000Z', + '20110101T230000Z/20110102T000000Z', + ); + + foreach($result->VFREEBUSY->FREEBUSY as $fb) { + + $this->assertContains((string)$fb, $expected); + + $k = array_search((string)$fb, $expected); + unset($expected[$k]); + + } + if (count($expected)>0) { + $this->fail('There were elements in the expected array that were not found in the output: ' . "\n" . print_r($expected,true) . "\n" . $result->serialize()); + + } + + } + + function testGeneratorBaseObject() { + + $obj = new Component('VCALENDAR'); + $obj->METHOD = 'PUBLISH'; + + $gen = new FreeBusyGenerator(); + $gen->setObjects(array()); + $gen->setBaseObject($obj); + + $result = $gen->getResult(); + + $this->assertEquals('PUBLISH', $result->METHOD->value); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testInvalidArg() { + + $gen = new FreeBusyGenerator( + new \DateTime('2012-01-01'), + new \DateTime('2012-12-31'), + new \StdClass() + ); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php new file mode 100644 index 00000000..1cc14c16 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue153Test.php @@ -0,0 +1,14 @@ +assertEquals('Test Benutzer', (string)$obj->fn); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php new file mode 100644 index 00000000..ed9c7c3f --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue154Test.php @@ -0,0 +1,29 @@ +VERSION = '3.0'; + $vcard->PHOTO = base64_encode('random_stuff'); + $vcard->PHOTO->add('BASE64',null); + $vcard->UID = 'foo-bar'; + + $result = $vcard->serialize(); + $expected = array( + "BEGIN:VCARD", + "VERSION:3.0", + "PHOTO;BASE64:" . base64_encode('random_stuff'), + "UID:foo-bar", + "END:VCARD", + "", + ); + + $this->assertEquals(implode("\r\n", $expected), $result); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php new file mode 100644 index 00000000..980d432b --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue48Test.php @@ -0,0 +1,47 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new RecurrenceIterator($vcal, 'foo'); + + $result = iterator_to_array($it); + + $tz = new DateTimeZone('Europe/Moscow'); + + $this->assertEquals(array( + new DateTime('2013-07-10 11:00:00', $tz), + new DateTime('2013-07-12 11:00:00', $tz), + new DateTime('2013-07-13 11:00:00', $tz), + ), $result); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php new file mode 100644 index 00000000..fdb012ba --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Issue50Test.php @@ -0,0 +1,128 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $it = new RecurrenceIterator($vcal, '1aef0b27-3d92-4581-829a-11999dd36724'); + + $result = array(); + foreach($it as $instance) { + + $result[] = $instance; + + } + + $tz = new DateTimeZone('Europe/Brussels'); + + $this->assertEquals(array( + new DateTime('2013-07-15 09:00:00', $tz), + new DateTime('2013-07-16 07:00:00', $tz), + new DateTime('2013-07-17 07:00:00', $tz), + new DateTime('2013-07-18 09:00:00', $tz), + new DateTime('2013-07-19 07:00:00', $tz), + ), $result); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php new file mode 100644 index 00000000..90eb5d2a --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ParameterTest.php @@ -0,0 +1,44 @@ +assertEquals('NAME',$param->name); + $this->assertEquals('value',$param->value); + $this->assertEquals('value',$param->getValue()); + + } + + function testCastToString() { + + $param = new Parameter('name','value'); + $this->assertEquals('value',$param->__toString()); + $this->assertEquals('value',(string)$param); + + } + + function testSerialize() { + + $param = new Parameter('name','value'); + $this->assertEquals('NAME=value',$param->serialize()); + + } + + function testSerializeEmpty() { + + $param = new Parameter('name',null); + $this->assertEquals('NAME',$param->serialize()); + + } + + function testSerializeColon() { + + $param = new Parameter('name','va:lue'); + $this->assertEquals('NAME="va:lue"',$param->serialize()); + + } +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php new file mode 100644 index 00000000..5d8cdaab --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/CompoundTest.php @@ -0,0 +1,59 @@ +setParts($arr); + + $this->assertEquals('ABC\, Inc.;North American Division;Marketing\;Sales', $elem->value); + $this->assertEquals(3, count($elem->getParts())); + $parts = $elem->getParts(); + $this->assertEquals('Marketing;Sales', $parts[2]); + + } + + function testGetParts() { + + $str = 'ABC\, Inc.;North American Division;Marketing\;Sales'; + + $elem = new Compound('ORG', $str); + + $this->assertEquals(3, count($elem->getParts())); + $parts = $elem->getParts(); + $this->assertEquals('Marketing;Sales', $parts[2]); + } + + function testGetPartsDefaultDelimiter() { + + $str = 'Hi!;Hello!'; + + $elem = new Compound('X-FOO', $str); + + $this->assertEquals(array( + 'Hi!', + 'Hello!', + ), $elem->getParts()); + + } + + function testGetPartsNull() { + + $str = 'ABC\, Inc.;North American Division;Marketing\;Sales'; + + $elem = new Compound('ORG', null); + + $this->assertEquals(0, count($elem->getParts())); + + } +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php new file mode 100644 index 00000000..b5b522e7 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/DateTimeTest.php @@ -0,0 +1,240 @@ +setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals('19850704T013000', $elem->value); + $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + + } + + function testSetDateTimeLOCAL() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt, DateTime::LOCAL); + + $this->assertEquals('19850704T013000', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeUTC() { + + $tz = new \DateTimeZone('GMT'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt, DateTime::UTC); + + $this->assertEquals('19850704T013000Z', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeLOCALTZ() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt, DateTime::LOCALTZ); + + $this->assertEquals('19850704T013000', $elem->value); + $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeDATE() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt, DateTime::DATE); + + $this->assertEquals('19850704', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE', (string)$elem['VALUE']); + + $this->assertFalse($elem->hasTime()); + } + + /** + * @expectedException InvalidArgumentException + */ + function testSetDateTimeInvalid() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt, 7); + + } + + function testGetDateTimeCached() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new DateTime('DTSTART'); + $elem->setDateTime($dt); + + $this->assertEquals($elem->getDateTime(), $dt); + + } + + function testGetDateTimeDateNULL() { + + $elem = new DateTime('DTSTART'); + $dt = $elem->getDateTime(); + + $this->assertNull($dt); + $this->assertNull($elem->getDateType()); + + } + + function testGetDateTimeDateDATE() { + + $elem = new DateTime('DTSTART','19850704'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 00:00:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals(DateTime::DATE, $elem->getDateType()); + + } + + + function testGetDateTimeDateLOCAL() { + + $elem = new DateTime('DTSTART','19850704T013000'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals(DateTime::LOCAL, $elem->getDateType()); + + } + + function testGetDateTimeDateUTC() { + + $elem = new DateTime('DTSTART','19850704T013000Z'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('UTC', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::UTC, $elem->getDateType()); + + } + + function testGetDateTimeDateLOCALTZ() { + + $elem = new DateTime('DTSTART','19850704T013000'); + $elem['TZID'] = 'Europe/Amsterdam'; + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testGetDateTimeDateInvalid() { + + $elem = new DateTime('DTSTART','bla'); + $dt = $elem->getDateTime(); + + } + + function testGetDateTimeWeirdTZ() { + + $elem = new DateTime('DTSTART','19850704T013000'); + $elem['TZID'] = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam'; + + + $event = new Component('VEVENT'); + $event->add($elem); + + $timezone = new Component('VTIMEZONE'); + $timezone->TZID = '/freeassociation.sourceforge.net/Tzfile/Europe/Amsterdam'; + $timezone->{'X-LIC-LOCATION'} = 'Europe/Amsterdam'; + + $calendar = new Component('VCALENDAR'); + $calendar->add($event); + $calendar->add($timezone); + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType()); + + } + + function testGetDateTimeBadTimeZone() { + + $default = date_default_timezone_get(); + date_default_timezone_set('Canada/Eastern'); + + $elem = new DateTime('DTSTART','19850704T013000'); + $elem['TZID'] = 'Moon'; + + + $event = new Component('VEVENT'); + $event->add($elem); + + $timezone = new Component('VTIMEZONE'); + $timezone->TZID = 'Moon'; + $timezone->{'X-LIC-LOCATION'} = 'Moon'; + + $calendar = new Component('VCALENDAR'); + $calendar->add($event); + $calendar->add($timezone); + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Canada/Eastern', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType()); + date_default_timezone_set($default); + + } +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php new file mode 100644 index 00000000..17761665 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Property/MultiDateTimeTest.php @@ -0,0 +1,208 @@ +setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2)); + + $this->assertEquals('19850704T013000,19860704T013000', $elem->value); + $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + + } + + function testSetDateTimeLOCAL() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1986-07-04 01:30:00', $tz); + $dt1->setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2), DateTime::LOCAL); + + $this->assertEquals('19850704T013000,19860704T013000', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeUTC() { + + $tz = new \DateTimeZone('GMT'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1986-07-04 01:30:00', $tz); + $dt1->setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2), DateTime::UTC); + + $this->assertEquals('19850704T013000Z,19860704T013000Z', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeLOCALTZ() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1986-07-04 01:30:00', $tz); + $dt1->setTimeZone($tz); + $dt2->setTimeZone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2), DateTime::LOCALTZ); + + $this->assertEquals('19850704T013000,19860704T013000', $elem->value); + $this->assertEquals('Europe/Amsterdam', (string)$elem['TZID']); + $this->assertEquals('DATE-TIME', (string)$elem['VALUE']); + + $this->assertTrue($elem->hasTime()); + } + + function testSetDateTimeDATE() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1986-07-04 01:30:00', $tz); + $dt1->settimezone($tz); + $dt2->settimezone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2), DateTime::DATE); + + $this->assertEquals('19850704,19860704', $elem->value); + $this->assertNull($elem['TZID']); + $this->assertEquals('DATE', (string)$elem['VALUE']); + + $this->assertFalse($elem->hasTime()); + } + + /** + * @expectedException InvalidArgumentException + */ + function testSetDateTimeInvalid() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt = new \DateTime('1985-07-04 01:30:00', $tz); + $dt->setTimeZone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt), 7); + + } + + function testGetDateTimeCached() { + + $tz = new \DateTimeZone('Europe/Amsterdam'); + $dt1 = new \DateTime('1985-07-04 01:30:00', $tz); + $dt2 = new \DateTime('1986-07-04 01:30:00', $tz); + $dt1->settimezone($tz); + $dt2->settimezone($tz); + + $elem = new MultiDateTime('DTSTART'); + $elem->setDateTimes(array($dt1,$dt2)); + + $this->assertEquals($elem->getDateTimes(), array($dt1,$dt2)); + + } + + function testGetDateTimeDateNULL() { + + $elem = new MultiDateTime('DTSTART'); + $dt = $elem->getDateTimes(); + + $this->assertNull($dt); + $this->assertNull($elem->getDateType()); + + } + + function testGetDateTimeDateDATE() { + + $elem = new MultiDateTime('DTSTART','19850704,19860704'); + $dt = $elem->getDateTimes(); + + $this->assertEquals('1985-07-04 00:00:00', $dt[0]->format('Y-m-d H:i:s')); + $this->assertEquals('1986-07-04 00:00:00', $dt[1]->format('Y-m-d H:i:s')); + $this->assertEquals(DateTime::DATE, $elem->getDateType()); + + } + + function testGetDateTimeDateDATEReverse() { + + $elem = new MultiDateTime('DTSTART','19850704,19860704'); + + $this->assertEquals(DateTime::DATE, $elem->getDateType()); + + $dt = $elem->getDateTimes(); + $this->assertEquals('1985-07-04 00:00:00', $dt[0]->format('Y-m-d H:i:s')); + $this->assertEquals('1986-07-04 00:00:00', $dt[1]->format('Y-m-d H:i:s')); + + } + + + function testGetDateTimeDateLOCAL() { + + $elem = new DateTime('DTSTART','19850704T013000'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals(DateTime::LOCAL, $elem->getDateType()); + + } + + function testGetDateTimeDateUTC() { + + $elem = new DateTime('DTSTART','19850704T013000Z'); + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('UTC', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::UTC, $elem->getDateType()); + + } + + function testGetDateTimeDateLOCALTZ() { + + $elem = new DateTime('DTSTART','19850704T013000'); + $elem['TZID'] = 'Europe/Amsterdam'; + + $dt = $elem->getDateTime(); + + $this->assertInstanceOf('DateTime', $dt); + $this->assertEquals('1985-07-04 01:30:00', $dt->format('Y-m-d H:i:s')); + $this->assertEquals('Europe/Amsterdam', $dt->getTimeZone()->getName()); + $this->assertEquals(DateTime::LOCALTZ, $elem->getDateType()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testGetDateTimeDateInvalid() { + + $elem = new DateTime('DTSTART','bla'); + $dt = $elem->getDateTime(); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php new file mode 100644 index 00000000..3bb28956 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/PropertyTest.php @@ -0,0 +1,324 @@ +assertEquals('PROPNAME', $property->name); + $this->assertEquals('propvalue', $property->value); + $this->assertEquals('propvalue', $property->__toString()); + $this->assertEquals('propvalue', (string)$property); + $this->assertEquals('propvalue', $property->getValue()); + + } + + /** + * @expectedException InvalidArgumentException + */ + public function testCreateNonScalar() { + + $property = new Property('propname',array()); + + } + + public function testParameterExists() { + + $property = new Property('propname','propvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + + $this->assertTrue(isset($property['PARAMNAME'])); + $this->assertTrue(isset($property['paramname'])); + $this->assertFalse(isset($property['foo'])); + + } + + public function testParameterGet() { + + $property = new Property('propname','propvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + + $this->assertInstanceOf('Sabre\\VObject\\Parameter',$property['paramname']); + + } + + public function testParameterNotExists() { + + $property = new Property('propname','propvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + + $this->assertInternalType('null',$property['foo']); + + } + + public function testParameterMultiple() { + + $property = new Property('propname','propvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + + $this->assertInstanceOf('Sabre\\VObject\\Parameter',$property['paramname']); + $this->assertEquals(2,count($property['paramname'])); + + } + + public function testSetParameterAsString() { + + $property = new Property('propname','propvalue'); + $property['paramname'] = 'paramvalue'; + + $this->assertEquals(1,count($property->parameters)); + $this->assertInstanceOf('Sabre\\VObject\\Parameter', $property->parameters[0]); + $this->assertEquals('PARAMNAME',$property->parameters[0]->name); + $this->assertEquals('paramvalue',$property->parameters[0]->value); + + } + + /** + * @expectedException InvalidArgumentException + */ + public function testSetParameterAsStringNoKey() { + + $property = new Property('propname','propvalue'); + $property[] = 'paramvalue'; + + } + + public function testSetParameterObject() { + + $property = new Property('propname','propvalue'); + $param = new Parameter('paramname','paramvalue'); + + $property[] = $param; + + $this->assertEquals(1,count($property->parameters)); + $this->assertEquals($param, $property->parameters[0]); + + } + + /** + * @expectedException InvalidArgumentException + */ + public function testSetParameterObjectWithKey() { + + $property = new Property('propname','propvalue'); + $param = new Parameter('paramname','paramvalue'); + + $property['key'] = $param; + + } + + + /** + * @expectedException InvalidArgumentException + */ + public function testSetParameterObjectRandomObject() { + + $property = new Property('propname','propvalue'); + $property[] = new \StdClass(); + + } + + public function testUnsetParameter() { + + $property = new Property('propname','propvalue'); + $param = new Parameter('paramname','paramvalue'); + $property->parameters[] = $param; + + unset($property['PARAMNAME']); + $this->assertEquals(0,count($property->parameters)); + + } + + public function testParamCount() { + + $property = new Property('propname','propvalue'); + $param = new Parameter('paramname','paramvalue'); + $property->parameters[] = $param; + $property->parameters[] = clone $param; + + $this->assertEquals(2,count($property->parameters)); + + } + + public function testSerialize() { + + $property = new Property('propname','propvalue'); + + $this->assertEquals("PROPNAME:propvalue\r\n",$property->serialize()); + + } + + public function testSerializeParam() { + + $property = new Property('propname','propvalue'); + $property->parameters[] = new Parameter('paramname','paramvalue'); + $property->parameters[] = new Parameter('paramname2','paramvalue2'); + + $this->assertEquals("PROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propvalue\r\n",$property->serialize()); + + } + + public function testSerializeNewLine() { + + $property = new Property('propname',"line1\nline2"); + + $this->assertEquals("PROPNAME:line1\\nline2\r\n",$property->serialize()); + + } + + public function testSerializeLongLine() { + + $value = str_repeat('!',200); + $property = new Property('propname',$value); + + $expected = "PROPNAME:" . str_repeat('!',66) . "\r\n " . str_repeat('!',74) . "\r\n " . str_repeat('!',60) . "\r\n"; + + $this->assertEquals($expected,$property->serialize()); + + } + + public function testSerializeUTF8LineFold() { + + $value = str_repeat('!',65) . "\xc3\xa4bla"; // inserted umlaut-a + $property = new Property('propname', $value); + $expected = "PROPNAME:" . str_repeat('!',65) . "\r\n \xc3\xa4bla\r\n"; + $this->assertEquals($expected, $property->serialize()); + + } + + public function testGetIterator() { + + $it = new ElementList(array()); + $property = new Property('propname','propvalue'); + $property->setIterator($it); + $this->assertEquals($it,$property->getIterator()); + + } + + + public function testGetIteratorDefault() { + + $property = new Property('propname','propvalue'); + $it = $property->getIterator(); + $this->assertTrue($it instanceof ElementList); + $this->assertEquals(1,count($it)); + + } + + function testAddScalar() { + + $property = new Property('EMAIL'); + + $property->add('myparam','value'); + + $this->assertEquals(1, count($property->parameters)); + + $this->assertTrue($property->parameters[0] instanceof Parameter); + $this->assertEquals('MYPARAM',$property->parameters[0]->name); + $this->assertEquals('value',$property->parameters[0]->value); + + } + + function testAddParameter() { + + $prop = new Property('EMAIL'); + + $prop->add(new Parameter('MYPARAM','value')); + + $this->assertEquals(1, count($prop->parameters)); + $this->assertEquals('MYPARAM',$prop['myparam']->name); + + } + + function testAddParameterTwice() { + + $prop = new Property('EMAIL'); + + $prop->add(new Parameter('MYPARAM', 'value1')); + $prop->add(new Parameter('MYPARAM', 'value2')); + + $this->assertEquals(2, count($prop->parameters)); + + $this->assertEquals('MYPARAM',$prop['MYPARAM']->name); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail() { + + $prop = new Property('EMAIL'); + $prop->add(new Parameter('MPARAM'),'hello'); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail2() { + + $property = new Property('EMAIL','value'); + $property->add(array()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testAddArgFail3() { + + $property = new Property('EMAIL','value'); + $property->add('hello',array()); + + } + + function testClone() { + + $property = new Property('EMAIL','value'); + $property['FOO'] = 'BAR'; + + $property2 = clone $property; + + $property['FOO'] = 'BAZ'; + $this->assertEquals('BAR', (string)$property2['FOO']); + + } + + function testCreateParams() { + + $property = Property::create('X-PROP', 'value', array( + 'param1' => 'value1', + 'param2' => array('value2', 'value3') + )); + + $this->assertEquals(1, count($property['PARAM1'])); + $this->assertEquals(2, count($property['PARAM2'])); + + } + + function testValidateNonUTF8() { + + $property = Property::create('X-PROP', "Bla\x00"); + $result = $property->validate(Property::REPAIR); + + $this->assertEquals('Property is not valid UTF-8!', $result[0]['message']); + $this->assertEquals('Bla', $property->value); + + } + + + function testValidateBadPropertyName() { + + $property = Property::create("X_*&PROP*", "Bla"); + $result = $property->validate(Property::REPAIR); + + $this->assertEquals($result[0]['message'], 'The propertyname: X_*&PROP* contains invalid characters. Only A-Z, 0-9 and - are allowed'); + $this->assertEquals('X-PROP', $property->name); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php new file mode 100644 index 00000000..0969c6e5 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/ReaderTest.php @@ -0,0 +1,367 @@ +assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children)); + + } + + function testReadComponentUnixNewLine() { + + $data = "BEGIN:VCALENDAR\nEND:VCALENDAR"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children)); + + } + + function testReadComponentMacNewLine() { + + $data = "BEGIN:VCALENDAR\rEND:VCALENDAR"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children)); + + } + + function testReadComponentLineFold() { + + $data = "BEGIN:\r\n\tVCALENDAR\r\nE\r\n ND:VCALENDAR"; + + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(0, count($result->children)); + + } + + /** + * @expectedException Sabre\VObject\ParseException + */ + function testReadCorruptComponent() { + + $data = "BEGIN:VCALENDAR\r\nEND:FOO"; + + $result = Reader::read($data); + + } + + function testReadProperty() { + + $data = "PROPNAME:propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + + } + + function testReadPropertyWithNewLine() { + + $data = 'PROPNAME:Line1\\nLine2\\NLine3\\\\Not the 4th line!'; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals("Line1\nLine2\nLine3\\Not the 4th line!", $result->value); + + } + + function testReadMappedProperty() { + + $data = "DTSTART:20110529"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property\\DateTime', $result); + $this->assertEquals('DTSTART', $result->name); + $this->assertEquals('20110529', $result->value); + + } + + function testReadMappedPropertyGrouped() { + + $data = "foo.DTSTART:20110529"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property\\DateTime', $result); + $this->assertEquals('DTSTART', $result->name); + $this->assertEquals('20110529', $result->value); + + } + + + /** + * @expectedException Sabre\VObject\ParseException + */ + function testReadBrokenLine() { + + $data = "PROPNAME;propValue"; + $result = Reader::read($data); + + } + + function testReadPropertyInComponent() { + + $data = array( + "BEGIN:VCALENDAR", + "PROPNAME:propValue", + "END:VCALENDAR" + ); + + $result = Reader::read(implode("\r\n",$data)); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(1, count($result->children)); + $this->assertInstanceOf('Sabre\\VObject\\Property', $result->children[0]); + $this->assertEquals('PROPNAME', $result->children[0]->name); + $this->assertEquals('propValue', $result->children[0]->value); + + } + function testReadNestedComponent() { + + $data = array( + "BEGIN:VCALENDAR", + "BEGIN:VTIMEZONE", + "BEGIN:DAYLIGHT", + "END:DAYLIGHT", + "END:VTIMEZONE", + "END:VCALENDAR" + ); + + $result = Reader::read(implode("\r\n",$data)); + + $this->assertInstanceOf('Sabre\\VObject\\Component', $result); + $this->assertEquals('VCALENDAR', $result->name); + $this->assertEquals(1, count($result->children)); + $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children[0]); + $this->assertEquals('VTIMEZONE', $result->children[0]->name); + $this->assertEquals(1, count($result->children[0]->children)); + $this->assertInstanceOf('Sabre\\VObject\\Component', $result->children[0]->children[0]); + $this->assertEquals('DAYLIGHT', $result->children[0]->children[0]->name); + + + } + + function testReadPropertyParameter() { + + $data = "PROPNAME;PARAMNAME=paramvalue:propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals('paramvalue', $result->parameters[0]->value); + + } + + function testReadPropertyNoValue() { + + $data = "PROPNAME;PARAMNAME:propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + + $this->assertNull($result->parameters[0]->value); + + } + + function testReadPropertyParameterExtraColon() { + + $data = "PROPNAME;PARAMNAME=paramvalue:propValue:anotherrandomstring"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue:anotherrandomstring', $result->value); + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals('paramvalue', $result->parameters[0]->value); + + } + + function testReadProperty2Parameters() { + + $data = "PROPNAME;PARAMNAME=paramvalue;PARAMNAME2=paramvalue2:propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + $this->assertEquals(2, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals('paramvalue', $result->parameters[0]->value); + $this->assertEquals('PARAMNAME2', $result->parameters[1]->name); + $this->assertEquals('paramvalue2', $result->parameters[1]->value); + + } + + function testReadPropertyParameterQuoted() { + + $data = "PROPNAME;PARAMNAME=\"paramvalue\":propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals('paramvalue', $result->parameters[0]->value); + + } + function testReadPropertyParameterNewLines() { + + $data = "PROPNAME;PARAMNAME=paramvalue1\\nvalue2\\\\nvalue3:propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals("paramvalue1\nvalue2\\nvalue3", $result->parameters[0]->value); + + } + + function testReadPropertyParameterQuotedColon() { + + $data = "PROPNAME;PARAMNAME=\"param:value\":propValue"; + $result = Reader::read($data); + + $this->assertInstanceOf('Sabre\\VObject\\Property', $result); + $this->assertEquals('PROPNAME', $result->name); + $this->assertEquals('propValue', $result->value); + $this->assertEquals(1, count($result->parameters)); + $this->assertEquals('PARAMNAME', $result->parameters[0]->name); + $this->assertEquals('param:value', $result->parameters[0]->value); + + } + + function testReadForgiving() { + + $data = array( + "BEGIN:VCALENDAR", + "X_PROP:propValue", + "END:VCALENDAR" + ); + + $caught = false; + try { + $result = Reader::read(implode("\r\n",$data)); + } catch (ParseException $e) { + $caught = true; + } + + $this->assertEquals(true, $caught); + + $result = Reader::read(implode("\r\n",$data), Reader::OPTION_FORGIVING); + + $expected = implode("\r\n", array( + "BEGIN:VCALENDAR", + "X_PROP:propValue", + "END:VCALENDAR", + "" + )); + + $this->assertEquals($expected, $result->serialize()); + + + } + + function testReadWithInvalidLine() { + + $data = array( + "BEGIN:VCALENDAR", + "DESCRIPTION:propValue", + "Yes, we've actually seen a file with non-idented property values on multiple lines", + "END:VCALENDAR" + ); + + $caught = false; + try { + $result = Reader::read(implode("\r\n",$data)); + } catch (ParseException $e) { + $caught = true; + } + + $this->assertEquals(true, $caught); + + $result = Reader::read(implode("\r\n",$data), Reader::OPTION_IGNORE_INVALID_LINES); + + $expected = implode("\r\n", array( + "BEGIN:VCALENDAR", + "DESCRIPTION:propValue", + "END:VCALENDAR", + "" + )); + + $this->assertEquals($expected, $result->serialize()); + + + } + + /** + * Reported as Issue 32. + * + * @expectedException \Sabre\VObject\ParseException + */ + function testReadIncompleteFile() { + + $input = <<VEVENT->UID); + + while($it->valid()) { + $it->next(); + } + + // If we got here, it means we were successful. The bug that was in the + // system before would fail on the 5th tuesday of the month, if the 5th + // tuesday did not exist. + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php new file mode 100644 index 00000000..9adc8537 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorIncorrectExpandTest.php @@ -0,0 +1,62 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal->expand(new DateTime('2011-01-01'), new DateTime('2014-01-01')); + + $result = $vcal->serialize(); + + $output = <<assertEquals($output, str_replace("\r", "", $result)); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php new file mode 100644 index 00000000..670c39ba --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorInfiniteLoopProblemTest.php @@ -0,0 +1,91 @@ +DTSTART = '20090420T180000Z'; + $ev->RRULE = 'FREQ=WEEKLY;BYDAY=MO;UNTIL=20090704T205959Z;INTERVAL=1'; + + $this->assertFalse($ev->isInTimeRange(new DateTime('2012-01-01 12:00:00'),new DateTime('3000-01-01 00:00:00'))); + + } + + /** + * Different bug, also likely an infinite loop. + */ + function testYearlyByMonthLoop() { + + $ev = Component::create('VEVENT'); + $ev->UID = 'uuid'; + $ev->DTSTART = '20120101T154500'; + $ev->DTSTART['TZID'] = 'Europe/Berlin'; + $ev->RRULE = 'FREQ=YEARLY;INTERVAL=1;UNTIL=20120203T225959Z;BYMONTH=2;BYSETPOS=1;BYDAY=SU,MO,TU,WE,TH,FR,SA'; + $ev->DTEND = '20120101T164500'; + $ev->DTEND['TZID'] = 'Europe/Berlin'; + + // This recurrence rule by itself is a yearly rule that should happen + // every february. + // + // The BYDAY part expands this to every day of the month, but the + // BYSETPOS limits this to only the 1st day of the month. Very crazy + // way to specify this, and could have certainly been a lot easier. + $cal = Component::create('VCALENDAR'); + $cal->add($ev); + + $it = new RecurrenceIterator($cal,'uuid'); + $it->fastForward(new DateTime('2012-01-29 23:00:00', new DateTimeZone('UTC'))); + + $collect = array(); + + while($it->valid()) { + $collect[] = $it->getDTSTART(); + if ($it->getDTSTART() > new DateTime('2013-02-05 22:59:59', new DateTimeZone('UTC'))) { + break; + } + $it->next(); + + } + + $this->assertEquals( + array(new DateTime('2012-02-01 15:45:00', new DateTimeZone('Europe/Berlin'))), + $collect + ); + + } + + /** + * Something, somewhere produced an ics with an interval set to 0. Because + * this means we increase the current day (or week, month) by 0, this also + * results in an infinite loop. + * + * @expectedException InvalidArgumentException + * @return void + */ + function testZeroInterval() { + + $ev = Component::create('VEVENT'); + $ev->UID = 'uuid'; + $ev->DTSTART = '20120824T145700Z'; + $ev->RRULE = 'FREQ=YEARLY;INTERVAL=0'; + $cal = Component::create('VCALENDAR'); + $cal->add($ev); + + $it = new RecurrenceIterator($cal,'uuid'); + $it->fastForward(new DateTime('2013-01-01 23:00:00', new DateTimeZone('UTC'))); + + // if we got this far.. it means we are no longer infinitely looping + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php new file mode 100644 index 00000000..2c17f9f6 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMinusOneProblemTest.php @@ -0,0 +1,30 @@ +VEVENT->UID); + + $this->assertTrue($it->valid()); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php new file mode 100644 index 00000000..f311329d --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorMissingOverriddenTest.php @@ -0,0 +1,63 @@ +assertInstanceOf('Sabre\\VObject\\Component\\VCalendar', $vcal); + + $vcal->expand(new DateTime('2011-01-01'), new DateTime('2015-01-01')); + + $result = $vcal->serialize(); + + $output = <<assertEquals($output, str_replace("\r","",$result)); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php new file mode 100644 index 00000000..5988f16e --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/RecurrenceIteratorTest.php @@ -0,0 +1,1425 @@ +UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;BYHOUR=10;BYMINUTE=5;BYSECOND=16;BYWEEKNO=32;BYYEARDAY=100,200'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07'),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertTrue($it->isInfinite()); + $this->assertEquals(array(10), $it->byHour); + $this->assertEquals(array(5), $it->byMinute); + $this->assertEquals(array(16), $it->bySecond); + $this->assertEquals(array(32), $it->byWeekNo); + $this->assertEquals(array(100,200), $it->byYearDay); + + } + + /** + * @expectedException InvalidArgumentException + * @depends testValues + */ + function testInvalidFreq() { + + $ev = new Component('VEVENT'); + $ev->RRULE = 'FREQ=SMONTHLY;INTERVAL=3;UNTIL=20111025T000000Z'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07'),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testVCalendarNoUID() { + + $vcal = new Component('VCALENDAR'); + $it = new RecurrenceIterator($vcal); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testVCalendarInvalidUID() { + + $vcal = new Component('VCALENDAR'); + $it = new RecurrenceIterator($vcal,'foo'); + + } + + /** + * @depends testValues + */ + function testHourly() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=HOURLY;INTERVAL=3;UNTIL=20111025T000000Z'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07 12:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,$ev->uid); + + $this->assertEquals('hourly', $it->frequency); + $this->assertEquals(3, $it->interval); + $this->assertEquals(new DateTime('2011-10-25', new DateTimeZone('UTC')), $it->until); + + // Max is to prevent overflow + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07 12:00:00', $tz), + new DateTime('2011-10-07 15:00:00', $tz), + new DateTime('2011-10-07 18:00:00', $tz), + new DateTime('2011-10-07 21:00:00', $tz), + new DateTime('2011-10-08 00:00:00', $tz), + new DateTime('2011-10-08 03:00:00', $tz), + new DateTime('2011-10-08 06:00:00', $tz), + new DateTime('2011-10-08 09:00:00', $tz), + new DateTime('2011-10-08 12:00:00', $tz), + new DateTime('2011-10-08 15:00:00', $tz), + new DateTime('2011-10-08 18:00:00', $tz), + new DateTime('2011-10-08 21:00:00', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testDaily() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=3;UNTIL=20111025T000000Z'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,$ev->uid); + + $this->assertEquals('daily', $it->frequency); + $this->assertEquals(3, $it->interval); + $this->assertEquals(new DateTime('2011-10-25', new DateTimeZone('UTC')), $it->until); + + // Max is to prevent overflow + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07', $tz), + new DateTime('2011-10-10', $tz), + new DateTime('2011-10-13', $tz), + new DateTime('2011-10-16', $tz), + new DateTime('2011-10-19', $tz), + new DateTime('2011-10-22', $tz), + new DateTime('2011-10-25', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testNoRRULE() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,$ev->uid); + + $this->assertEquals('daily', $it->frequency); + $this->assertEquals(1, $it->interval); + + // Max is to prevent overflow + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testDailyByDayByHour() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;BYDAY=SA,SU;BYHOUR=6,7'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-08 06:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('daily', $it->frequency); + $this->assertEquals(1, $it->interval); + $this->assertEquals(array('6','7'), $it->byHour); + $this->assertEquals(array('SA','SU'), $it->byDay); + + // Grabbing the next 12 items + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new datetime('2011-10-08 06:00:00', $tz), + new datetime('2011-10-08 07:00:00', $tz), + new datetime('2011-10-09 06:00:00', $tz), + new datetime('2011-10-09 07:00:00', $tz), + new datetime('2011-10-15 06:00:00', $tz), + new datetime('2011-10-15 07:00:00', $tz), + new datetime('2011-10-16 06:00:00', $tz), + new datetime('2011-10-16 07:00:00', $tz), + new datetime('2011-10-22 06:00:00', $tz), + new datetime('2011-10-22 07:00:00', $tz), + new datetime('2011-10-23 06:00:00', $tz), + new datetime('2011-10-23 07:00:00', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testDailyByHour() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYHOUR=10,11,12,13,14,15'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2012-10-11 12:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('daily', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(array('10','11','12','13','14','15'), $it->byHour); + + // Grabbing the next 12 items + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new datetime('2012-10-11 12:00:00', $tz), + new datetime('2012-10-11 13:00:00', $tz), + new datetime('2012-10-11 14:00:00', $tz), + new datetime('2012-10-11 15:00:00', $tz), + new datetime('2012-10-13 10:00:00', $tz), + new datetime('2012-10-13 11:00:00', $tz), + new datetime('2012-10-13 12:00:00', $tz), + new datetime('2012-10-13 13:00:00', $tz), + new datetime('2012-10-13 14:00:00', $tz), + new datetime('2012-10-13 15:00:00', $tz), + new datetime('2012-10-15 10:00:00', $tz), + new datetime('2012-10-15 11:00:00', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testDailyByDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=DAILY;INTERVAL=2;BYDAY=TU,WE,FR'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('daily', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(array('TU','WE','FR'), $it->byDay); + + // Grabbing the next 12 items + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07', $tz), + new DateTime('2011-10-11', $tz), + new DateTime('2011-10-19', $tz), + new DateTime('2011-10-21', $tz), + new DateTime('2011-10-25', $tz), + new DateTime('2011-11-02', $tz), + new DateTime('2011-11-04', $tz), + new DateTime('2011-11-08', $tz), + new DateTime('2011-11-16', $tz), + new DateTime('2011-11-18', $tz), + new DateTime('2011-11-22', $tz), + new DateTime('2011-11-30', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testWeekly() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;COUNT=10'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('weekly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(10, $it->count); + + // Max is to prevent overflow + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07', $tz), + new DateTime('2011-10-21', $tz), + new DateTime('2011-11-04', $tz), + new DateTime('2011-11-18', $tz), + new DateTime('2011-12-02', $tz), + new DateTime('2011-12-16', $tz), + new DateTime('2011-12-30', $tz), + new DateTime('2012-01-13', $tz), + new DateTime('2012-01-27', $tz), + new DateTime('2012-02-10', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testWeeklyByDayByHour() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=MO;BYHOUR=8,9,10'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07 08:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('weekly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(array('TU','WE','FR'), $it->byDay); + $this->assertEquals(array('8','9','10'), $it->byHour); + $this->assertEquals('MO', $it->weekStart); + + // Grabbing the next 12 items + $max = 15; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07 08:00:00', $tz), + new DateTime('2011-10-07 09:00:00', $tz), + new DateTime('2011-10-07 10:00:00', $tz), + new DateTime('2011-10-18 08:00:00', $tz), + new DateTime('2011-10-18 09:00:00', $tz), + new DateTime('2011-10-18 10:00:00', $tz), + new DateTime('2011-10-19 08:00:00', $tz), + new DateTime('2011-10-19 09:00:00', $tz), + new DateTime('2011-10-19 10:00:00', $tz), + new DateTime('2011-10-21 08:00:00', $tz), + new DateTime('2011-10-21 09:00:00', $tz), + new DateTime('2011-10-21 10:00:00', $tz), + new DateTime('2011-11-01 08:00:00', $tz), + new DateTime('2011-11-01 09:00:00', $tz), + new DateTime('2011-11-01 10:00:00', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testWeeklyByDaySpecificHour() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07 18:00:00', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('weekly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(array('TU','WE','FR'), $it->byDay); + $this->assertEquals('SU', $it->weekStart); + + // Grabbing the next 12 items + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07 18:00:00', $tz), + new DateTime('2011-10-18 18:00:00', $tz), + new DateTime('2011-10-19 18:00:00', $tz), + new DateTime('2011-10-21 18:00:00', $tz), + new DateTime('2011-11-01 18:00:00', $tz), + new DateTime('2011-11-02 18:00:00', $tz), + new DateTime('2011-11-04 18:00:00', $tz), + new DateTime('2011-11-15 18:00:00', $tz), + new DateTime('2011-11-16 18:00:00', $tz), + new DateTime('2011-11-18 18:00:00', $tz), + new DateTime('2011-11-29 18:00:00', $tz), + new DateTime('2011-11-30 18:00:00', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testWeeklyByDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=WEEKLY;INTERVAL=2;BYDAY=TU,WE,FR;WKST=SU'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-10-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('weekly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(array('TU','WE','FR'), $it->byDay); + $this->assertEquals('SU', $it->weekStart); + + // Grabbing the next 12 items + $max = 12; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-10-07', $tz), + new DateTime('2011-10-18', $tz), + new DateTime('2011-10-19', $tz), + new DateTime('2011-10-21', $tz), + new DateTime('2011-11-01', $tz), + new DateTime('2011-11-02', $tz), + new DateTime('2011-11-04', $tz), + new DateTime('2011-11-15', $tz), + new DateTime('2011-11-16', $tz), + new DateTime('2011-11-18', $tz), + new DateTime('2011-11-29', $tz), + new DateTime('2011-11-30', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testMonthly() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=3;COUNT=5'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-12-05', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(3, $it->interval); + $this->assertEquals(5, $it->count); + + $max = 14; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-12-05', $tz), + new DateTime('2012-03-05', $tz), + new DateTime('2012-06-05', $tz), + new DateTime('2012-09-05', $tz), + new DateTime('2012-12-05', $tz), + ), + $result + ); + + + } + + /** + * @depends testValues + */ + function testMonthlyEndOfMonth() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=12'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-12-31', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(12, $it->count); + + $max = 14; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-12-31', $tz), + new DateTime('2012-08-31', $tz), + new DateTime('2012-10-31', $tz), + new DateTime('2012-12-31', $tz), + new DateTime('2013-08-31', $tz), + new DateTime('2013-10-31', $tz), + new DateTime('2013-12-31', $tz), + new DateTime('2014-08-31', $tz), + new DateTime('2014-10-31', $tz), + new DateTime('2014-12-31', $tz), + new DateTime('2015-08-31', $tz), + new DateTime('2015-10-31', $tz), + ), + $result + ); + + + } + + /** + * @depends testValues + */ + function testMonthlyByMonthDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=5;COUNT=9;BYMONTHDAY=1,31,-7'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(5, $it->interval); + $this->assertEquals(9, $it->count); + $this->assertEquals(array(1, 31, -7), $it->byMonthDay); + + $max = 14; + $result = array(); + foreach($it as $item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-01-01', $tz), + new DateTime('2011-01-25', $tz), + new DateTime('2011-01-31', $tz), + new DateTime('2011-06-01', $tz), + new DateTime('2011-06-24', $tz), + new DateTime('2011-11-01', $tz), + new DateTime('2011-11-24', $tz), + new DateTime('2012-04-01', $tz), + new DateTime('2012-04-24', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testMonthlyByDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;INTERVAL=2;COUNT=16;BYDAY=MO,-2TU,+1WE,3TH'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(2, $it->interval); + $this->assertEquals(16, $it->count); + $this->assertEquals(array('MO','-2TU','+1WE','3TH'), $it->byDay); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-01-03', $tz), + new DateTime('2011-01-05', $tz), + new DateTime('2011-01-10', $tz), + new DateTime('2011-01-17', $tz), + new DateTime('2011-01-18', $tz), + new DateTime('2011-01-20', $tz), + new DateTime('2011-01-24', $tz), + new DateTime('2011-01-31', $tz), + new DateTime('2011-03-02', $tz), + new DateTime('2011-03-07', $tz), + new DateTime('2011-03-14', $tz), + new DateTime('2011-03-17', $tz), + new DateTime('2011-03-21', $tz), + new DateTime('2011-03-22', $tz), + new DateTime('2011-03-28', $tz), + new DateTime('2011-05-02', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testMonthlyByDayByMonthDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO;BYMONTHDAY=1'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-08-01', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(1, $it->interval); + $this->assertEquals(10, $it->count); + $this->assertEquals(array('MO'), $it->byDay); + $this->assertEquals(array(1), $it->byMonthDay); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-08-01', $tz), + new DateTime('2012-10-01', $tz), + new DateTime('2013-04-01', $tz), + new DateTime('2013-07-01', $tz), + new DateTime('2014-09-01', $tz), + new DateTime('2014-12-01', $tz), + new DateTime('2015-06-01', $tz), + new DateTime('2016-02-01', $tz), + new DateTime('2016-08-01', $tz), + new DateTime('2017-05-01', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testMonthlyByDayBySetPos() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=MONTHLY;COUNT=10;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=1,-1'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-01-03', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('monthly', $it->frequency); + $this->assertEquals(1, $it->interval); + $this->assertEquals(10, $it->count); + $this->assertEquals(array('MO','TU','WE','TH','FR'), $it->byDay); + $this->assertEquals(array(1,-1), $it->bySetPos); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-01-03', $tz), + new DateTime('2011-01-31', $tz), + new DateTime('2011-02-01', $tz), + new DateTime('2011-02-28', $tz), + new DateTime('2011-03-01', $tz), + new DateTime('2011-03-31', $tz), + new DateTime('2011-04-01', $tz), + new DateTime('2011-04-29', $tz), + new DateTime('2011-05-02', $tz), + new DateTime('2011-05-31', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testYearly() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=10;INTERVAL=3'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-01-01', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('yearly', $it->frequency); + $this->assertEquals(3, $it->interval); + $this->assertEquals(10, $it->count); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-01-01', $tz), + new DateTime('2014-01-01', $tz), + new DateTime('2017-01-01', $tz), + new DateTime('2020-01-01', $tz), + new DateTime('2023-01-01', $tz), + new DateTime('2026-01-01', $tz), + new DateTime('2029-01-01', $tz), + new DateTime('2032-01-01', $tz), + new DateTime('2035-01-01', $tz), + new DateTime('2038-01-01', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testYearlyLeapYear() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=3'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2012-02-29', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('yearly', $it->frequency); + $this->assertEquals(3, $it->count); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2012-02-29', $tz), + new DateTime('2016-02-29', $tz), + new DateTime('2020-02-29', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testYearlyByMonth() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=4;BYMONTH=4,10'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-04-07', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('yearly', $it->frequency); + $this->assertEquals(4, $it->interval); + $this->assertEquals(8, $it->count); + $this->assertEquals(array(4,10), $it->byMonth); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-04-07', $tz), + new DateTime('2011-10-07', $tz), + new DateTime('2015-04-07', $tz), + new DateTime('2015-10-07', $tz), + new DateTime('2019-04-07', $tz), + new DateTime('2019-10-07', $tz), + new DateTime('2023-04-07', $tz), + new DateTime('2023-10-07', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testYearlyByMonthByDay() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('yearly', $it->frequency); + $this->assertEquals(5, $it->interval); + $this->assertEquals(8, $it->count); + $this->assertEquals(array(4,10), $it->byMonth); + $this->assertEquals(array('1MO','-1SU'), $it->byDay); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $tz = new DateTimeZone('UTC'); + + $this->assertEquals( + array( + new DateTime('2011-04-04', $tz), + new DateTime('2011-04-24', $tz), + new DateTime('2011-10-03', $tz), + new DateTime('2011-10-30', $tz), + new DateTime('2016-04-04', $tz), + new DateTime('2016-04-24', $tz), + new DateTime('2016-10-03', $tz), + new DateTime('2016-10-30', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testFastForward() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=8;INTERVAL=5;BYMONTH=4,10;BYDAY=1MO,-1SU'; + $dtStart = new Property\DateTime('DTSTART'); + $dtStart->setDateTime(new DateTime('2011-04-04', new DateTimeZone('UTC')),Property\DateTime::UTC); + + $ev->add($dtStart); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + // The idea is that we're fast-forwarding too far in the future, so + // there will be no results left. + $it->fastForward(new DateTime('2020-05-05', new DateTimeZone('UTC'))); + + $max = 20; + $result = array(); + while($item = $it->current()) { + + $result[] = $item; + $max--; + + if (!$max) break; + $it->next(); + + } + + $tz = new DateTimeZone('UTC'); + $this->assertEquals(array(), $result); + + } + + /** + * @depends testValues + */ + function testComplexExclusions() { + + $ev = new Component('VEVENT'); + $ev->UID = 'bla'; + $ev->RRULE = 'FREQ=YEARLY;COUNT=10'; + $dtStart = new Property\DateTime('DTSTART'); + + $tz = new DateTimeZone('Canada/Eastern'); + $dtStart->setDateTime(new DateTime('2011-01-01 13:50:20', $tz),Property\DateTime::LOCALTZ); + + $exDate1 = new Property\MultiDateTime('EXDATE'); + $exDate1->setDateTimes(array(new DateTime('2012-01-01 13:50:20', $tz), new DateTime('2014-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ); + $exDate2 = new Property\MultiDateTime('EXDATE'); + $exDate2->setDateTimes(array(new DateTime('2016-01-01 13:50:20', $tz)), Property\DateTime::LOCALTZ); + + $ev->add($dtStart); + $ev->add($exDate1); + $ev->add($exDate2); + + $vcal = Component::create('VCALENDAR'); + $vcal->add($ev); + + $it = new RecurrenceIterator($vcal,(string)$ev->uid); + + $this->assertEquals('yearly', $it->frequency); + $this->assertEquals(1, $it->interval); + $this->assertEquals(10, $it->count); + + $max = 20; + $result = array(); + foreach($it as $k=>$item) { + + $result[] = $item; + $max--; + + if (!$max) break; + + } + + $this->assertEquals( + array( + new DateTime('2011-01-01 13:50:20', $tz), + new DateTime('2013-01-01 13:50:20', $tz), + new DateTime('2015-01-01 13:50:20', $tz), + new DateTime('2017-01-01 13:50:20', $tz), + new DateTime('2018-01-01 13:50:20', $tz), + new DateTime('2019-01-01 13:50:20', $tz), + new DateTime('2020-01-01 13:50:20', $tz), + ), + $result + ); + + } + + /** + * @depends testValues + */ + function testOverridenEvent() { + + $vcal = Component::create('VCALENDAR'); + + $ev1 = Component::create('VEVENT'); + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=DAILY;COUNT=10'; + $ev1->DTSTART = '20120107T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it on 2pm instead. + $ev2 = Component::create('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120110T120000Z'; + $ev2->DTSTART = '20120110T140000Z'; + $ev2->SUMMARY = 'Event 2'; + + $vcal->add($ev2); + + // ev3 overrides an event, and puts it 2 days and 2 hours later + $ev3 = Component::create('VEVENT'); + $ev3->UID = 'overridden'; + $ev3->{'RECURRENCE-ID'} = '20120113T120000Z'; + $ev3->DTSTART = '20120115T140000Z'; + $ev3->SUMMARY = 'Event 3'; + + $vcal->add($ev3); + + $it = new RecurrenceIterator($vcal,'overridden'); + + $dates = array(); + $summaries = array(); + while($it->valid()) { + + $dates[] = $it->getDTStart(); + $summaries[] = (string)$it->getEventObject()->SUMMARY; + $it->next(); + + } + + $tz = new DateTimeZone('UTC'); + $this->assertEquals(array( + new DateTime('2012-01-07 12:00:00',$tz), + new DateTime('2012-01-08 12:00:00',$tz), + new DateTime('2012-01-09 12:00:00',$tz), + new DateTime('2012-01-10 14:00:00',$tz), + new DateTime('2012-01-11 12:00:00',$tz), + new DateTime('2012-01-12 12:00:00',$tz), + new DateTime('2012-01-14 12:00:00',$tz), + new DateTime('2012-01-15 12:00:00',$tz), + new DateTime('2012-01-15 14:00:00',$tz), + new DateTime('2012-01-16 12:00:00',$tz), + ), $dates); + + $this->assertEquals(array( + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'Event 2', + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'baseEvent', + 'Event 3', + 'baseEvent', + ), $summaries); + + } + + /** + * @depends testValues + */ + function testOverridenEvent2() { + + $vcal = Component::create('VCALENDAR'); + + $ev1 = Component::create('VEVENT'); + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; + $ev1->DTSTART = '20120112T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it 6 days earlier instead. + $ev2 = Component::create('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120119T120000Z'; + $ev2->DTSTART = '20120113T120000Z'; + $ev2->SUMMARY = 'Override!'; + + $vcal->add($ev2); + + $it = new RecurrenceIterator($vcal,'overridden'); + + $dates = array(); + $summaries = array(); + while($it->valid()) { + + $dates[] = $it->getDTStart(); + $summaries[] = (string)$it->getEventObject()->SUMMARY; + $it->next(); + + } + + $tz = new DateTimeZone('UTC'); + $this->assertEquals(array( + new DateTime('2012-01-12 12:00:00',$tz), + new DateTime('2012-01-13 12:00:00',$tz), + new DateTime('2012-01-26 12:00:00',$tz), + + ), $dates); + + $this->assertEquals(array( + 'baseEvent', + 'Override!', + 'baseEvent', + ), $summaries); + + } + + /** + * @depends testValues + */ + function testOverridenEventNoValuesExpected() { + + $vcal = Component::create('VCALENDAR'); + + $ev1 = Component::create('VEVENT'); + $ev1->UID = 'overridden'; + $ev1->RRULE = 'FREQ=WEEKLY;COUNT=3'; + $ev1->DTSTART = '20120124T120000Z'; + $ev1->SUMMARY = 'baseEvent'; + + $vcal->add($ev1); + + // ev2 overrides an event, and puts it 6 days earlier instead. + $ev2 = Component::create('VEVENT'); + $ev2->UID = 'overridden'; + $ev2->{'RECURRENCE-ID'} = '20120131T120000Z'; + $ev2->DTSTART = '20120125T120000Z'; + $ev2->SUMMARY = 'Override!'; + + $vcal->add($ev2); + + $it = new RecurrenceIterator($vcal,'overridden'); + + $dates = array(); + $summaries = array(); + + // The reported problem was specifically related to the VCALENDAR + // expansion. In this parcitular case, we had to forward to the 28th of + // january. + $it->fastForward(new DateTime('2012-01-28 23:00:00')); + + // We stop the loop when it hits the 6th of februari. Normally this + // iterator would hit 24, 25 (overriden from 31) and 7 feb but because + // we 'filter' from the 28th till the 6th, we should get 0 results. + while($it->valid() && $it->getDTSTart() < new DateTime('2012-02-06 23:00:00')) { + + $dates[] = $it->getDTStart(); + $summaries[] = (string)$it->getEventObject()->SUMMARY; + $it->next(); + + } + + $this->assertEquals(array(), $dates); + $this->assertEquals(array(), $summaries); + + } +} + diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php new file mode 100644 index 00000000..ebbfb04a --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/SlashRTest.php @@ -0,0 +1,19 @@ +assertEquals("TEST:abc\\ndef\r\n", $prop->serialize()); + + } + + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php new file mode 100644 index 00000000..43613350 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/ICalendarTest.php @@ -0,0 +1,283 @@ +version = VObject\Version::VERSION; + } + + function createStream($data) { + + $stream = fopen('php://memory','r+'); + fwrite($stream, $data); + rewind($stream); + return $stream; + + } + + function testICalendarImportValidEvent() { + + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + } + + function testICalendarImportEndOfData() { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + $this->assertNull($object=$objects->getNext()); + } + + /** + * @expectedException Sabre\VObject\ParseException + */ + function testICalendarImportInvalidEvent() { + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + } + + function testICalendarImportMultipleValidEvents() { + + $event[] = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + $i = 0; + while($object=$objects->getNext()) { + + $expected = <<version//EN +CALSCALE:GREGORIAN +$event[$i] +END:VCALENDAR + +EOT; + + $return .= $object->serialize(); + $expected = str_replace("\n", "\r\n", $expected); + $this->assertEquals($expected, $object->serialize()); + $i++; + } + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + } + + function testICalendarImportEventWithoutUID() { + + $data = <<version//EN +CALSCALE:GREGORIAN +BEGIN:VEVENT +END:VEVENT +END:VCALENDAR + +EOT; + $tempFile = $this->createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $expected = str_replace("\n", "\r\n", $data); + $this->assertEquals($expected, $object->serialize()); + $return .= $object->serialize(); + } + + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + } + + function testICalendarImportMultipleVTIMEZONESAndMultipleValidEvents() { + + $timezones = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + $i = 0; + while($object=$objects->getNext()) { + + $expected = <<version//EN +CALSCALE:GREGORIAN +$timezones +$event[$i] +END:VCALENDAR + +EOT; + $expected = str_replace("\n", "\r\n", $expected); + + $this->assertEquals($expected, $object->serialize()); + $return .= $object->serialize(); + $i++; + + } + + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + } + + function testICalendarImportWithOutVTIMEZONES() { + + $data = <<createStream($data); + + $objects = new ICalendar($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + $this->assertEquals(array(), VObject\Reader::read($return)->validate()); + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php new file mode 100644 index 00000000..b6b41925 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/Splitter/VCardTest.php @@ -0,0 +1,138 @@ +createStream($data); + + $objects = new VCard($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + VObject\Reader::read($return); + } + + function testVCardImportValidVCardsWithCategories() { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + VObject\Reader::read($return); + } + + function testVCardImportEndOfData() { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + $object=$objects->getNext(); + + $this->assertFalse($object=$objects->getNext()); + + + } + + /** + * @expectedException InvalidArgumentException + */ + function testVCardImportCheckInvalidArgumentException() { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + } + + function testVCardImportMultipleValidVCards() { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + VObject\Reader::read($return); + } + + function testVCardImportVCardWithoutUID() { + $data = <<createStream($data); + + $objects = new VCard($tempFile); + + $return = ""; + while($object=$objects->getNext()) { + $return .= $object->serialize(); + } + + VObject\Reader::read($return); + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php new file mode 100644 index 00000000..59a83d29 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/StringUtilTest.php @@ -0,0 +1,59 @@ +assertEquals(false, $string); + + } + + function testIsUTF8() { + + $string = StringUtil::isUTF8('I 💚 SabreDAV'); + + $this->assertEquals(true, $string); + + } + + function testUTF8ControlChar() { + + $string = StringUtil::isUTF8(chr('0x00')); + + $this->assertEquals(false, $string); + + } + + function testConvertToUTF8nonUTF8() { + + $string = StringUtil::convertToUTF8(chr('0xbf')); + + $this->assertEquals(utf8_encode(chr('0xbf')), $string); + + } + + function testConvertToUTF8IsUTF8() { + + $string = StringUtil::convertToUTF8('I 💚 SabreDAV'); + + $this->assertEquals('I 💚 SabreDAV', $string); + + } + + function testConvertToUTF8ControlChar() { + + $string = StringUtil::convertToUTF8(chr(0x00)); + + $this->assertEquals('', $string); + + } + + + + + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php new file mode 100644 index 00000000..b898e8d2 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/TimeZoneUtilTest.php @@ -0,0 +1,306 @@ +assertEquals($ex->getName(), $tz->getName()); + + } + + function testWetherMicrosoftIsStillInsane() { + + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + + } + + function testUnknownExchangeId() { + + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + + } + + function testWindowsTimeZone() { + + $tz = TimeZoneUtil::getTimeZone('Eastern Standard Time'); + $ex = new \DateTimeZone('America/New_York'); + $this->assertEquals($ex->getName(), $tz->getName()); + + } + + function testTimezoneOffset() { + + $tz = TimeZoneUtil::getTimeZone('GMT-0400', null, true); + + if (version_compare(PHP_VERSION, '5.5.10', '>=')) { + $ex = new \DateTimeZone('-04:00'); + } else { + $ex = new \DateTimeZone('Etc/GMT-4'); + } + $this->assertEquals($ex->getName(), $tz->getName()); + + } + + /** + * @expectedException InvalidArgumentException + */ + function testTimezoneFail() { + + $tz = TimeZoneUtil::getTimeZone('FooBar',null,true); + + } + + function testFallBack() { + + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + + } + + function testLjubljanaBug() { + + $vobj = <<assertEquals($ex->getName(), $tz->getName()); + + } + + function testWeirdSystemVLICs() { + +$vobj = <<=')) { + $ex = new \DateTimeZone('America/New_York'); + } else { + $ex = new \DateTimeZone('EST5EDT'); + } + $this->assertEquals($ex->getName(), $tz->getName()); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php b/sources/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php new file mode 100644 index 00000000..ae6855e8 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/VersionTest.php @@ -0,0 +1,17 @@ +assertEquals(-1, version_compare('0.9.0',$v)); + + $s = Version::STABILITY; + $this->assertTrue($s == 'alpha' || $s == 'beta' || $s =='stable'); + + } + +} diff --git a/sources/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf b/sources/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf new file mode 100644 index 00000000..5fb0fa29 --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/Sabre/VObject/issue153.vcf @@ -0,0 +1,352 @@ +BEGIN:VCARD +VERSION:3.0 +N:Benutzer;Test;;; +FN:Test Benutzer +PHOTO;BASE64: + /9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQA + AAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAABQKADAAQAAAABAAABQAAAAAD/2wBD + AAIBAQIBAQICAQICAgICAwUDAwMDAwYEBAMFBwYHBwcGBgYHCAsJBwgKCAYGCQ0JCgsLDAwMBwkN + Dg0MDgsMDAv/2wBDAQICAgMCAwUDAwULCAYICwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsLCwsL + CwsLCwsLCwsLCwsLCwsLCwsLCwv/wAARCAFAAUADASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAA + AAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKB + kaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZn + aGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT + 1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcI + CQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAV + YnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6 + goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk + 5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD8J7JbO8tYo1tIFCDLOVG5qfdaVZRwmSOFWzyA + F4H1rLt5WViMhdp6HgmtKK8O3B+4Rhx6fSgBI9FtjaNN5aErwRjilSys7lFAt41xyTtqc2yJCVlY + 7eqgGqv2jyLcebjZnGPWncdzT0+w0u5eQXtrGiBcIyoPmNMXwpb/AGMTSRRbH6YAyPwqK21GKdfL + BAVfu+1SQX4jnjKFsp03dPypCKN9oEaKSkC7R0bGKpnSlSPdHErZOORXV3Ouy337sCLB6kpx+FY0 + t+VfyrgcbuCB1oAfoMemrcImq2sZX+I7ATXS618PdK1DRlvvDEaMq5LoV2nisx4LVrUfu5BOePau + m8EQS6PY3HmFXjljKhTzjOf1oA4mz8OxvMrLbW5RD8wbByKg1LRrRriRYY408w/KAMba1pRaWt/H + a6a7CVm2u7N8lUPEujzaRekzSK6tgqVNAGNBZJauY5Yon92GTRJp0ROY0Un0A4q3c2odkaYOMjii + KL7NIDGcj1NDAZBplmmWv1xnoFHStfS/DFpewqYoYm3DutZ8lv8AapdyOqk8EVteEbSe3KBSrDrQ + BT8S+HbawiiWGCAPjsuMnPesqHS4JSFlSMP7DitbXbvfrkkM2eGw3p+FMfTh5X+hr8w7t3oAhOhW + u8MkMZUY3fL0Heo9UsrN5FFrbxKmMBgoG41fWFra0Acjpzg9aoXjtgRoo29vagCoun27kbY059qn + bwykskYjRArdTT7GEl2UqMr2q/JtVU27iR15NADdK8DC/wBPle2iicxNg5ALH6Umm6FZ/a3ttQt4 + g2Cqnb0PbJ+tamn3j6ZCW0nILfeBORWVfO4dhLw7fMW7560AZuqeHf7MuTFcRpv6qVGVx70q2Eci + QwyW0SsPvOqjJrUtb6S9tHQKGeMZYuM8VUs7gRxbrncy9mWgB1x4QtTHvsQWkHJVhhax3tkhugHh + UkfeAXIFdPZ3v2uxkQ9G4jI6/j+tYun3r2Fy6yxeb2Py5IoAqXenJ5xaGNNvXH/1qcLSGeBdkSg9 + CcdaswC3be0pfexOMnpn2qaS1KQkQASKoydvLCgDNi09RKTNCuO2BxVjSobc6gqXMERQHkleDUsc + u9VADbG6qOWAp11bLbptkjlCkZRsde9AFi5sbO3kKfZYTnkHaOlVbuO2F5thtYcADjaKXUpHj8ku + Co2VDFL5wLeg696YFwQ2z7Qtlb8HJO0c1Zsr7T7a9kL6XazZ4CmMFRWfHdkEgjGRjPpU9raP5LSP + j5h2pAWdQ0+z1KdG+y21qvcRqBn8qXSvC+iTu63ssqyE/IAuR+NQwSrGm1g+c8E9qiSQW9wPNYYP + OR2oAW68GNa28k3lwGNHwvzDJGfSqM9nHBgm3j59QMVdmma4zIjsUBHy5OKp6o8s2BJjZjjAoAro + /nysbgYY9zWmLPCR+WQQwyaz4k2F/Pbft/GtKxvUeFN+B2x+NAEptsWpZSdo9etZe8su2X7pPFdU + LeOazKqVwevNYt7pw5EA5HIxQBQA8tAIeGz1NWIJvJlhW5OQBzjrUMR/eN9pwoXjB4qQ3ERJeYcy + 9P8AZoA0jf8AmybVxsHAFS6jp63ixmwjIwOfrWfaou12GcDpmt/w5qJhXc6hh2GM0AZkHiRpblVl + G0RjGMdxXQ+H/E0Rm+bjdw1crqEHm3EksY4Y9PTmq0cskc42qUOfpmgDovHOhLBOZ9O+aEnIUdRW + QZft1sgum/1Ywua3fDfiFDL5WoEPEwxzzirPizwTFPZC60kYUjcAp4NAHPSq91EoRS3061DHD9nb + 94Mkfw020v57GbcCRt4IIqzNcedIH2jc3JyOaAIYrRZmJxtNdB4fkGn2hluBgBR+NZ2n2X9ozAQD + 5qvaxGbKIRXkuFU4C96AMDxBKZdQkuEUkStuUegpNM1eWScAkqpHTHNPlwbjMzExZ4Pal1PS/s6+ + dY/6vuwPSgC9G8c0A+1xEknrnpUVxaeXNm2dVUfjVazvEZAEkMrccZzV1YYyBIhJP8SZ6fhQBSmV + 4JfMVT+96UJdSQdcMO4A6fjVmTUoJiqTOMJ/q+elRyQs0TtaxF0PVhzmgCzpd55r7YI2HHPTmrV0 + sDTF7gnJXGO4OKyNKgn80NbFhjoBzWjqdg6SISPmIBOaAKVnI1leyhsMJOD7CqOqRtZqotjiFulW + rhsSMshKH1ogsZbmF475TKifdf0oApabevHIAhCYOdxp0t59luS0I+995uxqpdRyWsrqmXGeCR/K + rVlZfaogqv8AvD/CaAIY42kV3K5zzn1p9jNLp6u/A80YPNWWsJNPAVpC4JAZT2HfFWJoVmVVjhVk + HTPrQBPoi2wsoo4APtBHL+tP1mS5uVEFxgJGNqH15plp5WmyBriMRsowM8UybXTNdbrpd6A/KKAD + xbJAGs44FIPlnd9c/wD16ynt/LiDW2SR2qa5vP7RnMs6BNuQMd6jhkAUb2K8+tADYp0fhj8w6itC + yQ3CFYeAOoqi8Uew+UMuf4u9T2NwIW+UgMetO4FmS6RJ1ik6HqxHAqC+gimUiA8DvjrU0kcE8ieY + itu+8c0+bShaWxksSZoM4b0SkBTgha0cq33Cuc1SvrrLFV6jpWqbuGe1HnnDdAKy7i3WSY7OT2NN + AMulWSV8ZDNzxV7SlbaFjClx69Kpww7W3ct7jpUtnNJHd5UjZnt1NIDdt7h7NQ7qGfpt7VR1XVEh + dhEpP94/4VpafexTy7ZlbBGDVHxFbQh1j04HaOTkdKAM5ZVlYso3E+tVp4w8gx0Bqd7QxNu+6D6V + DIoVySxAx2NAFyNmli2pjYBz61paW3lWrFS3BwP8/hWJbTBFJy2D6HgfWtiTWPsqxraBHyOeBg0A + RSoLSTdIepzz0606exTWyQGMXljORTNT1B7+ECZR5fHzDqapfbHjbFkTsIwSTQA43ptyyS44Paun + 8N64Z7Bre4YlZBtU5+7XLTQbjwN4Pb+IfWn2lw9uyrIw2Z5HpQBv3GirHc7LxWVZOVI71FNp7WDg + QYlIIGD6VvaPdi+tljb5yeAzcn8DT9YtbPSpVhDM87jJ3Htjnn6UAUIrJreD7Si7MDoKhv8AUxqt + pGt5GqIOr9zRfLM8ZFgZGtex2nGe4zWKN8rsDhYx2JpJ3Atx+HxcRSzWcpcL/CRwaj0zW1sQy3cS + nsFPSoYJpbIl7dm8tT8wzV7+0hqEO1Y4lQ9cqMn9KoCp9kW7kaaxU+Yx+5j5etWrb/RGxfr5bkdu + lW7KFILpfspDbVyc1fjNnrLtHqOYWP8AFjGfxpAc/e6Ql/GzW4AfqBWfpupS6Xer5vPlHmMjg10V + 5pp0u4JhYNGvAYHrUn2WLWrVo41AvSMRZAC/8CPr1oAvafdWOuNG+lqDekY+zg8MPXPX/wDXWZrF + tcWNw0erKElB4Rf4R6c1BpqyaBdbrnEcwyAc4x06H0rQS9a9jUTgOXPzMwycexoAw7u1jYb3zkU3 + Srtgdk54PFamv2C2pDQbWjcfKCeSa56aJld23YA6ZOKFqBrXGjjULuOKxKuZOTn+H/OKwr/ztOvs + uCrg7RgVLYapPbXAEW4EkHJNdBNBH4gtgyhFmXuw60AVpbT7VpiPJ94jLetQWsDRSIYz8mec1c0+ + 1nexdrw7GjJXk/epsFtDPG0bOdw+b5SaAKWsXA+14Y71FQi5S4RvlAC8A0y5hHmHarhvQ9BVGSQx + sUXPHX3oAmDCJ8rzgHg96gQ+ZGWbg9vahNRG7EnalkkF6hEXyD270MCWF3aEhdue1OsmNnMAih/r + VaBgAUY8561PaubdnMxJXseuKANhIY5Assp2v12itZtAgubEi2nb5xuKYHWubstQaO6SVzujTqpP + X8K2rXWLRF8xZJPMfjAzgUAcxcNiaRSpUocc96sW+yNgZCMVF4lvJdRvTOYkj52jbgZ98D6VWmlY + 2qCUnJOKaVwCzviibANwYc8Utkdl7tbKhjxmpUspvm8tgn16ipigSEG4G4pxu9TSA27GeFbRlGGm + P3cdhUN8GEP2hV3JjafrWfpU/wBmuAcZLA4/Sr1trkarJHcRmSEZO3uTQBmrcbZCLoDZ2x1qOHSi + yebJIAPQipp4kmbzI1EQJ6GtCxsoHP8Ap91GB2yDQBlSWO+M/ZsBHHzZ71XkfMIWNgGU9vSt3U9N + t9m21uonz0Iz/hVCfRkjg82FhtHDGgCuZ8EMjDZjBzSZ8pAwU7XbGT0pWtEjjAZgV4PFOml2QKqk + OoOcU1qBNYRSrdkrhw3BIrah8KwXoV/m3PyVzyDWNp999kccgZq/ea7PFAGgZlJ6EUgN23thpdi4 + V1Eucr7ev9K53V/ER1a/MkuWdBtG04zioLrXJ5wDK2XAxmqVqmZ2YPtHJ/GgDsvC3i0ppr2d2ish + yFAHIz706bRLNdOPnErKw4y3NcvZ3pjA8o4kB61o3OpSX9nbx3QIkU/MwoAj/sGaPzFjlWSJjk46 + ioYYwqssjIHHAHpWm4ESN9nYDIFZV+I7uVI1wrY5b1oAtafcvb3W4MM9Nx6U/VZpNRys54ToU4zW + KXaDKrJuC8cVdtpi1gzs43HNAD9N195bdYtRIUR4wD1NX2KuA9uThuSQelcsZwzq9xyzfezV/SdX + e3m8pXJhkPKkUAdYZk8RywjVVJES7U2cE/WtA+HDHohuY3Uxg7RF/GeaPBlxaawMW6rHKnAU9SOO + lX/FFv8A2bpzTQk+cpAAz93nrQBx+r4c5CODEOA3Y+wrKu5V1C1GFKznkk9K6Wzv49fs8Xf7y7DY + MhGNgrmtX0s2t66WknnKvUp0/WgCnbrJFdot0NwJxkDFdDYp86oMjjIArJivxbR7LuMyEjKitS21 + MW8auuW44H93/PFAG15aXdr5Uv7uULkA/wCFc+Yvstw0at8+eoq/p+rm6vRJMNwIx9KranYySXSy + WEZZHOCw7UARXFyj5STAk7ntWVf2gALLyfUVoataLbfLO2SO/Ws2c+VwhLK3QDpQBmz2xAyCG56d + 6uWPlnCkFcjoTzUBkMc/3cZpwn8oZkDFs8HsKALN1apDIHOeaiLkRkMOtSXE6yxAsRUcdxldswIJ + HANMCuJW8xQgOP51oacWPPGAeRUUOIZQzDhecd6mbIcbPusM0gLmq6bHPohlhDeZuH4c1zzF1+Rs + HByDXTae0s0IhjjZg3GPWqOs+HpLCTbNGyb+cHrQBZitjPEzW/LL97vinw2v2m2aORec9AKXQbsw + ygBBiX72TWxfaS8kiGFQAwz8vWkncDlbqNraT5cjb/n+lMGckx8kjOa1tU2TxkPkMpxyKyrhJ4Wa + KIDbTAkgvIp7URzgBwe/BpZYrd4vmZWNZ81x5cgBXDdzVlIvtUOGIBHpQA2aEROpR8DsB2q3bvG9 + iySzEsTkLnrVMqViCZzt7nrT7GBVuQRnODQA6Q+Sx80A4HApEJB3BAR9K19EmhkvCJ0ZsKe3tUc8 + Mc1yy7cpn6YoAzoUiclnYYY8AHpUl8zRxqpPy9qtC2tULgSMAvQ460lzIl9b7YiDt4GaAKMMQlJ5 + z9Kj8gIW5yKnS3Crlzhh6d6k0mbyZT565Q5z60ANtrRpPmhzWhbwy7DJcDhhwMdKlt7aK+gb+z33 + yKdxVuMCqaz5cqGYfWgB6yu8rBB8o6Gs/UpjGQXBGPTvVmSfyImyepqrqjbIw3WgCDz1ib9yOTg4 + NbVlNBJYvlVBHt1rBaPzQWU4IHSn2FwRJslJxQA6e3M0O4oAzdB6VXR2iKGQENGOK0ms1eAkFjF/ + BjrVGaAo371smgC7pety2kwl06Vo5AOWXmuwm+Itv4g8Ota30aWlySAJQfmkP/1zXIeG4Y5SVBB3 + evamXGly2tydwG0nKkHpQBZ86fRbpBLI252y4PGRWhO8Ml1IbJhHn+BTnNU9O1oRwvDqqhB2lHJP + 4U6awb+z4JdKbzdh5ZurDHtQBat5LaRHiaOP7QejEZKD/Oauy+FI7W3Bsroyhxkq3QH8q5a7ujM8 + nWOQnBqTR9burCT98xdR60AbbaHc6ZG3ymJsZC/3hVnw/fNIXt7hygHzZp2oeIBqCxzqfmCgEe3+ + RVdrmLVAEtf3bxfOW/ve36UAV7+7DXMu5Q4/Os2e3eRWkiAGOijtWrPodxfQmeNVAPOPWsppJIpi + JxsKcY9aAMwRyTSbpflx68VOYvOXb97OKtXAiZdzkqT0AGc037BIIRLHjsR60AVprZrZwGj4qTY0 + xyRj3PUVMJDduFfqvFRzxJCzrCzEr60ALEu+YI53c4qeGB7lGCnBU4FUopTBLvfk1at9R2sAMjNA + GtaXsnhy2FzPHvC46jgnNQ33imTXrkz3oVFAwo9Kfrtq03hAzEfJ5gyc81hWM5hhKrhgT0NPcByS + P5g2uVI98Vp6X4uuNGlyzCQIQR0bI7/1rNQxqW+05J7Y4qK5ZYUP2ZCW9TSA7SR9M8V30X9nMFZw + WfcNi5qPWPDtjo0pE7O03U/Mf055rmtFmN9E0DEox+atPWbiW7lSO8Ja4jQbcDC4A9PXFADYtM0+ + 6nc3u7aOm3IP6Vnak9tYt/xL/M445zTIbieOdmWNsE46cip42EkyC4hYx469KAFsrT7XEJgFPOT6 + 1s+H9PD3XlzxnL/MDtqn9pghgb7GjL/eJORWqfEnmrA9oFRoxjJ5BoAp6NqDW2pzRXtuyIAw3FMf + rVS4iF08pydmeCDxWvqeuC+Ro9qglcMw71mwReXD5aAlFJPPU0AZ0cEsbkSZKH15FD2xJJiJVj6c + VfnzLGEXAA71PFpDPaebE6/KOh60AYVws8TBgrFe57CmHUG25RVJA7AVozzSLbNvX5T1AHNY/m/Z + nPlqwDetAEtvqzJNu3FZBwQBjI96vPqkd3mRtokH31UYx+VZqWruxaFl+frkZxT1tvs1ujJgEH5m + PR/pQAXl2S371XAHI+Wkaf7VD8hGR2arKySylRccQ98DmiS0jifdsdgeODQBQd9x3IBx1xTYlBm3 + En86sXUAwPswKg9QeaBErIEj6nrQC0NHRtUjt0K3AHzDABGcVW1fTzJL51jyOpz0NVooispebBI4 + wK2YFEthk8qR07igDAgJil+TKtnnHFaP2h5yI3ZsgdSfaqd2P3im3BGM9aktsjmRgCOaAJZrMwR7 + 3A5PT0pdMvZtOning+byzuVDyh/A8VHczSzDPy7RwOKgiuHEewjKeoFAzp7TUNM8XXEw8RhYNQmP + 7ny18uNeOM7cCtMfDiS8uY0tDEYghyynjPbn864htP8ANhLIehzWzovxDvtFsDB9+PI4I/rQI0r3 + wNc6DO0N2VaQqW2q24YxmqFhYRgE/vkkDfMGBBP4GrSeJ7tZd6SxvIfmK4yQP84p0XiyC71gS65G + 00zAKGX5Qv4UAbFpd28WnIsBLsDzmub1+AXt1LJEoQqfu4xu+lbWsWgs4/NsCXjPIbqK5+5kklmE + rDD54BFAGb5cjybCrAnnB6ipEvXil2sM4GMVpFY7m4UNmNyOWJ4qteaM0BISVZe+RQBFHC2/zISg + B69KlIVhIHA3HuR70lqotlBulY5P4Vcls44k3u6N5oyoHb60wM6O1SRir5LemOKv2vhuW4iLg7VA + 6k4FTR2ax4aaVIwR3HWqGua5PcQm1WRBH6jqaQFzWbE2nhzynuIi+8HaHyKweJSEQEN6jpVcKyOw + cMVznOeKmtZvOPDKuOKAJbi0JYFf4eue9IW8sncfvdqnlvVFyFyu09abI0bysMZx0oArC4eCTcgb + juK2dNvE1N1M0ohljGQzc5A7cfSs6aweWAk7kTuapQysIT9mOSvG49aAOkvzLMxk06QNuG1l7j3r + PlnnJAuGJij+nNQ6XqT7wEYqyn5v9utLULaW7j321uiEjLqMkKKAIotbghb/AI8hKGPIBHNXLG6t + 7uzk3RLbKG/iP+Fc+8f2d1eFztzyD2q5p2oCFWRoxOX52nPFAGgLyC2lyZFKdB70r69buxRJBHjr + nvWVdeXLE7xE8fwnoPpVKZUnQPkBhwRmgDq7a9tLyARWiiWYngL1qG4gurJ28+NowO2a5a3v3smD + aa5WUd1HNbC6zI0KSX13JO7D5lbHFAE4V7pi0b5x1GazdUtXSM7v4iPw5rQ0/XrcXX75FgUdxzuq + /qFrp+sWRe3uDkc4BFAHLRDY42ycd6uPOXiiV+RGPlWnXOg3IQvEmIB/Ft6/jUUEZmMcgydvzECg + C1G2+Ly3YAvyM9qY88kaFcmmp807uwPJ4FS3do+Fzn5ulAFVrjbgS8Z4yah2C03SMffNWZdPknVA + iluQOnHWmX9pILvyY13HHK46UAVre7LSyOCTmtjSiy7VijLeZ0IqO08OzPIUiTI74Ga6bRP7O01F + h1KYJOv3V4BoA4zU1lExMrkbOAvpVcSifhjgrzmtjxPp7pO7SggOcqfUViy25hG5fSgC8rrLAojb + d7d6SexlEgwpRfTNV7e5LFBbKAwPNWHeX7TguxI7GmBPBExhaNVIJ6egqOVknO1fkx1J61aj1gLC + UEKlk4LVWvozC67kCFxkD1pAQ24e3uDLC3z9CR3H/wCqrczJdOGiOxvYc5/CocMYhtUBj3xU8Qjk + XbKPIZOjqclvzoAu2HiO60xPKvd7wY/1fGBWnJo8WuW6y6XIPMYZEAzuH9KxISonAuzuRzgk9qtR + 79KmMuhTt5cRyxznFADLzS2tMw6pAY5OoDEZ/Sm20TQQ74YwVQckGtMatB4kUpqreVIRw5+8aqXF + jc6bAsbD9yThWz94UAOmmjvrRCMJjOQRVS0sD9pLyABM5Of6Vdtrdn+RUGcZqO6uRBG0MuFI79KA + MfV7r7ZqDI7kohAVT6U2eJNimJQOuTnpSXFussrMvBz1pJov3YUsR9O9ABblRncQ3bAqY2EUwIiA + Vqr20ojfYqZx3q9bSKAGcYJPIoAoq7OCEQBffrRDGEcleM8nNPjuGkhHmbB74ApvmxltsuTnuDQA + +SFEjDwu5buD0qpLL5vMg2kEdOlXECMAyZGOMMePyprQRI5N0rt3BXO326UAV4b0Wt0pC5HrXS2W + qq9zE7jcO+OhFc81kbg7iMqeAFHSpLa8eymaNOUIwD6UAavjPQYYybq1bBmXcF9O39Kw4iXdDKcE + DAxW3q7NdWELISdiYIz71kz6ZNZNHI0cjqQfujIFAEtzAtu/7vODzmqlyzNyAo9vWp7uWSWJd+AM + jjGGqOWCSWRVVW2+uKAKskpWU5TP0p8c+ExsPPNTmCVD+5U/QrzRJHJGymeOQc45HFAFczh497KR + jirWlEsAudvII9znitEeBp7yAPZvEVPJUsP5ZqCO3j0yYDUNwliI6dOPpQBt/wDCR3Wj6eHFujvI + do3DIX9KoHXoL6J11CJYZAONlaWueIYtY8Nwx6ZHu2MdxVeTXKG0eaXKRuCeuBQB0mn+HRe2Yeze + MqRkFmwfyra0rwsIrRmvZICcgDLVw7xXFuFd2uEQfeAJAxUkkjSxh4J7gjPAErf40Abvjq1i0y4S + KByCdrfL+FUI7SR4Wc+WzMOCW5qhf3Mt9cCV2ZiihRk5qpdTSBgRI+R2DnFAFw2k6AqJZMjuD1qn + cxzyyAkPuiP3ieT/AJzV+01R7a2RpMZPVmGQ1WVuTqLDCptcfMBwRQBEkst/YMCSTH8vJqtJaoYQ + JPv1o+ZDZKAo+UnBpmrCBpRNp4/0crgZ9f8A9dAzCdGgkOynxSus2xjkj+L1qW5/fxYj+8D+NRWz + R4fzCd2O9Ai0lzI6mPaMOcZqW4uI7rbtJ3IMc1XScKqncQT0olPlKWfBz6UATKjSDcmdoFWtPCyR + kzckHiqUV0623lKVIPzHHWp7Ic/vSRz0zQBcCqdyT4J7YqC3uZdKv1a2UupO7B6H2NMglMUsmcnd + 0Lc4q3BmaMBiDjr60AWJRBfyb9P2RueWJ6KfQVLHqMdtcEysxJXayN0x0yKyWihWQBdwTOSdxHNb + zWEF5ErXhX7QQAMNge2f0oAnhs4rq2kksHwirkg9SfauXnJnmL3AbL9jXSRWh0N28x1cEfMqtnA/ + Cs+70+O9/fWRIb+76fhSTuBimbyyyKDgnipLk7AML1pZbCWO7Hnjn26U6ZykRL+veqAryuvm/Jwf + Sk3mo2AyHyCT6Ux5pLU5Gwg88gGkBPNAILUO3KmooyjL8ueegzTvPMsRjG4qBwKrW1sxJZzsIPGa + AJbmfp5q7MZx71NZawEi8qZSyHg4NRGLzCPtB3eme1R3Nutocodyd8UAaVtqEUDlI8/N3PaqV2Ht + X2x4lIOSwHFSWkEFyo+cD1BpbmNbNdkh20AMh1UiJ1c9RzWj/wAJa1vYiK1RmRvvetY5gDENxgnp + UlhN5TiI4O4845oAmu51lXzFDGQ8jnpTra4uJkBAOQavXvhG8tIhPawvJAfmY9gKE1COwgIiAZiO + 3rQBV866T52Qsw6YrXguZNTs0WSJ8IPnHr9KwZNamNumZSpPU4pbPxBeRy/uJjtXqfWgDodMtnXK + QjYeo3VnalpiXjMzXMKS9O9VV1ydCXkmLY/SorWwTVJTmQEt81AHTeCY49Mik+0SJKmOg71W1bxH + HLdgaXaSRNnjdzWapGlBBG2ec4GKtQ6yZD5hjLMvbIzQBfutWC2ajV4ywwN2OM/Sql/JY2kKGzU/ + McnBBqlf3Lam5e8lKMv3Yz2FU4VjgzsGQ3WgDa0ya0u7kxzgqCCcn1q43hizkEjRkOoXcAOua5Ka + 6Mc3ygEVb0nW57ac/ZC4Xuo5zQBBeZjcwuMxRn5fUUmnySx6kv2cgg98deK1LjT31pTLpymSVuWi + Xqv17U2GzFgFBUCVOo7igCTT7cnTp/ty5ZnyCvGOKz2uwimOY7geQB0FWY7tzu8xiqk8A96qOvmy + MSowOc0AVpkkgk3uAiP39KkjtonYtnO4cKOP1q1Z3K+X5V2N6OeM8gfWiewaxiKhDsAyJB2oAk0u + 1juAwniYshwoB61FLZfaJDv/AHWexpulXRNwpjkP7s8nu1Wd4uC7zfezxQBTjxZTHzlMigbdy8Up + YXEv7nPvk1aNqbhDhgARnFZMCvbzuWZgc/nQBo2l6qs63AJA6VIsiG4DI4jXP8XeqcbrK5JH3xkH + 0pWhWVR52CF6UAa8kUd7H8rD5f1p5txHAfNPasWRCjgh8D0BrV0a+DgCdfM3DaB9RigCml/JFPyB + 159xV+C/wfNHAbtUN9orxO3k5dhycfw1XmT7JarIjb1k6U2BcuNSVGDSAPu6be1QTXcO0CVSwbPA + 7VRtpftEmxW2Mx6HvUv2V1J2jkdaQBFJB5jBVYemetRyW6SqTKCfTFNllCHBX5vWkLBPvk4NADTG + 0ePKB5qdLN5NjycqvNQIpZAFVj71LsaJQBuGaAH3aCVwycKODUMsZgJjxv8AXIzUs0DpHhmBycjm + gOd37wdRjNAFETeTcARAbSeTViApfrhjufHXNJNCsUu18Z61Xit3Q5JxQBdW0MYKyn5hSf2BPIjS + 24I29T6f5xUMMrs5HOF71ooVmtMyu3ynAAzQBqeCfG7aaPsmuYkiYFG3HseKq67YQW2rSNpLCS0l + GQ5GSh74xWZc2SyxK4OZl5x7d/0rV0K+j+xPFOu4Pwpx0oAo3OnFreM7AR9Kp/2eYpxtyCx6VoXd + g2nSlQzMh6UxJdjqSpKgfN6mgCOLSZGkKyYw/wCn+c1YltRodoWA+Y8Z+taPhWz866DQqxLdmq34 + x0ZbS23yY3NgkUAcZcSyrjcc7zw3YU62meOeTazdOhrZ07TYLkYvSFVfmqveQWkDj7CW9zg0AZs9 + 8wbO3L8ZpvmGRsyZQDsO9WLu0EwZojwMc1DJCrsA5we1AFmGVZLc7Y1bA6nvU1gIyNzgxtnoKr7I + NgHO8dx0pJ3AYG3UnHegDRS+NpL5lsxh3dQverj38OtL/pKCKSPhWU/f+tYEt98xMnC9qgludrrJ + GzFl7DvQBq6pYNGdzHGO3aqS33kEBhlSME0+01z7OcXGXRupJ5H0q5fafFqNuJLLnofmGDRsBmJe + DzMEZGevpW7o8sN/bzLqTBML8oB71k/2YYh83FQRqbdtr7sDv60AX7jSo4ZsiVo067hj9anuNHey + jVizMj8gkdaqQyi+UxjO7O0A96tXDz6rEFucp5HygUANGEQKjDJGaqzWbzgyn5QOPY1p2xZtOaGN + VMo5BPoKqxa1NHHtmij+Q4xkUAUraZFiYScMOgNMf76CIZHf2q5KRq8arEjK4OTsGaki0oKwAEhP + uDmgCohEsqq/O6rrMNMj3AEdgfQmn3tqUgEcaYz1JFMtLdn0wpFGxYHhjQBa026M0XM2WQ/NnHzU + 6Yw6tCPt6rbpH0CdvzrPtrZ45ceU4cHk9qtzW6XLOjqwY9+1AEa+HWun8zR28xU5LAZx+VLaGSV9 + jrkr145amvEY4hGkjKMg5XoPY/571vaHFDr95HHqDMkoU4C9G+uKAOevoo5iSBjBxVYwLdRkL1Xt + XSeK/CdzpkjRMqyJ95SjbsD3rmJbUwoeuGOCfSgC9eWc9rcbbdA0KHPmhcq39Ka8e9DkBS5zk1X0 + /wAR3dvEtuTm3AwVzW/D4w0xIEivbOaSTAVWBAH40AYMu6CZDkFcHcTz6UrtkYlwVHIwOtb91olr + qtuRZSL5h5EX8VY97pc1jKAqZ2jB/wA/nQBRJhubjE4YOOnNMC+S+DzmrMkIA819wPTbjmqwfzcM + 4w3vQA9mbYwgIz/ENvSm2t+6jZsYKeTkVYjn/eqwGAOp9aeW+2sdkgVf5UAQLKY5MHGferNv+6IM + XT07CmyaeZIS1vtmkUdQKbZ+akOZoyqMe45oAvRzjUJPLLgSds8/zqyPDzwETagy4U8YwARWMbcw + NuDDePenPrbXEfkTn5hwrdqAO709LPSbbzlZdvqD0Ncnr/iufX793uWQrGdmFGBjpmstdQeFRHKx + 2Nn5f73+f61E7iLCxDnrjvQBaubtNypAxyRzg0q263DMsJIzzyc1mwyDeSD82e9XIGUIrSyBNw+X + 2+tAD3tSpcFvufrVZbdL2XbnDdjnGKnhs2nkYtcIEJ6461HMiJIApBVe5HWgB8mmtpzDzSrrkZYU + 65mRGYoBgirEkCStiJlC7c5IqjLNsYhtu0d6AKkshbAZcAdc81Gdwb5SD6cVZjYy5WXBVu/pWppn + h63urfdLdxR47MDk0AYjnhehxntVq11OVANuTj8q2/8AhBZ7mwkm00CYKQBtHXrWe+kTWS7J4zE+ + OQ1ACQX/ANrkC3DD0wODV280KQwM0jxheueKdZWcCrvkjYYHUHvRe6jFLapHtLKeDjg0AVrDQ5xd + xuhIUEMHx8pH1roZtH+2W+dPIbHDMOcms+81YNoqWltlFKhQD1HNP0e5udHsHFkcyMRkDoaALUPh + aa1n8yUgqRgjPOO/eq+reDkvHzoQYIB85JzzW5HBLqWmCSWQJM3UEdB3/Sk0S3uNPmIkBlgJyXAw + o/Ci4EHh3QYfDsfm3mHklGGLdFqS91HSYpvMw0jjkhTx/KqXjLUg8hihYiMn746H6Vg+QYxuV9vH + 1oA3xrem38TNe28rqp+VUyD+gpbTU7O6ylvEYoEBPzjDAjp2HeuUk1aeyfNqMH+8BTrvVhqEAMuP + O7n1oA3X1Q3U0klp5S7OGHFZt7rj4DwxlTJ6riqMTiDZsHTn6/WpbfU5EP8AxMVMqdFIOMfWgCZb + lpEO/GDgn9K6bwZpktjcC7lUsAMYPvj/AArBi0lrpc2sqbZsHbjkV20SvDp8UUZBcDp60AY+ueIZ + dIu3Frh0lbD+YNxAPXBPSqLrpuunyNPBSSM7mZyQpJ/KtWQ2uqvNDcjypQjAFjnJx0rhNYhntbvy + 7jcucgIe9AEUMOy5ImYgg4xViVVa4UFSoToc9a6DxZoEdqv2rTsHzDlx/dFcujFpG27vlPGe9AEi + anPpV359o7b143jqo/yP0rWs/FSavF9l1JltlB3tOerd+axl3XGfMXC9896iu7UbtyYIxg0AdTc2 + Vrqe3+zZxIF4Uj+I1S1Hwpexu0kts8aL7Vg2t9JZ8REjJ+UD+Guh0TxjeaW3/EwAuFAxh260AY8y + ujfLkBOCOuabHcqgCxYAbrz0rsbSysfHdzks1rO33Y0AwTWd4h+D2r6M5mmt0ER5D85P1oAxLfWZ + LSYrbnAb5eKnudVnyELFkHOcCqUmjzRzBWyD9K6W38JtLo6TtkLzmgDHtryGZiZUDZqDU1Vl3wp8 + g+9jsf8AOKmGnw2cpE8jFR1I7VdGjRXMQa0kdoSPmHrQBn6bYnWz5NydjgZVgORWeztBK8ZBJQld + x6nFdZ4ZtoNI1QPI7O+OB7VX8faO9rdC7ESrC4BJHqaAOcgUTtuORiraW0M9yiXLAIeoPc+1RWar + u6Haxq7e6ekEZkBGzGVz1ptgVprUw3ku3iJDgDPUYFEzAwZRN2CDgUw3JEkezD7+xolvytwn2pVV + RkADv060gLVlMk4aLIDHp7+1Vbu1+yzgThiHOOelElyIZl8v5CDkVtxWkGtaYs0bMblCcr/KgDCe + 3LzsN20L2HepUQJnHI9KsX+gT29pHKCd79qWw0u4aPcwU4796AL+meIr2G1aDSbiWHOMhR1qxZXz + xXBl1n/iYBBlg/FR6VZW1nciS9mdJADgYGO1Q3pIOOu5hz60AO1vxLDqluP7Pt47eJSQ2KzvtiSg + eWuPpU89gsfzH5cc+1ZaSpbXRZT8tAGjjz237gNuPwrc0O48uUPOM4GBXORXC3HmJD1bB/QVZivZ + fLwp+71oA6fVfEiwXC+UBGjfKTj14qZbi7gtJWjkY2zx5C9s4rnbCRdZiaOUkFQTke3P9KbYa1c6 + XcBARLEWxhzwBU2AotqzH5Ls5YdFPOKmiu1KgxfvCOqHrXTL4EXxLbl9MO6bGRkYzXPal4TuNLu2 + ju/3csfUD9KoDO19yChhO3OcqO1VoZEUbHVckZL9x3q09s8a5uDkZxUDWX2i4OzgHvQBLCwkwyEF + c4z6VNDZm7utkROCfwqCzAhuGRhhV/WtR5okjjkQ7ST2oAlSRtMdUjHzR1p2OuOI2Ly4kHQViS3K + iYBMsW5zSNF9klEjPnPSgC1dzm4uVKSMZd4JP41oeJPD8+r6ZHLbwmW5H3yCMqvr/Os6xu/tDfvU + CqSOfWuj0yf7OxLO2CAG9x6UAZs6vcIqSiVw3GQMisR7RVvpFkGFU46e1dN4c1hYmCXm0quDIO9c + 54quVl16drdDHGzZX6UAV5bTzWIi4Ws6/DQEoQSpI5q9BfywxkS7WU9OOlMa3F8hG7bj5sn86AKc + ErggKVA96lFwLcYHX3NQPAHnYD5e26pAnluA/JoAu6JevFqsEqs4YN0HQV39p8aL+CJVnWKWOP5c + OAf6VwCzrbxAIMMefpT48zEFD9RQB6hZ+PNE8YqsfiJFt5GOC0abcH6ioPF+i2/hiGK50xmuLOQ4 + AjO9s/T8a8wlzLIdxKkHIwcc1s6R43vdJi2xurxsdriQbto9RnpQBal1C1urtzcIVjfqu3FRMNM8 + zbpplViehyAKnuU0/X4N+ixtFdR/67e2fN+g4xzWPcWzWFyDL8gP3Qw+9+NAGhqulSWzpJHt/wBn + Bzj2NejeHLG28f8Ahox6/HsmA2DHBGO9eTrrksUTKSOD0Par+n/EnVdMRVsZYgpHIK9u9KwEvjn4 + eTeF9UY2Jie3HI+bJFc6b6eMkt909j2rsrTxpYa7bGHWYpXlc8Ord/yrOu/B8gEjQul3Ao6RjLL9 + cGhaAcu0skr7mK8HtTjEAcMMk881Zm0l7JXxg7uQBywqqzysygDBPr1qgHSWqzANL6UunXjWBOxW + KsaZcggbu4HSlindrf5ANxNIDqblPteiWrESNC2fujJ7Vd0bRY7KLfZswWYZYSdT2/pWJ4Q8ST21 + 1b2krIYj8pBFdd4k024ht0nsdpjA4AHNAHO6npkSs2SwPase6ieJcSYdenB+atGbWykgF9G2cHvi + qGqMxiWW0GFyCSRnFAFeSN4yGiLE9we1QXYEhzMo+bnAqaC9YzbpSGY8CoL/ACwDQ80AV1mxdJwQ + q9h1qd71WHU/QdqgDO0gJAyevFE4WI8dW60AafhzUHt5v3ZAzxVzXNFku/38Odg9KwbK4ELA4z+N + ddourgQKJsMv92gCr4Y8Qy6VGUmkdLcDjn5/8a6vS5tM8SWTG3kkaZeP3xIyfxrmPEuk/ZXF9akG + CY/LHj7tZy38tvcxSwnYw7DpQB0viLwrIigwhcHqAeKxDpbmcgJtKjOfStXRPHgjlEeuAzZ6bf4e + lajX+navE4gZIyQcFmxQBxd5ZPG+9iuDxmqitHGR5oO09M+tdDqmjNsDl90YPBHSsJ4N7uH7dOOt + MByxj+EkE/d5qwYGkUNu+VetUgxVz6gVNAryx7Y84J5PpSAeZWjG8A/Lg1sabqn2hF8wnniqPkK6 + qk/z/TilaEWo/cgqKANPSbRba8zM6MXGDzVPxHYPPOzOOVPy471R03XmSRXlQEHv6VstqaakgJKh + h0X1oA5jBjYrP8uTkA9TQ0qoxLHqPyrQ1+z6TMu104x65/8A1ViSsVc5GdwoAseWbkDyQWC01QVv + S+5WGcbe9OguTFZqIjhxnPHWnWTCO6LyKjPnpQBDfs4n3sMc8Y7VPBKWT922498U7X0RCjRnJmAL + KP4aq2rtA/ycBu5HXFAGkYg0GT8rY5J5qIw5jyMORxU28zwAou5jxj1pnktAzCUlT1xQBHFP/Z8w + dpNsg6ccj8a6jQPFNjqdqbfxJbvPM/yxTE/LF9c1zsNsJ1U3EYIP8VPe1iicCORsnnHTBoAtat4Z + mS92Wn79WBK7aw0ia3uXW4jdChxkjvW/Z+KLjTZFd4hKwyAc44qy+nwazpxEOPNdvMdx1UdTQBzb + AbSNyqGPf+lWvDPiW58IXDtZzOIpRiVVON4qS/0ePcG04/aYV4Z8YwaoPGJrgq2AqnAPY0AdVdww + eJLX7XoxSKfbnyRwzn61zGooyMzsreYpwQTyn+P/ANap9NvX0S4DQtzu7dhW/rel2viWzWfRiPtC + L88a/wAfuaAOQEvyDepIOOamtbFJZWKzrH7Gpk02QRBLgYYHkDtSTaf5LBgM7u1AEVxbS2aiSNfm + xw3St7RfiTLFZi2vUe4VRt44xWJDczTzoLoFgvO096bMomlkaJfI5ztFAG7Jqdlrcm2WNYHA+82C + KidbiCAoVLWzfKoHOawo1dyGO4bQcc9frWppOvSwQLDcDzQSOvbmgCjcWBQsqDYwOTmo44BdAZfG + OeuK1NYdZLjzCdu8dAKzpLYQt+6OKAK88ciXREQ3AY5/Ckmt3dlMoznPSrMU2zJxgD2zSSRmX5kY + gdiO9AFWO3KSDgqMjrXQ6fYuUAjG3HO7rWRawNeSDLYKnHPeunVG0bR4ruTnc20g96AHxn7ZbNA7 + qzgcVzup2s2mzOl0CAT8jYzvrb1TxpZ3tgr6fBFFL/EUqpp+pJqpxeqJAPulucfSgDDfcjgxAqSP + mB60xXXlZFBPXpV2+tms5W2oTnpk1nht0uZCAfTFAG9oOvCJBb6jueJj8qj+Grer6XFCqvHMvHTA + zmuajlMUmWHznoKvQ6tLDEPtKeZnsT0oAkaBVLGX7x54qOG6NvkEEA/rV2dYLi08y3fMhH3e4rMR + mkDLOMkHg9KALcN7vXI4Iq9ZyG5jw7An1rFuWMWMAopxTzqMkIxZAuOpINAD7ZAcg9F6VqaXdRFg + pX5h92sPzRbfKQdvr61c0+4MjDyxsYHkkUAdA2lvdQ+ZcDIPGOuawNY0wWNywjwVbocdK2E1ubTF + +T5gw5yM1Lc2kOqaX5kXMxG4nPT8KAOSUSKu5VGM03aZmRo22k9Tird26Fgp+6hwcVAZfNmCnBVu + mKAJp7N71FDcuOI8d6pJlLlt+d44PoK0dTZLKCI2HmCZQCd33c+1R6iqXKpJBu34+bPQGmBNpzND + bgH7zHjPapLiXMhEvzMRwarQXG+ILcfMP7w7VZjdHj+QgMOmaQCRF7AsVBZO2am2G5t2kIAJ9O1V + 2vzM21l+UU9Cjj5M8eh4NAAIXjUeRl8/pUa6k1hGFtWyG6n+lWYX25Y8dsUs9t5tkVkK7Tz7+tAE + 9l4hAj8q/RUf+Db0P1qZ/DUWrTO0paK9cfLGg+Qn61zc0SeYc53DgVr+HNfk0u623LgwSDaxHLY9 + QaYFa80a60G58vU1VmbqF5AFWdC1k6PqaTW6qyEbSD+FdRJd2s8IikZJbO46MTmRB7nr2/WsrxD4 + QjtohLo+9kHXPb0pAd6uh6Lrekm6hkkQSRgNtQfK/p+dc1f/AAsuGUnSWSVScgynbisHQfGFxpki + RKw8tRyD0z/nNWPFHji/1lFihkCxKMAocUAaNt8NNSt3bzYrYsnT5xTLvwZYQTIuqzlLh/vqigqP + xrk/7QuIwRHcXG4jnMpP9ary3kzhvtUkrSH7p3E0AdXqPgvT1vI47K4kfcCcYAx0/wAar2ngu2uW + ZIJX3pnjHFc3DqUikfPIGHU5PFb2ka3PDe7dPZGGzGW7/wCc0AX7LRLSzcxb3eXrhhxVG78JeVcA + bvvcVfEgudqaoyrOrbiV9Pwpmo311pMnmWmySH3w1AGRrXh6TRfLMq8yfcHGPxqxZ6fpmnmNddml + jlk5+RQRx/8ArqO51ptT3vMwWU9iOF/CsOZHnkIkYu3YnmgDo7qPTtPszcWTu5LcAr1ycVl6p4hk + 1BRbsCEXkCqEGqz20wEWGEZGAeRxVy+vRqV2JpUVJiACQMAUAZ0+mvaNuuz88hwAOmaktbt7C4Ub + c8jvW5rGkp/YUEsRM0nLSf7PFYogSWEF/lJ6CgDWcjXyuMhwOAO9Y09hLbSyKy9+pqzpM9xo90Jr + co2OMMM5ropr2PxBYGK7VVXBbIXG4jnrQByUI8xSADs6HPWpPLIjGxssvr3pxQmcqx+VGwFHenJI + gOF5oAW0jZB5nQnnH6Usnzjrg0rW2/8AeISD1x2pWR5VySNo60AQBX2EzHIXpSQJ5kjOOFpLgrtI + iLFvWi2Y3CFYuoNAEt4myTBBQ46Gq6OyHKjGTzSyyyXUm+/cnHc0+PY42RtuDcDigDS03UzdQlHG + WHFSw3/2CX99lo+hA64NUorOeyG9FJA68VJFaLqNu0hkIlXkgelAF3VtEjvNMF1pKOctyPTFc/bw + tGVeMfMRzW54f119M8yJ2IjlGzk9B/k1p6f4fsmi2xXsUmeP88U7gYV5Et3aQlWCsox+NR2eUnWG + 7bdvrZ1TRY7FXjuQsatzHJ7VkyeXbxnz38xl6NmkBFfiXR3MDKQjHI9xUMV0ijMnNdBZWbeJbUcC + SZU+U454rFu/DF7byNJcW0qxqeeOtAE0EcbI+4nax49qnKNY7CCG46Vjw3DRHO1gtaNrqPnBRKu1 + R0Y80AXYDHPAzlPmzzTWG2Evn8KafMMWIsFfamKxcAyjAHbNAFSeRJpOBg0xrXykVjyp6VLqFv5b + AqwTI6dal02ZZ5VjuMNGentQBJZxXFtFuUZDcitDSPFrwOYrkFkfj6Vl30l7p87RpKRDn92eoIqG + 31gRxk3qMzqRnmgC/wCJtIa2uzLYfMjgEj2rNs70woyIMjPLHtW7Y3y38gkUnGBke1R6p4dS/mNx + obeZgfvIVH3Pf3oAz7W3EmGzgrSSRqszF13+4/hqOOLdGSrk5HO0d6WCUxYaUMYhw4HegCM6TLcy + Ztkd0wckd6jtZZbPiI+aqnlem2tTStXNvcbYZyiSA4QcdMf41Y8Taf8A2dZieGMR7sAkc7s8H+dA + GVJqTT3AKtjIxtrStNVy/kyLuUj1rAlhG4NtKqOc/wB+l+2SpP8AcKMn3s07gdJdeHPtLRS2zpCr + csD171laro72bGSFWZRwzHpQdUe8hTDEMg5xU0N7Pcx7GVpIf4lzSAwlk2yAoevUDpWpa2hvYeTg + 0mo2UM8w8lPs4HUDvRpsFz9oYW6NKB07U0BbjvptGhkgJDRMu01VLRyyIYQSgA3HstVdVMiSlZyx + bPKiksbyS1hdWUmKQ5K0gJpt8UgAw69iKn0/UyJdrdOmKIPIvW/cyLEqj7p4zUEUIEr+blHXJBx1 + oAk1O28q6VoSFVhk1GbZQ25TzUlvcfakIucKAcAnqaWK1cyFkQlB70AJvJdNq5I4+tBcbCnCjv71 + LIVcAowVhxj0qO2t9zkXHKt0bsKAIpbPIHlKWUjk06wgaNiqIBzViF/kKKwBHA9aguI5oX3REk9j + TQErWypGPOGc/pTLTy47gMFyob5fetB7EmcG3G6N8hSTjNWRpgsws/y7ouWB70gKd5dGSRcfKnIP + HFXrHSYL61e4kfyVVcYA61lC7OrxurAKxbIHtUtxfC2sTDA/A49KAEazRmkEw+TqG9as+H7YSTeX + bvu7ccYrIt7qRdobPLc59K6jw9pf2KUXcJBVjuI/z9aALF88MsJh1AiRoPl54Iqt5GmXUG3ABx1x + 0/WneMbGfTryO8VB5d2N6qfTJHP5VBoNtFqUb/b28uU/d2d6AJLPV4dGtP8AQyokHGKgu/Fwu9wl + PXgj0pmpaSmnOxmYEdu5rOht2knZ4FX3oAimiju3AtlAznrVWSAW7OC2HQ/d7VdNjLaMjurbSeMC + s+4WS41BjyEB5zQBcgnk2ARnJbqKZcydmZt3fFVxB+9DRkjHfNWLh/KKGTp/6FQBGLg3C5PzFeBT + LeT5yEzlB0p1zb7wGtzt9RTNhWVQOHPWgDc0iUajbPbTgM5GE9aydTtPKk8sKcDrk9adZX5+0FLc + FZM/K1dPpmgReJLR2nOyZDhQT1z60AYWgXYtrvy5cFXBXA9+OtGpLceH9YIsZ3BwGI4+YHsaNR09 + 9C1ERTFTMjBgE6YyO9S+IoDqHlag5++RGPfGKALelpb+IbtA+Ldk+ZkXofxqHxFpn2Vpv7OXdGOW + 56Vk3GpCBQB8pB429a0bHXN8kX2gKY1ILju1AGakfmFfJXLN0/z+VdZYQG503yda5xyPp/8AqqXw + 2LKJJvsqbjIdwDL936Viarq8u9nhA8sNg88/TFAGrdeFbeWBHscSL/AM9DWRqnhObyS7KUYdfetH + wkx1Gdnm3rECAB6Vu674psYbIRxeZuHBJHWgDzZw2nybQMluDVnT9T2PsJK56Ve1OS1vJ/OhOfXj + pWVdWctu/mJhgTxQBeYrOS0xAxTojJHKHspCQ3GPSqaXCTuqpnf+lTQIJ5XRXwy0AaN7YxzWzT3I + /fSHp6VnS2LI8Yt13kj5ucAU17me4hYbvkHXJ5qvJfDMYDNlevqeaAJTAVJGBuHPFSWuoMN32iNW + UgjOelVo5vNUvg8HGKVollOIG4HNAGhb6dHewhrVy8gPK4qaFTZZRssT1GKzLWd7C5zDlS1a9rq5 + vU2uFAIznuaAK93po2GSIEjqefu1C8QZApc+uBxWnbQpeyCG1OB1cnjmi5sUuTlxgpTQFBAYCWEQ + bjrmmsHvDypH0qYqYGPlk56DPSnWFuz3BN2MCkB0niGK10bw/ExCyMxwhVskH8K5O98SPfWixqPm + AxkjBNEkkz2iQSzgqn3U54rPm4RkY4YEfhQBd0gPBMGnwc8fSpvElpFBIGU5Y4Ix0qjcanIkKBG5 + 7VGzPdIHvF3P9aAHpGtymc4Ira0fU5YYUG7KA5P0rAEgjOFjfHtVqzndD8ilFkGKAPTri4h1fRrW + DVAojmjwjdwPY/XNcJK6aTfubdjhDgc9a19PnbUYLW2upsRJ8o61S8WeH1sryKJ2AeRSUb1oApTX + TXpaQMWJGcdal8PSf6UTcj5WOKz5YW0zgTKZG44Bq4THLpSqj7LhWJdsdfSgDo9e16OGFba0ji3p + wZCBzXOoYZp2N2u0Mecd6Zp12cIbkfIBzTbwRG53W4wp5oAbeWVmgY2ZYeuTVC4SWFAzjdGO5qws + HmK28jaTVi1vhaR+XfRGeJhtVR69jz6dfwpgZEcrPcAp92pl2IzMxLuRwamfSJZCXtnRhnLgcFR6 + VWc7J9mNpbtikAW9w0MheQj5ea3NG1Y2sPmWhCvjuf5Vk7UadY48RseW960rDS11C3b7EMzL3oAt + 6hpn9pZu4GzGq7djH5g2PzpPDsMV/Y3Fveg/uVZl+vNJYRy2KhXfcB972q5aRw310/2eZLbcuCWH + X8qaA4yTeT845B4qaEqjZlVtzflV+80qY31z/Z8T3ENqMs8ZAAGcd6zoZMncEwH6H0pAdDpusLZQ + 7Rjc3ApkFoZJHmY4iAPXpms8R7oh/Gc5HtXQaALbUtGMN6ApPHrzQA/TvEdsdOWD92rRk8gcmud8 + QXkl1cZzlfapr3QP7NujGjfKTlSKzr2Jmdgx/wBX096AIkn8ucBQQjdat/bWMLZKOOnOOKzdjL0P + BoiXe2Cu7vQBpxC0KAyK2488Hiql3LskbaDtbpjrV+3tlubYC2TExGBVe+tJNOAF4PmHNAFO0meG + R1bI9jU0iK23zcbsdagWYO+xOH7mrkMWYcNgkUAQwKGA4JC5pzyFmPlEADt61asYIgSJWA3dOKv6 + zosFpdxPaBGVlG445BwKAMwuWADAbqs6eI/3hl++Pu1cj8NFyrRncAdxb0psElpY37NMhljD4YKe + poAsWmm/aIjKknlsvUnoalhtHLcbiueucA1Uu9UMs8wt4SsOfkUnkCrOmXcotj9rkV0HSLnmgDoD + 4JSXSzPNNFJhdwCkZX9a5+K9gD+XPgDdjNTpez6ZZywwPskcZbk/KK5qZ2llPmvvYnrQATr8zE5D + N1zxRbou7951anhZNYuUVFw7dvSp59IltXdZ1IZKAGvpLNGfLAfufaqDCSKUEkgdMkVd07VWs7oG + XLL0x60+7ePUjyCpByMUAV3bBGxsk1ZikV4gAMkHOKpzW5SUmN849qjjnlil3KODxj0oA6KykW7t + yJW8pk4BFdxrGhwax4TS5JWWaEBEY9QDn/CvNrPUfJmBcZDHLV0s2vsfDMwt2ZYy4z7cGgDHv9NK + yjfD+8bgYFUNRtTps4S6HlkjIBPU/wCcVeN86xKZmJlyMc5p/ifU5L/RYVmto9wJUyZ5oAy01Dfb + qZV2xnoKbfX6NEv2ZcHHWmPLFJYQx2ZLTL1U1EIJA+2bAJ6Y5oAIboyDb0PU1c8xLkBJLna4Hy44 + 5x06VAbZbdcyZ3elNBXeCRjnOaAG2808N5syYmJ7fx+5q7tW5QCZQso/iqsULT7rXLr6k4xVi0dX + +9kmgBlxpbI7SxqZAoGWz0p+i3txZ3AezJAHXjrWlZ26mFyzEnPC+vStzTLO3vZ1M8Yjwp6Hr0oA + 5/xFqyrIggQKrLlsdc96xpQZ5wySbu2DVnVYQ9/MJCSitxVOQFW4G1aAOm+H3iGPSbie1upBDBqC + CKRugwOfwrI8VWsenazNHZtvs0fEb/3h6j171Elg02N65x6Gt200i18VwwwXcjQ3Fou2NQMiTvye + 3WgDn4riKEhkfKf3h6+9aFlGLeyS8eT5DIMoDnv3FXZ9I0iwhJFxJLMpwY2ACg1TvvISzMs77S5w + EUcUAW9dH9qW6y6ZKBgcgdawoNOu7iWMmNiWOMDtT4Jxb5e1bKuMEHsfWpNM1ZrG4WWFmct0BHSg + CprWivp0u193mMeR6VHa2jmQbVH0zV3WNRkv5mkn5YnjFRJGBMjRMScdKANvR7OO1u4pS+SGGV68 + d61/GnhSHUYReQyqsZXiPI64rK0S5hRNzfePXvWr5w1KIwwucAccUAefW1q8kqiT+WK0RpdzFFuE + bFT0bHBqxrFj/Z87LjDZ/Km2ctw7Kgk3KO3SgDPQPuHmqNynv2rRs7hrhjDIcDqD6VPeafDfWbbC + UnUjav8AeHfn8qsaL4bl2pLcYWJT85PYdzQBq6dfjRtKX7QnmC4JQH07f1rIl0SztbsSrcoQnJQH + qaseJ7mBVT7PIXtDwrYwQ3esOO4RrxvLZmjI+90P5UAXrm881T9lHOeAOareXPH+8BKOB19Kb9rF + pcq0ILDPc8mp7m+S6k3fdKj7vWgB8Gtj7Oq3AZ3fCs7DmorqxQTbl+oAqJJlu4gJMKwIxT3kNq+H + G5/7o7D1zTA7Pwpd6NBrk5vQwMv3Pl+7UnjAwwXX7tFe3l5UjBbHvXP3GnCOxhuo2IL1G+qPcFYX + cknoT/n2pbgVZtGFxZvNbH5VOBk+vt+FZ8lrPakrcqyHGcEYzWidWS3lCxAlVPUdDWxf6pa6nLH/ + AGlH99QoI4wTwKbA45pHEirjk1asbxYZCsoDYH1rV17wyumSKVbeGG4Y6gVk/wBn7UdgCpPc0gLw + aEwtLKMDtWhoNykVwHdd8JGCjDIrDkSW1g2zOhVhkVLo+puSVlKlccYoA6Dxf4PbSLRb21wto7DG + W7ntj61mpKdXtxaOQvlfMCSBuJrqLfWIfEvhg2muKzQoN4CnBJHT9cVyU5hEjNbB0CHABPNAGTPa + fZriQONjqcZ6flUtqqB1SRmMr/dJzWlDaLrEUh1Qbnx+628ZNZE1s9nfctxEccjpQBO9tLcy7Zjw + vfNQ31q9oee3A75qe2Yyzby5OKiutRMsjKQDg4FG4EVvEyfM5xnsD1q5bbzKHBAB9KrCJN4YMd3p + V+wt8szRZUCnYDXsWSGPz7jGI+SMVVuvErXKEWuRk9QMYqXVyLXTUyRmRcmsSC4EAO8D2pAXxbma + IMR8w7+tVdRtkUAT9ew71as7wsF2nFGsKodDOMzHo/YU0rgULe7j098qW545Gaki1FIbwzeYyzfw + EdvyqkyGSfaw+bvRcQLayqyEnAyaQHR6gi6/pXnBER0IGFHzN15rnmlXyTGRuQHByeQau2GrS20G + 9OhO3H1//VWhf6RprXbXmnrMtuYsOjNk78DkfiDQBi2rpHIVQjb1otHPnBZAMAdRVUQiW6Bgyis2 + Buq29q2nXJjn/eDsycUAOLCG8yg9zkcVCzeVIZY+cenekN0LqYRSHAHA9aLMCOTy5BlTyPegCxa6 + ltkL2+ORzxjFWbTXpLSV3Y84+XFVJvLilKjgVFMpAyBxQBq6prEF7bQSzA+ZJ97jpVRGjDbUJAB+ + U+tUywlJUdE6VteHLK3kuoDqQZ0zyAcYFAG3feVo+io90u2d13R/LyR35rm77VZNSmzC5SEj5hnH + 14/Otu+hv/FN3gTWywW4KRqQM4/OsUeFZp5miaVAc9R0oAaXWa0EUWCIjuA9PeqEMbCYM3G77oAr + bi8Gz2YDmeLc3ygev61X1CxnnuTE8TvPb9fKXigDMuIJFlBdtzHnAPSrEF0IwDCm5hw2VNRzxTWt + 0BeKVMnTIxj8KZ/ahtgY49uT7UAX7VH1K63oERVOTxiuu0ex0nS7L7chJkm+R1kwwyPQZrh4JJDw + zbVbk4/OrNpefLsnyyg5UUAf/9k= +END:VCARD diff --git a/sources/vendor/sabre/vobject/tests/bootstrap.php b/sources/vendor/sabre/vobject/tests/bootstrap.php new file mode 100644 index 00000000..3608abec --- /dev/null +++ b/sources/vendor/sabre/vobject/tests/bootstrap.php @@ -0,0 +1,15 @@ + + + Sabre/ + + + + + ../lib/ + + + diff --git a/sources/version.inc b/sources/version.inc new file mode 100644 index 00000000..a8c43590 --- /dev/null +++ b/sources/version.inc @@ -0,0 +1 @@ +2015-08-20.1130 diff --git a/sources/view/.htaccess b/sources/view/.htaccess new file mode 100644 index 00000000..7aa6c450 --- /dev/null +++ b/sources/view/.htaccess @@ -0,0 +1,9 @@ + + + Require all denied + + + Order deny,allow + Deny from all + + diff --git a/sources/view/ca/lostpass_eml.tpl b/sources/view/ca/lostpass_eml.tpl new file mode 100644 index 00000000..469c429d --- /dev/null +++ b/sources/view/ca/lostpass_eml.tpl @@ -0,0 +1,35 @@ + +Apreciat/da {{$username}}, + + S'ha rebut una sol·licitud en {{$sitename}} recentment per restablir +la teva contrasenya. Per confirmar aquesta sol·licitud, per favor seleccioni l'enllaç de +verificació sota o copia-ho i pega-ho en la barra d'adreces del teu navegador. + +Si NO has sol·licitat aquest canvi, per favor NO segueixis l'enllaç indicat i ignora +i/o elimina aquest missatge. + +La teva contrasenya no es canviarà tret que puguem verificar que ets la teva qui +va emetre aquesta sol·licitud. + +Segueix aquest enllaç per verificar la teva identitat: + +{{$reset_link}} + +A continuació rebràs un missatge amb la nova contrasenya. + +Després de accedir, podràs canviar la contrasenya del teu compte a la pàgina de +configuració. + +Les dades d'accés són els següents: + + +Lloc: {{$siteurl}} +Nom: {{$email}} + + + + +Salutacions, + L'administració de {{$sitename}} + + diff --git a/sources/view/ca/messages.po b/sources/view/ca/messages.po new file mode 100644 index 00000000..7684159c --- /dev/null +++ b/sources/view/ca/messages.po @@ -0,0 +1,9074 @@ +# Red Matrix Project +# Copyright (C) 2012-2014 the Red Matrix Project +# This file is distributed under the same license as the Red package. +# +# Translators: +# Espart , 2015 +# Rafael, 2013-2015 +# Rafael, 2015 +# Rafael, 2015 +msgid "" +msgstr "" +"Project-Id-Version: Redmatrix\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-07 00:03-0700\n" +"PO-Revision-Date: 2015-08-11 22:02+0000\n" +"Last-Translator: Rafael\n" +"Language-Team: Catalan (Spain) (http://www.transifex.com/Friendica/red-matrix/language/ca_ES/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: ca_ES\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../../include/dba/dba_driver.php:141 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "No s'ha trobat informació de DNS pel servidor de base de dades '%s'" + +#: ../../include/photo/photo_driver.php:687 ../../mod/profile_photo.php:143 +#: ../../mod/profile_photo.php:302 ../../mod/profile_photo.php:424 +#: ../../mod/photos.php:92 ../../mod/photos.php:637 +msgid "Profile Photos" +msgstr "Fotos del Perfil" + +#: ../../include/menu.php:107 ../../include/page_widgets.php:8 +#: ../../include/page_widgets.php:36 ../../include/RedDAV/RedBrowser.php:266 +#: ../../include/ItemObject.php:100 ../../include/apps.php:254 +#: ../../mod/webpages.php:181 ../../mod/thing.php:227 +#: ../../mod/connections.php:382 ../../mod/connections.php:395 +#: ../../mod/connections.php:414 ../../mod/blocks.php:153 +#: ../../mod/editpost.php:106 ../../mod/editlayout.php:133 +#: ../../mod/editwebpage.php:178 ../../mod/editblock.php:134 +#: ../../mod/menu.php:103 ../../mod/settings.php:650 ../../mod/layouts.php:183 +msgid "Edit" +msgstr "Edita" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Freqüentment" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Horariament" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Dos vegades al dia" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Diariament" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Setmanalment" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Mensualment" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:822 +#: ../../mod/admin.php:831 ../../mod/id.php:15 ../../mod/id.php:16 +#: ../../boot.php:1553 +msgid "Email" +msgstr "Correu electrónic" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "LinkedIn" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/IM" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "Creada una nova entrada" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +msgstr "comentat a l'entrada de %s" + +#: ../../include/Import/import_diaspora.php:17 +msgid "No username found in import file." +msgstr "No s'ha trobat nom d'usuari a l'arxiu d'importació." + +#: ../../include/Import/import_diaspora.php:42 ../../mod/import.php:156 +msgid "Unable to create a unique channel address. Import failed." +msgstr "No s'ha pogut importar el canal perquè l'adreça única de canal no s'ha pogut crear." + +#: ../../include/Import/import_diaspora.php:140 ../../mod/import.php:504 +msgid "Import completed." +msgstr "S'ha completat la importació." + +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "Un grup esborrat amb aquest nom fou reviscolat. Els permisos dels items existents poden aplicar-se a aquest grup i qualsevol membre futur. Si no es això el que vols, si et plau, crea un altre grup amb un nom diferent." + +#: ../../include/group.php:235 +msgid "Default privacy group for new contacts" +msgstr "Privacitat de grup predeterminada per a contactes nous" + +#: ../../include/group.php:254 ../../mod/admin.php:831 +msgid "All Channels" +msgstr "Tots els Canals" + +#: ../../include/group.php:276 +msgid "edit" +msgstr "edita" + +#: ../../include/group.php:298 +msgid "Collections" +msgstr "Col·leccions" + +#: ../../include/group.php:299 +msgid "Edit collection" +msgstr "Edita col·leccions" + +#: ../../include/group.php:300 +msgid "Add new collection" +msgstr "Afegeix una nova col·lecció" + +#: ../../include/group.php:301 +msgid "Channels not in any collection" +msgstr "Canals a cap col·lecció" + +#: ../../include/group.php:303 ../../include/widgets.php:275 +msgid "add" +msgstr "afegeix" + +#: ../../include/account.php:27 +msgid "Not a valid email address" +msgstr "Adreça de correu electrònic no vàlida" + +#: ../../include/account.php:29 +msgid "Your email domain is not among those allowed on this site" +msgstr "El seu domini de correu electrònic no es troba entre els permesos en aquest lloc" + +#: ../../include/account.php:35 +msgid "Your email address is already registered at this site." +msgstr "La teva adreça de correu electrònic ja esta registrada en aquest lloc" + +#: ../../include/account.php:67 +msgid "An invitation is required." +msgstr "Es requereix Invitació" + +#: ../../include/account.php:71 +msgid "Invitation could not be verified." +msgstr "L'invitació no ha pogut ser verificada" + +#: ../../include/account.php:121 +msgid "Please enter the required information." +msgstr "Entra la informació sol·licitada" + +#: ../../include/account.php:188 +msgid "Failed to store account information." +msgstr "Ha fallat guardar la informació del compte" + +#: ../../include/account.php:246 +#, php-format +msgid "Registration confirmation for %s" +msgstr "Registre confirmat per %s" + +#: ../../include/account.php:312 +#, php-format +msgid "Registration request at %s" +msgstr "Sol·licitud de registre a %s" + +#: ../../include/account.php:314 ../../include/account.php:341 +#: ../../include/account.php:401 ../../include/network.php:1632 +msgid "Administrator" +msgstr "Administrador" + +#: ../../include/account.php:336 +msgid "your registration password" +msgstr "la teva contrasenya registrada" + +#: ../../include/account.php:339 ../../include/account.php:399 +#, php-format +msgid "Registration details for %s" +msgstr "Detalls del registre per %s" + +#: ../../include/account.php:408 +msgid "Account approved." +msgstr "Compte aprovat." + +#: ../../include/account.php:447 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registre revocat per %s" + +#: ../../include/account.php:492 +msgid "Account verified. Please login." +msgstr "Compte verificat. Si us plau, inicia sessió." + +#: ../../include/account.php:705 ../../include/account.php:707 +msgid "Click here to upgrade." +msgstr "Feu clic aquí per actualitzar." + +#: ../../include/account.php:713 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Aquesta acció és superior als límits establerts pel seu pla de subscripció." + +#: ../../include/account.php:718 +msgid "This action is not available under your subscription plan." +msgstr "Aquesta acció no està disponible en el seu pla de subscripció." + +#: ../../include/datetime.php:48 +msgid "Miscellaneous" +msgstr "Miscelania" + +#: ../../include/datetime.php:132 +msgid "YYYY-MM-DD or MM-DD" +msgstr "YYYY-MM-DD o MM-DD" + +#: ../../include/datetime.php:235 ../../mod/events.php:649 +#: ../../mod/appman.php:91 ../../mod/appman.php:92 +msgid "Required" +msgstr "Requerit" + +#: ../../include/datetime.php:262 ../../boot.php:2354 +msgid "never" +msgstr "mai" + +#: ../../include/datetime.php:268 +msgid "less than a second ago" +msgstr "fa menys d'un segon" + +#: ../../include/datetime.php:271 +msgid "year" +msgstr "any" + +#: ../../include/datetime.php:271 +msgid "years" +msgstr "anys" + +#: ../../include/datetime.php:272 +msgid "month" +msgstr "mes" + +#: ../../include/datetime.php:272 +msgid "months" +msgstr "mesos" + +#: ../../include/datetime.php:273 +msgid "week" +msgstr "setmana" + +#: ../../include/datetime.php:273 +msgid "weeks" +msgstr "setmanes" + +#: ../../include/datetime.php:274 +msgid "day" +msgstr "dia" + +#: ../../include/datetime.php:274 +msgid "days" +msgstr "dies" + +#: ../../include/datetime.php:275 +msgid "hour" +msgstr "hora" + +#: ../../include/datetime.php:275 +msgid "hours" +msgstr "hores" + +#: ../../include/datetime.php:276 +msgid "minute" +msgstr "minut" + +#: ../../include/datetime.php:276 +msgid "minutes" +msgstr "minuts" + +#: ../../include/datetime.php:277 +msgid "second" +msgstr "segon" + +#: ../../include/datetime.php:277 +msgid "seconds" +msgstr "segons" + +#: ../../include/datetime.php:285 +#, php-format +msgctxt "e.g. 22 hours ago, 1 minute ago" +msgid "%1$d %2$s ago" +msgstr "Fa %1$d i %2$s" + +#: ../../include/datetime.php:519 +#, php-format +msgid "%1$s's birthday" +msgstr "Aniversari de %1$s" + +#: ../../include/datetime.php:520 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "Feliç Aniversari %1$s" + +#: ../../include/dir_fns.php:126 +msgid "Directory Options" +msgstr "Opcions de Directori" + +#: ../../include/dir_fns.php:128 +msgid "Safe Mode" +msgstr "Mode Segur" + +#: ../../include/dir_fns.php:128 ../../include/dir_fns.php:129 +#: ../../include/dir_fns.php:130 ../../mod/api.php:106 +#: ../../mod/photos.php:568 ../../mod/mitem.php:157 ../../mod/mitem.php:158 +#: ../../mod/mitem.php:229 ../../mod/mitem.php:230 ../../mod/menu.php:91 +#: ../../mod/menu.php:147 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:428 +#: ../../mod/settings.php:579 ../../mod/removeme.php:60 +#: ../../mod/connedit.php:635 ../../mod/connedit.php:663 +#: ../../view/theme/redbasic/php/config.php:104 +#: ../../view/theme/redbasic/php/config.php:129 ../../boot.php:1555 +msgid "No" +msgstr "No" + +#: ../../include/dir_fns.php:128 ../../include/dir_fns.php:129 +#: ../../include/dir_fns.php:130 ../../mod/api.php:105 +#: ../../mod/photos.php:568 ../../mod/mitem.php:157 ../../mod/mitem.php:158 +#: ../../mod/mitem.php:229 ../../mod/mitem.php:230 ../../mod/menu.php:91 +#: ../../mod/menu.php:147 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:430 +#: ../../mod/settings.php:579 ../../mod/removeme.php:60 +#: ../../view/theme/redbasic/php/config.php:104 +#: ../../view/theme/redbasic/php/config.php:129 ../../boot.php:1555 +msgid "Yes" +msgstr "Sí" + +#: ../../include/dir_fns.php:129 +msgid "Public Forums Only" +msgstr "Només Fòrums Públics" + +#: ../../include/dir_fns.php:130 +msgid "This Website Only" +msgstr "Només Aquest Lloc Web" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "Pàgina Nova" + +#: ../../include/page_widgets.php:39 ../../mod/webpages.php:187 +#: ../../mod/blocks.php:159 ../../mod/layouts.php:188 +msgid "View" +msgstr "Mostra" + +#: ../../include/page_widgets.php:40 ../../include/ItemObject.php:677 +#: ../../include/conversation.php:1155 ../../mod/webpages.php:188 +#: ../../mod/events.php:667 ../../mod/editpost.php:143 +#: ../../mod/photos.php:982 ../../mod/editwebpage.php:214 +#: ../../mod/editblock.php:170 +msgid "Preview" +msgstr "Avanç" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:189 +msgid "Actions" +msgstr "Accions" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:190 +msgid "Page Link" +msgstr "Enllaç a Pàgina" + +#: ../../include/page_widgets.php:43 +msgid "Title" +msgstr "Títol" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:192 +#: ../../mod/blocks.php:150 ../../mod/menu.php:105 ../../mod/layouts.php:181 +msgid "Created" +msgstr "Creat" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:193 +#: ../../mod/blocks.php:151 ../../mod/menu.php:106 ../../mod/layouts.php:182 +msgid "Edited" +msgstr "Editat" + +#: ../../include/api.php:1193 +msgid "Public Timeline" +msgstr "Línia de Temps Pública" + +#: ../../include/comanche.php:34 ../../mod/admin.php:390 +#: ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "Predeterminat" + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "Esborrar aquest item?" + +#: ../../include/js_strings.php:6 ../../include/ItemObject.php:667 +#: ../../mod/photos.php:980 ../../mod/photos.php:1098 +msgid "Comment" +msgstr "Comentari" + +#: ../../include/js_strings.php:7 ../../include/ItemObject.php:384 +msgid "[+] show all" +msgstr "[+] mostra tot" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "[-] mostra menys" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "[+] expandeix" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "[-] colapsa" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "Contrasenya massa curta" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "Les paraules de pas no coincideixen" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:40 +msgid "everybody" +msgstr "tothom" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "Contrasenya Secreta" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "Pista per la Contrasenya" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "Avis: Els permisos han canviat però encara no han estat enviats." + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "tanca tot" + +#: ../../include/js_strings.php:18 +msgid "Nothing new here" +msgstr "Res de nou per aquí" + +#: ../../include/js_strings.php:19 +msgid "Rate This Channel (this is public)" +msgstr "Valora Aquest Canal (això es farà públic)" + +#: ../../include/js_strings.php:20 ../../mod/rate.php:156 +#: ../../mod/connedit.php:671 +msgid "Rating" +msgstr "Valora" + +#: ../../include/js_strings.php:21 +msgid "Describe (optional)" +msgstr "Descriu (opcional)" + +#: ../../include/js_strings.php:22 ../../include/ItemObject.php:668 +#: ../../mod/xchan.php:11 ../../mod/connect.php:93 ../../mod/thing.php:275 +#: ../../mod/thing.php:318 ../../mod/events.php:494 ../../mod/events.php:670 +#: ../../mod/group.php:81 ../../mod/photos.php:577 ../../mod/photos.php:654 +#: ../../mod/photos.php:941 ../../mod/photos.php:981 ../../mod/photos.php:1099 +#: ../../mod/pdledit.php:58 ../../mod/import.php:534 ../../mod/chat.php:177 +#: ../../mod/chat.php:211 ../../mod/mitem.php:232 ../../mod/rate.php:167 +#: ../../mod/invite.php:142 ../../mod/locs.php:105 ../../mod/sources.php:104 +#: ../../mod/sources.php:138 ../../mod/filestorage.php:156 +#: ../../mod/fsuggest.php:108 ../../mod/poke.php:166 +#: ../../mod/profiles.php:667 ../../mod/setup.php:327 ../../mod/setup.php:367 +#: ../../mod/admin.php:453 ../../mod/admin.php:819 ../../mod/admin.php:986 +#: ../../mod/admin.php:1118 ../../mod/admin.php:1312 ../../mod/admin.php:1397 +#: ../../mod/settings.php:588 ../../mod/settings.php:692 +#: ../../mod/settings.php:718 ../../mod/settings.php:746 +#: ../../mod/settings.php:769 ../../mod/settings.php:854 +#: ../../mod/settings.php:1050 ../../mod/mood.php:134 +#: ../../mod/connedit.php:692 ../../mod/mail.php:355 ../../mod/appman.php:99 +#: ../../mod/pconfig.php:108 ../../mod/poll.php:68 +#: ../../mod/bulksetclose.php:24 ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Submit" +msgstr "Presenta" + +#: ../../include/js_strings.php:23 +msgid "Please enter a link URL" +msgstr "Si us plau, entra l'enllaç URL" + +#: ../../include/js_strings.php:24 +msgid "Unsaved changes. Are you sure you wish to leave this page?" +msgstr "Hi ha canvis sense desar, estàs segur que vols abandonar la pàgina?" + +#: ../../include/js_strings.php:26 +msgid "timeago.prefixAgo" +msgstr "horapasada.prefixFa" + +#: ../../include/js_strings.php:27 +msgid "timeago.prefixFromNow" +msgstr "timeago.prefixFromNow" + +#: ../../include/js_strings.php:28 +msgid "ago" +msgstr "fa" + +#: ../../include/js_strings.php:29 +msgid "from now" +msgstr "des d'ara" + +#: ../../include/js_strings.php:30 +msgid "less than a minute" +msgstr "menys d'un minut" + +#: ../../include/js_strings.php:31 +msgid "about a minute" +msgstr "prop d'un minut" + +#: ../../include/js_strings.php:32 +#, php-format +msgid "%d minutes" +msgstr "%d minuts" + +#: ../../include/js_strings.php:33 +msgid "about an hour" +msgstr "prop d'una hora" + +#: ../../include/js_strings.php:34 +#, php-format +msgid "about %d hours" +msgstr "al voltant de %d hores" + +#: ../../include/js_strings.php:35 +msgid "a day" +msgstr "un dia" + +#: ../../include/js_strings.php:36 +#, php-format +msgid "%d days" +msgstr "%d dies" + +#: ../../include/js_strings.php:37 +msgid "about a month" +msgstr "prop d'un mes" + +#: ../../include/js_strings.php:38 +#, php-format +msgid "%d months" +msgstr "%d mesos" + +#: ../../include/js_strings.php:39 +msgid "about a year" +msgstr "prop d'un any" + +#: ../../include/js_strings.php:40 +#, php-format +msgid "%d years" +msgstr "%d anys" + +#: ../../include/js_strings.php:41 +msgid " " +msgstr " " + +#: ../../include/js_strings.php:42 +msgid "timeago.numbers" +msgstr "timeago.numbers" + +#: ../../include/text.php:395 +msgid "prev" +msgstr "prev" + +#: ../../include/text.php:397 +msgid "first" +msgstr "primer" + +#: ../../include/text.php:426 +msgid "last" +msgstr "últim" + +#: ../../include/text.php:429 +msgid "next" +msgstr "pròxim" + +#: ../../include/text.php:439 +msgid "older" +msgstr "el més antic" + +#: ../../include/text.php:441 +msgid "newer" +msgstr "El més nou" + +#: ../../include/text.php:834 +msgid "No connections" +msgstr "Sense Connexions" + +#: ../../include/text.php:848 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "%d Connexió" +msgstr[1] "%d Connexions" + +#: ../../include/text.php:861 ../../mod/viewconnections.php:104 +msgid "View Connections" +msgstr "Veure Connexions" + +#: ../../include/text.php:918 ../../include/text.php:930 +#: ../../include/nav.php:165 ../../include/apps.php:147 +#: ../../mod/search.php:38 +msgid "Search" +msgstr "Cerca" + +#: ../../include/text.php:919 ../../include/text.php:931 +#: ../../include/widgets.php:192 ../../mod/rbmark.php:28 +#: ../../mod/rbmark.php:98 ../../mod/filer.php:50 ../../mod/admin.php:1457 +#: ../../mod/admin.php:1477 +msgid "Save" +msgstr "Guardar" + +#: ../../include/text.php:994 +msgid "poke" +msgstr "emprenya" + +#: ../../include/text.php:994 ../../include/conversation.php:243 +msgid "poked" +msgstr "emprenyat" + +#: ../../include/text.php:995 +msgid "ping" +msgstr "coloca" + +#: ../../include/text.php:995 +msgid "pinged" +msgstr "colocat" + +#: ../../include/text.php:996 +msgid "prod" +msgstr "picar" + +#: ../../include/text.php:996 +msgid "prodded" +msgstr "picat" + +#: ../../include/text.php:997 +msgid "slap" +msgstr "bufetada" + +#: ../../include/text.php:997 +msgid "slapped" +msgstr "bufetejat" + +#: ../../include/text.php:998 +msgid "finger" +msgstr "senyal" + +#: ../../include/text.php:998 +msgid "fingered" +msgstr "senyalat" + +#: ../../include/text.php:999 +msgid "rebuff" +msgstr "menyspreu" + +#: ../../include/text.php:999 +msgid "rebuffed" +msgstr "menyspreuat" + +#: ../../include/text.php:1009 +msgid "happy" +msgstr "feliç" + +#: ../../include/text.php:1010 +msgid "sad" +msgstr "trist" + +#: ../../include/text.php:1011 +msgid "mellow" +msgstr "melós" + +#: ../../include/text.php:1012 +msgid "tired" +msgstr "cansat" + +#: ../../include/text.php:1013 +msgid "perky" +msgstr "turgent" + +#: ../../include/text.php:1014 +msgid "angry" +msgstr "enfadat" + +#: ../../include/text.php:1015 +msgid "stupified" +msgstr "encantat" + +#: ../../include/text.php:1016 +msgid "puzzled" +msgstr "perplexe" + +#: ../../include/text.php:1017 +msgid "interested" +msgstr "Interessat" + +#: ../../include/text.php:1018 +msgid "bitter" +msgstr "amargat" + +#: ../../include/text.php:1019 +msgid "cheerful" +msgstr "feliç" + +#: ../../include/text.php:1020 +msgid "alive" +msgstr "viu" + +#: ../../include/text.php:1021 +msgid "annoyed" +msgstr "molest" + +#: ../../include/text.php:1022 +msgid "anxious" +msgstr "ansiós" + +#: ../../include/text.php:1023 +msgid "cranky" +msgstr "malagaitós" + +#: ../../include/text.php:1024 +msgid "disturbed" +msgstr "transtornat" + +#: ../../include/text.php:1025 +msgid "frustrated" +msgstr "frustrat" + +#: ../../include/text.php:1026 +msgid "depressed" +msgstr "deprimit" + +#: ../../include/text.php:1027 +msgid "motivated" +msgstr "motivat" + +#: ../../include/text.php:1028 +msgid "relaxed" +msgstr "relaxat" + +#: ../../include/text.php:1029 +msgid "surprised" +msgstr "sorprès" + +#: ../../include/text.php:1201 +msgid "Monday" +msgstr "Dilluns" + +#: ../../include/text.php:1201 +msgid "Tuesday" +msgstr "Dimarts" + +#: ../../include/text.php:1201 +msgid "Wednesday" +msgstr "Dimecres" + +#: ../../include/text.php:1201 +msgid "Thursday" +msgstr "Dijous" + +#: ../../include/text.php:1201 +msgid "Friday" +msgstr "Divendres" + +#: ../../include/text.php:1201 +msgid "Saturday" +msgstr "Dissabte" + +#: ../../include/text.php:1201 +msgid "Sunday" +msgstr "Diumenge" + +#: ../../include/text.php:1205 +msgid "January" +msgstr "Gener" + +#: ../../include/text.php:1205 +msgid "February" +msgstr "Febrer" + +#: ../../include/text.php:1205 +msgid "March" +msgstr "Març" + +#: ../../include/text.php:1205 +msgid "April" +msgstr "Abril" + +#: ../../include/text.php:1205 +msgid "May" +msgstr "Maig" + +#: ../../include/text.php:1205 +msgid "June" +msgstr "Juny" + +#: ../../include/text.php:1205 +msgid "July" +msgstr "Juliol" + +#: ../../include/text.php:1205 +msgid "August" +msgstr "Agost" + +#: ../../include/text.php:1205 +msgid "September" +msgstr "Setembre" + +#: ../../include/text.php:1205 +msgid "October" +msgstr "Octubre" + +#: ../../include/text.php:1205 +msgid "November" +msgstr "Novembre" + +#: ../../include/text.php:1205 +msgid "December" +msgstr "Desembre" + +#: ../../include/text.php:1310 +msgid "unknown.???" +msgstr "desconegut.???" + +#: ../../include/text.php:1311 +msgid "bytes" +msgstr "bytes" + +#: ../../include/text.php:1347 +msgid "remove category" +msgstr "elimina categoria" + +#: ../../include/text.php:1422 +msgid "remove from file" +msgstr "elimina del arxiu" + +#: ../../include/text.php:1498 ../../include/text.php:1509 +msgid "Click to open/close" +msgstr "Clic per obrir/tancar" + +#: ../../include/text.php:1665 ../../mod/events.php:457 +msgid "Link to Source" +msgstr "Enllaç a la Font" + +#: ../../include/text.php:1686 ../../include/text.php:1757 +msgid "default" +msgstr "per defecte" + +#: ../../include/text.php:1694 +msgid "Page layout" +msgstr "Format de la pàgina" + +#: ../../include/text.php:1694 +msgid "You can create your own with the layouts tool" +msgstr "Pots crear el teu propi amb l'editor de format de pàgina." + +#: ../../include/text.php:1735 +msgid "Page content type" +msgstr "Tipus de contingut de la pàgina" + +#: ../../include/text.php:1769 +msgid "Select an alternate language" +msgstr "Tria un idioma alternatiu" + +#: ../../include/text.php:1888 ../../include/diaspora.php:2119 +#: ../../include/conversation.php:120 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +#: ../../mod/tagger.php:43 +msgid "photo" +msgstr "foto" + +#: ../../include/text.php:1891 ../../include/conversation.php:123 +#: ../../mod/like.php:348 ../../mod/tagger.php:47 +msgid "event" +msgstr "succés" + +#: ../../include/text.php:1894 ../../include/diaspora.php:2119 +#: ../../include/conversation.php:148 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +msgid "status" +msgstr "estat" + +#: ../../include/text.php:1896 ../../include/conversation.php:150 +#: ../../mod/tagger.php:53 +msgid "comment" +msgstr "comentari" + +#: ../../include/text.php:1901 +msgid "activity" +msgstr "activitat" + +#: ../../include/text.php:2196 +msgid "Design Tools" +msgstr "Eines de disseny" + +#: ../../include/text.php:2199 ../../mod/blocks.php:147 +msgid "Blocks" +msgstr "Bloc" + +#: ../../include/text.php:2200 ../../mod/menu.php:98 +msgid "Menus" +msgstr "Menús" + +#: ../../include/text.php:2201 ../../mod/layouts.php:174 +msgid "Layouts" +msgstr "Format Gràfic" + +#: ../../include/text.php:2202 +msgid "Pages" +msgstr "Pàgines" + +#: ../../include/text.php:2553 ../../include/RedDAV/RedBrowser.php:131 +msgid "Collection" +msgstr "Col·lecció" + +#: ../../include/RedDAV/RedBrowser.php:107 +#: ../../include/RedDAV/RedBrowser.php:265 +msgid "parent" +msgstr "pare" + +#: ../../include/RedDAV/RedBrowser.php:134 +msgid "Principal" +msgstr "Principal" + +#: ../../include/RedDAV/RedBrowser.php:137 +msgid "Addressbook" +msgstr "Llista d'Adreçes" + +#: ../../include/RedDAV/RedBrowser.php:140 +msgid "Calendar" +msgstr "Calendari" + +#: ../../include/RedDAV/RedBrowser.php:143 +msgid "Schedule Inbox" +msgstr "Programació de la bústia d'entrada" + +#: ../../include/RedDAV/RedBrowser.php:146 +msgid "Schedule Outbox" +msgstr "Programació de la bústia de sortida" + +#: ../../include/RedDAV/RedBrowser.php:164 ../../include/conversation.php:1019 +#: ../../include/apps.php:336 ../../include/apps.php:387 +#: ../../mod/photos.php:693 ../../mod/photos.php:1131 +msgid "Unknown" +msgstr "Desconegut" + +#: ../../include/RedDAV/RedBrowser.php:227 +#, php-format +msgid "%1$s used" +msgstr "%1$s emprat" + +#: ../../include/RedDAV/RedBrowser.php:232 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "%1$s emprat de %2$s (%3$s%)" + +#: ../../include/RedDAV/RedBrowser.php:251 ../../include/nav.php:98 +#: ../../include/conversation.php:1609 ../../include/apps.php:135 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "Arxius" + +#: ../../include/RedDAV/RedBrowser.php:253 +msgid "Total" +msgstr "Total" + +#: ../../include/RedDAV/RedBrowser.php:255 +msgid "Shared" +msgstr "Compartit" + +#: ../../include/RedDAV/RedBrowser.php:256 +#: ../../include/RedDAV/RedBrowser.php:303 ../../mod/webpages.php:180 +#: ../../mod/blocks.php:152 ../../mod/menu.php:109 +#: ../../mod/new_channel.php:121 ../../mod/layouts.php:175 +msgid "Create" +msgstr "Creada" + +#: ../../include/RedDAV/RedBrowser.php:257 +#: ../../include/RedDAV/RedBrowser.php:305 ../../mod/profile_photo.php:362 +#: ../../mod/photos.php:718 ../../mod/photos.php:1248 +msgid "Upload" +msgstr "Pujar" + +#: ../../include/RedDAV/RedBrowser.php:261 ../../mod/admin.php:994 +#: ../../mod/settings.php:590 ../../mod/settings.php:616 +#: ../../mod/sharedwithme.php:95 +msgid "Name" +msgstr "Nom" + +#: ../../include/RedDAV/RedBrowser.php:262 +msgid "Type" +msgstr "Tipus" + +#: ../../include/RedDAV/RedBrowser.php:263 ../../mod/sharedwithme.php:97 +msgid "Size" +msgstr "Mida" + +#: ../../include/RedDAV/RedBrowser.php:264 ../../mod/sharedwithme.php:98 +msgid "Last Modified" +msgstr "Últim Modificat" + +#: ../../include/RedDAV/RedBrowser.php:267 ../../include/ItemObject.php:120 +#: ../../include/conversation.php:660 ../../include/apps.php:255 +#: ../../mod/webpages.php:183 ../../mod/thing.php:228 ../../mod/group.php:176 +#: ../../mod/blocks.php:155 ../../mod/photos.php:1062 +#: ../../mod/editlayout.php:178 ../../mod/editwebpage.php:225 +#: ../../mod/editblock.php:180 ../../mod/admin.php:826 ../../mod/admin.php:988 +#: ../../mod/settings.php:651 ../../mod/connedit.php:551 +msgid "Delete" +msgstr "Esborra" + +#: ../../include/RedDAV/RedBrowser.php:302 +msgid "Create new folder" +msgstr "Crea una nova carpeta" + +#: ../../include/RedDAV/RedBrowser.php:304 +msgid "Upload file" +msgstr "Puja arxiu" + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "%1$s de marcadors" + +#: ../../include/network.php:635 +msgid "view full size" +msgstr "Veure a mida competa" + +#: ../../include/network.php:1585 ../../include/enotify.php:58 +msgid "$Projectname Notification" +msgstr "Notificació de $Projectname" + +#: ../../include/network.php:1586 ../../include/enotify.php:59 +#: ../../include/diaspora.php:2522 ../../include/diaspora.php:2533 +#: ../../mod/p.php:46 +msgid "$projectname" +msgstr "$projectname" + +#: ../../include/network.php:1588 ../../include/enotify.php:61 +msgid "Thank You," +msgstr "Gràcies," + +#: ../../include/network.php:1590 ../../include/enotify.php:63 +#, php-format +msgid "%s Administrator" +msgstr "%s Administrador" + +#: ../../include/network.php:1646 +msgid "No Subject" +msgstr "Sense Assumpte" + +#: ../../include/features.php:38 +msgid "General Features" +msgstr "Característiques Generals" + +#: ../../include/features.php:40 +msgid "Content Expiration" +msgstr "Expiració del Contingut" + +#: ../../include/features.php:40 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "elimina entrades/comentaris i/o missatges privats de aquí en endevant." + +#: ../../include/features.php:41 +msgid "Multiple Profiles" +msgstr "Multiples Perfils" + +#: ../../include/features.php:41 +msgid "Ability to create multiple profiles" +msgstr "Capacitat per crear multiples perfils" + +#: ../../include/features.php:42 +msgid "Advanced Profiles" +msgstr "Perfils Avançats" + +#: ../../include/features.php:42 +msgid "Additional profile sections and selections" +msgstr "Seccions i seleccions addicionals de perfils " + +#: ../../include/features.php:43 +msgid "Profile Import/Export" +msgstr "Importar/Exportar Perfil" + +#: ../../include/features.php:43 +msgid "Save and load profile details across sites/channels" +msgstr "Guarda i carrega els detalls del perfil al llarg dels llocs/canals" + +#: ../../include/features.php:44 +msgid "Web Pages" +msgstr "Pàgines Web" + +#: ../../include/features.php:44 +msgid "Provide managed web pages on your channel" +msgstr "Proporcionar pàgines web gestionades al seu canal" + +#: ../../include/features.php:45 +msgid "Private Notes" +msgstr "Notes Privades" + +#: ../../include/features.php:45 +msgid "Enables a tool to store notes and reminders" +msgstr "Activa l'eina per guardar notes i recordatoris" + +#: ../../include/features.php:46 +msgid "Navigation Channel Select" +msgstr "Navegació pel Selector de Canals" + +#: ../../include/features.php:46 +msgid "Change channels directly from within the navigation dropdown menu" +msgstr "Canvieu els canals directament des del menú desplegable de navegació" + +#: ../../include/features.php:47 +msgid "Photo Location" +msgstr "Ubicació de la Photo" + +#: ../../include/features.php:47 +msgid "If location data is available on uploaded photos, link this to a map." +msgstr "Si los datos de ubicación están disponibles en las fotos subidas, vincular a un mapa." + +#: ../../include/features.php:49 +msgid "Expert Mode" +msgstr "Mode Expert" + +#: ../../include/features.php:49 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "Activar Mode Expert per a proporcionar opcions avançades de configuració" + +#: ../../include/features.php:50 +msgid "Premium Channel" +msgstr "Canal Superior" + +#: ../../include/features.php:50 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "Li permet establir restriccions i els termes en els quals es connecten amb el seu canal" + +#: ../../include/features.php:55 +msgid "Post Composition Features" +msgstr "Característiques de Composició d'Entrades" + +#: ../../include/features.php:57 +msgid "Use Markdown" +msgstr "Us d'Abreviatures" + +#: ../../include/features.php:57 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "Permet emprat \"Abreviatures\" per formatar entrades" + +#: ../../include/features.php:58 +msgid "Large Photos" +msgstr "Grans Fotos" + +#: ../../include/features.php:58 +msgid "" +"Include large (640px) photo thumbnails in posts. If not enabled, use small " +"(320px) photo thumbnails" +msgstr "Inclou gran (640px) foto de miniatura a les entrades. Si no està activat, empra petita (320px) foto de miniatura." + +#: ../../include/features.php:59 ../../include/widgets.php:548 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "Canal Origen" + +#: ../../include/features.php:59 +msgid "Automatically import channel content from other channels or feeds" +msgstr "Importa automàticament el contingut del canal des de altres canals o feeds" + +#: ../../include/features.php:60 +msgid "Even More Encryption" +msgstr "Encara Més Encriptació" + +#: ../../include/features.php:60 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "Permet l'encripció opcional del contingut extrem-a-extrem amb clau secreta compartida" + +#: ../../include/features.php:61 +msgid "Enable voting tools" +msgstr "Habilitar eines de vot" + +#: ../../include/features.php:61 +msgid "Provide a class of post which others can vote on" +msgstr "Proporcionar una classe d'entrada que altres puguin votar" + +#: ../../include/features.php:67 +msgid "Network and Stream Filtering" +msgstr "Filtrat de Xarxa i Flux" + +#: ../../include/features.php:68 +msgid "Search by Date" +msgstr "Cerca per Data" + +#: ../../include/features.php:68 +msgid "Ability to select posts by date ranges" +msgstr "Capacitat per seleccionar entrades per rang de dates" + +#: ../../include/features.php:69 +msgid "Collections Filter" +msgstr "Filtre de Col·leccions" + +#: ../../include/features.php:69 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "Habilitar giny per mostrar les entrades de xarxa únicament de les col·leccions seleccionades" + +#: ../../include/features.php:70 ../../include/widgets.php:274 +msgid "Saved Searches" +msgstr "Cerques Guardades" + +#: ../../include/features.php:70 +msgid "Save search terms for re-use" +msgstr "Guardar els termin de la cerca per a re-usar" + +#: ../../include/features.php:71 +msgid "Network Personal Tab" +msgstr "Pestanya Personal de Xarxa" + +#: ../../include/features.php:71 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "Activa pestanya per mostrar només les entrades de xarxa en els que has intervingut" + +#: ../../include/features.php:72 +msgid "Network New Tab" +msgstr "Nova Pestanya de Xarxa" + +#: ../../include/features.php:72 +msgid "Enable tab to display all new Network activity" +msgstr "Activa pestanya per mostrar tota l'activitat nova de la Xarxa" + +#: ../../include/features.php:73 +msgid "Affinity Tool" +msgstr "Eina d'Afinitat" + +#: ../../include/features.php:73 +msgid "Filter stream activity by depth of relationships" +msgstr "Filtre d'activitat del flux per importància de la relació" + +#: ../../include/features.php:74 +msgid "Connection Filtering" +msgstr "Filtre de Connexió" + +#: ../../include/features.php:74 +msgid "Filter incoming posts from connections based on keywords/content" +msgstr "Filtre de missatges d'entrada de conexions, basat en paraules clau/contingut " + +#: ../../include/features.php:75 +msgid "Suggest Channels" +msgstr "Suggerir Canals" + +#: ../../include/features.php:75 +msgid "Show channel suggestions" +msgstr "Mostra suggerencies de canals" + +#: ../../include/features.php:80 +msgid "Post/Comment Tools" +msgstr "Eina d'Entrades/Comentaris" + +#: ../../include/features.php:81 +msgid "Tagging" +msgstr "Etiquetant" + +#: ../../include/features.php:81 +msgid "Ability to tag existing posts" +msgstr "Capacitat d'etiquetar entrades existents" + +#: ../../include/features.php:82 +msgid "Post Categories" +msgstr "Categories d'Entrades" + +#: ../../include/features.php:82 +msgid "Add categories to your posts" +msgstr "Afegeix categoria a la teva entrada" + +#: ../../include/features.php:83 ../../include/widgets.php:304 +#: ../../include/contact_widgets.php:57 +msgid "Saved Folders" +msgstr "Carpetes Guardades" + +#: ../../include/features.php:83 +msgid "Ability to file posts under folders" +msgstr "Capacitat de arxivar entrades en les carpetes" + +#: ../../include/features.php:84 +msgid "Dislike Posts" +msgstr "No Agrada l'Entrada" + +#: ../../include/features.php:84 +msgid "Ability to dislike posts/comments" +msgstr "Capacitat per marcar amb \"No Agrada\" les entrades/comentaris" + +#: ../../include/features.php:85 +msgid "Star Posts" +msgstr "Entrades Excel·lents" + +#: ../../include/features.php:85 +msgid "Ability to mark special posts with a star indicator" +msgstr "Capacitat per marcar entrades especials amb l'indicador d'excel·lencia" + +#: ../../include/features.php:86 +msgid "Tag Cloud" +msgstr "Núvol d'Etiquetes." + +#: ../../include/features.php:86 +msgid "Provide a personal tag cloud on your channel page" +msgstr "Proporcionar un núvol d'etiquetes personals a la teva pàgina de canal" + +#: ../../include/widgets.php:35 ../../include/taxonomy.php:264 +#: ../../include/contact_widgets.php:92 +msgid "Categories" +msgstr "Categories" + +#: ../../include/widgets.php:91 ../../include/nav.php:163 +#: ../../mod/apps.php:36 +msgid "Apps" +msgstr "Aplicatius" + +#: ../../include/widgets.php:92 +msgid "System" +msgstr "Sistema" + +#: ../../include/widgets.php:94 ../../include/conversation.php:1504 +msgid "Personal" +msgstr "Personal" + +#: ../../include/widgets.php:95 +msgid "Create Personal App" +msgstr "Crear Personal App" + +#: ../../include/widgets.php:96 +msgid "Edit Personal App" +msgstr "Editar Personal App" + +#: ../../include/widgets.php:136 ../../include/widgets.php:175 +#: ../../include/Contact.php:107 ../../include/conversation.php:945 +#: ../../include/identity.php:857 ../../mod/directory.php:316 +#: ../../mod/match.php:64 ../../mod/suggest.php:52 +msgid "Connect" +msgstr "Connecta " + +#: ../../include/widgets.php:138 ../../mod/suggest.php:54 +msgid "Ignore/Hide" +msgstr "Ignora/Amaga" + +#: ../../include/widgets.php:143 ../../mod/connections.php:268 +msgid "Suggestions" +msgstr "Suggerencies" + +#: ../../include/widgets.php:144 +msgid "See more..." +msgstr "Veure més....." + +#: ../../include/widgets.php:166 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "Tens %1$.0f de %2$.0f connexions permeses." + +#: ../../include/widgets.php:172 +msgid "Add New Connection" +msgstr "Afegeix una Nova Connexió" + +#: ../../include/widgets.php:173 +msgid "Enter the channel address" +msgstr "Introdueix la adreça del canal" + +#: ../../include/widgets.php:174 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Exemple: pep@exemple.com, http://exemple.com/vinyet" + +#: ../../include/widgets.php:190 +msgid "Notes" +msgstr "Notes" + +#: ../../include/widgets.php:266 +msgid "Remove term" +msgstr "Plaç de remoció" + +#: ../../include/widgets.php:307 ../../include/contact_widgets.php:60 +#: ../../include/contact_widgets.php:95 +msgid "Everything" +msgstr "Tot" + +#: ../../include/widgets.php:349 +msgid "Archives" +msgstr "Arxius" + +#: ../../include/widgets.php:429 ../../mod/connedit.php:571 +msgid "Me" +msgstr "Jo" + +#: ../../include/widgets.php:430 ../../mod/connedit.php:572 +msgid "Family" +msgstr "Família" + +#: ../../include/widgets.php:431 ../../include/identity.php:394 +#: ../../include/identity.php:395 ../../include/identity.php:402 +#: ../../include/profile_selectors.php:80 ../../mod/settings.php:345 +#: ../../mod/settings.php:349 ../../mod/settings.php:350 +#: ../../mod/settings.php:353 ../../mod/settings.php:364 +#: ../../mod/connedit.php:573 +msgid "Friends" +msgstr "Amics" + +#: ../../include/widgets.php:432 ../../mod/connedit.php:574 +msgid "Acquaintances" +msgstr "Coneguts" + +#: ../../include/widgets.php:433 ../../mod/connections.php:231 +#: ../../mod/connections.php:246 ../../mod/connedit.php:575 +msgid "All" +msgstr "Tots" + +#: ../../include/widgets.php:452 +msgid "Refresh" +msgstr "Refresc" + +#: ../../include/widgets.php:487 +msgid "Account settings" +msgstr "Ajustos de Compte" + +#: ../../include/widgets.php:493 +msgid "Channel settings" +msgstr "Ajustos de Canal" + +#: ../../include/widgets.php:499 +msgid "Additional features" +msgstr "Característiques addicionals" + +#: ../../include/widgets.php:505 +msgid "Feature/Addon settings" +msgstr "Ajustos de Característica/Afegit" + +#: ../../include/widgets.php:511 +msgid "Display settings" +msgstr "Ajustos de pantalla" + +#: ../../include/widgets.php:517 +msgid "Connected apps" +msgstr "Apps connectades" + +#: ../../include/widgets.php:523 +msgid "Export channel" +msgstr "Exportat canal" + +#: ../../include/widgets.php:532 ../../mod/connedit.php:662 +msgid "Connection Default Permissions" +msgstr "Permisos per Defecte de la Connexió" + +#: ../../include/widgets.php:540 +msgid "Premium Channel Settings" +msgstr "Ajustos Premium de Canal" + +#: ../../include/widgets.php:556 ../../include/nav.php:208 +#: ../../include/apps.php:134 ../../mod/admin.php:1079 +#: ../../mod/admin.php:1279 +msgid "Settings" +msgstr "Ajustos" + +#: ../../include/widgets.php:569 ../../mod/message.php:31 +#: ../../mod/mail.php:128 +msgid "Messages" +msgstr "Missatges" + +#: ../../include/widgets.php:572 +msgid "Check Mail" +msgstr "Comprovar Correu" + +#: ../../include/widgets.php:577 ../../include/nav.php:199 +msgid "New Message" +msgstr "Nou Missatge" + +#: ../../include/widgets.php:652 +msgid "Chat Rooms" +msgstr "Sales de Xat" + +#: ../../include/widgets.php:672 +msgid "Bookmarked Chatrooms" +msgstr "Sales de Xat Favorites" + +#: ../../include/widgets.php:692 +msgid "Suggested Chatrooms" +msgstr "Sales de Xat Suggerides" + +#: ../../include/widgets.php:819 ../../include/widgets.php:877 +msgid "photo/image" +msgstr "foto/imatge" + +#: ../../include/widgets.php:972 ../../include/widgets.php:974 +msgid "Rate Me" +msgstr "Valora'm" + +#: ../../include/widgets.php:978 +msgid "View Ratings" +msgstr "Veure Valoracions" + +#: ../../include/widgets.php:989 +msgid "Public Hubs" +msgstr "Concentradors Públics" + +#: ../../include/event.php:22 ../../include/bb2diaspora.php:459 +msgid "l F d, Y \\@ g:i A" +msgstr "l F d, Y \\@ g:i A" + +#: ../../include/event.php:30 ../../include/bb2diaspora.php:465 +msgid "Starts:" +msgstr "Inicia:" + +#: ../../include/event.php:40 ../../include/bb2diaspora.php:473 +msgid "Finishes:" +msgstr "Acaba:" + +#: ../../include/event.php:50 ../../include/bb2diaspora.php:481 +#: ../../include/identity.php:908 ../../mod/directory.php:302 +#: ../../mod/events.php:661 +msgid "Location:" +msgstr "Localització:" + +#: ../../include/event.php:535 +msgid "This event has been added to your calendar." +msgstr "Aquest succés ha estat afegit al teu calendari." + +#: ../../include/enotify.php:96 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:100 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "[Red:Notificació] Un nou missatge s'ha rebut a %s" + +#: ../../include/enotify.php:102 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "%1$s, %2$s t'ha enviat un nou missatge privat a %3$s." + +#: ../../include/enotify.php:103 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s t'ha enviat %2$s." + +#: ../../include/enotify.php:103 +msgid "a private message" +msgstr "un missatge privat" + +#: ../../include/enotify.php:104 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Per favor, visita %s per a veure i/o respondre els teus missatges privats." + +#: ../../include/enotify.php:158 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "%1$s, %2$s comentat en [zrl=%3$s]a %4$s[/zrl]" + +#: ../../include/enotify.php:166 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "%1$s, %2$s comentat en [zrl=%3$s]%4$s de %5$s[/zrl]" + +#: ../../include/enotify.php:175 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "%1$s, %2$s comentat en [zrl=%3$s]el teu %4$s[/zrl]" + +#: ../../include/enotify.php:186 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Red:Notify] Comentari a la conversa #%1$d per %2$s" + +#: ../../include/enotify.php:187 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "%1$s, %2$s comentat en un article/conversa que havies estat seguint." + +#: ../../include/enotify.php:190 ../../include/enotify.php:205 +#: ../../include/enotify.php:231 ../../include/enotify.php:249 +#: ../../include/enotify.php:263 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Si us plau visita %s per veure i/o contestar a la conversa" + +#: ../../include/enotify.php:196 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "[Red:Avís] %s ha escrit una entrada al teu mur" + +#: ../../include/enotify.php:198 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "%1$s, %2$s ha escrit una entrada al teu mur en %3$s" + +#: ../../include/enotify.php:200 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "%1$s, %2$s enviat correu a [zrl=%3$s]el teu mur[/zrl]" + +#: ../../include/enotify.php:224 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "[Red:Notificació] %s t'ha etiquetat" + +#: ../../include/enotify.php:225 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "%1$s, %2$s t'ha etiquetat a %3$s" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "%1$s, %2$s [zrl=%3$s]t'ha etiquetat[/zrl]." + +#: ../../include/enotify.php:238 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "[Red:Avís] %1$s s'en fot de tu" + +#: ../../include/enotify.php:239 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "%1$s, %2$s s'en fot de tú a %3$s" + +#: ../../include/enotify.php:240 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "%1$s, %2$s [zrl=%2$s]s'en fot de tú[/zrl]." + +#: ../../include/enotify.php:256 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "[Red:Avís] %s ha etiquetat la teva entrada" + +#: ../../include/enotify.php:257 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "%1$s, %2$s ha etiquetat la teva entrada a %3$s" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "%1$s, %2$s etiquetat [zrl=%3$s]la teva entrada[/zrl]" + +#: ../../include/enotify.php:270 +msgid "[Red:Notify] Introduction received" +msgstr "[Red:Avís] Presentació rebuda" + +#: ../../include/enotify.php:271 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "%1$s, has rebut una nova petició de connexió de '%2$s' a %3$s" + +#: ../../include/enotify.php:272 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "%1$s, has rebut [zrl=%2$s]una nova petició de connexió[/zrl] de %3$s." + +#: ../../include/enotify.php:276 ../../include/enotify.php:295 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Pots visitar el seu perfil a %s" + +#: ../../include/enotify.php:278 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "Si us plau, visita %s per aprovar o rebutjar la petició de connexió." + +#: ../../include/enotify.php:285 +msgid "[Red:Notify] Friend suggestion received" +msgstr "[Red:Notificació] Rebuda suggerencia d'amistat" + +#: ../../include/enotify.php:286 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "%1$s, has rebut una suggerència d'amistat de '%2$s' a %3$s" + +#: ../../include/enotify.php:287 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from " +"%4$s." +msgstr "%1$s, has rebut [zrl=%2$s]una suggerència d'amistat[/zrl] per %3$s de %4$s." + +#: ../../include/enotify.php:293 +msgid "Name:" +msgstr "Nom:" + +#: ../../include/enotify.php:294 +msgid "Photo:" +msgstr "Foto:" + +#: ../../include/enotify.php:297 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Per favor, visita %s per a aprovar o rebutjar la suggerencia." + +#: ../../include/enotify.php:508 +msgid "[Red:Notify]" +msgstr "[Red:Notificació]" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "No s'ha proporcionat bústia." + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "[no subject]" + +#: ../../include/message.php:45 +msgid "Unable to determine sender." +msgstr "incapaç de determinar el remitent" + +#: ../../include/message.php:200 +msgid "Stored post could not be verified." +msgstr "L'entrada guardada no pot ser verificada" + +#: ../../include/diaspora.php:2148 ../../include/conversation.php:164 +#: ../../mod/like.php:394 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "%1$s agrada %2$s de %3$s" + +#: ../../include/diaspora.php:2494 +msgid "Please choose" +msgstr "Escull" + +#: ../../include/diaspora.php:2496 +msgid "Agree" +msgstr "A favor" + +#: ../../include/diaspora.php:2498 +msgid "Disagree" +msgstr "En contra" + +#: ../../include/diaspora.php:2500 +msgid "Abstain" +msgstr "Abstenció" + +#: ../../include/follow.php:28 +msgid "Channel is blocked on this site." +msgstr "El canal està bloquejat en aquest lloc." + +#: ../../include/follow.php:33 +msgid "Channel location missing." +msgstr "Ubicació del canal perduda." + +#: ../../include/follow.php:83 +msgid "Response from remote channel was incomplete." +msgstr "La resposta del canal remot fou incompleta." + +#: ../../include/follow.php:100 +msgid "Channel was deleted and no longer exists." +msgstr "El canal fou esborrat i actualment no existeix." + +#: ../../include/follow.php:135 ../../include/follow.php:206 +msgid "Protocol disabled." +msgstr "Protocol desactivat." + +#: ../../include/follow.php:144 +msgid "Protocol blocked for this channel." +msgstr "El protocol està bloquejat per a aquest canal." + +#: ../../include/follow.php:179 +msgid "Channel discovery failed." +msgstr "Descobriment de canal fallit." + +#: ../../include/follow.php:195 +msgid "local account not found." +msgstr "compte local no trobat." + +#: ../../include/follow.php:224 +msgid "Cannot connect to yourself." +msgstr "No pots connectar amb tu mateix." + +#: ../../include/ItemObject.php:89 ../../include/conversation.php:667 +msgid "Private Message" +msgstr "Missatge Privat" + +#: ../../include/ItemObject.php:126 ../../include/conversation.php:659 +msgid "Select" +msgstr "Selecciona" + +#: ../../include/ItemObject.php:130 +msgid "Save to Folder" +msgstr "Guardar en la Carpeta" + +#: ../../include/ItemObject.php:151 +msgid "I will attend" +msgstr "Assistiré" + +#: ../../include/ItemObject.php:151 +msgid "I will not attend" +msgstr "No assistiré" + +#: ../../include/ItemObject.php:151 +msgid "I might attend" +msgstr "Podria assistir" + +#: ../../include/ItemObject.php:161 +msgid "I agree" +msgstr "D'acord" + +#: ../../include/ItemObject.php:161 +msgid "I disagree" +msgstr "En desacord" + +#: ../../include/ItemObject.php:161 +msgid "I abstain" +msgstr "M'abstinc" + +#: ../../include/ItemObject.php:175 ../../include/ItemObject.php:187 +#: ../../include/conversation.php:1677 ../../mod/photos.php:1015 +#: ../../mod/photos.php:1027 +msgid "View all" +msgstr "Veure tot" + +#: ../../include/ItemObject.php:179 ../../include/taxonomy.php:396 +#: ../../include/conversation.php:1701 ../../include/identity.php:1167 +#: ../../mod/photos.php:1019 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "Agrada" +msgstr[1] "Agraden" + +#: ../../include/ItemObject.php:184 ../../include/conversation.php:1704 +#: ../../mod/photos.php:1024 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "Desagrada" +msgstr[1] "Desagrada" + +#: ../../include/ItemObject.php:212 +msgid "Add Star" +msgstr "Fes-lo Preferit" + +#: ../../include/ItemObject.php:213 +msgid "Remove Star" +msgstr "Treu-lo de Preferits" + +#: ../../include/ItemObject.php:214 +msgid "Toggle Star Status" +msgstr "Canvia el Estat de la Preferència" + +#: ../../include/ItemObject.php:218 +msgid "starred" +msgstr "preferit" + +#: ../../include/ItemObject.php:227 ../../include/conversation.php:674 +msgid "Message signature validated" +msgstr "Validada la signatura del missatge" + +#: ../../include/ItemObject.php:228 ../../include/conversation.php:675 +msgid "Message signature incorrect" +msgstr "Signatura del missatge incorrecta" + +#: ../../include/ItemObject.php:236 +msgid "Add Tag" +msgstr "Afegeix Etiqueta" + +#: ../../include/ItemObject.php:254 ../../mod/photos.php:959 +msgid "I like this (toggle)" +msgstr "M'agrada això (canvia)" + +#: ../../include/ItemObject.php:254 ../../include/taxonomy.php:310 +msgid "like" +msgstr "agrada" + +#: ../../include/ItemObject.php:255 ../../mod/photos.php:960 +msgid "I don't like this (toggle)" +msgstr "No m'agrada això (canvia)" + +#: ../../include/ItemObject.php:255 ../../include/taxonomy.php:311 +msgid "dislike" +msgstr "desagrada" + +#: ../../include/ItemObject.php:259 +msgid "Share This" +msgstr "Comparteix Això" + +#: ../../include/ItemObject.php:259 +msgid "share" +msgstr "comparteix" + +#: ../../include/ItemObject.php:276 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d commentari" +msgstr[1] "%d commentaris" + +#: ../../include/ItemObject.php:294 ../../include/ItemObject.php:295 +#, php-format +msgid "View %s's profile - %s" +msgstr "Veure %s de perfil - %s" + +#: ../../include/ItemObject.php:298 +msgid "to" +msgstr "a" + +#: ../../include/ItemObject.php:299 +msgid "via" +msgstr "via" + +#: ../../include/ItemObject.php:300 +msgid "Wall-to-Wall" +msgstr "Mur-a-Mur" + +#: ../../include/ItemObject.php:301 +msgid "via Wall-To-Wall:" +msgstr "via Mur-a-Mur:" + +#: ../../include/ItemObject.php:312 ../../include/conversation.php:716 +#, php-format +msgid "from %s" +msgstr "De %s" + +#: ../../include/ItemObject.php:315 ../../include/conversation.php:719 +#, php-format +msgid "last edited: %s" +msgstr "últim editat: %s" + +#: ../../include/ItemObject.php:316 ../../include/conversation.php:720 +#, php-format +msgid "Expires: %s" +msgstr "Expira: %s" + +#: ../../include/ItemObject.php:337 +msgid "Save Bookmarks" +msgstr "Guarda Favorits" + +#: ../../include/ItemObject.php:338 +msgid "Add to Calendar" +msgstr "Afegeix al Calendari" + +#: ../../include/ItemObject.php:347 +msgid "Mark all seen" +msgstr "Marca tot com ja vist" + +#: ../../include/ItemObject.php:353 ../../mod/photos.php:1145 +msgctxt "noun" +msgid "Likes" +msgstr "Agrada" + +#: ../../include/ItemObject.php:354 ../../mod/photos.php:1146 +msgctxt "noun" +msgid "Dislikes" +msgstr "Desagrada" + +#: ../../include/ItemObject.php:359 ../../include/acl_selectors.php:249 +#: ../../mod/photos.php:1151 +msgid "Close" +msgstr "Tanca" + +#: ../../include/ItemObject.php:364 ../../include/conversation.php:737 +#: ../../include/conversation.php:1209 ../../mod/editpost.php:123 +#: ../../mod/photos.php:962 ../../mod/editlayout.php:147 +#: ../../mod/editwebpage.php:192 ../../mod/editblock.php:149 +#: ../../mod/mail.php:241 ../../mod/mail.php:356 +msgid "Please wait" +msgstr "Si us plau, espera" + +#: ../../include/ItemObject.php:665 ../../mod/photos.php:978 +#: ../../mod/photos.php:1096 +msgid "This is you" +msgstr "Ets tú" + +#: ../../include/ItemObject.php:669 ../../include/conversation.php:1181 +#: ../../mod/editpost.php:107 ../../mod/editlayout.php:134 +#: ../../mod/editwebpage.php:179 ../../mod/editblock.php:135 +msgid "Bold" +msgstr "Negreta" + +#: ../../include/ItemObject.php:670 ../../include/conversation.php:1182 +#: ../../mod/editpost.php:108 ../../mod/editlayout.php:135 +#: ../../mod/editwebpage.php:180 ../../mod/editblock.php:136 +msgid "Italic" +msgstr "Italica" + +#: ../../include/ItemObject.php:671 ../../include/conversation.php:1183 +#: ../../mod/editpost.php:109 ../../mod/editlayout.php:136 +#: ../../mod/editwebpage.php:181 ../../mod/editblock.php:137 +msgid "Underline" +msgstr "Subratllat" + +#: ../../include/ItemObject.php:672 ../../include/conversation.php:1184 +#: ../../mod/editpost.php:110 ../../mod/editlayout.php:137 +#: ../../mod/editwebpage.php:182 ../../mod/editblock.php:138 +msgid "Quote" +msgstr "Cometes" + +#: ../../include/ItemObject.php:673 ../../include/conversation.php:1185 +#: ../../mod/editpost.php:111 ../../mod/editlayout.php:138 +#: ../../mod/editwebpage.php:183 ../../mod/editblock.php:139 +msgid "Code" +msgstr "Codi" + +#: ../../include/ItemObject.php:674 +msgid "Image" +msgstr "Imatge" + +#: ../../include/ItemObject.php:675 +msgid "Insert Link" +msgstr "Insereix Enllaç" + +#: ../../include/ItemObject.php:676 +msgid "Video" +msgstr "Video" + +#: ../../include/ItemObject.php:680 ../../include/conversation.php:1236 +#: ../../mod/editpost.php:151 ../../mod/mail.php:247 ../../mod/mail.php:361 +msgid "Encrypt text" +msgstr "Text encriptat" + +#: ../../include/Contact.php:124 +msgid "New window" +msgstr "Nova finestra" + +#: ../../include/Contact.php:125 +msgid "Open the selected location in a different window or browser tab" +msgstr "Obrir la localització seleccionada en un altre finestra o pestanya del navegador" + +#: ../../include/Contact.php:215 ../../mod/admin.php:739 +#, php-format +msgid "User '%s' deleted" +msgstr "usuari '%s' esborrat" + +#: ../../include/bb2diaspora.php:373 +msgid "Attachments:" +msgstr "Adjuntat:" + +#: ../../include/bb2diaspora.php:461 +msgid "$Projectname event notification:" +msgstr "Notificació d'esdeveniment de $Projectname" + +#: ../../include/nav.php:87 ../../include/nav.php:120 ../../boot.php:1550 +msgid "Logout" +msgstr "Desconectar" + +#: ../../include/nav.php:87 ../../include/nav.php:120 +msgid "End this session" +msgstr "Finalitza aquesta sessió" + +#: ../../include/nav.php:90 ../../include/nav.php:151 +msgid "Home" +msgstr "Personal" + +#: ../../include/nav.php:90 +msgid "Your posts and conversations" +msgstr "Les teves entrades i converses" + +#: ../../include/nav.php:91 ../../include/conversation.php:942 +#: ../../mod/connedit.php:498 +msgid "View Profile" +msgstr "Veure Perfil" + +#: ../../include/nav.php:91 +msgid "Your profile page" +msgstr "La teva pàgina de perfil" + +#: ../../include/nav.php:93 +msgid "Edit Profiles" +msgstr "Editar Perfils" + +#: ../../include/nav.php:93 +msgid "Manage/Edit profiles" +msgstr "Gestiona/Edita perfils" + +#: ../../include/nav.php:95 ../../include/identity.php:880 +msgid "Edit Profile" +msgstr "Edita Perfil" + +#: ../../include/nav.php:95 +msgid "Edit your profile" +msgstr "Edita el teu perfil" + +#: ../../include/nav.php:97 ../../include/conversation.php:1600 +#: ../../include/apps.php:139 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "Fotos" + +#: ../../include/nav.php:97 +msgid "Your photos" +msgstr "Les Teves Fotos" + +#: ../../include/nav.php:98 +msgid "Your files" +msgstr "Els teus arxius" + +#: ../../include/nav.php:103 ../../include/apps.php:146 +msgid "Chat" +msgstr "Xerrar" + +#: ../../include/nav.php:103 +msgid "Your chatrooms" +msgstr "Les teves sales de xerrar" + +#: ../../include/nav.php:109 ../../include/conversation.php:1635 +#: ../../include/apps.php:129 +msgid "Bookmarks" +msgstr "Marcadors" + +#: ../../include/nav.php:109 +msgid "Your bookmarks" +msgstr "Els teus marcadors" + +#: ../../include/nav.php:113 ../../include/conversation.php:1645 +#: ../../include/apps.php:136 ../../mod/webpages.php:178 +msgid "Webpages" +msgstr "Pàgines web" + +#: ../../include/nav.php:113 +msgid "Your webpages" +msgstr "Les teves pàgines web" + +#: ../../include/nav.php:117 ../../include/apps.php:131 ../../boot.php:1551 +msgid "Login" +msgstr "Identifica't" + +#: ../../include/nav.php:117 +msgid "Sign in" +msgstr "Signatura" + +#: ../../include/nav.php:134 +#, php-format +msgid "%s - click to logout" +msgstr "%s - click per desconectar" + +#: ../../include/nav.php:137 +msgid "Remote authentication" +msgstr "Autenticació remota" + +#: ../../include/nav.php:137 +msgid "Click to authenticate to your home hub" +msgstr "Click per autentificar-te en el teu Lloc " + +#: ../../include/nav.php:151 +msgid "Home Page" +msgstr "Pàgina Personal" + +#: ../../include/nav.php:155 ../../mod/register.php:224 ../../boot.php:1527 +msgid "Register" +msgstr "Registre" + +#: ../../include/nav.php:155 +msgid "Create an account" +msgstr "Crear un compte" + +#: ../../include/nav.php:160 ../../include/apps.php:142 ../../mod/help.php:67 +#: ../../mod/help.php:72 ../../mod/layouts.php:176 +msgid "Help" +msgstr "Ajuda" + +#: ../../include/nav.php:160 +msgid "Help and documentation" +msgstr "Ajuda i documentació" + +#: ../../include/nav.php:163 +msgid "Applications, utilities, links, games" +msgstr "Aplicacions, utilitats, enllaços, jocs" + +#: ../../include/nav.php:165 +msgid "Search site content" +msgstr "Cerca en el contingut del lloc" + +#: ../../include/nav.php:168 ../../include/apps.php:141 +msgid "Directory" +msgstr "Directori" + +#: ../../include/nav.php:168 +msgid "Channel Directory" +msgstr "Directori de Canals" + +#: ../../include/nav.php:180 ../../include/apps.php:133 +msgid "Matrix" +msgstr "Matriu/Matrix" + +#: ../../include/nav.php:180 +msgid "Your matrix" +msgstr "El teu matrix" + +#: ../../include/nav.php:181 +msgid "Mark all matrix notifications seen" +msgstr "Marca totes les notificacions de matrix vistes" + +#: ../../include/nav.php:183 ../../include/apps.php:137 +msgid "Channel Home" +msgstr "Canal Personal" + +#: ../../include/nav.php:183 +msgid "Channel home" +msgstr "Canal personal" + +#: ../../include/nav.php:184 +msgid "Mark all channel notifications seen" +msgstr "Marca totes les notificacions de canal vistes" + +#: ../../include/nav.php:187 ../../mod/connections.php:407 +msgid "Connections" +msgstr "Connexions" + +#: ../../include/nav.php:190 +msgid "Notices" +msgstr "Noticies" + +#: ../../include/nav.php:190 +msgid "Notifications" +msgstr "Notificacions" + +#: ../../include/nav.php:191 +msgid "See all notifications" +msgstr "Veure totes les Notificacions" + +#: ../../include/nav.php:192 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "Marca totes les notificacions vistes" + +#: ../../include/nav.php:194 ../../include/apps.php:143 +msgid "Mail" +msgstr "Correu" + +#: ../../include/nav.php:194 +msgid "Private mail" +msgstr "Correu privat" + +#: ../../include/nav.php:195 +msgid "See all private messages" +msgstr "Veure tots els missatges privats" + +#: ../../include/nav.php:196 +msgid "Mark all private messages seen" +msgstr "Marcar tots els missatges privats vistos" + +#: ../../include/nav.php:197 +msgid "Inbox" +msgstr "Safata d'entrada" + +#: ../../include/nav.php:198 +msgid "Outbox" +msgstr "Safata de sortida" + +#: ../../include/nav.php:202 ../../include/apps.php:140 +#: ../../mod/events.php:486 +msgid "Events" +msgstr "Events" + +#: ../../include/nav.php:202 +msgid "Event Calendar" +msgstr "Calendari d'Events" + +#: ../../include/nav.php:203 +msgid "See all events" +msgstr "Veure tots els events" + +#: ../../include/nav.php:204 +msgid "Mark all events seen" +msgstr "Marcar tots els events vistos" + +#: ../../include/nav.php:206 ../../include/apps.php:132 +#: ../../mod/manage.php:166 +msgid "Channel Manager" +msgstr "Gestor del Canal" + +#: ../../include/nav.php:206 +msgid "Manage Your Channels" +msgstr "Gestiona els Teus Canals" + +#: ../../include/nav.php:208 +msgid "Account/Channel Settings" +msgstr "Ajustos de Compte/Canal" + +#: ../../include/nav.php:216 ../../mod/admin.php:120 +msgid "Admin" +msgstr "Admin" + +#: ../../include/nav.php:216 +msgid "Site Setup and Configuration" +msgstr "Ajustos i Configuració del Lloc" + +#: ../../include/nav.php:247 ../../include/conversation.php:850 +msgid "Loading..." +msgstr "Carregant..." + +#: ../../include/nav.php:252 +msgid "@name, #tag, content" +msgstr "@name, #tag, content" + +#: ../../include/nav.php:253 +msgid "Please wait..." +msgstr "Si us plau, espera......." + +#: ../../include/taxonomy.php:222 ../../include/taxonomy.php:243 +msgid "Tags" +msgstr "Etiquetes" + +#: ../../include/taxonomy.php:287 +msgid "Keywords" +msgstr "Paraules clau" + +#: ../../include/taxonomy.php:308 +msgid "have" +msgstr "tinc" + +#: ../../include/taxonomy.php:308 +msgid "has" +msgstr "tens" + +#: ../../include/taxonomy.php:309 +msgid "want" +msgstr "vull" + +#: ../../include/taxonomy.php:309 +msgid "wants" +msgstr "vols" + +#: ../../include/taxonomy.php:310 +msgid "likes" +msgstr "agrada" + +#: ../../include/taxonomy.php:311 +msgid "dislikes" +msgstr "desagrada" + +#: ../../include/activities.php:39 +msgid " and " +msgstr "i" + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "Perfil públic" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s canviat %2$s a “%3$s”" + +#: ../../include/activities.php:57 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "Visita %1$s de %2$s" + +#: ../../include/activities.php:60 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s Ha actualitzat %2$s, canviant %3$s." + +#: ../../include/security.php:349 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "El formulario de la cadena de seguridad no era correcto. Esto probablemente ocurrió porque el formulario se ha abierto durante demasiado tiempo (> 3 horas) antes de enviarlo." + +#: ../../include/permissions.php:26 +msgid "Can view my normal stream and posts" +msgstr "Pot veure el flux i entrades normals" + +#: ../../include/permissions.php:27 +msgid "Can view my default channel profile" +msgstr "Pot veure el meu perfil del canal per defecte" + +#: ../../include/permissions.php:28 +msgid "Can view my photo albums" +msgstr "Pot veure el meus àlbums de fotos" + +#: ../../include/permissions.php:29 +msgid "Can view my connections" +msgstr "Pot veure les meves connexions" + +#: ../../include/permissions.php:30 +msgid "Can view my file storage" +msgstr "Pot veure al meu magatzem d'arxius" + +#: ../../include/permissions.php:31 +msgid "Can view my webpages" +msgstr "Pot veure les meves pàgines web" + +#: ../../include/permissions.php:34 +msgid "Can send me their channel stream and posts" +msgstr "Pot enviar-me el flux i entrades del seu canal" + +#: ../../include/permissions.php:35 +msgid "Can post on my channel page (\"wall\")" +msgstr "Pot fer entrades a la meva pàgina de canal (\"mur\")" + +#: ../../include/permissions.php:36 +msgid "Can comment on or like my posts" +msgstr "Pot fer comentaris o dir si agrada en les meves entrades" + +#: ../../include/permissions.php:37 +msgid "Can send me private mail messages" +msgstr "Pot enviar-me un missatge de correu privat" + +#: ../../include/permissions.php:38 +msgid "Can post photos to my photo albums" +msgstr "Pot enviar fotos al meus àlbums de fotos" + +#: ../../include/permissions.php:39 +msgid "Can like/dislike stuff" +msgstr "Pot dir si agrada/desagrada " + +#: ../../include/permissions.php:39 +msgid "Profiles and things other than posts/comments" +msgstr "Perfils i altres coses a més d'entrades/comentaris" + +#: ../../include/permissions.php:41 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "Ho pot enviar a tots els meus contactes del canal via entrades @mencions" + +#: ../../include/permissions.php:41 +msgid "Advanced - useful for creating group forum channels" +msgstr "Avançat - capaç de crear canals de grups de foro" + +#: ../../include/permissions.php:42 +msgid "Can chat with me (when available)" +msgstr "Pot xatejar amb mi (si estic disponible)" + +#: ../../include/permissions.php:43 +msgid "Can write to my file storage" +msgstr "Pot escriure al meu magatzem d'arxius" + +#: ../../include/permissions.php:44 +msgid "Can edit my webpages" +msgstr "Pot editar les meves pàgines web" + +#: ../../include/permissions.php:46 +msgid "Can source my public posts in derived channels" +msgstr "Pot mostrar l'origen de les meves entrades públiques en altres canals" + +#: ../../include/permissions.php:46 +msgid "Somewhat advanced - very useful in open communities" +msgstr "Quelcom avançat - molt útil en comunitats obertes" + +#: ../../include/permissions.php:48 +msgid "Can administer my channel resources" +msgstr "Pot administrar els meus recursos del canal" + +#: ../../include/permissions.php:48 +msgid "" +"Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "Extremadament avançat. No toquis res si no saps que estàs fent" + +#: ../../include/permissions.php:893 +msgid "Social Networking" +msgstr "Xarxes Socials" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Mostly Public" +msgstr "Més aviat Públic" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Restricted" +msgstr "Restringit" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +msgid "Private" +msgstr "Privat" + +#: ../../include/permissions.php:894 +msgid "Community Forum" +msgstr "Foro de Comunitat" + +#: ../../include/permissions.php:895 +msgid "Feed Republish" +msgstr "Republicador" + +#: ../../include/permissions.php:896 +msgid "Special Purpose" +msgstr "Objectiu Especial" + +#: ../../include/permissions.php:896 +msgid "Celebrity/Soapbox" +msgstr "Celebritat/Faristol" + +#: ../../include/permissions.php:896 +msgid "Group Repository" +msgstr "Repositori de Grup" + +#: ../../include/permissions.php:897 ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 +msgid "Other" +msgstr "Altres" + +#: ../../include/permissions.php:897 +msgid "Custom/Expert Mode" +msgstr "Personalitzat/Mode Expert" + +#: ../../include/conversation.php:126 ../../mod/like.php:113 +msgid "channel" +msgstr "canal" + +#: ../../include/conversation.php:167 ../../mod/like.php:396 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "%1$s no agrada %2$s de %3$s" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "%1$s esta ara connectat amb %2$s" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "%1$s emprenyat %2$s" + +#: ../../include/conversation.php:260 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "%1$s es %2$s" + +#: ../../include/conversation.php:572 ../../mod/photos.php:996 +msgctxt "title" +msgid "Likes" +msgstr "Agrada" + +#: ../../include/conversation.php:572 ../../mod/photos.php:996 +msgctxt "title" +msgid "Dislikes" +msgstr "Desagrada" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Agree" +msgstr "Acord" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Disagree" +msgstr "Desacord" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Abstain" +msgstr "Abstenirse" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Attending" +msgstr "Assistint" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Not attending" +msgstr "Desassistint" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Might attend" +msgstr "Podrien assistir" + +#: ../../include/conversation.php:692 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Vista %s del perfil @ %s" + +#: ../../include/conversation.php:707 +msgid "Categories:" +msgstr "Categories:" + +#: ../../include/conversation.php:708 +msgid "Filed under:" +msgstr "Arxivar a:" + +#: ../../include/conversation.php:735 +msgid "View in context" +msgstr "Veure en context" + +#: ../../include/conversation.php:846 +msgid "remove" +msgstr "treu" + +#: ../../include/conversation.php:851 +msgid "Delete Selected Items" +msgstr "Esborra els Articles Seleccionats" + +#: ../../include/conversation.php:939 +msgid "View Source" +msgstr "Veure l'Origen" + +#: ../../include/conversation.php:940 +msgid "Follow Thread" +msgstr "Segueix el Fil" + +#: ../../include/conversation.php:941 +msgid "View Status" +msgstr "Veure Status" + +#: ../../include/conversation.php:943 +msgid "View Photos" +msgstr "Veure Fotos" + +#: ../../include/conversation.php:944 +msgid "Matrix Activity" +msgstr "Activitat de Matrix" + +#: ../../include/conversation.php:946 +msgid "Edit Contact" +msgstr "Editar Contacte" + +#: ../../include/conversation.php:947 +msgid "Send PM" +msgstr "Enviar MP" + +#: ../../include/conversation.php:948 ../../include/apps.php:145 +msgid "Poke" +msgstr "Emprenya" + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s likes this." +msgstr "%s agrada això." + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s doesn't like this." +msgstr "%s no agrada això." + +#: ../../include/conversation.php:1066 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "%2$d gent agrada això." +msgstr[1] "%2$d gent agrada això." + +#: ../../include/conversation.php:1068 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "%2$d gent no agrada això." +msgstr[1] "%2$d gent no agrada això." + +#: ../../include/conversation.php:1074 +msgid "and" +msgstr "i" + +#: ../../include/conversation.php:1077 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] ", i %d altra gent" +msgstr[1] ", i %d altra gent" + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s like this." +msgstr "%s agrada això." + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s don't like this." +msgstr "%s no agrada això." + +#: ../../include/conversation.php:1140 +msgid "Visible to everybody" +msgstr "Visible a tothom" + +#: ../../include/conversation.php:1141 ../../mod/mail.php:174 +#: ../../mod/mail.php:289 +msgid "Please enter a link URL:" +msgstr "Si us plau entra l'enllaç URL:" + +#: ../../include/conversation.php:1142 +msgid "Please enter a video link/URL:" +msgstr "Si us plau entra l'enllaç/URL a un video:" + +#: ../../include/conversation.php:1143 +msgid "Please enter an audio link/URL:" +msgstr "Si us plau, entra l'enllaç/URL a un audio:" + +#: ../../include/conversation.php:1144 +msgid "Tag term:" +msgstr "Paraula de l'Etiqueta:" + +#: ../../include/conversation.php:1145 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "Guardar en la Carpeta" + +#: ../../include/conversation.php:1146 +msgid "Where are you right now?" +msgstr "On ets ara?" + +#: ../../include/conversation.php:1147 ../../mod/editpost.php:47 +#: ../../mod/mail.php:175 ../../mod/mail.php:290 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "Expira YYYY-MM-DD HH:MM" + +#: ../../include/conversation.php:1174 ../../mod/webpages.php:182 +#: ../../mod/blocks.php:154 ../../mod/photos.php:961 ../../mod/layouts.php:184 +msgid "Share" +msgstr "Compartir" + +#: ../../include/conversation.php:1176 +msgid "Page link name" +msgstr "Nom de la pàgina enllaçada" + +#: ../../include/conversation.php:1179 +msgid "Post as" +msgstr "Envia com" + +#: ../../include/conversation.php:1186 ../../mod/editpost.php:112 +#: ../../mod/editlayout.php:139 ../../mod/editwebpage.php:184 +#: ../../mod/editblock.php:141 ../../mod/mail.php:238 ../../mod/mail.php:352 +msgid "Upload photo" +msgstr "Puja foto" + +#: ../../include/conversation.php:1187 +msgid "upload photo" +msgstr "puja foto" + +#: ../../include/conversation.php:1188 ../../mod/editpost.php:113 +#: ../../mod/editlayout.php:140 ../../mod/editwebpage.php:185 +#: ../../mod/editblock.php:142 ../../mod/mail.php:239 ../../mod/mail.php:353 +msgid "Attach file" +msgstr "Adjunta arxiu" + +#: ../../include/conversation.php:1189 +msgid "attach file" +msgstr "adjunta arxiu" + +#: ../../include/conversation.php:1190 ../../mod/editpost.php:114 +#: ../../mod/editlayout.php:141 ../../mod/editwebpage.php:186 +#: ../../mod/editblock.php:143 ../../mod/mail.php:240 ../../mod/mail.php:354 +msgid "Insert web link" +msgstr "Insereix enllaç web" + +#: ../../include/conversation.php:1191 +msgid "web link" +msgstr "enllaç web" + +#: ../../include/conversation.php:1192 +msgid "Insert video link" +msgstr "Insereix enllaç video" + +#: ../../include/conversation.php:1193 +msgid "video link" +msgstr "enllaç video" + +#: ../../include/conversation.php:1194 +msgid "Insert audio link" +msgstr "Insereix enllaç d'audio" + +#: ../../include/conversation.php:1195 +msgid "audio link" +msgstr "enllaç d'audio" + +#: ../../include/conversation.php:1196 ../../mod/editpost.php:118 +#: ../../mod/editlayout.php:145 ../../mod/editwebpage.php:190 +#: ../../mod/editblock.php:147 +msgid "Set your location" +msgstr "Ajusta la teva ubicació" + +#: ../../include/conversation.php:1197 +msgid "set location" +msgstr "ajusta localització" + +#: ../../include/conversation.php:1198 ../../mod/editpost.php:120 +msgid "Toggle voting" +msgstr "Commutar votació" + +#: ../../include/conversation.php:1201 ../../mod/editpost.php:119 +#: ../../mod/editlayout.php:146 ../../mod/editwebpage.php:191 +#: ../../mod/editblock.php:148 +msgid "Clear browser location" +msgstr "Treu la localització del navegador" + +#: ../../include/conversation.php:1202 +msgid "clear location" +msgstr "treu localització" + +#: ../../include/conversation.php:1204 ../../mod/editpost.php:135 +#: ../../mod/editwebpage.php:207 ../../mod/editblock.php:161 +msgid "Title (optional)" +msgstr "Títol (opcional)" + +#: ../../include/conversation.php:1208 ../../mod/editpost.php:137 +#: ../../mod/editlayout.php:162 ../../mod/editwebpage.php:209 +#: ../../mod/editblock.php:164 +msgid "Categories (optional, comma-separated list)" +msgstr "Categories (opcional, llista separada per comes)" + +#: ../../include/conversation.php:1210 ../../mod/editpost.php:124 +#: ../../mod/editlayout.php:148 ../../mod/editwebpage.php:193 +#: ../../mod/editblock.php:150 +msgid "Permission settings" +msgstr "Ajustos de permisos" + +#: ../../include/conversation.php:1211 +msgid "permissions" +msgstr "permisos " + +#: ../../include/conversation.php:1219 ../../mod/editpost.php:132 +#: ../../mod/editlayout.php:155 ../../mod/editwebpage.php:202 +#: ../../mod/editblock.php:158 +msgid "Public post" +msgstr "Entrada pública" + +#: ../../include/conversation.php:1221 ../../mod/editpost.php:138 +#: ../../mod/editlayout.php:163 ../../mod/editwebpage.php:210 +#: ../../mod/editblock.php:165 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Exemple: bob@example.com, mary@example.com" + +#: ../../include/conversation.php:1234 ../../mod/editpost.php:149 +#: ../../mod/editlayout.php:172 ../../mod/editwebpage.php:219 +#: ../../mod/editblock.php:175 ../../mod/mail.php:245 ../../mod/mail.php:359 +msgid "Set expiration date" +msgstr "Ajusta la data d'expiració" + +#: ../../include/conversation.php:1238 ../../mod/events.php:651 +#: ../../mod/editpost.php:153 +msgid "OK" +msgstr "OK" + +#: ../../include/conversation.php:1239 ../../mod/tagrm.php:11 +#: ../../mod/tagrm.php:134 ../../mod/events.php:650 ../../mod/fbrowser.php:82 +#: ../../mod/fbrowser.php:117 ../../mod/editpost.php:154 +#: ../../mod/settings.php:589 ../../mod/settings.php:615 +msgid "Cancel" +msgstr "Cancel·la" + +#: ../../include/conversation.php:1481 +msgid "Discover" +msgstr "Descobrir" + +#: ../../include/conversation.php:1484 +msgid "Imported public streams" +msgstr "Importar fluxos públics" + +#: ../../include/conversation.php:1489 +msgid "Commented Order" +msgstr "Ordre per Comentaris" + +#: ../../include/conversation.php:1492 +msgid "Sort by Comment Date" +msgstr "Ordenar per Data del Comentari" + +#: ../../include/conversation.php:1496 +msgid "Posted Order" +msgstr "Ordenar per Entrades" + +#: ../../include/conversation.php:1499 +msgid "Sort by Post Date" +msgstr "Ordenar per Data d' Entrada" + +#: ../../include/conversation.php:1507 +msgid "Posts that mention or involve you" +msgstr "Entrades que et mencionen o involucren" + +#: ../../include/conversation.php:1513 ../../mod/connections.php:212 +#: ../../mod/connections.php:225 ../../mod/menu.php:107 +msgid "New" +msgstr "Nou" + +#: ../../include/conversation.php:1516 +msgid "Activity Stream - by date" +msgstr "Activitat del Flux - per data" + +#: ../../include/conversation.php:1522 +msgid "Starred" +msgstr "Preferit" + +#: ../../include/conversation.php:1525 +msgid "Favourite Posts" +msgstr "Entrades Favorites" + +#: ../../include/conversation.php:1532 +msgid "Spam" +msgstr "Spam" + +#: ../../include/conversation.php:1535 +msgid "Posts flagged as SPAM" +msgstr "Entrades marcades com a SPAM" + +#: ../../include/conversation.php:1579 ../../mod/admin.php:993 +msgid "Channel" +msgstr "Canal" + +#: ../../include/conversation.php:1582 +msgid "Status Messages and Posts" +msgstr "Estat dels Missatges i Entrades" + +#: ../../include/conversation.php:1591 +msgid "About" +msgstr "Sobre això" + +#: ../../include/conversation.php:1594 +msgid "Profile Details" +msgstr "Detalls del Perfil" + +#: ../../include/conversation.php:1603 ../../include/photos.php:359 +msgid "Photo Albums" +msgstr "Albums de Fotos" + +#: ../../include/conversation.php:1612 +msgid "Files and Storage" +msgstr "Arxius i Emmagatzegament" + +#: ../../include/conversation.php:1622 ../../include/conversation.php:1625 +msgid "Chatrooms" +msgstr "Sala per Xerrar" + +#: ../../include/conversation.php:1638 +msgid "Saved Bookmarks" +msgstr "Marcadors Guardats" + +#: ../../include/conversation.php:1648 +msgid "Manage Webpages" +msgstr "Gestió de Pàgines Web" + +#: ../../include/conversation.php:1707 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "Assistint" +msgstr[1] "Assistint" + +#: ../../include/conversation.php:1710 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "Desassistint" +msgstr[1] "Desassistint" + +#: ../../include/conversation.php:1713 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] "Indecís" +msgstr[1] "Indecisos" + +#: ../../include/conversation.php:1716 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "Acord" +msgstr[1] "Acords" + +#: ../../include/conversation.php:1719 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "Desacord" +msgstr[1] "Desacords" + +#: ../../include/conversation.php:1722 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "Abstenirse" +msgstr[1] "Abstenirse" + +#: ../../include/items.php:413 ../../mod/like.php:270 +#: ../../mod/subthread.php:49 ../../mod/group.php:68 ../../mod/profperm.php:23 +#: ../../mod/bulksetclose.php:11 ../../index.php:392 +msgid "Permission denied" +msgstr "Permís denegat" + +#: ../../include/items.php:1035 ../../include/items.php:1081 +msgid "(Unknown)" +msgstr "(Desconegut)" + +#: ../../include/items.php:1307 +msgid "Visible to anybody on the internet." +msgstr "Visible per tothom a la Internet" + +#: ../../include/items.php:1309 +msgid "Visible to you only." +msgstr "Visible només per tú." + +#: ../../include/items.php:1311 +msgid "Visible to anybody in this network." +msgstr "Visible per tothom en aquesta xarxa." + +#: ../../include/items.php:1313 +msgid "Visible to anybody authenticated." +msgstr "Visible per tothom autenticat." + +#: ../../include/items.php:1315 +#, php-format +msgid "Visible to anybody on %s." +msgstr "Visible per a tothom a %s." + +#: ../../include/items.php:1317 +msgid "Visible to all connections." +msgstr "Visible per a totes les connexions." + +#: ../../include/items.php:1319 +msgid "Visible to approved connections." +msgstr "Visible per a les connexions aprovades." + +#: ../../include/items.php:1321 +msgid "Visible to specific connections." +msgstr "Visible per a específiques connexions." + +#: ../../include/items.php:4215 ../../mod/thing.php:74 +#: ../../mod/filestorage.php:27 ../../mod/viewsrc.php:20 +#: ../../mod/admin.php:167 ../../mod/admin.php:1025 ../../mod/admin.php:1225 +#: ../../mod/display.php:36 +msgid "Item not found." +msgstr "Element no trobat." + +#: ../../include/items.php:4288 ../../include/attach.php:137 +#: ../../include/attach.php:184 ../../include/attach.php:247 +#: ../../include/attach.php:261 ../../include/attach.php:305 +#: ../../include/attach.php:319 ../../include/attach.php:350 +#: ../../include/attach.php:546 ../../include/attach.php:618 +#: ../../include/chat.php:131 ../../include/photos.php:26 +#: ../../mod/profile.php:64 ../../mod/profile.php:72 +#: ../../mod/achievements.php:30 ../../mod/manage.php:6 ../../mod/api.php:26 +#: ../../mod/api.php:31 ../../mod/webpages.php:69 ../../mod/thing.php:241 +#: ../../mod/thing.php:256 ../../mod/thing.php:290 +#: ../../mod/profile_photo.php:264 ../../mod/profile_photo.php:277 +#: ../../mod/block.php:22 ../../mod/block.php:72 ../../mod/like.php:178 +#: ../../mod/events.php:232 ../../mod/group.php:9 ../../mod/item.php:206 +#: ../../mod/item.php:214 ../../mod/item.php:978 ../../mod/network.php:12 +#: ../../mod/common.php:35 ../../mod/connections.php:169 +#: ../../mod/blocks.php:69 ../../mod/blocks.php:76 ../../mod/editpost.php:13 +#: ../../mod/photos.php:69 ../../mod/pdledit.php:21 ../../mod/authtest.php:13 +#: ../../mod/editlayout.php:63 ../../mod/editlayout.php:87 +#: ../../mod/chat.php:90 ../../mod/chat.php:95 ../../mod/mitem.php:109 +#: ../../mod/editwebpage.php:64 ../../mod/editwebpage.php:86 +#: ../../mod/editwebpage.php:101 ../../mod/editwebpage.php:125 +#: ../../mod/rate.php:110 ../../mod/editblock.php:65 ../../mod/invite.php:13 +#: ../../mod/invite.php:104 ../../mod/locs.php:77 ../../mod/sources.php:66 +#: ../../mod/menu.php:69 ../../mod/filestorage.php:18 +#: ../../mod/filestorage.php:73 ../../mod/filestorage.php:88 +#: ../../mod/filestorage.php:115 ../../mod/fsuggest.php:78 +#: ../../mod/poke.php:128 ../../mod/profiles.php:188 +#: ../../mod/profiles.php:576 ../../mod/viewsrc.php:14 ../../mod/setup.php:223 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +#: ../../mod/register.php:72 ../../mod/settings.php:570 ../../mod/id.php:71 +#: ../../mod/message.php:16 ../../mod/mood.php:111 ../../mod/connedit.php:336 +#: ../../mod/mail.php:114 ../../mod/notifications.php:66 +#: ../../mod/regmod.php:17 ../../mod/new_channel.php:68 +#: ../../mod/new_channel.php:99 ../../mod/appman.php:66 +#: ../../mod/layouts.php:69 ../../mod/layouts.php:76 ../../mod/layouts.php:87 +#: ../../mod/page.php:31 ../../mod/page.php:86 ../../mod/bookmarks.php:46 +#: ../../mod/channel.php:100 ../../mod/channel.php:219 +#: ../../mod/channel.php:262 ../../mod/suggest.php:26 +#: ../../mod/service_limits.php:7 ../../mod/sharedwithme.php:7 +#: ../../index.php:182 ../../index.php:393 +msgid "Permission denied." +msgstr "Permís denegat." + +#: ../../include/items.php:4690 ../../mod/group.php:38 ../../mod/group.php:140 +#: ../../mod/bulksetclose.php:51 +msgid "Collection not found." +msgstr "Col·lecció no trobada." + +#: ../../include/items.php:4706 +msgid "Collection is empty." +msgstr "La col·lecció esta buida." + +#: ../../include/items.php:4713 +#, php-format +msgid "Collection: %s" +msgstr "Col·lecció: %s" + +#: ../../include/items.php:4723 ../../mod/connedit.php:662 +#, php-format +msgid "Connection: %s" +msgstr "Connexió: %s" + +#: ../../include/items.php:4725 +msgid "Connection not found." +msgstr "Connexió no trobada." + +#: ../../include/zot.php:666 +msgid "Invalid data packet" +msgstr "paquet de dades invàlid" + +#: ../../include/zot.php:682 +msgid "Unable to verify channel signature" +msgstr "No es pot verificar la signatura del canal" + +#: ../../include/zot.php:2132 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "No es pot verificar la signatura del lloc per %s" + +#: ../../include/oembed.php:183 +msgid "Embedded content" +msgstr "Contingut embegut" + +#: ../../include/oembed.php:192 +msgid "Embedding disabled" +msgstr "Incorporació desactivada" + +#: ../../include/auth.php:131 +msgid "Logged out." +msgstr "Sortir." + +#: ../../include/auth.php:272 +msgid "Failed authentication" +msgstr "Autenticació fallida" + +#: ../../include/auth.php:286 ../../mod/openid.php:190 +msgid "Login failed." +msgstr "Identificació fallida." + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "%d invitació disponible" +msgstr[1] "%d invitacions disponibles" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:457 +msgid "Advanced" +msgstr "Avançat" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "Troba Canals" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "Entra un nom o interes" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "Conecta/Segueix" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Exemples: Lionel Messi, Futbolista" + +#: ../../include/contact_widgets.php:26 ../../mod/directory.php:379 +#: ../../mod/directory.php:384 ../../mod/connections.php:413 +msgid "Find" +msgstr "Troba" + +#: ../../include/contact_widgets.php:27 ../../mod/directory.php:383 +#: ../../mod/suggest.php:60 +msgid "Channel Suggestions" +msgstr "Canals Suggerits" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "Perfil Aleatori" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "Convida Amics" + +#: ../../include/contact_widgets.php:32 +msgid "Advanced example: name=fred and country=iceland" +msgstr "Exemple avançat: nom=pep i pais=eire" + +#: ../../include/contact_widgets.php:125 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "%d connexió en comú" +msgstr[1] "%d connexions en comú" + +#: ../../include/contact_widgets.php:130 +msgid "show more" +msgstr "mostrar més" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "Visible per a la teva audiència " + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "Mostra" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "No mostrar" + +#: ../../include/acl_selectors.php:248 ../../mod/events.php:668 +#: ../../mod/photos.php:571 ../../mod/photos.php:934 ../../mod/chat.php:209 +#: ../../mod/filestorage.php:147 +msgid "Permissions" +msgstr "Permisos " + +#: ../../include/attach.php:242 ../../include/attach.php:300 +msgid "Item was not found." +msgstr "Article no trobat." + +#: ../../include/attach.php:363 +msgid "No source file." +msgstr "No hi ha arxiu d'origen." + +#: ../../include/attach.php:381 +msgid "Cannot locate file to replace" +msgstr "No trobo l'arxiu a reemplaçar" + +#: ../../include/attach.php:399 +msgid "Cannot locate file to revise/update" +msgstr "No trobo l'arxiu a revisar/actualitzar" + +#: ../../include/attach.php:410 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "L'arxiu excedeix la mida limit de %d" + +#: ../../include/attach.php:422 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "Has arribat al teu límit de %1$.0f Mbytes de emagatzematge d'adjunts." + +#: ../../include/attach.php:505 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "Pujada del arxiu fallida. Possible límit del sistema o acció interrompuda." + +#: ../../include/attach.php:517 +msgid "Stored file could not be verified. Upload failed." +msgstr "L'arxiu guardat no es pot verificar. Pujada fallida." + +#: ../../include/attach.php:561 ../../include/attach.php:578 +msgid "Path not available." +msgstr "Trajectòria no disponible" + +#: ../../include/attach.php:623 +msgid "Empty pathname" +msgstr "Trajèctoria vuida." + +#: ../../include/attach.php:639 +msgid "duplicate filename or path" +msgstr "Nom o trajectòria duplicat" + +#: ../../include/attach.php:663 +msgid "Path not found." +msgstr "Trajectòria no trobada." + +#: ../../include/attach.php:714 +msgid "mkdir failed." +msgstr "mkdir va fracassar." + +#: ../../include/attach.php:718 +msgid "database storage failed." +msgstr "Arxiu de base de dades va fallar." + +#: ../../include/identity.php:33 +msgid "Unable to obtain identity information from database" +msgstr "Incapaç de trobar l'informació d'identitat a la base de dades" + +#: ../../include/identity.php:67 +msgid "Empty name" +msgstr "Nom buit" + +#: ../../include/identity.php:70 +msgid "Name too long" +msgstr "Nom massa llarg" + +#: ../../include/identity.php:186 +msgid "No account identifier" +msgstr "Sense identificador de compte" + +#: ../../include/identity.php:198 +msgid "Nickname is required." +msgstr "Alies/malnom es requerit." + +#: ../../include/identity.php:212 +msgid "Reserved nickname. Please choose another." +msgstr "Àlies reservat. Tria un altre." + +#: ../../include/identity.php:217 ../../include/dimport.php:34 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "L'álies te caracters no soportats o ja esta en ús en aquest lloc" + +#: ../../include/identity.php:292 +msgid "Unable to retrieve created identity" +msgstr "No es pot recuperar la identitat creada" + +#: ../../include/identity.php:350 +msgid "Default Profile" +msgstr "Perfil per Defecte" + +#: ../../include/identity.php:660 +msgid "Requested channel is not available." +msgstr "El canal demanat no està disponible." + +#: ../../include/identity.php:707 ../../mod/profile.php:16 +#: ../../mod/achievements.php:11 ../../mod/webpages.php:29 +#: ../../mod/connect.php:13 ../../mod/hcard.php:8 ../../mod/blocks.php:29 +#: ../../mod/editlayout.php:27 ../../mod/editwebpage.php:28 +#: ../../mod/editblock.php:29 ../../mod/filestorage.php:54 +#: ../../mod/layouts.php:29 +msgid "Requested profile is not available." +msgstr "El perfil demanat no està disponible." + +#: ../../include/identity.php:870 ../../mod/profiles.php:774 +msgid "Change profile photo" +msgstr "Canviar la foto del perfil" + +#: ../../include/identity.php:876 +msgid "Profiles" +msgstr "Perfils" + +#: ../../include/identity.php:876 +msgid "Manage/edit profiles" +msgstr "Gestiona/edita perfils" + +#: ../../include/identity.php:877 ../../mod/profiles.php:775 +msgid "Create New Profile" +msgstr "Crear un Perfil Nou" + +#: ../../include/identity.php:892 ../../mod/profiles.php:786 +msgid "Profile Image" +msgstr "Imatge del Perfil" + +#: ../../include/identity.php:895 +msgid "visible to everybody" +msgstr "visible per tothom" + +#: ../../include/identity.php:896 ../../mod/profiles.php:669 +#: ../../mod/profiles.php:790 +msgid "Edit visibility" +msgstr "Editar visibilitat" + +#: ../../include/identity.php:912 ../../include/identity.php:1151 +msgid "Gender:" +msgstr "Gènere:" + +#: ../../include/identity.php:913 ../../include/identity.php:1195 +msgid "Status:" +msgstr "Estatus:" + +#: ../../include/identity.php:914 ../../include/identity.php:1206 +msgid "Homepage:" +msgstr "Pàgina Personal:" + +#: ../../include/identity.php:915 +msgid "Online Now" +msgstr "Ara en Linia" + +#: ../../include/identity.php:998 ../../include/identity.php:1076 +#: ../../mod/ping.php:324 +msgid "g A l F d" +msgstr "g A l F d" + +#: ../../include/identity.php:999 ../../include/identity.php:1077 +msgid "F d" +msgstr "F d" + +#: ../../include/identity.php:1044 ../../include/identity.php:1116 +#: ../../mod/ping.php:346 +msgid "[today]" +msgstr "[avui]" + +#: ../../include/identity.php:1055 +msgid "Birthday Reminders" +msgstr "Recordatori d'Aniversaris" + +#: ../../include/identity.php:1056 +msgid "Birthdays this week:" +msgstr "Aniversari aquesta setmana:" + +#: ../../include/identity.php:1109 +msgid "[No description]" +msgstr "[Sense descripció]" + +#: ../../include/identity.php:1127 +msgid "Event Reminders" +msgstr "Recordatori d'Events" + +#: ../../include/identity.php:1128 +msgid "Events this week:" +msgstr "Event aquesta setmana:" + +#: ../../include/identity.php:1141 ../../include/identity.php:1258 +#: ../../include/apps.php:138 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "Perfil" + +#: ../../include/identity.php:1149 ../../mod/settings.php:1056 +msgid "Full Name:" +msgstr "Nom Complet:" + +#: ../../include/identity.php:1156 +msgid "Like this channel" +msgstr "M'agrada aquest canal" + +#: ../../include/identity.php:1180 +msgid "j F, Y" +msgstr "j F, Y" + +#: ../../include/identity.php:1181 +msgid "j F" +msgstr "j F" + +#: ../../include/identity.php:1188 +msgid "Birthday:" +msgstr "Aniversari:" + +#: ../../include/identity.php:1192 ../../mod/directory.php:297 +msgid "Age:" +msgstr "Edat:" + +#: ../../include/identity.php:1201 +#, php-format +msgid "for %1$d %2$s" +msgstr "per %1$d %2$s" + +#: ../../include/identity.php:1204 ../../mod/profiles.php:691 +msgid "Sexual Preference:" +msgstr "Preferència Sexual:" + +#: ../../include/identity.php:1208 ../../mod/directory.php:313 +#: ../../mod/profiles.php:693 +msgid "Hometown:" +msgstr "Ciutat Natal:" + +#: ../../include/identity.php:1210 +msgid "Tags:" +msgstr "Etiquetes:" + +#: ../../include/identity.php:1212 ../../mod/profiles.php:694 +msgid "Political Views:" +msgstr "Idees Polítiques:" + +#: ../../include/identity.php:1214 +msgid "Religion:" +msgstr "Religió:" + +#: ../../include/identity.php:1216 ../../mod/directory.php:315 +msgid "About:" +msgstr "Sobre:" + +#: ../../include/identity.php:1218 +msgid "Hobbies/Interests:" +msgstr "Aficions/Interessos:" + +#: ../../include/identity.php:1220 ../../mod/profiles.php:697 +msgid "Likes:" +msgstr "Agrada:" + +#: ../../include/identity.php:1222 ../../mod/profiles.php:698 +msgid "Dislikes:" +msgstr "Desagrada:" + +#: ../../include/identity.php:1224 +msgid "Contact information and Social Networks:" +msgstr "Informació de contacte i Xarxes Socials:" + +#: ../../include/identity.php:1226 +msgid "My other channels:" +msgstr "Els meus altres canals:" + +#: ../../include/identity.php:1228 +msgid "Musical interests:" +msgstr "Interessos Musicals:" + +#: ../../include/identity.php:1230 +msgid "Books, literature:" +msgstr "Llibres, literatura:" + +#: ../../include/identity.php:1232 +msgid "Television:" +msgstr "Televisió:" + +#: ../../include/identity.php:1234 +msgid "Film/dance/culture/entertainment:" +msgstr "Películes/Dança/Cultura/Entreteniment:" + +#: ../../include/identity.php:1236 +msgid "Love/Romance:" +msgstr "Amor/Romace:" + +#: ../../include/identity.php:1238 +msgid "Work/employment:" +msgstr "Treball/feina:" + +#: ../../include/identity.php:1240 +msgid "School/education:" +msgstr "Escola/educació:" + +#: ../../include/identity.php:1260 +msgid "Like this thing" +msgstr "M'agrada això" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:103 +msgid "Male" +msgstr "Masculí" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:105 +msgid "Female" +msgstr "Femení" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Actualment Masculí" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Actualment Femení" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Més aviat Masculí" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Més Aviat Femení" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Canvi de Sexe" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Intersexual" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transsexual" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Hermafrodita" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Neutre" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "Indefinit" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Indecís" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "Homes" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "Dones" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "Gay" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "Lesbianes" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "Sense Preferències" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "Bisexual" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "Autosexual" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "Abstinent" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "Verge" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "Desviat" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "Fetixiste" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "Orgies" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "Asexual" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "Solter" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "Solitari" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "Disponible" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "No Disponible" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "Aplastat" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "Encapritxat" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "Promés" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "Infidel" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "Adicte al Sexe" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "Amics amb Beneficis" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "Casual" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "Ocupat" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "Casat" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "Casat Imaginàriament" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "Parella" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "Cohabitant" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "Tradició" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "Feliç" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "No Cerco" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "Llibertí" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "Traït" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "Separat" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "Inestable" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "Divorciat" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "Divorciat Imaginàriament" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "Vidu/ua" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "Incert" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "Es Complicat" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "No Et Fa Res" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "Pregunta" + +#: ../../include/apps.php:128 +msgid "Site Admin" +msgstr "Administració" + +#: ../../include/apps.php:130 +msgid "Address Book" +msgstr "Adreçes" + +#: ../../include/apps.php:144 ../../mod/mood.php:130 +msgid "Mood" +msgstr "Ànim" + +#: ../../include/apps.php:148 +msgid "Probe" +msgstr "Sondeig" + +#: ../../include/apps.php:149 +msgid "Suggest" +msgstr "Suggeriment" + +#: ../../include/apps.php:150 +msgid "Random Channel" +msgstr "Canal Aleatori" + +#: ../../include/apps.php:151 +msgid "Invite" +msgstr "Convida" + +#: ../../include/apps.php:152 +msgid "Features" +msgstr "Funcionalitats" + +#: ../../include/apps.php:153 ../../mod/id.php:28 +msgid "Language" +msgstr "Idioma" + +#: ../../include/apps.php:154 +msgid "Post" +msgstr "Entrada" + +#: ../../include/apps.php:155 ../../mod/id.php:17 ../../mod/id.php:18 +#: ../../mod/id.php:19 +msgid "Profile Photo" +msgstr "Foto del Perfil" + +#: ../../include/apps.php:247 ../../mod/settings.php:84 +#: ../../mod/settings.php:614 +msgid "Update" +msgstr "Actualització" + +#: ../../include/apps.php:247 +msgid "Install" +msgstr "Instal·lar" + +#: ../../include/apps.php:252 +msgid "Purchase" +msgstr "Compra" + +#: ../../include/bbcode.php:122 ../../include/bbcode.php:768 +#: ../../include/bbcode.php:771 ../../include/bbcode.php:776 +#: ../../include/bbcode.php:779 ../../include/bbcode.php:782 +#: ../../include/bbcode.php:785 ../../include/bbcode.php:790 +#: ../../include/bbcode.php:793 ../../include/bbcode.php:798 +#: ../../include/bbcode.php:801 ../../include/bbcode.php:804 +#: ../../include/bbcode.php:807 +msgid "Image/photo" +msgstr "Imatge/foto" + +#: ../../include/bbcode.php:161 ../../include/bbcode.php:818 +msgid "Encrypted content" +msgstr "Contingut encriptat" + +#: ../../include/bbcode.php:178 +#, php-format +msgid "Install %s element: " +msgstr "Instal·la l'element %s:" + +#: ../../include/bbcode.php:182 +#, php-format +msgid "" +"This post contains an installable %s element, however you lack permissions " +"to install it on this site." +msgstr "Aquesta entrada contè un element %s instal·lable, potser manques de permissos per instal·lar-lo en aquest lloc." + +#: ../../include/bbcode.php:192 ../../mod/impel.php:37 +msgid "webpage" +msgstr "pàgina web" + +#: ../../include/bbcode.php:195 ../../mod/impel.php:47 +msgid "layout" +msgstr "disposició" + +#: ../../include/bbcode.php:198 ../../mod/impel.php:42 +msgid "block" +msgstr "bloc" + +#: ../../include/bbcode.php:201 ../../mod/impel.php:54 +msgid "menu" +msgstr "menú" + +#: ../../include/bbcode.php:215 +msgid "QR code" +msgstr "QR code" + +#: ../../include/bbcode.php:266 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "%1$s va escriure el següent %2$s %3$s" + +#: ../../include/bbcode.php:268 ../../mod/tagger.php:51 +msgid "post" +msgstr "entrada" + +#: ../../include/bbcode.php:518 +msgid "Different viewers will see this text differently" +msgstr "Diferents observadors veuran aquest text de diferents formes" + +#: ../../include/bbcode.php:729 +msgid "$1 spoiler" +msgstr "$1 spoiler" + +#: ../../include/bbcode.php:756 +msgid "$1 wrote:" +msgstr "$1 va escriure:" + +#: ../../include/chat.php:23 +msgid "Missing room name" +msgstr "Perdut el nom de la sala" + +#: ../../include/chat.php:32 +msgid "Duplicate room name" +msgstr "Nom de la sala duplicat" + +#: ../../include/chat.php:82 ../../include/chat.php:90 +msgid "Invalid room specifier." +msgstr "Especificació de la sala invàlida." + +#: ../../include/chat.php:120 +msgid "Room not found." +msgstr "Sala no trobada." + +#: ../../include/chat.php:141 +msgid "Room is full" +msgstr "La sala es plena" + +#: ../../include/photos.php:94 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "La imatge excedeix la mida limit pel lloc web en %lu bytes" + +#: ../../include/photos.php:101 +msgid "Image file is empty." +msgstr "El fitxer d'imatge esta buit." + +#: ../../include/photos.php:128 ../../mod/profile_photo.php:217 +msgid "Unable to process image" +msgstr "incapaç de processar la imatge" + +#: ../../include/photos.php:199 +msgid "Photo storage failed." +msgstr "Fracassà l'emmagatzematge de la Foto" + +#: ../../include/photos.php:363 +msgid "Upload New Photos" +msgstr "Puja Noves Fotos" + +#: ../../mod/achievements.php:34 +msgid "Some blurb about what to do when you're new here" +msgstr "Algunes propostes sobre el que cal fer quan ets nou aquí" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "Has creat %1$.0f de %2$.0f canals permesos." + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "Crear un nou canal" + +#: ../../mod/manage.php:167 +msgid "Current Channel" +msgstr "Canal Actual" + +#: ../../mod/manage.php:169 +msgid "Switch to one of your channels by selecting it." +msgstr "Canviar a un altre dels teus canals seleccionant-ho." + +#: ../../mod/manage.php:170 +msgid "Default Channel" +msgstr "Canal per Defecte" + +#: ../../mod/manage.php:171 +msgid "Make Default" +msgstr "Estableix com a Predeterminat" + +#: ../../mod/manage.php:174 +#, php-format +msgid "%d new messages" +msgstr "%d missatges nous" + +#: ../../mod/manage.php:175 +#, php-format +msgid "%d new introductions" +msgstr "%d noves presentacions" + +#: ../../mod/manage.php:177 +msgid "Delegated Channels" +msgstr "Canals Delegats" + +#: ../../mod/directory.php:59 ../../mod/photos.php:441 ../../mod/search.php:13 +#: ../../mod/ratings.php:82 ../../mod/viewconnections.php:17 +#: ../../mod/display.php:13 +msgid "Public access denied." +msgstr "Accés públic denegat." + +#: ../../mod/directory.php:234 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "%d valoració" +msgstr[1] "%d valoracions" + +#: ../../mod/directory.php:245 +msgid "Gender: " +msgstr "Gènere:" + +#: ../../mod/directory.php:247 +msgid "Status: " +msgstr "Estatus:" + +#: ../../mod/directory.php:249 +msgid "Homepage: " +msgstr "Pàgina Personal:" + +#: ../../mod/directory.php:308 ../../mod/events.php:659 +msgid "Description:" +msgstr "Descripció:" + +#: ../../mod/directory.php:317 +msgid "Public Forum:" +msgstr "Forum Públic:" + +#: ../../mod/directory.php:320 +msgid "Keywords: " +msgstr "Paraules Clau:" + +#: ../../mod/directory.php:323 +msgid "Don't suggest" +msgstr "No suggerir" + +#: ../../mod/directory.php:325 +msgid "Common connections:" +msgstr "Connexions en comú:" + +#: ../../mod/directory.php:374 +msgid "Global Directory" +msgstr "Directori Global" + +#: ../../mod/directory.php:374 +msgid "Local Directory" +msgstr "Directori Local" + +#: ../../mod/directory.php:380 +msgid "Finding:" +msgstr "Cercant:" + +#: ../../mod/directory.php:385 +msgid "next page" +msgstr "pàgina següent" + +#: ../../mod/directory.php:385 +msgid "previous page" +msgstr "pàgina anterior" + +#: ../../mod/directory.php:386 +msgid "Sort options" +msgstr "Opcions per ordenar" + +#: ../../mod/directory.php:387 +msgid "Alphabetic" +msgstr "Alfabètic" + +#: ../../mod/directory.php:388 +msgid "Reverse Alphabetic" +msgstr "Alfabètic Invers" + +#: ../../mod/directory.php:389 +msgid "Newest to Oldest" +msgstr "De més Nou a més Vell" + +#: ../../mod/directory.php:390 +msgid "Oldest to Newest" +msgstr "De més Antic a més Nou" + +#: ../../mod/directory.php:407 +msgid "No entries (some entries may be hidden)." +msgstr "Sense entrades (algunes podrien estar amagades)." + +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +msgstr "Cerca a xchan" + +#: ../../mod/xchan.php:9 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "Cerca a xchan començant per (o webbie)" + +#: ../../mod/xchan.php:37 ../../mod/mitem.php:114 ../../mod/menu.php:156 +msgid "Not found." +msgstr "No trobat." + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Autoritza la connexió de l'aplicació" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Torna a la teva aplicació i insereix aquest Codi de Seguretat:" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Si et plau, identifica't per continuar." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Vols autoritzar a aquesta aplicació l'accés a les teves entrades i contactes i/o a crear noves entrades com si fos tu mateix." + +#: ../../mod/webpages.php:191 +msgid "Page Title" +msgstr "Títol de la pàgina" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "S'ha afegit el canal." + +#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94 +msgid "Tag removed" +msgstr "S'ha tret l'etiqueta" + +#: ../../mod/tagrm.php:119 +msgid "Remove Item Tag" +msgstr "Elimina l'etiqueta d'element" + +#: ../../mod/tagrm.php:121 +msgid "Select a tag to remove: " +msgstr "Tria l'etiqueta a eliminar:" + +#: ../../mod/tagrm.php:133 ../../mod/photos.php:887 +msgid "Remove" +msgstr "Esborra" + +#: ../../mod/connect.php:56 ../../mod/connect.php:104 +msgid "Continue" +msgstr "Continua" + +#: ../../mod/connect.php:85 +msgid "Premium Channel Setup" +msgstr "Configuració de Canals Premium" + +#: ../../mod/connect.php:87 +msgid "Enable premium channel connection restrictions" +msgstr "Habilita les restriccions de connexió del canal premium" + +#: ../../mod/connect.php:88 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "Si us plau, introdueixi les restriccions o condicions, com ara el rebut de PayPal, les pautes d'ús, etc." + +#: ../../mod/connect.php:90 ../../mod/connect.php:110 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "Aquest canal pot requerir passos addicionals o reconeixement de les següents condicions abans de connectar:" + +#: ../../mod/connect.php:91 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "Connexions potencials veuran el següent text abans de continuar:" + +#: ../../mod/connect.php:92 ../../mod/connect.php:113 +msgid "" +"By continuing, I certify that I have complied with any instructions provided" +" on this page." +msgstr "En continuar, certifico que he complert amb totes les instruccions proporcionades en aquesta pàgina." + +#: ../../mod/connect.php:101 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "(No s'han proporcionat instruccions específiques pel propietari del canal.)" + +#: ../../mod/connect.php:109 +msgid "Restricted or Premium Channel" +msgstr "Canal Restringit o Premium" + +#: ../../mod/thing.php:94 +msgid "Thing updated" +msgstr "S'ha actualitzat la cosa" + +#: ../../mod/thing.php:153 +msgid "Object store: failed" +msgstr "No s'ha pogut emmagatzemar l'objecte" + +#: ../../mod/thing.php:157 +msgid "Thing added" +msgstr "S'ha afegit la cosa" + +#: ../../mod/thing.php:175 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "OBJ: %1$s %2$s %3$s" + +#: ../../mod/thing.php:226 +msgid "Show Thing" +msgstr "Mostra la cosa" + +#: ../../mod/thing.php:233 +msgid "item not found." +msgstr "no s'ha trobat l'element." + +#: ../../mod/thing.php:261 +msgid "Edit Thing" +msgstr "Edita la cosa" + +#: ../../mod/thing.php:263 ../../mod/thing.php:310 +msgid "Select a profile" +msgstr "Tria un perfil" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Post an activity" +msgstr "Publica una activitat" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Only sends to viewers of the applicable profile" +msgstr "S'envia només a visitants del perfil corresponent" + +#: ../../mod/thing.php:269 ../../mod/thing.php:315 +msgid "Name of thing e.g. something" +msgstr "Nom de la cosa. Exemple: patata" + +#: ../../mod/thing.php:271 ../../mod/thing.php:316 +msgid "URL of thing (optional)" +msgstr "Adreça URL de la cosa (opcional)" + +#: ../../mod/thing.php:273 ../../mod/thing.php:317 +msgid "URL for photo of thing (optional)" +msgstr "Adreça URL de la foto d'una cosa (opcional)" + +#: ../../mod/thing.php:308 +msgid "Add Thing to your Profile" +msgstr "Afegeix una cosa al teu perfil" + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "Article no disponible." + +#: ../../mod/probe.php:24 ../../mod/probe.php:30 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "URL sol·licitada retorna error: %1$s" + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "S'ha pujat la imatge però no s'ha pogut retallar." + +#: ../../mod/profile_photo.php:162 +msgid "Image resize failed." +msgstr "No s'ha pogut escalar la imatge." + +#: ../../mod/profile_photo.php:206 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Refresca la memòria cau del navegador si la foto no s'actualitza immediatament. Dreceres: «Ctrl+F5» i «Ctrl+Maj+R»" + +#: ../../mod/profile_photo.php:233 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "La imatge excedeix la mida límit de %d" + +#: ../../mod/profile_photo.php:242 +msgid "Unable to process image." +msgstr "Incapaç de processar l'imatge." + +#: ../../mod/profile_photo.php:291 ../../mod/profile_photo.php:340 +msgid "Photo not available." +msgstr "Foto no disponible." + +#: ../../mod/profile_photo.php:359 +msgid "Upload File:" +msgstr "Puja Arxiu:" + +#: ../../mod/profile_photo.php:360 +msgid "Select a profile:" +msgstr "Tria un perfil:" + +#: ../../mod/profile_photo.php:361 +msgid "Upload Profile Photo" +msgstr "Puja una Foto pel Perfil" + +#: ../../mod/profile_photo.php:366 ../../mod/settings.php:995 +msgid "or" +msgstr "o" + +#: ../../mod/profile_photo.php:366 +msgid "skip this step" +msgstr "salta aquest pas" + +#: ../../mod/profile_photo.php:366 +msgid "select a photo from your photo albums" +msgstr "tria una foto del teu àlbum de fotos" + +#: ../../mod/profile_photo.php:382 +msgid "Crop Image" +msgstr "Retalla Imatge" + +#: ../../mod/profile_photo.php:383 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Si us plau, retalla la imatge per a una optima visualització" + +#: ../../mod/profile_photo.php:385 +msgid "Done Editing" +msgstr "Edició Feta" + +#: ../../mod/profile_photo.php:428 +msgid "Image uploaded successfully." +msgstr "Imatge pujada exitosament." + +#: ../../mod/profile_photo.php:430 +msgid "Image upload failed." +msgstr "La pujada de la imatge va fracassar." + +#: ../../mod/profile_photo.php:439 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "La reducció de mida de la imatge [%s] va fracassar." + +#: ../../mod/block.php:27 ../../mod/page.php:36 +msgid "Invalid item." +msgstr "Article invàlid." + +#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:52 +msgid "Channel not found." +msgstr "Canal no trobat." + +#: ../../mod/block.php:75 ../../mod/display.php:110 ../../mod/help.php:79 +#: ../../mod/page.php:89 ../../index.php:241 +msgid "Page not found." +msgstr "Pàgina no trobada." + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "M'agrada / No m'agrada" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "Aquesta acció està restringida als membres." + +#: ../../mod/like.php:21 +msgid "" +"Please login with your $Projectname ID or register as a new $Projectname member to continue." +msgstr "Entra amb la teva identitat $Projectname o registra't a $Projectname per continuar." + +#: ../../mod/like.php:101 ../../mod/like.php:128 ../../mod/like.php:166 +msgid "Invalid request." +msgstr "Sol·licitud invàlida." + +#: ../../mod/like.php:143 +msgid "thing" +msgstr "cosa" + +#: ../../mod/like.php:189 +msgid "Channel unavailable." +msgstr "El canal està inactiu." + +#: ../../mod/like.php:228 +msgid "Previous action reversed." +msgstr "S'ha desfet l'acció anterior." + +#: ../../mod/like.php:398 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" +msgstr "%1$s està d'acord amb %3$s de %2$s" + +#: ../../mod/like.php:400 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" +msgstr "%1$s no està d'acord amb %3$s de %2$s" + +#: ../../mod/like.php:402 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" +msgstr "%1$s s'abstén en %3$s de %2$s" + +#: ../../mod/like.php:404 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "%1$s assistirà a %3$s de %2$s" + +#: ../../mod/like.php:406 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "%1$s no assistirà a %3$s de %2$s" + +#: ../../mod/like.php:408 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "%1$s potser assistirà a %3$s de %2$s" + +#: ../../mod/like.php:492 +msgid "Action completed." +msgstr "S'ha completat l'acció." + +#: ../../mod/like.php:493 +msgid "Thank you." +msgstr "Gràcies." + +#: ../../mod/events.php:21 +msgid "Calendar entries imported." +msgstr "Entrades de Calendari importades." + +#: ../../mod/events.php:23 +msgid "No calendar entries found." +msgstr "No es troben entrades decalendari." + +#: ../../mod/events.php:101 +msgid "Event can not end before it has started." +msgstr "L'esdeveniment ha de començar abans d'acabar." + +#: ../../mod/events.php:103 ../../mod/events.php:112 ../../mod/events.php:130 +msgid "Unable to generate preview." +msgstr "No s'ha pogut generar la vista prèvia." + +#: ../../mod/events.php:110 +msgid "Event title and start time are required." +msgstr "Cal indicar l'inici i el final de l'esdeveniment." + +#: ../../mod/events.php:128 +msgid "Event not found." +msgstr "No s'ha trobat l'esdeveniment." + +#: ../../mod/events.php:409 +msgid "l, F j" +msgstr "l, F j" + +#: ../../mod/events.php:431 +msgid "Edit event" +msgstr "Edita l'esdeveniment" + +#: ../../mod/events.php:432 +msgid "Delete event" +msgstr "Esborra l'esdeveniment" + +#: ../../mod/events.php:466 +msgid "calendar" +msgstr "calendari" + +#: ../../mod/events.php:487 +msgid "Create New Event" +msgstr "Crea un esdeveniment nou" + +#: ../../mod/events.php:488 ../../mod/photos.php:839 +msgid "Previous" +msgstr "Anterior" + +#: ../../mod/events.php:489 ../../mod/photos.php:848 ../../mod/setup.php:281 +msgid "Next" +msgstr "Pròxim" + +#: ../../mod/events.php:490 +msgid "Export" +msgstr "Exporta" + +#: ../../mod/events.php:493 +msgid "Import" +msgstr "Importar" + +#: ../../mod/events.php:518 +msgid "Event removed" +msgstr "S'ha eliminat l'esdeveniment" + +#: ../../mod/events.php:521 +msgid "Failed to remove event" +msgstr "No s'ha pogut esborrar l'esdeveniment" + +#: ../../mod/events.php:641 +msgid "Event details" +msgstr "Detalls de l'esdeveniment" + +#: ../../mod/events.php:642 +msgid "Starting date and Title are required." +msgstr "La data d'inici i el títol són obligatoris." + +#: ../../mod/events.php:644 +msgid "Categories (comma-separated list)" +msgstr "Categories (llista separada per comes)" + +#: ../../mod/events.php:646 +msgid "Event Starts:" +msgstr "Inici:" + +#: ../../mod/events.php:653 +msgid "Finish date/time is not known or not relevant" +msgstr "La data i hora de final no és coneguda o irrellevant" + +#: ../../mod/events.php:655 +msgid "Event Finishes:" +msgstr "Final:" + +#: ../../mod/events.php:657 ../../mod/events.php:658 +msgid "Adjust for viewer timezone" +msgstr "Ajusta a la zona horària del visitant." + +#: ../../mod/events.php:657 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." +msgstr "És important per esdeveniments locals, però pels globals no és pràctic." + +#: ../../mod/events.php:663 +msgid "Title:" +msgstr "Títol:" + +#: ../../mod/events.php:665 +msgid "Share this event" +msgstr "Comparteix aquest esdeveniment" + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "%1$s esta seguint %2$s de %3$s" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "Llocs públics" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration for the $Projectname network. All" +" sites in the network are interlinked so membership on any of them conveys " +"membership in the network as a whole. Some sites may require subscription or" +" provide tiered service plans. The provider links may " +"provide additional details." +msgstr "Els llocs llistats permeten registrar usuaris de la xarxa $Projectname. Com que tots els llocs estan enllaçats entre ells, la identitat és vàlida a tota la xarxa. Alguns llocs poden demanar subscripció o oferir serveis addicional de pagament. Per a més detalls, proveu de seguir els enllaços dels proveïdors." + +#: ../../mod/pubsites.php:25 +msgid "Rate this hub" +msgstr "Valora aquest hub" + +#: ../../mod/pubsites.php:26 +msgid "Site URL" +msgstr "Adreça URL del web" + +#: ../../mod/pubsites.php:26 +msgid "Access Type" +msgstr "Tipus d'accés" + +#: ../../mod/pubsites.php:26 +msgid "Registration Policy" +msgstr "Condicions de registre" + +#: ../../mod/pubsites.php:26 ../../mod/profiles.php:454 +msgid "Location" +msgstr "Localització" + +#: ../../mod/pubsites.php:26 +msgid "View hub ratings" +msgstr "Mostra la valoració del hub" + +#: ../../mod/pubsites.php:30 +msgid "Rate" +msgstr "Puntua" + +#: ../../mod/pubsites.php:31 +msgid "View ratings" +msgstr "Mostra les valoracions" + +#: ../../mod/rpost.php:131 ../../mod/editpost.php:158 +msgid "Edit post" +msgstr "Modifica l'entrada" + +#: ../../mod/dav.php:121 +msgid "$Projectname channel" +msgstr "Canal de $Projectname" + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "Creada una col·lecció" + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "No puc crear la col·lecció." + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "Col·lecció actualitzada." + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "Creada una col·lecció de canals." + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "Nom de la Col·lecció:" + +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "Els membres son visibles en altres canals" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "Col·lecció esborrada." + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "Incapaç d'esborrar la col·lecció." + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "Editor de Col·leccions" + +#: ../../mod/group.php:196 ../../mod/bulksetclose.php:89 +msgid "Members" +msgstr "Membres" + +#: ../../mod/group.php:198 ../../mod/bulksetclose.php:91 +msgid "All Connected Channels" +msgstr "Tots els Canals Connectats" + +#: ../../mod/group.php:233 ../../mod/bulksetclose.php:126 +msgid "Click on a channel to add or remove." +msgstr "Clic sobre el canal per afegir o esborrar." + +#: ../../mod/siteinfo.php:112 +#, php-format +msgid "Version %s" +msgstr "Versió %s" + +#: ../../mod/siteinfo.php:133 +msgid "Installed plugins/addons/apps:" +msgstr "Plugins/addons/apps Instal·lats:" + +#: ../../mod/siteinfo.php:146 +msgid "No installed plugins/addons/apps" +msgstr "Plugins/addons/apps no instal·lats" + +#: ../../mod/siteinfo.php:155 ../../mod/home.php:58 ../../mod/home.php:64 +msgid "$Projectname" +msgstr "$Projectname" + +#: ../../mod/siteinfo.php:156 +msgid "" +"This is a hub of $Projectname - a global cooperative network of " +"decentralized privacy enhanced websites." +msgstr "Aquest és un hub de $Projectname, una xarxa cooperativa mundial de llocs web descentralitzats amb gran control de la privacitat." + +#: ../../mod/siteinfo.php:158 +msgid "Tag: " +msgstr "Etiqueta:" + +#: ../../mod/siteinfo.php:160 +msgid "Last background fetch: " +msgstr "Última actualització en rerefons:" + +#: ../../mod/siteinfo.php:163 +msgid "Running at web location" +msgstr "Correguent en el lloc web" + +#: ../../mod/siteinfo.php:164 +msgid "" +"Please visit redmatrix.me to learn more" +" about $Projectname." +msgstr "Ves a redmatrix.me per saber-ne més sobre $Projectname." + +#: ../../mod/siteinfo.php:165 +msgid "Bug reports and issues: please visit" +msgstr "Per informar d'errors o problemes ves a" + +#: ../../mod/siteinfo.php:167 +msgid "$projectname issues" +msgstr "$projectname emisions" + +#: ../../mod/siteinfo.php:168 +msgid "" +"Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot " +"com" +msgstr "Per suggerències, felicitacions i altres, envia'ns un mail a «redmatrix» [arroba] librelist [punt] com" + +#: ../../mod/siteinfo.php:170 +msgid "Site Administrators" +msgstr "Administradors del lloc" + +#: ../../mod/item.php:174 +msgid "Unable to locate original post." +msgstr "No s'ha pogut trobar l'entrada original." + +#: ../../mod/item.php:440 +msgid "Empty post discarded." +msgstr "S'ha descartat l'entrada perquè no té contingut." + +#: ../../mod/item.php:480 +msgid "Executable content type not permitted to this channel." +msgstr "No està permès el contingut de tipus executable en aquest canal." + +#: ../../mod/item.php:901 +msgid "System error. Post not saved." +msgstr "Hi ha hagut un error del sistema. L'entrada no s'ha desat." + +#: ../../mod/item.php:1119 +msgid "Unable to obtain post information from database." +msgstr "No s'ha pogut obtenir informació de l'entrada a la base de dades." + +#: ../../mod/item.php:1126 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "Has assolit el teu límit de %1$.0f entrades (descomptant comentaris)." + +#: ../../mod/item.php:1133 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "Has assolit el teu limit de %1$.0f pàgines web." + +#: ../../mod/network.php:91 +msgid "No such group" +msgstr "No existeix el grup" + +#: ../../mod/network.php:129 +msgid "No such channel" +msgstr "No existeix el canal" + +#: ../../mod/network.php:143 +msgid "Search Results For:" +msgstr "Cerca resultats per:" + +#: ../../mod/network.php:198 +msgid "Collection is empty" +msgstr "La coÅ€lecció és buida" + +#: ../../mod/network.php:207 +msgid "Collection: " +msgstr "CoÅ€lecció:" + +#: ../../mod/network.php:226 +msgid "Connection: " +msgstr "Connexió:" + +#: ../../mod/network.php:233 +msgid "Invalid connection." +msgstr "La connexió és invàlida." + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "No s'ha trobat el canal" + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "Connexions en comú" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "No hi ha connexions en comú." + +#: ../../mod/regdir.php:45 ../../mod/dirsearch.php:21 +msgid "This site is not a directory server" +msgstr "Aquest lloc web no és un servidor de directori" + +#: ../../mod/connections.php:37 ../../mod/connedit.php:75 +msgid "Could not access contact record." +msgstr "No s'ha pogut accedir al llibre de contactes." + +#: ../../mod/connections.php:51 ../../mod/connedit.php:99 +msgid "Could not locate selected profile." +msgstr "No s'ha trobat el perfil indicat." + +#: ../../mod/connections.php:94 ../../mod/connedit.php:219 +msgid "Connection updated." +msgstr "S'ha actualitzat la connexió." + +#: ../../mod/connections.php:96 ../../mod/connedit.php:221 +msgid "Failed to update connection record." +msgstr "No s'ha pogut actualitzar el registre de connexió." + +#: ../../mod/connections.php:192 ../../mod/connections.php:293 +msgid "Blocked" +msgstr "Bloquejades" + +#: ../../mod/connections.php:197 ../../mod/connections.php:300 +msgid "Ignored" +msgstr "Ignorades" + +#: ../../mod/connections.php:202 ../../mod/connections.php:314 +msgid "Hidden" +msgstr "Amagades" + +#: ../../mod/connections.php:207 ../../mod/connections.php:307 +msgid "Archived" +msgstr "Arxivades" + +#: ../../mod/connections.php:271 +msgid "Suggest new connections" +msgstr "Suggereix noves connexions" + +#: ../../mod/connections.php:274 +msgid "New Connections" +msgstr "Noves Connexions" + +#: ../../mod/connections.php:277 +msgid "Show pending (new) connections" +msgstr "Mostra les connexions pendents (noves)" + +#: ../../mod/connections.php:280 ../../mod/profperm.php:139 +msgid "All Connections" +msgstr "Totes les Connexions" + +#: ../../mod/connections.php:283 +msgid "Show all connections" +msgstr "Mostra totes les connexions" + +#: ../../mod/connections.php:286 +msgid "Unblocked" +msgstr "No bloquejades" + +#: ../../mod/connections.php:289 +msgid "Only show unblocked connections" +msgstr "Mostra només les connexions no bloquejades" + +#: ../../mod/connections.php:296 +msgid "Only show blocked connections" +msgstr "Mostra només les connexions bloquejades" + +#: ../../mod/connections.php:303 +msgid "Only show ignored connections" +msgstr "Mostra només les connexions ignorades" + +#: ../../mod/connections.php:310 +msgid "Only show archived connections" +msgstr "Mostra només les connexions arxivades" + +#: ../../mod/connections.php:317 +msgid "Only show hidden connections" +msgstr "Mostra només les connexions amagades" + +#: ../../mod/connections.php:372 +#, php-format +msgid "%1$s [%2$s]" +msgstr "%1$s [%2$s]" + +#: ../../mod/connections.php:373 +msgid "Edit connection" +msgstr "Modifica la connexió" + +#: ../../mod/connections.php:411 +msgid "Search your connections" +msgstr "Cerca entre les teves connexions" + +#: ../../mod/connections.php:412 +msgid "Finding: " +msgstr "Cercant:" + +#: ../../mod/blocks.php:95 ../../mod/blocks.php:148 +msgid "Block Name" +msgstr "Nom del Bloc" + +#: ../../mod/blocks.php:149 +msgid "Block Title" +msgstr "Títol del bloc" + +#: ../../mod/editpost.php:20 ../../mod/editlayout.php:76 +#: ../../mod/editwebpage.php:77 ../../mod/editblock.php:78 +#: ../../mod/editblock.php:94 +msgid "Item not found" +msgstr "No s'ha trobat l'element" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "Article no editable" + +#: ../../mod/editpost.php:48 +msgid "Delete item?" +msgstr "Esborrar ítem" + +#: ../../mod/editpost.php:115 ../../mod/editlayout.php:142 +#: ../../mod/editwebpage.php:187 ../../mod/editblock.php:144 +msgid "Insert YouTube video" +msgstr "insereix video YouTube" + +#: ../../mod/editpost.php:116 ../../mod/editlayout.php:143 +#: ../../mod/editwebpage.php:188 ../../mod/editblock.php:145 +msgid "Insert Vorbis [.ogg] video" +msgstr "Insereix video Vorbis [.ogg]" + +#: ../../mod/editpost.php:117 ../../mod/editlayout.php:144 +#: ../../mod/editwebpage.php:189 ../../mod/editblock.php:146 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Insereix audio Vorbis [.ogg]" + +#: ../../mod/cloud.php:120 +msgid "$Projectname - Guests: Username: {your email address}, Password: +++" +msgstr "$Projectname - Convidats: Nom d'usuari: {el teu correu electrònic}, Contrasenya: +++" + +#: ../../mod/photos.php:78 +msgid "Page owner information could not be retrieved." +msgstr "La informació del propietari de la pàgina no va poder ser recuperada" + +#: ../../mod/photos.php:98 +msgid "Album not found." +msgstr "Àlbum no trobat" + +#: ../../mod/photos.php:120 ../../mod/photos.php:655 +msgid "Delete Album" +msgstr "Esborra Àlbum" + +#: ../../mod/photos.php:160 ../../mod/photos.php:942 +msgid "Delete Photo" +msgstr "Esborra Foto" + +#: ../../mod/photos.php:452 +msgid "No photos selected" +msgstr "No has seleccionat fotos" + +#: ../../mod/photos.php:496 +msgid "Access to this item is restricted." +msgstr "L'accés a aquest element esta restringit." + +#: ../../mod/photos.php:535 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgstr "S'estan fent servir %1$.2f MB de %2$.2f MB de l'espai per a imatges." + +#: ../../mod/photos.php:538 +#, php-format +msgid "%1$.2f MB photo storage used." +msgstr "S'estan fent servir %1$.2f MB de l'espai per a imatges." + +#: ../../mod/photos.php:562 +msgid "Upload Photos" +msgstr "Puja imatges" + +#: ../../mod/photos.php:566 ../../mod/photos.php:648 ../../mod/photos.php:927 +msgid "Enter a new album name" +msgstr "Escriu el nom del nou àlbum" + +#: ../../mod/photos.php:567 ../../mod/photos.php:649 ../../mod/photos.php:928 +msgid "or select an existing one (doubleclick)" +msgstr "o bé fes doble clic a un d'existent" + +#: ../../mod/photos.php:568 +msgid "Create a status post for this upload" +msgstr "Genera una entrada a partir de la pujada" + +#: ../../mod/photos.php:596 +msgid "Album name could not be decoded" +msgstr "No s'ha pogut descodificar el nom de l'àlbum" + +#: ../../mod/photos.php:637 ../../mod/photos.php:1169 +#: ../../mod/photos.php:1185 +msgid "Contact Photos" +msgstr "Imatges de contactes" + +#: ../../mod/photos.php:661 +msgid "Show Newest First" +msgstr "Ordena de més nou a més antic" + +#: ../../mod/photos.php:663 +msgid "Show Oldest First" +msgstr "Ordena de més antic a més nou" + +#: ../../mod/photos.php:687 ../../mod/photos.php:1217 +msgid "View Photo" +msgstr "Mostra la imatge" + +#: ../../mod/photos.php:716 +msgid "Edit Album" +msgstr "Modifica l'àlbum" + +#: ../../mod/photos.php:761 +msgid "Permission denied. Access to this item may be restricted." +msgstr "S'ha denegat el permís. Pot ser que l'accés estigui restringit." + +#: ../../mod/photos.php:763 +msgid "Photo not available" +msgstr "La imatge no està disponible" + +#: ../../mod/photos.php:821 +msgid "Use as profile photo" +msgstr "Fes-la imatge de perfil" + +#: ../../mod/photos.php:828 +msgid "Private Photo" +msgstr "Imatge privada" + +#: ../../mod/photos.php:843 +msgid "View Full Size" +msgstr "Mostra a mida completa" + +#: ../../mod/photos.php:921 +msgid "Edit photo" +msgstr "Modifica la imatge" + +#: ../../mod/photos.php:923 +msgid "Rotate CW (right)" +msgstr "Tomba cap a la dreta" + +#: ../../mod/photos.php:924 +msgid "Rotate CCW (left)" +msgstr "Tomba cap a l'esquerra" + +#: ../../mod/photos.php:931 +msgid "Caption" +msgstr "Llegenda" + +#: ../../mod/photos.php:933 +msgid "Add a Tag" +msgstr "Afegeix una etiqueta" + +#: ../../mod/photos.php:937 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +msgstr "Exemple: @joan, @Paula_Peris, @mar@exemple.org" + +#: ../../mod/photos.php:940 +msgid "Flag as adult in album view" +msgstr "Marca com a contingut adult" + +#: ../../mod/photos.php:1132 +msgid "In This Photo:" +msgstr "Hi apareixen:" + +#: ../../mod/photos.php:1137 +msgid "Map" +msgstr "Mapa" + +#: ../../mod/photos.php:1223 +msgid "View Album" +msgstr "Mostra'n l'àlbum" + +#: ../../mod/photos.php:1246 +msgid "Recent Photos" +msgstr "Imatges recents" + +#: ../../mod/search.php:206 +#, php-format +msgid "Items tagged with: %s" +msgstr "Elements etiquetats amb: %s" + +#: ../../mod/search.php:208 +#, php-format +msgid "Search results for: %s" +msgstr "Resultats de cerca per: %s" + +#: ../../mod/match.php:22 +msgid "Profile Match" +msgstr "Perfils compatibles" + +#: ../../mod/match.php:31 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "No tens paraules clau al perfil principal per poder cercar perfils semblants." + +#: ../../mod/match.php:63 +msgid "is interested in:" +msgstr "té interès en:" + +#: ../../mod/match.php:70 +msgid "No matches" +msgstr "No s'han trobat perfils compatibles" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "Absent" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "En connexió" + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "Tria una carpeta d'interès" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "Guarda Favorits" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "URL de favorit" + +#: ../../mod/rbmark.php:95 ../../mod/appman.php:93 +msgid "Description" +msgstr "Descripció" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "O entra un nou nom de favorit" + +#: ../../mod/notify.php:53 ../../mod/notifications.php:94 +msgid "No more system notifications." +msgstr "No hi ha més notificacions de sistema." + +#: ../../mod/notify.php:57 ../../mod/notifications.php:98 +msgid "System Notifications" +msgstr "Notificacions de sistema" + +#: ../../mod/acl.php:231 +msgid "network" +msgstr "xarxa" + +#: ../../mod/acl.php:241 +msgid "RSS" +msgstr "RSS" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "S'ha actualitzat la disposició." + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "Editor del Sistema de Descripció de Pàgines" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "No s'ha trobat cap disposició de pàgina." + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "Nom del mòdul:" + +#: ../../mod/pdledit.php:55 +msgid "Layout Help" +msgstr "Ajuda per la disposició de pàgina" + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "- selecciona -" + +#: ../../mod/import.php:25 +#, php-format +msgid "Your service plan only allows %d channels." +msgstr "El teu paquet de serveis només admet %d canals." + +#: ../../mod/import.php:60 +msgid "Nothing to import." +msgstr "No hi ha res a importar." + +#: ../../mod/import.php:84 +msgid "Unable to download data from old server" +msgstr "No s'han pogut descarregar les dades del servidor antic" + +#: ../../mod/import.php:90 +msgid "Imported file is empty." +msgstr "El fitxer importat està buit." + +#: ../../mod/import.php:110 +msgid "The data provided is not compatible with this project." +msgstr "Les dades subministrades no son compatibles amb aquest projecte." + +#: ../../mod/import.php:115 +#, php-format +msgid "Warning: Database versions differ by %1$d updates." +msgstr "Atenció: Les versions de la Base de Dades difereixen en %1$d actualitzacions." + +#: ../../mod/import.php:135 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "No s'ha pogut importar el canal perquè l'identificador del canal no s'ha pogut duplicar en aquest servidor." + +#: ../../mod/import.php:176 +msgid "Channel clone failed. Import failed." +msgstr "No s'ha pogut importar el canal perquè el canal no s'ha pogut clonar." + +#: ../../mod/import.php:186 +msgid "Cloned channel not found. Import failed." +msgstr "No s'ha pogut importar el canal perquè el canal clonat no s'ha trobat." + +#: ../../mod/import.php:516 +msgid "You must be logged in to use this feature." +msgstr "Has d'estar registrat per fer servir aquesta funcionalitat." + +#: ../../mod/import.php:521 +msgid "Import Channel" +msgstr "Importa un canal" + +#: ../../mod/import.php:522 +msgid "" +"Use this form to import an existing channel from a different server/hub. You" +" may retrieve the channel identity from the old server/hub via the network " +"or provide an export file." +msgstr "Empra aquest formulari per importar un canal existent en un altre servidor/concentrador. Pots recuperar el canal des de l'antic servidor/concentrador via la xarxa o mitjançant un fitxer d'exportació" + +#: ../../mod/import.php:523 +msgid "File to Upload" +msgstr "Fitxer a pujar" + +#: ../../mod/import.php:524 +msgid "Or provide the old server/hub details" +msgstr "O proveeix els detalls de l'antic servidor/concentrador" + +#: ../../mod/import.php:525 +msgid "Your old identity address (xyz@example.com)" +msgstr "La teva adreça de canal antiga. El format és canal@exemple.org" + +#: ../../mod/import.php:526 +msgid "Your old login email address" +msgstr "La teva adreça de correu electrònic antiga" + +#: ../../mod/import.php:527 +msgid "Your old login password" +msgstr "La teva contrasenya antiga" + +#: ../../mod/import.php:528 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be" +" able to post from either location, but only one can be marked as the " +"primary location for files, photos, and media." +msgstr "Per a qualsevol de les opcions, escull si vols fer primària l'adreça d'aquest hub o mantenir l'anterior com a primària. Podràs penjar entrades des de totes dues adreces, però per als fitxers, imatges i altres en cal una de primària." + +#: ../../mod/import.php:529 +msgid "Make this hub my primary location" +msgstr "Fes d'aquest hub la meva ubicació primària" + +#: ../../mod/import.php:530 +msgid "" +"Import existing posts if possible (experimental - limited by available " +"memory" +msgstr "Importa les entrades existents si es possible (experimental - limitat per la memòria disponible" + +#: ../../mod/import.php:531 +msgid "" +"This process may take several minutes to complete. Please submit the form " +"only once and leave this page open until finished." +msgstr "Aquest procès pot trigar minuts en completar. Si et plau envia el formulari només una vegada i manté aquesta pàgina oberta fins que finalitzi." + +#: ../../mod/editlayout.php:111 +msgid "Delete layout?" +msgstr "Esborra format?" + +#: ../../mod/editlayout.php:158 ../../mod/layouts.php:124 +msgid "Layout Description (Optional)" +msgstr "Descripció del Format (Opcional)" + +#: ../../mod/editlayout.php:160 ../../mod/layouts.php:121 +#: ../../mod/layouts.php:179 +msgid "Layout Name" +msgstr "Nom del Format Gràfic" + +#: ../../mod/editlayout.php:177 +msgid "Edit Layout" +msgstr "Edita Format Gràfic" + +#: ../../mod/chat.php:19 ../../mod/channel.php:25 +msgid "You must be logged in to see this page." +msgstr "Has d'estar identificat per a veure aquesta pàgina." + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "No s'ha trobat la sala" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "Abandona la sala" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "Elimina la sala" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "Absent" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "Estic connectat/da" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "Fes favorit aquest xat" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "Nova sala per a Xerrar" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "Nom del Xat" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "%1$s de Xats" + +#: ../../mod/mitem.php:24 ../../mod/menu.php:134 +msgid "Menu not found." +msgstr "Menú no trobat." + +#: ../../mod/mitem.php:48 +msgid "Unable to create element." +msgstr "Incapaç de crear l'element." + +#: ../../mod/mitem.php:71 +msgid "Unable to update menu element." +msgstr "Incapaç d'actualitzar un element del menú." + +#: ../../mod/mitem.php:86 +msgid "Unable to add menu element." +msgstr "Incapaç d'afegir l'element del menú." + +#: ../../mod/mitem.php:152 ../../mod/mitem.php:223 +msgid "Menu Item Permissions" +msgstr "Permisos de l'Article del Menú" + +#: ../../mod/mitem.php:153 ../../mod/mitem.php:224 ../../mod/settings.php:1083 +msgid "(click to open/close)" +msgstr "(clica per obrir/tancar)" + +#: ../../mod/mitem.php:155 ../../mod/mitem.php:171 +msgid "Link Name" +msgstr "Nom de l'Enllaç" + +#: ../../mod/mitem.php:156 ../../mod/mitem.php:228 +msgid "Link or Submenu Target" +msgstr "Enllaç o Submenú Objectiu" + +#: ../../mod/mitem.php:156 +msgid "Enter URL of the link or select a menu name to create a submenu" +msgstr "Entra la URL de l'enlla´o tria un nom de menú per crear un submenú" + +#: ../../mod/mitem.php:157 ../../mod/mitem.php:229 +msgid "Use magic-auth if available" +msgstr "Empra magic-auth si esta disponible" + +#: ../../mod/mitem.php:158 ../../mod/mitem.php:230 +msgid "Open link in new window" +msgstr "Obrir l'enllaç en una nova finestra" + +#: ../../mod/mitem.php:159 ../../mod/mitem.php:231 +msgid "Order in list" +msgstr "Ordre per llista" + +#: ../../mod/mitem.php:159 ../../mod/mitem.php:231 +msgid "Higher numbers will sink to bottom of listing" +msgstr "Els números més alts aniràn al fons de la llista" + +#: ../../mod/mitem.php:160 +msgid "Submit and finish" +msgstr "Envia i termina" + +#: ../../mod/mitem.php:161 +msgid "Submit and continue" +msgstr "Envia i continua" + +#: ../../mod/mitem.php:169 +msgid "Menu:" +msgstr "Menú:" + +#: ../../mod/mitem.php:172 +msgid "Link Target" +msgstr "Enllaç Objectiu" + +#: ../../mod/mitem.php:175 +msgid "Edit menu" +msgstr "Edita menú" + +#: ../../mod/mitem.php:178 +msgid "Edit element" +msgstr "Edita element" + +#: ../../mod/mitem.php:179 +msgid "Drop element" +msgstr "Deixa anar element" + +#: ../../mod/mitem.php:180 +msgid "New element" +msgstr "Nou element" + +#: ../../mod/mitem.php:181 +msgid "Edit this menu container" +msgstr "Edita aquest contenidor de menú" + +#: ../../mod/mitem.php:182 +msgid "Add menu element" +msgstr "Afegeix element de menú" + +#: ../../mod/mitem.php:183 +msgid "Delete this menu item" +msgstr "Esborra aquest article del menú" + +#: ../../mod/mitem.php:184 +msgid "Edit this menu item" +msgstr "Edita aquest article del menú" + +#: ../../mod/mitem.php:201 +msgid "Menu item not found." +msgstr "Article del menú no trobat." + +#: ../../mod/mitem.php:212 +msgid "Menu item deleted." +msgstr "Article del menú eliminat." + +#: ../../mod/mitem.php:214 +msgid "Menu item could not be deleted." +msgstr "Article del menú no es pot eliminar." + +#: ../../mod/mitem.php:221 +msgid "Edit Menu Element" +msgstr "Editar Element del Menú" + +#: ../../mod/mitem.php:227 +msgid "Link text" +msgstr "Enllaç de text" + +#: ../../mod/editwebpage.php:152 +msgid "Delete webpage?" +msgstr "Esborrar pàgina web?" + +#: ../../mod/editwebpage.php:173 +msgid "Page link title" +msgstr "Títol de la pàgina enllaçada" + +#: ../../mod/editwebpage.php:224 +msgid "Edit Webpage" +msgstr "Edita la Pàgina Web" + +#: ../../mod/dirsearch.php:29 +msgid "This directory server requires an access token" +msgstr "Aquest servidor de directori requereix un token de accès" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "No es troba un compte vàlid." + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "Sol·licitud de restabliment de contrasenya emesa. Consulta el teu correu electrònic." + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "Lloc d'Usuari (%s)" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "S'ha soÅ€licitat restablir la contrasenya al hub %s" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "Ha fallat el restabliment de contrasenya perquè la no s'ha pogut verificar soÅ€licitud. Pot ser que ja ho hàgiu soÅ€licitat abans." + +#: ../../mod/lostpass.php:85 ../../boot.php:1559 +msgid "Password Reset" +msgstr "Restabliment de contrasenya" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "S'ha restablert la vostra contrasenya." + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "La nova contrasenya és" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "Desa o copia la nova contrasenya, i després" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "fes clic aquí per iniciar sessió" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Pots canviar la contrasenya a la pàgina Paràmetres, un cop iniciada la sessió." + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "La teva contrasenya a %s ha canviat" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "No recordes la contrasenya?" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Escriu la teva adreça de correu electrònic i envia per restablir la contrasenya. Després revisa el seu correu electrònic per obtenir més instruccions." + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "Adreça electrònica" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "Reajustar" + +#: ../../mod/rate.php:157 +msgid "Website:" +msgstr "Lloc web:" + +#: ../../mod/rate.php:160 +#, php-format +msgid "Remote Channel [%s] (not yet known on this site)" +msgstr "Canal Remot [%s] (encara no es coneix en aquest lloc)" + +#: ../../mod/rate.php:161 +msgid "Rating (this information is public)" +msgstr "Valoració (aquesta informació és pública)" + +#: ../../mod/rate.php:162 +msgid "Optionally explain your rating (this information is public)" +msgstr "Opcionalment pots explicar la teva qualificació (aquesta informació és pública)" + +#: ../../mod/editblock.php:117 +msgid "Delete block?" +msgstr "Eliminar bloc?" + +#: ../../mod/editblock.php:179 +msgid "Edit Block" +msgstr "Editar Bloc" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "El límit total invitacions s'ha superat." + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s: adreça de correu electrònic no vàlida." + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "Si us plau, uneix-te a Red" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Límit d'invitacions excedit. Si us plau, poseu-vos en contacte amb l'administrador del lloc." + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : Entrega del Missatge fallida." + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d missatge enviat." +msgstr[1] "%d missatges enviats." + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "No té més invitacions disponibles" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "Enviar invitacions" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "Introduïu les adreces de correu electrònic, una per línia:" + +#: ../../mod/invite.php:131 ../../mod/mail.php:235 ../../mod/mail.php:348 +msgid "Your message:" +msgstr "El teu missatge:" + +#: ../../mod/invite.php:132 +msgid "Please join my community on $Projectname." +msgstr "Si us plau uneix-te la meva comunitat en $Projectname." + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "Has de proporcionar aquest codi d'invitació:" + +#: ../../mod/invite.php:135 +msgid "" +"1. Register at any $Projectname location (they are all inter-connected)" +msgstr "1. Registre en qualsevol lloc del $Projectname (estàn tots interconnectats)" + +#: ../../mod/invite.php:137 +msgid "2. Enter my $Projectname network address into the site searchbar." +msgstr "2. Entra a la meva adreça de xarxa al $Projectname, a la barra de cerca del lloc." + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "o visita" + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "3. Click [Conectar]" + +#: ../../mod/locs.php:21 ../../mod/locs.php:52 +msgid "Location not found." +msgstr "Situació que no es troba." + +#: ../../mod/locs.php:56 +msgid "Primary location cannot be removed." +msgstr "La ubicació primària no es pot treure." + +#: ../../mod/locs.php:88 +msgid "No locations found." +msgstr "No es troben els llocs." + +#: ../../mod/locs.php:101 +msgid "Manage Channel Locations" +msgstr "Gestionar Ubicacions de Canal" + +#: ../../mod/locs.php:102 +msgid "Location (address)" +msgstr "Ubicació (direcció)" + +#: ../../mod/locs.php:103 +msgid "Primary Location" +msgstr "Ubicació Primària" + +#: ../../mod/locs.php:104 +msgid "Drop location" +msgstr "Treure la ubicació" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "Error en crear l'origen. Cap canal seleccionat." + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "Origen creat." + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "Origen actualitzat." + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "*" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "Gestiona contingut per al teu canal d'origens remots" + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "Nou Origen" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "Importar tot o sel·lecciona contingut dels següents canals, en aquest canal i distribueix-lo d'acord als teus ajustos de canals." + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "Només importa contingut amb aquestes paraules (una per línia)" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "Deixar en blanc per importar tot el contingut públic" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:112 +msgid "Channel Name" +msgstr "Nom del canal" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "No s'ha trobat la font." + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "Edita la font" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "Esborra la font" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "S'ha esborrat la font" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "No s'ha pogut esborrar la font." + +#: ../../mod/menu.php:44 +msgid "Unable to update menu." +msgstr "No s'ha pogut actualitzar el menú." + +#: ../../mod/menu.php:53 +msgid "Unable to create menu." +msgstr "No s'ha pogut crear el menú." + +#: ../../mod/menu.php:89 ../../mod/menu.php:101 +msgid "Menu Name" +msgstr "Nom del menú" + +#: ../../mod/menu.php:89 +msgid "Unique name (not visible on webpage) - required" +msgstr "Nom únic (no visible a la pàgina web) - requerit" + +#: ../../mod/menu.php:90 ../../mod/menu.php:102 +msgid "Menu Title" +msgstr "Títol del menú" + +#: ../../mod/menu.php:90 +msgid "Visible on webpage - leave empty for no title" +msgstr "Visible a la pàgina web - deixar buit per a no posar títol" + +#: ../../mod/menu.php:91 +msgid "Allow Bookmarks" +msgstr "Permetre Marcadors" + +#: ../../mod/menu.php:91 ../../mod/menu.php:147 +msgid "Menu may be used to store saved bookmarks" +msgstr "El menú es pot emprar per a guardar marcadors" + +#: ../../mod/menu.php:92 ../../mod/menu.php:149 +msgid "Submit and proceed" +msgstr "Envia i procedeix" + +#: ../../mod/menu.php:104 +msgid "Drop" +msgstr "Menysprea" + +#: ../../mod/menu.php:108 +msgid "Bookmarks allowed" +msgstr "Marcadors permesos" + +#: ../../mod/menu.php:110 +msgid "Delete this menu" +msgstr "Esborra el menú" + +#: ../../mod/menu.php:111 ../../mod/menu.php:144 +msgid "Edit menu contents" +msgstr "Edita el contingut del menú" + +#: ../../mod/menu.php:112 +msgid "Edit this menu" +msgstr "Edita el menú" + +#: ../../mod/menu.php:126 +msgid "Menu could not be deleted." +msgstr "El menu no es pot esborrar." + +#: ../../mod/menu.php:139 +msgid "Edit Menu" +msgstr "Edita Menú" + +#: ../../mod/menu.php:143 +msgid "Add or remove entries to this menu" +msgstr "Afegeix o esborra entrades a aquest menú" + +#: ../../mod/menu.php:145 +msgid "Menu name" +msgstr "Nom del Menú" + +#: ../../mod/menu.php:145 +msgid "Must be unique, only seen by you" +msgstr "Ha de ser únic, nomes vist per tú" + +#: ../../mod/menu.php:146 +msgid "Menu title" +msgstr "Títol del menú" + +#: ../../mod/menu.php:146 +msgid "Menu title as seen by others" +msgstr "Títol del menú vist pels altres" + +#: ../../mod/menu.php:147 +msgid "Allow bookmarks" +msgstr "Marcadors permesos" + +#: ../../mod/filestorage.php:82 +msgid "Permission Denied." +msgstr "Permisos Denegats." + +#: ../../mod/filestorage.php:98 +msgid "File not found." +msgstr "Arxiu no torbat." + +#: ../../mod/filestorage.php:141 +msgid "Edit file permissions" +msgstr "Edita els permisos d'arxiu" + +#: ../../mod/filestorage.php:150 +msgid "Set/edit permissions" +msgstr "Canvia/edita permisos" + +#: ../../mod/filestorage.php:151 +msgid "Include all files and sub folders" +msgstr "Inclou tots als arxius i subdirectoris" + +#: ../../mod/filestorage.php:152 +msgid "Return to file list" +msgstr "Tornar al llistat d'arxius" + +#: ../../mod/filestorage.php:154 +msgid "Copy/paste this code to attach file to a post" +msgstr "Copia/enganxa aquest codi per a adjuntar un arxiu a l'entrada" + +#: ../../mod/filestorage.php:155 +msgid "Copy/paste this URL to link file from a web page" +msgstr "Copia/enganxa aquesta URL per a enllaçar l'arxiu d'una pàgina web" + +#: ../../mod/filestorage.php:157 +msgid "Share this file" +msgstr "Comparteix l'arxiu" + +#: ../../mod/filestorage.php:158 +msgid "Show URL to this file" +msgstr "Mostra la URL d'aquest arxiu" + +#: ../../mod/filestorage.php:159 +msgid "Notify your contacts about this file" +msgstr "Notifica als teus contactes aquest arxiu" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "Contacte no trobat." + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Suggeriment d'amistat enviada." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Amics Suggerits" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Suggereix un amic per a %s" + +#: ../../mod/magic.php:69 +msgid "Hub not found." +msgstr "Concentrador no trobat." + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "Emprenyat/Picat" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "emprenyar, picar o fer altres coses a algú" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "Destinatari" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "Tria que vols fer amb el destinatari" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "Fer aquesta entrada privada" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "Identificador invàlid de perfil." + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "Perfil del Editor de Visibilitat" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "Clica sobre el contacte per afegir o esborrar." + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "Visible per" + +#: ../../mod/impel.php:191 +#, php-format +msgid "%s element installed" +msgstr "%s element instal·lat" + +#: ../../mod/impel.php:194 +#, php-format +msgid "%s element installation failed" +msgstr "%s instal·lació d'element va fallar" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:174 +#: ../../mod/profiles.php:231 ../../mod/profiles.php:600 +msgid "Profile not found." +msgstr "Perfil no trobat." + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "Perfil eliminat." + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "Perfil-" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "Nou perfil creat." + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "Perfil que no es pot clonar." + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "Perfil que no es pot exportar." + +#: ../../mod/profiles.php:241 +msgid "Profile Name is required." +msgstr "Es requereix el Nom del Perfil." + +#: ../../mod/profiles.php:404 +msgid "Marital Status" +msgstr "Estat Marital" + +#: ../../mod/profiles.php:408 +msgid "Romantic Partner" +msgstr "Company/a Romàntic" + +#: ../../mod/profiles.php:412 +msgid "Likes" +msgstr "Agrada" + +#: ../../mod/profiles.php:416 +msgid "Dislikes" +msgstr "Desagrada" + +#: ../../mod/profiles.php:420 +msgid "Work/Employment" +msgstr "Treball/Feina" + +#: ../../mod/profiles.php:423 +msgid "Religion" +msgstr "Religió" + +#: ../../mod/profiles.php:427 +msgid "Political Views" +msgstr "Idees Polítiques" + +#: ../../mod/profiles.php:431 ../../mod/id.php:33 +msgid "Gender" +msgstr "Gènere" + +#: ../../mod/profiles.php:435 +msgid "Sexual Preference" +msgstr "Preferència Sexual" + +#: ../../mod/profiles.php:439 +msgid "Homepage" +msgstr "Pàgina Personal" + +#: ../../mod/profiles.php:443 +msgid "Interests" +msgstr "Interessos" + +#: ../../mod/profiles.php:447 ../../mod/admin.php:994 +msgid "Address" +msgstr "Adreça" + +#: ../../mod/profiles.php:537 +msgid "Profile updated." +msgstr "Perfil actualitzat." + +#: ../../mod/profiles.php:626 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "Amaga la teva llista de contactes/amics dels visitadors d'aquest perfil?" + +#: ../../mod/profiles.php:666 +msgid "Edit Profile Details" +msgstr "Edita els Detalls del Perfil" + +#: ../../mod/profiles.php:668 +msgid "View this profile" +msgstr "Veure aquest perfil" + +#: ../../mod/profiles.php:670 +msgid "Change Profile Photo" +msgstr "Canviar Foto del Perfil" + +#: ../../mod/profiles.php:671 +msgid "Create a new profile using these settings" +msgstr "Crea un perfil nou amb aquests ajustos" + +#: ../../mod/profiles.php:672 +msgid "Clone this profile" +msgstr "Clonar aquest perfil" + +#: ../../mod/profiles.php:673 +msgid "Delete this profile" +msgstr "Elimina aquest perfil" + +#: ../../mod/profiles.php:675 +msgid "Import profile from file" +msgstr "Importa perfil des d'un arxiu" + +#: ../../mod/profiles.php:676 +msgid "Export profile to file" +msgstr "Exporta perfil a un arxiu" + +#: ../../mod/profiles.php:677 +msgid "Profile Name:" +msgstr "Nom del Perfil:" + +#: ../../mod/profiles.php:678 +msgid "Your Full Name:" +msgstr "El Teu Nom Complet" + +#: ../../mod/profiles.php:679 +msgid "Title/Description:" +msgstr "Títol/Descripció:" + +#: ../../mod/profiles.php:680 +msgid "Your Gender:" +msgstr "El Teu Gènere:" + +#: ../../mod/profiles.php:681 +msgid "Birthday :" +msgstr "Aniversari:" + +#: ../../mod/profiles.php:682 +msgid "Street Address:" +msgstr "Carrer:" + +#: ../../mod/profiles.php:683 +msgid "Locality/City:" +msgstr "Població/Ciutat:" + +#: ../../mod/profiles.php:684 +msgid "Postal/Zip Code:" +msgstr "Codi Postal:" + +#: ../../mod/profiles.php:685 +msgid "Country:" +msgstr "País:" + +#: ../../mod/profiles.php:686 +msgid "Region/State:" +msgstr "Regió/Estat:" + +#: ../../mod/profiles.php:687 +msgid " Marital Status:" +msgstr " Marital Estatus:" + +#: ../../mod/profiles.php:688 +msgid "Who: (if applicable)" +msgstr "Qui: (si es aplicable)" + +#: ../../mod/profiles.php:689 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Examples: cathy123, Cathy Williams, cathy@example.com" + +#: ../../mod/profiles.php:690 +msgid "Since [date]:" +msgstr "Des de [data]:" + +#: ../../mod/profiles.php:692 +msgid "Homepage URL:" +msgstr "Pàgina Personal URL:" + +#: ../../mod/profiles.php:695 +msgid "Religious Views:" +msgstr "Creences Religioses:" + +#: ../../mod/profiles.php:696 +msgid "Keywords:" +msgstr "Paraules Clau:" + +#: ../../mod/profiles.php:699 +msgid "Example: fishing photography software" +msgstr "Exemple: software de fotografia submarina" + +#: ../../mod/profiles.php:700 +msgid "Used in directory listings" +msgstr "Emprat en els llistats de directoris" + +#: ../../mod/profiles.php:701 +msgid "Tell us about yourself..." +msgstr "Quelcom sobre tú:" + +#: ../../mod/profiles.php:702 +msgid "Hobbies/Interests" +msgstr "Aficions/Interessos" + +#: ../../mod/profiles.php:703 +msgid "Contact information and Social Networks" +msgstr "Informació de Contacte i Xarxes Socials" + +#: ../../mod/profiles.php:704 +msgid "My other channels" +msgstr "Els meus altres canals" + +#: ../../mod/profiles.php:705 +msgid "Musical interests" +msgstr "Interessos Musicals" + +#: ../../mod/profiles.php:706 +msgid "Books, literature" +msgstr "Llibres, literatura" + +#: ../../mod/profiles.php:707 +msgid "Television" +msgstr "Televisió" + +#: ../../mod/profiles.php:708 +msgid "Film/dance/culture/entertainment" +msgstr "Pel·lícules/Dansa/Cultura/Entreteniment" + +#: ../../mod/profiles.php:709 +msgid "Love/romance" +msgstr "Amor/Romace" + +#: ../../mod/profiles.php:710 +msgid "Work/employment" +msgstr "Treball/feina" + +#: ../../mod/profiles.php:711 +msgid "School/education" +msgstr "Escola/educació" + +#: ../../mod/profiles.php:717 +msgid "This is your default profile." +msgstr "Aquest es el teu perfil per defecte" + +#: ../../mod/profiles.php:728 +msgid "Age: " +msgstr "Edat:" + +#: ../../mod/profiles.php:771 +msgid "Edit/Manage Profiles" +msgstr "Edita/Gestiona Perfils" + +#: ../../mod/profiles.php:772 +msgid "Add profile things" +msgstr "Afegeix coses al perfil" + +#: ../../mod/profiles.php:773 +msgid "Include desirable objects in your profile" +msgstr "Inclou objectius desitjables al teu perfil" + +#: ../../mod/ratings.php:69 +msgid "No ratings" +msgstr "No valorat" + +#: ../../mod/ratings.php:99 +msgid "Ratings" +msgstr "Valoracions" + +#: ../../mod/ratings.php:100 +msgid "Rating: " +msgstr "Valoració:" + +#: ../../mod/ratings.php:101 +msgid "Website: " +msgstr "Lloc web:" + +#: ../../mod/ratings.php:103 +msgid "Description: " +msgstr "Descripció:" + +#: ../../mod/viewsrc.php:38 +msgid "Source of Item" +msgstr "Origen de l'article" + +#: ../../mod/setup.php:187 +msgid "$Projectname Server - Setup" +msgstr "Servidor $Projectname - Configuració" + +#: ../../mod/setup.php:191 +msgid "Could not connect to database." +msgstr "No puc connectar amb la base de dades" + +#: ../../mod/setup.php:195 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "No s'ha pogut connectar a l'URL del lloc especificat. Possible problema amb el certificat SSL o de DNS." + +#: ../../mod/setup.php:202 +msgid "Could not create table." +msgstr "No puc crear la taula." + +#: ../../mod/setup.php:207 +msgid "Your site database has been installed." +msgstr "La teva base de dades del lloc s'ha instal·lat." + +#: ../../mod/setup.php:211 +msgid "" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." +msgstr "Podria ser necessari importar el fitxer \"install / schema_xxx.sql\" manualment utilitzant un client de base de dades." + +#: ../../mod/setup.php:212 ../../mod/setup.php:280 ../../mod/setup.php:730 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "Si us plau, consulteu el fitxer \"install / INSTALL.txt\"." + +#: ../../mod/setup.php:277 +msgid "System check" +msgstr "Comprovació del sistema" + +#: ../../mod/setup.php:282 +msgid "Check again" +msgstr "Comprova de nou" + +#: ../../mod/setup.php:304 +msgid "Database connection" +msgstr "Connexió de base de dades" + +#: ../../mod/setup.php:305 +msgid "" +"In order to install $Projectname we need to know how to connect to your " +"database." +msgstr "Per tal d'instaÅ€lar $Projectname cal configurar la connexió a la base de dades." + +#: ../../mod/setup.php:306 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Si us plau, poseu-vos en contacte amb el proveïdor de serveis o administrador del lloc si vostè té preguntes sobre aquests paràmetres." + +#: ../../mod/setup.php:307 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "La base de dades s'especifica a continuació ja ha d'existir. Si no és així, si us plau crear-la abans de continuar." + +#: ../../mod/setup.php:311 +msgid "Database Server Name" +msgstr "Base de Dades Nom del Servidor" + +#: ../../mod/setup.php:311 +msgid "Default is localhost" +msgstr "Per defecte es localhost" + +#: ../../mod/setup.php:312 +msgid "Database Port" +msgstr "Port per a la Base de Dades" + +#: ../../mod/setup.php:312 +msgid "Communication port number - use 0 for default" +msgstr "Numero del port de comunicacions - empra 0 per defecte" + +#: ../../mod/setup.php:313 +msgid "Database Login Name" +msgstr "Base de Dades Nom d'Accès" + +#: ../../mod/setup.php:314 +msgid "Database Login Password" +msgstr "Base de Dades Contrasenya d'Accès" + +#: ../../mod/setup.php:315 +msgid "Database Name" +msgstr "Nom de la Base de Dades" + +#: ../../mod/setup.php:316 +msgid "Database Type" +msgstr "Tipus de Base de Dades" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "Site administrator email address" +msgstr "Adreça de correu de l'administrador del lloc" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "El teu compte de email ha de coincidir amb això per poder emprar el panel web d'administrador." + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Website URL" +msgstr "URL del lloc web" + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Please use SSL (https) URL if available." +msgstr "Si us plau, empra SSL (https) URL si està disponible." + +#: ../../mod/setup.php:321 ../../mod/setup.php:363 +msgid "Please select a default timezone for your website" +msgstr "Si us plau, tria la zona horària del teu lloc web" + +#: ../../mod/setup.php:348 +msgid "Site settings" +msgstr "Ajustos del lloc" + +#: ../../mod/setup.php:413 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "No s'ha pogut trobar una versió de línia d'ordres del PHP en el PATH del servidor web." + +#: ../../mod/setup.php:414 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "Si vostè no té una versió de línia d'ordres del PHP instal·lada al servidor, vostè no serà capaç d'executar sondejos en segon pla via cron." + +#: ../../mod/setup.php:418 +msgid "PHP executable path" +msgstr "Camí cap l'executable de PHP" + +#: ../../mod/setup.php:418 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Introdueix el camí cap l'executable de php. Pots deixa-ho en blanc i continuar l'instal·lació." + +#: ../../mod/setup.php:423 +msgid "Command line PHP" +msgstr "Línia d'ordres de PHP" + +#: ../../mod/setup.php:432 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "La versió de línia d'ordres de PHP al teu sistema no te el \"register_argc_argv\" activat." + +#: ../../mod/setup.php:433 +msgid "This is required for message delivery to work." +msgstr "Això es requereix per que funcioni l'entrega de missatges." + +#: ../../mod/setup.php:436 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/setup.php:454 +#, php-format +msgid "" +"Your max allowed total upload size is set to %s. Maximum size of one file to" +" upload is set to %s. You are allowed to upload up to %d files at once." +msgstr "La mida màxima que se't permet pujar està establerta en %s. La mida màxima per arxiu pujat es de %s. Se't permet pujar fins a %d arxius d'una vegada." + +#: ../../mod/setup.php:459 +msgid "You can adjust these settings in the servers php.ini." +msgstr "Pots ajustar aquests valors a l'arxiu php.ini del servidor" + +#: ../../mod/setup.php:461 +msgid "PHP upload limits" +msgstr "Límits de pujada de PHP" + +#: ../../mod/setup.php:484 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Error: la funció \"openssl_pkey_new\" en aquest sistema no es capaç de generar claus d'encriptació" + +#: ../../mod/setup.php:485 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Si esta funcionant sota Windows, per favor, miri \"http://www.php.net/manual/en/openssl.installation.php\"." + +#: ../../mod/setup.php:488 +msgid "Generate encryption keys" +msgstr "Generar claus de xifrat" + +#: ../../mod/setup.php:500 +msgid "libCurl PHP module" +msgstr "mòdul PHP libCurl " + +#: ../../mod/setup.php:501 +msgid "GD graphics PHP module" +msgstr "mòdul PHP GD gràfics" + +#: ../../mod/setup.php:502 +msgid "OpenSSL PHP module" +msgstr "mòdul PHP OpenSSL" + +#: ../../mod/setup.php:503 +msgid "mysqli or postgres PHP module" +msgstr "mòdul PHP mysqli o postgres" + +#: ../../mod/setup.php:504 +msgid "mb_string PHP module" +msgstr "mòdul PHP mb_string" + +#: ../../mod/setup.php:505 +msgid "mcrypt PHP module" +msgstr "mòdul PHP mcrypt" + +#: ../../mod/setup.php:506 +msgid "xml PHP module" +msgstr "Mòdul xml de PHP" + +#: ../../mod/setup.php:510 ../../mod/setup.php:512 +msgid "Apache mod_rewrite module" +msgstr "mòdul Apache mod_rewrite" + +#: ../../mod/setup.php:510 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Error: el mòdul mod-rewrite del servidor web Apache es requereix i no està instal·lat." + +#: ../../mod/setup.php:516 ../../mod/setup.php:519 +msgid "proc_open" +msgstr "proc_open" + +#: ../../mod/setup.php:516 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "Error: es requereix proc_open però o no està instal·lat o ha estat desactivat a php.ini" + +#: ../../mod/setup.php:524 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Error: el mòdul PHP libCURL es requereix però no està instal·lat." + +#: ../../mod/setup.php:528 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Error: el mòdul PHP GD graphics amb support JPEG es requereix però no està instal·lat." + +#: ../../mod/setup.php:532 +msgid "Error: openssl PHP module required but not installed." +msgstr "Error: el mòdul PHP openssl es requereix però no està instal·lat." + +#: ../../mod/setup.php:536 +msgid "" +"Error: mysqli or postgres PHP module required but neither are installed." +msgstr "Error: el mòdul PHO mysqli o postgres es requereix però no està instal·lat." + +#: ../../mod/setup.php:540 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Error: el mòdul PHP mb_string es requereix però no està instal·lat." + +#: ../../mod/setup.php:544 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "Error: el mòdul PHP mcrypt es requereix però no està instal·lat." + +#: ../../mod/setup.php:548 +msgid "Error: xml PHP module required for DAV but not installed." +msgstr "Error: el mòdul xml de PHP es requereix per DAV però no està instal·lat." + +#: ../../mod/setup.php:566 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "L'instaÅ€lador ha de poder crear i modificar un fitxer anomenat «.htconfig.php» a la carpeta arrel del servidor, però sembla que no ho pot fer." + +#: ../../mod/setup.php:567 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Això sol ser un problema de permisos. Per molt que el teu usuari pugui modificar-lo, és el del servidor web qui necessita els poders de modificació." + +#: ../../mod/setup.php:568 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "Al final d'aquest procés hauràs de desar un text a l'arxiu «.htconfig.php», que es troba a la carpeta arrel del servidor." + +#: ../../mod/setup.php:569 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "Aquest procés és opcional. Per a fer una instaÅ€lació manual consulta les instruccions a «install/INSTALL.txt\"." + +#: ../../mod/setup.php:572 +msgid ".htconfig.php is writable" +msgstr "L'arxiu «.htconfig.php» es pot modificar" + +#: ../../mod/setup.php:586 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "Red fa servir el motor de plantilles Smarty3 per a renderitzar les vistes més ràpidament." + +#: ../../mod/setup.php:587 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "Per tal de guardar aquestes plantilles compilades, el servidor web necessita tenir premis d'escriptura en el directori %s sota la carpeta principal de Red." + +#: ../../mod/setup.php:588 ../../mod/setup.php:609 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "Comprova que l'usuari que executa el servidor (www-data en Apache) té permisos d'escriptura en aquesta carpeta." + +#: ../../mod/setup.php:589 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "Nota: com a mesura de seguretat l'usuari del servidor web ha de tenir accés d'escriptura només a %s, i no a les plantilles (.tpl) que conté." + +#: ../../mod/setup.php:592 +#, php-format +msgid "%s is writable" +msgstr "Es pot escriure a %s" + +#: ../../mod/setup.php:608 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to" +" have write access to the store directory under the Red top level folder" +msgstr "Red fa servir la carpeta «store» per a desar els fitxers pujats. Per tant, el servidor web necessita tenir permís d'escriptura en aquesta carpeta, que està a l'arrel del servidor web." + +#: ../../mod/setup.php:612 +msgid "store is writable" +msgstr "Es pot escriure al magatzem (store)" + +#: ../../mod/setup.php:645 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access" +" to this site." +msgstr "El certificat SSL no s'ha pogut validar. Arregla-ho o deshabilita l'accés https a aquest lloc" + +#: ../../mod/setup.php:646 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "Si tens accès pet https al teu lloc web o permets connexions pel port TCP 443 (port https), Has d'emprar un certificat VÀLID. NO es poden emprar certificats AUTO-SIGNATS!" + +#: ../../mod/setup.php:647 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "El motiu d'aquesta restricció és que les teves entrades públiques poden contenir referències a imatges del teu propi hub." + +#: ../../mod/setup.php:648 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "Si el teu certificat no és reconegut, llavors el membres d'altres hubs, encara que tinguin certificats vàlids, rebran una advertència de seguretat en carregar contingut teu." + +#: ../../mod/setup.php:649 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "Per tant, com que perjudica la usabilitat més enllà del teu lloc, la restricció de tenir un certificat reconegut és molt important." + +#: ../../mod/setup.php:650 +msgid "" +"Providers are available that issue free certificates which are browser-" +"valid." +msgstr "Hi ha autoritats de certificació reconegudes que ofereixen certificats gratuïts." + +#: ../../mod/setup.php:652 +msgid "SSL certificate validation" +msgstr "Validació del certificat SSL" + +#: ../../mod/setup.php:658 +msgid "" +"Url rewrite in .htaccess is not working. Check your server " +"configuration.Test: " +msgstr "No es poden reescriure les URL a «.htaccess». Comprova la configuració del servidor:" + +#: ../../mod/setup.php:661 +msgid "Url rewrite is working" +msgstr "Es poden reescriure les URL a «.htaccess»" + +#: ../../mod/setup.php:670 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "L'arxiu de configuracio de la base de dades «.htconfig.php» no s'ha pogut modificar. El pots crear tu a l'arrel del servidor web amb el text de la caixa com a contingut." + +#: ../../mod/setup.php:694 +msgid "Errors encountered creating database tables." +msgstr "S'han produït errors mentre es creaven taules a la base de dades." + +#: ../../mod/setup.php:728 +msgid "

    What next

    " +msgstr "

    I ara què?

    " + +#: ../../mod/setup.php:729 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "IMPORTANT! Cal que configuris manualment una execució periòdica del \"poller\"." + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "Error del protocol OpenID. No ha retornat ID" + +#: ../../mod/openid.php:72 ../../mod/openid.php:180 ../../mod/post.php:286 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "Benvingut %s. Autenticació remota reeixida." + +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s ha etiquetat %3$s de %2$s amb %4$s" + +#: ../../mod/uexport.php:41 ../../mod/uexport.php:42 +msgid "Export Channel" +msgstr "Exportar Canal" + +#: ../../mod/uexport.php:43 +msgid "" +"Export your basic channel information to a small file. This acts as a " +"backup of your connections, permissions, profile and basic data, which can " +"be used to import your data to a new hub, but\tdoes not contain your " +"content." +msgstr "Exporta la informació bàsica del canal a un petit arxiu. Això actua com a còpia de recolzament de les teves connexions, permisos, perfil i dades bàsiques, les quals pots emprar per traslladar aquestes dades a una altre lloc/centre, però no conté el contingut del canal." + +#: ../../mod/uexport.php:44 +msgid "Export Content" +msgstr "Exportar el Contingut" + +#: ../../mod/uexport.php:45 +msgid "" +"Export your channel information and all the content to a JSON backup. This " +"backs up all of your connections, permissions, profile data and all of your " +"content, but is generally not suitable for importing a channel to a new hub " +"as this file may be VERY large. Please be patient - it may take several " +"minutes for this download to begin." +msgstr "Exporta la informació del canal i tot el contingut a un arxiu de recolzament JSON. Això còpia totes les teves connexions, permisos, perfil i dades i tot el contingut, però normalment no es pot importar en un altre canal d'un nou lloc/centre donat que l'arxiu acostuma a ser MOLT gran. Si et plau, sigues pacient ja que pot trigar uns minuts a començar a baixar." + +#: ../../mod/viewconnections.php:62 +msgid "No connections." +msgstr "Sense connexions." + +#: ../../mod/viewconnections.php:75 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Visita el perfil [%s] de %s" + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "Signatura objectiu invàlida" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "Ajustos de tema actualitzats." + +#: ../../mod/admin.php:93 ../../mod/admin.php:452 +msgid "Site" +msgstr "Lloc" + +#: ../../mod/admin.php:94 +msgid "Accounts" +msgstr "Comptes" + +#: ../../mod/admin.php:95 ../../mod/admin.php:985 +msgid "Channels" +msgstr "Canals" + +#: ../../mod/admin.php:96 ../../mod/admin.php:1077 ../../mod/admin.php:1117 +msgid "Plugins" +msgstr "Plugins" + +#: ../../mod/admin.php:97 ../../mod/admin.php:1277 ../../mod/admin.php:1311 +msgid "Themes" +msgstr "Temes" + +#: ../../mod/admin.php:98 +msgid "Inspect queue" +msgstr "Revisa cua" + +#: ../../mod/admin.php:100 +msgid "Profile Config" +msgstr "Configuració del Perfil" + +#: ../../mod/admin.php:101 +msgid "DB updates" +msgstr "Actualitzacions de Base de Dades" + +#: ../../mod/admin.php:115 ../../mod/admin.php:122 ../../mod/admin.php:1396 +msgid "Logs" +msgstr "Logs" + +#: ../../mod/admin.php:121 +msgid "Plugin Features" +msgstr "Característiques del Plugin" + +#: ../../mod/admin.php:123 +msgid "User registrations waiting for confirmation" +msgstr "Registre d'usuaris esperant confirmació" + +#: ../../mod/admin.php:200 +msgid "# Accounts" +msgstr "# Comptes" + +#: ../../mod/admin.php:201 +msgid "# blocked accounts" +msgstr "# comptes bloquejats" + +#: ../../mod/admin.php:202 +msgid "# expired accounts" +msgstr "# comptes expirats" + +#: ../../mod/admin.php:203 +msgid "# expiring accounts" +msgstr "# comptes expirant" + +#: ../../mod/admin.php:216 +msgid "# Channels" +msgstr "# Canals" + +#: ../../mod/admin.php:217 +msgid "# primary" +msgstr "# primari" + +#: ../../mod/admin.php:218 +msgid "# clones" +msgstr "# clons" + +#: ../../mod/admin.php:224 +msgid "Message queues" +msgstr "Cues de missatges" + +#: ../../mod/admin.php:240 ../../mod/admin.php:451 ../../mod/admin.php:548 +#: ../../mod/admin.php:817 ../../mod/admin.php:984 ../../mod/admin.php:1076 +#: ../../mod/admin.php:1116 ../../mod/admin.php:1276 ../../mod/admin.php:1310 +#: ../../mod/admin.php:1395 +msgid "Administration" +msgstr "Administració" + +#: ../../mod/admin.php:241 +msgid "Summary" +msgstr "Sumari" + +#: ../../mod/admin.php:244 +msgid "Registered accounts" +msgstr "Comptes registrades" + +#: ../../mod/admin.php:245 ../../mod/admin.php:552 +msgid "Pending registrations" +msgstr "Comptes pendents de registre" + +#: ../../mod/admin.php:246 +msgid "Registered channels" +msgstr "Canals registrats" + +#: ../../mod/admin.php:247 ../../mod/admin.php:553 +msgid "Active plugins" +msgstr "Plugins actius" + +#: ../../mod/admin.php:248 +msgid "Version" +msgstr "Versió" + +#: ../../mod/admin.php:363 +msgid "Site settings updated." +msgstr "Ajustos del Lloc actualitzats" + +#: ../../mod/admin.php:400 ../../mod/settings.php:813 +msgid "mobile" +msgstr "mòbil" + +#: ../../mod/admin.php:402 +msgid "experimental" +msgstr "experimental" + +#: ../../mod/admin.php:404 +msgid "unsupported" +msgstr "no soportat" + +#: ../../mod/admin.php:429 +msgid "Yes - with approval" +msgstr "Sí - amb aprovació" + +#: ../../mod/admin.php:435 +msgid "My site is not a public server" +msgstr "El meu lloc no es un servidor públic" + +#: ../../mod/admin.php:436 +msgid "My site has paid access only" +msgstr "El meu lloc te accès per pagament" + +#: ../../mod/admin.php:437 +msgid "My site has free access only" +msgstr "El meu lloc te lliure accés" + +#: ../../mod/admin.php:438 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "El meu lloc te comptes gratis amb opció de millores per pagament" + +#: ../../mod/admin.php:454 ../../mod/register.php:207 +msgid "Registration" +msgstr "Registre" + +#: ../../mod/admin.php:455 +msgid "File upload" +msgstr "Pujar arxiu" + +#: ../../mod/admin.php:456 +msgid "Policies" +msgstr "Polítiques" + +#: ../../mod/admin.php:461 +msgid "Site name" +msgstr "Nom del lloc" + +#: ../../mod/admin.php:462 +msgid "Banner/Logo" +msgstr "Senyera/Logo" + +#: ../../mod/admin.php:463 +msgid "Administrator Information" +msgstr "Informació de l'Administrador" + +#: ../../mod/admin.php:463 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "Informació per contactar amb els administradors del lloc. Mostrada a la pàgina d'informació del lloc. Es pot emprar BBCode aquí" + +#: ../../mod/admin.php:464 +msgid "System language" +msgstr "Idioma del sistema" + +#: ../../mod/admin.php:465 +msgid "System theme" +msgstr "Tema del sistema" + +#: ../../mod/admin.php:465 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "Tema del sistema per defecte - pot ser sobrescrit pel perfils dels usuaris - Ajustos de canvi del tema" + +#: ../../mod/admin.php:466 +msgid "Mobile system theme" +msgstr "Tema del sistema per a mòbils" + +#: ../../mod/admin.php:466 +msgid "Theme for mobile devices" +msgstr "Tema per a aparells mòbils" + +#: ../../mod/admin.php:468 +msgid "Enable Diaspora Protocol" +msgstr "Activat el Protocol Diaspora" + +#: ../../mod/admin.php:468 +msgid "Communicate with Diaspora and Friendica - experimental" +msgstr "Comunicar amb Diaspora i Friendica - experimental" + +#: ../../mod/admin.php:469 +msgid "Allow Feeds as Connections" +msgstr "Permetre Retroalimentadors com Connexions" + +#: ../../mod/admin.php:469 +msgid "(Heavy system resource usage)" +msgstr "(Demana molts recursos del sistema)" + +#: ../../mod/admin.php:470 +msgid "Maximum image size" +msgstr "Mida màxima d'imatge" + +#: ../../mod/admin.php:470 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Mida màxima en bytes de imatges pujades. Per defecte es 0, el que vol dir sense límits." + +#: ../../mod/admin.php:471 +msgid "Does this site allow new member registration?" +msgstr "Permet aquest lloc registre de nous membres?" + +#: ../../mod/admin.php:472 +msgid "Which best describes the types of account offered by this hub?" +msgstr "Que es es que millor descriu la mena de comptes oferits per aquest concentrador?" + +#: ../../mod/admin.php:473 +msgid "Register text" +msgstr "text de registre" + +#: ../../mod/admin.php:473 +msgid "Will be displayed prominently on the registration page." +msgstr "Es mostrarà preminentment a la pàgina de registre" + +#: ../../mod/admin.php:474 +msgid "Site homepage to show visitors (default: login box)" +msgstr "Pàgina d'inici a mostrar als visitants (per defecte: la pàgina d'identificació)" + +#: ../../mod/admin.php:474 +msgid "" +"example: 'public' to show public stream, 'page/sys/home' to show a system " +"webpage called 'home' or 'include:home.html' to include a file." +msgstr "exemple: 'públic' per a mostrar un flux públic, 'page/sys/home' per a mostrar una pàgina web dita 'home' o 'include:home.html' per a incloure un arxiu." + +#: ../../mod/admin.php:475 +msgid "Preserve site homepage URL" +msgstr "Preservar URL de la pàgina web" + +#: ../../mod/admin.php:475 +msgid "" +"Present the site homepage in a frame at the original location instead of " +"redirecting" +msgstr "Presenta la pàgina web del lloc en un marc en el lloc original enlloc de redirigir cap a ella" + +#: ../../mod/admin.php:476 +msgid "Accounts abandoned after x days" +msgstr "Els copmte es consideren abandonats despres de x dies" + +#: ../../mod/admin.php:476 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "No malgastar recursos del sistema sondejant llocs externs per acomptes abandonats. Entrar 0 vol dir sense límit de temps." + +#: ../../mod/admin.php:477 +msgid "Allowed friend domains" +msgstr "dominis amics permesos" + +#: ../../mod/admin.php:477 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "llista separada per comes de dominis en els que està permès establir relacions d'amistat amb aquest lloc. S'accepten comodins. Deixar buit per acceptar qualsevol domini" + +#: ../../mod/admin.php:478 +msgid "Allowed email domains" +msgstr "Dominis de correu electonic acceptats" + +#: ../../mod/admin.php:478 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "llista separada per comes de dominis de adreces de correu electrònic permeses en aquest lloc. S'accepten comodins. Deixar buit per acceptar qualsevol domini" + +#: ../../mod/admin.php:479 +msgid "Not allowed email domains" +msgstr "Dominis de correu electrònic no acceptats" + +#: ../../mod/admin.php:479 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for" +" registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "llista separada per comes de dominis de adreces de correu electrònic no permeses en aquest lloc. S'accepten comodins. Deixar buit per no acceptar cap domini, excepte els que s'hagin definits com acceptats." + +#: ../../mod/admin.php:480 +msgid "Block public" +msgstr "Bloc públic" + +#: ../../mod/admin.php:480 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Activa per a bloquejar l'accés públic a totes les pàgines públiques personals excepte si estàs identificat en el sistema." + +#: ../../mod/admin.php:481 +msgid "Verify Email Addresses" +msgstr "Verifica l'Adreça de Correu Electrònic" + +#: ../../mod/admin.php:481 +msgid "" +"Check to verify email addresses used in account registration (recommended)." +msgstr "Activa per comprovar l'adreça de correu electrònic emprada durant el registre d'un nou compte (recomanat)" + +#: ../../mod/admin.php:482 +msgid "Force publish" +msgstr "Forza la publicació" + +#: ../../mod/admin.php:482 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Activa per forzar que tots el perfils en aquest lloc siguin llistats en el directori del lloc." + +#: ../../mod/admin.php:483 +msgid "Disable discovery tab" +msgstr "Desactiva la pestañnya de descobrir" + +#: ../../mod/admin.php:483 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "Treu la pesranya per veure contingut públic de la xarxa extret d'origens triats per aquest lloc." + +#: ../../mod/admin.php:484 +msgid "login on Homepage" +msgstr "Accés a la Pàgina d'inici" + +#: ../../mod/admin.php:484 +msgid "" +"Present a login box to visitors on the home page if no other content has " +"been configured." +msgstr "Presenta una casella d'identificació a la pàgina d'inici als visitants si no s'ha configurat altre contingut." + +#: ../../mod/admin.php:486 +msgid "Proxy user" +msgstr "Usuari Proxy" + +#: ../../mod/admin.php:487 +msgid "Proxy URL" +msgstr "URL del Proxy" + +#: ../../mod/admin.php:488 +msgid "Network timeout" +msgstr "Temps d'espera de la xarxa" + +#: ../../mod/admin.php:488 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "Valor en segons. Ajusta a 0 per a sense límits (no recomanat)" + +#: ../../mod/admin.php:489 +msgid "Delivery interval" +msgstr "Interval de lliurament" + +#: ../../mod/admin.php:489 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Retarda en segon plà l'interval de lliurament per aquests segons per reduir la càrrega del sistema. Recomanat: 4-5 per a hostes compartits, 2-3 per a servidors privats virtuals. 0-1 per a servidors dedicats." + +#: ../../mod/admin.php:490 +msgid "Poll interval" +msgstr "interval de sondeig" + +#: ../../mod/admin.php:490 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Retarda en segon pla el sondeig en aquesta quantitat de segons per a reduir la càrrega dels sistema. Si es 0 , empra l'interval de lliurament." + +#: ../../mod/admin.php:491 +msgid "Maximum Load Average" +msgstr "Càrrega Mitja Màxima" + +#: ../../mod/admin.php:491 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Càrrega màxima del sistema, abans que els processos de lliurament i sondeig es difereixin - 50 per defecte." + +#: ../../mod/admin.php:492 +msgid "Expiration period in days for imported (matrix/network) content" +msgstr "Periode d'expiració per a contingut importat (matrix/xarxa)" + +#: ../../mod/admin.php:492 +msgid "0 for no expiration of imported content" +msgstr "0 vol dir sense temps d'expiració pel contingut importat" + +#: ../../mod/admin.php:540 +msgid "No server found" +msgstr "No es troba servidor" + +#: ../../mod/admin.php:547 ../../mod/admin.php:831 +msgid "ID" +msgstr "ID" + +#: ../../mod/admin.php:547 +msgid "for channel" +msgstr "per a canal" + +#: ../../mod/admin.php:547 +msgid "on server" +msgstr "al servidor" + +#: ../../mod/admin.php:547 +msgid "Status" +msgstr "Estat" + +#: ../../mod/admin.php:549 +msgid "Server" +msgstr "Servidor" + +#: ../../mod/admin.php:566 +msgid "Update has been marked successful" +msgstr "Actualització marcada amb exit" + +#: ../../mod/admin.php:576 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "Executant %s ha fallat. Comprova els logs del sistema." + +#: ../../mod/admin.php:579 +#, php-format +msgid "Update %s was successfully applied." +msgstr "Actualització %s es va realitzar correctament." + +#: ../../mod/admin.php:583 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "Actualització %s no ha retornat l'estat. Es desconeix si ha finalitzat amb exit." + +#: ../../mod/admin.php:586 +#, php-format +msgid "Update function %s could not be found." +msgstr "La funció d'actualitzacio %s no es pot trobar." + +#: ../../mod/admin.php:602 +msgid "No failed updates." +msgstr "No hi ha actualitzacions fallides." + +#: ../../mod/admin.php:606 +msgid "Failed Updates" +msgstr "Actualitzacions Fallides" + +#: ../../mod/admin.php:608 +msgid "Mark success (if update was manually applied)" +msgstr "Marca èxit (si l'actualització s'ha aplicat de forma manual)" + +#: ../../mod/admin.php:609 +msgid "Attempt to execute this update step automatically" +msgstr "Prova a fer automàticament aquesta actualització" + +#: ../../mod/admin.php:641 +msgid "Queue Statistics" +msgstr "Cua d'Estadístiques" + +#: ../../mod/admin.php:642 +msgid "Total Entries" +msgstr "Total d'Entrades" + +#: ../../mod/admin.php:643 +msgid "Priority" +msgstr "Prioritat" + +#: ../../mod/admin.php:644 +msgid "Destination URL" +msgstr "URL de Destí" + +#: ../../mod/admin.php:645 +msgid "Mark hub permanently offline" +msgstr "Marca el concentrador coma permanentment fora de línia" + +#: ../../mod/admin.php:646 +msgid "Empty queue for this hub" +msgstr "Cua buida per aquest concentrador" + +#: ../../mod/admin.php:647 +msgid "Last known contact" +msgstr "Últim contacte conegut" + +#: ../../mod/admin.php:683 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s usuari bloquejat/desbloquejat" +msgstr[1] "%s usuaris bloquejats/desbloquejats" + +#: ../../mod/admin.php:691 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s usuari esborrat" +msgstr[1] "%s usuaris esborrats" + +#: ../../mod/admin.php:727 +msgid "Account not found" +msgstr "Compte no trobat" + +#: ../../mod/admin.php:747 +#, php-format +msgid "User '%s' blocked" +msgstr "Usuari '%s' bloquejat" + +#: ../../mod/admin.php:755 +#, php-format +msgid "User '%s' unblocked" +msgstr "Usuari '%s' desbloquejat" + +#: ../../mod/admin.php:818 ../../mod/admin.php:830 +msgid "Users" +msgstr "Usuaris" + +#: ../../mod/admin.php:820 ../../mod/admin.php:987 +msgid "select all" +msgstr "Sel·leciona-ho tot" + +#: ../../mod/admin.php:821 +msgid "User registrations waiting for confirm" +msgstr "Registres d'usuaris pendents de confirmació" + +#: ../../mod/admin.php:822 +msgid "Request date" +msgstr "Data de la petició" + +#: ../../mod/admin.php:823 +msgid "No registrations." +msgstr "Sense registracions." + +#: ../../mod/admin.php:824 ../../mod/connedit.php:687 +msgid "Approve" +msgstr "Aprovat" + +#: ../../mod/admin.php:825 +msgid "Deny" +msgstr "Denegat" + +#: ../../mod/admin.php:827 ../../mod/connedit.php:519 +msgid "Block" +msgstr "Bloquejat" + +#: ../../mod/admin.php:828 ../../mod/connedit.php:519 +msgid "Unblock" +msgstr "Desbloquejat" + +#: ../../mod/admin.php:831 +msgid "Register date" +msgstr "Data de registre" + +#: ../../mod/admin.php:831 +msgid "Last login" +msgstr "Darrera identificació" + +#: ../../mod/admin.php:831 +msgid "Expires" +msgstr "Expira" + +#: ../../mod/admin.php:831 +msgid "Service Class" +msgstr "Classe de Servei" + +#: ../../mod/admin.php:833 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Tria els usuaris que s'esborraran!\\n\\nTotes les publicacions d'aquests usuaris en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur? " + +#: ../../mod/admin.php:834 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "L'usuari {0} sera esborrat!\\n\\nTotes les publicacions d'aquest usuari en aquest lloc s'eliminarà de forma permanent!\\n\\nEstas segur?" + +#: ../../mod/admin.php:870 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channels censored/uncensored" +msgstr[0] "%s canal censurat/no censurat" +msgstr[1] "%s canals censurats/no censurats" + +#: ../../mod/admin.php:879 +#, php-format +msgid "%s channel code allowed/disallowed" +msgid_plural "%s channels code allowed/disallowed" +msgstr[0] "%s codi permes/no permes al canal" +msgstr[1] "%s codi permesos/no permesos al canal" + +#: ../../mod/admin.php:886 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "%s canal esborrat" +msgstr[1] "%s canals esborrats" + +#: ../../mod/admin.php:906 +msgid "Channel not found" +msgstr "Canal no trobat" + +#: ../../mod/admin.php:917 +#, php-format +msgid "Channel '%s' deleted" +msgstr "Canal '%s' esborrat" + +#: ../../mod/admin.php:929 +#, php-format +msgid "Channel '%s' censored" +msgstr "Canal '%s' censurat" + +#: ../../mod/admin.php:929 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "Canal '%s' no censurat" + +#: ../../mod/admin.php:940 +#, php-format +msgid "Channel '%s' code allowed" +msgstr "Canal '%s' permet codi" + +#: ../../mod/admin.php:940 +#, php-format +msgid "Channel '%s' code disallowed" +msgstr "Canal '%s' no permet codi" + +#: ../../mod/admin.php:989 +msgid "Censor" +msgstr "Censurat" + +#: ../../mod/admin.php:990 +msgid "Uncensor" +msgstr "No censurat" + +#: ../../mod/admin.php:991 +msgid "Allow Code" +msgstr "Permet Codi" + +#: ../../mod/admin.php:992 +msgid "Disallow Code" +msgstr "No Permet Codi" + +#: ../../mod/admin.php:994 +msgid "UID" +msgstr "UID" + +#: ../../mod/admin.php:996 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Els canals sel·leccionats s'esborraran!\\n\\nTotes les publicacions d'aquests canals en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur? " + +#: ../../mod/admin.php:997 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "El canal {0} serà esborrat!\\n\\nTotes les publicacions d'aquest canal en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur?" + +#: ../../mod/admin.php:1037 +#, php-format +msgid "Plugin %s disabled." +msgstr "Plugin %s desactivat." + +#: ../../mod/admin.php:1041 +#, php-format +msgid "Plugin %s enabled." +msgstr "Plugin %s activat." + +#: ../../mod/admin.php:1051 ../../mod/admin.php:1249 +msgid "Disable" +msgstr "Desactivat" + +#: ../../mod/admin.php:1054 ../../mod/admin.php:1251 +msgid "Enable" +msgstr "Activat" + +#: ../../mod/admin.php:1078 ../../mod/admin.php:1278 +msgid "Toggle" +msgstr "Commutar" + +#: ../../mod/admin.php:1086 ../../mod/admin.php:1288 +msgid "Author: " +msgstr "Autor: " + +#: ../../mod/admin.php:1087 ../../mod/admin.php:1289 +msgid "Maintainer: " +msgstr "Mantenedor:" + +#: ../../mod/admin.php:1214 +msgid "No themes found." +msgstr "No s'han trobat temes." + +#: ../../mod/admin.php:1270 +msgid "Screenshot" +msgstr "Copia de pantalla" + +#: ../../mod/admin.php:1316 +msgid "[Experimental]" +msgstr "[Experimental]" + +#: ../../mod/admin.php:1317 +msgid "[Unsupported]" +msgstr "[No soportat]" + +#: ../../mod/admin.php:1341 +msgid "Log settings updated." +msgstr "Registre d'ajustos actualitzat." + +#: ../../mod/admin.php:1398 +msgid "Clear" +msgstr "Neteja" + +#: ../../mod/admin.php:1404 +msgid "Debugging" +msgstr "Depurant" + +#: ../../mod/admin.php:1405 +msgid "Log file" +msgstr "Arxiu de registre" + +#: ../../mod/admin.php:1405 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "Ha de ser escribible pel servidor web. Relatiu al directori de nivell superior de Red" + +#: ../../mod/admin.php:1406 +msgid "Log level" +msgstr "Nivell de registre" + +#: ../../mod/admin.php:1452 +msgid "New Profile Field" +msgstr "Camp de Perfil Nou" + +#: ../../mod/admin.php:1453 ../../mod/admin.php:1473 +msgid "Field nickname" +msgstr "Àlies de Camp" + +#: ../../mod/admin.php:1453 ../../mod/admin.php:1473 +msgid "System name of field" +msgstr "nOM DEL SISTEMA DEL CAMP" + +#: ../../mod/admin.php:1454 ../../mod/admin.php:1474 +msgid "Input type" +msgstr "Tipus d'entrada" + +#: ../../mod/admin.php:1455 ../../mod/admin.php:1475 +msgid "Field Name" +msgstr "Nom de Camp" + +#: ../../mod/admin.php:1455 ../../mod/admin.php:1475 +msgid "Label on profile pages" +msgstr "Etiqueta a les pàgines de perfil" + +#: ../../mod/admin.php:1456 ../../mod/admin.php:1476 +msgid "Help text" +msgstr "Text d'ajuda" + +#: ../../mod/admin.php:1456 ../../mod/admin.php:1476 +msgid "Additional info (optional)" +msgstr "Informació adicional (opcional)" + +#: ../../mod/admin.php:1466 +msgid "Field definition not found" +msgstr "No es troba la definició del camp" + +#: ../../mod/admin.php:1472 +msgid "Edit Profile Field" +msgstr "Camp d'Edició del Perfil" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "No es possible trobar el concentrador" + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "Entrada realitzada amb èxit. " + +#: ../../mod/register.php:44 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "Nombre màxim de registres diaris excedit. Si us plau, provau demà." + +#: ../../mod/register.php:50 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "El registre ha fallat. Si et plau, indica que acceptes les Condicions del Servei." + +#: ../../mod/register.php:84 +msgid "Passwords do not match." +msgstr "Les contrasenyes no coincideixen." + +#: ../../mod/register.php:117 +msgid "" +"Registration successful. Please check your email for validation " +"instructions." +msgstr "registrat amb èxit. Si et plau revisa el teu e-correu per a instruccions de validació." + +#: ../../mod/register.php:123 +msgid "Your registration is pending approval by the site owner." +msgstr "El teu registre esta pendent de validació pel propietari del lloc." + +#: ../../mod/register.php:126 +msgid "Your registration can not be processed." +msgstr "El teu registre no ha pogut ser processat. " + +#: ../../mod/register.php:163 +msgid "Registration on this site/hub is by approval only." +msgstr "El registre en aquest lloc/centre es únicament per validació." + +#: ../../mod/register.php:164 +msgid "Register at another affiliated site/hub" +msgstr "Registre en altre lloc/centre afiliat" + +#: ../../mod/register.php:174 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "El lloc ha excedit el límit màxim diari de nous comptes/registres. Provau demà." + +#: ../../mod/register.php:185 +msgid "Terms of Service" +msgstr "Condicions del Servei" + +#: ../../mod/register.php:191 +#, php-format +msgid "I accept the %s for this website" +msgstr "Accepto el %s per a aquest lloc web" + +#: ../../mod/register.php:193 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "Tinc més de 13 anys i accepto les %s d'aquest lloc web" + +#: ../../mod/register.php:212 +msgid "Membership on this site is by invitation only." +msgstr "La pertinença en aquest lloc es per invitació exclusivament." + +#: ../../mod/register.php:213 +msgid "Please enter your invitation code" +msgstr "Si et plau, introdueix el teu codi d'invitació" + +#: ../../mod/register.php:216 +msgid "Your email address" +msgstr "La teva adreça de correu electrónic" + +#: ../../mod/register.php:217 +msgid "Choose a password" +msgstr "Tria una contrasenya" + +#: ../../mod/register.php:218 +msgid "Please re-enter your password" +msgstr "Si et plau, re-entra la contrasenya" + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "L'esborrat de comptes no està permès fins que transcorren 48 hores des de l'últim canvi de contrasenya." + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "Esborra el compte" + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "WARNING: " +msgstr "ALERTA:" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This account and all its channels will be completely removed from the " +"network. " +msgstr "Aquest compte i tots els seus canals s'estan apunt d'esborrar totalment de la xarxa." + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "This action is permanent and can not be undone!" +msgstr "Aquesta acció és irreversible!" + +#: ../../mod/removeaccount.php:59 ../../mod/removeme.php:59 +msgid "Please enter your password for verification:" +msgstr "Aquesta acció requereix tornar a introduir la contrasenya:" + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "Esborra de la xarxa aquest compte, tots els seus canals, i tots els seus canals clons." + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "Per defecte, només les instancies dels canal ubicats en aquest concentrador poden esser esborrades de la xarxa" + +#: ../../mod/removeaccount.php:61 ../../mod/settings.php:720 +msgid "Remove Account" +msgstr "Esborra el Compte" + +#: ../../mod/help.php:49 ../../mod/help.php:55 ../../mod/help.php:61 +msgid "Help:" +msgstr "Ajuda:" + +#: ../../mod/help.php:76 ../../index.php:238 +msgid "Not Found" +msgstr "No s'ha pogut trobar la pàgina" + +#: ../../mod/help.php:100 +msgid "$Projectname Documentation" +msgstr "$Projectname Documentació" + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +#: ../../mod/update_home.php:21 ../../mod/update_public.php:21 +msgid "[Embedded content - reload page to view]" +msgstr "[Contingut embegut - recarrega la pàgina per veure-ho]" + +#: ../../mod/lockview.php:37 +msgid "Remote privacy information not available." +msgstr "informació privada remota no disponible." + +#: ../../mod/lockview.php:58 +msgid "Visible to:" +msgstr "Visible per:" + +#: ../../mod/settings.php:76 +msgid "Name is required" +msgstr "Es requereix un Nom" + +#: ../../mod/settings.php:80 +msgid "Key and Secret are required" +msgstr "Es requereix Clau (Key) i el Secret (Secret)" + +#: ../../mod/settings.php:130 +msgid "Diaspora Policy Settings updated." +msgstr "Actualitzats els Ajustos de Política de Diaspora." + +#: ../../mod/settings.php:238 +msgid "Passwords do not match. Password unchanged." +msgstr "Les contrasenyes no coincideixen. Contrasenya sense canvis." + +#: ../../mod/settings.php:242 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Les contrasenyes en blanc no estan permesas. Contrasenya sense canvis." + +#: ../../mod/settings.php:256 +msgid "Password changed." +msgstr "Contrasenya canviada." + +#: ../../mod/settings.php:258 +msgid "Password update failed. Please try again." +msgstr "L'actualització de la contrasenya va fallar. Si us plau, torneu a intentar-ho." + +#: ../../mod/settings.php:272 +msgid "Not valid email." +msgstr "E-correu no vàlid." + +#: ../../mod/settings.php:275 +msgid "Protected email address. Cannot change to that email." +msgstr "Adreça d'e-correu protegida. No es pot canviar a aquest e-correu." + +#: ../../mod/settings.php:284 +msgid "System failure storing new email. Please try again." +msgstr "Fallada del sistema al guardar un nou correu. Si us plau, proba de nou." + +#: ../../mod/settings.php:523 +msgid "Settings updated." +msgstr "Ajustes actualizados." + +#: ../../mod/settings.php:587 ../../mod/settings.php:613 +#: ../../mod/settings.php:649 +msgid "Add application" +msgstr "Afegir aplicatiu" + +#: ../../mod/settings.php:590 +msgid "Name of application" +msgstr "Nom de l'aplicatiu" + +#: ../../mod/settings.php:591 ../../mod/settings.php:617 +msgid "Consumer Key" +msgstr "Consumer Key" + +#: ../../mod/settings.php:591 ../../mod/settings.php:592 +msgid "Automatically generated - change if desired. Max length 20" +msgstr "Generat automàticament- Canvia-ho si ho vols. Max. longitud 20" + +#: ../../mod/settings.php:592 ../../mod/settings.php:618 +msgid "Consumer Secret" +msgstr "Consumer Secret" + +#: ../../mod/settings.php:593 ../../mod/settings.php:619 +msgid "Redirect" +msgstr "Redirecciona" + +#: ../../mod/settings.php:593 +msgid "" +"Redirect URI - leave blank unless your application specifically requires " +"this" +msgstr "URI redirigida - No canviar excepte perquè el teu aplicatiu ho requereixi." + +#: ../../mod/settings.php:594 ../../mod/settings.php:620 +msgid "Icon url" +msgstr "Icona de url" + +#: ../../mod/settings.php:594 +msgid "Optional" +msgstr "Opcional" + +#: ../../mod/settings.php:605 +msgid "You can't edit this application." +msgstr "No pots editar aquest aplicatiu." + +#: ../../mod/settings.php:648 +msgid "Connected Apps" +msgstr "Aplicatius Conectats" + +#: ../../mod/settings.php:652 +msgid "Client key starts with" +msgstr "La clau del client comença amb" + +#: ../../mod/settings.php:653 +msgid "No name" +msgstr "Sin nombre" + +#: ../../mod/settings.php:654 +msgid "Remove authorization" +msgstr "Elimina autorització" + +#: ../../mod/settings.php:668 +msgid "No feature settings configured" +msgstr "No hi ha opcions de les funcions configurades" + +#: ../../mod/settings.php:685 +msgid "Feature/Addon Settings" +msgstr "Ajustos de Característica/Afegit" + +#: ../../mod/settings.php:687 +msgid "Settings for the built-in Diaspora emulator" +msgstr "Ajustos pel emulador de Diaspora incorporat" + +#: ../../mod/settings.php:688 +msgid "Allow any Diaspora member to comment on your public posts" +msgstr "Permetre que cualsevol membre de Diaspora pugui comentar les teves entrades públiques" + +#: ../../mod/settings.php:689 +msgid "Enable the Diaspora protocol for this channel" +msgstr "Activa el protocol Diaspora en aquest canal" + +#: ../../mod/settings.php:690 +msgid "Diaspora Policy Settings" +msgstr "Política d'Ajustos de Diaspora" + +#: ../../mod/settings.php:691 +msgid "Prevent your hashtags from being redirected to other sites" +msgstr "Evita que els teus hashtags puguin ser redirigits a altres llocs" + +#: ../../mod/settings.php:715 +msgid "Account Settings" +msgstr "Ajustos de Compte" + +#: ../../mod/settings.php:716 +msgid "Enter New Password:" +msgstr "Entra la Nova Contrasenya" + +#: ../../mod/settings.php:717 +msgid "Confirm New Password:" +msgstr "Confirma la Nova Contrasenya:" + +#: ../../mod/settings.php:717 +msgid "Leave password fields blank unless changing" +msgstr "Deixa els camps de contrasenya en blanc llevat que la volguis canviar" + +#: ../../mod/settings.php:719 ../../mod/settings.php:1057 +msgid "Email Address:" +msgstr "Adreça de E-Correu:" + +#: ../../mod/settings.php:721 +msgid "Remove this account including all its channels" +msgstr "Esborra aquest compte inclosos tots els seus canals" + +#: ../../mod/settings.php:737 +msgid "Off" +msgstr "Apagat" + +#: ../../mod/settings.php:737 +msgid "On" +msgstr "Funcionant" + +#: ../../mod/settings.php:744 +msgid "Additional Features" +msgstr "Característiques Addicionals" + +#: ../../mod/settings.php:768 +msgid "Connector Settings" +msgstr "Ajustos de Connector" + +#: ../../mod/settings.php:807 +msgid "No special theme for mobile devices" +msgstr "No emprar tema especial per aparells mòbils" + +#: ../../mod/settings.php:810 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s - (Experimental)" + +#: ../../mod/settings.php:849 +msgid "Display Settings" +msgstr "Ajustos de Pantalla" + +#: ../../mod/settings.php:850 +msgid "Theme Settings" +msgstr "Ajustos de Tema" + +#: ../../mod/settings.php:851 +msgid "Custom Theme Settings" +msgstr "Ajustos Personals de Tema" + +#: ../../mod/settings.php:852 +msgid "Content Settings" +msgstr "Ajustos de Contingut" + +#: ../../mod/settings.php:858 +msgid "Display Theme:" +msgstr "Ajustos de Tema:" + +#: ../../mod/settings.php:859 +msgid "Mobile Theme:" +msgstr "Tema Mòbil:" + +#: ../../mod/settings.php:860 +msgid "Enable user zoom on mobile devices" +msgstr "Zoom d'usuari en dispositius mòbils" + +#: ../../mod/settings.php:861 +msgid "Update browser every xx seconds" +msgstr "Actualitza el navegador cada xx segons" + +#: ../../mod/settings.php:861 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Mínim de 10 segons, sense màxim" + +#: ../../mod/settings.php:862 +msgid "Maximum number of conversations to load at any time:" +msgstr "Nombre màxim de conversacions a càrregar cada vegada" + +#: ../../mod/settings.php:862 +msgid "Maximum of 100 items" +msgstr "Màxim de 100 elements" + +#: ../../mod/settings.php:863 +msgid "Show emoticons (smilies) as images" +msgstr "Mostra emoticons (smilies) com a imatges" + +#: ../../mod/settings.php:864 +msgid "Link post titles to source" +msgstr "Enllaça a l'origen els títols de l'entrada" + +#: ../../mod/settings.php:865 +msgid "System Page Layout Editor - (advanced)" +msgstr "Editor de Disseny de la Pàgina del Sistema - (avançat)" + +#: ../../mod/settings.php:868 +msgid "Use blog/list mode on channel page" +msgstr "Empra el mode blog/llista a la pàgina del canal" + +#: ../../mod/settings.php:868 ../../mod/settings.php:869 +msgid "(comments displayed separately)" +msgstr "(Observacions es mostren per separat)" + +#: ../../mod/settings.php:869 +msgid "Use blog/list mode on matrix page" +msgstr "Empra mode blog/llista a la pàgina de matrix" + +#: ../../mod/settings.php:870 +msgid "Channel page max height of content (in pixels)" +msgstr "Alçada màxima de contingut (en píxels) de la pàgina de Canal" + +#: ../../mod/settings.php:870 ../../mod/settings.php:871 +msgid "click to expand content exceeding this height" +msgstr "Clic per expandir el contingut que excedeixi aquesta alçada" + +#: ../../mod/settings.php:871 +msgid "Matrix page max height of content (in pixels)" +msgstr "Alçada màxima del contingut (en píxels) de la pàgina Matrix" + +#: ../../mod/settings.php:905 +msgid "Nobody except yourself" +msgstr "Ningú excepte tú" + +#: ../../mod/settings.php:906 +msgid "Only those you specifically allow" +msgstr "Només allò que específicament permetis" + +#: ../../mod/settings.php:907 +msgid "Approved connections" +msgstr "Connexions aprovades" + +#: ../../mod/settings.php:908 +msgid "Any connections" +msgstr "Qualsevol connexió" + +#: ../../mod/settings.php:909 +msgid "Anybody on this website" +msgstr "Qualsevol en aquest lloc" + +#: ../../mod/settings.php:910 +msgid "Anybody in this network" +msgstr "Qualsevol en aquesta xarxa" + +#: ../../mod/settings.php:911 +msgid "Anybody authenticated" +msgstr "Qualsevol autenticat" + +#: ../../mod/settings.php:912 +msgid "Anybody on the internet" +msgstr "Qualsevol a internet" + +#: ../../mod/settings.php:986 +msgid "Publish your default profile in the network directory" +msgstr "Publica el teu perfil per defecte al directori de la xarxa" + +#: ../../mod/settings.php:991 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "Ens permets suggerir-te com a potencial amic als nous membres?" + +#: ../../mod/settings.php:1000 +msgid "Your channel address is" +msgstr "La teva direcció del canal es" + +#: ../../mod/settings.php:1048 +msgid "Channel Settings" +msgstr "Ajustos del Canal" + +#: ../../mod/settings.php:1055 +msgid "Basic Settings" +msgstr "Ajustos Bàsics" + +#: ../../mod/settings.php:1058 +msgid "Your Timezone:" +msgstr "La teva Franja Horària" + +#: ../../mod/settings.php:1059 +msgid "Default Post Location:" +msgstr "Localització Predeterminada de les Entrades:" + +#: ../../mod/settings.php:1059 +msgid "Geographical location to display on your posts" +msgstr "Posició geogràfica a mostrar a les teves entrades" + +#: ../../mod/settings.php:1060 +msgid "Use Browser Location:" +msgstr "Empra la Localització del Navegador:" + +#: ../../mod/settings.php:1062 +msgid "Adult Content" +msgstr "Contingut per a Adults" + +#: ../../mod/settings.php:1062 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "Aquest canal publica freqúentment o amb regularitat contingut per a adults. (Si us plau, etiqueti qualsevol material per a adults amb #NSFW)" + +#: ../../mod/settings.php:1064 +msgid "Security and Privacy Settings" +msgstr "Ajustos de Seguretat i Privacitat" + +#: ../../mod/settings.php:1066 +msgid "Your permissions are already configured. Click to view/adjust" +msgstr "Els teus permisos estan configurats. Clic per veure/ajustar" + +#: ../../mod/settings.php:1068 +msgid "Hide my online presence" +msgstr "Amaga la meva presencia en línia" + +#: ../../mod/settings.php:1068 +msgid "Prevents displaying in your profile that you are online" +msgstr "Evita mostrar en el teu perfil, que estàs en línia" + +#: ../../mod/settings.php:1070 +msgid "Simple Privacy Settings:" +msgstr "Ajustos simples de privacitat:" + +#: ../../mod/settings.php:1071 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "Molt públic - extremadament permissiu (s'ha d'anar en compte)" + +#: ../../mod/settings.php:1072 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "Normal - públic per defecte, privat quan es desitgi (similar als permisos de xarxa social, però amb millor privacitat)" + +#: ../../mod/settings.php:1073 +msgid "Private - default private, never open or public" +msgstr "Privat - privat per defecte, mai públic o obert" + +#: ../../mod/settings.php:1074 +msgid "Blocked - default blocked to/from everybody" +msgstr "Bloquejat - tothom bloquejat per defecte" + +#: ../../mod/settings.php:1076 +msgid "Allow others to tag your posts" +msgstr "Permet a altres etiquetar les teves entrades" + +#: ../../mod/settings.php:1076 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "Sovint emprat per la comunitat per marcar retroactivament contingut inapropiat" + +#: ../../mod/settings.php:1078 +msgid "Advanced Privacy Settings" +msgstr "Ajustos avançats de privacitat" + +#: ../../mod/settings.php:1080 +msgid "Expire other channel content after this many days" +msgstr "El contingut d'altes canals caduca després d'aquests dies" + +#: ../../mod/settings.php:1080 +msgid "0 or blank prevents expiration" +msgstr "0 o vuit evita caducitat" + +#: ../../mod/settings.php:1081 +msgid "Maximum Friend Requests/Day:" +msgstr "Nombre màxim de peticions d'amistat per dia" + +#: ../../mod/settings.php:1081 +msgid "May reduce spam activity" +msgstr "Pot reduir l'SPAM" + +#: ../../mod/settings.php:1082 +msgid "Default Post Permissions" +msgstr "Permisos de publicació per defecte" + +#: ../../mod/settings.php:1087 +msgid "Channel permissions category:" +msgstr "Categoria de permisos de canal:" + +#: ../../mod/settings.php:1093 +msgid "Maximum private messages per day from unknown people:" +msgstr "Nombre màxim de missatges privats de desconeguts al dia:" + +#: ../../mod/settings.php:1093 +msgid "Useful to reduce spamming" +msgstr "Útil per a reduir l'spam" + +#: ../../mod/settings.php:1096 +msgid "Notification Settings" +msgstr "Ajustos de notificacions" + +#: ../../mod/settings.php:1097 +msgid "By default post a status message when:" +msgstr "Per defecte envia un missatge d'estat quan:" + +#: ../../mod/settings.php:1098 +msgid "accepting a friend request" +msgstr "Acceptar una sol·licitud d'amistat" + +#: ../../mod/settings.php:1099 +msgid "joining a forum/community" +msgstr "Apuntar-se a un fòrum o comunitat" + +#: ../../mod/settings.php:1100 +msgid "making an interesting profile change" +msgstr "faci un canvi interesant al perfil" + +#: ../../mod/settings.php:1101 +msgid "Send a notification email when:" +msgstr "Notifica per correu quan:" + +#: ../../mod/settings.php:1102 +msgid "You receive a connection request" +msgstr "Rebi una petició de connexió" + +#: ../../mod/settings.php:1103 +msgid "Your connections are confirmed" +msgstr "Es confirma una connexió" + +#: ../../mod/settings.php:1104 +msgid "Someone writes on your profile wall" +msgstr "Algú ha escrit al mur del teu perfil" + +#: ../../mod/settings.php:1105 +msgid "Someone writes a followup comment" +msgstr "Algú ha escrit un comentari de resposta" + +#: ../../mod/settings.php:1106 +msgid "You receive a private message" +msgstr "Rebi un missatge privat" + +#: ../../mod/settings.php:1107 +msgid "You receive a friend suggestion" +msgstr "Rebi una suggerència d'amistat" + +#: ../../mod/settings.php:1108 +msgid "You are tagged in a post" +msgstr "Estàs etiquetat a l'entrada" + +#: ../../mod/settings.php:1109 +msgid "You are poked/prodded/etc. in a post" +msgstr "S'enfoten/te piquen/etc. en una entrada" + +#: ../../mod/settings.php:1112 +msgid "Show visual notifications including:" +msgstr "Mostra notificacion visuals, com ara:" + +#: ../../mod/settings.php:1114 +msgid "Unseen matrix activity" +msgstr "Activitat no vista a la xarxa" + +#: ../../mod/settings.php:1115 +msgid "Unseen channel activity" +msgstr "Activitat no vista del canal" + +#: ../../mod/settings.php:1116 +msgid "Unseen private messages" +msgstr "Missatges privats no llegits" + +#: ../../mod/settings.php:1116 ../../mod/settings.php:1121 +#: ../../mod/settings.php:1122 ../../mod/settings.php:1123 +msgid "Recommended" +msgstr "Recomanat" + +#: ../../mod/settings.php:1117 +msgid "Upcoming events" +msgstr "Esdeveniments propers" + +#: ../../mod/settings.php:1118 +msgid "Events today" +msgstr "Esdeveniments d'avui" + +#: ../../mod/settings.php:1119 +msgid "Upcoming birthdays" +msgstr "Aniversaris propers" + +#: ../../mod/settings.php:1119 +msgid "Not available in all themes" +msgstr "No està disponible en tots els temes" + +#: ../../mod/settings.php:1120 +msgid "System (personal) notifications" +msgstr "Notificacions (personals) de sistema" + +#: ../../mod/settings.php:1121 +msgid "System info messages" +msgstr "Missatges d'informació del sistema" + +#: ../../mod/settings.php:1122 +msgid "System critical alerts" +msgstr "Alertes crítiques del sistema" + +#: ../../mod/settings.php:1123 +msgid "New connections" +msgstr "Noves connexions" + +#: ../../mod/settings.php:1124 +msgid "System Registrations" +msgstr "Registres del sistema" + +#: ../../mod/settings.php:1125 +msgid "" +"Also show new wall posts, private messages and connections under Notices" +msgstr "Mostra també les entrades de mur noves, les entrades privades i les connexions a \"Notícies\"" + +#: ../../mod/settings.php:1127 +msgid "Notify me of events this many days in advance" +msgstr "Notifica'm dels esdeveniments amb aquests dies d'antelació" + +#: ../../mod/settings.php:1127 +msgid "Must be greater than 0" +msgstr "Ha de ser més gran que 0" + +#: ../../mod/settings.php:1129 +msgid "Advanced Account/Page Type Settings" +msgstr "Ajustos avançats de compte i tipus de pàgina" + +#: ../../mod/settings.php:1130 +msgid "Change the behaviour of this account for special situations" +msgstr "Modifica el comportament d'aquest compte en situacions especials" + +#: ../../mod/settings.php:1133 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "Activa el mode d'expert (a Ajustos > Més funcions)" + +#: ../../mod/settings.php:1134 +msgid "Miscellaneous Settings" +msgstr "Ajustos diversos" + +#: ../../mod/settings.php:1136 +msgid "Personal menu to display in your channel pages" +msgstr "Menú personal per mostrar en les teves pàgines de canal" + +#: ../../mod/settings.php:1137 ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "Elimina el canal" + +#: ../../mod/settings.php:1138 +msgid "Remove this channel." +msgstr "Elimina aquest canal." + +#: ../../mod/id.php:11 +msgid "First Name" +msgstr "Nom" + +#: ../../mod/id.php:12 +msgid "Last Name" +msgstr "Cognoms" + +#: ../../mod/id.php:13 +msgid "Nickname" +msgstr "Àlies" + +#: ../../mod/id.php:14 +msgid "Full Name" +msgstr "Nom Sencer" + +#: ../../mod/id.php:20 +msgid "Profile Photo 16px" +msgstr "Foto del Perfil 16px" + +#: ../../mod/id.php:21 +msgid "Profile Photo 32px" +msgstr "Foto del Perfil 32px" + +#: ../../mod/id.php:22 +msgid "Profile Photo 48px" +msgstr "Foto del Perfil 48px" + +#: ../../mod/id.php:23 +msgid "Profile Photo 64px" +msgstr "Foto del Perfil 64px" + +#: ../../mod/id.php:24 +msgid "Profile Photo 80px" +msgstr "Foto del Perfil 80px" + +#: ../../mod/id.php:25 +msgid "Profile Photo 128px" +msgstr "Foto del Perfil 128px" + +#: ../../mod/id.php:26 +msgid "Timezone" +msgstr "Zona horària" + +#: ../../mod/id.php:27 +msgid "Homepage URL" +msgstr "URL de la pàgina d'inici" + +#: ../../mod/id.php:29 +msgid "Birth Year" +msgstr "Any de Naixement" + +#: ../../mod/id.php:30 +msgid "Birth Month" +msgstr "Mes de Naixement" + +#: ../../mod/id.php:31 +msgid "Birth Day" +msgstr "Dia de Naixement" + +#: ../../mod/id.php:32 +msgid "Birthdate" +msgstr "Aniversari" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "Conversació eliminada." + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "Sense missatges." + +#: ../../mod/message.php:72 ../../mod/mail.php:336 +msgid "Delete conversation" +msgstr "Conversació esborrada" + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "D, d M Y - g:i A" + +#: ../../mod/mood.php:131 +msgid "Set your current mood and tell your friends" +msgstr "Estableix el teu estat d'ànim actual i digues-li als teus amics" + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "Total de vots" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "Valoració Mitja" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "L'esborrat de canals no està permès fins que transcorren 48 hores des de l'últim canvi de contrasenya." + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "Elimina Aquest Canal" + +#: ../../mod/removeme.php:58 +msgid "This channel will be completely removed from the network. " +msgstr "Aquest canal serà completament eliminat de la xarxa." + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "Elimina aquest canal i els seus clons de la xarxa" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "Per defecte, només la instancia del canal ubicat en aquest concentrador pot esser esborrat de la xarxa" + +#: ../../mod/connedit.php:267 +msgid "is now connected to" +msgstr "Ara està conectat amb" + +#: ../../mod/connedit.php:380 +msgid "Could not access address book record." +msgstr "No puc accedir al registre del contacte" + +#: ../../mod/connedit.php:394 +msgid "Refresh failed - channel is currently unavailable." +msgstr "Ha fallat la recàrrega - el canal es actualment inaccesible." + +#: ../../mod/connedit.php:406 ../../mod/connedit.php:418 +#: ../../mod/connedit.php:430 ../../mod/connedit.php:442 +#: ../../mod/connedit.php:458 +msgid "Unable to set address book parameters." +msgstr "No es poden ajustar els paràmetres dels contactes." + +#: ../../mod/connedit.php:482 +msgid "Connection has been removed." +msgstr "S'han eliminat les conexions." + +#: ../../mod/connedit.php:501 +#, php-format +msgid "View %s's profile" +msgstr "Mostra el perfil de %s" + +#: ../../mod/connedit.php:505 +msgid "Refresh Permissions" +msgstr "Recarrega els Permissos" + +#: ../../mod/connedit.php:508 +msgid "Fetch updated permissions" +msgstr "Obté els permisos actualitzats" + +#: ../../mod/connedit.php:512 +msgid "Recent Activity" +msgstr "Activitat Recent" + +#: ../../mod/connedit.php:515 +msgid "View recent posts and comments" +msgstr "Mostra les entrades i comentaris recents" + +#: ../../mod/connedit.php:522 +msgid "Block (or Unblock) all communications with this connection" +msgstr "Boqueja (o Desbloqueja) les comunicacions amb aquesta connexió" + +#: ../../mod/connedit.php:523 +msgid "This connection is blocked!" +msgstr "Aquesta connexió està bloquejada!" + +#: ../../mod/connedit.php:527 +msgid "Unignore" +msgstr "Inhabilita" + +#: ../../mod/connedit.php:527 ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "Ignora" + +#: ../../mod/connedit.php:530 +msgid "Ignore (or Unignore) all inbound communications from this connection" +msgstr "Ignora (o Considera) les communicacions entrants d'aquesta connexió" + +#: ../../mod/connedit.php:531 +msgid "This connection is ignored!" +msgstr "Aquesta connexió es ignorada!" + +#: ../../mod/connedit.php:535 +msgid "Unarchive" +msgstr "Desarxiva" + +#: ../../mod/connedit.php:535 +msgid "Archive" +msgstr "Arxiva" + +#: ../../mod/connedit.php:538 +msgid "" +"Archive (or Unarchive) this connection - mark channel dead but keep content" +msgstr "Arxiva (o Desarxiva) aquesta connexió - Marca el canal com a mort pero manté el contingut " + +#: ../../mod/connedit.php:539 +msgid "This connection is archived!" +msgstr "Aquesta connexió està arxivada!" + +#: ../../mod/connedit.php:543 +msgid "Unhide" +msgstr "Mostra" + +#: ../../mod/connedit.php:543 +msgid "Hide" +msgstr "Amaga" + +#: ../../mod/connedit.php:546 +msgid "Hide or Unhide this connection from your other connections" +msgstr "Amaga (o Mostra) aquesta connexió de les altres connexions teves" + +#: ../../mod/connedit.php:547 +msgid "This connection is hidden!" +msgstr "Aquesta connexió està amagada!" + +#: ../../mod/connedit.php:554 +msgid "Delete this connection" +msgstr "Elimina aquesta connexió" + +#: ../../mod/connedit.php:635 +msgid "Approve this connection" +msgstr "Apccepta aquesta connexió" + +#: ../../mod/connedit.php:635 +msgid "Accept connection to allow communication" +msgstr "Accepta la connexió per permetre la comunicació" + +#: ../../mod/connedit.php:640 +msgid "Set Affinity" +msgstr "Ajusta l'Afinitat" + +#: ../../mod/connedit.php:643 +msgid "Set Profile" +msgstr "Ajusta el Perfil" + +#: ../../mod/connedit.php:646 +msgid "Set Affinity & Profile" +msgstr "Ajusta Afinitat i Perfil" + +#: ../../mod/connedit.php:663 +msgid "Apply these permissions automatically" +msgstr "Aplica aquests permissos automaticament" + +#: ../../mod/connedit.php:665 +msgid "This connection's address is" +msgstr "La direcció d'aquesta connexió es" + +#: ../../mod/connedit.php:668 +msgid "" +"The permissions indicated on this page will be applied to all new " +"connections." +msgstr "Els permisos indicats en aquesta pàgina seran aplicats a totes les noves connexions." + +#: ../../mod/connedit.php:670 +msgid "Slide to adjust your degree of friendship" +msgstr "Llisca per ajustar el nivell d'amistat" + +#: ../../mod/connedit.php:672 +msgid "Slide to adjust your rating" +msgstr "Llisca per ajustar la valoració" + +#: ../../mod/connedit.php:673 ../../mod/connedit.php:678 +msgid "Optionally explain your rating" +msgstr "Opcionalment pots explicar la teva valoració" + +#: ../../mod/connedit.php:675 +msgid "Custom Filter" +msgstr "Filtre a mida" + +#: ../../mod/connedit.php:676 +msgid "Only import posts with this text" +msgstr "Importa exclusivament entrades amb aquest text" + +#: ../../mod/connedit.php:676 ../../mod/connedit.php:677 +msgid "" +"words one per line or #tags or /patterns/, leave blank to import all posts" +msgstr "paraules una per línia o #etiquetes o /patrons/, deixar en blanc per importar totes les entrades" + +#: ../../mod/connedit.php:677 +msgid "Do not import posts with this text" +msgstr "No importar entrades amb aquest text" + +#: ../../mod/connedit.php:679 +msgid "This information is public!" +msgstr "Aquesta informació es pública!" + +#: ../../mod/connedit.php:684 +msgid "Connection Pending Approval" +msgstr "Connexió Pendent d'Aprovació" + +#: ../../mod/connedit.php:685 +msgid "Connection Request" +msgstr "Petició de Connexió" + +#: ../../mod/connedit.php:686 +#, php-format +msgid "" +"(%s) would like to connect with you. Please approve this connection to allow" +" communication." +msgstr "(%s) voldria conectar amb tu. Aprova aquesta connexió per permetre la connexió." + +#: ../../mod/connedit.php:688 +msgid "Approve Later" +msgstr "Aprovar més tard" + +#: ../../mod/connedit.php:691 +msgid "inherited" +msgstr "heretat" + +#: ../../mod/connedit.php:693 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Tria el perfil que vols mostrar a %s quan es vegi el perfil segur." + +#: ../../mod/connedit.php:695 +msgid "Their Settings" +msgstr "Els seus Ajustos" + +#: ../../mod/connedit.php:696 +msgid "My Settings" +msgstr "Els Meus Ajustos" + +#: ../../mod/connedit.php:698 +msgid "Individual Permissions" +msgstr "Permisos Individuals" + +#: ../../mod/connedit.php:699 +msgid "" +"Some permissions may be inherited from your channel's privacy settings, which have higher " +"priority than individual settings. You can not change those" +" settings here." +msgstr "Alguns permisos poden ser heretats dels teus canals ajustos de privacitat, Els quals tenen més prioritat que els ajustos individuals. No pots canviar aquests ajustos aquí." + +#: ../../mod/connedit.php:700 +msgid "" +"Some permissions may be inherited from your channel's privacy settings, which have higher " +"priority than individual settings. You can change those settings here but " +"they wont have any impact unless the inherited setting changes." +msgstr "Alguns permisos poden ser heretats dels teus canals ajustos de privacitat, Els quals tenen més prioritat que els ajustos individuals. Pots canviar aquests ajustos aquí pero no tindran cap impacte fins que no canviis els ajustos heretats." + +#: ../../mod/connedit.php:701 +msgid "Last update:" +msgstr "Darrera actualització:" + +#: ../../mod/rmagic.php:40 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Em trobat un problema durant l'inici de sessió amb el OpenID que has facilitat. verifica l'ortografia correcta de la ID." + +#: ../../mod/rmagic.php:40 +msgid "The error message was:" +msgstr "El missatge d'error fou:" + +#: ../../mod/rmagic.php:44 +msgid "Authentication failed." +msgstr "Ha fallat l'autentificació." + +#: ../../mod/rmagic.php:84 +msgid "Remote Authentication" +msgstr "Autentificació Remota" + +#: ../../mod/rmagic.php:85 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "Introdueix la teva adreça del canal (eg canal@exemple.com)" + +#: ../../mod/rmagic.php:86 +msgid "Authenticate" +msgstr "Autentica't" + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "Incapaç de trobar el destinatari." + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "Incapaç de comunicar amb el canal demanat." + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "No puc verificar el canal demanat." + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "El canal seleccionat te restriccions sobre els missatges privats. L'enviament ha fallat." + +#: ../../mod/mail.php:139 +msgid "Message deleted." +msgstr "Missatge eliminat." + +#: ../../mod/mail.php:156 +msgid "Message recalled." +msgstr "Recupera el missatge." + +#: ../../mod/mail.php:225 +msgid "Send Private Message" +msgstr "Envia Missatge Privat" + +#: ../../mod/mail.php:226 ../../mod/mail.php:343 +msgid "To:" +msgstr "Per:" + +#: ../../mod/mail.php:231 ../../mod/mail.php:345 +msgid "Subject:" +msgstr "Assumpte:" + +#: ../../mod/mail.php:242 +msgid "Send" +msgstr "Envia" + +#: ../../mod/mail.php:269 +msgid "Message not found." +msgstr "Missatge no trobat." + +#: ../../mod/mail.php:312 +msgid "Delete message" +msgstr "Elimina el missatge" + +#: ../../mod/mail.php:313 +msgid "Recall message" +msgstr "Recupera el missatge" + +#: ../../mod/mail.php:315 +msgid "Message has been recalled." +msgstr "El missatge s'ha recuperat." + +#: ../../mod/mail.php:332 +msgid "Private Conversation" +msgstr "Conversació Privada" + +#: ../../mod/mail.php:338 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Comunicació segura no disponible. Pots respondre des de la pàgina de perfil del remitent." + +#: ../../mod/mail.php:342 +msgid "Send Reply" +msgstr "Envia Resposta" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Sol·licitud d'identificació invàlida." + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "Descarta" + +#: ../../mod/regmod.php:11 +msgid "Please login." +msgstr "Inicia Sessió." + +#: ../../mod/post.php:235 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please" +" logout and retry." +msgstr "Autenticació remota bloquejada. Ha iniciat sessió en aquest lloc a nivell local. Si us plau, tanca la sessió i torna-ho a intentar." + +#: ../../mod/new_channel.php:109 +msgid "Add a Channel" +msgstr "Afegeix un Canal" + +#: ../../mod/new_channel.php:110 +msgid "" +"A channel is your own collection of related web pages. A channel can be used" +" to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "Un canal es la teva pròpia col·lecció de pàgines web. Un canal pot emprat per mantenir perfils a una xarxa social, blocs, grups de conversació, fòrums, pàgines de famosos, i molt més. Pots crear tants canals com el teu servei d'internet et permeti." + +#: ../../mod/new_channel.php:113 +msgid "Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " +msgstr "Exemples: \"Joan Tou\", \"Manel i els seus esquirols\", \"Fútbol\", \"Grup de Gegants\"" + +#: ../../mod/new_channel.php:114 +msgid "Choose a short nickname" +msgstr "Tria un àlies curt" + +#: ../../mod/new_channel.php:115 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "El teu àlies es pot emprar per crear un canal fàcilment memoritzatble (com una adreça de correu electrònic) que pot ser compartit amb altres." + +#: ../../mod/new_channel.php:116 +msgid "Or import an existing channel from another location" +msgstr "O importa un canal existent d'un altre lloc" + +#: ../../mod/new_channel.php:118 +msgid "" +"Please choose a channel type (such as social networking or community forum) " +"and privacy requirements so we can select the best permissions for you" +msgstr "Tria un tipus de canal (com a xarxa social o fòrum comunitari) i els requisits de privacitat, així podem proposar el que te el permisos més adients." + +#: ../../mod/new_channel.php:119 +msgid "Channel Type" +msgstr "tipus de Canal" + +#: ../../mod/new_channel.php:119 +msgid "Read more about roles" +msgstr "Llegix més sobre els rols" + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "Aplicació instal·lada." + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "Aplicació amb errors" + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "Codi embegut" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "Edita l'Aplicació" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "Crea l'Aplicació" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "Nom de l'Aplicació" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "Ubicació (URL) de l'aplicació" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "Foto icona URL" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "80 x 80 pixels - opcional" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "Versió ID" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "Preu de l'aplicació" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "Ubicació (URL) per comprar l'aplicació" + +#: ../../mod/ping.php:263 +msgid "sent you a private message" +msgstr "Se t'ha enviat un missatge privat" + +#: ../../mod/ping.php:314 +msgid "added your channel" +msgstr "el teu canal s'ha afegit" + +#: ../../mod/ping.php:355 +msgid "posted an event" +msgstr "enviat un event" + +#: ../../mod/layouts.php:176 +msgid "Comanche page description language help" +msgstr "Pgina d'ajuda del llenguatge Comanche" + +#: ../../mod/layouts.php:180 +msgid "Layout Description" +msgstr "Descripció del Disseny de la Pàgina" + +#: ../../mod/layouts.php:185 +msgid "Download PDL file" +msgstr "Descarrega l'arxiu PDL" + +#: ../../mod/home.php:73 +#, php-format +msgid "Welcome to %s" +msgstr "Benvingut a %s" + +#: ../../mod/page.php:126 +msgid "Lorem Ipsum" +msgstr "Lorem Ipsum" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "Favorit afegit" + +#: ../../mod/bookmarks.php:60 +msgid "My Bookmarks" +msgstr "Els Meus Favorits" + +#: ../../mod/bookmarks.php:71 +msgid "My Connections Bookmarks" +msgstr "Les connexions dels meus Favorits" + +#: ../../mod/channel.php:97 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "Permisos insuficients. Petició redirigida a la pàgina del perfil." + +#: ../../mod/pconfig.php:27 ../../mod/pconfig.php:60 +msgid "This setting requires special processing and editing has been blocked." +msgstr "Aquest ajust requereix un procés espedial i l'edició esta bloquejada." + +#: ../../mod/pconfig.php:49 +msgid "Configuration Editor" +msgstr "Editor de Configuració" + +#: ../../mod/pconfig.php:50 +msgid "" +"Warning: Changing some settings could render your channel inoperable. Please" +" leave this page unless you are comfortable with and knowledgeable about how" +" to correctly use this feature." +msgstr "atenció: Realitzar segons quins ajustos pot fer el canal inoperable. Deixa aquesta pàgina si no estas segur i tens suficients coneixements sobre l'ús correcte d'aquesta característica." + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "No hi ha suggerencies. Si es un lloc nou, espera 24 hores i proba de nou." + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "Sondeija" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "Mostra els Resultats" + +#: ../../mod/service_limits.php:19 +msgid "No service class restrictions found." +msgstr "No s'han trobat restriccions de clase." + +#: ../../mod/sharedwithme.php:94 +msgid "Files: shared with me" +msgstr "Arxius: compartits amb jo" + +#: ../../mod/sharedwithme.php:96 +msgid "NEW" +msgstr "NOU" + +#: ../../mod/sharedwithme.php:99 +msgid "Remove all files" +msgstr "Esborra tots els arxius" + +#: ../../mod/sharedwithme.php:100 +msgid "Remove this file" +msgstr "Esborra l'arxiu" + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "Esquema Predeterminat" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "Sans-Serif" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "Monospace" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Theme settings" +msgstr "Ajustos de tema" + +#: ../../view/theme/apw/php/config.php:260 +msgid "Set scheme" +msgstr "Ajustos d'esquema" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set font-size for posts and comments" +msgstr "Ajusta la mida del tipus de lletra per a entrades i comentaris" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "Ajusta el tipus de lletra" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "Ajusta el conjunt d'icones" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "Ajusta la mida gran de l'ombra, predeterminat a 15px 15px 15px" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "Ajusta la mida petita de l'ombra, predeterminat a 5px 5px 5px" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "Ajusta el color de l'ombra, predeterminat a #000" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "Ajusta la mida del radi, predeterminat a 5px" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "Ajusta el gruix de línia per entrades i comentaris" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "Ajusta l'imatge de fons" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "Ajusta els adjunts en segon pla" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "Ajusta el color en segon pla" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "Ajusta la secció d'imatge en segon pla" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "Ajusta el color de la secció en segon pla" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "Ajuste el color dels articles - empra codi hexadecimal" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "ajusta el color dels enlaços - empra codi hexadecimal" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "Ajusta l'amplada màxima dels articles. Predeterminat a 400px" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "Ajusta l'amplada minima dels articles. Predeterminat a 240px" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "Ajusta l'amplada de l'embolcall del contingut genèric. Predeterminat a 48%" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "Ajusta el color del tipus de lletra - empra codi hexadecimal" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "Ajusta la mida de l'element en segon pla" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "Opacitat de l'article" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "Mostra tan sols les previsualitzacions de les entrades" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "Mostra la barra lateral a la pàgina del canal" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "Color de la barra de navegació" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "Article flotant" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "Desplaçament esquerra de l'element de secció" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "Desplaçament dret de l'element de secció" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "Amplada de la secció" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "Desplaçament esquerra del costat" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "Desplaçament dret de l'element del costat" + +#: ../../view/theme/redbasic/php/config.php:82 +msgid "Light (Red Matrix default)" +msgstr "Clar (predeterminat)" + +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Select scheme" +msgstr "Tria esquema" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Narrow navbar" +msgstr "Barra de navegació estreta" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar background color" +msgstr "Color de fons de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation bar gradient top color" +msgstr "Gradient de color de la part superior de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation bar gradient bottom color" +msgstr "Gradient de color de la part inferior de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation active button gradient top color" +msgstr "Gradient de color de la part superior del botó actiu de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation active button gradient bottom color" +msgstr "Gradient de color de la part inferior del botó actiu de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar border color " +msgstr "Color de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "Navigation bar icon color " +msgstr "Color de la icona de la barra de navegació" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Navigation bar active icon color " +msgstr "Color de la icona de la barra de navegació activa" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "link color" +msgstr "Color d'enllaç" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set font-color for banner" +msgstr "Ajusta el color del tipus de lletra per la senyera" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color" +msgstr "Ajusta el color de fons" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background image" +msgstr "Ajusta la imatge de fons" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the background color of items" +msgstr "ajusta el color dels articles de fons" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the background color of comments" +msgstr "Ajusta el color dels comentaris en segon pla" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the border color of comments" +msgstr "Canviar el color del marge dels comentaris" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the indent for comments" +msgstr "ajusta l'indentació dels comentaris" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set the basic color for item icons" +msgstr "ajusta el color basic per les icones dels articles" + +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set the hover color for item icons" +msgstr "Ajusta el color de la libració de les icones dels articles" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-size for the entire application" +msgstr "Ajusta la mida del tipus de lletra per tota l'aplicació" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Example: 14px" +msgstr "Exemple: 14px" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set font-color for posts and comments" +msgstr "Ajusta el color del tipus de lletra per entrades i comentaris" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set radius of corners" +msgstr "Ajusta el radi de les cantonades" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Set shadow depth of photos" +msgstr "Ajusta la profunditat d'ombres de les fotos" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set maximum width of content region in pixel" +msgstr "Ajusta l'amplada màxima de la zona de contingut en pixels" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Leave empty for default width" +msgstr "Deixa en blanc per l'amplada predeterminada" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Center page content" +msgstr "Contingut del centre de la pàgina" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "Ajusta la opacitat mínima de la harra de navegació - per amagar-la" + +#: ../../view/theme/redbasic/php/config.php:131 +msgid "Set size of conversation author photo" +msgstr "Ajusta la mida de la foto del autor a la conversa" + +#: ../../view/theme/redbasic/php/config.php:132 +msgid "Set size of followup author photos" +msgstr "Ajusta la mida del seguidor de les fotos de l'autor" + +#: ../../boot.php:1356 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "L'actualització %s ha fallat. Mira el registre d'errors." + +#: ../../boot.php:1359 +#, php-format +msgid "Update Error at %s" +msgstr "Error d'Actualització a %s" + +#: ../../boot.php:1526 +msgid "" +"Create an account to access services and applications within the Red Matrix" +msgstr "Crea un compte per accedir als serveis i aplicacions dins de RedMatrix" + +#: ../../boot.php:1554 +msgid "Password" +msgstr "Contrasenya" + +#: ../../boot.php:1555 +msgid "Remember me" +msgstr "Recorda'm" + +#: ../../boot.php:1558 +msgid "Forgot your password?" +msgstr "Has perdut la Contrasenya?" + +#: ../../boot.php:2178 +msgid "toggle mobile" +msgstr "canvia a format per a mòbils" + +#: ../../boot.php:2313 +msgid "Website SSL certificate is not valid. Please correct." +msgstr "El certificat SSL és invalid, soluciona-ho, si us plau." + +#: ../../boot.php:2316 +#, php-format +msgid "[red] Website SSL error for %s" +msgstr "[red] Error de SSL per la web %s" + +#: ../../boot.php:2353 +msgid "Cron/Scheduled tasks not running." +msgstr "No s'estan executan les tasques programades al cron." + +#: ../../boot.php:2357 +#, php-format +msgid "[red] Cron tasks not running on %s" +msgstr "[red] No s'estan executan les tasques programades del cron a %s" diff --git a/sources/view/ca/passchanged_eml.tpl b/sources/view/ca/passchanged_eml.tpl new file mode 100644 index 00000000..f0d62d9a --- /dev/null +++ b/sources/view/ca/passchanged_eml.tpl @@ -0,0 +1,19 @@ + +Apreciat/da {{$username}}, + + La teva contrasenya ha estat modificada com has sol·licitat. Pren nota d'aquesta informació +(o canvía immediatament la contrasenya amb quelcom que recordis). + + +Les teves dades d'accés son les següents: + +Lloc: {{$siteurl}} +Nom: {{$email}} +Contrasenya: {{$new_password}} + +Després d'accedir pots canviar la contrasenya des de la pàgina de configuració del teu perfil. + + + {{$sitename}} + + diff --git a/sources/view/ca/register_open_eml.tpl b/sources/view/ca/register_open_eml.tpl new file mode 100644 index 00000000..7da9a2b8 --- /dev/null +++ b/sources/view/ca/register_open_eml.tpl @@ -0,0 +1,22 @@ + +Apreciat/da {{$username}}, + + Gràcies per registrar-te en {{$sitename}}. El teu compte ha estat creat. + + +Les dades d'accés són les següents: + + +Lloc: {{$siteurl}} +Nom: {{$email}} +Contrasenya: {{$password}} + + +Després d'accedir pots canviar la teva contrasenya a la pàgina de "Configuració". + +Pren un moment per revisar les altres configuracions del compte en aquesta pàgina. + + +Gràcies i benvingut/da {{$sitename}}. + + diff --git a/sources/view/ca/register_verify_eml.tpl b/sources/view/ca/register_verify_eml.tpl new file mode 100644 index 00000000..651e8eff --- /dev/null +++ b/sources/view/ca/register_verify_eml.tpl @@ -0,0 +1,23 @@ + +S'ha rebut la sol·licitud de registre d'un nou usuari en +{{$sitename}} que requereix la teva aprovació. + +Les dades d'accés són els següents: + +Nom Complet: {{$username}} +Lloc: {{$siteurl}} +Nom: {{$email}} + + +Per aprovar aquesta sol·licitud, visita el següent enllaç: + +{{$siteurl}}/regmod/allow/{{$hash}} + +Per denegar la sol·licitud i eliminar el compte, per favor visita: + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Gràcies. + + diff --git a/sources/view/ca/strings.php b/sources/view/ca/strings.php new file mode 100644 index 00000000..aeb58f69 --- /dev/null +++ b/sources/view/ca/strings.php @@ -0,0 +1,2148 @@ +strings["Cannot locate DNS info for database server '%s'"] = "No s'ha trobat informació de DNS pel servidor de base de dades '%s'"; +$a->strings["Profile Photos"] = "Fotos del Perfil"; +$a->strings["Edit"] = "Edita"; +$a->strings["Frequently"] = "Freqüentment"; +$a->strings["Hourly"] = "Horariament"; +$a->strings["Twice daily"] = "Dos vegades al dia"; +$a->strings["Daily"] = "Diariament"; +$a->strings["Weekly"] = "Setmanalment"; +$a->strings["Monthly"] = "Mensualment"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Email"] = "Correu electrónic"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "LinkedIn"; +$a->strings["XMPP/IM"] = "XMPP/IM"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["created a new post"] = "Creada una nova entrada"; +$a->strings["commented on %s's post"] = "comentat a l'entrada de %s"; +$a->strings["No username found in import file."] = "No s'ha trobat nom d'usuari a l'arxiu d'importació."; +$a->strings["Unable to create a unique channel address. Import failed."] = "No s'ha pogut importar el canal perquè l'adreça única de canal no s'ha pogut crear."; +$a->strings["Import completed."] = "S'ha completat la importació."; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "Un grup esborrat amb aquest nom fou reviscolat. Els permisos dels items existents poden aplicar-se a aquest grup i qualsevol membre futur. Si no es això el que vols, si et plau, crea un altre grup amb un nom diferent."; +$a->strings["Default privacy group for new contacts"] = "Privacitat de grup predeterminada per a contactes nous"; +$a->strings["All Channels"] = "Tots els Canals"; +$a->strings["edit"] = "edita"; +$a->strings["Collections"] = "Col·leccions"; +$a->strings["Edit collection"] = "Edita col·leccions"; +$a->strings["Add new collection"] = "Afegeix una nova col·lecció"; +$a->strings["Channels not in any collection"] = "Canals a cap col·lecció"; +$a->strings["add"] = "afegeix"; +$a->strings["Not a valid email address"] = "Adreça de correu electrònic no vàlida"; +$a->strings["Your email domain is not among those allowed on this site"] = "El seu domini de correu electrònic no es troba entre els permesos en aquest lloc"; +$a->strings["Your email address is already registered at this site."] = "La teva adreça de correu electrònic ja esta registrada en aquest lloc"; +$a->strings["An invitation is required."] = "Es requereix Invitació"; +$a->strings["Invitation could not be verified."] = "L'invitació no ha pogut ser verificada"; +$a->strings["Please enter the required information."] = "Entra la informació sol·licitada"; +$a->strings["Failed to store account information."] = "Ha fallat guardar la informació del compte"; +$a->strings["Registration confirmation for %s"] = "Registre confirmat per %s"; +$a->strings["Registration request at %s"] = "Sol·licitud de registre a %s"; +$a->strings["Administrator"] = "Administrador"; +$a->strings["your registration password"] = "la teva contrasenya registrada"; +$a->strings["Registration details for %s"] = "Detalls del registre per %s"; +$a->strings["Account approved."] = "Compte aprovat."; +$a->strings["Registration revoked for %s"] = "Registre revocat per %s"; +$a->strings["Account verified. Please login."] = "Compte verificat. Si us plau, inicia sessió."; +$a->strings["Click here to upgrade."] = "Feu clic aquí per actualitzar."; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Aquesta acció és superior als límits establerts pel seu pla de subscripció."; +$a->strings["This action is not available under your subscription plan."] = "Aquesta acció no està disponible en el seu pla de subscripció."; +$a->strings["Miscellaneous"] = "Miscelania"; +$a->strings["YYYY-MM-DD or MM-DD"] = "YYYY-MM-DD o MM-DD"; +$a->strings["Required"] = "Requerit"; +$a->strings["never"] = "mai"; +$a->strings["less than a second ago"] = "fa menys d'un segon"; +$a->strings["year"] = "any"; +$a->strings["years"] = "anys"; +$a->strings["month"] = "mes"; +$a->strings["months"] = "mesos"; +$a->strings["week"] = "setmana"; +$a->strings["weeks"] = "setmanes"; +$a->strings["day"] = "dia"; +$a->strings["days"] = "dies"; +$a->strings["hour"] = "hora"; +$a->strings["hours"] = "hores"; +$a->strings["minute"] = "minut"; +$a->strings["minutes"] = "minuts"; +$a->strings["second"] = "segon"; +$a->strings["seconds"] = "segons"; +$a->strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = "Fa %1\$d i %2\$s"; +$a->strings["%1\$s's birthday"] = "Aniversari de %1\$s"; +$a->strings["Happy Birthday %1\$s"] = "Feliç Aniversari %1\$s"; +$a->strings["Directory Options"] = "Opcions de Directori"; +$a->strings["Safe Mode"] = "Mode Segur"; +$a->strings["No"] = "No"; +$a->strings["Yes"] = "Sí"; +$a->strings["Public Forums Only"] = "Només Fòrums Públics"; +$a->strings["This Website Only"] = "Només Aquest Lloc Web"; +$a->strings["New Page"] = "Pàgina Nova"; +$a->strings["View"] = "Mostra"; +$a->strings["Preview"] = "Avanç"; +$a->strings["Actions"] = "Accions"; +$a->strings["Page Link"] = "Enllaç a Pàgina"; +$a->strings["Title"] = "Títol"; +$a->strings["Created"] = "Creat"; +$a->strings["Edited"] = "Editat"; +$a->strings["Public Timeline"] = "Línia de Temps Pública"; +$a->strings["Default"] = "Predeterminat"; +$a->strings["Delete this item?"] = "Esborrar aquest item?"; +$a->strings["Comment"] = "Comentari"; +$a->strings["[+] show all"] = "[+] mostra tot"; +$a->strings["[-] show less"] = "[-] mostra menys"; +$a->strings["[+] expand"] = "[+] expandeix"; +$a->strings["[-] collapse"] = "[-] colapsa"; +$a->strings["Password too short"] = "Contrasenya massa curta"; +$a->strings["Passwords do not match"] = "Les paraules de pas no coincideixen"; +$a->strings["everybody"] = "tothom"; +$a->strings["Secret Passphrase"] = "Contrasenya Secreta"; +$a->strings["Passphrase hint"] = "Pista per la Contrasenya"; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = "Avis: Els permisos han canviat però encara no han estat enviats."; +$a->strings["close all"] = "tanca tot"; +$a->strings["Nothing new here"] = "Res de nou per aquí"; +$a->strings["Rate This Channel (this is public)"] = "Valora Aquest Canal (això es farà públic)"; +$a->strings["Rating"] = "Valora"; +$a->strings["Describe (optional)"] = "Descriu (opcional)"; +$a->strings["Submit"] = "Presenta"; +$a->strings["Please enter a link URL"] = "Si us plau, entra l'enllaç URL"; +$a->strings["Unsaved changes. Are you sure you wish to leave this page?"] = "Hi ha canvis sense desar, estàs segur que vols abandonar la pàgina?"; +$a->strings["timeago.prefixAgo"] = "horapasada.prefixFa"; +$a->strings["timeago.prefixFromNow"] = "timeago.prefixFromNow"; +$a->strings["ago"] = "fa"; +$a->strings["from now"] = "des d'ara"; +$a->strings["less than a minute"] = "menys d'un minut"; +$a->strings["about a minute"] = "prop d'un minut"; +$a->strings["%d minutes"] = "%d minuts"; +$a->strings["about an hour"] = "prop d'una hora"; +$a->strings["about %d hours"] = "al voltant de %d hores"; +$a->strings["a day"] = "un dia"; +$a->strings["%d days"] = "%d dies"; +$a->strings["about a month"] = "prop d'un mes"; +$a->strings["%d months"] = "%d mesos"; +$a->strings["about a year"] = "prop d'un any"; +$a->strings["%d years"] = "%d anys"; +$a->strings[" "] = " "; +$a->strings["timeago.numbers"] = "timeago.numbers"; +$a->strings["prev"] = "prev"; +$a->strings["first"] = "primer"; +$a->strings["last"] = "últim"; +$a->strings["next"] = "pròxim"; +$a->strings["older"] = "el més antic"; +$a->strings["newer"] = "El més nou"; +$a->strings["No connections"] = "Sense Connexions"; +$a->strings["%d Connection"] = array( + 0 => "%d Connexió", + 1 => "%d Connexions", +); +$a->strings["View Connections"] = "Veure Connexions"; +$a->strings["Search"] = "Cerca"; +$a->strings["Save"] = "Guardar"; +$a->strings["poke"] = "emprenya"; +$a->strings["poked"] = "emprenyat"; +$a->strings["ping"] = "coloca"; +$a->strings["pinged"] = "colocat"; +$a->strings["prod"] = "picar"; +$a->strings["prodded"] = "picat"; +$a->strings["slap"] = "bufetada"; +$a->strings["slapped"] = "bufetejat"; +$a->strings["finger"] = "senyal"; +$a->strings["fingered"] = "senyalat"; +$a->strings["rebuff"] = "menyspreu"; +$a->strings["rebuffed"] = "menyspreuat"; +$a->strings["happy"] = "feliç"; +$a->strings["sad"] = "trist"; +$a->strings["mellow"] = "melós"; +$a->strings["tired"] = "cansat"; +$a->strings["perky"] = "turgent"; +$a->strings["angry"] = "enfadat"; +$a->strings["stupified"] = "encantat"; +$a->strings["puzzled"] = "perplexe"; +$a->strings["interested"] = "Interessat"; +$a->strings["bitter"] = "amargat"; +$a->strings["cheerful"] = "feliç"; +$a->strings["alive"] = "viu"; +$a->strings["annoyed"] = "molest"; +$a->strings["anxious"] = "ansiós"; +$a->strings["cranky"] = "malagaitós"; +$a->strings["disturbed"] = "transtornat"; +$a->strings["frustrated"] = "frustrat"; +$a->strings["depressed"] = "deprimit"; +$a->strings["motivated"] = "motivat"; +$a->strings["relaxed"] = "relaxat"; +$a->strings["surprised"] = "sorprès"; +$a->strings["Monday"] = "Dilluns"; +$a->strings["Tuesday"] = "Dimarts"; +$a->strings["Wednesday"] = "Dimecres"; +$a->strings["Thursday"] = "Dijous"; +$a->strings["Friday"] = "Divendres"; +$a->strings["Saturday"] = "Dissabte"; +$a->strings["Sunday"] = "Diumenge"; +$a->strings["January"] = "Gener"; +$a->strings["February"] = "Febrer"; +$a->strings["March"] = "Març"; +$a->strings["April"] = "Abril"; +$a->strings["May"] = "Maig"; +$a->strings["June"] = "Juny"; +$a->strings["July"] = "Juliol"; +$a->strings["August"] = "Agost"; +$a->strings["September"] = "Setembre"; +$a->strings["October"] = "Octubre"; +$a->strings["November"] = "Novembre"; +$a->strings["December"] = "Desembre"; +$a->strings["unknown.???"] = "desconegut.???"; +$a->strings["bytes"] = "bytes"; +$a->strings["remove category"] = "elimina categoria"; +$a->strings["remove from file"] = "elimina del arxiu"; +$a->strings["Click to open/close"] = "Clic per obrir/tancar"; +$a->strings["Link to Source"] = "Enllaç a la Font"; +$a->strings["default"] = "per defecte"; +$a->strings["Page layout"] = "Format de la pàgina"; +$a->strings["You can create your own with the layouts tool"] = "Pots crear el teu propi amb l'editor de format de pàgina."; +$a->strings["Page content type"] = "Tipus de contingut de la pàgina"; +$a->strings["Select an alternate language"] = "Tria un idioma alternatiu"; +$a->strings["photo"] = "foto"; +$a->strings["event"] = "succés"; +$a->strings["status"] = "estat"; +$a->strings["comment"] = "comentari"; +$a->strings["activity"] = "activitat"; +$a->strings["Design Tools"] = "Eines de disseny"; +$a->strings["Blocks"] = "Bloc"; +$a->strings["Menus"] = "Menús"; +$a->strings["Layouts"] = "Format Gràfic"; +$a->strings["Pages"] = "Pàgines"; +$a->strings["Collection"] = "Col·lecció"; +$a->strings["parent"] = "pare"; +$a->strings["Principal"] = "Principal"; +$a->strings["Addressbook"] = "Llista d'Adreçes"; +$a->strings["Calendar"] = "Calendari"; +$a->strings["Schedule Inbox"] = "Programació de la bústia d'entrada"; +$a->strings["Schedule Outbox"] = "Programació de la bústia de sortida"; +$a->strings["Unknown"] = "Desconegut"; +$a->strings["%1\$s used"] = "%1\$s emprat"; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = "%1\$s emprat de %2\$s (%3\$s%)"; +$a->strings["Files"] = "Arxius"; +$a->strings["Total"] = "Total"; +$a->strings["Shared"] = "Compartit"; +$a->strings["Create"] = "Creada"; +$a->strings["Upload"] = "Pujar"; +$a->strings["Name"] = "Nom"; +$a->strings["Type"] = "Tipus"; +$a->strings["Size"] = "Mida"; +$a->strings["Last Modified"] = "Últim Modificat"; +$a->strings["Delete"] = "Esborra"; +$a->strings["Create new folder"] = "Crea una nova carpeta"; +$a->strings["Upload file"] = "Puja arxiu"; +$a->strings["%1\$s's bookmarks"] = "%1\$s de marcadors"; +$a->strings["view full size"] = "Veure a mida competa"; +$a->strings["\$Projectname Notification"] = "Notificació de \$Projectname"; +$a->strings["\$projectname"] = "\$projectname"; +$a->strings["Thank You,"] = "Gràcies,"; +$a->strings["%s Administrator"] = "%s Administrador"; +$a->strings["No Subject"] = "Sense Assumpte"; +$a->strings["General Features"] = "Característiques Generals"; +$a->strings["Content Expiration"] = "Expiració del Contingut"; +$a->strings["Remove posts/comments and/or private messages at a future time"] = "elimina entrades/comentaris i/o missatges privats de aquí en endevant."; +$a->strings["Multiple Profiles"] = "Multiples Perfils"; +$a->strings["Ability to create multiple profiles"] = "Capacitat per crear multiples perfils"; +$a->strings["Advanced Profiles"] = "Perfils Avançats"; +$a->strings["Additional profile sections and selections"] = "Seccions i seleccions addicionals de perfils "; +$a->strings["Profile Import/Export"] = "Importar/Exportar Perfil"; +$a->strings["Save and load profile details across sites/channels"] = "Guarda i carrega els detalls del perfil al llarg dels llocs/canals"; +$a->strings["Web Pages"] = "Pàgines Web"; +$a->strings["Provide managed web pages on your channel"] = "Proporcionar pàgines web gestionades al seu canal"; +$a->strings["Private Notes"] = "Notes Privades"; +$a->strings["Enables a tool to store notes and reminders"] = "Activa l'eina per guardar notes i recordatoris"; +$a->strings["Navigation Channel Select"] = "Navegació pel Selector de Canals"; +$a->strings["Change channels directly from within the navigation dropdown menu"] = "Canvieu els canals directament des del menú desplegable de navegació"; +$a->strings["Photo Location"] = "Ubicació de la Photo"; +$a->strings["If location data is available on uploaded photos, link this to a map."] = "Si los datos de ubicación están disponibles en las fotos subidas, vincular a un mapa."; +$a->strings["Expert Mode"] = "Mode Expert"; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = "Activar Mode Expert per a proporcionar opcions avançades de configuració"; +$a->strings["Premium Channel"] = "Canal Superior"; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = "Li permet establir restriccions i els termes en els quals es connecten amb el seu canal"; +$a->strings["Post Composition Features"] = "Característiques de Composició d'Entrades"; +$a->strings["Use Markdown"] = "Us d'Abreviatures"; +$a->strings["Allow use of \"Markdown\" to format posts"] = "Permet emprat \"Abreviatures\" per formatar entrades"; +$a->strings["Large Photos"] = "Grans Fotos"; +$a->strings["Include large (640px) photo thumbnails in posts. If not enabled, use small (320px) photo thumbnails"] = "Inclou gran (640px) foto de miniatura a les entrades. Si no està activat, empra petita (320px) foto de miniatura."; +$a->strings["Channel Sources"] = "Canal Origen"; +$a->strings["Automatically import channel content from other channels or feeds"] = "Importa automàticament el contingut del canal des de altres canals o feeds"; +$a->strings["Even More Encryption"] = "Encara Més Encriptació"; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = "Permet l'encripció opcional del contingut extrem-a-extrem amb clau secreta compartida"; +$a->strings["Enable voting tools"] = "Habilitar eines de vot"; +$a->strings["Provide a class of post which others can vote on"] = "Proporcionar una classe d'entrada que altres puguin votar"; +$a->strings["Network and Stream Filtering"] = "Filtrat de Xarxa i Flux"; +$a->strings["Search by Date"] = "Cerca per Data"; +$a->strings["Ability to select posts by date ranges"] = "Capacitat per seleccionar entrades per rang de dates"; +$a->strings["Collections Filter"] = "Filtre de Col·leccions"; +$a->strings["Enable widget to display Network posts only from selected collections"] = "Habilitar giny per mostrar les entrades de xarxa únicament de les col·leccions seleccionades"; +$a->strings["Saved Searches"] = "Cerques Guardades"; +$a->strings["Save search terms for re-use"] = "Guardar els termin de la cerca per a re-usar"; +$a->strings["Network Personal Tab"] = "Pestanya Personal de Xarxa"; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = "Activa pestanya per mostrar només les entrades de xarxa en els que has intervingut"; +$a->strings["Network New Tab"] = "Nova Pestanya de Xarxa"; +$a->strings["Enable tab to display all new Network activity"] = "Activa pestanya per mostrar tota l'activitat nova de la Xarxa"; +$a->strings["Affinity Tool"] = "Eina d'Afinitat"; +$a->strings["Filter stream activity by depth of relationships"] = "Filtre d'activitat del flux per importància de la relació"; +$a->strings["Connection Filtering"] = "Filtre de Connexió"; +$a->strings["Filter incoming posts from connections based on keywords/content"] = "Filtre de missatges d'entrada de conexions, basat en paraules clau/contingut "; +$a->strings["Suggest Channels"] = "Suggerir Canals"; +$a->strings["Show channel suggestions"] = "Mostra suggerencies de canals"; +$a->strings["Post/Comment Tools"] = "Eina d'Entrades/Comentaris"; +$a->strings["Tagging"] = "Etiquetant"; +$a->strings["Ability to tag existing posts"] = "Capacitat d'etiquetar entrades existents"; +$a->strings["Post Categories"] = "Categories d'Entrades"; +$a->strings["Add categories to your posts"] = "Afegeix categoria a la teva entrada"; +$a->strings["Saved Folders"] = "Carpetes Guardades"; +$a->strings["Ability to file posts under folders"] = "Capacitat de arxivar entrades en les carpetes"; +$a->strings["Dislike Posts"] = "No Agrada l'Entrada"; +$a->strings["Ability to dislike posts/comments"] = "Capacitat per marcar amb \"No Agrada\" les entrades/comentaris"; +$a->strings["Star Posts"] = "Entrades Excel·lents"; +$a->strings["Ability to mark special posts with a star indicator"] = "Capacitat per marcar entrades especials amb l'indicador d'excel·lencia"; +$a->strings["Tag Cloud"] = "Núvol d'Etiquetes."; +$a->strings["Provide a personal tag cloud on your channel page"] = "Proporcionar un núvol d'etiquetes personals a la teva pàgina de canal"; +$a->strings["Categories"] = "Categories"; +$a->strings["Apps"] = "Aplicatius"; +$a->strings["System"] = "Sistema"; +$a->strings["Personal"] = "Personal"; +$a->strings["Create Personal App"] = "Crear Personal App"; +$a->strings["Edit Personal App"] = "Editar Personal App"; +$a->strings["Connect"] = "Connecta "; +$a->strings["Ignore/Hide"] = "Ignora/Amaga"; +$a->strings["Suggestions"] = "Suggerencies"; +$a->strings["See more..."] = "Veure més....."; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = "Tens %1$.0f de %2$.0f connexions permeses."; +$a->strings["Add New Connection"] = "Afegeix una Nova Connexió"; +$a->strings["Enter the channel address"] = "Introdueix la adreça del canal"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Exemple: pep@exemple.com, http://exemple.com/vinyet"; +$a->strings["Notes"] = "Notes"; +$a->strings["Remove term"] = "Plaç de remoció"; +$a->strings["Everything"] = "Tot"; +$a->strings["Archives"] = "Arxius"; +$a->strings["Me"] = "Jo"; +$a->strings["Family"] = "Família"; +$a->strings["Friends"] = "Amics"; +$a->strings["Acquaintances"] = "Coneguts"; +$a->strings["All"] = "Tots"; +$a->strings["Refresh"] = "Refresc"; +$a->strings["Account settings"] = "Ajustos de Compte"; +$a->strings["Channel settings"] = "Ajustos de Canal"; +$a->strings["Additional features"] = "Característiques addicionals"; +$a->strings["Feature/Addon settings"] = "Ajustos de Característica/Afegit"; +$a->strings["Display settings"] = "Ajustos de pantalla"; +$a->strings["Connected apps"] = "Apps connectades"; +$a->strings["Export channel"] = "Exportat canal"; +$a->strings["Connection Default Permissions"] = "Permisos per Defecte de la Connexió"; +$a->strings["Premium Channel Settings"] = "Ajustos Premium de Canal"; +$a->strings["Settings"] = "Ajustos"; +$a->strings["Messages"] = "Missatges"; +$a->strings["Check Mail"] = "Comprovar Correu"; +$a->strings["New Message"] = "Nou Missatge"; +$a->strings["Chat Rooms"] = "Sales de Xat"; +$a->strings["Bookmarked Chatrooms"] = "Sales de Xat Favorites"; +$a->strings["Suggested Chatrooms"] = "Sales de Xat Suggerides"; +$a->strings["photo/image"] = "foto/imatge"; +$a->strings["Rate Me"] = "Valora'm"; +$a->strings["View Ratings"] = "Veure Valoracions"; +$a->strings["Public Hubs"] = "Concentradors Públics"; +$a->strings["l F d, Y \\@ g:i A"] = "l F d, Y \\@ g:i A"; +$a->strings["Starts:"] = "Inicia:"; +$a->strings["Finishes:"] = "Acaba:"; +$a->strings["Location:"] = "Localització:"; +$a->strings["This event has been added to your calendar."] = "Aquest succés ha estat afegit al teu calendari."; +$a->strings["%s "] = "%s "; +$a->strings["[Red:Notify] New mail received at %s"] = "[Red:Notificació] Un nou missatge s'ha rebut a %s"; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s t'ha enviat un nou missatge privat a %3\$s."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s t'ha enviat %2\$s."; +$a->strings["a private message"] = "un missatge privat"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Per favor, visita %s per a veure i/o respondre els teus missatges privats."; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s comentat en [zrl=%3\$s]a %4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s comentat en [zrl=%3\$s]%4\$s de %5\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s comentat en [zrl=%3\$s]el teu %4\$s[/zrl]"; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red:Notify] Comentari a la conversa #%1\$d per %2\$s"; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s comentat en un article/conversa que havies estat seguint."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Si us plau visita %s per veure i/o contestar a la conversa"; +$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Avís] %s ha escrit una entrada al teu mur"; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s ha escrit una entrada al teu mur en %3\$s"; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s enviat correu a [zrl=%3\$s]el teu mur[/zrl]"; +$a->strings["[Red:Notify] %s tagged you"] = "[Red:Notificació] %s t'ha etiquetat"; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s t'ha etiquetat a %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]t'ha etiquetat[/zrl]."; +$a->strings["[Red:Notify] %1\$s poked you"] = "[Red:Avís] %1\$s s'en fot de tu"; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s s'en fot de tú a %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]s'en fot de tú[/zrl]."; +$a->strings["[Red:Notify] %s tagged your post"] = "[Red:Avís] %s ha etiquetat la teva entrada"; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s ha etiquetat la teva entrada a %3\$s"; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s etiquetat [zrl=%3\$s]la teva entrada[/zrl]"; +$a->strings["[Red:Notify] Introduction received"] = "[Red:Avís] Presentació rebuda"; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, has rebut una nova petició de connexió de '%2\$s' a %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, has rebut [zrl=%2\$s]una nova petició de connexió[/zrl] de %3\$s."; +$a->strings["You may visit their profile at %s"] = "Pots visitar el seu perfil a %s"; +$a->strings["Please visit %s to approve or reject the connection request."] = "Si us plau, visita %s per aprovar o rebutjar la petició de connexió."; +$a->strings["[Red:Notify] Friend suggestion received"] = "[Red:Notificació] Rebuda suggerencia d'amistat"; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, has rebut una suggerència d'amistat de '%2\$s' a %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, has rebut [zrl=%2\$s]una suggerència d'amistat[/zrl] per %3\$s de %4\$s."; +$a->strings["Name:"] = "Nom:"; +$a->strings["Photo:"] = "Foto:"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Per favor, visita %s per a aprovar o rebutjar la suggerencia."; +$a->strings["[Red:Notify]"] = "[Red:Notificació]"; +$a->strings["No recipient provided."] = "No s'ha proporcionat bústia."; +$a->strings["[no subject]"] = "[no subject]"; +$a->strings["Unable to determine sender."] = "incapaç de determinar el remitent"; +$a->strings["Stored post could not be verified."] = "L'entrada guardada no pot ser verificada"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s agrada %2\$s de %3\$s"; +$a->strings["Please choose"] = "Escull"; +$a->strings["Agree"] = "A favor"; +$a->strings["Disagree"] = "En contra"; +$a->strings["Abstain"] = "Abstenció"; +$a->strings["Channel is blocked on this site."] = "El canal està bloquejat en aquest lloc."; +$a->strings["Channel location missing."] = "Ubicació del canal perduda."; +$a->strings["Response from remote channel was incomplete."] = "La resposta del canal remot fou incompleta."; +$a->strings["Channel was deleted and no longer exists."] = "El canal fou esborrat i actualment no existeix."; +$a->strings["Protocol disabled."] = "Protocol desactivat."; +$a->strings["Protocol blocked for this channel."] = "El protocol està bloquejat per a aquest canal."; +$a->strings["Channel discovery failed."] = "Descobriment de canal fallit."; +$a->strings["local account not found."] = "compte local no trobat."; +$a->strings["Cannot connect to yourself."] = "No pots connectar amb tu mateix."; +$a->strings["Private Message"] = "Missatge Privat"; +$a->strings["Select"] = "Selecciona"; +$a->strings["Save to Folder"] = "Guardar en la Carpeta"; +$a->strings["I will attend"] = "Assistiré"; +$a->strings["I will not attend"] = "No assistiré"; +$a->strings["I might attend"] = "Podria assistir"; +$a->strings["I agree"] = "D'acord"; +$a->strings["I disagree"] = "En desacord"; +$a->strings["I abstain"] = "M'abstinc"; +$a->strings["View all"] = "Veure tot"; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "Agrada", + 1 => "Agraden", +); +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "Desagrada", + 1 => "Desagrada", +); +$a->strings["Add Star"] = "Fes-lo Preferit"; +$a->strings["Remove Star"] = "Treu-lo de Preferits"; +$a->strings["Toggle Star Status"] = "Canvia el Estat de la Preferència"; +$a->strings["starred"] = "preferit"; +$a->strings["Message signature validated"] = "Validada la signatura del missatge"; +$a->strings["Message signature incorrect"] = "Signatura del missatge incorrecta"; +$a->strings["Add Tag"] = "Afegeix Etiqueta"; +$a->strings["I like this (toggle)"] = "M'agrada això (canvia)"; +$a->strings["like"] = "agrada"; +$a->strings["I don't like this (toggle)"] = "No m'agrada això (canvia)"; +$a->strings["dislike"] = "desagrada"; +$a->strings["Share This"] = "Comparteix Això"; +$a->strings["share"] = "comparteix"; +$a->strings["%d comment"] = array( + 0 => "%d commentari", + 1 => "%d commentaris", +); +$a->strings["View %s's profile - %s"] = "Veure %s de perfil - %s"; +$a->strings["to"] = "a"; +$a->strings["via"] = "via"; +$a->strings["Wall-to-Wall"] = "Mur-a-Mur"; +$a->strings["via Wall-To-Wall:"] = "via Mur-a-Mur:"; +$a->strings["from %s"] = "De %s"; +$a->strings["last edited: %s"] = "últim editat: %s"; +$a->strings["Expires: %s"] = "Expira: %s"; +$a->strings["Save Bookmarks"] = "Guarda Favorits"; +$a->strings["Add to Calendar"] = "Afegeix al Calendari"; +$a->strings["Mark all seen"] = "Marca tot com ja vist"; +$a->strings["__ctx:noun__ Likes"] = "Agrada"; +$a->strings["__ctx:noun__ Dislikes"] = "Desagrada"; +$a->strings["Close"] = "Tanca"; +$a->strings["Please wait"] = "Si us plau, espera"; +$a->strings["This is you"] = "Ets tú"; +$a->strings["Bold"] = "Negreta"; +$a->strings["Italic"] = "Italica"; +$a->strings["Underline"] = "Subratllat"; +$a->strings["Quote"] = "Cometes"; +$a->strings["Code"] = "Codi"; +$a->strings["Image"] = "Imatge"; +$a->strings["Insert Link"] = "Insereix Enllaç"; +$a->strings["Video"] = "Video"; +$a->strings["Encrypt text"] = "Text encriptat"; +$a->strings["New window"] = "Nova finestra"; +$a->strings["Open the selected location in a different window or browser tab"] = "Obrir la localització seleccionada en un altre finestra o pestanya del navegador"; +$a->strings["User '%s' deleted"] = "usuari '%s' esborrat"; +$a->strings["Attachments:"] = "Adjuntat:"; +$a->strings["\$Projectname event notification:"] = "Notificació d'esdeveniment de \$Projectname"; +$a->strings["Logout"] = "Desconectar"; +$a->strings["End this session"] = "Finalitza aquesta sessió"; +$a->strings["Home"] = "Personal"; +$a->strings["Your posts and conversations"] = "Les teves entrades i converses"; +$a->strings["View Profile"] = "Veure Perfil"; +$a->strings["Your profile page"] = "La teva pàgina de perfil"; +$a->strings["Edit Profiles"] = "Editar Perfils"; +$a->strings["Manage/Edit profiles"] = "Gestiona/Edita perfils"; +$a->strings["Edit Profile"] = "Edita Perfil"; +$a->strings["Edit your profile"] = "Edita el teu perfil"; +$a->strings["Photos"] = "Fotos"; +$a->strings["Your photos"] = "Les Teves Fotos"; +$a->strings["Your files"] = "Els teus arxius"; +$a->strings["Chat"] = "Xerrar"; +$a->strings["Your chatrooms"] = "Les teves sales de xerrar"; +$a->strings["Bookmarks"] = "Marcadors"; +$a->strings["Your bookmarks"] = "Els teus marcadors"; +$a->strings["Webpages"] = "Pàgines web"; +$a->strings["Your webpages"] = "Les teves pàgines web"; +$a->strings["Login"] = "Identifica't"; +$a->strings["Sign in"] = "Signatura"; +$a->strings["%s - click to logout"] = "%s - click per desconectar"; +$a->strings["Remote authentication"] = "Autenticació remota"; +$a->strings["Click to authenticate to your home hub"] = "Click per autentificar-te en el teu Lloc "; +$a->strings["Home Page"] = "Pàgina Personal"; +$a->strings["Register"] = "Registre"; +$a->strings["Create an account"] = "Crear un compte"; +$a->strings["Help"] = "Ajuda"; +$a->strings["Help and documentation"] = "Ajuda i documentació"; +$a->strings["Applications, utilities, links, games"] = "Aplicacions, utilitats, enllaços, jocs"; +$a->strings["Search site content"] = "Cerca en el contingut del lloc"; +$a->strings["Directory"] = "Directori"; +$a->strings["Channel Directory"] = "Directori de Canals"; +$a->strings["Matrix"] = "Matriu/Matrix"; +$a->strings["Your matrix"] = "El teu matrix"; +$a->strings["Mark all matrix notifications seen"] = "Marca totes les notificacions de matrix vistes"; +$a->strings["Channel Home"] = "Canal Personal"; +$a->strings["Channel home"] = "Canal personal"; +$a->strings["Mark all channel notifications seen"] = "Marca totes les notificacions de canal vistes"; +$a->strings["Connections"] = "Connexions"; +$a->strings["Notices"] = "Noticies"; +$a->strings["Notifications"] = "Notificacions"; +$a->strings["See all notifications"] = "Veure totes les Notificacions"; +$a->strings["Mark all system notifications seen"] = "Marca totes les notificacions vistes"; +$a->strings["Mail"] = "Correu"; +$a->strings["Private mail"] = "Correu privat"; +$a->strings["See all private messages"] = "Veure tots els missatges privats"; +$a->strings["Mark all private messages seen"] = "Marcar tots els missatges privats vistos"; +$a->strings["Inbox"] = "Safata d'entrada"; +$a->strings["Outbox"] = "Safata de sortida"; +$a->strings["Events"] = "Events"; +$a->strings["Event Calendar"] = "Calendari d'Events"; +$a->strings["See all events"] = "Veure tots els events"; +$a->strings["Mark all events seen"] = "Marcar tots els events vistos"; +$a->strings["Channel Manager"] = "Gestor del Canal"; +$a->strings["Manage Your Channels"] = "Gestiona els Teus Canals"; +$a->strings["Account/Channel Settings"] = "Ajustos de Compte/Canal"; +$a->strings["Admin"] = "Admin"; +$a->strings["Site Setup and Configuration"] = "Ajustos i Configuració del Lloc"; +$a->strings["Loading..."] = "Carregant..."; +$a->strings["@name, #tag, content"] = "@name, #tag, content"; +$a->strings["Please wait..."] = "Si us plau, espera......."; +$a->strings["Tags"] = "Etiquetes"; +$a->strings["Keywords"] = "Paraules clau"; +$a->strings["have"] = "tinc"; +$a->strings["has"] = "tens"; +$a->strings["want"] = "vull"; +$a->strings["wants"] = "vols"; +$a->strings["likes"] = "agrada"; +$a->strings["dislikes"] = "desagrada"; +$a->strings[" and "] = "i"; +$a->strings["public profile"] = "Perfil públic"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s canviat %2\$s a “%3\$s”"; +$a->strings["Visit %1\$s's %2\$s"] = "Visita %1\$s de %2\$s"; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s Ha actualitzat %2\$s, canviant %3\$s."; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "El formulario de la cadena de seguridad no era correcto. Esto probablemente ocurrió porque el formulario se ha abierto durante demasiado tiempo (> 3 horas) antes de enviarlo."; +$a->strings["Can view my normal stream and posts"] = "Pot veure el flux i entrades normals"; +$a->strings["Can view my default channel profile"] = "Pot veure el meu perfil del canal per defecte"; +$a->strings["Can view my photo albums"] = "Pot veure el meus àlbums de fotos"; +$a->strings["Can view my connections"] = "Pot veure les meves connexions"; +$a->strings["Can view my file storage"] = "Pot veure al meu magatzem d'arxius"; +$a->strings["Can view my webpages"] = "Pot veure les meves pàgines web"; +$a->strings["Can send me their channel stream and posts"] = "Pot enviar-me el flux i entrades del seu canal"; +$a->strings["Can post on my channel page (\"wall\")"] = "Pot fer entrades a la meva pàgina de canal (\"mur\")"; +$a->strings["Can comment on or like my posts"] = "Pot fer comentaris o dir si agrada en les meves entrades"; +$a->strings["Can send me private mail messages"] = "Pot enviar-me un missatge de correu privat"; +$a->strings["Can post photos to my photo albums"] = "Pot enviar fotos al meus àlbums de fotos"; +$a->strings["Can like/dislike stuff"] = "Pot dir si agrada/desagrada "; +$a->strings["Profiles and things other than posts/comments"] = "Perfils i altres coses a més d'entrades/comentaris"; +$a->strings["Can forward to all my channel contacts via post @mentions"] = "Ho pot enviar a tots els meus contactes del canal via entrades @mencions"; +$a->strings["Advanced - useful for creating group forum channels"] = "Avançat - capaç de crear canals de grups de foro"; +$a->strings["Can chat with me (when available)"] = "Pot xatejar amb mi (si estic disponible)"; +$a->strings["Can write to my file storage"] = "Pot escriure al meu magatzem d'arxius"; +$a->strings["Can edit my webpages"] = "Pot editar les meves pàgines web"; +$a->strings["Can source my public posts in derived channels"] = "Pot mostrar l'origen de les meves entrades públiques en altres canals"; +$a->strings["Somewhat advanced - very useful in open communities"] = "Quelcom avançat - molt útil en comunitats obertes"; +$a->strings["Can administer my channel resources"] = "Pot administrar els meus recursos del canal"; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Extremadament avançat. No toquis res si no saps que estàs fent"; +$a->strings["Social Networking"] = "Xarxes Socials"; +$a->strings["Mostly Public"] = "Més aviat Públic"; +$a->strings["Restricted"] = "Restringit"; +$a->strings["Private"] = "Privat"; +$a->strings["Community Forum"] = "Foro de Comunitat"; +$a->strings["Feed Republish"] = "Republicador"; +$a->strings["Special Purpose"] = "Objectiu Especial"; +$a->strings["Celebrity/Soapbox"] = "Celebritat/Faristol"; +$a->strings["Group Repository"] = "Repositori de Grup"; +$a->strings["Other"] = "Altres"; +$a->strings["Custom/Expert Mode"] = "Personalitzat/Mode Expert"; +$a->strings["channel"] = "canal"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s no agrada %2\$s de %3\$s"; +$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s esta ara connectat amb %2\$s"; +$a->strings["%1\$s poked %2\$s"] = "%1\$s emprenyat %2\$s"; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s es %2\$s"; +$a->strings["__ctx:title__ Likes"] = "Agrada"; +$a->strings["__ctx:title__ Dislikes"] = "Desagrada"; +$a->strings["__ctx:title__ Agree"] = "Acord"; +$a->strings["__ctx:title__ Disagree"] = "Desacord"; +$a->strings["__ctx:title__ Abstain"] = "Abstenirse"; +$a->strings["__ctx:title__ Attending"] = "Assistint"; +$a->strings["__ctx:title__ Not attending"] = "Desassistint"; +$a->strings["__ctx:title__ Might attend"] = "Podrien assistir"; +$a->strings["View %s's profile @ %s"] = "Vista %s del perfil @ %s"; +$a->strings["Categories:"] = "Categories:"; +$a->strings["Filed under:"] = "Arxivar a:"; +$a->strings["View in context"] = "Veure en context"; +$a->strings["remove"] = "treu"; +$a->strings["Delete Selected Items"] = "Esborra els Articles Seleccionats"; +$a->strings["View Source"] = "Veure l'Origen"; +$a->strings["Follow Thread"] = "Segueix el Fil"; +$a->strings["View Status"] = "Veure Status"; +$a->strings["View Photos"] = "Veure Fotos"; +$a->strings["Matrix Activity"] = "Activitat de Matrix"; +$a->strings["Edit Contact"] = "Editar Contacte"; +$a->strings["Send PM"] = "Enviar MP"; +$a->strings["Poke"] = "Emprenya"; +$a->strings["%s likes this."] = "%s agrada això."; +$a->strings["%s doesn't like this."] = "%s no agrada això."; +$a->strings["%2\$d people like this."] = array( + 0 => "%2\$d gent agrada això.", + 1 => "%2\$d gent agrada això.", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "%2\$d gent no agrada això.", + 1 => "%2\$d gent no agrada això.", +); +$a->strings["and"] = "i"; +$a->strings[", and %d other people"] = array( + 0 => ", i %d altra gent", + 1 => ", i %d altra gent", +); +$a->strings["%s like this."] = "%s agrada això."; +$a->strings["%s don't like this."] = "%s no agrada això."; +$a->strings["Visible to everybody"] = "Visible a tothom"; +$a->strings["Please enter a link URL:"] = "Si us plau entra l'enllaç URL:"; +$a->strings["Please enter a video link/URL:"] = "Si us plau entra l'enllaç/URL a un video:"; +$a->strings["Please enter an audio link/URL:"] = "Si us plau, entra l'enllaç/URL a un audio:"; +$a->strings["Tag term:"] = "Paraula de l'Etiqueta:"; +$a->strings["Save to Folder:"] = "Guardar en la Carpeta"; +$a->strings["Where are you right now?"] = "On ets ara?"; +$a->strings["Expires YYYY-MM-DD HH:MM"] = "Expira YYYY-MM-DD HH:MM"; +$a->strings["Share"] = "Compartir"; +$a->strings["Page link name"] = "Nom de la pàgina enllaçada"; +$a->strings["Post as"] = "Envia com"; +$a->strings["Upload photo"] = "Puja foto"; +$a->strings["upload photo"] = "puja foto"; +$a->strings["Attach file"] = "Adjunta arxiu"; +$a->strings["attach file"] = "adjunta arxiu"; +$a->strings["Insert web link"] = "Insereix enllaç web"; +$a->strings["web link"] = "enllaç web"; +$a->strings["Insert video link"] = "Insereix enllaç video"; +$a->strings["video link"] = "enllaç video"; +$a->strings["Insert audio link"] = "Insereix enllaç d'audio"; +$a->strings["audio link"] = "enllaç d'audio"; +$a->strings["Set your location"] = "Ajusta la teva ubicació"; +$a->strings["set location"] = "ajusta localització"; +$a->strings["Toggle voting"] = "Commutar votació"; +$a->strings["Clear browser location"] = "Treu la localització del navegador"; +$a->strings["clear location"] = "treu localització"; +$a->strings["Title (optional)"] = "Títol (opcional)"; +$a->strings["Categories (optional, comma-separated list)"] = "Categories (opcional, llista separada per comes)"; +$a->strings["Permission settings"] = "Ajustos de permisos"; +$a->strings["permissions"] = "permisos "; +$a->strings["Public post"] = "Entrada pública"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Exemple: bob@example.com, mary@example.com"; +$a->strings["Set expiration date"] = "Ajusta la data d'expiració"; +$a->strings["OK"] = "OK"; +$a->strings["Cancel"] = "Cancel·la"; +$a->strings["Discover"] = "Descobrir"; +$a->strings["Imported public streams"] = "Importar fluxos públics"; +$a->strings["Commented Order"] = "Ordre per Comentaris"; +$a->strings["Sort by Comment Date"] = "Ordenar per Data del Comentari"; +$a->strings["Posted Order"] = "Ordenar per Entrades"; +$a->strings["Sort by Post Date"] = "Ordenar per Data d' Entrada"; +$a->strings["Posts that mention or involve you"] = "Entrades que et mencionen o involucren"; +$a->strings["New"] = "Nou"; +$a->strings["Activity Stream - by date"] = "Activitat del Flux - per data"; +$a->strings["Starred"] = "Preferit"; +$a->strings["Favourite Posts"] = "Entrades Favorites"; +$a->strings["Spam"] = "Spam"; +$a->strings["Posts flagged as SPAM"] = "Entrades marcades com a SPAM"; +$a->strings["Channel"] = "Canal"; +$a->strings["Status Messages and Posts"] = "Estat dels Missatges i Entrades"; +$a->strings["About"] = "Sobre això"; +$a->strings["Profile Details"] = "Detalls del Perfil"; +$a->strings["Photo Albums"] = "Albums de Fotos"; +$a->strings["Files and Storage"] = "Arxius i Emmagatzegament"; +$a->strings["Chatrooms"] = "Sala per Xerrar"; +$a->strings["Saved Bookmarks"] = "Marcadors Guardats"; +$a->strings["Manage Webpages"] = "Gestió de Pàgines Web"; +$a->strings["__ctx:noun__ Attending"] = array( + 0 => "Assistint", + 1 => "Assistint", +); +$a->strings["__ctx:noun__ Not Attending"] = array( + 0 => "Desassistint", + 1 => "Desassistint", +); +$a->strings["__ctx:noun__ Undecided"] = array( + 0 => "Indecís", + 1 => "Indecisos", +); +$a->strings["__ctx:noun__ Agree"] = array( + 0 => "Acord", + 1 => "Acords", +); +$a->strings["__ctx:noun__ Disagree"] = array( + 0 => "Desacord", + 1 => "Desacords", +); +$a->strings["__ctx:noun__ Abstain"] = array( + 0 => "Abstenirse", + 1 => "Abstenirse", +); +$a->strings["Permission denied"] = "Permís denegat"; +$a->strings["(Unknown)"] = "(Desconegut)"; +$a->strings["Visible to anybody on the internet."] = "Visible per tothom a la Internet"; +$a->strings["Visible to you only."] = "Visible només per tú."; +$a->strings["Visible to anybody in this network."] = "Visible per tothom en aquesta xarxa."; +$a->strings["Visible to anybody authenticated."] = "Visible per tothom autenticat."; +$a->strings["Visible to anybody on %s."] = "Visible per a tothom a %s."; +$a->strings["Visible to all connections."] = "Visible per a totes les connexions."; +$a->strings["Visible to approved connections."] = "Visible per a les connexions aprovades."; +$a->strings["Visible to specific connections."] = "Visible per a específiques connexions."; +$a->strings["Item not found."] = "Element no trobat."; +$a->strings["Permission denied."] = "Permís denegat."; +$a->strings["Collection not found."] = "Col·lecció no trobada."; +$a->strings["Collection is empty."] = "La col·lecció esta buida."; +$a->strings["Collection: %s"] = "Col·lecció: %s"; +$a->strings["Connection: %s"] = "Connexió: %s"; +$a->strings["Connection not found."] = "Connexió no trobada."; +$a->strings["Invalid data packet"] = "paquet de dades invàlid"; +$a->strings["Unable to verify channel signature"] = "No es pot verificar la signatura del canal"; +$a->strings["Unable to verify site signature for %s"] = "No es pot verificar la signatura del lloc per %s"; +$a->strings["Embedded content"] = "Contingut embegut"; +$a->strings["Embedding disabled"] = "Incorporació desactivada"; +$a->strings["Logged out."] = "Sortir."; +$a->strings["Failed authentication"] = "Autenticació fallida"; +$a->strings["Login failed."] = "Identificació fallida."; +$a->strings["%d invitation available"] = array( + 0 => "%d invitació disponible", + 1 => "%d invitacions disponibles", +); +$a->strings["Advanced"] = "Avançat"; +$a->strings["Find Channels"] = "Troba Canals"; +$a->strings["Enter name or interest"] = "Entra un nom o interes"; +$a->strings["Connect/Follow"] = "Conecta/Segueix"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Exemples: Lionel Messi, Futbolista"; +$a->strings["Find"] = "Troba"; +$a->strings["Channel Suggestions"] = "Canals Suggerits"; +$a->strings["Random Profile"] = "Perfil Aleatori"; +$a->strings["Invite Friends"] = "Convida Amics"; +$a->strings["Advanced example: name=fred and country=iceland"] = "Exemple avançat: nom=pep i pais=eire"; +$a->strings["%d connection in common"] = array( + 0 => "%d connexió en comú", + 1 => "%d connexions en comú", +); +$a->strings["show more"] = "mostrar més"; +$a->strings["Visible to your default audience"] = "Visible per a la teva audiència "; +$a->strings["Show"] = "Mostra"; +$a->strings["Don't show"] = "No mostrar"; +$a->strings["Permissions"] = "Permisos "; +$a->strings["Item was not found."] = "Article no trobat."; +$a->strings["No source file."] = "No hi ha arxiu d'origen."; +$a->strings["Cannot locate file to replace"] = "No trobo l'arxiu a reemplaçar"; +$a->strings["Cannot locate file to revise/update"] = "No trobo l'arxiu a revisar/actualitzar"; +$a->strings["File exceeds size limit of %d"] = "L'arxiu excedeix la mida limit de %d"; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Has arribat al teu límit de %1$.0f Mbytes de emagatzematge d'adjunts."; +$a->strings["File upload failed. Possible system limit or action terminated."] = "Pujada del arxiu fallida. Possible límit del sistema o acció interrompuda."; +$a->strings["Stored file could not be verified. Upload failed."] = "L'arxiu guardat no es pot verificar. Pujada fallida."; +$a->strings["Path not available."] = "Trajectòria no disponible"; +$a->strings["Empty pathname"] = "Trajèctoria vuida."; +$a->strings["duplicate filename or path"] = "Nom o trajectòria duplicat"; +$a->strings["Path not found."] = "Trajectòria no trobada."; +$a->strings["mkdir failed."] = "mkdir va fracassar."; +$a->strings["database storage failed."] = "Arxiu de base de dades va fallar."; +$a->strings["Unable to obtain identity information from database"] = "Incapaç de trobar l'informació d'identitat a la base de dades"; +$a->strings["Empty name"] = "Nom buit"; +$a->strings["Name too long"] = "Nom massa llarg"; +$a->strings["No account identifier"] = "Sense identificador de compte"; +$a->strings["Nickname is required."] = "Alies/malnom es requerit."; +$a->strings["Reserved nickname. Please choose another."] = "Àlies reservat. Tria un altre."; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = "L'álies te caracters no soportats o ja esta en ús en aquest lloc"; +$a->strings["Unable to retrieve created identity"] = "No es pot recuperar la identitat creada"; +$a->strings["Default Profile"] = "Perfil per Defecte"; +$a->strings["Requested channel is not available."] = "El canal demanat no està disponible."; +$a->strings["Requested profile is not available."] = "El perfil demanat no està disponible."; +$a->strings["Change profile photo"] = "Canviar la foto del perfil"; +$a->strings["Profiles"] = "Perfils"; +$a->strings["Manage/edit profiles"] = "Gestiona/edita perfils"; +$a->strings["Create New Profile"] = "Crear un Perfil Nou"; +$a->strings["Profile Image"] = "Imatge del Perfil"; +$a->strings["visible to everybody"] = "visible per tothom"; +$a->strings["Edit visibility"] = "Editar visibilitat"; +$a->strings["Gender:"] = "Gènere:"; +$a->strings["Status:"] = "Estatus:"; +$a->strings["Homepage:"] = "Pàgina Personal:"; +$a->strings["Online Now"] = "Ara en Linia"; +$a->strings["g A l F d"] = "g A l F d"; +$a->strings["F d"] = "F d"; +$a->strings["[today]"] = "[avui]"; +$a->strings["Birthday Reminders"] = "Recordatori d'Aniversaris"; +$a->strings["Birthdays this week:"] = "Aniversari aquesta setmana:"; +$a->strings["[No description]"] = "[Sense descripció]"; +$a->strings["Event Reminders"] = "Recordatori d'Events"; +$a->strings["Events this week:"] = "Event aquesta setmana:"; +$a->strings["Profile"] = "Perfil"; +$a->strings["Full Name:"] = "Nom Complet:"; +$a->strings["Like this channel"] = "M'agrada aquest canal"; +$a->strings["j F, Y"] = "j F, Y"; +$a->strings["j F"] = "j F"; +$a->strings["Birthday:"] = "Aniversari:"; +$a->strings["Age:"] = "Edat:"; +$a->strings["for %1\$d %2\$s"] = "per %1\$d %2\$s"; +$a->strings["Sexual Preference:"] = "Preferència Sexual:"; +$a->strings["Hometown:"] = "Ciutat Natal:"; +$a->strings["Tags:"] = "Etiquetes:"; +$a->strings["Political Views:"] = "Idees Polítiques:"; +$a->strings["Religion:"] = "Religió:"; +$a->strings["About:"] = "Sobre:"; +$a->strings["Hobbies/Interests:"] = "Aficions/Interessos:"; +$a->strings["Likes:"] = "Agrada:"; +$a->strings["Dislikes:"] = "Desagrada:"; +$a->strings["Contact information and Social Networks:"] = "Informació de contacte i Xarxes Socials:"; +$a->strings["My other channels:"] = "Els meus altres canals:"; +$a->strings["Musical interests:"] = "Interessos Musicals:"; +$a->strings["Books, literature:"] = "Llibres, literatura:"; +$a->strings["Television:"] = "Televisió:"; +$a->strings["Film/dance/culture/entertainment:"] = "Películes/Dança/Cultura/Entreteniment:"; +$a->strings["Love/Romance:"] = "Amor/Romace:"; +$a->strings["Work/employment:"] = "Treball/feina:"; +$a->strings["School/education:"] = "Escola/educació:"; +$a->strings["Like this thing"] = "M'agrada això"; +$a->strings["Male"] = "Masculí"; +$a->strings["Female"] = "Femení"; +$a->strings["Currently Male"] = "Actualment Masculí"; +$a->strings["Currently Female"] = "Actualment Femení"; +$a->strings["Mostly Male"] = "Més aviat Masculí"; +$a->strings["Mostly Female"] = "Més Aviat Femení"; +$a->strings["Transgender"] = "Canvi de Sexe"; +$a->strings["Intersex"] = "Intersexual"; +$a->strings["Transsexual"] = "Transsexual"; +$a->strings["Hermaphrodite"] = "Hermafrodita"; +$a->strings["Neuter"] = "Neutre"; +$a->strings["Non-specific"] = "Indefinit"; +$a->strings["Undecided"] = "Indecís"; +$a->strings["Males"] = "Homes"; +$a->strings["Females"] = "Dones"; +$a->strings["Gay"] = "Gay"; +$a->strings["Lesbian"] = "Lesbianes"; +$a->strings["No Preference"] = "Sense Preferències"; +$a->strings["Bisexual"] = "Bisexual"; +$a->strings["Autosexual"] = "Autosexual"; +$a->strings["Abstinent"] = "Abstinent"; +$a->strings["Virgin"] = "Verge"; +$a->strings["Deviant"] = "Desviat"; +$a->strings["Fetish"] = "Fetixiste"; +$a->strings["Oodles"] = "Orgies"; +$a->strings["Nonsexual"] = "Asexual"; +$a->strings["Single"] = "Solter"; +$a->strings["Lonely"] = "Solitari"; +$a->strings["Available"] = "Disponible"; +$a->strings["Unavailable"] = "No Disponible"; +$a->strings["Has crush"] = "Aplastat"; +$a->strings["Infatuated"] = "Encapritxat"; +$a->strings["Dating"] = "Promés"; +$a->strings["Unfaithful"] = "Infidel"; +$a->strings["Sex Addict"] = "Adicte al Sexe"; +$a->strings["Friends/Benefits"] = "Amics amb Beneficis"; +$a->strings["Casual"] = "Casual"; +$a->strings["Engaged"] = "Ocupat"; +$a->strings["Married"] = "Casat"; +$a->strings["Imaginarily married"] = "Casat Imaginàriament"; +$a->strings["Partners"] = "Parella"; +$a->strings["Cohabiting"] = "Cohabitant"; +$a->strings["Common law"] = "Tradició"; +$a->strings["Happy"] = "Feliç"; +$a->strings["Not looking"] = "No Cerco"; +$a->strings["Swinger"] = "Llibertí"; +$a->strings["Betrayed"] = "Traït"; +$a->strings["Separated"] = "Separat"; +$a->strings["Unstable"] = "Inestable"; +$a->strings["Divorced"] = "Divorciat"; +$a->strings["Imaginarily divorced"] = "Divorciat Imaginàriament"; +$a->strings["Widowed"] = "Vidu/ua"; +$a->strings["Uncertain"] = "Incert"; +$a->strings["It's complicated"] = "Es Complicat"; +$a->strings["Don't care"] = "No Et Fa Res"; +$a->strings["Ask me"] = "Pregunta"; +$a->strings["Site Admin"] = "Administració"; +$a->strings["Address Book"] = "Adreçes"; +$a->strings["Mood"] = "Ànim"; +$a->strings["Probe"] = "Sondeig"; +$a->strings["Suggest"] = "Suggeriment"; +$a->strings["Random Channel"] = "Canal Aleatori"; +$a->strings["Invite"] = "Convida"; +$a->strings["Features"] = "Funcionalitats"; +$a->strings["Language"] = "Idioma"; +$a->strings["Post"] = "Entrada"; +$a->strings["Profile Photo"] = "Foto del Perfil"; +$a->strings["Update"] = "Actualització"; +$a->strings["Install"] = "Instal·lar"; +$a->strings["Purchase"] = "Compra"; +$a->strings["Image/photo"] = "Imatge/foto"; +$a->strings["Encrypted content"] = "Contingut encriptat"; +$a->strings["Install %s element: "] = "Instal·la l'element %s:"; +$a->strings["This post contains an installable %s element, however you lack permissions to install it on this site."] = "Aquesta entrada contè un element %s instal·lable, potser manques de permissos per instal·lar-lo en aquest lloc."; +$a->strings["webpage"] = "pàgina web"; +$a->strings["layout"] = "disposició"; +$a->strings["block"] = "bloc"; +$a->strings["menu"] = "menú"; +$a->strings["QR code"] = "QR code"; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s va escriure el següent %2\$s %3\$s"; +$a->strings["post"] = "entrada"; +$a->strings["Different viewers will see this text differently"] = "Diferents observadors veuran aquest text de diferents formes"; +$a->strings["$1 spoiler"] = "$1 spoiler"; +$a->strings["$1 wrote:"] = "$1 va escriure:"; +$a->strings["Missing room name"] = "Perdut el nom de la sala"; +$a->strings["Duplicate room name"] = "Nom de la sala duplicat"; +$a->strings["Invalid room specifier."] = "Especificació de la sala invàlida."; +$a->strings["Room not found."] = "Sala no trobada."; +$a->strings["Room is full"] = "La sala es plena"; +$a->strings["Image exceeds website size limit of %lu bytes"] = "La imatge excedeix la mida limit pel lloc web en %lu bytes"; +$a->strings["Image file is empty."] = "El fitxer d'imatge esta buit."; +$a->strings["Unable to process image"] = "incapaç de processar la imatge"; +$a->strings["Photo storage failed."] = "Fracassà l'emmagatzematge de la Foto"; +$a->strings["Upload New Photos"] = "Puja Noves Fotos"; +$a->strings["Some blurb about what to do when you're new here"] = "Algunes propostes sobre el que cal fer quan ets nou aquí"; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Has creat %1$.0f de %2$.0f canals permesos."; +$a->strings["Create a new channel"] = "Crear un nou canal"; +$a->strings["Current Channel"] = "Canal Actual"; +$a->strings["Switch to one of your channels by selecting it."] = "Canviar a un altre dels teus canals seleccionant-ho."; +$a->strings["Default Channel"] = "Canal per Defecte"; +$a->strings["Make Default"] = "Estableix com a Predeterminat"; +$a->strings["%d new messages"] = "%d missatges nous"; +$a->strings["%d new introductions"] = "%d noves presentacions"; +$a->strings["Delegated Channels"] = "Canals Delegats"; +$a->strings["Public access denied."] = "Accés públic denegat."; +$a->strings["%d rating"] = array( + 0 => "%d valoració", + 1 => "%d valoracions", +); +$a->strings["Gender: "] = "Gènere:"; +$a->strings["Status: "] = "Estatus:"; +$a->strings["Homepage: "] = "Pàgina Personal:"; +$a->strings["Description:"] = "Descripció:"; +$a->strings["Public Forum:"] = "Forum Públic:"; +$a->strings["Keywords: "] = "Paraules Clau:"; +$a->strings["Don't suggest"] = "No suggerir"; +$a->strings["Common connections:"] = "Connexions en comú:"; +$a->strings["Global Directory"] = "Directori Global"; +$a->strings["Local Directory"] = "Directori Local"; +$a->strings["Finding:"] = "Cercant:"; +$a->strings["next page"] = "pàgina següent"; +$a->strings["previous page"] = "pàgina anterior"; +$a->strings["Sort options"] = "Opcions per ordenar"; +$a->strings["Alphabetic"] = "Alfabètic"; +$a->strings["Reverse Alphabetic"] = "Alfabètic Invers"; +$a->strings["Newest to Oldest"] = "De més Nou a més Vell"; +$a->strings["Oldest to Newest"] = "De més Antic a més Nou"; +$a->strings["No entries (some entries may be hidden)."] = "Sense entrades (algunes podrien estar amagades)."; +$a->strings["Xchan Lookup"] = "Cerca a xchan"; +$a->strings["Lookup xchan beginning with (or webbie): "] = "Cerca a xchan començant per (o webbie)"; +$a->strings["Not found."] = "No trobat."; +$a->strings["Authorize application connection"] = "Autoritza la connexió de l'aplicació"; +$a->strings["Return to your app and insert this Securty Code:"] = "Torna a la teva aplicació i insereix aquest Codi de Seguretat:"; +$a->strings["Please login to continue."] = "Si et plau, identifica't per continuar."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Vols autoritzar a aquesta aplicació l'accés a les teves entrades i contactes i/o a crear noves entrades com si fos tu mateix."; +$a->strings["Page Title"] = "Títol de la pàgina"; +$a->strings["Channel added."] = "S'ha afegit el canal."; +$a->strings["Tag removed"] = "S'ha tret l'etiqueta"; +$a->strings["Remove Item Tag"] = "Elimina l'etiqueta d'element"; +$a->strings["Select a tag to remove: "] = "Tria l'etiqueta a eliminar:"; +$a->strings["Remove"] = "Esborra"; +$a->strings["Continue"] = "Continua"; +$a->strings["Premium Channel Setup"] = "Configuració de Canals Premium"; +$a->strings["Enable premium channel connection restrictions"] = "Habilita les restriccions de connexió del canal premium"; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Si us plau, introdueixi les restriccions o condicions, com ara el rebut de PayPal, les pautes d'ús, etc."; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Aquest canal pot requerir passos addicionals o reconeixement de les següents condicions abans de connectar:"; +$a->strings["Potential connections will then see the following text before proceeding:"] = "Connexions potencials veuran el següent text abans de continuar:"; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "En continuar, certifico que he complert amb totes les instruccions proporcionades en aquesta pàgina."; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(No s'han proporcionat instruccions específiques pel propietari del canal.)"; +$a->strings["Restricted or Premium Channel"] = "Canal Restringit o Premium"; +$a->strings["Thing updated"] = "S'ha actualitzat la cosa"; +$a->strings["Object store: failed"] = "No s'ha pogut emmagatzemar l'objecte"; +$a->strings["Thing added"] = "S'ha afegit la cosa"; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = "OBJ: %1\$s %2\$s %3\$s"; +$a->strings["Show Thing"] = "Mostra la cosa"; +$a->strings["item not found."] = "no s'ha trobat l'element."; +$a->strings["Edit Thing"] = "Edita la cosa"; +$a->strings["Select a profile"] = "Tria un perfil"; +$a->strings["Post an activity"] = "Publica una activitat"; +$a->strings["Only sends to viewers of the applicable profile"] = "S'envia només a visitants del perfil corresponent"; +$a->strings["Name of thing e.g. something"] = "Nom de la cosa. Exemple: patata"; +$a->strings["URL of thing (optional)"] = "Adreça URL de la cosa (opcional)"; +$a->strings["URL for photo of thing (optional)"] = "Adreça URL de la foto d'una cosa (opcional)"; +$a->strings["Add Thing to your Profile"] = "Afegeix una cosa al teu perfil"; +$a->strings["Item not available."] = "Article no disponible."; +$a->strings["Fetching URL returns error: %1\$s"] = "URL sol·licitada retorna error: %1\$s"; +$a->strings["Image uploaded but image cropping failed."] = "S'ha pujat la imatge però no s'ha pogut retallar."; +$a->strings["Image resize failed."] = "No s'ha pogut escalar la imatge."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Refresca la memòria cau del navegador si la foto no s'actualitza immediatament. Dreceres: «Ctrl+F5» i «Ctrl+Maj+R»"; +$a->strings["Image exceeds size limit of %d"] = "La imatge excedeix la mida límit de %d"; +$a->strings["Unable to process image."] = "Incapaç de processar l'imatge."; +$a->strings["Photo not available."] = "Foto no disponible."; +$a->strings["Upload File:"] = "Puja Arxiu:"; +$a->strings["Select a profile:"] = "Tria un perfil:"; +$a->strings["Upload Profile Photo"] = "Puja una Foto pel Perfil"; +$a->strings["or"] = "o"; +$a->strings["skip this step"] = "salta aquest pas"; +$a->strings["select a photo from your photo albums"] = "tria una foto del teu àlbum de fotos"; +$a->strings["Crop Image"] = "Retalla Imatge"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Si us plau, retalla la imatge per a una optima visualització"; +$a->strings["Done Editing"] = "Edició Feta"; +$a->strings["Image uploaded successfully."] = "Imatge pujada exitosament."; +$a->strings["Image upload failed."] = "La pujada de la imatge va fracassar."; +$a->strings["Image size reduction [%s] failed."] = "La reducció de mida de la imatge [%s] va fracassar."; +$a->strings["Invalid item."] = "Article invàlid."; +$a->strings["Channel not found."] = "Canal no trobat."; +$a->strings["Page not found."] = "Pàgina no trobada."; +$a->strings["Like/Dislike"] = "M'agrada / No m'agrada"; +$a->strings["This action is restricted to members."] = "Aquesta acció està restringida als membres."; +$a->strings["Please login with your \$Projectname ID or register as a new \$Projectname member to continue."] = "Entra amb la teva identitat \$Projectname o registra't a \$Projectname per continuar."; +$a->strings["Invalid request."] = "Sol·licitud invàlida."; +$a->strings["thing"] = "cosa"; +$a->strings["Channel unavailable."] = "El canal està inactiu."; +$a->strings["Previous action reversed."] = "S'ha desfet l'acció anterior."; +$a->strings["%1\$s agrees with %2\$s's %3\$s"] = "%1\$s està d'acord amb %3\$s de %2\$s"; +$a->strings["%1\$s doesn't agree with %2\$s's %3\$s"] = "%1\$s no està d'acord amb %3\$s de %2\$s"; +$a->strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = "%1\$s s'abstén en %3\$s de %2\$s"; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%1\$s assistirà a %3\$s de %2\$s"; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%1\$s no assistirà a %3\$s de %2\$s"; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%1\$s potser assistirà a %3\$s de %2\$s"; +$a->strings["Action completed."] = "S'ha completat l'acció."; +$a->strings["Thank you."] = "Gràcies."; +$a->strings["Calendar entries imported."] = "Entrades de Calendari importades."; +$a->strings["No calendar entries found."] = "No es troben entrades decalendari."; +$a->strings["Event can not end before it has started."] = "L'esdeveniment ha de començar abans d'acabar."; +$a->strings["Unable to generate preview."] = "No s'ha pogut generar la vista prèvia."; +$a->strings["Event title and start time are required."] = "Cal indicar l'inici i el final de l'esdeveniment."; +$a->strings["Event not found."] = "No s'ha trobat l'esdeveniment."; +$a->strings["l, F j"] = "l, F j"; +$a->strings["Edit event"] = "Edita l'esdeveniment"; +$a->strings["Delete event"] = "Esborra l'esdeveniment"; +$a->strings["calendar"] = "calendari"; +$a->strings["Create New Event"] = "Crea un esdeveniment nou"; +$a->strings["Previous"] = "Anterior"; +$a->strings["Next"] = "Pròxim"; +$a->strings["Export"] = "Exporta"; +$a->strings["Import"] = "Importar"; +$a->strings["Event removed"] = "S'ha eliminat l'esdeveniment"; +$a->strings["Failed to remove event"] = "No s'ha pogut esborrar l'esdeveniment"; +$a->strings["Event details"] = "Detalls de l'esdeveniment"; +$a->strings["Starting date and Title are required."] = "La data d'inici i el títol són obligatoris."; +$a->strings["Categories (comma-separated list)"] = "Categories (llista separada per comes)"; +$a->strings["Event Starts:"] = "Inici:"; +$a->strings["Finish date/time is not known or not relevant"] = "La data i hora de final no és coneguda o irrellevant"; +$a->strings["Event Finishes:"] = "Final:"; +$a->strings["Adjust for viewer timezone"] = "Ajusta a la zona horària del visitant."; +$a->strings["Important for events that happen in a particular place. Not practical for global holidays."] = "És important per esdeveniments locals, però pels globals no és pràctic."; +$a->strings["Title:"] = "Títol:"; +$a->strings["Share this event"] = "Comparteix aquest esdeveniment"; +$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s esta seguint %2\$s de %3\$s"; +$a->strings["Public Sites"] = "Llocs públics"; +$a->strings["The listed sites allow public registration for the \$Projectname network. All sites in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = "Els llocs llistats permeten registrar usuaris de la xarxa \$Projectname. Com que tots els llocs estan enllaçats entre ells, la identitat és vàlida a tota la xarxa. Alguns llocs poden demanar subscripció o oferir serveis addicional de pagament. Per a més detalls, proveu de seguir els enllaços dels proveïdors."; +$a->strings["Rate this hub"] = "Valora aquest hub"; +$a->strings["Site URL"] = "Adreça URL del web"; +$a->strings["Access Type"] = "Tipus d'accés"; +$a->strings["Registration Policy"] = "Condicions de registre"; +$a->strings["Location"] = "Localització"; +$a->strings["View hub ratings"] = "Mostra la valoració del hub"; +$a->strings["Rate"] = "Puntua"; +$a->strings["View ratings"] = "Mostra les valoracions"; +$a->strings["Edit post"] = "Modifica l'entrada"; +$a->strings["\$Projectname channel"] = "Canal de \$Projectname"; +$a->strings["Collection created."] = "Creada una col·lecció"; +$a->strings["Could not create collection."] = "No puc crear la col·lecció."; +$a->strings["Collection updated."] = "Col·lecció actualitzada."; +$a->strings["Create a collection of channels."] = "Creada una col·lecció de canals."; +$a->strings["Collection Name: "] = "Nom de la Col·lecció:"; +$a->strings["Members are visible to other channels"] = "Els membres son visibles en altres canals"; +$a->strings["Collection removed."] = "Col·lecció esborrada."; +$a->strings["Unable to remove collection."] = "Incapaç d'esborrar la col·lecció."; +$a->strings["Collection Editor"] = "Editor de Col·leccions"; +$a->strings["Members"] = "Membres"; +$a->strings["All Connected Channels"] = "Tots els Canals Connectats"; +$a->strings["Click on a channel to add or remove."] = "Clic sobre el canal per afegir o esborrar."; +$a->strings["Version %s"] = "Versió %s"; +$a->strings["Installed plugins/addons/apps:"] = "Plugins/addons/apps Instal·lats:"; +$a->strings["No installed plugins/addons/apps"] = "Plugins/addons/apps no instal·lats"; +$a->strings["\$Projectname"] = "\$Projectname"; +$a->strings["This is a hub of \$Projectname - a global cooperative network of decentralized privacy enhanced websites."] = "Aquest és un hub de \$Projectname, una xarxa cooperativa mundial de llocs web descentralitzats amb gran control de la privacitat."; +$a->strings["Tag: "] = "Etiqueta:"; +$a->strings["Last background fetch: "] = "Última actualització en rerefons:"; +$a->strings["Running at web location"] = "Correguent en el lloc web"; +$a->strings["Please visit redmatrix.me to learn more about \$Projectname."] = "Ves a redmatrix.me per saber-ne més sobre \$Projectname."; +$a->strings["Bug reports and issues: please visit"] = "Per informar d'errors o problemes ves a"; +$a->strings["\$projectname issues"] = "\$projectname emisions"; +$a->strings["Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot com"] = "Per suggerències, felicitacions i altres, envia'ns un mail a «redmatrix» [arroba] librelist [punt] com"; +$a->strings["Site Administrators"] = "Administradors del lloc"; +$a->strings["Unable to locate original post."] = "No s'ha pogut trobar l'entrada original."; +$a->strings["Empty post discarded."] = "S'ha descartat l'entrada perquè no té contingut."; +$a->strings["Executable content type not permitted to this channel."] = "No està permès el contingut de tipus executable en aquest canal."; +$a->strings["System error. Post not saved."] = "Hi ha hagut un error del sistema. L'entrada no s'ha desat."; +$a->strings["Unable to obtain post information from database."] = "No s'ha pogut obtenir informació de l'entrada a la base de dades."; +$a->strings["You have reached your limit of %1$.0f top level posts."] = "Has assolit el teu límit de %1$.0f entrades (descomptant comentaris)."; +$a->strings["You have reached your limit of %1$.0f webpages."] = "Has assolit el teu limit de %1$.0f pàgines web."; +$a->strings["No such group"] = "No existeix el grup"; +$a->strings["No such channel"] = "No existeix el canal"; +$a->strings["Search Results For:"] = "Cerca resultats per:"; +$a->strings["Collection is empty"] = "La coÅ€lecció és buida"; +$a->strings["Collection: "] = "CoÅ€lecció:"; +$a->strings["Connection: "] = "Connexió:"; +$a->strings["Invalid connection."] = "La connexió és invàlida."; +$a->strings["No channel."] = "No s'ha trobat el canal"; +$a->strings["Common connections"] = "Connexions en comú"; +$a->strings["No connections in common."] = "No hi ha connexions en comú."; +$a->strings["This site is not a directory server"] = "Aquest lloc web no és un servidor de directori"; +$a->strings["Could not access contact record."] = "No s'ha pogut accedir al llibre de contactes."; +$a->strings["Could not locate selected profile."] = "No s'ha trobat el perfil indicat."; +$a->strings["Connection updated."] = "S'ha actualitzat la connexió."; +$a->strings["Failed to update connection record."] = "No s'ha pogut actualitzar el registre de connexió."; +$a->strings["Blocked"] = "Bloquejades"; +$a->strings["Ignored"] = "Ignorades"; +$a->strings["Hidden"] = "Amagades"; +$a->strings["Archived"] = "Arxivades"; +$a->strings["Suggest new connections"] = "Suggereix noves connexions"; +$a->strings["New Connections"] = "Noves Connexions"; +$a->strings["Show pending (new) connections"] = "Mostra les connexions pendents (noves)"; +$a->strings["All Connections"] = "Totes les Connexions"; +$a->strings["Show all connections"] = "Mostra totes les connexions"; +$a->strings["Unblocked"] = "No bloquejades"; +$a->strings["Only show unblocked connections"] = "Mostra només les connexions no bloquejades"; +$a->strings["Only show blocked connections"] = "Mostra només les connexions bloquejades"; +$a->strings["Only show ignored connections"] = "Mostra només les connexions ignorades"; +$a->strings["Only show archived connections"] = "Mostra només les connexions arxivades"; +$a->strings["Only show hidden connections"] = "Mostra només les connexions amagades"; +$a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]"; +$a->strings["Edit connection"] = "Modifica la connexió"; +$a->strings["Search your connections"] = "Cerca entre les teves connexions"; +$a->strings["Finding: "] = "Cercant:"; +$a->strings["Block Name"] = "Nom del Bloc"; +$a->strings["Block Title"] = "Títol del bloc"; +$a->strings["Item not found"] = "No s'ha trobat l'element"; +$a->strings["Item is not editable"] = "Article no editable"; +$a->strings["Delete item?"] = "Esborrar ítem"; +$a->strings["Insert YouTube video"] = "insereix video YouTube"; +$a->strings["Insert Vorbis [.ogg] video"] = "Insereix video Vorbis [.ogg]"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Insereix audio Vorbis [.ogg]"; +$a->strings["\$Projectname - Guests: Username: {your email address}, Password: +++"] = "\$Projectname - Convidats: Nom d'usuari: {el teu correu electrònic}, Contrasenya: +++"; +$a->strings["Page owner information could not be retrieved."] = "La informació del propietari de la pàgina no va poder ser recuperada"; +$a->strings["Album not found."] = "Àlbum no trobat"; +$a->strings["Delete Album"] = "Esborra Àlbum"; +$a->strings["Delete Photo"] = "Esborra Foto"; +$a->strings["No photos selected"] = "No has seleccionat fotos"; +$a->strings["Access to this item is restricted."] = "L'accés a aquest element esta restringit."; +$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "S'estan fent servir %1$.2f MB de %2$.2f MB de l'espai per a imatges."; +$a->strings["%1$.2f MB photo storage used."] = "S'estan fent servir %1$.2f MB de l'espai per a imatges."; +$a->strings["Upload Photos"] = "Puja imatges"; +$a->strings["Enter a new album name"] = "Escriu el nom del nou àlbum"; +$a->strings["or select an existing one (doubleclick)"] = "o bé fes doble clic a un d'existent"; +$a->strings["Create a status post for this upload"] = "Genera una entrada a partir de la pujada"; +$a->strings["Album name could not be decoded"] = "No s'ha pogut descodificar el nom de l'àlbum"; +$a->strings["Contact Photos"] = "Imatges de contactes"; +$a->strings["Show Newest First"] = "Ordena de més nou a més antic"; +$a->strings["Show Oldest First"] = "Ordena de més antic a més nou"; +$a->strings["View Photo"] = "Mostra la imatge"; +$a->strings["Edit Album"] = "Modifica l'àlbum"; +$a->strings["Permission denied. Access to this item may be restricted."] = "S'ha denegat el permís. Pot ser que l'accés estigui restringit."; +$a->strings["Photo not available"] = "La imatge no està disponible"; +$a->strings["Use as profile photo"] = "Fes-la imatge de perfil"; +$a->strings["Private Photo"] = "Imatge privada"; +$a->strings["View Full Size"] = "Mostra a mida completa"; +$a->strings["Edit photo"] = "Modifica la imatge"; +$a->strings["Rotate CW (right)"] = "Tomba cap a la dreta"; +$a->strings["Rotate CCW (left)"] = "Tomba cap a l'esquerra"; +$a->strings["Caption"] = "Llegenda"; +$a->strings["Add a Tag"] = "Afegeix una etiqueta"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Exemple: @joan, @Paula_Peris, @mar@exemple.org"; +$a->strings["Flag as adult in album view"] = "Marca com a contingut adult"; +$a->strings["In This Photo:"] = "Hi apareixen:"; +$a->strings["Map"] = "Mapa"; +$a->strings["View Album"] = "Mostra'n l'àlbum"; +$a->strings["Recent Photos"] = "Imatges recents"; +$a->strings["Items tagged with: %s"] = "Elements etiquetats amb: %s"; +$a->strings["Search results for: %s"] = "Resultats de cerca per: %s"; +$a->strings["Profile Match"] = "Perfils compatibles"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "No tens paraules clau al perfil principal per poder cercar perfils semblants."; +$a->strings["is interested in:"] = "té interès en:"; +$a->strings["No matches"] = "No s'han trobat perfils compatibles"; +$a->strings["Away"] = "Absent"; +$a->strings["Online"] = "En connexió"; +$a->strings["Select a bookmark folder"] = "Tria una carpeta d'interès"; +$a->strings["Save Bookmark"] = "Guarda Favorits"; +$a->strings["URL of bookmark"] = "URL de favorit"; +$a->strings["Description"] = "Descripció"; +$a->strings["Or enter new bookmark folder name"] = "O entra un nou nom de favorit"; +$a->strings["No more system notifications."] = "No hi ha més notificacions de sistema."; +$a->strings["System Notifications"] = "Notificacions de sistema"; +$a->strings["network"] = "xarxa"; +$a->strings["RSS"] = "RSS"; +$a->strings["Layout updated."] = "S'ha actualitzat la disposició."; +$a->strings["Edit System Page Description"] = "Editor del Sistema de Descripció de Pàgines"; +$a->strings["Layout not found."] = "No s'ha trobat cap disposició de pàgina."; +$a->strings["Module Name:"] = "Nom del mòdul:"; +$a->strings["Layout Help"] = "Ajuda per la disposició de pàgina"; +$a->strings["- select -"] = "- selecciona -"; +$a->strings["Your service plan only allows %d channels."] = "El teu paquet de serveis només admet %d canals."; +$a->strings["Nothing to import."] = "No hi ha res a importar."; +$a->strings["Unable to download data from old server"] = "No s'han pogut descarregar les dades del servidor antic"; +$a->strings["Imported file is empty."] = "El fitxer importat està buit."; +$a->strings["The data provided is not compatible with this project."] = "Les dades subministrades no son compatibles amb aquest projecte."; +$a->strings["Warning: Database versions differ by %1\$d updates."] = "Atenció: Les versions de la Base de Dades difereixen en %1\$d actualitzacions."; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "No s'ha pogut importar el canal perquè l'identificador del canal no s'ha pogut duplicar en aquest servidor."; +$a->strings["Channel clone failed. Import failed."] = "No s'ha pogut importar el canal perquè el canal no s'ha pogut clonar."; +$a->strings["Cloned channel not found. Import failed."] = "No s'ha pogut importar el canal perquè el canal clonat no s'ha trobat."; +$a->strings["You must be logged in to use this feature."] = "Has d'estar registrat per fer servir aquesta funcionalitat."; +$a->strings["Import Channel"] = "Importa un canal"; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file."] = "Empra aquest formulari per importar un canal existent en un altre servidor/concentrador. Pots recuperar el canal des de l'antic servidor/concentrador via la xarxa o mitjançant un fitxer d'exportació"; +$a->strings["File to Upload"] = "Fitxer a pujar"; +$a->strings["Or provide the old server/hub details"] = "O proveeix els detalls de l'antic servidor/concentrador"; +$a->strings["Your old identity address (xyz@example.com)"] = "La teva adreça de canal antiga. El format és canal@exemple.org"; +$a->strings["Your old login email address"] = "La teva adreça de correu electrònic antiga"; +$a->strings["Your old login password"] = "La teva contrasenya antiga"; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Per a qualsevol de les opcions, escull si vols fer primària l'adreça d'aquest hub o mantenir l'anterior com a primària. Podràs penjar entrades des de totes dues adreces, però per als fitxers, imatges i altres en cal una de primària."; +$a->strings["Make this hub my primary location"] = "Fes d'aquest hub la meva ubicació primària"; +$a->strings["Import existing posts if possible (experimental - limited by available memory"] = "Importa les entrades existents si es possible (experimental - limitat per la memòria disponible"; +$a->strings["This process may take several minutes to complete. Please submit the form only once and leave this page open until finished."] = "Aquest procès pot trigar minuts en completar. Si et plau envia el formulari només una vegada i manté aquesta pàgina oberta fins que finalitzi."; +$a->strings["Delete layout?"] = "Esborra format?"; +$a->strings["Layout Description (Optional)"] = "Descripció del Format (Opcional)"; +$a->strings["Layout Name"] = "Nom del Format Gràfic"; +$a->strings["Edit Layout"] = "Edita Format Gràfic"; +$a->strings["You must be logged in to see this page."] = "Has d'estar identificat per a veure aquesta pàgina."; +$a->strings["Room not found"] = "No s'ha trobat la sala"; +$a->strings["Leave Room"] = "Abandona la sala"; +$a->strings["Delete This Room"] = "Elimina la sala"; +$a->strings["I am away right now"] = "Absent"; +$a->strings["I am online"] = "Estic connectat/da"; +$a->strings["Bookmark this room"] = "Fes favorit aquest xat"; +$a->strings["New Chatroom"] = "Nova sala per a Xerrar"; +$a->strings["Chatroom Name"] = "Nom del Xat"; +$a->strings["%1\$s's Chatrooms"] = "%1\$s de Xats"; +$a->strings["Menu not found."] = "Menú no trobat."; +$a->strings["Unable to create element."] = "Incapaç de crear l'element."; +$a->strings["Unable to update menu element."] = "Incapaç d'actualitzar un element del menú."; +$a->strings["Unable to add menu element."] = "Incapaç d'afegir l'element del menú."; +$a->strings["Menu Item Permissions"] = "Permisos de l'Article del Menú"; +$a->strings["(click to open/close)"] = "(clica per obrir/tancar)"; +$a->strings["Link Name"] = "Nom de l'Enllaç"; +$a->strings["Link or Submenu Target"] = "Enllaç o Submenú Objectiu"; +$a->strings["Enter URL of the link or select a menu name to create a submenu"] = "Entra la URL de l'enlla´o tria un nom de menú per crear un submenú"; +$a->strings["Use magic-auth if available"] = "Empra magic-auth si esta disponible"; +$a->strings["Open link in new window"] = "Obrir l'enllaç en una nova finestra"; +$a->strings["Order in list"] = "Ordre per llista"; +$a->strings["Higher numbers will sink to bottom of listing"] = "Els números més alts aniràn al fons de la llista"; +$a->strings["Submit and finish"] = "Envia i termina"; +$a->strings["Submit and continue"] = "Envia i continua"; +$a->strings["Menu:"] = "Menú:"; +$a->strings["Link Target"] = "Enllaç Objectiu"; +$a->strings["Edit menu"] = "Edita menú"; +$a->strings["Edit element"] = "Edita element"; +$a->strings["Drop element"] = "Deixa anar element"; +$a->strings["New element"] = "Nou element"; +$a->strings["Edit this menu container"] = "Edita aquest contenidor de menú"; +$a->strings["Add menu element"] = "Afegeix element de menú"; +$a->strings["Delete this menu item"] = "Esborra aquest article del menú"; +$a->strings["Edit this menu item"] = "Edita aquest article del menú"; +$a->strings["Menu item not found."] = "Article del menú no trobat."; +$a->strings["Menu item deleted."] = "Article del menú eliminat."; +$a->strings["Menu item could not be deleted."] = "Article del menú no es pot eliminar."; +$a->strings["Edit Menu Element"] = "Editar Element del Menú"; +$a->strings["Link text"] = "Enllaç de text"; +$a->strings["Delete webpage?"] = "Esborrar pàgina web?"; +$a->strings["Page link title"] = "Títol de la pàgina enllaçada"; +$a->strings["Edit Webpage"] = "Edita la Pàgina Web"; +$a->strings["This directory server requires an access token"] = "Aquest servidor de directori requereix un token de accès"; +$a->strings["No valid account found."] = "No es troba un compte vàlid."; +$a->strings["Password reset request issued. Check your email."] = "Sol·licitud de restabliment de contrasenya emesa. Consulta el teu correu electrònic."; +$a->strings["Site Member (%s)"] = "Lloc d'Usuari (%s)"; +$a->strings["Password reset requested at %s"] = "S'ha soÅ€licitat restablir la contrasenya al hub %s"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Ha fallat el restabliment de contrasenya perquè la no s'ha pogut verificar soÅ€licitud. Pot ser que ja ho hàgiu soÅ€licitat abans."; +$a->strings["Password Reset"] = "Restabliment de contrasenya"; +$a->strings["Your password has been reset as requested."] = "S'ha restablert la vostra contrasenya."; +$a->strings["Your new password is"] = "La nova contrasenya és"; +$a->strings["Save or copy your new password - and then"] = "Desa o copia la nova contrasenya, i després"; +$a->strings["click here to login"] = "fes clic aquí per iniciar sessió"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Pots canviar la contrasenya a la pàgina Paràmetres, un cop iniciada la sessió."; +$a->strings["Your password has changed at %s"] = "La teva contrasenya a %s ha canviat"; +$a->strings["Forgot your Password?"] = "No recordes la contrasenya?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Escriu la teva adreça de correu electrònic i envia per restablir la contrasenya. Després revisa el seu correu electrònic per obtenir més instruccions."; +$a->strings["Email Address"] = "Adreça electrònica"; +$a->strings["Reset"] = "Reajustar"; +$a->strings["Website:"] = "Lloc web:"; +$a->strings["Remote Channel [%s] (not yet known on this site)"] = "Canal Remot [%s] (encara no es coneix en aquest lloc)"; +$a->strings["Rating (this information is public)"] = "Valoració (aquesta informació és pública)"; +$a->strings["Optionally explain your rating (this information is public)"] = "Opcionalment pots explicar la teva qualificació (aquesta informació és pública)"; +$a->strings["Delete block?"] = "Eliminar bloc?"; +$a->strings["Edit Block"] = "Editar Bloc"; +$a->strings["Total invitation limit exceeded."] = "El límit total invitacions s'ha superat."; +$a->strings["%s : Not a valid email address."] = "%s: adreça de correu electrònic no vàlida."; +$a->strings["Please join us on Red"] = "Si us plau, uneix-te a Red"; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = "Límit d'invitacions excedit. Si us plau, poseu-vos en contacte amb l'administrador del lloc."; +$a->strings["%s : Message delivery failed."] = "%s : Entrega del Missatge fallida."; +$a->strings["%d message sent."] = array( + 0 => "%d missatge enviat.", + 1 => "%d missatges enviats.", +); +$a->strings["You have no more invitations available"] = "No té més invitacions disponibles"; +$a->strings["Send invitations"] = "Enviar invitacions"; +$a->strings["Enter email addresses, one per line:"] = "Introduïu les adreces de correu electrònic, una per línia:"; +$a->strings["Your message:"] = "El teu missatge:"; +$a->strings["Please join my community on \$Projectname."] = "Si us plau uneix-te la meva comunitat en \$Projectname."; +$a->strings["You will need to supply this invitation code: "] = "Has de proporcionar aquest codi d'invitació:"; +$a->strings["1. Register at any \$Projectname location (they are all inter-connected)"] = "1. Registre en qualsevol lloc del \$Projectname (estàn tots interconnectats)"; +$a->strings["2. Enter my \$Projectname network address into the site searchbar."] = "2. Entra a la meva adreça de xarxa al \$Projectname, a la barra de cerca del lloc."; +$a->strings["or visit "] = "o visita"; +$a->strings["3. Click [Connect]"] = "3. Click [Conectar]"; +$a->strings["Location not found."] = "Situació que no es troba."; +$a->strings["Primary location cannot be removed."] = "La ubicació primària no es pot treure."; +$a->strings["No locations found."] = "No es troben els llocs."; +$a->strings["Manage Channel Locations"] = "Gestionar Ubicacions de Canal"; +$a->strings["Location (address)"] = "Ubicació (direcció)"; +$a->strings["Primary Location"] = "Ubicació Primària"; +$a->strings["Drop location"] = "Treure la ubicació"; +$a->strings["Failed to create source. No channel selected."] = "Error en crear l'origen. Cap canal seleccionat."; +$a->strings["Source created."] = "Origen creat."; +$a->strings["Source updated."] = "Origen actualitzat."; +$a->strings["*"] = "*"; +$a->strings["Manage remote sources of content for your channel."] = "Gestiona contingut per al teu canal d'origens remots"; +$a->strings["New Source"] = "Nou Origen"; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importar tot o sel·lecciona contingut dels següents canals, en aquest canal i distribueix-lo d'acord als teus ajustos de canals."; +$a->strings["Only import content with these words (one per line)"] = "Només importa contingut amb aquestes paraules (una per línia)"; +$a->strings["Leave blank to import all public content"] = "Deixar en blanc per importar tot el contingut públic"; +$a->strings["Channel Name"] = "Nom del canal"; +$a->strings["Source not found."] = "No s'ha trobat la font."; +$a->strings["Edit Source"] = "Edita la font"; +$a->strings["Delete Source"] = "Esborra la font"; +$a->strings["Source removed"] = "S'ha esborrat la font"; +$a->strings["Unable to remove source."] = "No s'ha pogut esborrar la font."; +$a->strings["Unable to update menu."] = "No s'ha pogut actualitzar el menú."; +$a->strings["Unable to create menu."] = "No s'ha pogut crear el menú."; +$a->strings["Menu Name"] = "Nom del menú"; +$a->strings["Unique name (not visible on webpage) - required"] = "Nom únic (no visible a la pàgina web) - requerit"; +$a->strings["Menu Title"] = "Títol del menú"; +$a->strings["Visible on webpage - leave empty for no title"] = "Visible a la pàgina web - deixar buit per a no posar títol"; +$a->strings["Allow Bookmarks"] = "Permetre Marcadors"; +$a->strings["Menu may be used to store saved bookmarks"] = "El menú es pot emprar per a guardar marcadors"; +$a->strings["Submit and proceed"] = "Envia i procedeix"; +$a->strings["Drop"] = "Menysprea"; +$a->strings["Bookmarks allowed"] = "Marcadors permesos"; +$a->strings["Delete this menu"] = "Esborra el menú"; +$a->strings["Edit menu contents"] = "Edita el contingut del menú"; +$a->strings["Edit this menu"] = "Edita el menú"; +$a->strings["Menu could not be deleted."] = "El menu no es pot esborrar."; +$a->strings["Edit Menu"] = "Edita Menú"; +$a->strings["Add or remove entries to this menu"] = "Afegeix o esborra entrades a aquest menú"; +$a->strings["Menu name"] = "Nom del Menú"; +$a->strings["Must be unique, only seen by you"] = "Ha de ser únic, nomes vist per tú"; +$a->strings["Menu title"] = "Títol del menú"; +$a->strings["Menu title as seen by others"] = "Títol del menú vist pels altres"; +$a->strings["Allow bookmarks"] = "Marcadors permesos"; +$a->strings["Permission Denied."] = "Permisos Denegats."; +$a->strings["File not found."] = "Arxiu no torbat."; +$a->strings["Edit file permissions"] = "Edita els permisos d'arxiu"; +$a->strings["Set/edit permissions"] = "Canvia/edita permisos"; +$a->strings["Include all files and sub folders"] = "Inclou tots als arxius i subdirectoris"; +$a->strings["Return to file list"] = "Tornar al llistat d'arxius"; +$a->strings["Copy/paste this code to attach file to a post"] = "Copia/enganxa aquest codi per a adjuntar un arxiu a l'entrada"; +$a->strings["Copy/paste this URL to link file from a web page"] = "Copia/enganxa aquesta URL per a enllaçar l'arxiu d'una pàgina web"; +$a->strings["Share this file"] = "Comparteix l'arxiu"; +$a->strings["Show URL to this file"] = "Mostra la URL d'aquest arxiu"; +$a->strings["Notify your contacts about this file"] = "Notifica als teus contactes aquest arxiu"; +$a->strings["Contact not found."] = "Contacte no trobat."; +$a->strings["Friend suggestion sent."] = "Suggeriment d'amistat enviada."; +$a->strings["Suggest Friends"] = "Amics Suggerits"; +$a->strings["Suggest a friend for %s"] = "Suggereix un amic per a %s"; +$a->strings["Hub not found."] = "Concentrador no trobat."; +$a->strings["Poke/Prod"] = "Emprenyat/Picat"; +$a->strings["poke, prod or do other things to somebody"] = "emprenyar, picar o fer altres coses a algú"; +$a->strings["Recipient"] = "Destinatari"; +$a->strings["Choose what you wish to do to recipient"] = "Tria que vols fer amb el destinatari"; +$a->strings["Make this post private"] = "Fer aquesta entrada privada"; +$a->strings["Invalid profile identifier."] = "Identificador invàlid de perfil."; +$a->strings["Profile Visibility Editor"] = "Perfil del Editor de Visibilitat"; +$a->strings["Click on a contact to add or remove."] = "Clica sobre el contacte per afegir o esborrar."; +$a->strings["Visible To"] = "Visible per"; +$a->strings["%s element installed"] = "%s element instal·lat"; +$a->strings["%s element installation failed"] = "%s instal·lació d'element va fallar"; +$a->strings["Profile not found."] = "Perfil no trobat."; +$a->strings["Profile deleted."] = "Perfil eliminat."; +$a->strings["Profile-"] = "Perfil-"; +$a->strings["New profile created."] = "Nou perfil creat."; +$a->strings["Profile unavailable to clone."] = "Perfil que no es pot clonar."; +$a->strings["Profile unavailable to export."] = "Perfil que no es pot exportar."; +$a->strings["Profile Name is required."] = "Es requereix el Nom del Perfil."; +$a->strings["Marital Status"] = "Estat Marital"; +$a->strings["Romantic Partner"] = "Company/a Romàntic"; +$a->strings["Likes"] = "Agrada"; +$a->strings["Dislikes"] = "Desagrada"; +$a->strings["Work/Employment"] = "Treball/Feina"; +$a->strings["Religion"] = "Religió"; +$a->strings["Political Views"] = "Idees Polítiques"; +$a->strings["Gender"] = "Gènere"; +$a->strings["Sexual Preference"] = "Preferència Sexual"; +$a->strings["Homepage"] = "Pàgina Personal"; +$a->strings["Interests"] = "Interessos"; +$a->strings["Address"] = "Adreça"; +$a->strings["Profile updated."] = "Perfil actualitzat."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "Amaga la teva llista de contactes/amics dels visitadors d'aquest perfil?"; +$a->strings["Edit Profile Details"] = "Edita els Detalls del Perfil"; +$a->strings["View this profile"] = "Veure aquest perfil"; +$a->strings["Change Profile Photo"] = "Canviar Foto del Perfil"; +$a->strings["Create a new profile using these settings"] = "Crea un perfil nou amb aquests ajustos"; +$a->strings["Clone this profile"] = "Clonar aquest perfil"; +$a->strings["Delete this profile"] = "Elimina aquest perfil"; +$a->strings["Import profile from file"] = "Importa perfil des d'un arxiu"; +$a->strings["Export profile to file"] = "Exporta perfil a un arxiu"; +$a->strings["Profile Name:"] = "Nom del Perfil:"; +$a->strings["Your Full Name:"] = "El Teu Nom Complet"; +$a->strings["Title/Description:"] = "Títol/Descripció:"; +$a->strings["Your Gender:"] = "El Teu Gènere:"; +$a->strings["Birthday :"] = "Aniversari:"; +$a->strings["Street Address:"] = "Carrer:"; +$a->strings["Locality/City:"] = "Població/Ciutat:"; +$a->strings["Postal/Zip Code:"] = "Codi Postal:"; +$a->strings["Country:"] = "País:"; +$a->strings["Region/State:"] = "Regió/Estat:"; +$a->strings[" Marital Status:"] = " Marital Estatus:"; +$a->strings["Who: (if applicable)"] = "Qui: (si es aplicable)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Examples: cathy123, Cathy Williams, cathy@example.com"; +$a->strings["Since [date]:"] = "Des de [data]:"; +$a->strings["Homepage URL:"] = "Pàgina Personal URL:"; +$a->strings["Religious Views:"] = "Creences Religioses:"; +$a->strings["Keywords:"] = "Paraules Clau:"; +$a->strings["Example: fishing photography software"] = "Exemple: software de fotografia submarina"; +$a->strings["Used in directory listings"] = "Emprat en els llistats de directoris"; +$a->strings["Tell us about yourself..."] = "Quelcom sobre tú:"; +$a->strings["Hobbies/Interests"] = "Aficions/Interessos"; +$a->strings["Contact information and Social Networks"] = "Informació de Contacte i Xarxes Socials"; +$a->strings["My other channels"] = "Els meus altres canals"; +$a->strings["Musical interests"] = "Interessos Musicals"; +$a->strings["Books, literature"] = "Llibres, literatura"; +$a->strings["Television"] = "Televisió"; +$a->strings["Film/dance/culture/entertainment"] = "Pel·lícules/Dansa/Cultura/Entreteniment"; +$a->strings["Love/romance"] = "Amor/Romace"; +$a->strings["Work/employment"] = "Treball/feina"; +$a->strings["School/education"] = "Escola/educació"; +$a->strings["This is your default profile."] = "Aquest es el teu perfil per defecte"; +$a->strings["Age: "] = "Edat:"; +$a->strings["Edit/Manage Profiles"] = "Edita/Gestiona Perfils"; +$a->strings["Add profile things"] = "Afegeix coses al perfil"; +$a->strings["Include desirable objects in your profile"] = "Inclou objectius desitjables al teu perfil"; +$a->strings["No ratings"] = "No valorat"; +$a->strings["Ratings"] = "Valoracions"; +$a->strings["Rating: "] = "Valoració:"; +$a->strings["Website: "] = "Lloc web:"; +$a->strings["Description: "] = "Descripció:"; +$a->strings["Source of Item"] = "Origen de l'article"; +$a->strings["\$Projectname Server - Setup"] = "Servidor \$Projectname - Configuració"; +$a->strings["Could not connect to database."] = "No puc connectar amb la base de dades"; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "No s'ha pogut connectar a l'URL del lloc especificat. Possible problema amb el certificat SSL o de DNS."; +$a->strings["Could not create table."] = "No puc crear la taula."; +$a->strings["Your site database has been installed."] = "La teva base de dades del lloc s'ha instal·lat."; +$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Podria ser necessari importar el fitxer \"install / schema_xxx.sql\" manualment utilitzant un client de base de dades."; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Si us plau, consulteu el fitxer \"install / INSTALL.txt\"."; +$a->strings["System check"] = "Comprovació del sistema"; +$a->strings["Check again"] = "Comprova de nou"; +$a->strings["Database connection"] = "Connexió de base de dades"; +$a->strings["In order to install \$Projectname we need to know how to connect to your database."] = "Per tal d'instaÅ€lar \$Projectname cal configurar la connexió a la base de dades."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Si us plau, poseu-vos en contacte amb el proveïdor de serveis o administrador del lloc si vostè té preguntes sobre aquests paràmetres."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "La base de dades s'especifica a continuació ja ha d'existir. Si no és així, si us plau crear-la abans de continuar."; +$a->strings["Database Server Name"] = "Base de Dades Nom del Servidor"; +$a->strings["Default is localhost"] = "Per defecte es localhost"; +$a->strings["Database Port"] = "Port per a la Base de Dades"; +$a->strings["Communication port number - use 0 for default"] = "Numero del port de comunicacions - empra 0 per defecte"; +$a->strings["Database Login Name"] = "Base de Dades Nom d'Accès"; +$a->strings["Database Login Password"] = "Base de Dades Contrasenya d'Accès"; +$a->strings["Database Name"] = "Nom de la Base de Dades"; +$a->strings["Database Type"] = "Tipus de Base de Dades"; +$a->strings["Site administrator email address"] = "Adreça de correu de l'administrador del lloc"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "El teu compte de email ha de coincidir amb això per poder emprar el panel web d'administrador."; +$a->strings["Website URL"] = "URL del lloc web"; +$a->strings["Please use SSL (https) URL if available."] = "Si us plau, empra SSL (https) URL si està disponible."; +$a->strings["Please select a default timezone for your website"] = "Si us plau, tria la zona horària del teu lloc web"; +$a->strings["Site settings"] = "Ajustos del lloc"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "No s'ha pogut trobar una versió de línia d'ordres del PHP en el PATH del servidor web."; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Si vostè no té una versió de línia d'ordres del PHP instal·lada al servidor, vostè no serà capaç d'executar sondejos en segon pla via cron."; +$a->strings["PHP executable path"] = "Camí cap l'executable de PHP"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Introdueix el camí cap l'executable de php. Pots deixa-ho en blanc i continuar l'instal·lació."; +$a->strings["Command line PHP"] = "Línia d'ordres de PHP"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "La versió de línia d'ordres de PHP al teu sistema no te el \"register_argc_argv\" activat."; +$a->strings["This is required for message delivery to work."] = "Això es requereix per que funcioni l'entrega de missatges."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once."] = "La mida màxima que se't permet pujar està establerta en %s. La mida màxima per arxiu pujat es de %s. Se't permet pujar fins a %d arxius d'una vegada."; +$a->strings["You can adjust these settings in the servers php.ini."] = "Pots ajustar aquests valors a l'arxiu php.ini del servidor"; +$a->strings["PHP upload limits"] = "Límits de pujada de PHP"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Error: la funció \"openssl_pkey_new\" en aquest sistema no es capaç de generar claus d'encriptació"; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Si esta funcionant sota Windows, per favor, miri \"http://www.php.net/manual/en/openssl.installation.php\"."; +$a->strings["Generate encryption keys"] = "Generar claus de xifrat"; +$a->strings["libCurl PHP module"] = "mòdul PHP libCurl "; +$a->strings["GD graphics PHP module"] = "mòdul PHP GD gràfics"; +$a->strings["OpenSSL PHP module"] = "mòdul PHP OpenSSL"; +$a->strings["mysqli or postgres PHP module"] = "mòdul PHP mysqli o postgres"; +$a->strings["mb_string PHP module"] = "mòdul PHP mb_string"; +$a->strings["mcrypt PHP module"] = "mòdul PHP mcrypt"; +$a->strings["xml PHP module"] = "Mòdul xml de PHP"; +$a->strings["Apache mod_rewrite module"] = "mòdul Apache mod_rewrite"; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Error: el mòdul mod-rewrite del servidor web Apache es requereix i no està instal·lat."; +$a->strings["proc_open"] = "proc_open"; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Error: es requereix proc_open però o no està instal·lat o ha estat desactivat a php.ini"; +$a->strings["Error: libCURL PHP module required but not installed."] = "Error: el mòdul PHP libCURL es requereix però no està instal·lat."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Error: el mòdul PHP GD graphics amb support JPEG es requereix però no està instal·lat."; +$a->strings["Error: openssl PHP module required but not installed."] = "Error: el mòdul PHP openssl es requereix però no està instal·lat."; +$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Error: el mòdul PHO mysqli o postgres es requereix però no està instal·lat."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Error: el mòdul PHP mb_string es requereix però no està instal·lat."; +$a->strings["Error: mcrypt PHP module required but not installed."] = "Error: el mòdul PHP mcrypt es requereix però no està instal·lat."; +$a->strings["Error: xml PHP module required for DAV but not installed."] = "Error: el mòdul xml de PHP es requereix per DAV però no està instal·lat."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = "L'instaÅ€lador ha de poder crear i modificar un fitxer anomenat «.htconfig.php» a la carpeta arrel del servidor, però sembla que no ho pot fer."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Això sol ser un problema de permisos. Per molt que el teu usuari pugui modificar-lo, és el del servidor web qui necessita els poders de modificació."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Al final d'aquest procés hauràs de desar un text a l'arxiu «.htconfig.php», que es troba a la carpeta arrel del servidor."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Aquest procés és opcional. Per a fer una instaÅ€lació manual consulta les instruccions a «install/INSTALL.txt\"."; +$a->strings[".htconfig.php is writable"] = "L'arxiu «.htconfig.php» es pot modificar"; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red fa servir el motor de plantilles Smarty3 per a renderitzar les vistes més ràpidament."; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "Per tal de guardar aquestes plantilles compilades, el servidor web necessita tenir premis d'escriptura en el directori %s sota la carpeta principal de Red."; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Comprova que l'usuari que executa el servidor (www-data en Apache) té permisos d'escriptura en aquesta carpeta."; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Nota: com a mesura de seguretat l'usuari del servidor web ha de tenir accés d'escriptura només a %s, i no a les plantilles (.tpl) que conté."; +$a->strings["%s is writable"] = "Es pot escriure a %s"; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red fa servir la carpeta «store» per a desar els fitxers pujats. Per tant, el servidor web necessita tenir permís d'escriptura en aquesta carpeta, que està a l'arrel del servidor web."; +$a->strings["store is writable"] = "Es pot escriure al magatzem (store)"; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "El certificat SSL no s'ha pogut validar. Arregla-ho o deshabilita l'accés https a aquest lloc"; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Si tens accès pet https al teu lloc web o permets connexions pel port TCP 443 (port https), Has d'emprar un certificat VÀLID. NO es poden emprar certificats AUTO-SIGNATS!"; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "El motiu d'aquesta restricció és que les teves entrades públiques poden contenir referències a imatges del teu propi hub."; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Si el teu certificat no és reconegut, llavors el membres d'altres hubs, encara que tinguin certificats vàlids, rebran una advertència de seguretat en carregar contingut teu."; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Per tant, com que perjudica la usabilitat més enllà del teu lloc, la restricció de tenir un certificat reconegut és molt important."; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Hi ha autoritats de certificació reconegudes que ofereixen certificats gratuïts."; +$a->strings["SSL certificate validation"] = "Validació del certificat SSL"; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "No es poden reescriure les URL a «.htaccess». Comprova la configuració del servidor:"; +$a->strings["Url rewrite is working"] = "Es poden reescriure les URL a «.htaccess»"; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "L'arxiu de configuracio de la base de dades «.htconfig.php» no s'ha pogut modificar. El pots crear tu a l'arrel del servidor web amb el text de la caixa com a contingut."; +$a->strings["Errors encountered creating database tables."] = "S'han produït errors mentre es creaven taules a la base de dades."; +$a->strings["

    What next

    "] = "

    I ara què?

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "IMPORTANT! Cal que configuris manualment una execució periòdica del \"poller\"."; +$a->strings["OpenID protocol error. No ID returned."] = "Error del protocol OpenID. No ha retornat ID"; +$a->strings["Welcome %s. Remote authentication successful."] = "Benvingut %s. Autenticació remota reeixida."; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s ha etiquetat %3\$s de %2\$s amb %4\$s"; +$a->strings["Export Channel"] = "Exportar Canal"; +$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = "Exporta la informació bàsica del canal a un petit arxiu. Això actua com a còpia de recolzament de les teves connexions, permisos, perfil i dades bàsiques, les quals pots emprar per traslladar aquestes dades a una altre lloc/centre, però no conté el contingut del canal."; +$a->strings["Export Content"] = "Exportar el Contingut"; +$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = "Exporta la informació del canal i tot el contingut a un arxiu de recolzament JSON. Això còpia totes les teves connexions, permisos, perfil i dades i tot el contingut, però normalment no es pot importar en un altre canal d'un nou lloc/centre donat que l'arxiu acostuma a ser MOLT gran. Si et plau, sigues pacient ja que pot trigar uns minuts a començar a baixar."; +$a->strings["No connections."] = "Sense connexions."; +$a->strings["Visit %s's profile [%s]"] = "Visita el perfil [%s] de %s"; +$a->strings["invalid target signature"] = "Signatura objectiu invàlida"; +$a->strings["Theme settings updated."] = "Ajustos de tema actualitzats."; +$a->strings["Site"] = "Lloc"; +$a->strings["Accounts"] = "Comptes"; +$a->strings["Channels"] = "Canals"; +$a->strings["Plugins"] = "Plugins"; +$a->strings["Themes"] = "Temes"; +$a->strings["Inspect queue"] = "Revisa cua"; +$a->strings["Profile Config"] = "Configuració del Perfil"; +$a->strings["DB updates"] = "Actualitzacions de Base de Dades"; +$a->strings["Logs"] = "Logs"; +$a->strings["Plugin Features"] = "Característiques del Plugin"; +$a->strings["User registrations waiting for confirmation"] = "Registre d'usuaris esperant confirmació"; +$a->strings["# Accounts"] = "# Comptes"; +$a->strings["# blocked accounts"] = "# comptes bloquejats"; +$a->strings["# expired accounts"] = "# comptes expirats"; +$a->strings["# expiring accounts"] = "# comptes expirant"; +$a->strings["# Channels"] = "# Canals"; +$a->strings["# primary"] = "# primari"; +$a->strings["# clones"] = "# clons"; +$a->strings["Message queues"] = "Cues de missatges"; +$a->strings["Administration"] = "Administració"; +$a->strings["Summary"] = "Sumari"; +$a->strings["Registered accounts"] = "Comptes registrades"; +$a->strings["Pending registrations"] = "Comptes pendents de registre"; +$a->strings["Registered channels"] = "Canals registrats"; +$a->strings["Active plugins"] = "Plugins actius"; +$a->strings["Version"] = "Versió"; +$a->strings["Site settings updated."] = "Ajustos del Lloc actualitzats"; +$a->strings["mobile"] = "mòbil"; +$a->strings["experimental"] = "experimental"; +$a->strings["unsupported"] = "no soportat"; +$a->strings["Yes - with approval"] = "Sí - amb aprovació"; +$a->strings["My site is not a public server"] = "El meu lloc no es un servidor públic"; +$a->strings["My site has paid access only"] = "El meu lloc te accès per pagament"; +$a->strings["My site has free access only"] = "El meu lloc te lliure accés"; +$a->strings["My site offers free accounts with optional paid upgrades"] = "El meu lloc te comptes gratis amb opció de millores per pagament"; +$a->strings["Registration"] = "Registre"; +$a->strings["File upload"] = "Pujar arxiu"; +$a->strings["Policies"] = "Polítiques"; +$a->strings["Site name"] = "Nom del lloc"; +$a->strings["Banner/Logo"] = "Senyera/Logo"; +$a->strings["Administrator Information"] = "Informació de l'Administrador"; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = "Informació per contactar amb els administradors del lloc. Mostrada a la pàgina d'informació del lloc. Es pot emprar BBCode aquí"; +$a->strings["System language"] = "Idioma del sistema"; +$a->strings["System theme"] = "Tema del sistema"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "Tema del sistema per defecte - pot ser sobrescrit pel perfils dels usuaris - Ajustos de canvi del tema"; +$a->strings["Mobile system theme"] = "Tema del sistema per a mòbils"; +$a->strings["Theme for mobile devices"] = "Tema per a aparells mòbils"; +$a->strings["Enable Diaspora Protocol"] = "Activat el Protocol Diaspora"; +$a->strings["Communicate with Diaspora and Friendica - experimental"] = "Comunicar amb Diaspora i Friendica - experimental"; +$a->strings["Allow Feeds as Connections"] = "Permetre Retroalimentadors com Connexions"; +$a->strings["(Heavy system resource usage)"] = "(Demana molts recursos del sistema)"; +$a->strings["Maximum image size"] = "Mida màxima d'imatge"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Mida màxima en bytes de imatges pujades. Per defecte es 0, el que vol dir sense límits."; +$a->strings["Does this site allow new member registration?"] = "Permet aquest lloc registre de nous membres?"; +$a->strings["Which best describes the types of account offered by this hub?"] = "Que es es que millor descriu la mena de comptes oferits per aquest concentrador?"; +$a->strings["Register text"] = "text de registre"; +$a->strings["Will be displayed prominently on the registration page."] = "Es mostrarà preminentment a la pàgina de registre"; +$a->strings["Site homepage to show visitors (default: login box)"] = "Pàgina d'inici a mostrar als visitants (per defecte: la pàgina d'identificació)"; +$a->strings["example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file."] = "exemple: 'públic' per a mostrar un flux públic, 'page/sys/home' per a mostrar una pàgina web dita 'home' o 'include:home.html' per a incloure un arxiu."; +$a->strings["Preserve site homepage URL"] = "Preservar URL de la pàgina web"; +$a->strings["Present the site homepage in a frame at the original location instead of redirecting"] = "Presenta la pàgina web del lloc en un marc en el lloc original enlloc de redirigir cap a ella"; +$a->strings["Accounts abandoned after x days"] = "Els copmte es consideren abandonats despres de x dies"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "No malgastar recursos del sistema sondejant llocs externs per acomptes abandonats. Entrar 0 vol dir sense límit de temps."; +$a->strings["Allowed friend domains"] = "dominis amics permesos"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "llista separada per comes de dominis en els que està permès establir relacions d'amistat amb aquest lloc. S'accepten comodins. Deixar buit per acceptar qualsevol domini"; +$a->strings["Allowed email domains"] = "Dominis de correu electonic acceptats"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "llista separada per comes de dominis de adreces de correu electrònic permeses en aquest lloc. S'accepten comodins. Deixar buit per acceptar qualsevol domini"; +$a->strings["Not allowed email domains"] = "Dominis de correu electrònic no acceptats"; +$a->strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = "llista separada per comes de dominis de adreces de correu electrònic no permeses en aquest lloc. S'accepten comodins. Deixar buit per no acceptar cap domini, excepte els que s'hagin definits com acceptats."; +$a->strings["Block public"] = "Bloc públic"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Activa per a bloquejar l'accés públic a totes les pàgines públiques personals excepte si estàs identificat en el sistema."; +$a->strings["Verify Email Addresses"] = "Verifica l'Adreça de Correu Electrònic"; +$a->strings["Check to verify email addresses used in account registration (recommended)."] = "Activa per comprovar l'adreça de correu electrònic emprada durant el registre d'un nou compte (recomanat)"; +$a->strings["Force publish"] = "Forza la publicació"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Activa per forzar que tots el perfils en aquest lloc siguin llistats en el directori del lloc."; +$a->strings["Disable discovery tab"] = "Desactiva la pestañnya de descobrir"; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = "Treu la pesranya per veure contingut públic de la xarxa extret d'origens triats per aquest lloc."; +$a->strings["login on Homepage"] = "Accés a la Pàgina d'inici"; +$a->strings["Present a login box to visitors on the home page if no other content has been configured."] = "Presenta una casella d'identificació a la pàgina d'inici als visitants si no s'ha configurat altre contingut."; +$a->strings["Proxy user"] = "Usuari Proxy"; +$a->strings["Proxy URL"] = "URL del Proxy"; +$a->strings["Network timeout"] = "Temps d'espera de la xarxa"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "Valor en segons. Ajusta a 0 per a sense límits (no recomanat)"; +$a->strings["Delivery interval"] = "Interval de lliurament"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Retarda en segon plà l'interval de lliurament per aquests segons per reduir la càrrega del sistema. Recomanat: 4-5 per a hostes compartits, 2-3 per a servidors privats virtuals. 0-1 per a servidors dedicats."; +$a->strings["Poll interval"] = "interval de sondeig"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Retarda en segon pla el sondeig en aquesta quantitat de segons per a reduir la càrrega dels sistema. Si es 0 , empra l'interval de lliurament."; +$a->strings["Maximum Load Average"] = "Càrrega Mitja Màxima"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Càrrega màxima del sistema, abans que els processos de lliurament i sondeig es difereixin - 50 per defecte."; +$a->strings["Expiration period in days for imported (matrix/network) content"] = "Periode d'expiració per a contingut importat (matrix/xarxa)"; +$a->strings["0 for no expiration of imported content"] = "0 vol dir sense temps d'expiració pel contingut importat"; +$a->strings["No server found"] = "No es troba servidor"; +$a->strings["ID"] = "ID"; +$a->strings["for channel"] = "per a canal"; +$a->strings["on server"] = "al servidor"; +$a->strings["Status"] = "Estat"; +$a->strings["Server"] = "Servidor"; +$a->strings["Update has been marked successful"] = "Actualització marcada amb exit"; +$a->strings["Executing %s failed. Check system logs."] = "Executant %s ha fallat. Comprova els logs del sistema."; +$a->strings["Update %s was successfully applied."] = "Actualització %s es va realitzar correctament."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "Actualització %s no ha retornat l'estat. Es desconeix si ha finalitzat amb exit."; +$a->strings["Update function %s could not be found."] = "La funció d'actualitzacio %s no es pot trobar."; +$a->strings["No failed updates."] = "No hi ha actualitzacions fallides."; +$a->strings["Failed Updates"] = "Actualitzacions Fallides"; +$a->strings["Mark success (if update was manually applied)"] = "Marca èxit (si l'actualització s'ha aplicat de forma manual)"; +$a->strings["Attempt to execute this update step automatically"] = "Prova a fer automàticament aquesta actualització"; +$a->strings["Queue Statistics"] = "Cua d'Estadístiques"; +$a->strings["Total Entries"] = "Total d'Entrades"; +$a->strings["Priority"] = "Prioritat"; +$a->strings["Destination URL"] = "URL de Destí"; +$a->strings["Mark hub permanently offline"] = "Marca el concentrador coma permanentment fora de línia"; +$a->strings["Empty queue for this hub"] = "Cua buida per aquest concentrador"; +$a->strings["Last known contact"] = "Últim contacte conegut"; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "%s usuari bloquejat/desbloquejat", + 1 => "%s usuaris bloquejats/desbloquejats", +); +$a->strings["%s user deleted"] = array( + 0 => "%s usuari esborrat", + 1 => "%s usuaris esborrats", +); +$a->strings["Account not found"] = "Compte no trobat"; +$a->strings["User '%s' blocked"] = "Usuari '%s' bloquejat"; +$a->strings["User '%s' unblocked"] = "Usuari '%s' desbloquejat"; +$a->strings["Users"] = "Usuaris"; +$a->strings["select all"] = "Sel·leciona-ho tot"; +$a->strings["User registrations waiting for confirm"] = "Registres d'usuaris pendents de confirmació"; +$a->strings["Request date"] = "Data de la petició"; +$a->strings["No registrations."] = "Sense registracions."; +$a->strings["Approve"] = "Aprovat"; +$a->strings["Deny"] = "Denegat"; +$a->strings["Block"] = "Bloquejat"; +$a->strings["Unblock"] = "Desbloquejat"; +$a->strings["Register date"] = "Data de registre"; +$a->strings["Last login"] = "Darrera identificació"; +$a->strings["Expires"] = "Expira"; +$a->strings["Service Class"] = "Classe de Servei"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Tria els usuaris que s'esborraran!\\n\\nTotes les publicacions d'aquests usuaris en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur? "; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "L'usuari {0} sera esborrat!\\n\\nTotes les publicacions d'aquest usuari en aquest lloc s'eliminarà de forma permanent!\\n\\nEstas segur?"; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "%s canal censurat/no censurat", + 1 => "%s canals censurats/no censurats", +); +$a->strings["%s channel code allowed/disallowed"] = array( + 0 => "%s codi permes/no permes al canal", + 1 => "%s codi permesos/no permesos al canal", +); +$a->strings["%s channel deleted"] = array( + 0 => "%s canal esborrat", + 1 => "%s canals esborrats", +); +$a->strings["Channel not found"] = "Canal no trobat"; +$a->strings["Channel '%s' deleted"] = "Canal '%s' esborrat"; +$a->strings["Channel '%s' censored"] = "Canal '%s' censurat"; +$a->strings["Channel '%s' uncensored"] = "Canal '%s' no censurat"; +$a->strings["Channel '%s' code allowed"] = "Canal '%s' permet codi"; +$a->strings["Channel '%s' code disallowed"] = "Canal '%s' no permet codi"; +$a->strings["Censor"] = "Censurat"; +$a->strings["Uncensor"] = "No censurat"; +$a->strings["Allow Code"] = "Permet Codi"; +$a->strings["Disallow Code"] = "No Permet Codi"; +$a->strings["UID"] = "UID"; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = "Els canals sel·leccionats s'esborraran!\\n\\nTotes les publicacions d'aquests canals en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur? "; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = "El canal {0} serà esborrat!\\n\\nTotes les publicacions d'aquest canal en aquest lloc s'eliminaran de forma permanent!\\n\\nEstàs segur?"; +$a->strings["Plugin %s disabled."] = "Plugin %s desactivat."; +$a->strings["Plugin %s enabled."] = "Plugin %s activat."; +$a->strings["Disable"] = "Desactivat"; +$a->strings["Enable"] = "Activat"; +$a->strings["Toggle"] = "Commutar"; +$a->strings["Author: "] = "Autor: "; +$a->strings["Maintainer: "] = "Mantenedor:"; +$a->strings["No themes found."] = "No s'han trobat temes."; +$a->strings["Screenshot"] = "Copia de pantalla"; +$a->strings["[Experimental]"] = "[Experimental]"; +$a->strings["[Unsupported]"] = "[No soportat]"; +$a->strings["Log settings updated."] = "Registre d'ajustos actualitzat."; +$a->strings["Clear"] = "Neteja"; +$a->strings["Debugging"] = "Depurant"; +$a->strings["Log file"] = "Arxiu de registre"; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = "Ha de ser escribible pel servidor web. Relatiu al directori de nivell superior de Red"; +$a->strings["Log level"] = "Nivell de registre"; +$a->strings["New Profile Field"] = "Camp de Perfil Nou"; +$a->strings["Field nickname"] = "Àlies de Camp"; +$a->strings["System name of field"] = "nOM DEL SISTEMA DEL CAMP"; +$a->strings["Input type"] = "Tipus d'entrada"; +$a->strings["Field Name"] = "Nom de Camp"; +$a->strings["Label on profile pages"] = "Etiqueta a les pàgines de perfil"; +$a->strings["Help text"] = "Text d'ajuda"; +$a->strings["Additional info (optional)"] = "Informació adicional (opcional)"; +$a->strings["Field definition not found"] = "No es troba la definició del camp"; +$a->strings["Edit Profile Field"] = "Camp d'Edició del Perfil"; +$a->strings["Unable to find your hub."] = "No es possible trobar el concentrador"; +$a->strings["Post successful."] = "Entrada realitzada amb èxit. "; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Nombre màxim de registres diaris excedit. Si us plau, provau demà."; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "El registre ha fallat. Si et plau, indica que acceptes les Condicions del Servei."; +$a->strings["Passwords do not match."] = "Les contrasenyes no coincideixen."; +$a->strings["Registration successful. Please check your email for validation instructions."] = "registrat amb èxit. Si et plau revisa el teu e-correu per a instruccions de validació."; +$a->strings["Your registration is pending approval by the site owner."] = "El teu registre esta pendent de validació pel propietari del lloc."; +$a->strings["Your registration can not be processed."] = "El teu registre no ha pogut ser processat. "; +$a->strings["Registration on this site/hub is by approval only."] = "El registre en aquest lloc/centre es únicament per validació."; +$a->strings["Register at another affiliated site/hub"] = "Registre en altre lloc/centre afiliat"; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "El lloc ha excedit el límit màxim diari de nous comptes/registres. Provau demà."; +$a->strings["Terms of Service"] = "Condicions del Servei"; +$a->strings["I accept the %s for this website"] = "Accepto el %s per a aquest lloc web"; +$a->strings["I am over 13 years of age and accept the %s for this website"] = "Tinc més de 13 anys i accepto les %s d'aquest lloc web"; +$a->strings["Membership on this site is by invitation only."] = "La pertinença en aquest lloc es per invitació exclusivament."; +$a->strings["Please enter your invitation code"] = "Si et plau, introdueix el teu codi d'invitació"; +$a->strings["Your email address"] = "La teva adreça de correu electrónic"; +$a->strings["Choose a password"] = "Tria una contrasenya"; +$a->strings["Please re-enter your password"] = "Si et plau, re-entra la contrasenya"; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = "L'esborrat de comptes no està permès fins que transcorren 48 hores des de l'últim canvi de contrasenya."; +$a->strings["Remove This Account"] = "Esborra el compte"; +$a->strings["WARNING: "] = "ALERTA:"; +$a->strings["This account and all its channels will be completely removed from the network. "] = "Aquest compte i tots els seus canals s'estan apunt d'esborrar totalment de la xarxa."; +$a->strings["This action is permanent and can not be undone!"] = "Aquesta acció és irreversible!"; +$a->strings["Please enter your password for verification:"] = "Aquesta acció requereix tornar a introduir la contrasenya:"; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = "Esborra de la xarxa aquest compte, tots els seus canals, i tots els seus canals clons."; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = "Per defecte, només les instancies dels canal ubicats en aquest concentrador poden esser esborrades de la xarxa"; +$a->strings["Remove Account"] = "Esborra el Compte"; +$a->strings["Help:"] = "Ajuda:"; +$a->strings["Not Found"] = "No s'ha pogut trobar la pàgina"; +$a->strings["\$Projectname Documentation"] = "\$Projectname Documentació"; +$a->strings["[Embedded content - reload page to view]"] = "[Contingut embegut - recarrega la pàgina per veure-ho]"; +$a->strings["Remote privacy information not available."] = "informació privada remota no disponible."; +$a->strings["Visible to:"] = "Visible per:"; +$a->strings["Name is required"] = "Es requereix un Nom"; +$a->strings["Key and Secret are required"] = "Es requereix Clau (Key) i el Secret (Secret)"; +$a->strings["Diaspora Policy Settings updated."] = "Actualitzats els Ajustos de Política de Diaspora."; +$a->strings["Passwords do not match. Password unchanged."] = "Les contrasenyes no coincideixen. Contrasenya sense canvis."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Les contrasenyes en blanc no estan permesas. Contrasenya sense canvis."; +$a->strings["Password changed."] = "Contrasenya canviada."; +$a->strings["Password update failed. Please try again."] = "L'actualització de la contrasenya va fallar. Si us plau, torneu a intentar-ho."; +$a->strings["Not valid email."] = "E-correu no vàlid."; +$a->strings["Protected email address. Cannot change to that email."] = "Adreça d'e-correu protegida. No es pot canviar a aquest e-correu."; +$a->strings["System failure storing new email. Please try again."] = "Fallada del sistema al guardar un nou correu. Si us plau, proba de nou."; +$a->strings["Settings updated."] = "Ajustes actualizados."; +$a->strings["Add application"] = "Afegir aplicatiu"; +$a->strings["Name of application"] = "Nom de l'aplicatiu"; +$a->strings["Consumer Key"] = "Consumer Key"; +$a->strings["Automatically generated - change if desired. Max length 20"] = "Generat automàticament- Canvia-ho si ho vols. Max. longitud 20"; +$a->strings["Consumer Secret"] = "Consumer Secret"; +$a->strings["Redirect"] = "Redirecciona"; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = "URI redirigida - No canviar excepte perquè el teu aplicatiu ho requereixi."; +$a->strings["Icon url"] = "Icona de url"; +$a->strings["Optional"] = "Opcional"; +$a->strings["You can't edit this application."] = "No pots editar aquest aplicatiu."; +$a->strings["Connected Apps"] = "Aplicatius Conectats"; +$a->strings["Client key starts with"] = "La clau del client comença amb"; +$a->strings["No name"] = "Sin nombre"; +$a->strings["Remove authorization"] = "Elimina autorització"; +$a->strings["No feature settings configured"] = "No hi ha opcions de les funcions configurades"; +$a->strings["Feature/Addon Settings"] = "Ajustos de Característica/Afegit"; +$a->strings["Settings for the built-in Diaspora emulator"] = "Ajustos pel emulador de Diaspora incorporat"; +$a->strings["Allow any Diaspora member to comment on your public posts"] = "Permetre que cualsevol membre de Diaspora pugui comentar les teves entrades públiques"; +$a->strings["Enable the Diaspora protocol for this channel"] = "Activa el protocol Diaspora en aquest canal"; +$a->strings["Diaspora Policy Settings"] = "Política d'Ajustos de Diaspora"; +$a->strings["Prevent your hashtags from being redirected to other sites"] = "Evita que els teus hashtags puguin ser redirigits a altres llocs"; +$a->strings["Account Settings"] = "Ajustos de Compte"; +$a->strings["Enter New Password:"] = "Entra la Nova Contrasenya"; +$a->strings["Confirm New Password:"] = "Confirma la Nova Contrasenya:"; +$a->strings["Leave password fields blank unless changing"] = "Deixa els camps de contrasenya en blanc llevat que la volguis canviar"; +$a->strings["Email Address:"] = "Adreça de E-Correu:"; +$a->strings["Remove this account including all its channels"] = "Esborra aquest compte inclosos tots els seus canals"; +$a->strings["Off"] = "Apagat"; +$a->strings["On"] = "Funcionant"; +$a->strings["Additional Features"] = "Característiques Addicionals"; +$a->strings["Connector Settings"] = "Ajustos de Connector"; +$a->strings["No special theme for mobile devices"] = "No emprar tema especial per aparells mòbils"; +$a->strings["%s - (Experimental)"] = "%s - (Experimental)"; +$a->strings["Display Settings"] = "Ajustos de Pantalla"; +$a->strings["Theme Settings"] = "Ajustos de Tema"; +$a->strings["Custom Theme Settings"] = "Ajustos Personals de Tema"; +$a->strings["Content Settings"] = "Ajustos de Contingut"; +$a->strings["Display Theme:"] = "Ajustos de Tema:"; +$a->strings["Mobile Theme:"] = "Tema Mòbil:"; +$a->strings["Enable user zoom on mobile devices"] = "Zoom d'usuari en dispositius mòbils"; +$a->strings["Update browser every xx seconds"] = "Actualitza el navegador cada xx segons"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Mínim de 10 segons, sense màxim"; +$a->strings["Maximum number of conversations to load at any time:"] = "Nombre màxim de conversacions a càrregar cada vegada"; +$a->strings["Maximum of 100 items"] = "Màxim de 100 elements"; +$a->strings["Show emoticons (smilies) as images"] = "Mostra emoticons (smilies) com a imatges"; +$a->strings["Link post titles to source"] = "Enllaça a l'origen els títols de l'entrada"; +$a->strings["System Page Layout Editor - (advanced)"] = "Editor de Disseny de la Pàgina del Sistema - (avançat)"; +$a->strings["Use blog/list mode on channel page"] = "Empra el mode blog/llista a la pàgina del canal"; +$a->strings["(comments displayed separately)"] = "(Observacions es mostren per separat)"; +$a->strings["Use blog/list mode on matrix page"] = "Empra mode blog/llista a la pàgina de matrix"; +$a->strings["Channel page max height of content (in pixels)"] = "Alçada màxima de contingut (en píxels) de la pàgina de Canal"; +$a->strings["click to expand content exceeding this height"] = "Clic per expandir el contingut que excedeixi aquesta alçada"; +$a->strings["Matrix page max height of content (in pixels)"] = "Alçada màxima del contingut (en píxels) de la pàgina Matrix"; +$a->strings["Nobody except yourself"] = "Ningú excepte tú"; +$a->strings["Only those you specifically allow"] = "Només allò que específicament permetis"; +$a->strings["Approved connections"] = "Connexions aprovades"; +$a->strings["Any connections"] = "Qualsevol connexió"; +$a->strings["Anybody on this website"] = "Qualsevol en aquest lloc"; +$a->strings["Anybody in this network"] = "Qualsevol en aquesta xarxa"; +$a->strings["Anybody authenticated"] = "Qualsevol autenticat"; +$a->strings["Anybody on the internet"] = "Qualsevol a internet"; +$a->strings["Publish your default profile in the network directory"] = "Publica el teu perfil per defecte al directori de la xarxa"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Ens permets suggerir-te com a potencial amic als nous membres?"; +$a->strings["Your channel address is"] = "La teva direcció del canal es"; +$a->strings["Channel Settings"] = "Ajustos del Canal"; +$a->strings["Basic Settings"] = "Ajustos Bàsics"; +$a->strings["Your Timezone:"] = "La teva Franja Horària"; +$a->strings["Default Post Location:"] = "Localització Predeterminada de les Entrades:"; +$a->strings["Geographical location to display on your posts"] = "Posició geogràfica a mostrar a les teves entrades"; +$a->strings["Use Browser Location:"] = "Empra la Localització del Navegador:"; +$a->strings["Adult Content"] = "Contingut per a Adults"; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = "Aquest canal publica freqúentment o amb regularitat contingut per a adults. (Si us plau, etiqueti qualsevol material per a adults amb #NSFW)"; +$a->strings["Security and Privacy Settings"] = "Ajustos de Seguretat i Privacitat"; +$a->strings["Your permissions are already configured. Click to view/adjust"] = "Els teus permisos estan configurats. Clic per veure/ajustar"; +$a->strings["Hide my online presence"] = "Amaga la meva presencia en línia"; +$a->strings["Prevents displaying in your profile that you are online"] = "Evita mostrar en el teu perfil, que estàs en línia"; +$a->strings["Simple Privacy Settings:"] = "Ajustos simples de privacitat:"; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = "Molt públic - extremadament permissiu (s'ha d'anar en compte)"; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = "Normal - públic per defecte, privat quan es desitgi (similar als permisos de xarxa social, però amb millor privacitat)"; +$a->strings["Private - default private, never open or public"] = "Privat - privat per defecte, mai públic o obert"; +$a->strings["Blocked - default blocked to/from everybody"] = "Bloquejat - tothom bloquejat per defecte"; +$a->strings["Allow others to tag your posts"] = "Permet a altres etiquetar les teves entrades"; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = "Sovint emprat per la comunitat per marcar retroactivament contingut inapropiat"; +$a->strings["Advanced Privacy Settings"] = "Ajustos avançats de privacitat"; +$a->strings["Expire other channel content after this many days"] = "El contingut d'altes canals caduca després d'aquests dies"; +$a->strings["0 or blank prevents expiration"] = "0 o vuit evita caducitat"; +$a->strings["Maximum Friend Requests/Day:"] = "Nombre màxim de peticions d'amistat per dia"; +$a->strings["May reduce spam activity"] = "Pot reduir l'SPAM"; +$a->strings["Default Post Permissions"] = "Permisos de publicació per defecte"; +$a->strings["Channel permissions category:"] = "Categoria de permisos de canal:"; +$a->strings["Maximum private messages per day from unknown people:"] = "Nombre màxim de missatges privats de desconeguts al dia:"; +$a->strings["Useful to reduce spamming"] = "Útil per a reduir l'spam"; +$a->strings["Notification Settings"] = "Ajustos de notificacions"; +$a->strings["By default post a status message when:"] = "Per defecte envia un missatge d'estat quan:"; +$a->strings["accepting a friend request"] = "Acceptar una sol·licitud d'amistat"; +$a->strings["joining a forum/community"] = "Apuntar-se a un fòrum o comunitat"; +$a->strings["making an interesting profile change"] = "faci un canvi interesant al perfil"; +$a->strings["Send a notification email when:"] = "Notifica per correu quan:"; +$a->strings["You receive a connection request"] = "Rebi una petició de connexió"; +$a->strings["Your connections are confirmed"] = "Es confirma una connexió"; +$a->strings["Someone writes on your profile wall"] = "Algú ha escrit al mur del teu perfil"; +$a->strings["Someone writes a followup comment"] = "Algú ha escrit un comentari de resposta"; +$a->strings["You receive a private message"] = "Rebi un missatge privat"; +$a->strings["You receive a friend suggestion"] = "Rebi una suggerència d'amistat"; +$a->strings["You are tagged in a post"] = "Estàs etiquetat a l'entrada"; +$a->strings["You are poked/prodded/etc. in a post"] = "S'enfoten/te piquen/etc. en una entrada"; +$a->strings["Show visual notifications including:"] = "Mostra notificacion visuals, com ara:"; +$a->strings["Unseen matrix activity"] = "Activitat no vista a la xarxa"; +$a->strings["Unseen channel activity"] = "Activitat no vista del canal"; +$a->strings["Unseen private messages"] = "Missatges privats no llegits"; +$a->strings["Recommended"] = "Recomanat"; +$a->strings["Upcoming events"] = "Esdeveniments propers"; +$a->strings["Events today"] = "Esdeveniments d'avui"; +$a->strings["Upcoming birthdays"] = "Aniversaris propers"; +$a->strings["Not available in all themes"] = "No està disponible en tots els temes"; +$a->strings["System (personal) notifications"] = "Notificacions (personals) de sistema"; +$a->strings["System info messages"] = "Missatges d'informació del sistema"; +$a->strings["System critical alerts"] = "Alertes crítiques del sistema"; +$a->strings["New connections"] = "Noves connexions"; +$a->strings["System Registrations"] = "Registres del sistema"; +$a->strings["Also show new wall posts, private messages and connections under Notices"] = "Mostra també les entrades de mur noves, les entrades privades i les connexions a \"Notícies\""; +$a->strings["Notify me of events this many days in advance"] = "Notifica'm dels esdeveniments amb aquests dies d'antelació"; +$a->strings["Must be greater than 0"] = "Ha de ser més gran que 0"; +$a->strings["Advanced Account/Page Type Settings"] = "Ajustos avançats de compte i tipus de pàgina"; +$a->strings["Change the behaviour of this account for special situations"] = "Modifica el comportament d'aquest compte en situacions especials"; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = "Activa el mode d'expert (a Ajustos > Més funcions)"; +$a->strings["Miscellaneous Settings"] = "Ajustos diversos"; +$a->strings["Personal menu to display in your channel pages"] = "Menú personal per mostrar en les teves pàgines de canal"; +$a->strings["Remove Channel"] = "Elimina el canal"; +$a->strings["Remove this channel."] = "Elimina aquest canal."; +$a->strings["First Name"] = "Nom"; +$a->strings["Last Name"] = "Cognoms"; +$a->strings["Nickname"] = "Àlies"; +$a->strings["Full Name"] = "Nom Sencer"; +$a->strings["Profile Photo 16px"] = "Foto del Perfil 16px"; +$a->strings["Profile Photo 32px"] = "Foto del Perfil 32px"; +$a->strings["Profile Photo 48px"] = "Foto del Perfil 48px"; +$a->strings["Profile Photo 64px"] = "Foto del Perfil 64px"; +$a->strings["Profile Photo 80px"] = "Foto del Perfil 80px"; +$a->strings["Profile Photo 128px"] = "Foto del Perfil 128px"; +$a->strings["Timezone"] = "Zona horària"; +$a->strings["Homepage URL"] = "URL de la pàgina d'inici"; +$a->strings["Birth Year"] = "Any de Naixement"; +$a->strings["Birth Month"] = "Mes de Naixement"; +$a->strings["Birth Day"] = "Dia de Naixement"; +$a->strings["Birthdate"] = "Aniversari"; +$a->strings["Conversation removed."] = "Conversació eliminada."; +$a->strings["No messages."] = "Sense missatges."; +$a->strings["Delete conversation"] = "Conversació esborrada"; +$a->strings["D, d M Y - g:i A"] = "D, d M Y - g:i A"; +$a->strings["Set your current mood and tell your friends"] = "Estableix el teu estat d'ànim actual i digues-li als teus amics"; +$a->strings["Total votes"] = "Total de vots"; +$a->strings["Average Rating"] = "Valoració Mitja"; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "L'esborrat de canals no està permès fins que transcorren 48 hores des de l'últim canvi de contrasenya."; +$a->strings["Remove This Channel"] = "Elimina Aquest Canal"; +$a->strings["This channel will be completely removed from the network. "] = "Aquest canal serà completament eliminat de la xarxa."; +$a->strings["Remove this channel and all its clones from the network"] = "Elimina aquest canal i els seus clons de la xarxa"; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = "Per defecte, només la instancia del canal ubicat en aquest concentrador pot esser esborrat de la xarxa"; +$a->strings["is now connected to"] = "Ara està conectat amb"; +$a->strings["Could not access address book record."] = "No puc accedir al registre del contacte"; +$a->strings["Refresh failed - channel is currently unavailable."] = "Ha fallat la recàrrega - el canal es actualment inaccesible."; +$a->strings["Unable to set address book parameters."] = "No es poden ajustar els paràmetres dels contactes."; +$a->strings["Connection has been removed."] = "S'han eliminat les conexions."; +$a->strings["View %s's profile"] = "Mostra el perfil de %s"; +$a->strings["Refresh Permissions"] = "Recarrega els Permissos"; +$a->strings["Fetch updated permissions"] = "Obté els permisos actualitzats"; +$a->strings["Recent Activity"] = "Activitat Recent"; +$a->strings["View recent posts and comments"] = "Mostra les entrades i comentaris recents"; +$a->strings["Block (or Unblock) all communications with this connection"] = "Boqueja (o Desbloqueja) les comunicacions amb aquesta connexió"; +$a->strings["This connection is blocked!"] = "Aquesta connexió està bloquejada!"; +$a->strings["Unignore"] = "Inhabilita"; +$a->strings["Ignore"] = "Ignora"; +$a->strings["Ignore (or Unignore) all inbound communications from this connection"] = "Ignora (o Considera) les communicacions entrants d'aquesta connexió"; +$a->strings["This connection is ignored!"] = "Aquesta connexió es ignorada!"; +$a->strings["Unarchive"] = "Desarxiva"; +$a->strings["Archive"] = "Arxiva"; +$a->strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = "Arxiva (o Desarxiva) aquesta connexió - Marca el canal com a mort pero manté el contingut "; +$a->strings["This connection is archived!"] = "Aquesta connexió està arxivada!"; +$a->strings["Unhide"] = "Mostra"; +$a->strings["Hide"] = "Amaga"; +$a->strings["Hide or Unhide this connection from your other connections"] = "Amaga (o Mostra) aquesta connexió de les altres connexions teves"; +$a->strings["This connection is hidden!"] = "Aquesta connexió està amagada!"; +$a->strings["Delete this connection"] = "Elimina aquesta connexió"; +$a->strings["Approve this connection"] = "Apccepta aquesta connexió"; +$a->strings["Accept connection to allow communication"] = "Accepta la connexió per permetre la comunicació"; +$a->strings["Set Affinity"] = "Ajusta l'Afinitat"; +$a->strings["Set Profile"] = "Ajusta el Perfil"; +$a->strings["Set Affinity & Profile"] = "Ajusta Afinitat i Perfil"; +$a->strings["Apply these permissions automatically"] = "Aplica aquests permissos automaticament"; +$a->strings["This connection's address is"] = "La direcció d'aquesta connexió es"; +$a->strings["The permissions indicated on this page will be applied to all new connections."] = "Els permisos indicats en aquesta pàgina seran aplicats a totes les noves connexions."; +$a->strings["Slide to adjust your degree of friendship"] = "Llisca per ajustar el nivell d'amistat"; +$a->strings["Slide to adjust your rating"] = "Llisca per ajustar la valoració"; +$a->strings["Optionally explain your rating"] = "Opcionalment pots explicar la teva valoració"; +$a->strings["Custom Filter"] = "Filtre a mida"; +$a->strings["Only import posts with this text"] = "Importa exclusivament entrades amb aquest text"; +$a->strings["words one per line or #tags or /patterns/, leave blank to import all posts"] = "paraules una per línia o #etiquetes o /patrons/, deixar en blanc per importar totes les entrades"; +$a->strings["Do not import posts with this text"] = "No importar entrades amb aquest text"; +$a->strings["This information is public!"] = "Aquesta informació es pública!"; +$a->strings["Connection Pending Approval"] = "Connexió Pendent d'Aprovació"; +$a->strings["Connection Request"] = "Petició de Connexió"; +$a->strings["(%s) would like to connect with you. Please approve this connection to allow communication."] = "(%s) voldria conectar amb tu. Aprova aquesta connexió per permetre la connexió."; +$a->strings["Approve Later"] = "Aprovar més tard"; +$a->strings["inherited"] = "heretat"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Tria el perfil que vols mostrar a %s quan es vegi el perfil segur."; +$a->strings["Their Settings"] = "Els seus Ajustos"; +$a->strings["My Settings"] = "Els Meus Ajustos"; +$a->strings["Individual Permissions"] = "Permisos Individuals"; +$a->strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can not change those settings here."] = "Alguns permisos poden ser heretats dels teus canals ajustos de privacitat, Els quals tenen més prioritat que els ajustos individuals. No pots canviar aquests ajustos aquí."; +$a->strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes."] = "Alguns permisos poden ser heretats dels teus canals ajustos de privacitat, Els quals tenen més prioritat que els ajustos individuals. Pots canviar aquests ajustos aquí pero no tindran cap impacte fins que no canviis els ajustos heretats."; +$a->strings["Last update:"] = "Darrera actualització:"; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Em trobat un problema durant l'inici de sessió amb el OpenID que has facilitat. verifica l'ortografia correcta de la ID."; +$a->strings["The error message was:"] = "El missatge d'error fou:"; +$a->strings["Authentication failed."] = "Ha fallat l'autentificació."; +$a->strings["Remote Authentication"] = "Autentificació Remota"; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Introdueix la teva adreça del canal (eg canal@exemple.com)"; +$a->strings["Authenticate"] = "Autentica't"; +$a->strings["Unable to lookup recipient."] = "Incapaç de trobar el destinatari."; +$a->strings["Unable to communicate with requested channel."] = "Incapaç de comunicar amb el canal demanat."; +$a->strings["Cannot verify requested channel."] = "No puc verificar el canal demanat."; +$a->strings["Selected channel has private message restrictions. Send failed."] = "El canal seleccionat te restriccions sobre els missatges privats. L'enviament ha fallat."; +$a->strings["Message deleted."] = "Missatge eliminat."; +$a->strings["Message recalled."] = "Recupera el missatge."; +$a->strings["Send Private Message"] = "Envia Missatge Privat"; +$a->strings["To:"] = "Per:"; +$a->strings["Subject:"] = "Assumpte:"; +$a->strings["Send"] = "Envia"; +$a->strings["Message not found."] = "Missatge no trobat."; +$a->strings["Delete message"] = "Elimina el missatge"; +$a->strings["Recall message"] = "Recupera el missatge"; +$a->strings["Message has been recalled."] = "El missatge s'ha recuperat."; +$a->strings["Private Conversation"] = "Conversació Privada"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Comunicació segura no disponible. Pots respondre des de la pàgina de perfil del remitent."; +$a->strings["Send Reply"] = "Envia Resposta"; +$a->strings["Invalid request identifier."] = "Sol·licitud d'identificació invàlida."; +$a->strings["Discard"] = "Descarta"; +$a->strings["Please login."] = "Inicia Sessió."; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "Autenticació remota bloquejada. Ha iniciat sessió en aquest lloc a nivell local. Si us plau, tanca la sessió i torna-ho a intentar."; +$a->strings["Add a Channel"] = "Afegeix un Canal"; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = "Un canal es la teva pròpia col·lecció de pàgines web. Un canal pot emprat per mantenir perfils a una xarxa social, blocs, grups de conversació, fòrums, pàgines de famosos, i molt més. Pots crear tants canals com el teu servei d'internet et permeti."; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = "Exemples: \"Joan Tou\", \"Manel i els seus esquirols\", \"Fútbol\", \"Grup de Gegants\""; +$a->strings["Choose a short nickname"] = "Tria un àlies curt"; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "El teu àlies es pot emprar per crear un canal fàcilment memoritzatble (com una adreça de correu electrònic) que pot ser compartit amb altres."; +$a->strings["Or import an existing channel from another location"] = "O importa un canal existent d'un altre lloc"; +$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = "Tria un tipus de canal (com a xarxa social o fòrum comunitari) i els requisits de privacitat, així podem proposar el que te el permisos més adients."; +$a->strings["Channel Type"] = "tipus de Canal"; +$a->strings["Read more about roles"] = "Llegix més sobre els rols"; +$a->strings["App installed."] = "Aplicació instal·lada."; +$a->strings["Malformed app."] = "Aplicació amb errors"; +$a->strings["Embed code"] = "Codi embegut"; +$a->strings["Edit App"] = "Edita l'Aplicació"; +$a->strings["Create App"] = "Crea l'Aplicació"; +$a->strings["Name of app"] = "Nom de l'Aplicació"; +$a->strings["Location (URL) of app"] = "Ubicació (URL) de l'aplicació"; +$a->strings["Photo icon URL"] = "Foto icona URL"; +$a->strings["80 x 80 pixels - optional"] = "80 x 80 pixels - opcional"; +$a->strings["Version ID"] = "Versió ID"; +$a->strings["Price of app"] = "Preu de l'aplicació"; +$a->strings["Location (URL) to purchase app"] = "Ubicació (URL) per comprar l'aplicació"; +$a->strings["sent you a private message"] = "Se t'ha enviat un missatge privat"; +$a->strings["added your channel"] = "el teu canal s'ha afegit"; +$a->strings["posted an event"] = "enviat un event"; +$a->strings["Comanche page description language help"] = "Pgina d'ajuda del llenguatge Comanche"; +$a->strings["Layout Description"] = "Descripció del Disseny de la Pàgina"; +$a->strings["Download PDL file"] = "Descarrega l'arxiu PDL"; +$a->strings["Welcome to %s"] = "Benvingut a %s"; +$a->strings["Lorem Ipsum"] = "Lorem Ipsum"; +$a->strings["Bookmark added"] = "Favorit afegit"; +$a->strings["My Bookmarks"] = "Els Meus Favorits"; +$a->strings["My Connections Bookmarks"] = "Les connexions dels meus Favorits"; +$a->strings["Insufficient permissions. Request redirected to profile page."] = "Permisos insuficients. Petició redirigida a la pàgina del perfil."; +$a->strings["This setting requires special processing and editing has been blocked."] = "Aquest ajust requereix un procés espedial i l'edició esta bloquejada."; +$a->strings["Configuration Editor"] = "Editor de Configuració"; +$a->strings["Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature."] = "atenció: Realitzar segons quins ajustos pot fer el canal inoperable. Deixa aquesta pàgina si no estas segur i tens suficients coneixements sobre l'ús correcte d'aquesta característica."; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "No hi ha suggerencies. Si es un lloc nou, espera 24 hores i proba de nou."; +$a->strings["Poll"] = "Sondeija"; +$a->strings["View Results"] = "Mostra els Resultats"; +$a->strings["No service class restrictions found."] = "No s'han trobat restriccions de clase."; +$a->strings["Files: shared with me"] = "Arxius: compartits amb jo"; +$a->strings["NEW"] = "NOU"; +$a->strings["Remove all files"] = "Esborra tots els arxius"; +$a->strings["Remove this file"] = "Esborra l'arxiu"; +$a->strings["Schema Default"] = "Esquema Predeterminat"; +$a->strings["Sans-Serif"] = "Sans-Serif"; +$a->strings["Monospace"] = "Monospace"; +$a->strings["Theme settings"] = "Ajustos de tema"; +$a->strings["Set scheme"] = "Ajustos d'esquema"; +$a->strings["Set font-size for posts and comments"] = "Ajusta la mida del tipus de lletra per a entrades i comentaris"; +$a->strings["Set font face"] = "Ajusta el tipus de lletra"; +$a->strings["Set iconset"] = "Ajusta el conjunt d'icones"; +$a->strings["Set big shadow size, default 15px 15px 15px"] = "Ajusta la mida gran de l'ombra, predeterminat a 15px 15px 15px"; +$a->strings["Set small shadow size, default 5px 5px 5px"] = "Ajusta la mida petita de l'ombra, predeterminat a 5px 5px 5px"; +$a->strings["Set shadow color, default #000"] = "Ajusta el color de l'ombra, predeterminat a #000"; +$a->strings["Set radius size, default 5px"] = "Ajusta la mida del radi, predeterminat a 5px"; +$a->strings["Set line-height for posts and comments"] = "Ajusta el gruix de línia per entrades i comentaris"; +$a->strings["Set background image"] = "Ajusta l'imatge de fons"; +$a->strings["Set background attachment"] = "Ajusta els adjunts en segon pla"; +$a->strings["Set background color"] = "Ajusta el color en segon pla"; +$a->strings["Set section background image"] = "Ajusta la secció d'imatge en segon pla"; +$a->strings["Set section background color"] = "Ajusta el color de la secció en segon pla"; +$a->strings["Set color of items - use hex"] = "Ajuste el color dels articles - empra codi hexadecimal"; +$a->strings["Set color of links - use hex"] = "ajusta el color dels enlaços - empra codi hexadecimal"; +$a->strings["Set max-width for items. Default 400px"] = "Ajusta l'amplada màxima dels articles. Predeterminat a 400px"; +$a->strings["Set min-width for items. Default 240px"] = "Ajusta l'amplada minima dels articles. Predeterminat a 240px"; +$a->strings["Set the generic content wrapper width. Default 48%"] = "Ajusta l'amplada de l'embolcall del contingut genèric. Predeterminat a 48%"; +$a->strings["Set color of fonts - use hex"] = "Ajusta el color del tipus de lletra - empra codi hexadecimal"; +$a->strings["Set background-size element"] = "Ajusta la mida de l'element en segon pla"; +$a->strings["Item opacity"] = "Opacitat de l'article"; +$a->strings["Display post previews only"] = "Mostra tan sols les previsualitzacions de les entrades"; +$a->strings["Display side bar on channel page"] = "Mostra la barra lateral a la pàgina del canal"; +$a->strings["Colour of the navigation bar"] = "Color de la barra de navegació"; +$a->strings["Item float"] = "Article flotant"; +$a->strings["Left offset of the section element"] = "Desplaçament esquerra de l'element de secció"; +$a->strings["Right offset of the section element"] = "Desplaçament dret de l'element de secció"; +$a->strings["Section width"] = "Amplada de la secció"; +$a->strings["Left offset of the aside"] = "Desplaçament esquerra del costat"; +$a->strings["Right offset of the aside element"] = "Desplaçament dret de l'element del costat"; +$a->strings["Light (Red Matrix default)"] = "Clar (predeterminat)"; +$a->strings["Select scheme"] = "Tria esquema"; +$a->strings["Narrow navbar"] = "Barra de navegació estreta"; +$a->strings["Navigation bar background color"] = "Color de fons de la barra de navegació"; +$a->strings["Navigation bar gradient top color"] = "Gradient de color de la part superior de la barra de navegació"; +$a->strings["Navigation bar gradient bottom color"] = "Gradient de color de la part inferior de la barra de navegació"; +$a->strings["Navigation active button gradient top color"] = "Gradient de color de la part superior del botó actiu de la barra de navegació"; +$a->strings["Navigation active button gradient bottom color"] = "Gradient de color de la part inferior del botó actiu de la barra de navegació"; +$a->strings["Navigation bar border color "] = "Color de la barra de navegació"; +$a->strings["Navigation bar icon color "] = "Color de la icona de la barra de navegació"; +$a->strings["Navigation bar active icon color "] = "Color de la icona de la barra de navegació activa"; +$a->strings["link color"] = "Color d'enllaç"; +$a->strings["Set font-color for banner"] = "Ajusta el color del tipus de lletra per la senyera"; +$a->strings["Set the background color"] = "Ajusta el color de fons"; +$a->strings["Set the background image"] = "Ajusta la imatge de fons"; +$a->strings["Set the background color of items"] = "ajusta el color dels articles de fons"; +$a->strings["Set the background color of comments"] = "Ajusta el color dels comentaris en segon pla"; +$a->strings["Set the border color of comments"] = "Canviar el color del marge dels comentaris"; +$a->strings["Set the indent for comments"] = "ajusta l'indentació dels comentaris"; +$a->strings["Set the basic color for item icons"] = "ajusta el color basic per les icones dels articles"; +$a->strings["Set the hover color for item icons"] = "Ajusta el color de la libració de les icones dels articles"; +$a->strings["Set font-size for the entire application"] = "Ajusta la mida del tipus de lletra per tota l'aplicació"; +$a->strings["Example: 14px"] = "Exemple: 14px"; +$a->strings["Set font-color for posts and comments"] = "Ajusta el color del tipus de lletra per entrades i comentaris"; +$a->strings["Set radius of corners"] = "Ajusta el radi de les cantonades"; +$a->strings["Set shadow depth of photos"] = "Ajusta la profunditat d'ombres de les fotos"; +$a->strings["Set maximum width of content region in pixel"] = "Ajusta l'amplada màxima de la zona de contingut en pixels"; +$a->strings["Leave empty for default width"] = "Deixa en blanc per l'amplada predeterminada"; +$a->strings["Center page content"] = "Contingut del centre de la pàgina"; +$a->strings["Set minimum opacity of nav bar - to hide it"] = "Ajusta la opacitat mínima de la harra de navegació - per amagar-la"; +$a->strings["Set size of conversation author photo"] = "Ajusta la mida de la foto del autor a la conversa"; +$a->strings["Set size of followup author photos"] = "Ajusta la mida del seguidor de les fotos de l'autor"; +$a->strings["Update %s failed. See error logs."] = "L'actualització %s ha fallat. Mira el registre d'errors."; +$a->strings["Update Error at %s"] = "Error d'Actualització a %s"; +$a->strings["Create an account to access services and applications within the Red Matrix"] = "Crea un compte per accedir als serveis i aplicacions dins de RedMatrix"; +$a->strings["Password"] = "Contrasenya"; +$a->strings["Remember me"] = "Recorda'm"; +$a->strings["Forgot your password?"] = "Has perdut la Contrasenya?"; +$a->strings["toggle mobile"] = "canvia a format per a mòbils"; +$a->strings["Website SSL certificate is not valid. Please correct."] = "El certificat SSL és invalid, soluciona-ho, si us plau."; +$a->strings["[red] Website SSL error for %s"] = "[red] Error de SSL per la web %s"; +$a->strings["Cron/Scheduled tasks not running."] = "No s'estan executan les tasques programades al cron."; +$a->strings["[red] Cron tasks not running on %s"] = "[red] No s'estan executan les tasques programades del cron a %s"; diff --git a/sources/view/cs/htconfig.tpl b/sources/view/cs/htconfig.tpl new file mode 100644 index 00000000..cc4087f9 --- /dev/null +++ b/sources/view/cs/htconfig.tpl @@ -0,0 +1,70 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// Maximum size of an imported message, 0 is unlimited + +$a->config['system']['max_import_size'] = 200000; + +// maximum size of uploaded photos + +$a->config['system']['maximagesize'] = 8000000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + diff --git a/sources/view/cs/lostpass_eml.tpl b/sources/view/cs/lostpass_eml.tpl new file mode 100644 index 00000000..3b79d279 --- /dev/null +++ b/sources/view/cs/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Dear {{$username}}, + A request was recently received at {{$sitename}} to reset your account +password. In order to confirm this request, please select the verification link +below or paste it into your web browser address bar. + +If you did NOT request this change, please DO NOT follow the link +provided and ignore and/or delete this email. + +Your password will not be changed unless we can verify that you +issued this request. + +Follow this link to verify your identity: + +{{$reset_link}} + +You will then receive a follow-up message containing the new password. + +You may change that password from your account settings page after logging in. + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + + + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/cs/messages.po b/sources/view/cs/messages.po new file mode 100644 index 00000000..8e5b54d3 --- /dev/null +++ b/sources/view/cs/messages.po @@ -0,0 +1,4618 @@ +# FRIENDICA Distributed Social Network +# Copyright (C) 2010, 2011 Mike Macgirvin +# This file is distributed under the same license as the Friendika package. +# +# Michal Å upler , 2011. +msgid "" +msgstr "" +"Project-Id-Version: friendika\n" +"Report-Msgid-Bugs-To: http://bugs.friendika.com/\n" +"POT-Creation-Date: 2011-08-14 21:17-0700\n" +"PO-Revision-Date: 2011-09-03 04:29+0000\n" +"Last-Translator: michal_s \n" +"Language-Team: Czech (http://www.transifex.net/projects/p/friendika/team/cs/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: cs\n" +"Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2\n" + +#: ../../mod/oexchange.php:27 +msgid "Post successful." +msgstr "PříspÄ›vek úspěšnÄ› odeslán" + +#: ../../mod/crepair.php:42 +msgid "Contact settings applied." +msgstr "Nastavení kontaktu zmÄ›nÄ›no" + +#: ../../mod/crepair.php:44 +msgid "Contact update failed." +msgstr "Aktualizace kontaktu selhala." + +#: ../../mod/crepair.php:54 ../../mod/wall_attach.php:43 +#: ../../mod/fsuggest.php:78 ../../mod/events.php:102 ../../mod/photos.php:122 +#: ../../mod/photos.php:849 ../../mod/editpost.php:10 ../../mod/install.php:96 +#: ../../mod/notifications.php:62 ../../mod/contacts.php:132 +#: ../../mod/settings.php:41 ../../mod/settings.php:46 +#: ../../mod/settings.php:305 ../../mod/manage.php:75 ../../mod/network.php:6 +#: ../../mod/notes.php:20 ../../mod/attach.php:33 ../../mod/group.php:19 +#: ../../mod/viewconnections.php:21 ../../mod/register.php:27 +#: ../../mod/regmod.php:111 ../../mod/item.php:110 +#: ../../mod/profile_photo.php:19 ../../mod/profile_photo.php:133 +#: ../../mod/profile_photo.php:144 ../../mod/profile_photo.php:155 +#: ../../mod/message.php:8 ../../mod/message.php:116 ../../mod/admin.php:10 +#: ../../mod/wall_upload.php:42 ../../mod/follow.php:8 +#: ../../mod/display.php:108 ../../mod/profiles.php:7 +#: ../../mod/profiles.php:226 ../../mod/invite.php:13 ../../mod/invite.php:81 +#: ../../mod/dfrn_confirm.php:53 ../../addon/facebook/facebook.php:308 +#: ../../include/items.php:1930 ../../index.php:266 +msgid "Permission denied." +msgstr "Přístup odmítnut." + +#: ../../mod/crepair.php:68 ../../mod/fsuggest.php:20 +#: ../../mod/fsuggest.php:92 ../../mod/contacts.php:240 +#: ../../mod/dfrn_confirm.php:114 +msgid "Contact not found." +msgstr "Kontakt nenalezen." + +#: ../../mod/crepair.php:74 +msgid "Repair Contact Settings" +msgstr "Opravit nastavení kontaktu" + +#: ../../mod/crepair.php:76 +msgid "" +"WARNING: This is highly advanced and if you enter incorrect" +" information your communications with this contact will stop working." +msgstr "" +"VAROVÃNÃ: Toto je velmi pokroÄilé nastavení, pokud zadáte " +"nesprávné informace, komunikace s tímto kontaktem pÅ™estane fungovat." + +#: ../../mod/crepair.php:77 +msgid "" +"Please use your browser 'Back' button now if you are " +"uncertain what to do on this page." +msgstr "" +"Prosím použijte ihned v prohlížeÄi tlaÄítko \"zpÄ›t\" pokud " +"si nejste jistí co dÄ›lat na této stránce." + +#: ../../mod/crepair.php:85 ../../mod/admin.php:464 ../../mod/admin.php:473 +msgid "Name" +msgstr "Jméno" + +#: ../../mod/crepair.php:86 +msgid "Account Nickname" +msgstr "PÅ™ezdívka úÄtu" + +#: ../../mod/crepair.php:87 +msgid "Account URL" +msgstr "URL adresa úÄtu" + +#: ../../mod/crepair.php:88 +msgid "Friend Request URL" +msgstr "Žádost o přátelství URL" + +#: ../../mod/crepair.php:89 +msgid "Friend Confirm URL" +msgstr "URL adresa potvrzení přátelství" + +#: ../../mod/crepair.php:90 +msgid "Notification Endpoint URL" +msgstr "NotifikaÄní URL adresa" + +#: ../../mod/crepair.php:91 +msgid "Poll/Feed URL" +msgstr "Poll/Feed URL adresa" + +#: ../../mod/crepair.php:100 ../../mod/fsuggest.php:107 +#: ../../mod/events.php:333 ../../mod/photos.php:877 ../../mod/photos.php:934 +#: ../../mod/photos.php:1144 ../../mod/photos.php:1184 +#: ../../mod/photos.php:1223 ../../mod/photos.php:1254 +#: ../../mod/install.php:137 ../../mod/contacts.php:296 +#: ../../mod/settings.php:482 ../../mod/manage.php:106 ../../mod/group.php:84 +#: ../../mod/group.php:167 ../../mod/admin.php:298 ../../mod/admin.php:461 +#: ../../mod/admin.php:587 ../../mod/admin.php:652 ../../mod/profiles.php:372 +#: ../../mod/invite.php:106 ../../addon/facebook/facebook.php:366 +#: ../../addon/randplace/randplace.php:178 +#: ../../addon/impressum/impressum.php:69 ../../addon/oembed/oembed.php:41 +#: ../../addon/statusnet/statusnet.php:274 +#: ../../addon/statusnet/statusnet.php:288 +#: ../../addon/statusnet/statusnet.php:314 +#: ../../addon/statusnet/statusnet.php:321 +#: ../../addon/statusnet/statusnet.php:343 +#: ../../addon/statusnet/statusnet.php:468 ../../addon/piwik/piwik.php:76 +#: ../../addon/twitter/twitter.php:171 ../../addon/twitter/twitter.php:194 +#: ../../addon/twitter/twitter.php:280 ../../include/conversation.php:409 +msgid "Submit" +msgstr "Odeslat" + +#: ../../mod/help.php:27 +msgid "Help:" +msgstr "NápovÄ›da:" + +#: ../../mod/help.php:31 ../../include/nav.php:64 +msgid "Help" +msgstr "NápovÄ›da" + +#: ../../mod/wall_attach.php:57 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Velikost souboru pÅ™esáhla limit %d" + +#: ../../mod/wall_attach.php:87 ../../mod/wall_attach.php:98 +msgid "File upload failed." +msgstr "Nahrání souboru se nezdaÅ™ilo." + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Návrhy přátelství odeslány " + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "NavrhnÄ›te přátelé" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "NavrhnÄ›te přátelé pro uživatele %s" + +#: ../../mod/events.php:112 ../../mod/photos.php:834 ../../mod/notes.php:46 +#: ../../mod/profile.php:116 +msgid "Status" +msgstr "Stav" + +#: ../../mod/events.php:113 ../../mod/photos.php:835 ../../mod/notes.php:47 +#: ../../mod/profperm.php:103 ../../mod/profile.php:117 +#: ../../include/profile_advanced.php:7 +msgid "Profile" +msgstr "Profil" + +#: ../../mod/events.php:114 ../../mod/photos.php:836 ../../mod/notes.php:48 +#: ../../mod/profile.php:118 +msgid "Photos" +msgstr "Fotografie" + +#: ../../mod/events.php:115 ../../mod/events.php:120 ../../mod/photos.php:837 +#: ../../mod/notes.php:49 ../../mod/profile.php:119 +msgid "Events" +msgstr "Události" + +#: ../../mod/events.php:116 ../../mod/photos.php:838 ../../mod/notes.php:50 +#: ../../mod/notes.php:55 ../../mod/profile.php:120 +msgid "Personal Notes" +msgstr "Osobní poznámky" + +#: ../../mod/events.php:210 +msgid "Create New Event" +msgstr "VytvoÅ™it novou událost" + +#: ../../mod/events.php:213 +msgid "Previous" +msgstr "PÅ™edchozí" + +#: ../../mod/events.php:216 +msgid "Next" +msgstr "Následující" + +#: ../../mod/events.php:223 +msgid "l, F j" +msgstr "l, F j" + +#: ../../mod/events.php:235 +msgid "Edit event" +msgstr "Editovat událost" + +#: ../../mod/events.php:237 ../../include/text.php:846 +msgid "link to source" +msgstr "odkaz na zdroj" + +#: ../../mod/events.php:305 +msgid "hour:minute" +msgstr "hodina:minuta" + +#: ../../mod/events.php:314 +msgid "Event details" +msgstr "Detaily události" + +#: ../../mod/events.php:315 +#, php-format +msgid "Format is %s %s. Starting date and Description are required." +msgstr "Formát je %s %s. Datum zahájení a popis jsou povinné." + +#: ../../mod/events.php:316 +msgid "Event Starts:" +msgstr "Událost zaÄíná:" + +#: ../../mod/events.php:319 +msgid "Finish date/time is not known or not relevant" +msgstr "Datum/Äas konce není zadán nebo není relevantní" + +#: ../../mod/events.php:321 +msgid "Event Finishes:" +msgstr "Akce konÄí:" + +#: ../../mod/events.php:324 +msgid "Adjust for viewer timezone" +msgstr "Nastavit Äasové pásmo pro uživatele s právem pro Ätení" + +#: ../../mod/events.php:326 +msgid "Description:" +msgstr "Popis:" + +#: ../../mod/events.php:328 ../../include/event.php:37 ../../boot.php:868 +msgid "Location:" +msgstr "Místo:" + +#: ../../mod/events.php:330 +msgid "Share this event" +msgstr "Sdílet tuto událost" + +#: ../../mod/tagrm.php:11 ../../mod/tagrm.php:94 +#: ../../mod/dfrn_request.php:644 ../../addon/js_upload/js_upload.php:45 +msgid "Cancel" +msgstr "ZruÅ¡it" + +#: ../../mod/tagrm.php:41 +msgid "Tag removed" +msgstr "Å títek odstranÄ›n" + +#: ../../mod/tagrm.php:79 +msgid "Remove Item Tag" +msgstr "Odebrat Å¡títek položky" + +#: ../../mod/tagrm.php:81 +msgid "Select a tag to remove: " +msgstr "Vyberte Å¡títek k odebrání:" + +#: ../../mod/tagrm.php:93 +msgid "Remove" +msgstr "Odstranit" + +#: ../../mod/dfrn_poll.php:90 ../../mod/dfrn_poll.php:516 +#, php-format +msgid "%s welcomes %s" +msgstr "%s vítá %s " + +#: ../../mod/photos.php:37 +msgid "Photo Albums" +msgstr "Fotoalba" + +#: ../../mod/photos.php:45 ../../mod/photos.php:143 ../../mod/photos.php:857 +#: ../../mod/photos.php:926 ../../mod/photos.php:941 ../../mod/photos.php:1332 +#: ../../mod/photos.php:1344 +msgid "Contact Photos" +msgstr "Fotogalerie kontaktu" + +#: ../../mod/photos.php:57 ../../mod/settings.php:9 +msgid "everybody" +msgstr "Žádost o pÅ™ipojení selhala nebo byla zruÅ¡ena." + +#: ../../mod/photos.php:132 +msgid "Contact information unavailable" +msgstr "Kontakt byl zablokován" + +#: ../../mod/photos.php:143 ../../mod/photos.php:577 ../../mod/photos.php:926 +#: ../../mod/photos.php:941 ../../mod/register.php:316 +#: ../../mod/register.php:323 ../../mod/register.php:330 +#: ../../mod/profile_photo.php:58 ../../mod/profile_photo.php:65 +#: ../../mod/profile_photo.php:72 ../../mod/profile_photo.php:160 +#: ../../mod/profile_photo.php:236 ../../mod/profile_photo.php:245 +msgid "Profile Photos" +msgstr "Profilové fotografie" + +#: ../../mod/photos.php:153 +msgid "Album not found." +msgstr "Album nenalezeno." + +#: ../../mod/photos.php:171 ../../mod/photos.php:935 +msgid "Delete Album" +msgstr "Smazat album" + +#: ../../mod/photos.php:234 ../../mod/photos.php:1145 +msgid "Delete Photo" +msgstr "Smazat fotografii" + +#: ../../mod/photos.php:508 +msgid "was tagged in a" +msgstr "Å¡títek byl pÅ™idán v" + +#: ../../mod/photos.php:508 ../../mod/like.php:110 +#: ../../include/diaspora.php:446 ../../include/conversation.php:31 +msgid "photo" +msgstr "fotografie" + +#: ../../mod/photos.php:508 +msgid "by" +msgstr "od" + +#: ../../mod/photos.php:608 ../../addon/js_upload/js_upload.php:310 +msgid "Image exceeds size limit of " +msgstr "Velikost obrázku pÅ™ekraÄuje limit velikosti" + +#: ../../mod/photos.php:616 +msgid "Image file is empty." +msgstr "Soubor obrázku je prázdný." + +#: ../../mod/photos.php:630 ../../mod/profile_photo.php:118 +#: ../../mod/wall_upload.php:65 +msgid "Unable to process image." +msgstr "Obrázek není možné zprocesovat" + +#: ../../mod/photos.php:650 ../../mod/profile_photo.php:241 +#: ../../mod/wall_upload.php:84 +msgid "Image upload failed." +msgstr "Nahrání obrázku selhalo." + +#: ../../mod/photos.php:733 ../../mod/community.php:9 +#: ../../mod/dfrn_request.php:591 ../../mod/viewconnections.php:16 +#: ../../mod/display.php:7 ../../mod/search.php:13 ../../mod/directory.php:20 +msgid "Public access denied." +msgstr "VeÅ™ejný přístup odepÅ™en." + +#: ../../mod/photos.php:743 +msgid "No photos selected" +msgstr "Není vybrána žádná fotografie" + +#: ../../mod/photos.php:820 +msgid "Access to this item is restricted." +msgstr "Přístup k této položce je omezen." + +#: ../../mod/photos.php:884 +msgid "Upload Photos" +msgstr "Nahrání fotografií " + +#: ../../mod/photos.php:887 ../../mod/photos.php:930 +msgid "New album name: " +msgstr "Název nového alba:" + +#: ../../mod/photos.php:888 +msgid "or existing album name: " +msgstr "nebo stávající název alba:" + +#: ../../mod/photos.php:890 ../../mod/photos.php:1140 +msgid "Permissions" +msgstr "OprávnÄ›ní:" + +#: ../../mod/photos.php:945 +msgid "Edit Album" +msgstr "Edituj album" + +#: ../../mod/photos.php:955 ../../mod/photos.php:1362 +msgid "View Photo" +msgstr "Zobraz fotografii" + +#: ../../mod/photos.php:984 +msgid "Photo not available" +msgstr "Fotografie není k dispozici" + +#: ../../mod/photos.php:1033 +msgid "Edit photo" +msgstr "Editovat fotografii" + +#: ../../mod/photos.php:1034 +msgid "Use as profile photo" +msgstr "Použít jako profilovou fotografii" + +#: ../../mod/photos.php:1040 ../../include/conversation.php:342 +msgid "Private Message" +msgstr "Soukromá zpráva" + +#: ../../mod/photos.php:1051 +msgid "View Full Size" +msgstr "Zobrazit v plné velikosti" + +#: ../../mod/photos.php:1119 +msgid "Tags: " +msgstr "Å títky:" + +#: ../../mod/photos.php:1122 +msgid "[Remove any tag]" +msgstr "[Odstranit vÅ¡echny Å¡títky]" + +#: ../../mod/photos.php:1133 +msgid "New album name" +msgstr "Nové jméno alba" + +#: ../../mod/photos.php:1136 +msgid "Caption" +msgstr "Titulek" + +#: ../../mod/photos.php:1138 +msgid "Add a Tag" +msgstr "PÅ™idat Å¡títek" + +#: ../../mod/photos.php:1142 +msgid "" +"Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" +msgstr "" +"Příklad: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" + +#: ../../mod/photos.php:1162 ../../include/conversation.php:390 +msgid "I like this (toggle)" +msgstr "Líbí se mi to (pÅ™epínaÄ)" + +#: ../../mod/photos.php:1163 ../../include/conversation.php:391 +msgid "I don't like this (toggle)" +msgstr "Nelíbí se mi to (pÅ™epínaÄ)" + +#: ../../mod/photos.php:1164 ../../include/conversation.php:392 +#: ../../include/conversation.php:746 +msgid "Share" +msgstr "Sdílet" + +#: ../../mod/photos.php:1165 ../../mod/editpost.php:99 +#: ../../mod/message.php:190 ../../mod/message.php:324 +#: ../../include/conversation.php:393 ../../include/conversation.php:756 +msgid "Please wait" +msgstr "ÄŒekejte prosím" + +#: ../../mod/photos.php:1181 ../../mod/photos.php:1220 +#: ../../mod/photos.php:1251 ../../include/conversation.php:406 +msgid "This is you" +msgstr "To je Vy" + +#: ../../mod/photos.php:1183 ../../mod/photos.php:1222 +#: ../../mod/photos.php:1253 ../../include/conversation.php:408 +#: ../../boot.php:411 +msgid "Comment" +msgstr "Okomentovat" + +#: ../../mod/photos.php:1281 ../../mod/group.php:154 ../../mod/admin.php:468 +#: ../../include/conversation.php:427 +msgid "Delete" +msgstr "Odstranit" + +#: ../../mod/photos.php:1349 +msgid "Recent Photos" +msgstr "Aktuální fotografie" + +#: ../../mod/photos.php:1353 +msgid "Upload New Photos" +msgstr "Nahrát nové fotografie" + +#: ../../mod/photos.php:1366 +msgid "View Album" +msgstr "Zobrazit album" + +#: ../../mod/community.php:14 +msgid "Not available." +msgstr "Není k dispozici." + +#: ../../mod/community.php:26 ../../include/nav.php:79 +msgid "Community" +msgstr "Komunita" + +#: ../../mod/community.php:56 ../../mod/search.php:65 +msgid "No results." +msgstr "Žádné výsledky." + +#: ../../mod/community.php:83 ../../mod/network.php:302 +#: ../../mod/register.php:504 ../../mod/profile.php:241 +#: ../../mod/display.php:117 +msgid "" +"Shared content is covered by the Creative Commons " +"Attribution 3.0 license." +msgstr "" +"Sdílený obsah je v souladu s Commons Creative " +"3.0 licencí." + +#: ../../mod/editpost.php:17 ../../mod/editpost.php:27 +msgid "Item not found" +msgstr "Položka nenalezena" + +#: ../../mod/editpost.php:32 +msgid "Edit post" +msgstr "Upravit příspÄ›vek" + +#: ../../mod/editpost.php:75 ../../include/conversation.php:732 +msgid "Post to Email" +msgstr "Poslat příspÄ›vek na e-mail" + +#: ../../mod/editpost.php:90 ../../include/group.php:171 +#: ../../include/group.php:172 ../../include/conversation.php:417 +msgid "Edit" +msgstr "Upravit" + +#: ../../mod/editpost.php:91 ../../mod/message.php:188 +#: ../../mod/message.php:322 ../../include/conversation.php:747 +msgid "Upload photo" +msgstr "Nahrát fotografii" + +#: ../../mod/editpost.php:92 ../../include/conversation.php:748 +msgid "Attach file" +msgstr "PÅ™iložit soubor" + +#: ../../mod/editpost.php:93 ../../mod/message.php:189 +#: ../../mod/message.php:323 ../../include/conversation.php:749 +msgid "Insert web link" +msgstr "Vložit webový odkaz" + +#: ../../mod/editpost.php:94 ../../include/conversation.php:750 +msgid "Insert YouTube video" +msgstr "Vložit YouTube video" + +#: ../../mod/editpost.php:95 ../../include/conversation.php:751 +msgid "Insert Vorbis [.ogg] video" +msgstr "Vložit Vorbis [.ogg] video" + +#: ../../mod/editpost.php:96 ../../include/conversation.php:752 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Vložit Vorbis [.ogg] audio" + +#: ../../mod/editpost.php:97 ../../include/conversation.php:753 +msgid "Set your location" +msgstr "Nastavte vaÅ¡i polohu" + +#: ../../mod/editpost.php:98 ../../include/conversation.php:754 +msgid "Clear browser location" +msgstr "Odstranit adresu v prohlížeÄi" + +#: ../../mod/editpost.php:100 ../../include/conversation.php:757 +msgid "Permission settings" +msgstr "Nastavení oprávnÄ›ní" + +#: ../../mod/editpost.php:108 ../../include/conversation.php:765 +msgid "CC: email addresses" +msgstr "skrytá kopie: e-mailové adresy" + +#: ../../mod/editpost.php:109 ../../include/conversation.php:766 +msgid "Public post" +msgstr "VeÅ™ejný příspÄ›vek" + +#: ../../mod/editpost.php:111 ../../include/conversation.php:768 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Příklad: bob@example.com, mary@example.com" + +#: ../../mod/dfrn_request.php:96 +msgid "This introduction has already been accepted." +msgstr "Toto pozvání již bylo pÅ™ijato" + +#: ../../mod/dfrn_request.php:120 ../../mod/dfrn_request.php:351 +msgid "Profile location is not valid or does not contain profile information." +msgstr "Adresa profilu není platná nebo neobsahuje profilové informace" + +#: ../../mod/dfrn_request.php:125 ../../mod/dfrn_request.php:356 +msgid "Warning: profile location has no identifiable owner name." +msgstr "" +"Varování: umístÄ›ní profilu nemá žádné identifikovatelné jméno vlastníka" + +#: ../../mod/dfrn_request.php:127 ../../mod/dfrn_request.php:358 +msgid "Warning: profile location has no profile photo." +msgstr "Varování: umístÄ›ní profilu nemá žádnou profilovou fotografii." + +#: ../../mod/dfrn_request.php:130 ../../mod/dfrn_request.php:361 +#, php-format +msgid "%d required parameter was not found at the given location" +msgid_plural "%d required parameters were not found at the given location" +msgstr[0] "%d požadovaný parametr nebyl nalezen na daném místÄ›" +msgstr[1] "%d požadované parametry nebyly nalezeny na daném místÄ›" +msgstr[2] "%d požadované parametry nebyly nalezeny na daném místÄ›" + +#: ../../mod/dfrn_request.php:168 +msgid "Introduction complete." +msgstr "PÅ™edstavení dokonÄeno." + +#: ../../mod/dfrn_request.php:192 +msgid "Unrecoverable protocol error." +msgstr "Neopravitelná chyba protokolu" + +#: ../../mod/dfrn_request.php:220 +msgid "Profile unavailable." +msgstr "Profil není k dispozici." + +#: ../../mod/dfrn_request.php:245 +#, php-format +msgid "%s has received too many connection requests today." +msgstr "%s dnes obdržel příliÅ¡ mnoho požadavků na pÅ™ipojení." + +#: ../../mod/dfrn_request.php:246 +msgid "Spam protection measures have been invoked." +msgstr "Ochrana proti spamu byla aktivována" + +#: ../../mod/dfrn_request.php:247 +msgid "Friends are advised to please try again in 24 hours." +msgstr "Přátelům se doporuÄuje to zkusit znovu za 24 hodin." + +#: ../../mod/dfrn_request.php:277 +msgid "Invalid locator" +msgstr "Neplatný odkaz" + +#: ../../mod/dfrn_request.php:296 +msgid "Unable to resolve your name at the provided location." +msgstr "NepodaÅ™ilo se zjistit VaÅ¡e jméno na zadané adrese." + +#: ../../mod/dfrn_request.php:309 +msgid "You have already introduced yourself here." +msgstr "Již jste se zde zavedli." + +#: ../../mod/dfrn_request.php:313 +#, php-format +msgid "Apparently you are already friends with %s." +msgstr "ZÅ™ejmÄ› jste již přátelé se %s." + +#: ../../mod/dfrn_request.php:334 +msgid "Invalid profile URL." +msgstr "Neplatné URL profilu." + +#: ../../mod/dfrn_request.php:340 ../../mod/follow.php:20 +msgid "Disallowed profile URL." +msgstr "Nepovolené URL profilu." + +#: ../../mod/dfrn_request.php:406 ../../mod/contacts.php:116 +msgid "Failed to update contact record." +msgstr "NepodaÅ™ilo se aktualizovat kontakt." + +#: ../../mod/dfrn_request.php:427 +msgid "Your introduction has been sent." +msgstr "VaÅ¡e žádost o propojení byla odeslána." + +#: ../../mod/dfrn_request.php:481 +msgid "Please login to confirm introduction." +msgstr "Prosím pÅ™ihlaÅ¡te se k potvrzení žádosti o propojení." + +#: ../../mod/dfrn_request.php:495 +msgid "" +"Incorrect identity currently logged in. Please login to " +"this profile." +msgstr "" +"Jste pÅ™ihlášeni pod nesprávnou identitou Prosím, pÅ™ihlaste se do " +"tohoto profilu." + +#: ../../mod/dfrn_request.php:507 +#, php-format +msgid "Welcome home %s." +msgstr "Vítejte doma %s." + +#: ../../mod/dfrn_request.php:508 +#, php-format +msgid "Please confirm your introduction/connection request to %s." +msgstr "Prosím potvrÄte VaÅ¡i žádost o pÅ™edstavení/spojení %s." + +#: ../../mod/dfrn_request.php:509 +msgid "Confirm" +msgstr "Potvrdit" + +#: ../../mod/dfrn_request.php:542 ../../include/items.php:1519 +msgid "[Name Withheld]" +msgstr "[Jméno odepÅ™eno]" + +#: ../../mod/dfrn_request.php:549 +msgid "Introduction received at " +msgstr "Pozvánka pÅ™ijata v" + +#: ../../mod/dfrn_request.php:551 ../../mod/lostpass.php:44 +#: ../../mod/lostpass.php:106 ../../mod/register.php:369 +#: ../../mod/register.php:423 ../../mod/regmod.php:54 +#: ../../mod/dfrn_notify.php:291 ../../mod/dfrn_notify.php:547 +#: ../../mod/dfrn_confirm.php:674 ../../include/items.php:1528 +msgid "Administrator" +msgstr "Administrátor" + +#: ../../mod/dfrn_request.php:630 +msgid "Friend/Connection Request" +msgstr "Požadavek o přátelství / propojení" + +#: ../../mod/dfrn_request.php:631 +msgid "" +"Examples: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, " +"testuser@identi.ca" +msgstr "" +"Příklady: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, " +"testuser@identi.ca" + +#: ../../mod/dfrn_request.php:632 +msgid "Please answer the following:" +msgstr "OdpovÄ›zte, prosím, následující:" + +#: ../../mod/dfrn_request.php:633 +#, php-format +msgid "Does %s know you?" +msgstr "Zná Vás uživatel %s ?" + +#: ../../mod/dfrn_request.php:634 ../../mod/settings.php:415 +#: ../../mod/settings.php:421 ../../mod/settings.php:429 +#: ../../mod/settings.php:433 ../../mod/register.php:498 +#: ../../mod/profiles.php:354 +msgid "Yes" +msgstr "Ano" + +#: ../../mod/dfrn_request.php:635 ../../mod/settings.php:415 +#: ../../mod/settings.php:421 ../../mod/settings.php:429 +#: ../../mod/settings.php:433 ../../mod/register.php:499 +#: ../../mod/profiles.php:355 +msgid "No" +msgstr "Ne" + +#: ../../mod/dfrn_request.php:636 +msgid "Add a personal note:" +msgstr "PÅ™idat osobní poznámku:" + +#: ../../mod/dfrn_request.php:637 +msgid "" +"Please enter your 'Identity Address' from one of the following supported " +"social networks:" +msgstr "" +"Prosím, zadejte adresu své 'identity' jedné z následujících podporovaných " +"sociálních sítí:" + +#: ../../mod/dfrn_request.php:638 +msgid "Friendika" +msgstr "Friendika" + +#: ../../mod/dfrn_request.php:639 +msgid "StatusNet/Federated Social Web" +msgstr "StatusNet / Federativní Sociální Web" + +#: ../../mod/dfrn_request.php:640 +msgid "Private (secure) network" +msgstr "Soukromá (zabezpeÄená) síť" + +#: ../../mod/dfrn_request.php:641 +msgid "Public (insecure) network" +msgstr "VeÅ™ejná (nezabezpeÄená) síť" + +#: ../../mod/dfrn_request.php:642 +msgid "Your Identity Address:" +msgstr "Adresa Vaší identity :" + +#: ../../mod/dfrn_request.php:643 +msgid "Submit Request" +msgstr "Odeslat žádost" + +#: ../../mod/install.php:34 +msgid "Could not create/connect to database." +msgstr "Nelze vytvoÅ™it / pÅ™ipojit se k databázi." + +#: ../../mod/install.php:39 +msgid "Connected to database." +msgstr "PÅ™ipojeno k databázi." + +#: ../../mod/install.php:75 +msgid "Proceed with Installation" +msgstr "PokraÄovat v instalaci" + +#: ../../mod/install.php:77 +msgid "Your Friendika site database has been installed." +msgstr "VaÅ¡e databáze Friendiky byla nainstalována." + +#: ../../mod/install.php:78 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "Důležité: Budete si muset [ruÄnÄ›] plánovat úlohu pro poller." + +#: ../../mod/install.php:79 ../../mod/install.php:89 ../../mod/install.php:207 +msgid "Please see the file \"INSTALL.txt\"." +msgstr "PÅ™eÄtÄ›te si prosím informace v souboru \"INSTALL.txt\"." + +#: ../../mod/install.php:81 +msgid "Proceed to registration" +msgstr "PokraÄovat k registraci" + +#: ../../mod/install.php:87 +msgid "Database import failed." +msgstr "Import databáze se nezdaÅ™il." + +#: ../../mod/install.php:88 +msgid "" +"You may need to import the file \"database.sql\" manually using phpmyadmin " +"or mysql." +msgstr "" +"Možná budete muset importovat soubor \"database.sql\" ruÄnÄ› pomocí " +"phpMyAdmin Äi MySQL." + +#: ../../mod/install.php:101 +msgid "Welcome to Friendika." +msgstr "Vítejte na Friendice." + +#: ../../mod/install.php:124 +msgid "Friendika Social Network" +msgstr "Sociální síť Friendika " + +#: ../../mod/install.php:125 +msgid "Installation" +msgstr "Instalace" + +#: ../../mod/install.php:126 +msgid "" +"In order to install Friendika we need to know how to connect to your " +"database." +msgstr "Pro instalaci Friendika musíme vÄ›dÄ›t, jak se pÅ™ipojit k databázi." + +#: ../../mod/install.php:127 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "" +"ObraÅ¥te se na svého poskytovatele hostingu nebo administrátora serveru , " +"pokud máte dotazy týkající se tÄ›chto nastavení." + +#: ../../mod/install.php:128 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "" +"Databázi, kterou uvedete níže by již mÄ›la existovat. Pokud tak není, " +"prosíme, vytvoÅ™te ji pÅ™ed pokraÄováním." + +#: ../../mod/install.php:129 +msgid "Database Server Name" +msgstr "Jméno databázového serveru" + +#: ../../mod/install.php:130 +msgid "Database Login Name" +msgstr "PÅ™ihlaÅ¡ovací jméno k databázi" + +#: ../../mod/install.php:131 +msgid "Database Login Password" +msgstr "Heslo k databázovému úÄtu " + +#: ../../mod/install.php:132 +msgid "Database Name" +msgstr "Jméno databáze" + +#: ../../mod/install.php:133 +msgid "Please select a default timezone for your website" +msgstr "Prosím, vyberte výchozí Äasové pásmo pro vaÅ¡e webové stránky" + +#: ../../mod/install.php:134 +msgid "" +"Site administrator email address. Your account email address must match this" +" in order to use the web admin panel." +msgstr "" +"e-mailová adresa administrárota webu. E-mailová adresa vaÅ¡eho úÄtu se musí " +"shodovat, aby bylo možné využívat panel webové administrace." + +#: ../../mod/install.php:153 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Nelze najít verzi PHP pro příkazový řádek v PATH webového serveru." + +#: ../../mod/install.php:154 +msgid "" +"This is required. Please adjust the configuration file .htconfig.php " +"accordingly." +msgstr "" +"Tento krok je nutný. Upravte přísluÅ¡ným způsobem konfiguraÄní soubor " +".htconfig.php." + +#: ../../mod/install.php:161 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "" +"Verze PHP pro příkazový řádek na vaÅ¡em systému nemá povolen " +"\"register_argc_argv\"." + +#: ../../mod/install.php:162 +msgid "This is required for message delivery to work." +msgstr "Toto je nutné pro fungování doruÄování zpráv." + +#: ../../mod/install.php:184 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "" +"Chyba: funkce \"openssl_pkey_new\" na tomto systému není schopna generovat " +"Å¡ifrovací klíÄe" + +#: ../../mod/install.php:185 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "" +"Pokud systém běží na Windows, seznamte se s " +"\"http://www.php.net/manual/en/openssl.installation.php\"." + +#: ../../mod/install.php:194 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "" +"Chyba: Požadovaný Apache webserver mod-rewrite modul není nainstalován." + +#: ../../mod/install.php:196 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Chyba: požadovaný libcurl PHP modul není nainstalován." + +#: ../../mod/install.php:198 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Chyba: požadovaný GD graphics PHP modul není nainstalován." + +#: ../../mod/install.php:200 +msgid "Error: openssl PHP module required but not installed." +msgstr "Chyba: požadovaný openssl PHP modul není nainstalován." + +#: ../../mod/install.php:202 +msgid "Error: mysqli PHP module required but not installed." +msgstr "Chyba: požadovaný mysqli PHP modul není nainstalován." + +#: ../../mod/install.php:204 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Chyba: PHP modul mb_string je vyžadován, ale není nainstalován." + +#: ../../mod/install.php:216 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "" +"Webový instalátor musí být schopen vytvoÅ™it soubor s názvem " +"\".htconfig.php\" v hlavním adresáři vaÅ¡eho webového serveru ale nyní mu to " +"není umožnÄ›no." + +#: ../../mod/install.php:217 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "" +"Toto je nejÄastÄ›ji nastavením oprávnÄ›ní, kdy webový server nemusí být " +"schopen zapisovat soubory do vaÅ¡eho adresáře - i když Vy můžete." + +#: ../../mod/install.php:218 +msgid "" +"Please check with your site documentation or support people to see if this " +"situation can be corrected." +msgstr "" +"Prosím, poraÄte se s dokumentací k VaÅ¡emu hostingu nebo s technickou " +"podporou, zda-li lze tuto situaci napravit." + +#: ../../mod/install.php:219 +msgid "" +"If not, you may be required to perform a manual installation. Please see the" +" file \"INSTALL.txt\" for instructions." +msgstr "" +"Pokud ne, může být vyžadováno provedení ruÄní instalace. Prosím, seznamte se" +" s návodem popsaným v souboru \"INSTALL.txt\"." + +#: ../../mod/install.php:228 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "" +"Databázový konfiguraÄní soubor \".htconfig.php\" nemohl být uložen. Prosím, " +"použijte pÅ™iložený text k vytvoÅ™ení konfiguraÄního souboru ve vaÅ¡em " +"koÅ™enovém adresáři webového serveru." + +#: ../../mod/install.php:243 +msgid "Errors encountered creating database tables." +msgstr "PÅ™i vytváření databázových tabulek doÅ¡lo k chybám." + +#: ../../mod/update_community.php:18 ../../mod/update_network.php:22 +#: ../../mod/update_profile.php:41 +msgid "[Embedded content - reload page to view]" +msgstr "[Vložený obsah - obnovení stránky pro zobrazení]" + +#: ../../mod/match.php:10 +msgid "Profile Match" +msgstr "Shoda profilu" + +#: ../../mod/match.php:18 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "" +"Žádná klíÄová slova k porovnání. Prosím, pÅ™idejte klíÄová slova do VaÅ¡eho " +"výchozího profilu." + +#: ../../mod/match.php:54 +msgid "No matches" +msgstr "Žádné shody" + +#: ../../mod/lockview.php:39 +msgid "Remote privacy information not available." +msgstr "Vzdálené soukromé informace nejsou k dispozici." + +#: ../../mod/lockview.php:43 +msgid "Visible to:" +msgstr "Viditelné pro:" + +#: ../../mod/home.php:23 +#, php-format +msgid "Welcome to %s" +msgstr "Vítá Vás %s" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Neplatný identifikátor požadavku." + +#: ../../mod/notifications.php:35 ../../mod/notifications.php:118 +#: ../../mod/notifications.php:162 +msgid "Discard" +msgstr "Odstranit" + +#: ../../mod/notifications.php:47 ../../mod/notifications.php:117 +#: ../../mod/notifications.php:161 +msgid "Ignore" +msgstr "Ignorovat" + +#: ../../mod/notifications.php:74 +msgid "Pending Friend/Connect Notifications" +msgstr "ÄŒekající požadavky na Přátelství / PÅ™ipojení " + +#: ../../mod/notifications.php:78 +msgid "Show Ignored Requests" +msgstr "Zobrazit ignorované žádosti" + +#: ../../mod/notifications.php:78 +msgid "Hide Ignored Requests" +msgstr "Skrýt ignorované žádosti" + +#: ../../mod/notifications.php:105 ../../mod/notifications.php:148 +msgid "Notification type: " +msgstr "Typ oznámení:" + +#: ../../mod/notifications.php:106 +msgid "Friend Suggestion" +msgstr "Návrh přátelství" + +#: ../../mod/notifications.php:108 +#, php-format +msgid "suggested by %s" +msgstr "navrhl %s" + +#: ../../mod/notifications.php:114 ../../mod/notifications.php:159 +#: ../../mod/admin.php:466 +msgid "Approve" +msgstr "Schválit" + +#: ../../mod/notifications.php:133 +msgid "Claims to be known to you: " +msgstr "VaÅ¡i údajní známí:" + +#: ../../mod/notifications.php:133 +msgid "yes" +msgstr "ano" + +#: ../../mod/notifications.php:133 +msgid "no" +msgstr "ne" + +#: ../../mod/notifications.php:139 +msgid "Approve as: " +msgstr "Schválit jako:" + +#: ../../mod/notifications.php:140 +msgid "Friend" +msgstr "Přítel" + +#: ../../mod/notifications.php:141 +msgid "Fan/Admirer" +msgstr "FanouÅ¡ek / obdivovatel" + +#: ../../mod/notifications.php:149 +msgid "Friend/Connect Request" +msgstr "Přítel / žádost o pÅ™ipojení" + +#: ../../mod/notifications.php:149 +msgid "New Follower" +msgstr "Nový následovník" + +#: ../../mod/notifications.php:168 +msgid "No notifications." +msgstr "Žádné oznámení." + +#: ../../mod/contacts.php:26 +msgid "Invite Friends" +msgstr "Pozvat přátele" + +#: ../../mod/contacts.php:32 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "Pozvánka %d k dispozici" +msgstr[1] "Pozvánky %d k dispozici" +msgstr[2] "Pozvánky %d k dispozici" + +#: ../../mod/contacts.php:41 +msgid "Find People With Shared Interests" +msgstr "Najít lidi se spoleÄnými zájmy" + +#: ../../mod/contacts.php:45 +msgid "Connect/Follow" +msgstr "PÅ™ipojit / Následovat" + +#: ../../mod/contacts.php:46 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Příklad: jan@příklad.cz, http://příklad.cz/jana" + +#: ../../mod/contacts.php:47 +msgid "Follow" +msgstr "Následovat" + +#: ../../mod/contacts.php:69 ../../mod/contacts.php:150 +msgid "Could not access contact record." +msgstr "Nelze získat přístup k záznamu kontaktu." + +#: ../../mod/contacts.php:83 +msgid "Could not locate selected profile." +msgstr "Nelze nalézt vybraný profil." + +#: ../../mod/contacts.php:114 +msgid "Contact updated." +msgstr "Kontakt aktualizován." + +#: ../../mod/contacts.php:172 +msgid "Contact has been blocked" +msgstr "Kontakt byl zablokován" + +#: ../../mod/contacts.php:172 +msgid "Contact has been unblocked" +msgstr "Kontakt byl odblokován" + +#: ../../mod/contacts.php:186 +msgid "Contact has been ignored" +msgstr "Kontakt bude ignorován" + +#: ../../mod/contacts.php:186 +msgid "Contact has been unignored" +msgstr "Kontakt pÅ™estal být ignorován" + +#: ../../mod/contacts.php:207 +msgid "stopped following" +msgstr "následování zastaveno" + +#: ../../mod/contacts.php:226 +msgid "Contact has been removed." +msgstr "Kontakt byl odstranÄ›n." + +#: ../../mod/contacts.php:254 ../../mod/contacts.php:397 +msgid "Mutual Friendship" +msgstr "Vzájemné přátelství" + +#: ../../mod/contacts.php:258 ../../mod/contacts.php:401 +msgid "is a fan of yours" +msgstr "je Váš fanouÅ¡ek" + +#: ../../mod/contacts.php:263 ../../mod/contacts.php:405 +msgid "you are a fan of" +msgstr "jste fanouÅ¡kem" + +#: ../../mod/contacts.php:280 +msgid "Privacy Unavailable" +msgstr "Ochrana soukromí není k dispozici" + +#: ../../mod/contacts.php:281 +msgid "Private communications are not available for this contact." +msgstr "Soukromá komunikace není dostupná pro tento kontakt." + +#: ../../mod/contacts.php:284 +msgid "Never" +msgstr "Nikdy" + +#: ../../mod/contacts.php:288 +msgid "(Update was successful)" +msgstr "(Aktualizace byla úspěšná)" + +#: ../../mod/contacts.php:288 +msgid "(Update was not successful)" +msgstr "(Aktualizace nebyla úspěšná)" + +#: ../../mod/contacts.php:291 +msgid "Suggest friends" +msgstr "NavrhnÄ›te přátelé" + +#: ../../mod/contacts.php:295 +msgid "Contact Editor" +msgstr "Editor kontaktu" + +#: ../../mod/contacts.php:297 +msgid "Profile Visibility" +msgstr "Viditelnost profilu" + +#: ../../mod/contacts.php:298 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "" +"Vyberte prosím profil, který chcete zobrazit %s pÅ™i zabezpeÄeném prohlížení " +"vaÅ¡eho profilu." + +#: ../../mod/contacts.php:299 +msgid "Contact Information / Notes" +msgstr "Kontaktní informace / poznámky" + +#: ../../mod/contacts.php:300 +msgid "Online Reputation" +msgstr "Online povÄ›st" + +#: ../../mod/contacts.php:301 +msgid "" +"Occasionally your friends may wish to inquire about this person's online " +"legitimacy." +msgstr "" +"ObÄas mohou vaÅ¡i přátelé chtít informovat o online legitimitÄ› této osoby." + +#: ../../mod/contacts.php:302 +msgid "" +"You may help them choose whether or not to interact with this person by " +"providing a reputation to guide them." +msgstr "" +"Poskytnutím povÄ›sti jim můžete pomoci se rozhodnout, zda-li s touto" +" osobou komunikovat Äi nikoliv." + +#: ../../mod/contacts.php:303 +msgid "" +"Please take a moment to elaborate on this selection if you feel it could be " +"helpful to others." +msgstr "" +"VÄ›nujte prosím chvilku vyplnÄ›ní této volby, pokud máte pocit, že by mohlo " +"být užiteÄné pro ostatní." + +#: ../../mod/contacts.php:304 ../../mod/contacts.php:421 +#: ../../mod/viewconnections.php:61 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "NavÅ¡tivte profil uživatele %s [%s]" + +#: ../../mod/contacts.php:305 +msgid "Block/Unblock contact" +msgstr "Blokovat / Odblokovat kontakt" + +#: ../../mod/contacts.php:306 +msgid "Ignore contact" +msgstr "Ignorovat kontakt" + +#: ../../mod/contacts.php:307 +msgid "Repair contact URL settings" +msgstr "Opravit nastavení URL kontaktu" + +#: ../../mod/contacts.php:308 +msgid "Repair contact URL settings (WARNING: Advanced)" +msgstr "Opravit nastavení URL kontaktu (Varování: PokroÄilé)" + +#: ../../mod/contacts.php:309 +msgid "View conversations" +msgstr "Zobrazit konverzace" + +#: ../../mod/contacts.php:312 +msgid "Delete contact" +msgstr "Odstranit kontakt" + +#: ../../mod/contacts.php:314 +msgid "Last updated: " +msgstr "Poslední aktualizace:" + +#: ../../mod/contacts.php:315 +msgid "Update public posts: " +msgstr "Aktualizace veÅ™ejných příspÄ›vků:" + +#: ../../mod/contacts.php:317 ../../mod/admin.php:701 +msgid "Update now" +msgstr "Aktualizovat" + +#: ../../mod/contacts.php:320 +msgid "Unblock this contact" +msgstr "Odblokovat tento kontakt" + +#: ../../mod/contacts.php:320 +msgid "Block this contact" +msgstr "Blokovat tento kontakt" + +#: ../../mod/contacts.php:321 +msgid "Unignore this contact" +msgstr "PÅ™estat ignorovat tento kontakt" + +#: ../../mod/contacts.php:321 +msgid "Ignore this contact" +msgstr "Ignorovat tento kontakt" + +#: ../../mod/contacts.php:324 +msgid "Currently blocked" +msgstr "V souÄasnosti zablokováno" + +#: ../../mod/contacts.php:325 +msgid "Currently ignored" +msgstr "V souÄasnosti ignorováno" + +#: ../../mod/contacts.php:356 ../../include/nav.php:110 +msgid "Contacts" +msgstr "Kontakty" + +#: ../../mod/contacts.php:358 +msgid "Show Blocked Connections" +msgstr "Zobrazit blokované spojení" + +#: ../../mod/contacts.php:358 +msgid "Hide Blocked Connections" +msgstr "Skrýt blokované spojení" + +#: ../../mod/contacts.php:360 ../../mod/directory.php:55 +msgid "Finding: " +msgstr "ZjiÅ¡tÄ›ní: " + +#: ../../mod/contacts.php:361 ../../mod/directory.php:57 +msgid "Find" +msgstr "Najít" + +#: ../../mod/contacts.php:422 ../../include/conversation.php:612 +msgid "Edit contact" +msgstr "Editovat kontakt" + +#: ../../mod/lostpass.php:16 +msgid "No valid account found." +msgstr "Nenalezen žádný platný úÄet." + +#: ../../mod/lostpass.php:31 +msgid "Password reset request issued. Check your email." +msgstr "" +"Žádost o obnovení hesla vyřízena. Zkontrolujte VaÅ¡i e-mailovou schránku." + +#: ../../mod/lostpass.php:42 +#, php-format +msgid "Password reset requested at %s" +msgstr "Na %s bylo zažádáno o resetování hesla" + +#: ../../mod/lostpass.php:64 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "" +"Žádost nemohla být ověřena. (Možná jste ji odeslali již dříve.) Obnovení " +"hesla se nezdaÅ™ilo." + +#: ../../mod/lostpass.php:82 ../../boot.php:654 +msgid "Password Reset" +msgstr "Obnovení hesla" + +#: ../../mod/lostpass.php:83 +msgid "Your password has been reset as requested." +msgstr "VaÅ¡e heslo bylo na VaÅ¡e přání resetováno." + +#: ../../mod/lostpass.php:84 +msgid "Your new password is" +msgstr "VaÅ¡e nové heslo je" + +#: ../../mod/lostpass.php:85 +msgid "Save or copy your new password - and then" +msgstr "Uložte si nebo zkopírujte nové heslo - a pak" + +#: ../../mod/lostpass.php:86 +msgid "click here to login" +msgstr "kliknÄ›te zde pro pÅ™ihlášení" + +#: ../../mod/lostpass.php:87 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "" +"VaÅ¡e heslo může být zmÄ›nÄ›no na stránce nastavení po úspěšném " +"pÅ™ihlášení." + +#: ../../mod/lostpass.php:118 +msgid "Forgot your Password?" +msgstr "ZapomnÄ›li jste heslo?" + +#: ../../mod/lostpass.php:119 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "" +"Zadejte svůj e-mailovou adresu a odeÅ¡lete žádost o zaslání VaÅ¡eho nového " +"hesla. Poté zkontrolujte svůj e-mail pro další instrukce." + +#: ../../mod/lostpass.php:120 +msgid "Nickname or Email: " +msgstr "PÅ™ezdívka nebo e-mail:" + +#: ../../mod/lostpass.php:121 +msgid "Reset" +msgstr "Reset" + +#: ../../mod/settings.php:64 +msgid "Passwords do not match. Password unchanged." +msgstr "Hesla se neshodují. Heslo nebylo zmÄ›nÄ›no." + +#: ../../mod/settings.php:69 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Prázdné hesla nejsou povolena. Heslo nebylo zmÄ›nÄ›no." + +#: ../../mod/settings.php:80 +msgid "Password changed." +msgstr "Heslo bylo zmÄ›nÄ›no." + +#: ../../mod/settings.php:82 +msgid "Password update failed. Please try again." +msgstr "Aktualizace hesla se nezdaÅ™ila. Zkuste to prosím znovu." + +#: ../../mod/settings.php:161 +msgid "Failed to connect with email account using the settings provided." +msgstr "NepodaÅ™ilo se pÅ™ipojit k e-mailovému úÄtu pomocí dodaného nastavení." + +#: ../../mod/settings.php:188 +msgid " Please use a shorter name." +msgstr "Prosím použijte kratší jméno." + +#: ../../mod/settings.php:190 +msgid " Name too short." +msgstr "Jméno je příliÅ¡ krátké." + +#: ../../mod/settings.php:196 +msgid " Not valid email." +msgstr "Neplatný e-mail." + +#: ../../mod/settings.php:198 +msgid " Cannot change to that email." +msgstr "Nelze provést zmÄ›nu na tento e-mail." + +#: ../../mod/settings.php:257 ../../addon/facebook/facebook.php:297 +#: ../../addon/impressum/impressum.php:64 ../../addon/piwik/piwik.php:89 +#: ../../addon/twitter/twitter.php:275 +msgid "Settings updated." +msgstr "Nastavení aktualizováno." + +#: ../../mod/settings.php:311 ../../include/nav.php:108 +msgid "Account settings" +msgstr "Nastavení úÄtu" + +#: ../../mod/settings.php:312 +msgid "Plugin settings" +msgstr "Nastavení pluginu" + +#: ../../mod/settings.php:322 +msgid "No Plugin settings configured" +msgstr "Žádný doplnÄ›k není nastaven" + +#: ../../mod/settings.php:329 ../../addon/widgets/widgets.php:122 +msgid "Plugin Settings" +msgstr "Nastavení doplňku" + +#: ../../mod/settings.php:382 ../../mod/admin.php:133 ../../mod/admin.php:443 +msgid "Normal Account" +msgstr "Normální úÄet" + +#: ../../mod/settings.php:383 +msgid "This account is a normal personal profile" +msgstr "Tento úÄet je běžný osobní profil" + +#: ../../mod/settings.php:386 ../../mod/admin.php:134 ../../mod/admin.php:444 +msgid "Soapbox Account" +msgstr "Soapbox úÄet" + +#: ../../mod/settings.php:387 +msgid "Automatically approve all connection/friend requests as read-only fans" +msgstr "" +"Automaticky schválit vÅ¡echna spojení / přátelství jako fanouÅ¡ky s právem " +"pouze ke Ätení" + +#: ../../mod/settings.php:390 ../../mod/admin.php:135 ../../mod/admin.php:445 +msgid "Community/Celebrity Account" +msgstr "Komunitní úÄet / ÚÄet celebrity" + +#: ../../mod/settings.php:391 +msgid "" +"Automatically approve all connection/friend requests as read-write fans" +msgstr "" +"Automaticky schvalovat vÅ¡echny žádosti o spojení / přátelství, jako fanouÅ¡ky" +" s právem ke Ätení." + +#: ../../mod/settings.php:394 ../../mod/admin.php:136 ../../mod/admin.php:446 +msgid "Automatic Friend Account" +msgstr "ÚÄet s automatickým schvalováním přátel" + +#: ../../mod/settings.php:395 +msgid "Automatically approve all connection/friend requests as friends" +msgstr "" +"Automaticky schvalovat vÅ¡echny žádosti o spojení / přátelství jako přátele" + +#: ../../mod/settings.php:405 +msgid "OpenID:" +msgstr "OpenID:" + +#: ../../mod/settings.php:405 +msgid "(Optional) Allow this OpenID to login to this account." +msgstr "(Volitelné) Povolit OpenID pro pÅ™ihlášení k tomuto úÄtu." + +#: ../../mod/settings.php:415 +msgid "Publish your default profile in your local site directory?" +msgstr "Publikovat Váš výchozí profil v místním adresáři webu?" + +#: ../../mod/settings.php:421 +msgid "Publish your default profile in the global social directory?" +msgstr "Publikovat Váš výchozí profil v globální sociálním adresáři?" + +#: ../../mod/settings.php:429 +msgid "Hide your contact/friend list from viewers of your default profile?" +msgstr "" +"Skrýt VaÅ¡e kontaktní údaje a seznam přátel pÅ™ed návÅ¡tÄ›vníky ve VaÅ¡em " +"výchozím profilu?" + +#: ../../mod/settings.php:433 +msgid "Hide profile details and all your messages from unknown viewers?" +msgstr "Skrýt detaily profilu a vÅ¡echny zprávy pÅ™ed neznámými uživateli?" + +#: ../../mod/settings.php:442 +msgid "Profile is not published." +msgstr "Profil není zveÅ™ejnÄ›n." + +#: ../../mod/settings.php:461 ../../mod/profile_photo.php:196 +msgid "or" +msgstr "nebo" + +#: ../../mod/settings.php:466 +msgid "Your Identity Address is" +msgstr "VaÅ¡e adresa identity je" + +#: ../../mod/settings.php:480 +msgid "Account Settings" +msgstr "Nastavení úÄtu" + +#: ../../mod/settings.php:487 +msgid "Export Personal Data" +msgstr "Export osobních údajů" + +#: ../../mod/settings.php:490 +msgid "Password Settings" +msgstr "Nastavení hesla" + +#: ../../mod/settings.php:491 +msgid "New Password:" +msgstr "Nové heslo:" + +#: ../../mod/settings.php:492 +msgid "Confirm:" +msgstr "PotvrÄte:" + +#: ../../mod/settings.php:492 +msgid "Leave password fields blank unless changing" +msgstr "Pokud nechcete zmÄ›nit heslo, položku hesla nevyplňujte" + +#: ../../mod/settings.php:496 +msgid "Basic Settings" +msgstr "Základní nastavení" + +#: ../../mod/settings.php:497 ../../include/profile_advanced.php:10 +msgid "Full Name:" +msgstr "Celé jméno:" + +#: ../../mod/settings.php:498 +msgid "Email Address:" +msgstr "E-mailová adresa:" + +#: ../../mod/settings.php:499 +msgid "Your Timezone:" +msgstr "VaÅ¡e Äasové pásmo:" + +#: ../../mod/settings.php:500 +msgid "Default Post Location:" +msgstr "Výchozí umístÄ›ní příspÄ›vků:" + +#: ../../mod/settings.php:501 +msgid "Use Browser Location:" +msgstr "Používat umístÄ›ní dle prohlížeÄe:" + +#: ../../mod/settings.php:502 +msgid "Display Theme:" +msgstr "Vybrat grafickou Å¡ablonu:" + +#: ../../mod/settings.php:506 +msgid "Security and Privacy Settings" +msgstr "Nastavení zabezpeÄení a soukromí" + +#: ../../mod/settings.php:508 +msgid "Maximum Friend Requests/Day:" +msgstr "Maximální poÄet žádostí o přátelství za den:" + +#: ../../mod/settings.php:508 +msgid "(to prevent spam abuse)" +msgstr "(Aby se zabránilo spamu)" + +#: ../../mod/settings.php:509 +msgid "Default Post Permissions" +msgstr "Výchozí oprávnÄ›ní pro příspÄ›vek" + +#: ../../mod/settings.php:510 +msgid "(click to open/close)" +msgstr "(KliknÄ›te pro otevÅ™ení/zavÅ™ení)" + +#: ../../mod/settings.php:514 +msgid "Allow friends to post to your profile page:" +msgstr "Povolit přátelům příspÄ›vky na VaÅ¡i profilovou stránku:" + +#: ../../mod/settings.php:515 +msgid "Automatically expire posts after days:" +msgstr "Po kolika dnech automaticky expirovat příspÄ›vky:" + +#: ../../mod/settings.php:515 +msgid "If empty, posts will not expire. Expired posts will be deleted" +msgstr "" +"Pokud je prázdné, příspÄ›vky nebudou nikdy expirovat. Expirované příspÄ›vky " +"budou vymazány" + +#: ../../mod/settings.php:524 +msgid "Notification Settings" +msgstr "Nastavení notifikací" + +#: ../../mod/settings.php:525 +msgid "Send a notification email when:" +msgstr "Poslat notifikaci e-mailem, když" + +#: ../../mod/settings.php:526 +msgid "You receive an introduction" +msgstr "obdržíte žádost o propojení" + +#: ../../mod/settings.php:527 +msgid "Your introductions are confirmed" +msgstr "VaÅ¡e žádosti jsou potvrzeny" + +#: ../../mod/settings.php:528 +msgid "Someone writes on your profile wall" +msgstr "nÄ›kdo Vám napíše na VaÅ¡i profilovou stránku" + +#: ../../mod/settings.php:529 +msgid "Someone writes a followup comment" +msgstr "nÄ›kdo Vám napíše následný komentář" + +#: ../../mod/settings.php:530 +msgid "You receive a private message" +msgstr "obdržíte soukromou zprávu" + +#: ../../mod/settings.php:534 +msgid "Email/Mailbox Setup" +msgstr "Nastavení e-mailu" + +#: ../../mod/settings.php:535 +msgid "" +"If you wish to communicate with email contacts using this service " +"(optional), please specify how to connect to your mailbox." +msgstr "" +"Pokud chcete komunikovat pomocí této služby s VaÅ¡imi kontakty z e-mailu " +"(volitelné), uveÄte, jak se pÅ™ipojit k Vaší e-mailové schránce." + +#: ../../mod/settings.php:536 +msgid "Last successful email check:" +msgstr "Poslední úspěšná kontrola e-mailu:" + +#: ../../mod/settings.php:537 +msgid "Email access is disabled on this site." +msgstr "Přístup k elektronické poÅ¡tÄ› je na tomto serveru zakázán." + +#: ../../mod/settings.php:538 +msgid "IMAP server name:" +msgstr "jméno IMAP serveru:" + +#: ../../mod/settings.php:539 +msgid "IMAP port:" +msgstr "IMAP port:" + +#: ../../mod/settings.php:540 +msgid "Security:" +msgstr "ZabezpeÄení:" + +#: ../../mod/settings.php:540 +msgid "None" +msgstr "Žádný" + +#: ../../mod/settings.php:541 +msgid "Email login name:" +msgstr "pÅ™ihlaÅ¡ovací jméno k e-mailu:" + +#: ../../mod/settings.php:542 +msgid "Email password:" +msgstr "heslo k VaÅ¡emu e-mailu:" + +#: ../../mod/settings.php:543 +msgid "Reply-to address:" +msgstr "OdpovÄ›dÄ›t na adresu:" + +#: ../../mod/settings.php:544 +msgid "Send public posts to all email contacts:" +msgstr "Poslat veÅ™ejné příspÄ›vky na vÅ¡echny e-mailové kontakty:" + +#: ../../mod/settings.php:549 +msgid "Advanced Page Settings" +msgstr "PokroÄilé nastavení stránky" + +#: ../../mod/manage.php:37 +#, php-format +msgid "Welcome back %s" +msgstr "Vítejte zpÄ›t %s" + +#: ../../mod/manage.php:87 +msgid "Manage Identities and/or Pages" +msgstr "Správa identit a / nebo stránek" + +#: ../../mod/manage.php:90 +msgid "" +"(Toggle between different identities or community/group pages which share " +"your account details.)" +msgstr "" +"(PÅ™epínání mezi různými identitami nebo komunitními / skupinovými stránkami," +" které sdílejí VaÅ¡e detaily úÄtu.)" + +#: ../../mod/manage.php:92 +msgid "Select an identity to manage: " +msgstr "Vyberte identitu pro správu:" + +#: ../../mod/network.php:27 +msgid "View Conversations" +msgstr "Zobrazit konverzace" + +#: ../../mod/network.php:29 +msgid "View New Items" +msgstr "Zobrazit nové položky" + +#: ../../mod/network.php:35 +msgid "View Any Items" +msgstr "Zobrazit vÅ¡echny položky" + +#: ../../mod/network.php:43 +msgid "View Starred Items" +msgstr "Zobrazit položky oznaÄené hvÄ›zdu" + +#: ../../mod/network.php:94 +#, php-format +msgid "Warning: This group contains %s member from an insecure network." +msgid_plural "" +"Warning: This group contains %s members from an insecure network." +msgstr[0] "UpozornÄ›ní: Tato skupina obsahuje %s Älena z nezabezpeÄené sítÄ›." +msgstr[1] "UpozornÄ›ní: Tato skupina obsahuje %s Äleny z nezabezpeÄené sítÄ›." +msgstr[2] "UpozornÄ›ní: Tato skupina obsahuje %s Äleny z nezabezpeÄené sítÄ›." + +#: ../../mod/network.php:97 +msgid "Private messages to this group are at risk of public disclosure." +msgstr "Soukromé zprávy této skupinÄ› jsou vystaveny riziku prozrazení." + +#: ../../mod/network.php:164 +msgid "No such group" +msgstr "Žádná taková skupina" + +#: ../../mod/network.php:175 +msgid "Group is empty" +msgstr "Skupina je prázdná" + +#: ../../mod/network.php:180 +msgid "Group: " +msgstr "Skupina:" + +#: ../../mod/network.php:190 +msgid "Contact: " +msgstr "Kontakt:" + +#: ../../mod/network.php:192 +msgid "Private messages to this person are at risk of public disclosure." +msgstr "Soukromé zprávy této osobÄ› jsou vystaveny riziku prozrazení." + +#: ../../mod/network.php:197 +msgid "Invalid contact." +msgstr "Neplatný kontakt." + +#: ../../mod/notes.php:74 +msgid "Save" +msgstr "Uložit" + +#: ../../mod/newmember.php:6 +msgid "Welcome to Friendika" +msgstr "Vítejte na Friendika" + +#: ../../mod/newmember.php:8 +msgid "New Member Checklist" +msgstr "Seznam doporuÄení pro nového Älena" + +#: ../../mod/newmember.php:12 +msgid "" +"We would like to offer some tips and links to help make your experience " +"enjoyable. Click any item to visit the relevant page." +msgstr "" +"Dovolujeme si Vám nabídnout nÄ›které tipy a odkazy, abychom Vám zpříjemnili " +"práci se systémem Friendika. Kliknutím na libovolnou položku navÅ¡tívit " +"přísluÅ¡nou stránku." + +#: ../../mod/newmember.php:16 +msgid "" +"On your Settings page - change your initial password. Also make a " +"note of your Identity Address. This will be useful in making friends." +msgstr "" +"Na stránce Nastavení - zmÄ›nit výchozí heslo. Poznamenejte si také " +"adresu své identity. To může být užiteÄné pÅ™i navazování přátelství." + +#: ../../mod/newmember.php:18 +msgid "" +"Review the other settings, particularly the privacy settings. An unpublished" +" directory listing is like having an unlisted phone number. In general, you " +"should probably publish your listing - unless all of your friends and " +"potential friends know exactly how to find you." +msgstr "" +"ProhlédnÄ›te si další nastavení, a to zejména nastavení soukromí. " +"NezveÅ™ejnÄ›ní svého úÄtu v adresáři je jako mít nezveÅ™ejnÄ›né telefonní Äíslo." +" ObecnÄ› platí, že je lepší mít svůj úÄet zveÅ™ejnÄ›ný, leda by vÅ¡ichni vaÅ¡i " +"potenciální přátelé vÄ›dÄ›li, jak vás pÅ™esnÄ› najít." + +#: ../../mod/newmember.php:20 +msgid "" +"Upload a profile photo if you have not done so already. Studies have shown " +"that people with real photos of themselves are ten times more likely to make" +" friends than people who do not." +msgstr "" +"Nahrajte si svou profilovou fotku, pokud jste tak již neuÄinili. Studie " +"ukázaly, že lidé se skuteÄnými fotografiemi mají desetkrát ÄastÄ›ji přátele " +"než lidé, kteří nemají." + +#: ../../mod/newmember.php:23 +msgid "" +"Authorise the Facebook Connector if you currently have a Facebook account " +"and we will (optionally) import all your Facebook friends and conversations." +msgstr "" +"Jestliže máte úÄet na Facebooku, povolte konektor na Facebook a bude možné " +"(na přání) importovat vÅ¡echny VaÅ¡ přátele na Facebooku a vÅ¡echny VaÅ¡e " +"konverzace." + +#: ../../mod/newmember.php:28 +msgid "" +"Enter your email access information on your Settings page if you wish to " +"import and interact with friends or mailing lists from your email INBOX" +msgstr "" +"na stránce Nastavení zadejte informace pro přístup k Vaší e-mailové stránce," +" pokud si pÅ™ejete importovat a komunikovat s přáteli nebo distribuÄními " +"skupinami z Vaší e-mailové schránky" + +#: ../../mod/newmember.php:30 +msgid "" +"Edit your default profile to your liking. Review the " +"settings for hiding your list of friends and hiding the profile from unknown" +" visitors." +msgstr "" +"Upravit výchozí profil podle vaÅ¡ich pÅ™edstav. Prověřte " +"nastavení pro skrytí VaÅ¡eho seznamu přátel a skrytí profilu pÅ™ed neznámými " +"návÅ¡tÄ›vníky." + +#: ../../mod/newmember.php:32 +msgid "" +"Set some public keywords for your default profile which describe your " +"interests. We may be able to find other people with similar interests and " +"suggest friendships." +msgstr "" +"Nastavte si nÄ›jaká veÅ™ejné klíÄová slova pro výchozí profil, která popisují " +"vaÅ¡e zájmy. Friendika Vám může nalézt další lidi s podobnými zájmy a " +"navrhnout přátelství." + +#: ../../mod/newmember.php:34 +msgid "" +"Your Contacts page is your gateway to managing friendships and connecting " +"with friends on other networks. Typically you enter their address or site " +"URL in the Connect dialog." +msgstr "" +"Stránka Kontakty je Vaším odrazovým můstkem k řízení přátelství a spojení s " +"kamarády v jiných sítích. Obvykle zadáte jejich adresu nebo adresu URL do " +"dialogu PÅ™ipojit." + +#: ../../mod/newmember.php:36 +msgid "" +"The Directory page lets you find other people in this network or other " +"federated sites. Look for a Connect or Follow link on " +"their profile page. Provide your own Identity Address if requested." +msgstr "" +"Stránka Adresář Vám pomůže najít další lidi na tomto serveru nebo v jiných " +"propojených serverech. ProstÅ™ednictvím odkazů PÅ™ipojení nebo " +"Následovat si prohlédnÄ›te jejich profilovou stránku. UveÄte svou " +"vlastní adresu identity, je-li požadována." + +#: ../../mod/newmember.php:38 +msgid "" +"Once you have made some friends, organize them into private conversation " +"groups from the sidebar of your Contacts page and then you can interact with" +" each group privately on your Network page." +msgstr "" +"Jakmile získáte nÄ›jaké přátele, uspořádejte si je do soukromých " +"konverzaÄních skupin na postranním panelu vaší stránky Kontakty a pak můžete" +" komunikovat s každou touto skupinu soukromÄ› prostÅ™ednictvím stránky Síť." + +#: ../../mod/newmember.php:40 +msgid "" +"Our help pages may be consulted for detail on other program" +" features and resources." +msgstr "" +"Na stránkách NápovÄ›da naleznete nejen další podrobnosti o " +"vÅ¡ech funkcích Friendika ale také další zdroje informací." + +#: ../../mod/attach.php:8 +msgid "Item not available." +msgstr "Položka není k dispozici." + +#: ../../mod/attach.php:20 +msgid "Item was not found." +msgstr "Položka nebyla nalezena." + +#: ../../mod/group.php:27 +msgid "Group created." +msgstr "Skupina vytvoÅ™ena." + +#: ../../mod/group.php:33 +msgid "Could not create group." +msgstr "Nelze vytvoÅ™it skupinu." + +#: ../../mod/group.php:43 ../../mod/group.php:123 +msgid "Group not found." +msgstr "Skupina nenalezena." + +#: ../../mod/group.php:56 +msgid "Group name changed." +msgstr "Název skupiny byl zmÄ›nÄ›n." + +#: ../../mod/group.php:67 ../../mod/profperm.php:19 ../../index.php:265 +msgid "Permission denied" +msgstr "NedostateÄné oprávnÄ›ní" + +#: ../../mod/group.php:82 +msgid "Create a group of contacts/friends." +msgstr "VytvoÅ™it skupinu kontaktů / přátel." + +#: ../../mod/group.php:83 ../../mod/group.php:166 +msgid "Group Name: " +msgstr "Název skupiny:" + +#: ../../mod/group.php:98 +msgid "Group removed." +msgstr "Skupina odstranÄ›na. " + +#: ../../mod/group.php:100 +msgid "Unable to remove group." +msgstr "Nelze odstranit skupinu." + +#: ../../mod/group.php:164 ../../mod/profperm.php:105 +msgid "Click on a contact to add or remove." +msgstr "KliknÄ›te na kontakt pro pÅ™idání nebo odebrání" + +#: ../../mod/group.php:165 +msgid "Group Editor" +msgstr "Editor skupin" + +#: ../../mod/group.php:180 +msgid "Members" +msgstr "ÄŒlenové" + +#: ../../mod/group.php:195 +msgid "All Contacts" +msgstr "VÅ¡echny kontakty" + +#: ../../mod/profperm.php:25 ../../mod/profperm.php:55 +msgid "Invalid profile identifier." +msgstr "Neplatný identifikátor profilu." + +#: ../../mod/profperm.php:101 +msgid "Profile Visibility Editor" +msgstr "Editor viditelnosti profilu " + +#: ../../mod/profperm.php:114 +msgid "Visible To" +msgstr "Viditelný pro" + +#: ../../mod/profperm.php:128 +msgid "All Contacts (with secure profile access)" +msgstr "VÅ¡echny kontakty (se zabezpeÄeným přístupovým profilem )" + +#: ../../mod/viewconnections.php:25 ../../include/text.php:555 +msgid "View Contacts" +msgstr "Zobrazit kontakty" + +#: ../../mod/viewconnections.php:40 +msgid "No contacts." +msgstr "Žádné kontakty." + +#: ../../mod/register.php:53 +msgid "An invitation is required." +msgstr "Pozvánka je vyžadována." + +#: ../../mod/register.php:58 +msgid "Invitation could not be verified." +msgstr "Pozvánka nemohla být ověřena." + +#: ../../mod/register.php:66 +msgid "Invalid OpenID url" +msgstr "Neplatný odkaz OpenID" + +#: ../../mod/register.php:81 +msgid "Please enter the required information." +msgstr "Zadejte prosím požadované informace." + +#: ../../mod/register.php:95 +msgid "Please use a shorter name." +msgstr "Použijte prosím kratší jméno." + +#: ../../mod/register.php:97 +msgid "Name too short." +msgstr "Jméno je příliÅ¡ krátké." + +#: ../../mod/register.php:112 +msgid "That doesn't appear to be your full (First Last) name." +msgstr "Nezdá se, že by to bylo vaÅ¡e celé jméno (kÅ™estní jméno a příjmení)." + +#: ../../mod/register.php:117 +msgid "Your email domain is not among those allowed on this site." +msgstr "Váš e-mailová doména není na tomto serveru mezi povolenými." + +#: ../../mod/register.php:120 +msgid "Not a valid email address." +msgstr "Neplatná e-mailová adresa." + +#: ../../mod/register.php:130 +msgid "Cannot use that email." +msgstr "Tento e-mail nelze použít." + +#: ../../mod/register.php:136 +msgid "" +"Your \"nickname\" can only contain \"a-z\", \"0-9\", \"-\", and \"_\", and " +"must also begin with a letter." +msgstr "" +"VaÅ¡e \"pÅ™ezdívka\" může obsahovat pouze \"a-z\", \"0-9\", \"-\", a \"_\", a " +"musí zaÄínat písmenem." + +#: ../../mod/register.php:142 ../../mod/register.php:243 +msgid "Nickname is already registered. Please choose another." +msgstr "PÅ™ezdívka je již registrována. Prosím vyberte jinou." + +#: ../../mod/register.php:161 +msgid "SERIOUS ERROR: Generation of security keys failed." +msgstr "Závažná chyba: Generování bezpeÄnostních klíÄů se nezdaÅ™ilo." + +#: ../../mod/register.php:229 +msgid "An error occurred during registration. Please try again." +msgstr "DoÅ¡lo k chybÄ› pÅ™i registraci. Zkuste to prosím znovu." + +#: ../../mod/register.php:265 +msgid "An error occurred creating your default profile. Please try again." +msgstr "" +"DoÅ¡lo k chybÄ› pÅ™i vytváření VaÅ¡eho výchozího profilu. Zkuste to prosím " +"znovu." + +#: ../../mod/register.php:367 ../../mod/regmod.php:52 +#, php-format +msgid "Registration details for %s" +msgstr "RegistraÄní údaje pro %s" + +#: ../../mod/register.php:375 +msgid "" +"Registration successful. Please check your email for further instructions." +msgstr "" +"Registrace úspěšná. Zkontrolujte prosím svůj e-mail pro další instrukce." + +#: ../../mod/register.php:379 +msgid "Failed to send email message. Here is the message that failed." +msgstr "" +"NepodaÅ™ilo se odeslat zprávu na e-mail. Zde je zpráva, která nebyla " +"odeslána." + +#: ../../mod/register.php:384 +msgid "Your registration can not be processed." +msgstr "VaÅ¡i registraci nelze zpracovat." + +#: ../../mod/register.php:421 +#, php-format +msgid "Registration request at %s" +msgstr "Žádost o registraci na %s" + +#: ../../mod/register.php:430 +msgid "Your registration is pending approval by the site owner." +msgstr "VaÅ¡e registrace Äeká na schválení vlastníkem serveru." + +#: ../../mod/register.php:479 +msgid "" +"You may (optionally) fill in this form via OpenID by supplying your OpenID " +"and clicking 'Register'." +msgstr "" +"Tento formulář můžete (volitelnÄ›) vyplnit s pomocí OpenID tím, že vyplníte " +"své OpenID a kliknutete na tlaÄítko 'Zaregistrovat'." + +#: ../../mod/register.php:480 +msgid "" +"If you are not familiar with OpenID, please leave that field blank and fill " +"in the rest of the items." +msgstr "" +"Pokud nepoužíváte OpenID, nechte prosím toto pole prázdné a vyplňte zbylé " +"položky." + +#: ../../mod/register.php:481 +msgid "Your OpenID (optional): " +msgstr "VaÅ¡e OpenID (nepovinné):" + +#: ../../mod/register.php:495 +msgid "Include your profile in member directory?" +msgstr "Uvést Váš profil v adresáři Älenů?" + +#: ../../mod/register.php:511 +msgid "Membership on this site is by invitation only." +msgstr "ÄŒlenství na tomto webu je pouze na pozvání." + +#: ../../mod/register.php:512 +msgid "Your invitation ID: " +msgstr "VaÅ¡e pozvání ID:" + +#: ../../mod/register.php:515 ../../mod/admin.php:299 +msgid "Registration" +msgstr "Registrace" + +#: ../../mod/register.php:523 +msgid "Your Full Name (e.g. Joe Smith): " +msgstr "VaÅ¡e celé jméno (napÅ™. Jan Novák):" + +#: ../../mod/register.php:524 +msgid "Your Email Address: " +msgstr "VaÅ¡e e-mailová adresa:" + +#: ../../mod/register.php:525 +msgid "" +"Choose a profile nickname. This must begin with a text character. Your " +"profile address on this site will then be " +"'nickname@$sitename'." +msgstr "" +"Vyberte pÅ™ezdívku k profilu. Ta musí zaÄít s textovým znakem. VaÅ¡e profilová" +" adresa na tomto webu pak bude \"pÅ™ezdívka@$sitename\"." + +#: ../../mod/register.php:526 +msgid "Choose a nickname: " +msgstr "Vyberte pÅ™ezdívku:" + +#: ../../mod/register.php:529 ../../include/nav.php:59 ../../boot.php:637 +msgid "Register" +msgstr "Registrovat" + +#: ../../mod/like.php:110 ../../addon/facebook/facebook.php:954 +#: ../../include/diaspora.php:446 ../../include/conversation.php:26 +#: ../../include/conversation.php:35 +msgid "status" +msgstr "Stav" + +#: ../../mod/like.php:127 ../../addon/facebook/facebook.php:958 +#: ../../include/diaspora.php:463 ../../include/conversation.php:43 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "%1$s má rád %2$s' na %3$s" + +#: ../../mod/like.php:129 ../../include/diaspora.php:465 +#: ../../include/conversation.php:46 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "%1$s nemá rád %2$s na %3$s" + +#: ../../mod/friendika.php:42 +msgid "This is Friendika version" +msgstr "Toto je Friendika verze" + +#: ../../mod/friendika.php:43 +msgid "running at web location" +msgstr "běžící na webu" + +#: ../../mod/friendika.php:45 +msgid "" +"Shared content within the Friendika network is provided under the Creative Commons " +"Attribution 3.0 license" +msgstr "" +"Sdílený obsah v síti Friendika je poskytována pod licencí Creative " +"Commons Attribution 3.0" + +#: ../../mod/friendika.php:47 +msgid "" +"Please visit Project.Friendika.com to learn " +"more about the Friendika project." +msgstr "" +"Pokud se chcete dozvÄ›dÄ›t více o projektu Friendika, navÅ¡tivte, prosím, Project.Friendika.com" + +#: ../../mod/friendika.php:49 +msgid "Bug reports and issues: please visit" +msgstr "Pro hlášení chyb a námÄ›tů na zmÄ›ny navÅ¡tivte:" + +#: ../../mod/friendika.php:50 +msgid "" +"Suggestions, praise, donations, etc. - please email \"Info\" at Friendika - " +"dot com" +msgstr "" +"Návrhy, chválu, dary, atd. - prosím poÅ¡lete na e-mail \"Info\" na Friendika " +"teÄka com" + +#: ../../mod/friendika.php:55 +msgid "Installed plugins/addons/apps" +msgstr "Nainstalované doplňky/aplikace" + +#: ../../mod/friendika.php:63 +msgid "No installed plugins/addons/apps" +msgstr "Nejsou žádné nainstalované doplňky/aplikace" + +#: ../../mod/regmod.php:61 +msgid "Account approved." +msgstr "ÚÄet schválen." + +#: ../../mod/regmod.php:93 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registrace zruÅ¡ena pro %s" + +#: ../../mod/regmod.php:105 +msgid "Please login." +msgstr "PÅ™ihlaste se, prosím." + +#: ../../mod/item.php:81 +msgid "Unable to locate original post." +msgstr "Nelze nalézt původní příspÄ›vek." + +#: ../../mod/item.php:196 +msgid "Empty post discarded." +msgstr "Prázdný příspÄ›vek odstranÄ›n." + +#: ../../mod/item.php:296 ../../mod/message.php:93 +#: ../../mod/wall_upload.php:81 ../../mod/wall_upload.php:90 +#: ../../mod/wall_upload.php:97 +msgid "Wall Photos" +msgstr "Fotografie na zdi" + +#: ../../mod/item.php:623 ../../mod/item.php:668 ../../mod/item.php:691 +#: ../../mod/item.php:734 ../../mod/dfrn_notify.php:293 +#: ../../mod/dfrn_notify.php:503 ../../mod/dfrn_notify.php:548 +#: ../../mod/dfrn_notify.php:634 ../../mod/dfrn_notify.php:677 +msgid "noreply" +msgstr "bez odpovÄ›di" + +#: ../../mod/item.php:667 ../../mod/item.php:733 ../../mod/dfrn_notify.php:676 +msgid "Administrator@" +msgstr "Administrator@" + +#: ../../mod/item.php:670 ../../mod/dfrn_notify.php:550 +#: ../../mod/dfrn_notify.php:679 +#, php-format +msgid "%s commented on an item at %s" +msgstr "%s okomentoval položku v %s" + +#: ../../mod/item.php:736 +#, php-format +msgid "%s posted to your profile wall at %s" +msgstr "%s pÅ™idal příspÄ›vek na vaší profilovou zeÄ v %s" + +#: ../../mod/item.php:765 +msgid "System error. Post not saved." +msgstr "Chyba systému. PříspÄ›vek nebyl uložen." + +#: ../../mod/item.php:784 +#, php-format +msgid "" +"This message was sent to you by %s, a member of the Friendika social " +"network." +msgstr "Tuto zprávu Vám zaslal %s, Älen sociální sítÄ› Friendika." + +#: ../../mod/item.php:786 +#, php-format +msgid "You may visit them online at %s" +msgstr "Můžete je navÅ¡tívit online na adrese %s" + +#: ../../mod/item.php:787 +msgid "" +"Please contact the sender by replying to this post if you do not wish to " +"receive these messages." +msgstr "" +"Pokud nechcete dostávat tyto zprávy, kontaktujte prosím odesilatele odpovÄ›dí" +" na tento záznam." + +#: ../../mod/item.php:789 +#, php-format +msgid "%s posted an update." +msgstr "%s poslal aktualizaci." + +#: ../../mod/profile_photo.php:28 +msgid "Image uploaded but image cropping failed." +msgstr "Obrázek byl odeslán, ale jeho oříznutí se nesdaÅ™ilo." + +#: ../../mod/profile_photo.php:61 ../../mod/profile_photo.php:68 +#: ../../mod/profile_photo.php:75 ../../mod/profile_photo.php:248 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "NepodaÅ™ilo se snížit velikost obrázku [%s]." + +#: ../../mod/profile_photo.php:95 +msgid "Unable to process image" +msgstr "Obrázek nelze zpracovat " + +#: ../../mod/profile_photo.php:109 ../../mod/wall_upload.php:56 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "Obrázek pÅ™ekroÄil limit velikosti %d" + +#: ../../mod/profile_photo.php:193 +msgid "Upload File:" +msgstr "Nahrát soubor:" + +#: ../../mod/profile_photo.php:194 +msgid "Upload Profile Photo" +msgstr "Nahrát profilovou fotografii" + +#: ../../mod/profile_photo.php:195 +msgid "Upload" +msgstr "Nahrát" + +#: ../../mod/profile_photo.php:196 +msgid "skip this step" +msgstr "pÅ™eskoÄit tento krok " + +#: ../../mod/profile_photo.php:196 +msgid "select a photo from your photo albums" +msgstr "Vybrat fotografii z VaÅ¡ich fotoalb" + +#: ../../mod/profile_photo.php:209 +msgid "Crop Image" +msgstr "Oříznout obrázek" + +#: ../../mod/profile_photo.php:210 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Prosím, oříznÄ›te tento obrázek pro optimální zobrazení." + +#: ../../mod/profile_photo.php:211 +msgid "Done Editing" +msgstr "Editace dokonÄena" + +#: ../../mod/profile_photo.php:239 +msgid "Image uploaded successfully." +msgstr "Obrázek byl úspěšnÄ› nahrán." + +#: ../../mod/hcard.php:11 ../../mod/profile.php:11 ../../boot.php:792 +msgid "No profile" +msgstr "Žádný profil" + +#: ../../mod/removeme.php:42 ../../mod/removeme.php:45 +msgid "Remove My Account" +msgstr "Odstranit můj úÄet" + +#: ../../mod/removeme.php:43 +msgid "" +"This will completely remove your account. Once this has been done it is not " +"recoverable." +msgstr "" +"Tímto bude kompletnÄ› odstranÄ›n váš úÄet. Jakmile bude úÄet odstranÄ›n, nebude" +" už možné ho obnovit." + +#: ../../mod/removeme.php:44 +msgid "Please enter your password for verification:" +msgstr "Prosím, zadejte své heslo pro ověření:" + +#: ../../mod/message.php:18 +msgid "No recipient selected." +msgstr "Nevybrán příjemce." + +#: ../../mod/message.php:23 +msgid "[no subject]" +msgstr "[bez pÅ™edmÄ›tu]" + +#: ../../mod/message.php:34 +msgid "Unable to locate contact information." +msgstr "NepodaÅ™ilo se najít kontaktní informace." + +#: ../../mod/message.php:102 +msgid "Message sent." +msgstr "Zpráva odeslána." + +#: ../../mod/message.php:105 +msgid "Message could not be sent." +msgstr "Zprávu se nepodaÅ™ilo odeslat." + +#: ../../mod/message.php:125 ../../include/nav.php:102 +msgid "Messages" +msgstr "Zprávy" + +#: ../../mod/message.php:126 +msgid "Inbox" +msgstr "DoruÄená poÅ¡ta" + +#: ../../mod/message.php:127 +msgid "Outbox" +msgstr "Odeslaná poÅ¡ta" + +#: ../../mod/message.php:128 +msgid "New Message" +msgstr "Nová zpráva" + +#: ../../mod/message.php:142 +msgid "Message deleted." +msgstr "Zpráva odstranÄ›na." + +#: ../../mod/message.php:158 +msgid "Conversation removed." +msgstr "Konverzace odstranÄ›na." + +#: ../../mod/message.php:172 ../../include/conversation.php:699 +msgid "Please enter a link URL:" +msgstr "Zadejte prosím URL odkaz:" + +#: ../../mod/message.php:180 +msgid "Send Private Message" +msgstr "Odeslat soukromou zprávu" + +#: ../../mod/message.php:181 ../../mod/message.php:315 +msgid "To:" +msgstr "Adresát:" + +#: ../../mod/message.php:182 ../../mod/message.php:316 +msgid "Subject:" +msgstr "PÅ™edmÄ›t:" + +#: ../../mod/message.php:185 ../../mod/message.php:319 +#: ../../mod/invite.php:101 +msgid "Your message:" +msgstr "VaÅ¡e zpráva:" + +#: ../../mod/message.php:224 +msgid "No messages." +msgstr "Žádné zprávy." + +#: ../../mod/message.php:237 +msgid "Delete conversation" +msgstr "Odstranit konverzaci" + +#: ../../mod/message.php:240 +msgid "D, d M Y - g:i A" +msgstr "D M R - g:i A" + +#: ../../mod/message.php:267 +msgid "Message not available." +msgstr "Zpráva není k dispozici." + +#: ../../mod/message.php:304 +msgid "Delete message" +msgstr "Smazat zprávu" + +#: ../../mod/message.php:314 +msgid "Send Reply" +msgstr "Poslat odpovÄ›Ä" + +#: ../../mod/admin.php:66 ../../mod/admin.php:297 +msgid "Site" +msgstr "Web" + +#: ../../mod/admin.php:67 ../../mod/admin.php:460 ../../mod/admin.php:472 +msgid "Users" +msgstr "Uživatelé" + +#: ../../mod/admin.php:68 ../../mod/admin.php:549 ../../mod/admin.php:586 +msgid "Plugins" +msgstr "Pluginy" + +#: ../../mod/admin.php:69 +msgid "Update" +msgstr "Aktualizace" + +#: ../../mod/admin.php:83 ../../mod/admin.php:651 +msgid "Logs" +msgstr "Logy" + +#: ../../mod/admin.php:88 +msgid "User registrations waiting for confirmation" +msgstr "Registrace uživatele Äeká na potvrzení" + +#: ../../mod/admin.php:118 ../../mod/admin.php:502 ../../mod/display.php:25 +#: ../../mod/display.php:112 ../../include/items.php:1842 +msgid "Item not found." +msgstr "Položka nenalezena." + +#: ../../mod/admin.php:151 ../../mod/admin.php:296 ../../mod/admin.php:459 +#: ../../mod/admin.php:548 ../../mod/admin.php:585 ../../mod/admin.php:650 +msgid "Administration" +msgstr "Administrace" + +#: ../../mod/admin.php:152 +msgid "Summary" +msgstr "Shrnutí" + +#: ../../mod/admin.php:153 +msgid "Registered users" +msgstr "Registrovaní uživatelé" + +#: ../../mod/admin.php:155 +msgid "Pending registrations" +msgstr "ÄŒekající registrace" + +#: ../../mod/admin.php:156 +msgid "Version" +msgstr "Verze" + +#: ../../mod/admin.php:158 +msgid "Active plugins" +msgstr "Aktivní pluginy" + +#: ../../mod/admin.php:245 +msgid "Site settings updated." +msgstr "Nastavení webu aktualizováno." + +#: ../../mod/admin.php:289 +msgid "Closed" +msgstr "Uzavřít" + +#: ../../mod/admin.php:290 +msgid "Requires approval" +msgstr "Vyžaduje schválení" + +#: ../../mod/admin.php:291 +msgid "Open" +msgstr "OtevÅ™ená" + +#: ../../mod/admin.php:300 +msgid "File upload" +msgstr "Nahrání souborů" + +#: ../../mod/admin.php:301 +msgid "Policies" +msgstr "Politiky" + +#: ../../mod/admin.php:302 +msgid "Advanced" +msgstr "PokroÄilé" + +#: ../../mod/admin.php:306 ../../addon/statusnet/statusnet.php:459 +msgid "Site name" +msgstr "Název webu" + +#: ../../mod/admin.php:307 +msgid "Banner/Logo" +msgstr "Banner/logo" + +#: ../../mod/admin.php:308 +msgid "System language" +msgstr "Systémový jazyk" + +#: ../../mod/admin.php:309 +msgid "System theme" +msgstr "Grafická Å¡ablona systému " + +#: ../../mod/admin.php:311 +msgid "Maximum image size" +msgstr "Maximální velikost obrazu" + +#: ../../mod/admin.php:313 +msgid "Register policy" +msgstr "Politika registrace" + +#: ../../mod/admin.php:314 +msgid "Register text" +msgstr "Registrace textu" + +#: ../../mod/admin.php:315 +msgid "Allowed friend domains" +msgstr "Povolené domény přátel" + +#: ../../mod/admin.php:316 +msgid "Allowed email domains" +msgstr "Povolené e-mailové domény" + +#: ../../mod/admin.php:317 +msgid "Block public" +msgstr "Blokovat veÅ™ejnost" + +#: ../../mod/admin.php:318 +msgid "Force publish" +msgstr "Publikovat" + +#: ../../mod/admin.php:319 +msgid "Global directory update URL" +msgstr "aktualizace URL adresy Globálního adresáře " + +#: ../../mod/admin.php:321 +msgid "Block multiple registrations" +msgstr "Blokovat více registrací" + +#: ../../mod/admin.php:322 +msgid "OpenID support" +msgstr "podpora OpenID" + +#: ../../mod/admin.php:323 +msgid "Gravatar support" +msgstr "podpora Gravatar" + +#: ../../mod/admin.php:324 +msgid "Fullname check" +msgstr "kontrola úplného jména" + +#: ../../mod/admin.php:325 +msgid "UTF-8 Regular expressions" +msgstr "UTF-8 Regulární výrazy" + +#: ../../mod/admin.php:326 +msgid "Show Community Page" +msgstr "Zobrazit stránku komunity" + +#: ../../mod/admin.php:327 +msgid "Enable OStatus support" +msgstr "Zapnout podporu OStatus" + +#: ../../mod/admin.php:328 +msgid "Only allow Friendika contacts" +msgstr "Povolit pouze Friendika kontakty " + +#: ../../mod/admin.php:329 +msgid "Verify SSL" +msgstr "Ověřit SSL" + +#: ../../mod/admin.php:330 +msgid "Proxy user" +msgstr "Proxy uživatel" + +#: ../../mod/admin.php:331 +msgid "Proxy URL" +msgstr "Proxy URL adresa" + +#: ../../mod/admin.php:332 +msgid "Network timeout" +msgstr "Äas síťového spojení vyprÅ¡elo (timeout)" + +#: ../../mod/admin.php:353 +#, php-format +msgid "%s user blocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s uživatel zablokován" +msgstr[1] "%s uživatelů zablokováno / odblokováno" +msgstr[2] "%s uživatelů zablokováno / odblokováno" + +#: ../../mod/admin.php:360 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s uživatel smazán" +msgstr[1] "%s uživatelů smazáno" +msgstr[2] "%s uživatelů smazáno" + +#: ../../mod/admin.php:394 +#, php-format +msgid "User '%s' deleted" +msgstr "Uživatel '%s' smazán" + +#: ../../mod/admin.php:401 +#, php-format +msgid "User '%s' unblocked" +msgstr "Uživatel '%s' odblokován" + +#: ../../mod/admin.php:401 +#, php-format +msgid "User '%s' blocked" +msgstr "Uživatel '%s' blokován" + +#: ../../mod/admin.php:462 +msgid "select all" +msgstr "Vybrat vÅ¡e" + +#: ../../mod/admin.php:463 +msgid "User registrations waiting for confirm" +msgstr "Registrace uživatele Äeká na potvrzení" + +#: ../../mod/admin.php:464 +msgid "Request date" +msgstr "Datum žádosti" + +#: ../../mod/admin.php:464 ../../mod/admin.php:473 +msgid "Email" +msgstr "E-mail" + +#: ../../mod/admin.php:465 +msgid "No registrations." +msgstr "Žádné registrace." + +#: ../../mod/admin.php:467 +msgid "Deny" +msgstr "Odmítnout" + +#: ../../mod/admin.php:469 +msgid "Block" +msgstr "Blokovat" + +#: ../../mod/admin.php:470 +msgid "Unblock" +msgstr "Odblokovat" + +#: ../../mod/admin.php:473 +msgid "Register date" +msgstr "Datum registrace" + +#: ../../mod/admin.php:473 +msgid "Last login" +msgstr "Datum posledního pÅ™ihlášení" + +#: ../../mod/admin.php:473 +msgid "Last item" +msgstr "Poslední položka" + +#: ../../mod/admin.php:473 +msgid "Account" +msgstr "ÚÄet" + +#: ../../mod/admin.php:475 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" +"Vybraní uživatelé budou smazáni!\\n\\n VÅ¡e, co tito uživatelé na tÄ›chto " +"stránkách vytvoÅ™ili, bude trvale odstranÄ›no!\\n\\n Opravdu pokraÄovat?" + +#: ../../mod/admin.php:476 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "" +"Uživatel {0} bude smazán!\\n\\n VÅ¡e, co tento uživatel na tÄ›chto stránkách " +"vytvoÅ™il, bude trvale odstranÄ›no!\\n\\n Opravdu pokraÄovat?" + +#: ../../mod/admin.php:512 +#, php-format +msgid "Plugin %s disabled." +msgstr "Plugin %s zakázán." + +#: ../../mod/admin.php:516 +#, php-format +msgid "Plugin %s enabled." +msgstr "Plugin %s povolen." + +#: ../../mod/admin.php:526 +msgid "Disable" +msgstr "Zakázat" + +#: ../../mod/admin.php:528 +msgid "Enable" +msgstr "Povolit" + +#: ../../mod/admin.php:550 +msgid "Toggle" +msgstr "PÅ™epnout" + +#: ../../mod/admin.php:551 ../../include/nav.php:108 +msgid "Settings" +msgstr "Nastavení" + +#: ../../mod/admin.php:613 +msgid "Log settings updated." +msgstr "Nastavení protokolu aktualizováno." + +#: ../../mod/admin.php:653 +msgid "Clear" +msgstr "VyÄistit" + +#: ../../mod/admin.php:659 +msgid "Debugging" +msgstr "LadÄ›ní" + +#: ../../mod/admin.php:660 +msgid "Log file" +msgstr "Soubor s logem" + +#: ../../mod/admin.php:660 +msgid "Must be writable by web server. Relative to your Friendika index.php." +msgstr "" +"Webový server musí mít práva zápisu . Relativní k index.php Friendika." + +#: ../../mod/admin.php:661 +msgid "Log level" +msgstr "Úroveň auditu" + +#: ../../mod/admin.php:702 +msgid "Close" +msgstr "UzavÅ™ená" + +#: ../../mod/admin.php:708 +msgid "FTP Host" +msgstr "Hostitel FTP" + +#: ../../mod/admin.php:709 +msgid "FTP Path" +msgstr "Cesta FTP" + +#: ../../mod/admin.php:710 +msgid "FTP User" +msgstr "FTP uživatel" + +#: ../../mod/admin.php:711 +msgid "FTP Password" +msgstr "FTP heslo" + +#: ../../mod/profile.php:102 ../../mod/display.php:63 +msgid "Access to this profile has been restricted." +msgstr "Přístup na tento profil byl omezen." + +#: ../../mod/profile.php:133 +msgid "Tips for New Members" +msgstr "Tipy pro nové Äleny" + +#: ../../mod/openid.php:62 ../../mod/openid.php:122 ../../include/auth.php:120 +#: ../../include/auth.php:145 ../../include/auth.php:198 +msgid "Login failed." +msgstr "PÅ™ihlášení se nezdaÅ™ilo." + +#: ../../mod/openid.php:78 ../../include/auth.php:214 +msgid "Welcome " +msgstr "Vítejte " + +#: ../../mod/openid.php:79 ../../include/auth.php:215 +msgid "Please upload a profile photo." +msgstr "Prosím nahrejte profilovou fotografii" + +#: ../../mod/openid.php:82 ../../include/auth.php:218 +msgid "Welcome back " +msgstr "Vítejte zpÄ›t " + +#: ../../mod/follow.php:39 +msgid "" +"This site is not configured to allow communications with other networks." +msgstr "" +"Tento web není nakonfigurován tak, aby umožňoval komunikaci s ostatními " +"sítÄ›mi." + +#: ../../mod/follow.php:40 ../../mod/follow.php:50 +msgid "No compatible communication protocols or feeds were discovered." +msgstr "Nenalezen žádný kompatibilní komunikaÄní protokol nebo kanál." + +#: ../../mod/follow.php:48 +msgid "The profile address specified does not provide adequate information." +msgstr "Uvedená adresa profilu neposkytuje dostateÄné informace." + +#: ../../mod/follow.php:52 +msgid "An author or name was not found." +msgstr "Autor nebo jméno nenalezeno" + +#: ../../mod/follow.php:54 +msgid "No browser URL could be matched to this address." +msgstr "Této adrese neodpovídá žádné URL prohlížeÄe." + +#: ../../mod/follow.php:61 +msgid "" +"The profile address specified belongs to a network which has been disabled " +"on this site." +msgstr "" +"Zadaná adresa profilu patří do sítÄ›, která byla na tomto serveru zakázána." + +#: ../../mod/follow.php:66 +msgid "" +"Limited profile. This person will be unable to receive direct/personal " +"notifications from you." +msgstr "" +"Omezený profil. Tato osoba nebude schopna od Vás pÅ™ijímat přímé / osobní " +"sdÄ›lení." + +#: ../../mod/follow.php:122 +msgid "Unable to retrieve contact information." +msgstr "NepodaÅ™ilo se získat kontaktní informace." + +#: ../../mod/follow.php:168 +msgid "following" +msgstr "následující" + +#: ../../mod/display.php:105 +msgid "Item has been removed." +msgstr "Položka byla odstranÄ›na." + +#: ../../mod/dfrn_notify.php:353 +msgid "New mail received at " +msgstr "PÅ™iÅ¡el nový e-mail v" + +#: ../../mod/apps.php:6 +msgid "Applications" +msgstr "Aplikace" + +#: ../../mod/apps.php:11 +msgid "No installed applications." +msgstr "Žádné nainstalované aplikace." + +#: ../../mod/search.php:26 ../../include/text.php:610 ../../include/nav.php:69 +msgid "Search" +msgstr "Vyhledávání" + +#: ../../mod/profiles.php:21 ../../mod/profiles.php:236 +#: ../../mod/profiles.php:341 ../../mod/dfrn_confirm.php:62 +msgid "Profile not found." +msgstr "Profil nenalezen" + +#: ../../mod/profiles.php:28 +msgid "Profile Name is required." +msgstr "Jméno profilu je povinné." + +#: ../../mod/profiles.php:198 +msgid "Profile updated." +msgstr "Profil aktualizován." + +#: ../../mod/profiles.php:253 +msgid "Profile deleted." +msgstr "Profil smazán." + +#: ../../mod/profiles.php:269 ../../mod/profiles.php:300 +msgid "Profile-" +msgstr "Profil-" + +#: ../../mod/profiles.php:288 ../../mod/profiles.php:327 +msgid "New profile created." +msgstr "Nový profil vytvoÅ™en." + +#: ../../mod/profiles.php:306 +msgid "Profile unavailable to clone." +msgstr "Profil není možné naklonovat." + +#: ../../mod/profiles.php:353 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "" +"Skrýt u tohoto profilu vaÅ¡e kontakty / seznam přátel pÅ™ed pÅ™ed dalšími " +"uživateli zobrazující si tento profil?" + +#: ../../mod/profiles.php:371 +msgid "Edit Profile Details" +msgstr "Upravit podrobnosti profilu " + +#: ../../mod/profiles.php:373 +msgid "View this profile" +msgstr "Zobrazit tento profil" + +#: ../../mod/profiles.php:374 +msgid "Create a new profile using these settings" +msgstr "VytvoÅ™it nový profil pomocí tohoto nastavení" + +#: ../../mod/profiles.php:375 +msgid "Clone this profile" +msgstr "Klonovat tento profil" + +#: ../../mod/profiles.php:376 +msgid "Delete this profile" +msgstr "Smazat tento profil" + +#: ../../mod/profiles.php:377 +msgid "Profile Name:" +msgstr "Jméno profilu:" + +#: ../../mod/profiles.php:378 +msgid "Your Full Name:" +msgstr "VaÅ¡e celé jméno:" + +#: ../../mod/profiles.php:379 +msgid "Title/Description:" +msgstr "Název / Popis:" + +#: ../../mod/profiles.php:380 +msgid "Your Gender:" +msgstr "VaÅ¡e pohlaví:" + +#: ../../mod/profiles.php:381 +#, php-format +msgid "Birthday (%s):" +msgstr "Narozeniny uživatele (%s):" + +#: ../../mod/profiles.php:382 +msgid "Street Address:" +msgstr "Ulice:" + +#: ../../mod/profiles.php:383 +msgid "Locality/City:" +msgstr "MÄ›sto:" + +#: ../../mod/profiles.php:384 +msgid "Postal/Zip Code:" +msgstr "PSÄŒ:" + +#: ../../mod/profiles.php:385 +msgid "Country:" +msgstr "ZemÄ›:" + +#: ../../mod/profiles.php:386 +msgid "Region/State:" +msgstr "Region / stát:" + +#: ../../mod/profiles.php:387 +msgid " Marital Status:" +msgstr " Rodinný stav:" + +#: ../../mod/profiles.php:388 +msgid "Who: (if applicable)" +msgstr "Kdo: (pokud je možné)" + +#: ../../mod/profiles.php:389 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Příklady: jan123, Jan Novák, jan@seznam.cz" + +#: ../../mod/profiles.php:390 ../../include/profile_advanced.php:90 +msgid "Sexual Preference:" +msgstr "Sexuální preference:" + +#: ../../mod/profiles.php:391 +msgid "Homepage URL:" +msgstr "Odkaz na domovskou stránku:" + +#: ../../mod/profiles.php:392 ../../include/profile_advanced.php:115 +msgid "Political Views:" +msgstr "Politické pÅ™esvÄ›dÄení:" + +#: ../../mod/profiles.php:393 +msgid "Religious Views:" +msgstr "Náboženské pÅ™esvÄ›dÄení:" + +#: ../../mod/profiles.php:394 +msgid "Public Keywords:" +msgstr "VeÅ™ejná klíÄová slova:" + +#: ../../mod/profiles.php:395 +msgid "Private Keywords:" +msgstr "Soukromá klíÄová slova:" + +#: ../../mod/profiles.php:396 +msgid "Example: fishing photography software" +msgstr "Příklad: fishing photography software" + +#: ../../mod/profiles.php:397 +msgid "(Used for suggesting potential friends, can be seen by others)" +msgstr "" +"(Používá se pro doporuÄování potenciálních přátel, může být vidÄ›no " +"ostatními)" + +#: ../../mod/profiles.php:398 +msgid "(Used for searching profiles, never shown to others)" +msgstr "(Používá se pro vyhledávání profilů, není nikdy zobrazeno ostatním)" + +#: ../../mod/profiles.php:399 +msgid "Tell us about yourself..." +msgstr "ŘeknÄ›te nám nÄ›co o sobÄ› ..." + +#: ../../mod/profiles.php:400 +msgid "Hobbies/Interests" +msgstr "KoníÄky/zájmy" + +#: ../../mod/profiles.php:401 +msgid "Contact information and Social Networks" +msgstr "Kontaktní informace a sociální sítÄ›" + +#: ../../mod/profiles.php:402 +msgid "Musical interests" +msgstr "Hudební vkus" + +#: ../../mod/profiles.php:403 +msgid "Books, literature" +msgstr "Knihy, literatura" + +#: ../../mod/profiles.php:404 +msgid "Television" +msgstr "Televize" + +#: ../../mod/profiles.php:405 +msgid "Film/dance/culture/entertainment" +msgstr "Film/tanec/kultura/zábava" + +#: ../../mod/profiles.php:406 +msgid "Love/romance" +msgstr "Láska/romantika" + +#: ../../mod/profiles.php:407 +msgid "Work/employment" +msgstr "Práce/zamÄ›stnání" + +#: ../../mod/profiles.php:408 +msgid "School/education" +msgstr "Å kola/vzdÄ›lání" + +#: ../../mod/profiles.php:413 +msgid "" +"This is your public profile.
    It may " +"be visible to anybody using the internet." +msgstr "" +"Toto je váš veřejný profil.
    Ten může " +"být viditelný kýmkoliv na internetu." + +#: ../../mod/profiles.php:423 ../../mod/directory.php:112 +msgid "Age: " +msgstr "VÄ›k: " + +#: ../../mod/profiles.php:458 ../../include/nav.php:109 +msgid "Profiles" +msgstr "Profily" + +#: ../../mod/profiles.php:459 +msgid "Change profile photo" +msgstr "ZmÄ›nit profilovou fotografii" + +#: ../../mod/profiles.php:460 +msgid "Create New Profile" +msgstr "VytvoÅ™it nový profil" + +#: ../../mod/profiles.php:470 +msgid "Profile Image" +msgstr "Profilový obrázek" + +#: ../../mod/profiles.php:472 +msgid "visible to everybody" +msgstr "viditelné pro vÅ¡echny" + +#: ../../mod/profiles.php:473 +msgid "Edit visibility" +msgstr "Upravit viditelnost" + +#: ../../mod/directory.php:40 +msgid "Global Directory" +msgstr "Globální adresář" + +#: ../../mod/directory.php:46 +msgid "Normal site view" +msgstr "Normální zobrazení stránky" + +#: ../../mod/directory.php:48 +msgid "View all site entries" +msgstr "Zobrazit vÅ¡echny položky stránky" + +#: ../../mod/directory.php:56 +msgid "Site Directory" +msgstr "Adresář serveru" + +#: ../../mod/directory.php:115 +msgid "Gender: " +msgstr "Pohlaví: " + +#: ../../mod/directory.php:141 +msgid "No entries (some entries may be hidden)." +msgstr "Žádné záznamy (nÄ›které položky mohou být skryty)." + +#: ../../mod/invite.php:35 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s : není platná e-mailová adresa." + +#: ../../mod/invite.php:59 +#, php-format +msgid "Please join my network on %s" +msgstr "Prosím, pÅ™ipojte se do mé sítÄ› na %s" + +#: ../../mod/invite.php:69 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : DoruÄení zprávy se nezdaÅ™ilo." + +#: ../../mod/invite.php:73 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d zpráva odeslána." +msgstr[1] "%d zprávy odeslány." +msgstr[2] "%d zprávy odeslány." + +#: ../../mod/invite.php:92 +msgid "You have no more invitations available" +msgstr "Nemáte k dispozici žádné další pozvánky" + +#: ../../mod/invite.php:99 +msgid "Send invitations" +msgstr "Poslat pozvánky" + +#: ../../mod/invite.php:100 +msgid "Enter email addresses, one per line:" +msgstr "Zadejte e-mailové adresy, jednu na řádek:" + +#: ../../mod/invite.php:102 +#, php-format +msgid "Please join my social network on %s" +msgstr "Prosím, pÅ™ipojte se do mé sociální sítÄ› na %s" + +#: ../../mod/invite.php:103 +msgid "To accept this invitation, please visit:" +msgstr "Chcete-li toto pozvání pÅ™ijmout, navÅ¡tivte prosím:" + +#: ../../mod/invite.php:104 +msgid "You will need to supply this invitation code: $invite_code" +msgstr "Budete muset zadat kód této pozvánky: $invite_code" + +#: ../../mod/invite.php:104 +msgid "" +"Once you have registered, please connect with me via my profile page at:" +msgstr "" +"Jakmile se zaregistrujete, prosím spojte se se mnou pÅ™es mou profilovu " +"stránku na:" + +#: ../../mod/dfrn_confirm.php:233 +msgid "Response from remote site was not understood." +msgstr "OdpovÄ›Ä ze vzdáleného serveru nebyla srozumitelná." + +#: ../../mod/dfrn_confirm.php:242 +msgid "Unexpected response from remote site: " +msgstr "NeoÄekávaná odpovÄ›Ä od vzdáleného serveru:" + +#: ../../mod/dfrn_confirm.php:250 +msgid "Confirmation completed successfully." +msgstr "Potvrzení úspěšnÄ› dokonÄena." + +#: ../../mod/dfrn_confirm.php:252 ../../mod/dfrn_confirm.php:266 +#: ../../mod/dfrn_confirm.php:273 +msgid "Remote site reported: " +msgstr "Vzdálený server oznámil:" + +#: ../../mod/dfrn_confirm.php:264 +msgid "Temporary failure. Please wait and try again." +msgstr "DoÄasné selhání. Prosím, vyÄkejte a zkuste to znovu." + +#: ../../mod/dfrn_confirm.php:271 +msgid "Introduction failed or was revoked." +msgstr "Žádost o propojení selhala nebo byla zruÅ¡ena." + +#: ../../mod/dfrn_confirm.php:393 +msgid "Unable to set contact photo." +msgstr "Nelze nastavit fotografii kontaktu." + +#: ../../mod/dfrn_confirm.php:436 ../../include/conversation.php:79 +#, php-format +msgid "%1$s is now friends with %2$s" +msgstr "%1$s je nyní přítel s %2$s" + +#: ../../mod/dfrn_confirm.php:507 +#, php-format +msgid "No user record found for '%s' " +msgstr "Pro '%s' nenalezen žádný uživatelský záznam " + +#: ../../mod/dfrn_confirm.php:517 +msgid "Our site encryption key is apparently messed up." +msgstr "Náš Å¡ifrovací klÃ­Ä zÅ™ejmÄ› pÅ™estal správnÄ› fungovat." + +#: ../../mod/dfrn_confirm.php:528 +msgid "Empty site URL was provided or URL could not be decrypted by us." +msgstr "" +"Byla poskytnuta prázdná URL adresa nebo se nepodaÅ™ilo URL adresu deÅ¡ifrovat." + +#: ../../mod/dfrn_confirm.php:549 +msgid "Contact record was not found for you on our site." +msgstr "Kontakt záznam nebyl nalezen pro vás na naÅ¡ich stránkách." + +#: ../../mod/dfrn_confirm.php:578 +msgid "" +"The ID provided by your system is a duplicate on our system. It should work " +"if you try again." +msgstr "" +"Váš systém poskytl duplicitní ID vůÄi naÅ¡emu systému. Pokuste se akci " +"zopakovat." + +#: ../../mod/dfrn_confirm.php:589 +msgid "Unable to set your contact credentials on our system." +msgstr "Nelze nastavit VaÅ¡e pÅ™ihlaÅ¡ovací údaje v naÅ¡em systému." + +#: ../../mod/dfrn_confirm.php:642 +msgid "Unable to update your contact profile details on our system" +msgstr "Nelze aktualizovat Váš profil v naÅ¡em systému" + +#: ../../mod/dfrn_confirm.php:672 +#, php-format +msgid "Connection accepted at %s" +msgstr "PÅ™ipojení pÅ™ijato na %s" + +#: ../../addon/facebook/facebook.php:314 +msgid "Facebook disabled" +msgstr "Facebook zakázán" + +#: ../../addon/facebook/facebook.php:319 +msgid "Updating contacts" +msgstr "Aktualizace kontaktů" + +#: ../../addon/facebook/facebook.php:328 +msgid "Facebook API key is missing." +msgstr "Chybí Facebook API klíÄ." + +#: ../../addon/facebook/facebook.php:335 +msgid "Facebook Connect" +msgstr "Facebook pÅ™ipojen" + +#: ../../addon/facebook/facebook.php:341 +msgid "Install Facebook connector for this account." +msgstr "Nainstalovat pro tento úÄet Facebook konektor." + +#: ../../addon/facebook/facebook.php:348 +msgid "Remove Facebook connector" +msgstr "Odstranit konektor na Facebook" + +#: ../../addon/facebook/facebook.php:354 +msgid "Post to Facebook by default" +msgstr "StandardnÄ› posílat příspÄ›vky na Facebook" + +#: ../../addon/facebook/facebook.php:358 +msgid "Link all your Facebook friends and conversations" +msgstr "PÅ™ipojit vÅ¡echny své přátele na Facebooku a konverzace" + +#: ../../addon/facebook/facebook.php:363 +msgid "Warning: Your Facebook privacy settings can not be imported." +msgstr "" +"UpozornÄ›ní: nastavení ochrany osobních údajů na Facebooku nelze importovat." + +#: ../../addon/facebook/facebook.php:364 +msgid "" +"Linked Facebook items may be publicly visible, depending on" +" your privacy settings for this website/account." +msgstr "" +"Propojené položky z Facebook mohou být veÅ™ejnÄ› viditelné, v" +" závislosti na nastavení ochrany osobních údajů pro tuto webovou " +"stránku/úÄet." + +#: ../../addon/facebook/facebook.php:419 +msgid "Facebook" +msgstr "Facebook" + +#: ../../addon/facebook/facebook.php:420 +msgid "Facebook Connector Settings" +msgstr "Nastavení Facebook konektoru " + +#: ../../addon/facebook/facebook.php:434 +msgid "Post to Facebook" +msgstr "PÅ™idat příspÄ›vek na Facebook" + +#: ../../addon/facebook/facebook.php:507 +msgid "" +"Post to Facebook cancelled because of multi-network access permission " +"conflict." +msgstr "" +"PříspÄ›vek na Facebook zruÅ¡en kvůli konfliktu přístupových práv mezi sítÄ›mi." + +#: ../../addon/facebook/facebook.php:580 +msgid "Image: " +msgstr "Obrázek: " + +#: ../../addon/facebook/facebook.php:656 +msgid "View on Friendika" +msgstr "Pohled na Friendiku" + +#: ../../addon/facebook/facebook.php:687 +msgid "Facebook post failed. Queued for retry." +msgstr "" +"Zaslání příspÄ›vku na Facebook selhalo. PříspÄ›vek byl zaÅ™azen do fronty pro " +"opakované odeslání." + +#: ../../addon/widgets/widgets.php:53 +msgid "Generate new key" +msgstr "Generovat nové klíÄe" + +#: ../../addon/widgets/widgets.php:56 +msgid "Widgets key" +msgstr "Widgety klíÄ" + +#: ../../addon/widgets/widgets.php:58 +msgid "Widgets available" +msgstr "Widgety k dispozici" + +#: ../../addon/widgets/widget_friends.php:30 +msgid "Connect on Friendika!" +msgstr "Spojit se na Friendice!" + +#: ../../addon/tictac/tictac.php:20 +msgid "Three Dimensional Tic-Tac-Toe" +msgstr "TrojrozmÄ›rné Tic-Tac-Toe" + +#: ../../addon/tictac/tictac.php:53 +msgid "3D Tic-Tac-Toe" +msgstr "3D Tic-Tac-Toe" + +#: ../../addon/tictac/tictac.php:58 +msgid "New game" +msgstr "Nová hra" + +#: ../../addon/tictac/tictac.php:59 +msgid "New game with handicap" +msgstr "Nová hra s handicapem" + +#: ../../addon/tictac/tictac.php:60 +msgid "" +"Three dimensional tic-tac-toe is just like the traditional game except that " +"it is played on multiple levels simultaneously. " +msgstr "" +"TrojrozmÄ›rné tic-tac-toe je podobná této tradiÄní hÅ™e kromÄ› toho, že se " +"hraje na více úrovních souÄasnÄ›." + +#: ../../addon/tictac/tictac.php:61 +msgid "" +"In this case there are three levels. You win by getting three in a row on " +"any level, as well as up, down, and diagonally across the different levels." +msgstr "" +"V tomto případÄ› existují tÅ™i úrovnÄ›. Vyhrajete tím, že dostane tÅ™i v Å™adÄ› na" +" jakékoli úrovni, stejnÄ› jako nahoru, dolů a Å¡ikmo na různých úrovních." + +#: ../../addon/tictac/tictac.php:63 +msgid "" +"The handicap game disables the center position on the middle level because " +"the player claiming this square often has an unfair advantage." +msgstr "" +"Hra s handicapem zakáže centrální pozici na stÅ™ední úrovni, protože hrÃ¡Ä " +"zaujímající tuto polohu má Äasto nespravedlivou výhodu." + +#: ../../addon/tictac/tictac.php:182 +msgid "You go first..." +msgstr "Vy zaÄnÄ›te ..." + +#: ../../addon/tictac/tictac.php:187 +msgid "I'm going first this time..." +msgstr "Tentokrát zaÄnu já..." + +#: ../../addon/tictac/tictac.php:193 +msgid "You won!" +msgstr "Vyhrál jste!" + +#: ../../addon/tictac/tictac.php:199 ../../addon/tictac/tictac.php:224 +msgid "\"Cat\" game!" +msgstr "\"KoÄiÄí\" hra!" + +#: ../../addon/tictac/tictac.php:222 +msgid "I won!" +msgstr "Vyhrál jsem!" + +#: ../../addon/randplace/randplace.php:170 +msgid "Randplace Settings" +msgstr "Randplace Nastavení" + +#: ../../addon/randplace/randplace.php:172 +msgid "Enable Randplace Plugin" +msgstr "Povolit Randplace Plugin" + +#: ../../addon/js_upload/js_upload.php:43 +msgid "Upload a file" +msgstr "Nahrát soubor" + +#: ../../addon/js_upload/js_upload.php:44 +msgid "Drop files here to upload" +msgstr "PÅ™eneste sem soubory k nahrání" + +#: ../../addon/js_upload/js_upload.php:46 +msgid "Failed" +msgstr "NeúspÄ›ch" + +#: ../../addon/js_upload/js_upload.php:292 +msgid "No files were uploaded." +msgstr "Žádné soubory nebyly nahrány." + +#: ../../addon/js_upload/js_upload.php:298 +msgid "Uploaded file is empty" +msgstr "Nahraný soubor je prázdný" + +#: ../../addon/js_upload/js_upload.php:321 +msgid "File has an invalid extension, it should be one of " +msgstr "Soubor má neplatnou příponu, ta by mÄ›la být jednou z" + +#: ../../addon/js_upload/js_upload.php:332 +msgid "Upload was cancelled, or server error encountered" +msgstr "Nahrávání bylo zruÅ¡eno nebo doÅ¡lo k chybÄ› na serveru" + +#: ../../addon/impressum/impressum.php:25 +msgid "Impressum" +msgstr "Impressum" + +#: ../../addon/impressum/impressum.php:38 +#: ../../addon/impressum/impressum.php:40 +#: ../../addon/impressum/impressum.php:70 +msgid "Site Owner" +msgstr "Vlastník webu" + +#: ../../addon/impressum/impressum.php:38 +#: ../../addon/impressum/impressum.php:74 +msgid "Email Address" +msgstr "E-mailová adresa" + +#: ../../addon/impressum/impressum.php:43 +#: ../../addon/impressum/impressum.php:72 +msgid "Postal Address" +msgstr "PoÅ¡tovní adresa" + +#: ../../addon/impressum/impressum.php:49 +msgid "" +"The impressum addon needs to be configured!
    Please add at least the " +"owner variable to your config file. For other variables please " +"refer to the README file of the addon." +msgstr "" +"Doplněk Impressum musí být nakonfigurován!
    Prosím, pÅ™idejte alespoň " +"promÄ›nnou owner do konfiguraÄního souboru. Pro nastavení ostatních " +"promÄ›nných se seznamte s nápovÄ›dou v souboru README tohoto doplňku." + +#: ../../addon/impressum/impressum.php:71 +msgid "Site Owners Profile" +msgstr "Profil majitele webu" + +#: ../../addon/impressum/impressum.php:73 +msgid "Notes" +msgstr "Poznámky" + +#: ../../addon/oembed/oembed.php:30 +msgid "OEmbed settings updated" +msgstr "OEmbed nastavení aktualizováno" + +#: ../../addon/oembed/oembed.php:43 +msgid "Use OEmbed for YouTube videos" +msgstr "Použití OEmbed pro videa na YouTube" + +#: ../../addon/oembed/oembed.php:71 +msgid "URL to embed:" +msgstr "URL adresa k vložení:" + +#: ../../addon/statusnet/statusnet.php:133 +msgid "Post to StatusNet" +msgstr "Poslat příspÄ›vek na StatusNet" + +#: ../../addon/statusnet/statusnet.php:175 +msgid "" +"Please contact your site administrator.
    The provided API URL is not " +"valid." +msgstr "" +"Obraťte se na administratora webu.
    Poskytnutý odkaz na API není platný." + +#: ../../addon/statusnet/statusnet.php:203 +msgid "We could not contact the StatusNet API with the Path you entered." +msgstr "" +"S cestou, kterou jste zadali, se nebylo možné spojit s API StatusNetu." + +#: ../../addon/statusnet/statusnet.php:230 +msgid "StatusNet settings updated." +msgstr "Nastavení StatusNetu aktualizováno." + +#: ../../addon/statusnet/statusnet.php:253 +msgid "StatusNet Posting Settings" +msgstr "Nastavení zasílání příspÄ›vků na StatusNet " + +#: ../../addon/statusnet/statusnet.php:267 +msgid "Globally Available StatusNet OAuthKeys" +msgstr "GlobálnÄ› dostupné StatusNet OAuth klíÄe" + +#: ../../addon/statusnet/statusnet.php:268 +msgid "" +"There are preconfigured OAuth key pairs for some StatusNet servers " +"available. If you are useing one of them, please use these credentials. If " +"not feel free to connect to any other StatusNet instance (see below)." +msgstr "" +"Jsou dostupné pÅ™ednastavené OAuth páry klíÄů pro nÄ›které servery StatusNetu." +" Pokud používáte nÄ›který z nich, použijte toto pÅ™ihlášení. Pokud ne, " +"neváhejte se pÅ™ipojit k jiné instanci StatusNet (viz níže)." + +#: ../../addon/statusnet/statusnet.php:276 +msgid "Provide your own OAuth Credentials" +msgstr "UveÄte své vlastní OAuth pÅ™ihlaÅ¡ovací údaje" + +#: ../../addon/statusnet/statusnet.php:277 +msgid "" +"No consumer key pair for StatusNet found. Register your Friendika Account as" +" an desktop client on your StatusNet account, copy the consumer key pair " +"here and enter the API base root.
    Before you register your own OAuth " +"key pair ask the administrator if there is already a key pair for this " +"Friendika installation at your favorited StatusNet installation." +msgstr "" +"Nenalezen žádný consumer pár klíÄů pro StatusNet. Zaregistrujte svůj " +"Friendika úÄet jako desktopový klient na svém úÄtu StatusNetu, zkopírujte " +"níže consumer pár klíÄů a zadejte API base root.
    Než si zaregistrujete " +"svůj vlastní pár klíÄů OAuth, zjistÄ›te si od administrátora, zda-li už " +"náhodou na tento Friendika server nepÅ™idal pár klíÄů pro vámi požadovanou " +"instalaci StatusNetu." + +#: ../../addon/statusnet/statusnet.php:279 +msgid "OAuth Consumer Key" +msgstr "OAuth Consumer Key" + +#: ../../addon/statusnet/statusnet.php:282 +msgid "OAuth Consumer Secret" +msgstr "OAuth Consumer Secret" + +#: ../../addon/statusnet/statusnet.php:285 +msgid "Base API Path (remember the trailing /)" +msgstr "Cesta k Base API (nezapomeňte na koncový /)" + +#: ../../addon/statusnet/statusnet.php:306 +msgid "" +"To connect to your StatusNet account click the button below to get a " +"security code from StatusNet which you have to copy into the input box below" +" and submit the form. Only your public posts will be posted" +" to StatusNet." +msgstr "" +"Chcete-li pÅ™ipojit k vaÅ¡emu úÄtu StatusNet kliknÄ›te na tlaÄítko níže, abyste" +" dostati bezpeÄnostní kód ze StatusNetu, který musíte zkopírovat do " +"vstupního pole níže a odelat formulář. Pouze VaÅ¡e veÅ™ejné " +"příspÄ›vky budou zveÅ™ejnÄ›ny na StatusNetu." + +#: ../../addon/statusnet/statusnet.php:307 +msgid "Log in with StatusNet" +msgstr "PÅ™ihlásit se s StatusNet" + +#: ../../addon/statusnet/statusnet.php:309 +msgid "Copy the security code from StatusNet here" +msgstr "Zkopírujte sem bezpeÄnostní kód ze StatusNet" + +#: ../../addon/statusnet/statusnet.php:315 +msgid "Cancel Connection Process" +msgstr "ZruÅ¡it pÅ™ipojování" + +#: ../../addon/statusnet/statusnet.php:317 +msgid "Current StatusNet API is" +msgstr "Aktuální StatusNet API je" + +#: ../../addon/statusnet/statusnet.php:318 +msgid "Cancel StatusNet Connection" +msgstr "ZruÅ¡it StatusNet pÅ™ipojení" + +#: ../../addon/statusnet/statusnet.php:329 ../../addon/twitter/twitter.php:180 +msgid "Currently connected to: " +msgstr "V souÄasné dobÄ› pÅ™ipojen k:" + +#: ../../addon/statusnet/statusnet.php:330 +msgid "" +"If enabled all your public postings can be posted to the " +"associated StatusNet account. You can choose to do so by default (here) or " +"for every posting separately in the posting options when writing the entry." +msgstr "" +"Je-li povoleno, vÅ¡echny VaÅ¡e veÅ™ejné příspÄ›vky mohou být " +"zaslány na související StatusNet úÄet. Můžete si vybrat, zda-li toto bude " +"výchozí nastavení (zde), nebo budete mít možnost si vybrat požadované " +"chování pÅ™i psaní každého příspÄ›vku." + +#: ../../addon/statusnet/statusnet.php:332 +msgid "Allow posting to StatusNet" +msgstr "Povolit zasílání příspÄ›vků na StatusNet" + +#: ../../addon/statusnet/statusnet.php:335 +msgid "Send public postings to StatusNet by default" +msgstr "StandardnÄ› poslílat veÅ™ejné příspÄ›vky na StatusNet" + +#: ../../addon/statusnet/statusnet.php:340 ../../addon/twitter/twitter.php:191 +msgid "Clear OAuth configuration" +msgstr "Vymazat konfiguraci OAuth" + +#: ../../addon/statusnet/statusnet.php:460 +msgid "API URL" +msgstr "API URL" + +#: ../../addon/statusnet/statusnet.php:461 +msgid "Consumer Secret" +msgstr "Consumer Secret" + +#: ../../addon/statusnet/statusnet.php:462 +msgid "Consumer Key" +msgstr "Consumer Key" + +#: ../../addon/piwik/piwik.php:77 +msgid "Piwik Base URL" +msgstr "Piwik Base adresa URL" + +#: ../../addon/piwik/piwik.php:78 +msgid "Site ID" +msgstr "ID webu" + +#: ../../addon/piwik/piwik.php:79 +msgid "Show opt-out cookie link?" +msgstr "Zobrazit odkaz opt-out cookie?" + +#: ../../addon/twitter/twitter.php:70 +msgid "Post to Twitter" +msgstr "Poslat příspÄ›vek na Twitter" + +#: ../../addon/twitter/twitter.php:115 +msgid "Twitter settings updated." +msgstr "Nastavení Twitteru aktualizováno." + +#: ../../addon/twitter/twitter.php:137 +msgid "Twitter Posting Settings" +msgstr "Nastavení zasílání příspÄ›vků na Twitter " + +#: ../../addon/twitter/twitter.php:144 +msgid "" +"No consumer key pair for Twitter found. Please contact your site " +"administrator." +msgstr "" +"Nenalezen žádný spotÅ™ebitelský páru klíÄů pro Twitter. ObraÅ¥te se na " +"administrátora webu." + +#: ../../addon/twitter/twitter.php:163 +msgid "" +"At this Friendika instance the Twitter plugin was enabled but you have not " +"yet connected your account to your Twitter account. To do so click the " +"button below to get a PIN from Twitter which you have to copy into the input" +" box below and submit the form. Only your public posts will" +" be posted to Twitter." +msgstr "" +"Na tomto Friendika serveru je Twitter plugin povolen, ale jeÅ¡tÄ› nemáte svůj " +"úÄet pÅ™ipojen ke svému Twitter úÄtu. Chcete-li tak uÄinit, klepnutím na " +"tlaÄítko níže získejte PIN z Twitteru, který musíte zkopírovat do vstupního " +"pole níže a odeÅ¡lete formulář. Pouze VaÅ¡e veÅ™ejné příspÄ›vky" +" budou zveÅ™ejnÄ›ny na Twitteru." + +#: ../../addon/twitter/twitter.php:164 +msgid "Log in with Twitter" +msgstr "PÅ™ihlásit se s Twitter" + +#: ../../addon/twitter/twitter.php:166 +msgid "Copy the PIN from Twitter here" +msgstr "Zkopírujte sem PIN z Twitteru" + +#: ../../addon/twitter/twitter.php:181 +msgid "" +"If enabled all your public postings can be posted to the " +"associated Twitter account. You can choose to do so by default (here) or for" +" every posting separately in the posting options when writing the entry." +msgstr "" +"Je-li povoleno, vÅ¡echny VaÅ¡e veÅ™ejné příspÄ›vky mohou být " +"zaslány na související Twitter úÄet. Můžete si vybrat, zda-li toto bude " +"výchozí nastavení (zde), nebo budete mít možnost si vybrat požadované " +"chování pÅ™i psaní každého příspÄ›vku." + +#: ../../addon/twitter/twitter.php:183 +msgid "Allow posting to Twitter" +msgstr "Povolit odesílání na Twitter" + +#: ../../addon/twitter/twitter.php:186 +msgid "Send public postings to Twitter by default" +msgstr "DefaultnÄ› zasílat veÅ™ejné komentáře na Twitter" + +#: ../../addon/twitter/twitter.php:282 +msgid "Consumer key" +msgstr "Consumer key" + +#: ../../addon/twitter/twitter.php:283 +msgid "Consumer secret" +msgstr "Consumer secret" + +#: ../../include/profile_advanced.php:23 ../../boot.php:880 +msgid "Gender:" +msgstr "Pohlaví:" + +#: ../../include/profile_advanced.php:36 ../../include/items.php:1137 +msgid "Birthday:" +msgstr "Narozeniny:" + +#: ../../include/profile_advanced.php:45 +msgid "j F, Y" +msgstr "j F, Y" + +#: ../../include/profile_advanced.php:46 +msgid "j F" +msgstr "j F" + +#: ../../include/profile_advanced.php:59 +msgid "Age:" +msgstr "VÄ›k:" + +#: ../../include/profile_advanced.php:70 +msgid " Status:" +msgstr " Status:" + +#: ../../include/profile_advanced.php:103 ../../boot.php:886 +msgid "Homepage:" +msgstr "Domácí stránka:" + +#: ../../include/profile_advanced.php:127 +msgid "Religion:" +msgstr "Náboženství:" + +#: ../../include/profile_advanced.php:138 +msgid "About:" +msgstr "O mÄ›:" + +#: ../../include/profile_advanced.php:150 +msgid "Hobbies/Interests:" +msgstr "KoníÄky/zájmy:" + +#: ../../include/profile_advanced.php:162 +msgid "Contact information and Social Networks:" +msgstr "Kontaktní informace a sociální sítÄ›:" + +#: ../../include/profile_advanced.php:174 +msgid "Musical interests:" +msgstr "Hudební vkus:" + +#: ../../include/profile_advanced.php:186 +msgid "Books, literature:" +msgstr "Knihy, literatura:" + +#: ../../include/profile_advanced.php:198 +msgid "Television:" +msgstr "Televize:" + +#: ../../include/profile_advanced.php:210 +msgid "Film/dance/culture/entertainment:" +msgstr "Film/tanec/kultura/zábava:" + +#: ../../include/profile_advanced.php:222 +msgid "Love/Romance:" +msgstr "Láska/romance" + +#: ../../include/profile_advanced.php:234 +msgid "Work/employment:" +msgstr "Práce/zamÄ›stnání:" + +#: ../../include/profile_advanced.php:246 +msgid "School/education:" +msgstr "Å kola/vzdÄ›lávání:" + +#: ../../include/contact_selectors.php:32 +msgid "Unknown | Not categorised" +msgstr "Neznámé | NezaÅ™azeno" + +#: ../../include/contact_selectors.php:33 +msgid "Block immediately" +msgstr "OkamžitÄ› blokovat " + +#: ../../include/contact_selectors.php:34 +msgid "Shady, spammer, self-marketer" +msgstr "pochybný, spammer, self-makerter" + +#: ../../include/contact_selectors.php:35 +msgid "Known to me, but no opinion" +msgstr "Znám ho ale, ale bez rozhodnutí" + +#: ../../include/contact_selectors.php:36 +msgid "OK, probably harmless" +msgstr "OK, pravdÄ›podobnÄ› neÅ¡kodný" + +#: ../../include/contact_selectors.php:37 +msgid "Reputable, has my trust" +msgstr "Renomovaný, má mou důvÄ›ru" + +#: ../../include/contact_selectors.php:55 +msgid "Frequently" +msgstr "ÄŒasto" + +#: ../../include/contact_selectors.php:56 +msgid "Hourly" +msgstr "každou hodinu" + +#: ../../include/contact_selectors.php:57 +msgid "Twice daily" +msgstr "Dvakrát dennÄ›" + +#: ../../include/contact_selectors.php:58 +msgid "Daily" +msgstr "dennÄ›" + +#: ../../include/contact_selectors.php:59 +msgid "Weekly" +msgstr "TýdennÄ›" + +#: ../../include/contact_selectors.php:60 +msgid "Monthly" +msgstr "MÄ›síÄnÄ›" + +#: ../../include/profile_selectors.php:6 +msgid "Male" +msgstr "Muž" + +#: ../../include/profile_selectors.php:6 +msgid "Female" +msgstr "Žena" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "V souÄasné dobÄ› muž" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "V souÄasné dobÄ› žena" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "VÄ›tÅ¡inou muž" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "VÄ›tÅ¡inou žena" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transgender" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Intersex" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transexuál" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Hermafrodit" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Neutrál" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "Nespecifikováno" + +#: ../../include/profile_selectors.php:6 +msgid "Other" +msgstr "Jiné" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Nerozhodnuto" + +#: ../../include/profile_selectors.php:19 +msgid "Males" +msgstr "Muži" + +#: ../../include/profile_selectors.php:19 +msgid "Females" +msgstr "Ženy" + +#: ../../include/profile_selectors.php:19 +msgid "Gay" +msgstr "Gay" + +#: ../../include/profile_selectors.php:19 +msgid "Lesbian" +msgstr "LesbiÄka" + +#: ../../include/profile_selectors.php:19 +msgid "No Preference" +msgstr "Bez preferencí" + +#: ../../include/profile_selectors.php:19 +msgid "Bisexual" +msgstr "Bisexuál" + +#: ../../include/profile_selectors.php:19 +msgid "Autosexual" +msgstr "Autosexuál" + +#: ../../include/profile_selectors.php:19 +msgid "Abstinent" +msgstr "Abstinent" + +#: ../../include/profile_selectors.php:19 +msgid "Virgin" +msgstr "panic/panna" + +#: ../../include/profile_selectors.php:19 +msgid "Deviant" +msgstr "Deviant" + +#: ../../include/profile_selectors.php:19 +msgid "Fetish" +msgstr "FetiÅ¡ista" + +#: ../../include/profile_selectors.php:19 +msgid "Oodles" +msgstr "HodnÄ›" + +#: ../../include/profile_selectors.php:19 +msgid "Nonsexual" +msgstr "Nesexuální" + +#: ../../include/profile_selectors.php:33 +msgid "Single" +msgstr "Svobodný" + +#: ../../include/profile_selectors.php:33 +msgid "Lonely" +msgstr "OsamnÄ›lý" + +#: ../../include/profile_selectors.php:33 +msgid "Available" +msgstr "Dostupný" + +#: ../../include/profile_selectors.php:33 +msgid "Unavailable" +msgstr "Nedostupný" + +#: ../../include/profile_selectors.php:33 +msgid "Dating" +msgstr "Seznamující se" + +#: ../../include/profile_selectors.php:33 +msgid "Unfaithful" +msgstr "NevÄ›rný" + +#: ../../include/profile_selectors.php:33 +msgid "Sex Addict" +msgstr "Závislý na sexu" + +#: ../../include/profile_selectors.php:33 +msgid "Friends" +msgstr "Přátelé" + +#: ../../include/profile_selectors.php:33 +msgid "Friends/Benefits" +msgstr "Přátelé / výhody" + +#: ../../include/profile_selectors.php:33 +msgid "Casual" +msgstr "Ležérní" + +#: ../../include/profile_selectors.php:33 +msgid "Engaged" +msgstr "Zadaný" + +#: ../../include/profile_selectors.php:33 +msgid "Married" +msgstr "Ženatý/vdaná" + +#: ../../include/profile_selectors.php:33 +msgid "Partners" +msgstr "PartneÅ™i" + +#: ../../include/profile_selectors.php:33 +msgid "Cohabiting" +msgstr "Žijící ve spoleÄné domácnosti" + +#: ../../include/profile_selectors.php:33 +msgid "Happy" +msgstr "Šťastný" + +#: ../../include/profile_selectors.php:33 +msgid "Not Looking" +msgstr "Nehledající" + +#: ../../include/profile_selectors.php:33 +msgid "Swinger" +msgstr "Swinger" + +#: ../../include/profile_selectors.php:33 +msgid "Betrayed" +msgstr "Zrazen" + +#: ../../include/profile_selectors.php:33 +msgid "Separated" +msgstr "OdlouÄený" + +#: ../../include/profile_selectors.php:33 +msgid "Unstable" +msgstr "Nestálý" + +#: ../../include/profile_selectors.php:33 +msgid "Divorced" +msgstr "Rozvedený(á)" + +#: ../../include/profile_selectors.php:33 +msgid "Widowed" +msgstr "OvdovÄ›lý(á)" + +#: ../../include/profile_selectors.php:33 +msgid "Uncertain" +msgstr "Nejistý" + +#: ../../include/profile_selectors.php:33 +msgid "Complicated" +msgstr "Komplikovaný" + +#: ../../include/profile_selectors.php:33 +msgid "Don't care" +msgstr "Nezajímá" + +#: ../../include/profile_selectors.php:33 +msgid "Ask me" +msgstr "Zeptej se mÄ›" + +#: ../../include/event.php:11 +msgid "l F d, Y \\@ g:i A" +msgstr "l F d, Y \\@ g:i A" + +#: ../../include/event.php:17 +msgid "Starts:" +msgstr "ZaÄíná:" + +#: ../../include/event.php:27 +msgid "Finishes:" +msgstr "KonÄí:" + +#: ../../include/text.php:229 +msgid "prev" +msgstr "pÅ™edchozí" + +#: ../../include/text.php:231 +msgid "first" +msgstr "první" + +#: ../../include/text.php:260 +msgid "last" +msgstr "poslední" + +#: ../../include/text.php:263 +msgid "next" +msgstr "další" + +#: ../../include/text.php:542 +msgid "No contacts" +msgstr "Žádné kontakty" + +#: ../../include/text.php:550 +#, php-format +msgid "%d Contact" +msgid_plural "%d Contacts" +msgstr[0] "%d kontakt" +msgstr[1] "%d kontaktů" +msgstr[2] "%d kontaktů" + +#: ../../include/text.php:711 +msgid "Monday" +msgstr "PondÄ›lí" + +#: ../../include/text.php:711 +msgid "Tuesday" +msgstr "Úterý" + +#: ../../include/text.php:711 +msgid "Wednesday" +msgstr "StÅ™eda" + +#: ../../include/text.php:711 +msgid "Thursday" +msgstr "ÄŒtvrtek" + +#: ../../include/text.php:711 +msgid "Friday" +msgstr "Pátek" + +#: ../../include/text.php:711 +msgid "Saturday" +msgstr "Sobota" + +#: ../../include/text.php:711 +msgid "Sunday" +msgstr "NedÄ›le" + +#: ../../include/text.php:715 +msgid "January" +msgstr "Ledna" + +#: ../../include/text.php:715 +msgid "February" +msgstr "Února" + +#: ../../include/text.php:715 +msgid "March" +msgstr "BÅ™ezna" + +#: ../../include/text.php:715 +msgid "April" +msgstr "Dubna" + +#: ../../include/text.php:715 +msgid "May" +msgstr "KvÄ›tna" + +#: ../../include/text.php:715 +msgid "June" +msgstr "ÄŒervna" + +#: ../../include/text.php:715 +msgid "July" +msgstr "ÄŒervence" + +#: ../../include/text.php:715 +msgid "August" +msgstr "Srpna" + +#: ../../include/text.php:715 +msgid "September" +msgstr "Září" + +#: ../../include/text.php:715 +msgid "October" +msgstr "Října" + +#: ../../include/text.php:715 +msgid "November" +msgstr "Listopadu" + +#: ../../include/text.php:715 +msgid "December" +msgstr "Prosince" + +#: ../../include/text.php:778 +msgid "bytes" +msgstr "bytů" + +#: ../../include/text.php:861 +msgid "Select an alternate language" +msgstr "VybÄ›r alternativního jazyka" + +#: ../../include/diaspora.php:309 +msgid "Sharing notification from Diaspora network" +msgstr "Sdílení oznámení ze sítÄ› Diaspora" + +#: ../../include/oembed.php:95 +msgid "Embedding disabled" +msgstr "Vkládání zakázáno" + +#: ../../include/group.php:146 +msgid "Create a new group" +msgstr "VytvoÅ™it novou skupinu" + +#: ../../include/group.php:147 +msgid "Everybody" +msgstr "VÅ¡ichni" + +#: ../../include/nav.php:41 ../../boot.php:667 +msgid "Logout" +msgstr "Odhlásit se" + +#: ../../include/nav.php:41 +msgid "End this session" +msgstr "Konec této relace" + +#: ../../include/nav.php:44 ../../boot.php:645 ../../boot.php:651 +msgid "Login" +msgstr "PÅ™ihlásit se" + +#: ../../include/nav.php:44 +msgid "Sign in" +msgstr "PÅ™ihlásit se" + +#: ../../include/nav.php:55 ../../include/nav.php:93 +msgid "Home" +msgstr "Domů" + +#: ../../include/nav.php:55 +msgid "Home Page" +msgstr "Domácí stránka" + +#: ../../include/nav.php:59 +msgid "Create an account" +msgstr "VytvoÅ™it úÄet" + +#: ../../include/nav.php:64 +msgid "Help and documentation" +msgstr "NápovÄ›da a dokumentace" + +#: ../../include/nav.php:67 +msgid "Apps" +msgstr "Aplikace" + +#: ../../include/nav.php:67 +msgid "Addon applications, utilities, games" +msgstr "Doplňkové aplikace, nástroje, hry" + +#: ../../include/nav.php:69 +msgid "Search site content" +msgstr "Hledání na stránkách tohoto webu" + +#: ../../include/nav.php:79 +msgid "Conversations on this site" +msgstr "Konverzace na tomto webu" + +#: ../../include/nav.php:81 +msgid "Directory" +msgstr "Adresář" + +#: ../../include/nav.php:81 +msgid "People directory" +msgstr "Adresář" + +#: ../../include/nav.php:91 +msgid "Network" +msgstr "Síť" + +#: ../../include/nav.php:91 +msgid "Conversations from your friends" +msgstr "Konverzace od VaÅ¡ich přátel" + +#: ../../include/nav.php:93 +msgid "Your posts and conversations" +msgstr "VaÅ¡e příspÄ›vky a konverzace" + +#: ../../include/nav.php:99 +msgid "Notifications" +msgstr "UpozornÄ›ní" + +#: ../../include/nav.php:99 +msgid "Friend requests" +msgstr "Požadavky přátelství" + +#: ../../include/nav.php:102 +msgid "Private mail" +msgstr "Soukromá poÅ¡ta" + +#: ../../include/nav.php:105 +msgid "Manage" +msgstr "Spravovat" + +#: ../../include/nav.php:105 +msgid "Manage other pages" +msgstr "Spravovat jiné stránky" + +#: ../../include/nav.php:109 +msgid "Manage/edit profiles" +msgstr "Spravovat/upravit profily" + +#: ../../include/nav.php:110 +msgid "Manage/edit friends and contacts" +msgstr "Spravovat/upravit přátelé a kontakty" + +#: ../../include/nav.php:117 +msgid "Admin" +msgstr "Administrace" + +#: ../../include/nav.php:117 +msgid "Site setup and configuration" +msgstr "Nastavení webu a konfigurace" + +#: ../../include/auth.php:27 +msgid "Logged out." +msgstr "Odhlášen." + +#: ../../include/datetime.php:44 ../../include/datetime.php:46 +msgid "Miscellaneous" +msgstr "Různé" + +#: ../../include/datetime.php:105 ../../include/datetime.php:237 +msgid "year" +msgstr "rok" + +#: ../../include/datetime.php:110 ../../include/datetime.php:238 +msgid "month" +msgstr "mÄ›síc" + +#: ../../include/datetime.php:115 ../../include/datetime.php:240 +msgid "day" +msgstr "den" + +#: ../../include/datetime.php:228 +msgid "never" +msgstr "nikdy" + +#: ../../include/datetime.php:234 +msgid "less than a second ago" +msgstr "ménÄ› než pÅ™ed sekundou" + +#: ../../include/datetime.php:237 +msgid "years" +msgstr "let" + +#: ../../include/datetime.php:238 +msgid "months" +msgstr "mÄ›síců" + +#: ../../include/datetime.php:239 +msgid "week" +msgstr "týden" + +#: ../../include/datetime.php:239 +msgid "weeks" +msgstr "týdny" + +#: ../../include/datetime.php:240 +msgid "days" +msgstr "dnů" + +#: ../../include/datetime.php:241 +msgid "hour" +msgstr "hodina" + +#: ../../include/datetime.php:241 +msgid "hours" +msgstr "hodin" + +#: ../../include/datetime.php:242 +msgid "minute" +msgstr "minuta" + +#: ../../include/datetime.php:242 +msgid "minutes" +msgstr "minut" + +#: ../../include/datetime.php:243 +msgid "second" +msgstr "sekunda" + +#: ../../include/datetime.php:243 +msgid "seconds" +msgstr "sekund" + +#: ../../include/datetime.php:250 +msgid " ago" +msgstr " nazpÄ›t" + +#: ../../include/poller.php:418 +msgid "From: " +msgstr "Od:" + +#: ../../include/bbcode.php:116 +msgid "Image/photo" +msgstr "Obrázek/fotografie" + +#: ../../include/dba.php:31 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "Nelze nalézt záznam v DNS pro databázový server '%s'" + +#: ../../include/acl_selectors.php:279 +msgid "Visible to everybody" +msgstr "Viditelné pro vÅ¡echny" + +#: ../../include/acl_selectors.php:280 +msgid "show" +msgstr "zobrazit" + +#: ../../include/acl_selectors.php:281 +msgid "don't show" +msgstr "nikdy nezobrazit" + +#: ../../include/notifier.php:465 +msgid "(no subject)" +msgstr "(Bez pÅ™edmÄ›tu)" + +#: ../../include/items.php:1526 +msgid "You have a new follower at " +msgstr "Máte nového následovníka na" + +#: ../../include/conversation.php:23 +msgid "event" +msgstr "událost" + +#: ../../include/conversation.php:213 ../../include/conversation.php:488 +#: ../../include/conversation.php:489 +#, php-format +msgid "View %s's profile" +msgstr "Zobrazit %s profilu" + +#: ../../include/conversation.php:222 ../../include/conversation.php:501 +#, php-format +msgid "%s from %s" +msgstr "%s od %s" + +#: ../../include/conversation.php:230 +msgid "View in context" +msgstr "Pohled v kontextu" + +#: ../../include/conversation.php:301 +msgid "See more posts like this" +msgstr "Zobrazit více podobných příspÄ›vků" + +#: ../../include/conversation.php:329 +#, php-format +msgid "See all %d comments" +msgstr "Zobrazit vÅ¡echny komentáře %d" + +#: ../../include/conversation.php:427 +msgid "Select" +msgstr "Vybrat" + +#: ../../include/conversation.php:429 +msgid "toggle star status" +msgstr "pÅ™epnout hvÄ›zdu" + +#: ../../include/conversation.php:490 +msgid "to" +msgstr "pro" + +#: ../../include/conversation.php:491 +msgid "Wall-to-Wall" +msgstr "ZeÄ-na-ZeÄ" + +#: ../../include/conversation.php:492 +msgid "via Wall-To-Wall:" +msgstr "pÅ™es ZeÄ-na-ZeÄ " + +#: ../../include/conversation.php:534 +msgid "Delete Selected Items" +msgstr "Smazat vybrané položky" + +#: ../../include/conversation.php:608 +msgid "View status" +msgstr "Zobrazit stav" + +#: ../../include/conversation.php:609 +msgid "View profile" +msgstr "Zobrazit profil" + +#: ../../include/conversation.php:610 +msgid "View photos" +msgstr "Zobrazit fotografie" + +#: ../../include/conversation.php:611 +msgid "View recent" +msgstr "Zobrazit poslední" + +#: ../../include/conversation.php:613 +msgid "Send PM" +msgstr "Poslat soukromou zprávu" + +#: ../../include/conversation.php:663 +#, php-format +msgid "%s likes this." +msgstr "%s se to líbí." + +#: ../../include/conversation.php:663 +#, php-format +msgid "%s doesn't like this." +msgstr "%s se to nelíbí." + +#: ../../include/conversation.php:667 +#, php-format +msgid "%2$d people like this." +msgstr "%2$d lidem se to líbí." + +#: ../../include/conversation.php:669 +#, php-format +msgid "%2$d people don't like this." +msgstr "%2$d lidem se to nelíbí." + +#: ../../include/conversation.php:675 +msgid "and" +msgstr "a" + +#: ../../include/conversation.php:678 +#, php-format +msgid ", and %d other people" +msgstr ", a %d dalších lidí" + +#: ../../include/conversation.php:679 +#, php-format +msgid "%s like this." +msgstr "%s se to líbí." + +#: ../../include/conversation.php:679 +#, php-format +msgid "%s don't like this." +msgstr "%s se to nelíbí." + +#: ../../include/conversation.php:698 +msgid "Visible to everybody" +msgstr "Viditelné pro vÅ¡echny" + +#: ../../include/conversation.php:700 +msgid "Please enter a YouTube link:" +msgstr "Prosím zadejte odkaz na YouTube:" + +#: ../../include/conversation.php:701 +msgid "Please enter a video(.ogg) link/URL:" +msgstr "Prosím, zadejte odkaz na video (ogg.):" + +#: ../../include/conversation.php:702 +msgid "Please enter an audio(.ogg) link/URL:" +msgstr "Prosím, zadejte odkaz na audio (ogg.):" + +#: ../../include/conversation.php:703 +msgid "Where are you right now?" +msgstr "Kde právÄ› jste?" + +#: ../../include/conversation.php:704 +msgid "Enter a title for this item" +msgstr "Zadejte titulek pro tuto položku" + +#: ../../include/conversation.php:755 +msgid "Set title" +msgstr "Nastavit titulek" + +#: ../../boot.php:410 +msgid "Delete this item?" +msgstr "Odstranit tuto položku?" + +#: ../../boot.php:636 +msgid "Create a New Account" +msgstr "VytvoÅ™it nový úÄet" + +#: ../../boot.php:643 +msgid "Nickname or Email address: " +msgstr "PÅ™ezdívka nebo e-mailová adresa:" + +#: ../../boot.php:644 +msgid "Password: " +msgstr "Heslo: " + +#: ../../boot.php:649 +msgid "Nickname/Email/OpenID: " +msgstr "PÅ™ezdívka/E-mail/OpenID: " + +#: ../../boot.php:650 +msgid "Password (if not OpenID): " +msgstr "Heslo (pokud se nepoužívá OpenID):" + +#: ../../boot.php:653 +msgid "Forgot your password?" +msgstr "ZapomnÄ›li jste své heslo?" + +#: ../../boot.php:853 +msgid "Connect" +msgstr "Spojit" + +#: ../../boot.php:872 +msgid ", " +msgstr ", " + +#: ../../boot.php:884 +msgid "Status:" +msgstr "Status:" + +#: ../../boot.php:975 +msgid "g A l F d" +msgstr "g A l F d" + +#: ../../boot.php:993 +msgid "Birthday Reminders" +msgstr "PÅ™ipomínka narozenin" + +#: ../../boot.php:994 +msgid "Birthdays this week:" +msgstr "Narozeniny tento týden:" + +#: ../../boot.php:995 +msgid "(Adjusted for local time)" +msgstr "(Upraveno pro místní Äas)" + +#: ../../boot.php:1006 +msgid "[today]" +msgstr "[Dnes]" + +#: ../../index.php:209 +msgid "Not Found" +msgstr "Nenalezen" + +#: ../../index.php:210 +msgid "Page not found." +msgstr "Stránka nenalezena" + + diff --git a/sources/view/cs/passchanged_eml.tpl b/sources/view/cs/passchanged_eml.tpl new file mode 100644 index 00000000..0d94be3c --- /dev/null +++ b/sources/view/cs/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Dear {{$username}}, + Your password has been changed as requested. Please retain this +information for your records (or change your password immediately to +something that you will remember). + + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +Password: {{$new_password}} + +You may change that password from your account settings page after logging in. + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/cs/register_open_eml.tpl b/sources/view/cs/register_open_eml.tpl new file mode 100644 index 00000000..4b397201 --- /dev/null +++ b/sources/view/cs/register_open_eml.tpl @@ -0,0 +1,19 @@ + +An account has been created at {{$sitename}} for this email address. +The login details are as follows: + +Site Location: {{$siteurl}} +Login: {{$email}} +Password: (the password which was provided during registration) + +If this account was created without your knowledge and is not desired, you may +visit this site and reset the password. This will allow you to remove the +account from the links on the Settings page, and we +apologise for any inconvenience. + +Thank you and welcome to {{$sitename}}. + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/cs/register_verify_eml.tpl b/sources/view/cs/register_verify_eml.tpl new file mode 100644 index 00000000..85d9a12d --- /dev/null +++ b/sources/view/cs/register_verify_eml.tpl @@ -0,0 +1,25 @@ + +A new user registration request was received at {{$sitename}} which requires +your approval. + + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +IP Address: {{$details}} + +To approve this request please visit the following link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/cs/strings.php b/sources/view/cs/strings.php new file mode 100644 index 00000000..b0c778a6 --- /dev/null +++ b/sources/view/cs/strings.php @@ -0,0 +1,1044 @@ +=2 && $n<=4) ? 1 : 2; +}} +; +$a->strings["Post successful."] = "PříspÄ›vek úspěšnÄ› odeslán"; +$a->strings["Contact settings applied."] = "Nastavení kontaktu zmÄ›nÄ›no"; +$a->strings["Contact update failed."] = "Aktualizace kontaktu selhala."; +$a->strings["Permission denied."] = "Přístup odmítnut."; +$a->strings["Contact not found."] = "Kontakt nenalezen."; +$a->strings["Repair Contact Settings"] = "Opravit nastavení kontaktu"; +$a->strings["WARNING: This is highly advanced and if you enter incorrect information your communications with this contact will stop working."] = "VAROVÃNÃ: Toto je velmi pokroÄilé nastavení, pokud zadáte nesprávné informace, komunikace s tímto kontaktem pÅ™estane fungovat."; +$a->strings["Please use your browser 'Back' button now if you are uncertain what to do on this page."] = "Prosím použijte ihned v prohlížeÄi tlaÄítko \"zpÄ›t\" pokud si nejste jistí co dÄ›lat na této stránce."; +$a->strings["Name"] = "Jméno"; +$a->strings["Account Nickname"] = "PÅ™ezdívka úÄtu"; +$a->strings["Account URL"] = "URL adresa úÄtu"; +$a->strings["Friend Request URL"] = "Žádost o přátelství URL"; +$a->strings["Friend Confirm URL"] = "URL adresa potvrzení přátelství"; +$a->strings["Notification Endpoint URL"] = "NotifikaÄní URL adresa"; +$a->strings["Poll/Feed URL"] = "Poll/Feed URL adresa"; +$a->strings["Submit"] = "Odeslat"; +$a->strings["Help:"] = "NápovÄ›da:"; +$a->strings["Help"] = "NápovÄ›da"; +$a->strings["File exceeds size limit of %d"] = "Velikost souboru pÅ™esáhla limit %d"; +$a->strings["File upload failed."] = "Nahrání souboru se nezdaÅ™ilo."; +$a->strings["Friend suggestion sent."] = "Návrhy přátelství odeslány "; +$a->strings["Suggest Friends"] = "NavrhnÄ›te přátelé"; +$a->strings["Suggest a friend for %s"] = "NavrhnÄ›te přátelé pro uživatele %s"; +$a->strings["Status"] = "Stav"; +$a->strings["Profile"] = "Profil"; +$a->strings["Photos"] = "Fotografie"; +$a->strings["Events"] = "Události"; +$a->strings["Personal Notes"] = "Osobní poznámky"; +$a->strings["Create New Event"] = "VytvoÅ™it novou událost"; +$a->strings["Previous"] = "PÅ™edchozí"; +$a->strings["Next"] = "Následující"; +$a->strings["l, F j"] = "l, F j"; +$a->strings["Edit event"] = "Editovat událost"; +$a->strings["link to source"] = "odkaz na zdroj"; +$a->strings["hour:minute"] = "hodina:minuta"; +$a->strings["Event details"] = "Detaily události"; +$a->strings["Format is %s %s. Starting date and Description are required."] = "Formát je %s %s. Datum zahájení a popis jsou povinné."; +$a->strings["Event Starts:"] = "Událost zaÄíná:"; +$a->strings["Finish date/time is not known or not relevant"] = "Datum/Äas konce není zadán nebo není relevantní"; +$a->strings["Event Finishes:"] = "Akce konÄí:"; +$a->strings["Adjust for viewer timezone"] = "Nastavit Äasové pásmo pro uživatele s právem pro Ätení"; +$a->strings["Description:"] = "Popis:"; +$a->strings["Location:"] = "Místo:"; +$a->strings["Share this event"] = "Sdílet tuto událost"; +$a->strings["Cancel"] = "ZruÅ¡it"; +$a->strings["Tag removed"] = "Å títek odstranÄ›n"; +$a->strings["Remove Item Tag"] = "Odebrat Å¡títek položky"; +$a->strings["Select a tag to remove: "] = "Vyberte Å¡títek k odebrání:"; +$a->strings["Remove"] = "Odstranit"; +$a->strings["%s welcomes %s"] = "%s vítá %s "; +$a->strings["Photo Albums"] = "Fotoalba"; +$a->strings["Contact Photos"] = "Fotogalerie kontaktu"; +$a->strings["everybody"] = "Žádost o pÅ™ipojení selhala nebo byla zruÅ¡ena."; +$a->strings["Contact information unavailable"] = "Kontakt byl zablokován"; +$a->strings["Profile Photos"] = "Profilové fotografie"; +$a->strings["Album not found."] = "Album nenalezeno."; +$a->strings["Delete Album"] = "Smazat album"; +$a->strings["Delete Photo"] = "Smazat fotografii"; +$a->strings["was tagged in a"] = "Å¡títek byl pÅ™idán v"; +$a->strings["photo"] = "fotografie"; +$a->strings["by"] = "od"; +$a->strings["Image exceeds size limit of "] = "Velikost obrázku pÅ™ekraÄuje limit velikosti"; +$a->strings["Image file is empty."] = "Soubor obrázku je prázdný."; +$a->strings["Unable to process image."] = "Obrázek není možné zprocesovat"; +$a->strings["Image upload failed."] = "Nahrání obrázku selhalo."; +$a->strings["Public access denied."] = "VeÅ™ejný přístup odepÅ™en."; +$a->strings["No photos selected"] = "Není vybrána žádná fotografie"; +$a->strings["Access to this item is restricted."] = "Přístup k této položce je omezen."; +$a->strings["Upload Photos"] = "Nahrání fotografií "; +$a->strings["New album name: "] = "Název nového alba:"; +$a->strings["or existing album name: "] = "nebo stávající název alba:"; +$a->strings["Permissions"] = "OprávnÄ›ní:"; +$a->strings["Edit Album"] = "Edituj album"; +$a->strings["View Photo"] = "Zobraz fotografii"; +$a->strings["Photo not available"] = "Fotografie není k dispozici"; +$a->strings["Edit photo"] = "Editovat fotografii"; +$a->strings["Use as profile photo"] = "Použít jako profilovou fotografii"; +$a->strings["Private Message"] = "Soukromá zpráva"; +$a->strings["View Full Size"] = "Zobrazit v plné velikosti"; +$a->strings["Tags: "] = "Å títky:"; +$a->strings["[Remove any tag]"] = "[Odstranit vÅ¡echny Å¡títky]"; +$a->strings["New album name"] = "Nové jméno alba"; +$a->strings["Caption"] = "Titulek"; +$a->strings["Add a Tag"] = "PÅ™idat Å¡títek"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"] = "Příklad: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"; +$a->strings["I like this (toggle)"] = "Líbí se mi to (pÅ™epínaÄ)"; +$a->strings["I don't like this (toggle)"] = "Nelíbí se mi to (pÅ™epínaÄ)"; +$a->strings["Share"] = "Sdílet"; +$a->strings["Please wait"] = "ÄŒekejte prosím"; +$a->strings["This is you"] = "To je Vy"; +$a->strings["Comment"] = "Okomentovat"; +$a->strings["Delete"] = "Odstranit"; +$a->strings["Recent Photos"] = "Aktuální fotografie"; +$a->strings["Upload New Photos"] = "Nahrát nové fotografie"; +$a->strings["View Album"] = "Zobrazit album"; +$a->strings["Not available."] = "Není k dispozici."; +$a->strings["Community"] = "Komunita"; +$a->strings["No results."] = "Žádné výsledky."; +$a->strings["Shared content is covered by the Creative Commons Attribution 3.0 license."] = "Sdílený obsah je v souladu s Commons Creative 3.0 licencí."; +$a->strings["Item not found"] = "Položka nenalezena"; +$a->strings["Edit post"] = "Upravit příspÄ›vek"; +$a->strings["Post to Email"] = "Poslat příspÄ›vek na e-mail"; +$a->strings["Edit"] = "Upravit"; +$a->strings["Upload photo"] = "Nahrát fotografii"; +$a->strings["Attach file"] = "PÅ™iložit soubor"; +$a->strings["Insert web link"] = "Vložit webový odkaz"; +$a->strings["Insert YouTube video"] = "Vložit YouTube video"; +$a->strings["Insert Vorbis [.ogg] video"] = "Vložit Vorbis [.ogg] video"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Vložit Vorbis [.ogg] audio"; +$a->strings["Set your location"] = "Nastavte vaÅ¡i polohu"; +$a->strings["Clear browser location"] = "Odstranit adresu v prohlížeÄi"; +$a->strings["Permission settings"] = "Nastavení oprávnÄ›ní"; +$a->strings["CC: email addresses"] = "skrytá kopie: e-mailové adresy"; +$a->strings["Public post"] = "VeÅ™ejný příspÄ›vek"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Příklad: bob@example.com, mary@example.com"; +$a->strings["This introduction has already been accepted."] = "Toto pozvání již bylo pÅ™ijato"; +$a->strings["Profile location is not valid or does not contain profile information."] = "Adresa profilu není platná nebo neobsahuje profilové informace"; +$a->strings["Warning: profile location has no identifiable owner name."] = "Varování: umístÄ›ní profilu nemá žádné identifikovatelné jméno vlastníka"; +$a->strings["Warning: profile location has no profile photo."] = "Varování: umístÄ›ní profilu nemá žádnou profilovou fotografii."; +$a->strings["%d required parameter was not found at the given location"] = array( + 0 => "%d požadovaný parametr nebyl nalezen na daném místÄ›", + 1 => "%d požadované parametry nebyly nalezeny na daném místÄ›", + 2 => "%d požadované parametry nebyly nalezeny na daném místÄ›", +); +$a->strings["Introduction complete."] = "PÅ™edstavení dokonÄeno."; +$a->strings["Unrecoverable protocol error."] = "Neopravitelná chyba protokolu"; +$a->strings["Profile unavailable."] = "Profil není k dispozici."; +$a->strings["%s has received too many connection requests today."] = "%s dnes obdržel příliÅ¡ mnoho požadavků na pÅ™ipojení."; +$a->strings["Spam protection measures have been invoked."] = "Ochrana proti spamu byla aktivována"; +$a->strings["Friends are advised to please try again in 24 hours."] = "Přátelům se doporuÄuje to zkusit znovu za 24 hodin."; +$a->strings["Invalid locator"] = "Neplatný odkaz"; +$a->strings["Unable to resolve your name at the provided location."] = "NepodaÅ™ilo se zjistit VaÅ¡e jméno na zadané adrese."; +$a->strings["You have already introduced yourself here."] = "Již jste se zde zavedli."; +$a->strings["Apparently you are already friends with %s."] = "ZÅ™ejmÄ› jste již přátelé se %s."; +$a->strings["Invalid profile URL."] = "Neplatné URL profilu."; +$a->strings["Disallowed profile URL."] = "Nepovolené URL profilu."; +$a->strings["Failed to update contact record."] = "NepodaÅ™ilo se aktualizovat kontakt."; +$a->strings["Your introduction has been sent."] = "VaÅ¡e žádost o propojení byla odeslána."; +$a->strings["Please login to confirm introduction."] = "Prosím pÅ™ihlaÅ¡te se k potvrzení žádosti o propojení."; +$a->strings["Incorrect identity currently logged in. Please login to this profile."] = "Jste pÅ™ihlášeni pod nesprávnou identitou Prosím, pÅ™ihlaste se do tohoto profilu."; +$a->strings["Welcome home %s."] = "Vítejte doma %s."; +$a->strings["Please confirm your introduction/connection request to %s."] = "Prosím potvrÄte VaÅ¡i žádost o pÅ™edstavení/spojení %s."; +$a->strings["Confirm"] = "Potvrdit"; +$a->strings["[Name Withheld]"] = "[Jméno odepÅ™eno]"; +$a->strings["Introduction received at "] = "Pozvánka pÅ™ijata v"; +$a->strings["Administrator"] = "Administrátor"; +$a->strings["Friend/Connection Request"] = "Požadavek o přátelství / propojení"; +$a->strings["Examples: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca"] = "Příklady: jojo@demo.friendika.com, http://demo.friendika.com/profile/jojo, testuser@identi.ca"; +$a->strings["Please answer the following:"] = "OdpovÄ›zte, prosím, následující:"; +$a->strings["Does %s know you?"] = "Zná Vás uživatel %s ?"; +$a->strings["Yes"] = "Ano"; +$a->strings["No"] = "Ne"; +$a->strings["Add a personal note:"] = "PÅ™idat osobní poznámku:"; +$a->strings["Please enter your 'Identity Address' from one of the following supported social networks:"] = "Prosím, zadejte adresu své 'identity' jedné z následujících podporovaných sociálních sítí:"; +$a->strings["Friendika"] = "Friendika"; +$a->strings["StatusNet/Federated Social Web"] = "StatusNet / Federativní Sociální Web"; +$a->strings["Private (secure) network"] = "Soukromá (zabezpeÄená) síť"; +$a->strings["Public (insecure) network"] = "VeÅ™ejná (nezabezpeÄená) síť"; +$a->strings["Your Identity Address:"] = "Adresa Vaší identity :"; +$a->strings["Submit Request"] = "Odeslat žádost"; +$a->strings["Could not create/connect to database."] = "Nelze vytvoÅ™it / pÅ™ipojit se k databázi."; +$a->strings["Connected to database."] = "PÅ™ipojeno k databázi."; +$a->strings["Proceed with Installation"] = "PokraÄovat v instalaci"; +$a->strings["Your Friendika site database has been installed."] = "VaÅ¡e databáze Friendiky byla nainstalována."; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "Důležité: Budete si muset [ruÄnÄ›] plánovat úlohu pro poller."; +$a->strings["Please see the file \"INSTALL.txt\"."] = "PÅ™eÄtÄ›te si prosím informace v souboru \"INSTALL.txt\"."; +$a->strings["Proceed to registration"] = "PokraÄovat k registraci"; +$a->strings["Database import failed."] = "Import databáze se nezdaÅ™il."; +$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Možná budete muset importovat soubor \"database.sql\" ruÄnÄ› pomocí phpMyAdmin Äi MySQL."; +$a->strings["Welcome to Friendika."] = "Vítejte na Friendice."; +$a->strings["Friendika Social Network"] = "Sociální síť Friendika "; +$a->strings["Installation"] = "Instalace"; +$a->strings["In order to install Friendika we need to know how to connect to your database."] = "Pro instalaci Friendika musíme vÄ›dÄ›t, jak se pÅ™ipojit k databázi."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "ObraÅ¥te se na svého poskytovatele hostingu nebo administrátora serveru , pokud máte dotazy týkající se tÄ›chto nastavení."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Databázi, kterou uvedete níže by již mÄ›la existovat. Pokud tak není, prosíme, vytvoÅ™te ji pÅ™ed pokraÄováním."; +$a->strings["Database Server Name"] = "Jméno databázového serveru"; +$a->strings["Database Login Name"] = "PÅ™ihlaÅ¡ovací jméno k databázi"; +$a->strings["Database Login Password"] = "Heslo k databázovému úÄtu "; +$a->strings["Database Name"] = "Jméno databáze"; +$a->strings["Please select a default timezone for your website"] = "Prosím, vyberte výchozí Äasové pásmo pro vaÅ¡e webové stránky"; +$a->strings["Site administrator email address. Your account email address must match this in order to use the web admin panel."] = "e-mailová adresa administrárota webu. E-mailová adresa vaÅ¡eho úÄtu se musí shodovat, aby bylo možné využívat panel webové administrace."; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Nelze najít verzi PHP pro příkazový řádek v PATH webového serveru."; +$a->strings["This is required. Please adjust the configuration file .htconfig.php accordingly."] = "Tento krok je nutný. Upravte přísluÅ¡ným způsobem konfiguraÄní soubor .htconfig.php."; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "Verze PHP pro příkazový řádek na vaÅ¡em systému nemá povolen \"register_argc_argv\"."; +$a->strings["This is required for message delivery to work."] = "Toto je nutné pro fungování doruÄování zpráv."; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Chyba: funkce \"openssl_pkey_new\" na tomto systému není schopna generovat Å¡ifrovací klíÄe"; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Pokud systém běží na Windows, seznamte se s \"http://www.php.net/manual/en/openssl.installation.php\"."; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Chyba: Požadovaný Apache webserver mod-rewrite modul není nainstalován."; +$a->strings["Error: libCURL PHP module required but not installed."] = "Chyba: požadovaný libcurl PHP modul není nainstalován."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Chyba: požadovaný GD graphics PHP modul není nainstalován."; +$a->strings["Error: openssl PHP module required but not installed."] = "Chyba: požadovaný openssl PHP modul není nainstalován."; +$a->strings["Error: mysqli PHP module required but not installed."] = "Chyba: požadovaný mysqli PHP modul není nainstalován."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Chyba: PHP modul mb_string je vyžadován, ale není nainstalován."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\ in the top folder of your web server and it is unable to do so."] = "Webový instalátor musí být schopen vytvoÅ™it soubor s názvem \".htconfig.php\" v hlavním adresáři vaÅ¡eho webového serveru ale nyní mu to není umožnÄ›no."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Toto je nejÄastÄ›ji nastavením oprávnÄ›ní, kdy webový server nemusí být schopen zapisovat soubory do vaÅ¡eho adresáře - i když Vy můžete."; +$a->strings["Please check with your site documentation or support people to see if this situation can be corrected."] = "Prosím, poraÄte se s dokumentací k VaÅ¡emu hostingu nebo s technickou podporou, zda-li lze tuto situaci napravit."; +$a->strings["If not, you may be required to perform a manual installation. Please see the file \"INSTALL.txt\" for instructions."] = "Pokud ne, může být vyžadováno provedení ruÄní instalace. Prosím, seznamte se s návodem popsaným v souboru \"INSTALL.txt\"."; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Databázový konfiguraÄní soubor \".htconfig.php\" nemohl být uložen. Prosím, použijte pÅ™iložený text k vytvoÅ™ení konfiguraÄního souboru ve vaÅ¡em koÅ™enovém adresáři webového serveru."; +$a->strings["Errors encountered creating database tables."] = "PÅ™i vytváření databázových tabulek doÅ¡lo k chybám."; +$a->strings["[Embedded content - reload page to view]"] = "[Vložený obsah - obnovení stránky pro zobrazení]"; +$a->strings["Profile Match"] = "Shoda profilu"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "Žádná klíÄová slova k porovnání. Prosím, pÅ™idejte klíÄová slova do VaÅ¡eho výchozího profilu."; +$a->strings["No matches"] = "Žádné shody"; +$a->strings["Remote privacy information not available."] = "Vzdálené soukromé informace nejsou k dispozici."; +$a->strings["Visible to:"] = "Viditelné pro:"; +$a->strings["Welcome to %s"] = "Vítá Vás %s"; +$a->strings["Invalid request identifier."] = "Neplatný identifikátor požadavku."; +$a->strings["Discard"] = "Odstranit"; +$a->strings["Ignore"] = "Ignorovat"; +$a->strings["Pending Friend/Connect Notifications"] = "ÄŒekající požadavky na Přátelství / PÅ™ipojení "; +$a->strings["Show Ignored Requests"] = "Zobrazit ignorované žádosti"; +$a->strings["Hide Ignored Requests"] = "Skrýt ignorované žádosti"; +$a->strings["Notification type: "] = "Typ oznámení:"; +$a->strings["Friend Suggestion"] = "Návrh přátelství"; +$a->strings["suggested by %s"] = "navrhl %s"; +$a->strings["Approve"] = "Schválit"; +$a->strings["Claims to be known to you: "] = "VaÅ¡i údajní známí:"; +$a->strings["yes"] = "ano"; +$a->strings["no"] = "ne"; +$a->strings["Approve as: "] = "Schválit jako:"; +$a->strings["Friend"] = "Přítel"; +$a->strings["Fan/Admirer"] = "FanouÅ¡ek / obdivovatel"; +$a->strings["Friend/Connect Request"] = "Přítel / žádost o pÅ™ipojení"; +$a->strings["New Follower"] = "Nový následovník"; +$a->strings["No notifications."] = "Žádné oznámení."; +$a->strings["Invite Friends"] = "Pozvat přátele"; +$a->strings["%d invitation available"] = array( + 0 => "Pozvánka %d k dispozici", + 1 => "Pozvánky %d k dispozici", + 2 => "Pozvánky %d k dispozici", +); +$a->strings["Find People With Shared Interests"] = "Najít lidi se spoleÄnými zájmy"; +$a->strings["Connect/Follow"] = "PÅ™ipojit / Následovat"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Příklad: jan@příklad.cz, http://příklad.cz/jana"; +$a->strings["Follow"] = "Následovat"; +$a->strings["Could not access contact record."] = "Nelze získat přístup k záznamu kontaktu."; +$a->strings["Could not locate selected profile."] = "Nelze nalézt vybraný profil."; +$a->strings["Contact updated."] = "Kontakt aktualizován."; +$a->strings["Contact has been blocked"] = "Kontakt byl zablokován"; +$a->strings["Contact has been unblocked"] = "Kontakt byl odblokován"; +$a->strings["Contact has been ignored"] = "Kontakt bude ignorován"; +$a->strings["Contact has been unignored"] = "Kontakt pÅ™estal být ignorován"; +$a->strings["stopped following"] = "následování zastaveno"; +$a->strings["Contact has been removed."] = "Kontakt byl odstranÄ›n."; +$a->strings["Mutual Friendship"] = "Vzájemné přátelství"; +$a->strings["is a fan of yours"] = "je Váš fanouÅ¡ek"; +$a->strings["you are a fan of"] = "jste fanouÅ¡kem"; +$a->strings["Privacy Unavailable"] = "Ochrana soukromí není k dispozici"; +$a->strings["Private communications are not available for this contact."] = "Soukromá komunikace není dostupná pro tento kontakt."; +$a->strings["Never"] = "Nikdy"; +$a->strings["(Update was successful)"] = "(Aktualizace byla úspěšná)"; +$a->strings["(Update was not successful)"] = "(Aktualizace nebyla úspěšná)"; +$a->strings["Suggest friends"] = "NavrhnÄ›te přátelé"; +$a->strings["Contact Editor"] = "Editor kontaktu"; +$a->strings["Profile Visibility"] = "Viditelnost profilu"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Vyberte prosím profil, který chcete zobrazit %s pÅ™i zabezpeÄeném prohlížení vaÅ¡eho profilu."; +$a->strings["Contact Information / Notes"] = "Kontaktní informace / poznámky"; +$a->strings["Online Reputation"] = "Online povÄ›st"; +$a->strings["Occasionally your friends may wish to inquire about this person's online legitimacy."] = "ObÄas mohou vaÅ¡i přátelé chtít informovat o online legitimitÄ› této osoby."; +$a->strings["You may help them choose whether or not to interact with this person by providing a reputation to guide them."] = "Poskytnutím povÄ›sti jim můžete pomoci se rozhodnout, zda-li s touto osobou komunikovat Äi nikoliv."; +$a->strings["Please take a moment to elaborate on this selection if you feel it could be helpful to others."] = "VÄ›nujte prosím chvilku vyplnÄ›ní této volby, pokud máte pocit, že by mohlo být užiteÄné pro ostatní."; +$a->strings["Visit %s's profile [%s]"] = "NavÅ¡tivte profil uživatele %s [%s]"; +$a->strings["Block/Unblock contact"] = "Blokovat / Odblokovat kontakt"; +$a->strings["Ignore contact"] = "Ignorovat kontakt"; +$a->strings["Repair contact URL settings"] = "Opravit nastavení URL kontaktu"; +$a->strings["Repair contact URL settings (WARNING: Advanced)"] = "Opravit nastavení URL kontaktu (Varování: PokroÄilé)"; +$a->strings["View conversations"] = "Zobrazit konverzace"; +$a->strings["Delete contact"] = "Odstranit kontakt"; +$a->strings["Last updated: "] = "Poslední aktualizace:"; +$a->strings["Update public posts: "] = "Aktualizace veÅ™ejných příspÄ›vků:"; +$a->strings["Update now"] = "Aktualizovat"; +$a->strings["Unblock this contact"] = "Odblokovat tento kontakt"; +$a->strings["Block this contact"] = "Blokovat tento kontakt"; +$a->strings["Unignore this contact"] = "PÅ™estat ignorovat tento kontakt"; +$a->strings["Ignore this contact"] = "Ignorovat tento kontakt"; +$a->strings["Currently blocked"] = "V souÄasnosti zablokováno"; +$a->strings["Currently ignored"] = "V souÄasnosti ignorováno"; +$a->strings["Contacts"] = "Kontakty"; +$a->strings["Show Blocked Connections"] = "Zobrazit blokované spojení"; +$a->strings["Hide Blocked Connections"] = "Skrýt blokované spojení"; +$a->strings["Finding: "] = "ZjiÅ¡tÄ›ní: "; +$a->strings["Find"] = "Najít"; +$a->strings["Edit contact"] = "Editovat kontakt"; +$a->strings["No valid account found."] = "Nenalezen žádný platný úÄet."; +$a->strings["Password reset request issued. Check your email."] = "Žádost o obnovení hesla vyřízena. Zkontrolujte VaÅ¡i e-mailovou schránku."; +$a->strings["Password reset requested at %s"] = "Na %s bylo zažádáno o resetování hesla"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Žádost nemohla být ověřena. (Možná jste ji odeslali již dříve.) Obnovení hesla se nezdaÅ™ilo."; +$a->strings["Password Reset"] = "Obnovení hesla"; +$a->strings["Your password has been reset as requested."] = "VaÅ¡e heslo bylo na VaÅ¡e přání resetováno."; +$a->strings["Your new password is"] = "VaÅ¡e nové heslo je"; +$a->strings["Save or copy your new password - and then"] = "Uložte si nebo zkopírujte nové heslo - a pak"; +$a->strings["click here to login"] = "kliknÄ›te zde pro pÅ™ihlášení"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "VaÅ¡e heslo může být zmÄ›nÄ›no na stránce nastavení po úspěšném pÅ™ihlášení."; +$a->strings["Forgot your Password?"] = "ZapomnÄ›li jste heslo?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Zadejte svůj e-mailovou adresu a odeÅ¡lete žádost o zaslání VaÅ¡eho nového hesla. Poté zkontrolujte svůj e-mail pro další instrukce."; +$a->strings["Nickname or Email: "] = "PÅ™ezdívka nebo e-mail:"; +$a->strings["Reset"] = "Reset"; +$a->strings["Passwords do not match. Password unchanged."] = "Hesla se neshodují. Heslo nebylo zmÄ›nÄ›no."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Prázdné hesla nejsou povolena. Heslo nebylo zmÄ›nÄ›no."; +$a->strings["Password changed."] = "Heslo bylo zmÄ›nÄ›no."; +$a->strings["Password update failed. Please try again."] = "Aktualizace hesla se nezdaÅ™ila. Zkuste to prosím znovu."; +$a->strings["Failed to connect with email account using the settings provided."] = "NepodaÅ™ilo se pÅ™ipojit k e-mailovému úÄtu pomocí dodaného nastavení."; +$a->strings[" Please use a shorter name."] = "Prosím použijte kratší jméno."; +$a->strings[" Name too short."] = "Jméno je příliÅ¡ krátké."; +$a->strings[" Not valid email."] = "Neplatný e-mail."; +$a->strings[" Cannot change to that email."] = "Nelze provést zmÄ›nu na tento e-mail."; +$a->strings["Settings updated."] = "Nastavení aktualizováno."; +$a->strings["Account settings"] = "Nastavení úÄtu"; +$a->strings["Plugin settings"] = "Nastavení pluginu"; +$a->strings["No Plugin settings configured"] = "Žádný doplnÄ›k není nastaven"; +$a->strings["Plugin Settings"] = "Nastavení doplňku"; +$a->strings["Normal Account"] = "Normální úÄet"; +$a->strings["This account is a normal personal profile"] = "Tento úÄet je běžný osobní profil"; +$a->strings["Soapbox Account"] = "Soapbox úÄet"; +$a->strings["Automatically approve all connection/friend requests as read-only fans"] = "Automaticky schválit vÅ¡echna spojení / přátelství jako fanouÅ¡ky s právem pouze ke Ätení"; +$a->strings["Community/Celebrity Account"] = "Komunitní úÄet / ÚÄet celebrity"; +$a->strings["Automatically approve all connection/friend requests as read-write fans"] = "Automaticky schvalovat vÅ¡echny žádosti o spojení / přátelství, jako fanouÅ¡ky s právem ke Ätení."; +$a->strings["Automatic Friend Account"] = "ÚÄet s automatickým schvalováním přátel"; +$a->strings["Automatically approve all connection/friend requests as friends"] = "Automaticky schvalovat vÅ¡echny žádosti o spojení / přátelství jako přátele"; +$a->strings["OpenID:"] = "OpenID:"; +$a->strings["(Optional) Allow this OpenID to login to this account."] = "(Volitelné) Povolit OpenID pro pÅ™ihlášení k tomuto úÄtu."; +$a->strings["Publish your default profile in your local site directory?"] = "Publikovat Váš výchozí profil v místním adresáři webu?"; +$a->strings["Publish your default profile in the global social directory?"] = "Publikovat Váš výchozí profil v globální sociálním adresáři?"; +$a->strings["Hide your contact/friend list from viewers of your default profile?"] = "Skrýt VaÅ¡e kontaktní údaje a seznam přátel pÅ™ed návÅ¡tÄ›vníky ve VaÅ¡em výchozím profilu?"; +$a->strings["Hide profile details and all your messages from unknown viewers?"] = "Skrýt detaily profilu a vÅ¡echny zprávy pÅ™ed neznámými uživateli?"; +$a->strings["Profile is not published."] = "Profil není zveÅ™ejnÄ›n."; +$a->strings["or"] = "nebo"; +$a->strings["Your Identity Address is"] = "VaÅ¡e adresa identity je"; +$a->strings["Account Settings"] = "Nastavení úÄtu"; +$a->strings["Export Personal Data"] = "Export osobních údajů"; +$a->strings["Password Settings"] = "Nastavení hesla"; +$a->strings["New Password:"] = "Nové heslo:"; +$a->strings["Confirm:"] = "PotvrÄte:"; +$a->strings["Leave password fields blank unless changing"] = "Pokud nechcete zmÄ›nit heslo, položku hesla nevyplňujte"; +$a->strings["Basic Settings"] = "Základní nastavení"; +$a->strings["Full Name:"] = "Celé jméno:"; +$a->strings["Email Address:"] = "E-mailová adresa:"; +$a->strings["Your Timezone:"] = "VaÅ¡e Äasové pásmo:"; +$a->strings["Default Post Location:"] = "Výchozí umístÄ›ní příspÄ›vků:"; +$a->strings["Use Browser Location:"] = "Používat umístÄ›ní dle prohlížeÄe:"; +$a->strings["Display Theme:"] = "Vybrat grafickou Å¡ablonu:"; +$a->strings["Security and Privacy Settings"] = "Nastavení zabezpeÄení a soukromí"; +$a->strings["Maximum Friend Requests/Day:"] = "Maximální poÄet žádostí o přátelství za den:"; +$a->strings["(to prevent spam abuse)"] = "(Aby se zabránilo spamu)"; +$a->strings["Default Post Permissions"] = "Výchozí oprávnÄ›ní pro příspÄ›vek"; +$a->strings["(click to open/close)"] = "(KliknÄ›te pro otevÅ™ení/zavÅ™ení)"; +$a->strings["Allow friends to post to your profile page:"] = "Povolit přátelům příspÄ›vky na VaÅ¡i profilovou stránku:"; +$a->strings["Automatically expire posts after days:"] = "Po kolika dnech automaticky expirovat příspÄ›vky:"; +$a->strings["If empty, posts will not expire. Expired posts will be deleted"] = "Pokud je prázdné, příspÄ›vky nebudou nikdy expirovat. Expirované příspÄ›vky budou vymazány"; +$a->strings["Notification Settings"] = "Nastavení notifikací"; +$a->strings["Send a notification email when:"] = "Poslat notifikaci e-mailem, když"; +$a->strings["You receive an introduction"] = "obdržíte žádost o propojení"; +$a->strings["Your introductions are confirmed"] = "VaÅ¡e žádosti jsou potvrzeny"; +$a->strings["Someone writes on your profile wall"] = "nÄ›kdo Vám napíše na VaÅ¡i profilovou stránku"; +$a->strings["Someone writes a followup comment"] = "nÄ›kdo Vám napíše následný komentář"; +$a->strings["You receive a private message"] = "obdržíte soukromou zprávu"; +$a->strings["Email/Mailbox Setup"] = "Nastavení e-mailu"; +$a->strings["If you wish to communicate with email contacts using this service (optional), please specify how to connect to your mailbox."] = "Pokud chcete komunikovat pomocí této služby s VaÅ¡imi kontakty z e-mailu (volitelné), uveÄte, jak se pÅ™ipojit k Vaší e-mailové schránce."; +$a->strings["Last successful email check:"] = "Poslední úspěšná kontrola e-mailu:"; +$a->strings["Email access is disabled on this site."] = "Přístup k elektronické poÅ¡tÄ› je na tomto serveru zakázán."; +$a->strings["IMAP server name:"] = "jméno IMAP serveru:"; +$a->strings["IMAP port:"] = "IMAP port:"; +$a->strings["Security:"] = "ZabezpeÄení:"; +$a->strings["None"] = "Žádný"; +$a->strings["Email login name:"] = "pÅ™ihlaÅ¡ovací jméno k e-mailu:"; +$a->strings["Email password:"] = "heslo k VaÅ¡emu e-mailu:"; +$a->strings["Reply-to address:"] = "OdpovÄ›dÄ›t na adresu:"; +$a->strings["Send public posts to all email contacts:"] = "Poslat veÅ™ejné příspÄ›vky na vÅ¡echny e-mailové kontakty:"; +$a->strings["Advanced Page Settings"] = "PokroÄilé nastavení stránky"; +$a->strings["Welcome back %s"] = "Vítejte zpÄ›t %s"; +$a->strings["Manage Identities and/or Pages"] = "Správa identit a / nebo stránek"; +$a->strings["(Toggle between different identities or community/group pages which share your account details.)"] = "(PÅ™epínání mezi různými identitami nebo komunitními / skupinovými stránkami, které sdílejí VaÅ¡e detaily úÄtu.)"; +$a->strings["Select an identity to manage: "] = "Vyberte identitu pro správu:"; +$a->strings["View Conversations"] = "Zobrazit konverzace"; +$a->strings["View New Items"] = "Zobrazit nové položky"; +$a->strings["View Any Items"] = "Zobrazit vÅ¡echny položky"; +$a->strings["View Starred Items"] = "Zobrazit položky oznaÄené hvÄ›zdu"; +$a->strings["Warning: This group contains %s member from an insecure network."] = array( + 0 => "UpozornÄ›ní: Tato skupina obsahuje %s Älena z nezabezpeÄené sítÄ›.", + 1 => "UpozornÄ›ní: Tato skupina obsahuje %s Äleny z nezabezpeÄené sítÄ›.", + 2 => "UpozornÄ›ní: Tato skupina obsahuje %s Äleny z nezabezpeÄené sítÄ›.", +); +$a->strings["Private messages to this group are at risk of public disclosure."] = "Soukromé zprávy této skupinÄ› jsou vystaveny riziku prozrazení."; +$a->strings["No such group"] = "Žádná taková skupina"; +$a->strings["Group is empty"] = "Skupina je prázdná"; +$a->strings["Group: "] = "Skupina:"; +$a->strings["Contact: "] = "Kontakt:"; +$a->strings["Private messages to this person are at risk of public disclosure."] = "Soukromé zprávy této osobÄ› jsou vystaveny riziku prozrazení."; +$a->strings["Invalid contact."] = "Neplatný kontakt."; +$a->strings["Save"] = "Uložit"; +$a->strings["Welcome to Friendika"] = "Vítejte na Friendika"; +$a->strings["New Member Checklist"] = "Seznam doporuÄení pro nového Älena"; +$a->strings["We would like to offer some tips and links to help make your experience enjoyable. Click any item to visit the relevant page."] = "Dovolujeme si Vám nabídnout nÄ›které tipy a odkazy, abychom Vám zpříjemnili práci se systémem Friendika. Kliknutím na libovolnou položku navÅ¡tívit přísluÅ¡nou stránku."; +$a->strings["On your Settings page - change your initial password. Also make a note of your Identity Address. This will be useful in making friends."] = "Na stránce Nastavení - zmÄ›nit výchozí heslo. Poznamenejte si také adresu své identity. To může být užiteÄné pÅ™i navazování přátelství."; +$a->strings["Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you."] = "ProhlédnÄ›te si další nastavení, a to zejména nastavení soukromí. NezveÅ™ejnÄ›ní svého úÄtu v adresáři je jako mít nezveÅ™ejnÄ›né telefonní Äíslo. ObecnÄ› platí, že je lepší mít svůj úÄet zveÅ™ejnÄ›ný, leda by vÅ¡ichni vaÅ¡i potenciální přátelé vÄ›dÄ›li, jak vás pÅ™esnÄ› najít."; +$a->strings["Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not."] = "Nahrajte si svou profilovou fotku, pokud jste tak již neuÄinili. Studie ukázaly, že lidé se skuteÄnými fotografiemi mají desetkrát ÄastÄ›ji přátele než lidé, kteří nemají."; +$a->strings["Authorise the Facebook Connector if you currently have a Facebook account and we will (optionally) import all your Facebook friends and conversations."] = "Jestliže máte úÄet na Facebooku, povolte konektor na Facebook a bude možné (na přání) importovat vÅ¡echny VaÅ¡ přátele na Facebooku a vÅ¡echny VaÅ¡e konverzace."; +$a->strings["Enter your email access information on your Settings page if you wish to import and interact with friends or mailing lists from your email INBOX"] = "na stránce Nastavení zadejte informace pro přístup k Vaší e-mailové stránce, pokud si pÅ™ejete importovat a komunikovat s přáteli nebo distribuÄními skupinami z Vaší e-mailové schránky"; +$a->strings["Edit your default profile to your liking. Review the settings for hiding your list of friends and hiding the profile from unknown visitors."] = "Upravit výchozí profil podle vaÅ¡ich pÅ™edstav. Prověřte nastavení pro skrytí VaÅ¡eho seznamu přátel a skrytí profilu pÅ™ed neznámými návÅ¡tÄ›vníky."; +$a->strings["Set some public keywords for your default profile which describe your interests. We may be able to find other people with similar interests and suggest friendships."] = "Nastavte si nÄ›jaká veÅ™ejné klíÄová slova pro výchozí profil, která popisují vaÅ¡e zájmy. Friendika Vám může nalézt další lidi s podobnými zájmy a navrhnout přátelství."; +$a->strings["Your Contacts page is your gateway to managing friendships and connecting with friends on other networks. Typically you enter their address or site URL in the Connect dialog."] = "Stránka Kontakty je Vaším odrazovým můstkem k řízení přátelství a spojení s kamarády v jiných sítích. Obvykle zadáte jejich adresu nebo adresu URL do dialogu PÅ™ipojit."; +$a->strings["The Directory page lets you find other people in this network or other federated sites. Look for a Connect or Follow link on their profile page. Provide your own Identity Address if requested."] = "Stránka Adresář Vám pomůže najít další lidi na tomto serveru nebo v jiných propojených serverech. ProstÅ™ednictvím odkazů PÅ™ipojení nebo Následovat si prohlédnÄ›te jejich profilovou stránku. UveÄte svou vlastní adresu identity, je-li požadována."; +$a->strings["Once you have made some friends, organize them into private conversation groups from the sidebar of your Contacts page and then you can interact with each group privately on your Network page."] = "Jakmile získáte nÄ›jaké přátele, uspořádejte si je do soukromých konverzaÄních skupin na postranním panelu vaší stránky Kontakty a pak můžete komunikovat s každou touto skupinu soukromÄ› prostÅ™ednictvím stránky Síť."; +$a->strings["Our help pages may be consulted for detail on other program features and resources."] = "Na stránkách NápovÄ›da naleznete nejen další podrobnosti o vÅ¡ech funkcích Friendika ale také další zdroje informací."; +$a->strings["Item not available."] = "Položka není k dispozici."; +$a->strings["Item was not found."] = "Položka nebyla nalezena."; +$a->strings["Group created."] = "Skupina vytvoÅ™ena."; +$a->strings["Could not create group."] = "Nelze vytvoÅ™it skupinu."; +$a->strings["Group not found."] = "Skupina nenalezena."; +$a->strings["Group name changed."] = "Název skupiny byl zmÄ›nÄ›n."; +$a->strings["Permission denied"] = "NedostateÄné oprávnÄ›ní"; +$a->strings["Create a group of contacts/friends."] = "VytvoÅ™it skupinu kontaktů / přátel."; +$a->strings["Group Name: "] = "Název skupiny:"; +$a->strings["Group removed."] = "Skupina odstranÄ›na. "; +$a->strings["Unable to remove group."] = "Nelze odstranit skupinu."; +$a->strings["Click on a contact to add or remove."] = "KliknÄ›te na kontakt pro pÅ™idání nebo odebrání"; +$a->strings["Group Editor"] = "Editor skupin"; +$a->strings["Members"] = "ÄŒlenové"; +$a->strings["All Contacts"] = "VÅ¡echny kontakty"; +$a->strings["Invalid profile identifier."] = "Neplatný identifikátor profilu."; +$a->strings["Profile Visibility Editor"] = "Editor viditelnosti profilu "; +$a->strings["Visible To"] = "Viditelný pro"; +$a->strings["All Contacts (with secure profile access)"] = "VÅ¡echny kontakty (se zabezpeÄeným přístupovým profilem )"; +$a->strings["View Contacts"] = "Zobrazit kontakty"; +$a->strings["No contacts."] = "Žádné kontakty."; +$a->strings["An invitation is required."] = "Pozvánka je vyžadována."; +$a->strings["Invitation could not be verified."] = "Pozvánka nemohla být ověřena."; +$a->strings["Invalid OpenID url"] = "Neplatný odkaz OpenID"; +$a->strings["Please enter the required information."] = "Zadejte prosím požadované informace."; +$a->strings["Please use a shorter name."] = "Použijte prosím kratší jméno."; +$a->strings["Name too short."] = "Jméno je příliÅ¡ krátké."; +$a->strings["That doesn't appear to be your full (First Last) name."] = "Nezdá se, že by to bylo vaÅ¡e celé jméno (kÅ™estní jméno a příjmení)."; +$a->strings["Your email domain is not among those allowed on this site."] = "Váš e-mailová doména není na tomto serveru mezi povolenými."; +$a->strings["Not a valid email address."] = "Neplatná e-mailová adresa."; +$a->strings["Cannot use that email."] = "Tento e-mail nelze použít."; +$a->strings["Your \"nickname\" can only contain \"a-z\", \"0-9\", \"-\", and \"_\", and must also begin with a letter."] = "VaÅ¡e \"pÅ™ezdívka\" může obsahovat pouze \"a-z\", \"0-9\", \"-\", a \"_\", a musí zaÄínat písmenem."; +$a->strings["Nickname is already registered. Please choose another."] = "PÅ™ezdívka je již registrována. Prosím vyberte jinou."; +$a->strings["SERIOUS ERROR: Generation of security keys failed."] = "Závažná chyba: Generování bezpeÄnostních klíÄů se nezdaÅ™ilo."; +$a->strings["An error occurred during registration. Please try again."] = "DoÅ¡lo k chybÄ› pÅ™i registraci. Zkuste to prosím znovu."; +$a->strings["An error occurred creating your default profile. Please try again."] = "DoÅ¡lo k chybÄ› pÅ™i vytváření VaÅ¡eho výchozího profilu. Zkuste to prosím znovu."; +$a->strings["Registration details for %s"] = "RegistraÄní údaje pro %s"; +$a->strings["Registration successful. Please check your email for further instructions."] = "Registrace úspěšná. Zkontrolujte prosím svůj e-mail pro další instrukce."; +$a->strings["Failed to send email message. Here is the message that failed."] = "NepodaÅ™ilo se odeslat zprávu na e-mail. Zde je zpráva, která nebyla odeslána."; +$a->strings["Your registration can not be processed."] = "VaÅ¡i registraci nelze zpracovat."; +$a->strings["Registration request at %s"] = "Žádost o registraci na %s"; +$a->strings["Your registration is pending approval by the site owner."] = "VaÅ¡e registrace Äeká na schválení vlastníkem serveru."; +$a->strings["You may (optionally) fill in this form via OpenID by supplying your OpenID and clicking 'Register'."] = "Tento formulář můžete (volitelnÄ›) vyplnit s pomocí OpenID tím, že vyplníte své OpenID a kliknutete na tlaÄítko 'Zaregistrovat'."; +$a->strings["If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items."] = "Pokud nepoužíváte OpenID, nechte prosím toto pole prázdné a vyplňte zbylé položky."; +$a->strings["Your OpenID (optional): "] = "VaÅ¡e OpenID (nepovinné):"; +$a->strings["Include your profile in member directory?"] = "Uvést Váš profil v adresáři Älenů?"; +$a->strings["Membership on this site is by invitation only."] = "ÄŒlenství na tomto webu je pouze na pozvání."; +$a->strings["Your invitation ID: "] = "VaÅ¡e pozvání ID:"; +$a->strings["Registration"] = "Registrace"; +$a->strings["Your Full Name (e.g. Joe Smith): "] = "VaÅ¡e celé jméno (napÅ™. Jan Novák):"; +$a->strings["Your Email Address: "] = "VaÅ¡e e-mailová adresa:"; +$a->strings["Choose a profile nickname. This must begin with a text character. Your profile address on this site will then be 'nickname@\$sitename'."] = "Vyberte pÅ™ezdívku k profilu. Ta musí zaÄít s textovým znakem. VaÅ¡e profilová adresa na tomto webu pak bude \"pÅ™ezdívka@\$sitename\"."; +$a->strings["Choose a nickname: "] = "Vyberte pÅ™ezdívku:"; +$a->strings["Register"] = "Registrovat"; +$a->strings["status"] = "Stav"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s má rád %2\$s' na %3\$s"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s nemá rád %2\$s na %3\$s"; +$a->strings["This is Friendika version"] = "Toto je Friendika verze"; +$a->strings["running at web location"] = "běžící na webu"; +$a->strings["Shared content within the Friendika network is provided under the Creative Commons Attribution 3.0 license"] = "Sdílený obsah v síti Friendika je poskytována pod licencí Creative Commons Attribution 3.0"; +$a->strings["Please visit Project.Friendika.com to learn more about the Friendika project."] = "Pokud se chcete dozvÄ›dÄ›t více o projektu Friendika, navÅ¡tivte, prosím, Project.Friendika.com"; +$a->strings["Bug reports and issues: please visit"] = "Pro hlášení chyb a námÄ›tů na zmÄ›ny navÅ¡tivte:"; +$a->strings["Suggestions, praise, donations, etc. - please email \"Info\" at Friendika - dot com"] = "Návrhy, chválu, dary, atd. - prosím poÅ¡lete na e-mail \"Info\" na Friendika teÄka com"; +$a->strings["Installed plugins/addons/apps"] = "Nainstalované doplňky/aplikace"; +$a->strings["No installed plugins/addons/apps"] = "Nejsou žádné nainstalované doplňky/aplikace"; +$a->strings["Account approved."] = "ÚÄet schválen."; +$a->strings["Registration revoked for %s"] = "Registrace zruÅ¡ena pro %s"; +$a->strings["Please login."] = "PÅ™ihlaste se, prosím."; +$a->strings["Unable to locate original post."] = "Nelze nalézt původní příspÄ›vek."; +$a->strings["Empty post discarded."] = "Prázdný příspÄ›vek odstranÄ›n."; +$a->strings["Wall Photos"] = "Fotografie na zdi"; +$a->strings["noreply"] = "bez odpovÄ›di"; +$a->strings["Administrator@"] = "Administrator@"; +$a->strings["%s commented on an item at %s"] = "%s okomentoval položku v %s"; +$a->strings["%s posted to your profile wall at %s"] = "%s pÅ™idal příspÄ›vek na vaší profilovou zeÄ v %s"; +$a->strings["System error. Post not saved."] = "Chyba systému. PříspÄ›vek nebyl uložen."; +$a->strings["This message was sent to you by %s, a member of the Friendika social network."] = "Tuto zprávu Vám zaslal %s, Älen sociální sítÄ› Friendika."; +$a->strings["You may visit them online at %s"] = "Můžete je navÅ¡tívit online na adrese %s"; +$a->strings["Please contact the sender by replying to this post if you do not wish to receive these messages."] = "Pokud nechcete dostávat tyto zprávy, kontaktujte prosím odesilatele odpovÄ›dí na tento záznam."; +$a->strings["%s posted an update."] = "%s poslal aktualizaci."; +$a->strings["Image uploaded but image cropping failed."] = "Obrázek byl odeslán, ale jeho oříznutí se nesdaÅ™ilo."; +$a->strings["Image size reduction [%s] failed."] = "NepodaÅ™ilo se snížit velikost obrázku [%s]."; +$a->strings["Unable to process image"] = "Obrázek nelze zpracovat "; +$a->strings["Image exceeds size limit of %d"] = "Obrázek pÅ™ekroÄil limit velikosti %d"; +$a->strings["Upload File:"] = "Nahrát soubor:"; +$a->strings["Upload Profile Photo"] = "Nahrát profilovou fotografii"; +$a->strings["Upload"] = "Nahrát"; +$a->strings["skip this step"] = "pÅ™eskoÄit tento krok "; +$a->strings["select a photo from your photo albums"] = "Vybrat fotografii z VaÅ¡ich fotoalb"; +$a->strings["Crop Image"] = "Oříznout obrázek"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Prosím, oříznÄ›te tento obrázek pro optimální zobrazení."; +$a->strings["Done Editing"] = "Editace dokonÄena"; +$a->strings["Image uploaded successfully."] = "Obrázek byl úspěšnÄ› nahrán."; +$a->strings["No profile"] = "Žádný profil"; +$a->strings["Remove My Account"] = "Odstranit můj úÄet"; +$a->strings["This will completely remove your account. Once this has been done it is not recoverable."] = "Tímto bude kompletnÄ› odstranÄ›n váš úÄet. Jakmile bude úÄet odstranÄ›n, nebude už možné ho obnovit."; +$a->strings["Please enter your password for verification:"] = "Prosím, zadejte své heslo pro ověření:"; +$a->strings["No recipient selected."] = "Nevybrán příjemce."; +$a->strings["[no subject]"] = "[bez pÅ™edmÄ›tu]"; +$a->strings["Unable to locate contact information."] = "NepodaÅ™ilo se najít kontaktní informace."; +$a->strings["Message sent."] = "Zpráva odeslána."; +$a->strings["Message could not be sent."] = "Zprávu se nepodaÅ™ilo odeslat."; +$a->strings["Messages"] = "Zprávy"; +$a->strings["Inbox"] = "DoruÄená poÅ¡ta"; +$a->strings["Outbox"] = "Odeslaná poÅ¡ta"; +$a->strings["New Message"] = "Nová zpráva"; +$a->strings["Message deleted."] = "Zpráva odstranÄ›na."; +$a->strings["Conversation removed."] = "Konverzace odstranÄ›na."; +$a->strings["Please enter a link URL:"] = "Zadejte prosím URL odkaz:"; +$a->strings["Send Private Message"] = "Odeslat soukromou zprávu"; +$a->strings["To:"] = "Adresát:"; +$a->strings["Subject:"] = "PÅ™edmÄ›t:"; +$a->strings["Your message:"] = "VaÅ¡e zpráva:"; +$a->strings["No messages."] = "Žádné zprávy."; +$a->strings["Delete conversation"] = "Odstranit konverzaci"; +$a->strings["D, d M Y - g:i A"] = "D M R - g:i A"; +$a->strings["Message not available."] = "Zpráva není k dispozici."; +$a->strings["Delete message"] = "Smazat zprávu"; +$a->strings["Send Reply"] = "Poslat odpovÄ›Ä"; +$a->strings["Site"] = "Web"; +$a->strings["Users"] = "Uživatelé"; +$a->strings["Plugins"] = "Pluginy"; +$a->strings["Update"] = "Aktualizace"; +$a->strings["Logs"] = "Logy"; +$a->strings["User registrations waiting for confirmation"] = "Registrace uživatele Äeká na potvrzení"; +$a->strings["Item not found."] = "Položka nenalezena."; +$a->strings["Administration"] = "Administrace"; +$a->strings["Summary"] = "Shrnutí"; +$a->strings["Registered users"] = "Registrovaní uživatelé"; +$a->strings["Pending registrations"] = "ÄŒekající registrace"; +$a->strings["Version"] = "Verze"; +$a->strings["Active plugins"] = "Aktivní pluginy"; +$a->strings["Site settings updated."] = "Nastavení webu aktualizováno."; +$a->strings["Closed"] = "Uzavřít"; +$a->strings["Requires approval"] = "Vyžaduje schválení"; +$a->strings["Open"] = "OtevÅ™ená"; +$a->strings["File upload"] = "Nahrání souborů"; +$a->strings["Policies"] = "Politiky"; +$a->strings["Advanced"] = "PokroÄilé"; +$a->strings["Site name"] = "Název webu"; +$a->strings["Banner/Logo"] = "Banner/logo"; +$a->strings["System language"] = "Systémový jazyk"; +$a->strings["System theme"] = "Grafická Å¡ablona systému "; +$a->strings["Maximum image size"] = "Maximální velikost obrazu"; +$a->strings["Register policy"] = "Politika registrace"; +$a->strings["Register text"] = "Registrace textu"; +$a->strings["Allowed friend domains"] = "Povolené domény přátel"; +$a->strings["Allowed email domains"] = "Povolené e-mailové domény"; +$a->strings["Block public"] = "Blokovat veÅ™ejnost"; +$a->strings["Force publish"] = "Publikovat"; +$a->strings["Global directory update URL"] = "aktualizace URL adresy Globálního adresáře "; +$a->strings["Block multiple registrations"] = "Blokovat více registrací"; +$a->strings["OpenID support"] = "podpora OpenID"; +$a->strings["Gravatar support"] = "podpora Gravatar"; +$a->strings["Fullname check"] = "kontrola úplného jména"; +$a->strings["UTF-8 Regular expressions"] = "UTF-8 Regulární výrazy"; +$a->strings["Show Community Page"] = "Zobrazit stránku komunity"; +$a->strings["Enable OStatus support"] = "Zapnout podporu OStatus"; +$a->strings["Only allow Friendika contacts"] = "Povolit pouze Friendika kontakty "; +$a->strings["Verify SSL"] = "Ověřit SSL"; +$a->strings["Proxy user"] = "Proxy uživatel"; +$a->strings["Proxy URL"] = "Proxy URL adresa"; +$a->strings["Network timeout"] = "Äas síťového spojení vyprÅ¡elo (timeout)"; +$a->strings["%s user blocked"] = array( + 0 => "%s uživatel zablokován", + 1 => "%s uživatelů zablokováno / odblokováno", + 2 => "%s uživatelů zablokováno / odblokováno", +); +$a->strings["%s user deleted"] = array( + 0 => "%s uživatel smazán", + 1 => "%s uživatelů smazáno", + 2 => "%s uživatelů smazáno", +); +$a->strings["User '%s' deleted"] = "Uživatel '%s' smazán"; +$a->strings["User '%s' unblocked"] = "Uživatel '%s' odblokován"; +$a->strings["User '%s' blocked"] = "Uživatel '%s' blokován"; +$a->strings["select all"] = "Vybrat vÅ¡e"; +$a->strings["User registrations waiting for confirm"] = "Registrace uživatele Äeká na potvrzení"; +$a->strings["Request date"] = "Datum žádosti"; +$a->strings["Email"] = "E-mail"; +$a->strings["No registrations."] = "Žádné registrace."; +$a->strings["Deny"] = "Odmítnout"; +$a->strings["Block"] = "Blokovat"; +$a->strings["Unblock"] = "Odblokovat"; +$a->strings["Register date"] = "Datum registrace"; +$a->strings["Last login"] = "Datum posledního pÅ™ihlášení"; +$a->strings["Last item"] = "Poslední položka"; +$a->strings["Account"] = "ÚÄet"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Vybraní uživatelé budou smazáni!\\n\\n VÅ¡e, co tito uživatelé na tÄ›chto stránkách vytvoÅ™ili, bude trvale odstranÄ›no!\\n\\n Opravdu pokraÄovat?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Uživatel {0} bude smazán!\\n\\n VÅ¡e, co tento uživatel na tÄ›chto stránkách vytvoÅ™il, bude trvale odstranÄ›no!\\n\\n Opravdu pokraÄovat?"; +$a->strings["Plugin %s disabled."] = "Plugin %s zakázán."; +$a->strings["Plugin %s enabled."] = "Plugin %s povolen."; +$a->strings["Disable"] = "Zakázat"; +$a->strings["Enable"] = "Povolit"; +$a->strings["Toggle"] = "PÅ™epnout"; +$a->strings["Settings"] = "Nastavení"; +$a->strings["Log settings updated."] = "Nastavení protokolu aktualizováno."; +$a->strings["Clear"] = "VyÄistit"; +$a->strings["Debugging"] = "LadÄ›ní"; +$a->strings["Log file"] = "Soubor s logem"; +$a->strings["Must be writable by web server. Relative to your Friendika index.php."] = "Webový server musí mít práva zápisu . Relativní k index.php Friendika."; +$a->strings["Log level"] = "Úroveň auditu"; +$a->strings["Close"] = "UzavÅ™ená"; +$a->strings["FTP Host"] = "Hostitel FTP"; +$a->strings["FTP Path"] = "Cesta FTP"; +$a->strings["FTP User"] = "FTP uživatel"; +$a->strings["FTP Password"] = "FTP heslo"; +$a->strings["Access to this profile has been restricted."] = "Přístup na tento profil byl omezen."; +$a->strings["Tips for New Members"] = "Tipy pro nové Äleny"; +$a->strings["Login failed."] = "PÅ™ihlášení se nezdaÅ™ilo."; +$a->strings["Welcome "] = "Vítejte "; +$a->strings["Please upload a profile photo."] = "Prosím nahrejte profilovou fotografii"; +$a->strings["Welcome back "] = "Vítejte zpÄ›t "; +$a->strings["This site is not configured to allow communications with other networks."] = "Tento web není nakonfigurován tak, aby umožňoval komunikaci s ostatními sítÄ›mi."; +$a->strings["No compatible communication protocols or feeds were discovered."] = "Nenalezen žádný kompatibilní komunikaÄní protokol nebo kanál."; +$a->strings["The profile address specified does not provide adequate information."] = "Uvedená adresa profilu neposkytuje dostateÄné informace."; +$a->strings["An author or name was not found."] = "Autor nebo jméno nenalezeno"; +$a->strings["No browser URL could be matched to this address."] = "Této adrese neodpovídá žádné URL prohlížeÄe."; +$a->strings["The profile address specified belongs to a network which has been disabled on this site."] = "Zadaná adresa profilu patří do sítÄ›, která byla na tomto serveru zakázána."; +$a->strings["Limited profile. This person will be unable to receive direct/personal notifications from you."] = "Omezený profil. Tato osoba nebude schopna od Vás pÅ™ijímat přímé / osobní sdÄ›lení."; +$a->strings["Unable to retrieve contact information."] = "NepodaÅ™ilo se získat kontaktní informace."; +$a->strings["following"] = "následující"; +$a->strings["Item has been removed."] = "Položka byla odstranÄ›na."; +$a->strings["New mail received at "] = "PÅ™iÅ¡el nový e-mail v"; +$a->strings["Applications"] = "Aplikace"; +$a->strings["No installed applications."] = "Žádné nainstalované aplikace."; +$a->strings["Search"] = "Vyhledávání"; +$a->strings["Profile not found."] = "Profil nenalezen"; +$a->strings["Profile Name is required."] = "Jméno profilu je povinné."; +$a->strings["Profile updated."] = "Profil aktualizován."; +$a->strings["Profile deleted."] = "Profil smazán."; +$a->strings["Profile-"] = "Profil-"; +$a->strings["New profile created."] = "Nový profil vytvoÅ™en."; +$a->strings["Profile unavailable to clone."] = "Profil není možné naklonovat."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "Skrýt u tohoto profilu vaÅ¡e kontakty / seznam přátel pÅ™ed pÅ™ed dalšími uživateli zobrazující si tento profil?"; +$a->strings["Edit Profile Details"] = "Upravit podrobnosti profilu "; +$a->strings["View this profile"] = "Zobrazit tento profil"; +$a->strings["Create a new profile using these settings"] = "VytvoÅ™it nový profil pomocí tohoto nastavení"; +$a->strings["Clone this profile"] = "Klonovat tento profil"; +$a->strings["Delete this profile"] = "Smazat tento profil"; +$a->strings["Profile Name:"] = "Jméno profilu:"; +$a->strings["Your Full Name:"] = "VaÅ¡e celé jméno:"; +$a->strings["Title/Description:"] = "Název / Popis:"; +$a->strings["Your Gender:"] = "VaÅ¡e pohlaví:"; +$a->strings["Birthday (%s):"] = "Narozeniny uživatele (%s):"; +$a->strings["Street Address:"] = "Ulice:"; +$a->strings["Locality/City:"] = "MÄ›sto:"; +$a->strings["Postal/Zip Code:"] = "PSÄŒ:"; +$a->strings["Country:"] = "ZemÄ›:"; +$a->strings["Region/State:"] = "Region / stát:"; +$a->strings[" Marital Status:"] = " Rodinný stav:"; +$a->strings["Who: (if applicable)"] = "Kdo: (pokud je možné)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Příklady: jan123, Jan Novák, jan@seznam.cz"; +$a->strings["Sexual Preference:"] = "Sexuální preference:"; +$a->strings["Homepage URL:"] = "Odkaz na domovskou stránku:"; +$a->strings["Political Views:"] = "Politické pÅ™esvÄ›dÄení:"; +$a->strings["Religious Views:"] = "Náboženské pÅ™esvÄ›dÄení:"; +$a->strings["Public Keywords:"] = "VeÅ™ejná klíÄová slova:"; +$a->strings["Private Keywords:"] = "Soukromá klíÄová slova:"; +$a->strings["Example: fishing photography software"] = "Příklad: fishing photography software"; +$a->strings["(Used for suggesting potential friends, can be seen by others)"] = "(Používá se pro doporuÄování potenciálních přátel, může být vidÄ›no ostatními)"; +$a->strings["(Used for searching profiles, never shown to others)"] = "(Používá se pro vyhledávání profilů, není nikdy zobrazeno ostatním)"; +$a->strings["Tell us about yourself..."] = "ŘeknÄ›te nám nÄ›co o sobÄ› ..."; +$a->strings["Hobbies/Interests"] = "KoníÄky/zájmy"; +$a->strings["Contact information and Social Networks"] = "Kontaktní informace a sociální sítÄ›"; +$a->strings["Musical interests"] = "Hudební vkus"; +$a->strings["Books, literature"] = "Knihy, literatura"; +$a->strings["Television"] = "Televize"; +$a->strings["Film/dance/culture/entertainment"] = "Film/tanec/kultura/zábava"; +$a->strings["Love/romance"] = "Láska/romantika"; +$a->strings["Work/employment"] = "Práce/zamÄ›stnání"; +$a->strings["School/education"] = "Å kola/vzdÄ›lání"; +$a->strings["This is your public profile.
    It may be visible to anybody using the internet."] = "Toto je váš veřejný profil.
    Ten může být viditelný kýmkoliv na internetu."; +$a->strings["Age: "] = "VÄ›k: "; +$a->strings["Profiles"] = "Profily"; +$a->strings["Change profile photo"] = "ZmÄ›nit profilovou fotografii"; +$a->strings["Create New Profile"] = "VytvoÅ™it nový profil"; +$a->strings["Profile Image"] = "Profilový obrázek"; +$a->strings["visible to everybody"] = "viditelné pro vÅ¡echny"; +$a->strings["Edit visibility"] = "Upravit viditelnost"; +$a->strings["Global Directory"] = "Globální adresář"; +$a->strings["Normal site view"] = "Normální zobrazení stránky"; +$a->strings["View all site entries"] = "Zobrazit vÅ¡echny položky stránky"; +$a->strings["Site Directory"] = "Adresář serveru"; +$a->strings["Gender: "] = "Pohlaví: "; +$a->strings["No entries (some entries may be hidden)."] = "Žádné záznamy (nÄ›které položky mohou být skryty)."; +$a->strings["%s : Not a valid email address."] = "%s : není platná e-mailová adresa."; +$a->strings["Please join my network on %s"] = "Prosím, pÅ™ipojte se do mé sítÄ› na %s"; +$a->strings["%s : Message delivery failed."] = "%s : DoruÄení zprávy se nezdaÅ™ilo."; +$a->strings["%d message sent."] = array( + 0 => "%d zpráva odeslána.", + 1 => "%d zprávy odeslány.", + 2 => "%d zprávy odeslány.", +); +$a->strings["You have no more invitations available"] = "Nemáte k dispozici žádné další pozvánky"; +$a->strings["Send invitations"] = "Poslat pozvánky"; +$a->strings["Enter email addresses, one per line:"] = "Zadejte e-mailové adresy, jednu na řádek:"; +$a->strings["Please join my social network on %s"] = "Prosím, pÅ™ipojte se do mé sociální sítÄ› na %s"; +$a->strings["To accept this invitation, please visit:"] = "Chcete-li toto pozvání pÅ™ijmout, navÅ¡tivte prosím:"; +$a->strings["You will need to supply this invitation code: \$invite_code"] = "Budete muset zadat kód této pozvánky: \$invite_code"; +$a->strings["Once you have registered, please connect with me via my profile page at:"] = "Jakmile se zaregistrujete, prosím spojte se se mnou pÅ™es mou profilovu stránku na:"; +$a->strings["Response from remote site was not understood."] = "OdpovÄ›Ä ze vzdáleného serveru nebyla srozumitelná."; +$a->strings["Unexpected response from remote site: "] = "NeoÄekávaná odpovÄ›Ä od vzdáleného serveru:"; +$a->strings["Confirmation completed successfully."] = "Potvrzení úspěšnÄ› dokonÄena."; +$a->strings["Remote site reported: "] = "Vzdálený server oznámil:"; +$a->strings["Temporary failure. Please wait and try again."] = "DoÄasné selhání. Prosím, vyÄkejte a zkuste to znovu."; +$a->strings["Introduction failed or was revoked."] = "Žádost o propojení selhala nebo byla zruÅ¡ena."; +$a->strings["Unable to set contact photo."] = "Nelze nastavit fotografii kontaktu."; +$a->strings["%1\$s is now friends with %2\$s"] = "%1\$s je nyní přítel s %2\$s"; +$a->strings["No user record found for '%s' "] = "Pro '%s' nenalezen žádný uživatelský záznam "; +$a->strings["Our site encryption key is apparently messed up."] = "Náš Å¡ifrovací klÃ­Ä zÅ™ejmÄ› pÅ™estal správnÄ› fungovat."; +$a->strings["Empty site URL was provided or URL could not be decrypted by us."] = "Byla poskytnuta prázdná URL adresa nebo se nepodaÅ™ilo URL adresu deÅ¡ifrovat."; +$a->strings["Contact record was not found for you on our site."] = "Kontakt záznam nebyl nalezen pro vás na naÅ¡ich stránkách."; +$a->strings["The ID provided by your system is a duplicate on our system. It should work if you try again."] = "Váš systém poskytl duplicitní ID vůÄi naÅ¡emu systému. Pokuste se akci zopakovat."; +$a->strings["Unable to set your contact credentials on our system."] = "Nelze nastavit VaÅ¡e pÅ™ihlaÅ¡ovací údaje v naÅ¡em systému."; +$a->strings["Unable to update your contact profile details on our system"] = "Nelze aktualizovat Váš profil v naÅ¡em systému"; +$a->strings["Connection accepted at %s"] = "PÅ™ipojení pÅ™ijato na %s"; +$a->strings["Facebook disabled"] = "Facebook zakázán"; +$a->strings["Updating contacts"] = "Aktualizace kontaktů"; +$a->strings["Facebook API key is missing."] = "Chybí Facebook API klíÄ."; +$a->strings["Facebook Connect"] = "Facebook pÅ™ipojen"; +$a->strings["Install Facebook connector for this account."] = "Nainstalovat pro tento úÄet Facebook konektor."; +$a->strings["Remove Facebook connector"] = "Odstranit konektor na Facebook"; +$a->strings["Post to Facebook by default"] = "StandardnÄ› posílat příspÄ›vky na Facebook"; +$a->strings["Link all your Facebook friends and conversations"] = "PÅ™ipojit vÅ¡echny své přátele na Facebooku a konverzace"; +$a->strings["Warning: Your Facebook privacy settings can not be imported."] = "UpozornÄ›ní: nastavení ochrany osobních údajů na Facebooku nelze importovat."; +$a->strings["Linked Facebook items may be publicly visible, depending on your privacy settings for this website/account."] = "Propojené položky z Facebook mohou být veÅ™ejnÄ› viditelné, v závislosti na nastavení ochrany osobních údajů pro tuto webovou stránku/úÄet."; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Facebook Connector Settings"] = "Nastavení Facebook konektoru "; +$a->strings["Post to Facebook"] = "PÅ™idat příspÄ›vek na Facebook"; +$a->strings["Post to Facebook cancelled because of multi-network access permission conflict."] = "PříspÄ›vek na Facebook zruÅ¡en kvůli konfliktu přístupových práv mezi sítÄ›mi."; +$a->strings["Image: "] = "Obrázek: "; +$a->strings["View on Friendika"] = "Pohled na Friendiku"; +$a->strings["Facebook post failed. Queued for retry."] = "Zaslání příspÄ›vku na Facebook selhalo. PříspÄ›vek byl zaÅ™azen do fronty pro opakované odeslání."; +$a->strings["Generate new key"] = "Generovat nové klíÄe"; +$a->strings["Widgets key"] = "Widgety klíÄ"; +$a->strings["Widgets available"] = "Widgety k dispozici"; +$a->strings["Connect on Friendika!"] = "Spojit se na Friendice!"; +$a->strings["Three Dimensional Tic-Tac-Toe"] = "TrojrozmÄ›rné Tic-Tac-Toe"; +$a->strings["3D Tic-Tac-Toe"] = "3D Tic-Tac-Toe"; +$a->strings["New game"] = "Nová hra"; +$a->strings["New game with handicap"] = "Nová hra s handicapem"; +$a->strings["Three dimensional tic-tac-toe is just like the traditional game except that it is played on multiple levels simultaneously. "] = "TrojrozmÄ›rné tic-tac-toe je podobná této tradiÄní hÅ™e kromÄ› toho, že se hraje na více úrovních souÄasnÄ›."; +$a->strings["In this case there are three levels. You win by getting three in a row on any level, as well as up, down, and diagonally across the different levels."] = "V tomto případÄ› existují tÅ™i úrovnÄ›. Vyhrajete tím, že dostane tÅ™i v Å™adÄ› na jakékoli úrovni, stejnÄ› jako nahoru, dolů a Å¡ikmo na různých úrovních."; +$a->strings["The handicap game disables the center position on the middle level because the player claiming this square often has an unfair advantage."] = "Hra s handicapem zakáže centrální pozici na stÅ™ední úrovni, protože hrÃ¡Ä zaujímající tuto polohu má Äasto nespravedlivou výhodu."; +$a->strings["You go first..."] = "Vy zaÄnÄ›te ..."; +$a->strings["I'm going first this time..."] = "Tentokrát zaÄnu já..."; +$a->strings["You won!"] = "Vyhrál jste!"; +$a->strings["\"Cat\" game!"] = "\"KoÄiÄí\" hra!"; +$a->strings["I won!"] = "Vyhrál jsem!"; +$a->strings["Randplace Settings"] = "Randplace Nastavení"; +$a->strings["Enable Randplace Plugin"] = "Povolit Randplace Plugin"; +$a->strings["Upload a file"] = "Nahrát soubor"; +$a->strings["Drop files here to upload"] = "PÅ™eneste sem soubory k nahrání"; +$a->strings["Failed"] = "NeúspÄ›ch"; +$a->strings["No files were uploaded."] = "Žádné soubory nebyly nahrány."; +$a->strings["Uploaded file is empty"] = "Nahraný soubor je prázdný"; +$a->strings["File has an invalid extension, it should be one of "] = "Soubor má neplatnou příponu, ta by mÄ›la být jednou z"; +$a->strings["Upload was cancelled, or server error encountered"] = "Nahrávání bylo zruÅ¡eno nebo doÅ¡lo k chybÄ› na serveru"; +$a->strings["Impressum"] = "Impressum"; +$a->strings["Site Owner"] = "Vlastník webu"; +$a->strings["Email Address"] = "E-mailová adresa"; +$a->strings["Postal Address"] = "PoÅ¡tovní adresa"; +$a->strings["The impressum addon needs to be configured!
    Please add at least the owner variable to your config file. For other variables please refer to the README file of the addon."] = "Doplněk Impressum musí být nakonfigurován!
    Prosím, pÅ™idejte alespoň promÄ›nnou owner do konfiguraÄního souboru. Pro nastavení ostatních promÄ›nných se seznamte s nápovÄ›dou v souboru README tohoto doplňku."; +$a->strings["Site Owners Profile"] = "Profil majitele webu"; +$a->strings["Notes"] = "Poznámky"; +$a->strings["OEmbed settings updated"] = "OEmbed nastavení aktualizováno"; +$a->strings["Use OEmbed for YouTube videos"] = "Použití OEmbed pro videa na YouTube"; +$a->strings["URL to embed:"] = "URL adresa k vložení:"; +$a->strings["Post to StatusNet"] = "Poslat příspÄ›vek na StatusNet"; +$a->strings["Please contact your site administrator.
    The provided API URL is not valid."] = "Obraťte se na administratora webu.
    Poskytnutý odkaz na API není platný."; +$a->strings["We could not contact the StatusNet API with the Path you entered."] = "S cestou, kterou jste zadali, se nebylo možné spojit s API StatusNetu."; +$a->strings["StatusNet settings updated."] = "Nastavení StatusNetu aktualizováno."; +$a->strings["StatusNet Posting Settings"] = "Nastavení zasílání příspÄ›vků na StatusNet "; +$a->strings["Globally Available StatusNet OAuthKeys"] = "GlobálnÄ› dostupné StatusNet OAuth klíÄe"; +$a->strings["There are preconfigured OAuth key pairs for some StatusNet servers available. If you are useing one of them, please use these credentials. If not feel free to connect to any other StatusNet instance (see below)."] = "Jsou dostupné pÅ™ednastavené OAuth páry klíÄů pro nÄ›které servery StatusNetu. Pokud používáte nÄ›který z nich, použijte toto pÅ™ihlášení. Pokud ne, neváhejte se pÅ™ipojit k jiné instanci StatusNet (viz níže)."; +$a->strings["Provide your own OAuth Credentials"] = "UveÄte své vlastní OAuth pÅ™ihlaÅ¡ovací údaje"; +$a->strings["No consumer key pair for StatusNet found. Register your Friendika Account as an desktop client on your StatusNet account, copy the consumer key pair here and enter the API base root.
    Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Friendika installation at your favorited StatusNet installation."] = "Nenalezen žádný consumer pár klíÄů pro StatusNet. Zaregistrujte svůj Friendika úÄet jako desktopový klient na svém úÄtu StatusNetu, zkopírujte níže consumer pár klíÄů a zadejte API base root.
    Než si zaregistrujete svůj vlastní pár klíÄů OAuth, zjistÄ›te si od administrátora, zda-li už náhodou na tento Friendika server nepÅ™idal pár klíÄů pro vámi požadovanou instalaci StatusNetu."; +$a->strings["OAuth Consumer Key"] = "OAuth Consumer Key"; +$a->strings["OAuth Consumer Secret"] = "OAuth Consumer Secret"; +$a->strings["Base API Path (remember the trailing /)"] = "Cesta k Base API (nezapomeňte na koncový /)"; +$a->strings["To connect to your StatusNet account click the button below to get a security code from StatusNet which you have to copy into the input box below and submit the form. Only your public posts will be posted to StatusNet."] = "Chcete-li pÅ™ipojit k vaÅ¡emu úÄtu StatusNet kliknÄ›te na tlaÄítko níže, abyste dostati bezpeÄnostní kód ze StatusNetu, který musíte zkopírovat do vstupního pole níže a odelat formulář. Pouze VaÅ¡e veÅ™ejné příspÄ›vky budou zveÅ™ejnÄ›ny na StatusNetu."; +$a->strings["Log in with StatusNet"] = "PÅ™ihlásit se s StatusNet"; +$a->strings["Copy the security code from StatusNet here"] = "Zkopírujte sem bezpeÄnostní kód ze StatusNet"; +$a->strings["Cancel Connection Process"] = "ZruÅ¡it pÅ™ipojování"; +$a->strings["Current StatusNet API is"] = "Aktuální StatusNet API je"; +$a->strings["Cancel StatusNet Connection"] = "ZruÅ¡it StatusNet pÅ™ipojení"; +$a->strings["Currently connected to: "] = "V souÄasné dobÄ› pÅ™ipojen k:"; +$a->strings["If enabled all your public postings can be posted to the associated StatusNet account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry."] = "Je-li povoleno, vÅ¡echny VaÅ¡e veÅ™ejné příspÄ›vky mohou být zaslány na související StatusNet úÄet. Můžete si vybrat, zda-li toto bude výchozí nastavení (zde), nebo budete mít možnost si vybrat požadované chování pÅ™i psaní každého příspÄ›vku."; +$a->strings["Allow posting to StatusNet"] = "Povolit zasílání příspÄ›vků na StatusNet"; +$a->strings["Send public postings to StatusNet by default"] = "StandardnÄ› poslílat veÅ™ejné příspÄ›vky na StatusNet"; +$a->strings["Clear OAuth configuration"] = "Vymazat konfiguraci OAuth"; +$a->strings["API URL"] = "API URL"; +$a->strings["Consumer Secret"] = "Consumer Secret"; +$a->strings["Consumer Key"] = "Consumer Key"; +$a->strings["Piwik Base URL"] = "Piwik Base adresa URL"; +$a->strings["Site ID"] = "ID webu"; +$a->strings["Show opt-out cookie link?"] = "Zobrazit odkaz opt-out cookie?"; +$a->strings["Post to Twitter"] = "Poslat příspÄ›vek na Twitter"; +$a->strings["Twitter settings updated."] = "Nastavení Twitteru aktualizováno."; +$a->strings["Twitter Posting Settings"] = "Nastavení zasílání příspÄ›vků na Twitter "; +$a->strings["No consumer key pair for Twitter found. Please contact your site administrator."] = "Nenalezen žádný spotÅ™ebitelský páru klíÄů pro Twitter. ObraÅ¥te se na administrátora webu."; +$a->strings["At this Friendika instance the Twitter plugin was enabled but you have not yet connected your account to your Twitter account. To do so click the button below to get a PIN from Twitter which you have to copy into the input box below and submit the form. Only your public posts will be posted to Twitter."] = "Na tomto Friendika serveru je Twitter plugin povolen, ale jeÅ¡tÄ› nemáte svůj úÄet pÅ™ipojen ke svému Twitter úÄtu. Chcete-li tak uÄinit, klepnutím na tlaÄítko níže získejte PIN z Twitteru, který musíte zkopírovat do vstupního pole níže a odeÅ¡lete formulář. Pouze VaÅ¡e veÅ™ejné příspÄ›vky budou zveÅ™ejnÄ›ny na Twitteru."; +$a->strings["Log in with Twitter"] = "PÅ™ihlásit se s Twitter"; +$a->strings["Copy the PIN from Twitter here"] = "Zkopírujte sem PIN z Twitteru"; +$a->strings["If enabled all your public postings can be posted to the associated Twitter account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry."] = "Je-li povoleno, vÅ¡echny VaÅ¡e veÅ™ejné příspÄ›vky mohou být zaslány na související Twitter úÄet. Můžete si vybrat, zda-li toto bude výchozí nastavení (zde), nebo budete mít možnost si vybrat požadované chování pÅ™i psaní každého příspÄ›vku."; +$a->strings["Allow posting to Twitter"] = "Povolit odesílání na Twitter"; +$a->strings["Send public postings to Twitter by default"] = "DefaultnÄ› zasílat veÅ™ejné komentáře na Twitter"; +$a->strings["Consumer key"] = "Consumer key"; +$a->strings["Consumer secret"] = "Consumer secret"; +$a->strings["Gender:"] = "Pohlaví:"; +$a->strings["Birthday:"] = "Narozeniny:"; +$a->strings["j F, Y"] = "j F, Y"; +$a->strings["j F"] = "j F"; +$a->strings["Age:"] = "VÄ›k:"; +$a->strings[" Status:"] = " Status:"; +$a->strings["Homepage:"] = "Domácí stránka:"; +$a->strings["Religion:"] = "Náboženství:"; +$a->strings["About:"] = "O mÄ›:"; +$a->strings["Hobbies/Interests:"] = "KoníÄky/zájmy:"; +$a->strings["Contact information and Social Networks:"] = "Kontaktní informace a sociální sítÄ›:"; +$a->strings["Musical interests:"] = "Hudební vkus:"; +$a->strings["Books, literature:"] = "Knihy, literatura:"; +$a->strings["Television:"] = "Televize:"; +$a->strings["Film/dance/culture/entertainment:"] = "Film/tanec/kultura/zábava:"; +$a->strings["Love/Romance:"] = "Láska/romance"; +$a->strings["Work/employment:"] = "Práce/zamÄ›stnání:"; +$a->strings["School/education:"] = "Å kola/vzdÄ›lávání:"; +$a->strings["Unknown | Not categorised"] = "Neznámé | NezaÅ™azeno"; +$a->strings["Block immediately"] = "OkamžitÄ› blokovat "; +$a->strings["Shady, spammer, self-marketer"] = "pochybný, spammer, self-makerter"; +$a->strings["Known to me, but no opinion"] = "Znám ho ale, ale bez rozhodnutí"; +$a->strings["OK, probably harmless"] = "OK, pravdÄ›podobnÄ› neÅ¡kodný"; +$a->strings["Reputable, has my trust"] = "Renomovaný, má mou důvÄ›ru"; +$a->strings["Frequently"] = "ÄŒasto"; +$a->strings["Hourly"] = "každou hodinu"; +$a->strings["Twice daily"] = "Dvakrát dennÄ›"; +$a->strings["Daily"] = "dennÄ›"; +$a->strings["Weekly"] = "TýdennÄ›"; +$a->strings["Monthly"] = "MÄ›síÄnÄ›"; +$a->strings["Male"] = "Muž"; +$a->strings["Female"] = "Žena"; +$a->strings["Currently Male"] = "V souÄasné dobÄ› muž"; +$a->strings["Currently Female"] = "V souÄasné dobÄ› žena"; +$a->strings["Mostly Male"] = "VÄ›tÅ¡inou muž"; +$a->strings["Mostly Female"] = "VÄ›tÅ¡inou žena"; +$a->strings["Transgender"] = "Transgender"; +$a->strings["Intersex"] = "Intersex"; +$a->strings["Transsexual"] = "Transexuál"; +$a->strings["Hermaphrodite"] = "Hermafrodit"; +$a->strings["Neuter"] = "Neutrál"; +$a->strings["Non-specific"] = "Nespecifikováno"; +$a->strings["Other"] = "Jiné"; +$a->strings["Undecided"] = "Nerozhodnuto"; +$a->strings["Males"] = "Muži"; +$a->strings["Females"] = "Ženy"; +$a->strings["Gay"] = "Gay"; +$a->strings["Lesbian"] = "LesbiÄka"; +$a->strings["No Preference"] = "Bez preferencí"; +$a->strings["Bisexual"] = "Bisexuál"; +$a->strings["Autosexual"] = "Autosexuál"; +$a->strings["Abstinent"] = "Abstinent"; +$a->strings["Virgin"] = "panic/panna"; +$a->strings["Deviant"] = "Deviant"; +$a->strings["Fetish"] = "FetiÅ¡ista"; +$a->strings["Oodles"] = "HodnÄ›"; +$a->strings["Nonsexual"] = "Nesexuální"; +$a->strings["Single"] = "Svobodný"; +$a->strings["Lonely"] = "OsamnÄ›lý"; +$a->strings["Available"] = "Dostupný"; +$a->strings["Unavailable"] = "Nedostupný"; +$a->strings["Dating"] = "Seznamující se"; +$a->strings["Unfaithful"] = "NevÄ›rný"; +$a->strings["Sex Addict"] = "Závislý na sexu"; +$a->strings["Friends"] = "Přátelé"; +$a->strings["Friends/Benefits"] = "Přátelé / výhody"; +$a->strings["Casual"] = "Ležérní"; +$a->strings["Engaged"] = "Zadaný"; +$a->strings["Married"] = "Ženatý/vdaná"; +$a->strings["Partners"] = "PartneÅ™i"; +$a->strings["Cohabiting"] = "Žijící ve spoleÄné domácnosti"; +$a->strings["Happy"] = "Šťastný"; +$a->strings["Not Looking"] = "Nehledající"; +$a->strings["Swinger"] = "Swinger"; +$a->strings["Betrayed"] = "Zrazen"; +$a->strings["Separated"] = "OdlouÄený"; +$a->strings["Unstable"] = "Nestálý"; +$a->strings["Divorced"] = "Rozvedený(á)"; +$a->strings["Widowed"] = "OvdovÄ›lý(á)"; +$a->strings["Uncertain"] = "Nejistý"; +$a->strings["Complicated"] = "Komplikovaný"; +$a->strings["Don't care"] = "Nezajímá"; +$a->strings["Ask me"] = "Zeptej se mÄ›"; +$a->strings["l F d, Y \\@ g:i A"] = "l F d, Y \\@ g:i A"; +$a->strings["Starts:"] = "ZaÄíná:"; +$a->strings["Finishes:"] = "KonÄí:"; +$a->strings["prev"] = "pÅ™edchozí"; +$a->strings["first"] = "první"; +$a->strings["last"] = "poslední"; +$a->strings["next"] = "další"; +$a->strings["No contacts"] = "Žádné kontakty"; +$a->strings["%d Contact"] = array( + 0 => "%d kontakt", + 1 => "%d kontaktů", + 2 => "%d kontaktů", +); +$a->strings["Monday"] = "PondÄ›lí"; +$a->strings["Tuesday"] = "Úterý"; +$a->strings["Wednesday"] = "StÅ™eda"; +$a->strings["Thursday"] = "ÄŒtvrtek"; +$a->strings["Friday"] = "Pátek"; +$a->strings["Saturday"] = "Sobota"; +$a->strings["Sunday"] = "NedÄ›le"; +$a->strings["January"] = "Ledna"; +$a->strings["February"] = "Února"; +$a->strings["March"] = "BÅ™ezna"; +$a->strings["April"] = "Dubna"; +$a->strings["May"] = "KvÄ›tna"; +$a->strings["June"] = "ÄŒervna"; +$a->strings["July"] = "ÄŒervence"; +$a->strings["August"] = "Srpna"; +$a->strings["September"] = "Září"; +$a->strings["October"] = "Října"; +$a->strings["November"] = "Listopadu"; +$a->strings["December"] = "Prosince"; +$a->strings["bytes"] = "bytů"; +$a->strings["Select an alternate language"] = "VybÄ›r alternativního jazyka"; +$a->strings["Sharing notification from Diaspora network"] = "Sdílení oznámení ze sítÄ› Diaspora"; +$a->strings["Embedding disabled"] = "Vkládání zakázáno"; +$a->strings["Create a new group"] = "VytvoÅ™it novou skupinu"; +$a->strings["Everybody"] = "VÅ¡ichni"; +$a->strings["Logout"] = "Odhlásit se"; +$a->strings["End this session"] = "Konec této relace"; +$a->strings["Login"] = "PÅ™ihlásit se"; +$a->strings["Sign in"] = "PÅ™ihlásit se"; +$a->strings["Home"] = "Domů"; +$a->strings["Home Page"] = "Domácí stránka"; +$a->strings["Create an account"] = "VytvoÅ™it úÄet"; +$a->strings["Help and documentation"] = "NápovÄ›da a dokumentace"; +$a->strings["Apps"] = "Aplikace"; +$a->strings["Addon applications, utilities, games"] = "Doplňkové aplikace, nástroje, hry"; +$a->strings["Search site content"] = "Hledání na stránkách tohoto webu"; +$a->strings["Conversations on this site"] = "Konverzace na tomto webu"; +$a->strings["Directory"] = "Adresář"; +$a->strings["People directory"] = "Adresář"; +$a->strings["Network"] = "Síť"; +$a->strings["Conversations from your friends"] = "Konverzace od VaÅ¡ich přátel"; +$a->strings["Your posts and conversations"] = "VaÅ¡e příspÄ›vky a konverzace"; +$a->strings["Notifications"] = "UpozornÄ›ní"; +$a->strings["Friend requests"] = "Požadavky přátelství"; +$a->strings["Private mail"] = "Soukromá poÅ¡ta"; +$a->strings["Manage"] = "Spravovat"; +$a->strings["Manage other pages"] = "Spravovat jiné stránky"; +$a->strings["Manage/edit profiles"] = "Spravovat/upravit profily"; +$a->strings["Manage/edit friends and contacts"] = "Spravovat/upravit přátelé a kontakty"; +$a->strings["Admin"] = "Administrace"; +$a->strings["Site setup and configuration"] = "Nastavení webu a konfigurace"; +$a->strings["Logged out."] = "Odhlášen."; +$a->strings["Miscellaneous"] = "Různé"; +$a->strings["year"] = "rok"; +$a->strings["month"] = "mÄ›síc"; +$a->strings["day"] = "den"; +$a->strings["never"] = "nikdy"; +$a->strings["less than a second ago"] = "ménÄ› než pÅ™ed sekundou"; +$a->strings["years"] = "let"; +$a->strings["months"] = "mÄ›síců"; +$a->strings["week"] = "týden"; +$a->strings["weeks"] = "týdny"; +$a->strings["days"] = "dnů"; +$a->strings["hour"] = "hodina"; +$a->strings["hours"] = "hodin"; +$a->strings["minute"] = "minuta"; +$a->strings["minutes"] = "minut"; +$a->strings["second"] = "sekunda"; +$a->strings["seconds"] = "sekund"; +$a->strings[" ago"] = " nazpÄ›t"; +$a->strings["From: "] = "Od:"; +$a->strings["Image/photo"] = "Obrázek/fotografie"; +$a->strings["Cannot locate DNS info for database server '%s'"] = "Nelze nalézt záznam v DNS pro databázový server '%s'"; +$a->strings["Visible to everybody"] = "Viditelné pro vÅ¡echny"; +$a->strings["show"] = "zobrazit"; +$a->strings["don't show"] = "nikdy nezobrazit"; +$a->strings["(no subject)"] = "(Bez pÅ™edmÄ›tu)"; +$a->strings["You have a new follower at "] = "Máte nového následovníka na"; +$a->strings["event"] = "událost"; +$a->strings["View %s's profile"] = "Zobrazit %s profilu"; +$a->strings["%s from %s"] = "%s od %s"; +$a->strings["View in context"] = "Pohled v kontextu"; +$a->strings["See more posts like this"] = "Zobrazit více podobných příspÄ›vků"; +$a->strings["See all %d comments"] = "Zobrazit vÅ¡echny komentáře %d"; +$a->strings["Select"] = "Vybrat"; +$a->strings["toggle star status"] = "pÅ™epnout hvÄ›zdu"; +$a->strings["to"] = "pro"; +$a->strings["Wall-to-Wall"] = "ZeÄ-na-ZeÄ"; +$a->strings["via Wall-To-Wall:"] = "pÅ™es ZeÄ-na-ZeÄ "; +$a->strings["Delete Selected Items"] = "Smazat vybrané položky"; +$a->strings["View status"] = "Zobrazit stav"; +$a->strings["View profile"] = "Zobrazit profil"; +$a->strings["View photos"] = "Zobrazit fotografie"; +$a->strings["View recent"] = "Zobrazit poslední"; +$a->strings["Send PM"] = "Poslat soukromou zprávu"; +$a->strings["%s likes this."] = "%s se to líbí."; +$a->strings["%s doesn't like this."] = "%s se to nelíbí."; +$a->strings["%2\$d people like this."] = "%2\$d lidem se to líbí."; +$a->strings["%2\$d people don't like this."] = "%2\$d lidem se to nelíbí."; +$a->strings["and"] = "a"; +$a->strings[", and %d other people"] = ", a %d dalších lidí"; +$a->strings["%s like this."] = "%s se to líbí."; +$a->strings["%s don't like this."] = "%s se to nelíbí."; +$a->strings["Visible to everybody"] = "Viditelné pro vÅ¡echny"; +$a->strings["Please enter a YouTube link:"] = "Prosím zadejte odkaz na YouTube:"; +$a->strings["Please enter a video(.ogg) link/URL:"] = "Prosím, zadejte odkaz na video (ogg.):"; +$a->strings["Please enter an audio(.ogg) link/URL:"] = "Prosím, zadejte odkaz na audio (ogg.):"; +$a->strings["Where are you right now?"] = "Kde právÄ› jste?"; +$a->strings["Enter a title for this item"] = "Zadejte titulek pro tuto položku"; +$a->strings["Set title"] = "Nastavit titulek"; +$a->strings["Delete this item?"] = "Odstranit tuto položku?"; +$a->strings["Create a New Account"] = "VytvoÅ™it nový úÄet"; +$a->strings["Nickname or Email address: "] = "PÅ™ezdívka nebo e-mailová adresa:"; +$a->strings["Password: "] = "Heslo: "; +$a->strings["Nickname/Email/OpenID: "] = "PÅ™ezdívka/E-mail/OpenID: "; +$a->strings["Password (if not OpenID): "] = "Heslo (pokud se nepoužívá OpenID):"; +$a->strings["Forgot your password?"] = "ZapomnÄ›li jste své heslo?"; +$a->strings["Connect"] = "Spojit"; +$a->strings[", "] = ", "; +$a->strings["Status:"] = "Status:"; +$a->strings["g A l F d"] = "g A l F d"; +$a->strings["Birthday Reminders"] = "PÅ™ipomínka narozenin"; +$a->strings["Birthdays this week:"] = "Narozeniny tento týden:"; +$a->strings["(Adjusted for local time)"] = "(Upraveno pro místní Äas)"; +$a->strings["[today]"] = "[Dnes]"; +$a->strings["Not Found"] = "Nenalezen"; +$a->strings["Page not found."] = "Stránka nenalezena"; diff --git a/sources/view/cs/update_fail_eml.tpl b/sources/view/cs/update_fail_eml.tpl new file mode 100644 index 00000000..61f44b1e --- /dev/null +++ b/sources/view/cs/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hey, +I'm the web server at {{$sitename}}; + +The Hubzilla developers released update {{$update}} recently, +but when I tried to install it, something went terribly wrong. +This needs to be fixed soon and it requires human intervention. +Please contact a Red developer if you can not figure out how to +fix it on your own. My database might be invalid. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/css/bootstrap-red.css b/sources/view/css/bootstrap-red.css new file mode 100644 index 00000000..c6d99e7a --- /dev/null +++ b/sources/view/css/bootstrap-red.css @@ -0,0 +1,92 @@ +/* override some bootstrap settings */ + +/* nav overrides */ + +nav .badge { + position: relative; + top: -49px; + float: left; + font-size: 10px; + line-height: 20px; + padding: 0px 5px; + height: 20px; + min-width: 20px; + border-radius: 10px; + cursor: pointer; +} + +@media screen and (max-width: 767px) { + nav .badge { + top: -46px; + } +} + +nav i { + font-size: 14px; +} + +nav ul li { + max-height: 50px; +} + +nav img { + height: 49px; + width: 49px; + margin-top: 1px; +} + +nav .dropdown-menu { + max-height: 450px; + max-width: 300px; + overflow-y: auto; + margin-top: 0px; +} + +nav .navbar-collapse .navbar-left { + float: left; +} + +nav .navbar-collapse .navbar-right { + float: right; +} + +nav .navbar-toggle { + margin-bottom: 7px; +} + +/* nav overrides end */ + + +aside .nav-pills > li > a { + padding: 6px 10px; +} + +.dropdown-menu img { + float: left; + width: 32px; + height: 32px; + margin-right: 5px; +} + +.dropdown-menu li a { + overflow: hidden; + text-overflow: ellipsis; + line-height: 1em; + padding: 5px 10px; +} + +.nav-tabs.nav-justified > li { + white-space: nowrap; +} + +code { + white-space: normal; +} + +.form-control { + font-size: unset; +} + +/* Bootstrap assumes that checkboxes are on the left of labels, while it's usually the opposite in Red */ +.field.checkbox input[type="checkbox"] { margin-left: 0px; } +.field.checkbox label { padding-left: 0px; font-weight: 700} diff --git a/sources/view/css/choklet.css b/sources/view/css/choklet.css new file mode 100644 index 00000000..bf97e07b --- /dev/null +++ b/sources/view/css/choklet.css @@ -0,0 +1,56 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} + +#blog-banner { + position: relative; + width: 100%; + margin-bottom: 20px; +} + +nav.navbar { + width: 100%; + margin-left: 0; + margin-right: 0; +} + +#nav-backer { + width: 100%; +} + +aside#region_1 { + display: block; + min-width: 210px; + max-width: 220px; + width: 20%; + float: left; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + float: left; + min-width: 400px; + width: 70%; + display: block; + padding-bottom: 350px; +} + +#region_3 { + display: none; +} + +#blog-margin { + margin-right: 0; + margin-left: 0; +} diff --git a/sources/view/css/choklet_bannertwo.css b/sources/view/css/choklet_bannertwo.css new file mode 100644 index 00000000..92150ac9 --- /dev/null +++ b/sources/view/css/choklet_bannertwo.css @@ -0,0 +1,62 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} +#blog-banner { + position: relative; + width: 100%; + margin-bottom: 20px; + margin-left: auto; + margin-right: auto; + overflow-x: hidden; +} + +#blog-banner .widget { + border: none; +} + +main { + display: table; + table-layout: fixed; + position: relative; + width: 100%; + height: 100%; +} + +nav.navbar { + width: 100%; +} + +#nav-backer { + width: 100%; +} + +aside#region_1 { + min-width: 231px; + max-width: 231px; + display: table-cell; + width: 231px; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + width: 100%; + display: table-cell; + padding: 0 10px 200px 10px; +} + +#region_3 { + display: none; +} + + diff --git a/sources/view/css/choklet_edgesthree.css b/sources/view/css/choklet_edgesthree.css new file mode 100644 index 00000000..df936d66 --- /dev/null +++ b/sources/view/css/choklet_edgesthree.css @@ -0,0 +1,61 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} +#blog-banner { + position: relative; + margin-top: 75px; + width: 100%; + margin-bottom: 20px; +} + +nav.navbar { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +#nav-backer { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +aside#region_1 { + display: block; + min-width: 210px; + max-width: 220px; + width: 20%; + float: left; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + float: left; + min-width: 650px; + width: 60%; + display: block; + padding-bottom: 350px; +} + +#region_3 { + float: right; + min-width: 210px; + max-width: 220px; + width: 20%; +} + +#blog-margin { + margin-right: 5%; + margin-left: 5%; +} \ No newline at end of file diff --git a/sources/view/css/choklet_edgestwo.css b/sources/view/css/choklet_edgestwo.css new file mode 100644 index 00000000..a591a01c --- /dev/null +++ b/sources/view/css/choklet_edgestwo.css @@ -0,0 +1,60 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} +#blog-banner { + position: relative; + margin-top: 75px; + width: 100%; + margin-bottom: 20px; + overflow-x: hidden; +} + +nav.navbar { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +#nav-backer { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +aside#region_1 { + display: block; + min-width: 210px; + max-width: 220px; + width: 20%; + float: left; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + float: left; + min-width: 400px; + width: 70%; + display: block; + padding-bottom: 350px; +} + +#region_3 { + display: none; +} + + +#blog-margin { + margin-right: 5%; + margin-left: 5%; +} \ No newline at end of file diff --git a/sources/view/css/choklet_full.css b/sources/view/css/choklet_full.css new file mode 100644 index 00000000..d0017801 --- /dev/null +++ b/sources/view/css/choklet_full.css @@ -0,0 +1,55 @@ +#blog-banner { + position: relative; + margin-top: 45px; + width: 100%; + height: 100px; + margin-bottom: 20px; +} + +nav.navbar { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +#nav-backer { + width: 90%; + margin-left: 5%; + margin-right: 5%; +} + +aside#region_1 { + display: block; + min-width: 210px; + max-width: 220px; + width: 20%; + float: left; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + float: left; + min-width: 650px; + width: 60%; + display: block; + padding-bottom: 350px; +} + +#region_3 { + float: right; + min-width: 210px; + max-width: 220px; + width: 20%; +} + +#blog-margin { + margin-right: 5%; + margin-left: 5%; +} \ No newline at end of file diff --git a/sources/view/css/choklet_three.css b/sources/view/css/choklet_three.css new file mode 100644 index 00000000..5a305efc --- /dev/null +++ b/sources/view/css/choklet_three.css @@ -0,0 +1,57 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} +#blog-banner { + position: relative; + margin-top: 75px; + width: 100%; + margin-bottom: 20px; +} + +nav.navbar { + width: 100%; + margin-left: 0; + margin-right: 0; +} + +#nav-backer { + width: 100%; + margin-left: 0; + margin-right: 0; +} + +aside#region_1 { + display: block; + min-width: 210px; + max-width: 220px; + width: 20%; + float: left; + margin-left: 10px; +} + +aside input[type='text'] { + width: 174px; +} + + +section { + margin-left: 15px; + margin-right: 15px; + float: left; + min-width: 650px; + width: 60%; + display: block; + padding-bottom: 350px; +} + +#region_3 { + float: right; + min-width: 210px; + max-width: 220px; + width: 20%; +} + diff --git a/sources/view/css/colorbox.css b/sources/view/css/colorbox.css new file mode 100644 index 00000000..a1acfc44 --- /dev/null +++ b/sources/view/css/colorbox.css @@ -0,0 +1,45 @@ +#colorbox, #cboxOverlay, #cboxWrapper{position:absolute; top:0; left:0; z-index:1; overflow:hidden;} +#cboxWrapper {max-width:none;} +#cboxOverlay{position:fixed; width:100%; height:100%;} +#cboxMiddleLeft, #cboxBottomLeft{clear:left;} +#cboxContent{position:relative;} +#cboxLoadedContent{overflow:auto; -webkit-overflow-scrolling: touch;} +#cboxTitle{margin:0;} +#cboxLoadingOverlay, #cboxLoadingGraphic{position:absolute; top:0; left:0; width:100%; height:100%;} +#cboxPrevious, #cboxNext, #cboxClose, #cboxSlideshow{cursor:pointer;} +.cboxPhoto{float:left; margin:auto; border:0; display:block; max-width:none; -ms-interpolation-mode:bicubic;} +.cboxIframe{width:100%; height:100%; display:block; border:0; padding:0; margin:0;} +#colorbox, #cboxContent, #cboxLoadedContent{box-sizing:content-box; -moz-box-sizing:content-box; -webkit-box-sizing:content-box;} + +/* + User Style: + Change the following styles to modify the appearance of Colorbox. They are + ordered & tabbed in a way that represents the nesting of the generated HTML. +*/ +#cboxOverlay{background:url(/images/overlay.png) repeat 0 0; opacity: 0.9; filter: alpha(opacity = 90);} +#colorbox{outline:0;} + #cboxContent{background:#fff; overflow:hidden;} + .cboxIframe{background:#fff;} + #cboxError{padding:50px; border:1px solid #ccc;} + #cboxLoadedContent{margin-bottom:28px;} + #cboxTitle{position:absolute; bottom:4px; left:0; text-align:center; width:100%; color:#949494;} + #cboxCurrent{position:absolute; bottom:4px; left:58px; color:#949494;} + #cboxLoadingOverlay{background:url(/images/loading_background.png) no-repeat center center;} + #cboxLoadingGraphic{background:url(/images/loading.gif) no-repeat center center;} + + /* these elements are buttons, and may need to have additional styles reset to avoid unwanted base styles */ + #cboxPrevious, #cboxNext, #cboxSlideshow, #cboxClose {border:0; padding:0; margin:0; overflow:visible; width:auto; background:none; } + + /* avoid outlines on :active (mouseclick), but preserve outlines on :focus (tabbed navigating) */ + #cboxPrevious:active, #cboxNext:active, #cboxSlideshow:active, #cboxClose:active {outline:0;} + + #cboxSlideshow{position:absolute; bottom:4px; right:30px; color:#0092ef;} + #cboxPrevious{position:absolute; bottom:0; left:0; background:url(/images/controls.png) no-repeat -75px 0; width:25px +; height:25px; text-indent:-9999px;} + #cboxPrevious:hover{background-position:-75px -25px;} + #cboxNext{position:absolute; bottom:0; left:27px; background:url(/images/controls.png) no-repeat -50px 0; width:25px; + height:25px; text-indent:-9999px;} + #cboxNext:hover{background-position:-50px -25px;} + #cboxClose{position:absolute; bottom:0; right:0; background:url(/images/controls.png) no-repeat -25px 0; width:25px; +height:25px; text-indent:-9999px;} + #cboxClose:hover{background-position:-25px -25px;} diff --git a/sources/view/css/conversation.css b/sources/view/css/conversation.css new file mode 100644 index 00000000..7d4930aa --- /dev/null +++ b/sources/view/css/conversation.css @@ -0,0 +1,273 @@ +/* common */ + +code { + font-family: Courier, monospace; + display: block; + overflow: auto; +} + +/* jot */ + +.jothidden input { + border: 0px; + margin: 0px; + height: 39px; + width: 100%; +} + +.jothidden { + display:none; +} + +#jot-title-wrap input, +#jot-pagetitle-wrap input { + padding: 8px; + margin-bottom: 5px; +} + +.profile-jot-text { + height: 39px; + padding: 8px; + width: 100%; +} + +.jot-attachment { + padding: 8px; + width: 100%; +} + +#profile-jot-text-loading { + float: left; + padding: 30px 0px 0px 12px; +} + +#profile-jot-submit-wrapper { + margin-top: 10px; +} + +#profile-jot-perms-end { + height: 30px; +} + +#profile-jot-end { + margin-bottom: 30px; +} + +#profile-rotator-wrapper { + float: left; +} + +#profile-rotator { + margin: 16px; +} + +.profile-jot-net { + float: left; + margin-right: 10px; + margin-top: 5px; + margin-bottom: 5px; + padding: 5px; +} + +/* conversation */ + +.thread-wrapper.toplevel_item { + margin-bottom: 20px; +} + +/* conv_item */ + +.wall-item-info { + display: block; + float: left; + margin-right: 10px; +} + +.wall-item-photo-wrapper { + margin-top: 0px; + margin-bottom: 20px; +} + +.comment .wall-item-photo-wrapper { + margin-bottom: 15px; +} + +.wall-item-wrapper { + margin-left:10px; +} + +.lockview-panel { + padding: 3px 20px; +} + +.wall-item-lock { + float: left; +} + +a.wall-item-name-link { + font-weight: bold !important; +} + +.wall-item-author { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.wall-item-ago .icon-ok { + cursor: pointer; +} + +.wall-item-content { + overflow: auto; +} + +.wall-item-content h1, .wall-item-content h2 { + font-size: 1.319em; +} + +.wall-item-title h3, .wall-item-content h3, .wall-item-content h4 { + font-size: 1.112em; +} + +.wall-item-content img { + max-width: 100%; +} + +.wall-item-title h3 { + font-weight: bold; + margin: 0px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.wall-item-title-end { + clear: both; +} + +.wall-item-body { + word-wrap: break-word; +} + +.body-tag, .filesavetags, .categorytags { + opacity: 0.5; + filter:alpha(opacity=50); +} + +.body-tag:hover, .filesavetags:hover, .categorytags:hover { + opacity: 1.0 !important; + filter:alpha(opacity=100) !important; +} + +.body-tag { + margin-top: 10px; +} + +.categorytags { + margin-top: 10px; +} + +.wall-item-tools { + width: 100%; + margin-top: 10px; +} + +.item-tool { + cursor: pointer; +} + +.like-rotator { + float: right; + margin: 16px; +} + +.item-select { + opacity: 0.1; + filter:alpha(opacity=10); + float: right; + margin-right: 10px; + +} + +.item-select:hover, +.checkeditem { + opacity: 1; + filter:alpha(opacity=100); +} + +.shared_header { + margin-bottom: 20px; +} + +/* comment_item */ + +.comment-edit-text-empty, .comment-edit-text-full { + float: left; + width: 100%; +} + +.comment-edit-text-empty { + padding: 0px 8px; + line-height: 28px; + height: 30px; + overflow: hidden; + resize: none; + +} + +.comment-edit-text-full { + padding: 8px; + height: 150px; + overflow: auto; +} + +.qcomment { + border: 1px solid #EEE; + padding: 3px; + margin-top: 15px; + margin-left: 25px; + width: 125px; + overflow-y: auto; +} + +.qcomment option { + width: 125px; + overflow-x: hidden; +} + +.qcomment { + opacity: 0.3; + filter:alpha(opacity=30); +} + +.qcomment:hover { + opacity: 1.0; + filter:alpha(opacity=100); +} + +.comment-tools { + display: none; + margin-top: 7px; +} + +.comment-edit-preview { + display: none; + margin-top: 7px; +} + +/* disable link handling for unknown entries */ +.dropdown-menu > li > a.disabled { + pointer-events: none; + cursor: default; +} + +.item-verified { + color: darkgreen; + font-size: 1em !important; +} + +.item-forged { + color: #FF0000; + font-size: 1em !important; +} diff --git a/sources/view/css/custom_tinymce.css b/sources/view/css/custom_tinymce.css new file mode 100644 index 00000000..7932653b --- /dev/null +++ b/sources/view/css/custom_tinymce.css @@ -0,0 +1,41 @@ +body, td, pre {color:#000; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:14px; 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 {display:inline-block; width:11px !important; height:11px !important; background:url(img/items.gif) no-repeat 0 0;} +td.mceSelected, th.mceSelected {background-color:#3399ff !important} +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 {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; +} + +img:-moz-broken {-moz-force-broken-image-icon:1; width:24px; height:24px} +font[face=mceinline] {font-family:inherit !important} + + +object { + display: block; width: 400px; + background: #cccccc url(../images/plugin.png) no-repeat center center; +} diff --git a/sources/view/css/default.css b/sources/view/css/default.css new file mode 100644 index 00000000..f0c89a08 --- /dev/null +++ b/sources/view/css/default.css @@ -0,0 +1,41 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} + +main { + display: table; + table-layout: fixed; + position: relative; + width: 100%; + height: 100%; +} + +aside { + display: table-cell; + vertical-align: top; + padding: 80px 7px 0px 7px; + +} + +section { + width: 100%; + display: table-cell; + vertical-align: top; + padding: 80px 7px 200px 7px; +} + +@media screen and (max-width: 767px) { + + section { + padding: 65px 7px 200px 7px; + } + + aside#region_1 { + padding: 65px 7px 0px 7px; + } + +} diff --git a/sources/view/css/full.css b/sources/view/css/full.css new file mode 100644 index 00000000..05401f68 --- /dev/null +++ b/sources/view/css/full.css @@ -0,0 +1,13 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} + +section { + display: block; + min-height: 112px; + margin: 50px 10px; +} diff --git a/sources/view/css/mod_admin.css b/sources/view/css/mod_admin.css new file mode 100644 index 00000000..40974440 --- /dev/null +++ b/sources/view/css/mod_admin.css @@ -0,0 +1,72 @@ + + +/** + * ADMIN + */ +#pending-update { + float:right; + color: #ffffff; + font-weight: bold; + background-color: #FF0000; + padding: 0em 0.3em; + +} +#adminpage dl { + clear: left; + margin-bottom: 2px; + padding-bottom: 2px; + border-bottom: 1px solid black; +} +#adminpage dt { + width: 200px; + float: left; + font-weight: bold; +} +#adminpage dd { + margin-left: 200px; +} + +#adminpage h3 { + border-bottom: 1px solid #cccccc; +} +#adminpage .field label { + font-weight: bold; +} +#adminpage .submit { + clear:left; + text-align: right; +} + +#adminpage #pluginslist { + margin: 0px; padding: 0px; +} +#adminpage .plugin { + list-style: none; + display: block; + border: 1px solid #888888; + padding: 1em; + margin-bottom: 5px; + clear: left; +} +#adminpage .plugin .desc { margin-left: 2.5em;} +#adminpage .toggleplugin { + float:left; + margin-right: 1em; +} + +#adminpage table {width:100%; border-bottom: 1px solid #000000; margin: 5px 0px;} +#adminpage table th { text-align: left;} +#adminpage td .icon { float: left;} +#adminpage table#users img { width: 16px; height: 16px; } +#adminpage table tr:hover { background-color: #bbc7d7; } +#adminpage .selectall { text-align: right; } + +.checkbox_bulkedit { + width: 1.2em; + height: 1.2em; +} + +.channels_ckbx, .pending_ckbx, .users_ckbx { + margin-top: 0px !important; + margin-left: 0px !important; +} diff --git a/sources/view/css/mod_apps.css b/sources/view/css/mod_apps.css new file mode 100644 index 00000000..5e98a6a1 --- /dev/null +++ b/sources/view/css/mod_apps.css @@ -0,0 +1,6 @@ +.app-container { + float: left; + width: 125px; + height: 160px; + padding: 20px; +} diff --git a/sources/view/css/mod_blocks.css b/sources/view/css/mod_blocks.css new file mode 100644 index 00000000..36a12e1d --- /dev/null +++ b/sources/view/css/mod_blocks.css @@ -0,0 +1,36 @@ +#block-editor { + display: none; +} + +#block-list-table { + width: 100%; +} + +#block-list-table th:nth-child(1){ + padding: 7px 3px 7px 10px; + white-space: nowrap; +} + +#block-list-table td:nth-child(1){ + padding: 7px 3px 7px 10px; +} + +#block-list-table th:nth-child(2){ + white-space: nowrap; +} + +#block-list-table th:nth-child(6), +#block-list-table td:nth-child(6){ + padding: 7px 3px; + white-space: nowrap; +} + +#block-list-table th:nth-child(7), +#block-list-table td:nth-child(7){ + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.webpage-list-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/mod_chat.css b/sources/view/css/mod_chat.css new file mode 100644 index 00000000..58680bae --- /dev/null +++ b/sources/view/css/mod_chat.css @@ -0,0 +1,62 @@ + #chatContainer { + height: 100%; + width: 100%; + } + + #chatTopBar { + float: left; + height: 400px; + width: 650px; + overflow-y: auto; + } + + #chatSide { + float: right; + width: 150px; + height: 100%; + } + + #chatDrop { + margin-bottom: 20px; +} + + #chatUsers { + border: 1px solid #000; +} + + #chatBottomBar { + position: relative; + bottom: 0; + height: 150px; + margin-top: 20px; + } + + section { + padding-bottom: 0; + } + +.chat-item { + padding: 3px; +} + +.chat-item-end { + clear: both; +} + +.chat-item-photo { + float: left; + height: 32px; + width: 32px; +} + +.chat-body { + float: left; + width: 80%; + margin-left: 15px; +} + +.chat-item-text { + float: left; + padding: 3px; + display: inline-block; +} diff --git a/sources/view/css/mod_cloud.css b/sources/view/css/mod_cloud.css new file mode 100644 index 00000000..76ac8269 --- /dev/null +++ b/sources/view/css/mod_cloud.css @@ -0,0 +1,43 @@ +#files-mkdir-tools, +#files-upload-tools, +[id^="perms-panel-"] { + display: none; +} + +[id^="perms-panel-"] { + padding: 3px 10px 0px 10px !important; +} + +#attach-code, +#link-code { + display: none; +} + +#cloud-index { + width: 100%; +} + +#cloud-index td:nth-child(1){ + padding: 7px 3px 7px 10px; +} + +#cloud-index th:nth-child(8), +#cloud-index td:nth-child(8){ + padding: 7px 3px; + white-space: nowrap; +} + +#cloud-index th:nth-child(9), +#cloud-index td:nth-child(9){ + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.cloud-index-tool { + padding: 7px 10px; +} + +#files-upload { + padding: 4px; + width: 100%; +} diff --git a/sources/view/css/mod_connect.css b/sources/view/css/mod_connect.css new file mode 100644 index 00000000..e1f28484 --- /dev/null +++ b/sources/view/css/mod_connect.css @@ -0,0 +1,11 @@ +.sellpage-body { + margin-top: 25px; +} + +.sellpage-final { + margin-top: 25px; +} + +#sellpage-edit > label { + width: 300px; +} diff --git a/sources/view/css/mod_connections.css b/sources/view/css/mod_connections.css new file mode 100644 index 00000000..09702717 --- /dev/null +++ b/sources/view/css/mod_connections.css @@ -0,0 +1,147 @@ + +.search-input { + padding: 4px 12px; + margin: 3px; +} + +.field_abook_help { + color: #000; +} +.abook-them { + margin-left: 375px; + margin-bottom: 15px; +} +.abook-me { + margin-left: 36px; + margin-bottom: 15px; +} +.acheckbox { + margin-bottom: 5px !important; +} + +.abook-pending-contact { + background: orange; + font-weight: bold; + margin: 10px; + padding: 20px 5px 10px; +} + +#contact-slider { + width: 600px !important; +} + +.abook-edit-them, .abook-edit-me { + float: left; + width: 100px !important; +} +.field_abook_help { + float: left; +} + +#contacts-main { + margin-top: 20px; + margin-bottom: 20px; +} + + + +#contact-edit-wrapper { + margin-top: 10px; +} + +#contact-edit-banner-name { + font-size: 1.4em; + font-weight: bold; +} + +#contact-edit-poll-wrapper { + margin-top: 15px; +} + +#contact-edit-poll-text { + margin-top: 15px; + margin-bottom: 5px; +} + +#contact-edit-update-now { + margin-top: 15px; +} + +#contact-edit-links{ + clear: both; +} + +#contact-edit-links ul { + list-style: none; + list-style-type: none; + margin-left: 0px; + padding-left: 0px; +} + +#contact-edit-links li { + margin-top: 5px; +} + +#contact-edit-drop-link { + float: right; + margin-right: 20px; +} + +#contact-edit-nav-end { + clear: both; +} + +#contact-edit-wrapper { + width: 100%; +} + +#contact-edit-end { + clear: both; + margin-top: 15px; +} + +#contact-profile-selector { + width: 175px; + margin-left: 175px; +} + +.contact-edit-submit { + margin-top: 20px; +} + +.contact-entry-wrapper { + float: left; + width: 120px; + height: 150px; + padding: 10px; + margin: 8px 10px 0 0; + border-top: 1px solid #eee; + border-left: 2px solid #eee; +} + +#contacts-search { + font-size: 1em; + width: 300px; +} + +#contacts-search-end { + margin-bottom: 10px; +} + +.contact-entry-photo-end { + clear: both; +} + +.contact-entry-name { + float: left; + margin-left: 0px; + margin-right: 10px; + margin-bottom: 10px; + width: 120px; + height: 36px; + overflow: hidden; +} + +.contact-entry-end { + clear: both; +} diff --git a/sources/view/css/mod_connedit.css b/sources/view/css/mod_connedit.css new file mode 100644 index 00000000..87eff66d --- /dev/null +++ b/sources/view/css/mod_connedit.css @@ -0,0 +1,18 @@ +.abook-them, +.abook-me { + font-weight: bold; +} + +.slider { + position: relative; + left: 1%; + padding-bottom: 15px; +} + +#perms-tool-table { + width: 100%; +} + +#perms-tool-table td { + vertical-align: top; +} diff --git a/sources/view/css/mod_directory.css b/sources/view/css/mod_directory.css new file mode 100644 index 00000000..8e55ac3b --- /dev/null +++ b/sources/view/css/mod_directory.css @@ -0,0 +1,31 @@ +.directory-photo-img { + width: 80px; + height: 80px; + border: none; +} + +.directory-item { + margin-bottom: 20px; +} + +.contact-photo-wrapper { + display: table-cell; + table-layout: fixed; + vertical-align: top; +} + +.contact-info { + display: table-cell; + table-layout: fixed; + vertical-align: top; + padding-left: 10px; +} + +.contact-info-label { + font-weight: bold; +} + +.section-subtitle-wrapper .btn-xs { + margin-top: -2px; +} + diff --git a/sources/view/css/mod_display.css b/sources/view/css/mod_display.css new file mode 100644 index 00000000..dde242d4 --- /dev/null +++ b/sources/view/css/mod_display.css @@ -0,0 +1,3 @@ +#jot-popup { + display: none; +} diff --git a/sources/view/css/mod_events.css b/sources/view/css/mod_events.css new file mode 100644 index 00000000..a8e6415c --- /dev/null +++ b/sources/view/css/mod_events.css @@ -0,0 +1,55 @@ + +#event-desc-textarea, #event-location-textarea { + width: 400px; +} + +#event-summary-text, #event-start-text, #event-finish-text { + width: 200px; + float: left; +} + +#event-summary, #start_text { + width: 95%; + float: left; +} + +#finish_text { + width: 100%; + float: left; +} + + +#event-category-wrap { + margin-top: 15px; +} + +.event-cats { + margin-top: 15px; +} + +.bootstrap-tagsinput { + width: 100%; +} + + +.required { + float: left; + cursor: default; +} + +#event-datetime-break { + clear: both; +} + +#event-nofinish-break { + margin-bottom: 10px; +} + +#event-desc-text, #event-location-text, .event-form-location-end { + margin-top: 15px; +} + +#event-edit-preview-btn { + margin-right: 15px; +} + diff --git a/sources/view/css/mod_filestorage.css b/sources/view/css/mod_filestorage.css new file mode 100644 index 00000000..22f8a53d --- /dev/null +++ b/sources/view/css/mod_filestorage.css @@ -0,0 +1,12 @@ +#attach-edit-backlink, #cutpasteinput, #linkpasteinput { + margin-bottom: 10px; +} + +#attach-edit-submit { + margin-top: 20px; +} + +#cutpasteinput, #linkpasteinput { + width: 600px; +} + diff --git a/sources/view/css/mod_group.css b/sources/view/css/mod_group.css new file mode 100644 index 00000000..b828e551 --- /dev/null +++ b/sources/view/css/mod_group.css @@ -0,0 +1,66 @@ + +#group-new-submit-wrapper { + margin-top: 30px; +} +/* +#group-edit-form > label { + float: left; + width: 300px; +} + +#group-edit-form input { + float: left; + width: 175px; +} + +#group-edit-form .field { + clear: both; +} +*/ +#group-edit-submit-wrapper input { + clear: both; + width: 100px; +} + +#group-edit-select-end { + clear: both; +} +/* +#group-edit-name-label { + float: left; + width: 175px; + margin-top: 20px; + margin-bottom: 20px; +} + +#group-edit-name { + float: left; + width: 225px; + margin-top: 20px; + margin-bottom: 20px; +} + +#group-edit-name-wrapper { + + +} +*/ + +#group_members_select_label { + display: block; + float: left; + width: 175px; +} + +.group_members_select { + float: left; + width: 230px; + overflow: auto; +} + +#group_members_select_end { + clear: both; +} +#group-edit-name-end { + clear: both; +} diff --git a/sources/view/css/mod_import.css b/sources/view/css/mod_import.css new file mode 100644 index 00000000..8b988b32 --- /dev/null +++ b/sources/view/css/mod_import.css @@ -0,0 +1,37 @@ +h2 { + margin-left: 15%; + margin-top: 8%; +} + +#import-channel-form { + font-size: 1.4em; + margin-left: 15%; + margin-top: 5%; + width: 50%; +} + + + +#import-channel-form .descriptive-paragraph { + color: #888; + margin-left: 20px; + margin-bottom: 25px; +} + +.import-label { + float: left; + width: 275px; +} + +.import-input { + float: left; + width: 275px; + padding: 5px; +} + + +.import-field-end { + clear: both; + margin-bottom: 20px; +} + diff --git a/sources/view/css/mod_layouts.css b/sources/view/css/mod_layouts.css new file mode 100644 index 00000000..8e0a945b --- /dev/null +++ b/sources/view/css/mod_layouts.css @@ -0,0 +1,36 @@ +#layout-editor { + display: none; +} + +#layout-list-table { + width: 100%; +} + +#layout-list-table th:nth-child(1){ + padding: 7px 3px 7px 10px; + white-space: nowrap; +} + +#layout-list-table td:nth-child(1){ + padding: 7px 3px 7px 10px; +} + +#layout-list-table th:nth-child(2){ + white-space: nowrap; +} + +#layout-list-table th:nth-child(6), +#layout-list-table td:nth-child(6){ + padding: 7px 3px; + white-space: nowrap; +} + +#layout-list-table th:nth-child(7), +#layout-list-table td:nth-child(7){ + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.webpage-list-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/mod_locs.css b/sources/view/css/mod_locs.css new file mode 100644 index 00000000..95aee6ae --- /dev/null +++ b/sources/view/css/mod_locs.css @@ -0,0 +1,3 @@ +td { +padding: 10px; +} diff --git a/sources/view/css/mod_mail.css b/sources/view/css/mod_mail.css new file mode 100644 index 00000000..11affffb --- /dev/null +++ b/sources/view/css/mod_mail.css @@ -0,0 +1,96 @@ +/* message */ + +#mail-list-wrapper { + border-top: 1px solid #ccc; + padding: 5px 5px 5px 5px; +} + +span.mail-list { + float: left; + width: 20%; +} + +img.mail-list-sender-photo { + height: 24px; + width: 24px; + float: left; + margin-right: 30px; +} + +.mail-list-remove { + width: 5% !important; +} + +/* message/new */ + +#prvmail-to-label, +#prvmail-subject-label, +#prvmail-expires-label, +#prvmail-message-label { + margin-bottom: 10px; + margin-top: 20px; +} + +#prvmail-submit { + float: left; + margin-top: 10px; + margin-right: 30px; +} + +#prvmail-upload-wrapper, +#prvmail-attach-wrapper, +#prvmail-link-wrapper, +#prvmail-expire-wrapper, +#prvmail-encrypt-wrapper, +#prvmail-rotator-wrapper { + float: left; + margin-top: 10px; + cursor: pointer; +} + +#prvmail-end { + clear: both; +} + +/* message/id */ + +.mail-conv-outside-wrapper { + margin-top: 30px; +} + +.mail-conv-sender, +.mail-conv-detail { + float: left; +} + +.mail-conv-detail { + margin-left: 20px; + width: 500px; +} + +.mail-conv-subject { + font-size: 1.4em; + margin: 10px 0; +} + +.mail-conv-delete-wrapper { + float: right; + margin-right: 30px; + margin-top: 15px; + margin-bottom: 5px; +} + +.mail-conv-recall-wrapper { + float: right; + margin-right: 10px; + margin-top: 15px; + margin-bottom: 5px; +} + +.mail-conv-outside-wrapper-end { + clear: both; +} + +.mail-conv-break { + clear: both; +} diff --git a/sources/view/css/mod_manage.css b/sources/view/css/mod_manage.css new file mode 100644 index 00000000..fbe4a672 --- /dev/null +++ b/sources/view/css/mod_manage.css @@ -0,0 +1,57 @@ +#channels-selected { + color: #666666; + font-size: 0.8em; +} + +#channels-desc { + color: #666666; + font-size: 1.2em; + margin-top: 15px; + margin-bottom: 20px; +} + +.channels-break { + margin-bottom: 15px; +} + +.channel-selection-default { + font-size: 0.8em; + margin-bottom: 10px; +} + +.channel-selection { + width: 12em; + height: 16em; + float: left; + text-align: center; +} + +.channel-selection img { + display: block; + margin-left: auto; + margin-right: auto; +} + +.channel-selection-name-link { + font-size: 1.2em; + margin-top: 10px; +} + +.channel-selection-name-link .channel-name { + padding-top: 10px; + word-wrap: break-word; + overflow: hidden; +} + +.channels-notifications-wrapper { + clear: both; + padding-top: 10px; +} + +.selected-channel img { + border: 2px solid #ff0000; +} + +.channels-end { + clear: both; +} \ No newline at end of file diff --git a/sources/view/css/mod_menu.css b/sources/view/css/mod_menu.css new file mode 100644 index 00000000..7f0f4024 --- /dev/null +++ b/sources/view/css/mod_menu.css @@ -0,0 +1,24 @@ +#menu-list-table { + width: 100%; +} + +#menu-list-table th:nth-child(2), +#menu-list-table th:nth-child(3) { + white-space: nowrap; +} + +#menu-list-table th:nth-child(7), +#menu-list-table td:nth-child(7) { + padding: 7px 3px; + white-space: nowrap; +} + +#menu-list-table th:nth-child(8), +#menu-list-table td:nth-child(8) { + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.menu-list-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/mod_message.css b/sources/view/css/mod_message.css new file mode 100644 index 00000000..011c3edd --- /dev/null +++ b/sources/view/css/mod_message.css @@ -0,0 +1,100 @@ +/* message */ + +#mail-list-wrapper { + border-top: 1px solid #ccc; + padding: 5px 5px 5px 5px; +} + +span.mail-list { + float: left; + width: 20%; +} + +img.mail-list-sender-photo { + height: 24px; + width: 24px; + float: left; + margin-right: 30px; +} + +.mail-list-remove { + width: 5% !important; +} + +/* message/new */ + +#prvmail-to-label, +#prvmail-subject-label, +#prvmail-expires-label, +#prvmail-message-label { + margin-bottom: 10px; + margin-top: 20px; +} + +#prvmail-submit { + float: left; + margin-top: 10px; + margin-right: 30px; +} + +#prvmail-upload-wrapper, +#prvmail-attach-wrapper, +#prvmail-link-wrapper, +#prvmail-expire-wrapper, +#prvmail-encrypt-wrapper, +#prvmail-rotator-wrapper { + float: left; + margin-top: 10px; +/* margin-right: 10px; + width: 24px; */ + cursor: pointer; +} + +#prvmail-end { + clear: both; +} + +/* message/id */ + +.mail-conv-outside-wrapper { + margin-top: 30px; +} + +.mail-conv-sender, +.mail-conv-detail { + float: left; +} + +.mail-conv-detail { + margin-left: 20px; + width: 500px; +} + +.mail-conv-subject { + font-size: 1.4em; + margin: 10px 0; +} + +.mail-conv-delete-wrapper { + float: right; + margin-right: 30px; + margin-top: 15px; +} + +.mail-conv-delete-icon { + border: none; +} + +.mail-conv-recall-wrapper { + float: right; + margin-right: 10px; + margin-top: 15px; +} + +.mail-conv-outside-wrapper-end { + clear: both; +} + +.mail-conv-break { + clear: both; +} diff --git a/sources/view/css/mod_mitem.css b/sources/view/css/mod_mitem.css new file mode 100644 index 00000000..0718096e --- /dev/null +++ b/sources/view/css/mod_mitem.css @@ -0,0 +1,13 @@ +#mitem-list-table { + width: 100%; +} + +#mitem-list-table th:nth-child(1), +#mitem-list-table td:nth-child(1){ + padding: 7px 3px 7px 10px; + white-space: nowrap; +} + +.mitem-list-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/mod_new_channel.css b/sources/view/css/mod_new_channel.css new file mode 100644 index 00000000..39760163 --- /dev/null +++ b/sources/view/css/mod_new_channel.css @@ -0,0 +1,172 @@ + +h2 { + margin-left: 15%; + margin-top: 5%; +} + +#newchannel-form { + font-size: 1.4em; + margin-left: 15%; + margin-top: 20px; + width: 50%; +} + +#newchannel-form .descriptive-paragraph { + color: #888; + margin-left: 20px; + margin-bottom: 25px; +} + +.newchannel-label { + float: left; + width: 275px; +} + +.newchannel-role-morehelp { + float: left; + width: 32px; +} +.newchannel-input { + float: left; + width: 275px; + padding: 5px; +} + +.newchannel-feedback { + float: left; + margin-left: 5px; +} + +.newchannel-field-end { + clear: both; + margin-bottom: 20px; +} + +/** +* Stylish Select 0.4.9 - $ plugin to replace a select drop down box with a stylable unordered list +* http://github.com/scottdarby/Stylish-Select/ +* +* Copyright (c) 2009 Scott Darby +* +* Requires: jQuery 1.3 or newer +* +* Dual licensed under the MIT and GPL licenses. +*/ + +/** +* Hide lists on page load +---------------------------------------------------------*/ + +.stylish-select .SSContainerDivWrapper { + left:-9999px; +} + +/* +* Red example +---------------------------------------------------------*/ +.stylish-select .SSContainerDivWrapper { + margin:0; + padding:0; + width:290px; + position:absolute; + top:22px; + left:0; + z-index:9999; + font-size: 60%; + line-height: 1.1; +} + +.stylish-select a { + font-weight: normal !important; +} + +.stylish-select ul.newList { + margin:0; + padding:0; + list-style:none; + color:#000; + background:#fff; + border:1px solid #ccc; + overflow:auto; +} + +.stylish-select ul.newList * { + margin:0; + padding:0; +} + + +.stylish-select ul.newList a { + color: #000; + text-decoration:none; + display:block; + padding:3px 8px; +} + +.stylish-select .newListSelected { + width:285px; + color:#000; + height:19px; + padding:3px 0 0 6px; + float:left; + background:url(select-bg.png) no-repeat; +} + +.stylish-select ul.newList li a:focus { + -moz-outline-style: none; +} + +.stylish-select .selectedTxt { + width:258px; + overflow:hidden; + height:18px; + font-size: 90%; + padding:0 23px 0 0; +} + +.stylish-select .hiLite { + background:#650101!important; + color:#fff!important; +} + +.stylish-select .newListHover { + background:#ccc!important; + color:#000!important; + cursor:default; +} + +.stylish-select .newListDisabled { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); +} + +.stylish-select .newListItemDisabled { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); +} + +.stylish-select .newListOptionDisabled { + opacity: 0.6; + -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=60)"; + filter: alpha(opacity=60); +} + +.stylish-select .newListSelHover, +.stylish-select .newListSelFocus { + background-position:0 -22px; + cursor:default; +} + +.stylish-select .newListOptionTitle { + font-weight:bold; +} + +.stylish-select .newListOptionTitle ul { + margin:3px 0 0; +} + +.stylish-select .newListOptionTitle li { + font-weight:normal; +} \ No newline at end of file diff --git a/sources/view/css/mod_page.css b/sources/view/css/mod_page.css new file mode 100644 index 00000000..a0b63775 --- /dev/null +++ b/sources/view/css/mod_page.css @@ -0,0 +1,14 @@ + +.page-author { + font-size: 1.2em; + margin-bottom: 12px; +} + +.page-date { + margin-bottom: 10px; +} + + +.page-body { + +} diff --git a/sources/view/css/mod_photos.css b/sources/view/css/mod_photos.css new file mode 100644 index 00000000..7718289c --- /dev/null +++ b/sources/view/css/mod_photos.css @@ -0,0 +1,36 @@ +.photos-end { + clear: both; + margin-bottom: 25px; +} + +.photo-item-tools-left, +.photo-item-tools-right { + padding: 7px 10px; +} + +.photo-like-rotator { + margin-top: 23px; + margin-right: 5px; +} + +#photo-photo { + display: table; + margin: 0 auto; +} + +#photo-edit, +#photo-album-edit-wrapper, +#photo-upload-form { + display: none; +} + +#photos-upload-choose { + padding: 4px; + width: 100%; +} + +#photo-map { + position: absolute; + left: -9999px; + top: -9999px; +} \ No newline at end of file diff --git a/sources/view/css/mod_profile.css b/sources/view/css/mod_profile.css new file mode 100644 index 00000000..e1ceae7f --- /dev/null +++ b/sources/view/css/mod_profile.css @@ -0,0 +1,16 @@ +.aprofile dt { + font-weight: bold; +} + +.profile-thing-list { + list-style-type: none; +} + +.profile-thing-list img { + margin-bottom: 5px; +} + +.profile-thing-list > li { + margin-bottom: 15px; +} + diff --git a/sources/view/css/mod_profile_photo.css b/sources/view/css/mod_profile_photo.css new file mode 100644 index 00000000..5540b5fa --- /dev/null +++ b/sources/view/css/mod_profile_photo.css @@ -0,0 +1,12 @@ +.form-label { + margin-bottom: 15px; + float: left; + width: 150px; +} +.form-input { + margin-bottom: 15px; +} + +#profile-photo-submit-wrapper { + clear: both; +} \ No newline at end of file diff --git a/sources/view/css/mod_profiles.css b/sources/view/css/mod_profiles.css new file mode 100644 index 00000000..35ef73ce --- /dev/null +++ b/sources/view/css/mod_profiles.css @@ -0,0 +1,150 @@ +#profile-edit-default-desc { + background: none repeat scroll 0 0 orange; + font-weight: bold; + margin: 10px; + padding: 20px 5px 10px; +} + +#profile-edit-clone-link-wrapper { + float: left; + margin-left: 50px; + margin-bottom: 20px; + width: 300px; +} + + +#profile-listing-desc, #profile-stuff-link, #profile-listing-new-link-wrapper { + margin: 15px 10px 15px 0; +} + +#profile-edit-links-end { + clear: both; + margin-bottom: 15px; +} + +.profile-listing-photo { + border: none; +} + +.profile-edit-submit-wrapper { + margin-top: 20px; + margin-bottom: 20px; +} + +#profile-photo-link-select-wrapper { + margin-top: 2em; +} + +#profile-photo-submit-wrapper { + margin-top: 10px; +} + +#profile-edit-with-label, #profile-edit-howlong-label { + + width: 175px; + margin-left: 50px; + margin-bottom: 20px; +} + +#profile-edit-profile-name-label, +#profile-edit-name-label, +#profile-edit-pdesc-label, +#profile-edit-gender-label, +#profile-edit-dob-label, +#profile-edit-address-label, +#profile-edit-locality-label, +#profile-edit-region-label, +#profile-edit-postal-code-label, +#profile-edit-country-name-label, +#profile-edit-marital-label, +#profile-edit-sexual-label, +#profile-edit-politic-label, +#profile-edit-religion-label, +#profile-edit-pubkeywords-label, +#profile-edit-prvkeywords-label, +#profile-edit-homepage-label, +#profile-edit-hometown-label { + float: left; + width: 175px; +} + +#profile-edit-profile-name, +#profile-edit-name, +#profile-edit-pdesc, +#gender-select, +#profile-edit-dob, +#profile-edit-address, +#profile-edit-locality, +#profile-edit-region, +#profile-edit-postal-code, +#profile-edit-country-name, +#marital-select, +#sexual-select, +#profile-edit-politic, +#profile-edit-religion, +#profile-edit-pubkeywords, +#profile-edit-prvkeywords, +#profile-in-dir-yes, +#profile-in-dir-no, +#profile-in-netdir-yes, +#profile-in-netdir-no, +#hide-wall-yes, +#hide-wall-no, +#hide-friends-yes, +#hide-friends-no { + float: left; + margin-bottom: 20px; +} + + +#profile-edit-pdesc-desc, +#profile-edit-pubkeywords-desc, +#profile-edit-prvkeywords-desc { + float: left; + margin-left: 20px; +} + + +#profile-edit-homepage, #profile-edit-hometown { + float: left; + margin-bottom: 35px; +} + +#profile-edit-profile-name-end, +#profile-edit-name-end, +#profile-edit-pdesc-end, +#profile-edit-gender-end, +#profile-edit-dob-end, +#profile-edit-address-end, +#profile-edit-locality-end, +#profile-edit-region-end, +#profile-edit-postal-code-end, +#profile-edit-country-name-end, +#profile-edit-marital-end, +#profile-edit-sexual-end, +#profile-edit-politic-end, +#profile-edit-religion-end, +#profile-edit-pubkeywords-end, +#profile-edit-prvkeywords-end, +#profile-edit-homepage-end, +#profile-edit-hometown-end, +#profile-in-dir-break, +#profile-in-dir-end, +#profile-in-netdir-break, +#profile-in-netdir-end, +#hide-wall-break, +#hide-wall-end, +#hide-friends-break, +#hide-friends-end { + clear: both; +} + + +#gender-select, #marital-select, #sexual-select { + width: 220px; +} + +#profile-edit-profile-name-wrapper .required { + color: #FF0000; + float: left; +} diff --git a/sources/view/css/mod_pubsites.css b/sources/view/css/mod_pubsites.css new file mode 100644 index 00000000..34cf624d --- /dev/null +++ b/sources/view/css/mod_pubsites.css @@ -0,0 +1,3 @@ +td { + padding: 5px; +} \ No newline at end of file diff --git a/sources/view/css/mod_rate.css b/sources/view/css/mod_rate.css new file mode 100644 index 00000000..58e87b9b --- /dev/null +++ b/sources/view/css/mod_rate.css @@ -0,0 +1,8 @@ +#rating-slider { + width: 600px !important; +} + +#rating-text { + width: 400px; + height: 60px; +} diff --git a/sources/view/css/mod_ratings.css b/sources/view/css/mod_ratings.css new file mode 100644 index 00000000..c9f75c58 --- /dev/null +++ b/sources/view/css/mod_ratings.css @@ -0,0 +1,21 @@ +.contact-photo-wrapper { + float: left; + width: 120px; +} + +.prep-details { + float: left; +} + +.directory-item { + margin: 10px; +} + +.rating-value { + margin-top: 10px; +} + +.prep-rating-value { + margin-left: 10px; + font-size: 1.5rem; +} \ No newline at end of file diff --git a/sources/view/css/mod_register.css b/sources/view/css/mod_register.css new file mode 100644 index 00000000..b662610a --- /dev/null +++ b/sources/view/css/mod_register.css @@ -0,0 +1,40 @@ + +h2 { + margin-left: 5%; + margin-top: 5%; +} + +#register-form { + font-size: 1.4em; + margin-left: 10%; + margin-top: 5%; +} + +#register-desc, #register-text, #register-sites { + font-weight: bold; + margin-bottom: 15px; + padding: 8px; + border: 1px solid #ccc; +} + +.register-label { + float: left; + width: 275px; +} + +.register-input { + float: left; + width: 275px; + padding: 5px; +} + +.register-feedback { + float: left; + margin-left: 45px; +} + +.register-field-end { + clear: both; + margin-bottom: 20px; +} + diff --git a/sources/view/css/mod_settings.css b/sources/view/css/mod_settings.css new file mode 100644 index 00000000..7eff8e45 --- /dev/null +++ b/sources/view/css/mod_settings.css @@ -0,0 +1,3 @@ +.group { + margin-left: 10px; +} diff --git a/sources/view/css/mod_setup.css b/sources/view/css/mod_setup.css new file mode 100644 index 00000000..ee725d05 --- /dev/null +++ b/sources/view/css/mod_setup.css @@ -0,0 +1,34 @@ +#install-dbhost-label, +#install-dbuser-label, +#install-dbpass-label, +#install-dbdata-label, +#install-tz-desc { + float: left; + width: 250px; + margin-top: 10px; + margin-bottom: 10px; + +} + +#install-dbhost, +#install-dbuser, +#install-dbpass, +#install-dbdata { + float: left; + width: 200px; + margin-left: 20px; +} + +#install-dbhost-end, +#install-dbuser-end, +#install-dbpass-end, +#install-dbdata-end, +#install-tz-end { + clear: both; +} + +#install-form select#timezone_select { + float: left; + margin-top: 18px; + margin-left: 20px; +} diff --git a/sources/view/css/mod_sharedwithme.css b/sources/view/css/mod_sharedwithme.css new file mode 100644 index 00000000..8bf626de --- /dev/null +++ b/sources/view/css/mod_sharedwithme.css @@ -0,0 +1,23 @@ +#cloud-index { + width: 100%; +} + +#cloud-index td:nth-child(1){ + padding: 7px 3px 7px 10px; +} + +#cloud-index th:nth-child(4), +#cloud-index td:nth-child(4){ + padding: 7px 3px; + white-space: nowrap; +} + +#cloud-index th:nth-child(5), +#cloud-index td:nth-child(5){ + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.cloud-index-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/mod_thing.css b/sources/view/css/mod_thing.css new file mode 100644 index 00000000..1b091860 --- /dev/null +++ b/sources/view/css/mod_thing.css @@ -0,0 +1,20 @@ + + +.thing-profile #contact-profile-selector { + margin-left: 0; +} + +.thing-label, .field > label, .thing-verb-label, .thing-profile-label{ + float: left; + width: 350px; +} + +.thing-input, .thing-verb, .thing-profile{ + float: left; + margin-bottom: 15px; + width: 400px; +} + +.thing-field-end { + clear: both; +} diff --git a/sources/view/css/mod_viewconnections.css b/sources/view/css/mod_viewconnections.css new file mode 100644 index 00000000..56add4ca --- /dev/null +++ b/sources/view/css/mod_viewconnections.css @@ -0,0 +1,33 @@ + + +.contact-entry-wrapper { + float: left; + width: 120px; + height: 120px; + padding: 10px; +} + +#contacts-search { + font-size: 1em; + width: 300px; +} + +#contacts-search-end { + margin-bottom: 10px; +} + +.contact-entry-photo-end { + clear: both; +} + +.contact-entry-name { + float: left; + margin-left: 0px; + margin-right: 10px; + width: 120px; + overflow: hidden; +} + +.contact-entry-end { + clear: both; +} diff --git a/sources/view/css/mod_webpages.css b/sources/view/css/mod_webpages.css new file mode 100644 index 00000000..1c6ec4ae --- /dev/null +++ b/sources/view/css/mod_webpages.css @@ -0,0 +1,36 @@ +#webpage-editor { + display: none; +} + +#webpage-list-table { + width: 100%; +} + +#webpage-list-table th:nth-child(1){ + padding: 7px 3px 7px 10px; + white-space: nowrap; +} + +#webpage-list-table td:nth-child(1){ + padding: 7px 3px 7px 10px; +} + +#webpage-list-table th:nth-child(2){ + white-space: nowrap; +} + +#webpage-list-table th:nth-child(7), +#webpage-list-table td:nth-child(7){ + padding: 7px 3px; + white-space: nowrap; +} + +#webpage-list-table th:nth-child(8), +#webpage-list-table td:nth-child(8){ + padding: 7px 10px 7px 7px; + white-space: nowrap; +} + +.webpage-list-tool { + padding: 7px 10px; +} diff --git a/sources/view/css/redable.css b/sources/view/css/redable.css new file mode 100644 index 00000000..b8e31eab --- /dev/null +++ b/sources/view/css/redable.css @@ -0,0 +1,105 @@ +header #banner { + position: fixed; + top: 0; + width: 250px; + margin-left: auto; + margin-right: auto; +} + +main { + display: table; + table-layout: fixed; + position: relative; + width: 100%; + height: 100%; +} + +@media screen and (max-width: 801px) { + main { + left: -14rem !important; + right: -14rem !important; + width: calc(100% + 14rem + 14rem) !important; +} + +#profile-photo-wrapper { + display:none; +} +} + +aside#region_1 { + width: 14rem; + min-width: 14rem; + max-width: 14rem; + display: table-cell; + vertical-align: top; + padding: 65px 7px 0px 7px; + } + +aside#region_1 * { + font-size: 0.8rem; + line-height: 1.45; +} + +aside input[type='text'] { + width: 100%; +} + +section#region_2wrap { + width: 100%; + display: table-cell; + vertical-align: top; + padding: 65px 10px 200px 10px; +} + +section#region_2 { + max-width: 36rem; + margin-left: auto; + margin-right: auto; + vertical-align: top; +} + +section#region_2 * { + text-align: justify; + font-size: 1.15rem; + line-height: 1.55; +} + +section#region_2 p + p { + margin-top: 1.5em; +} + +aside#region_3 { + width: 14rem; + min-width: 14rem; + max-width: 14rem; + display: table-cell; + vertical-align: top; + padding: 65px 7px 0px 7px; +} + +aside#region_3 * { + font-size: 0.8rem; + line-height: 1.45; +} + +h1 { + font-size: 1.39em !important; + text-align: left !important; +} + +h2 { + font-size: 1.18em !important; + text-align: left !important; +} + +h1 *, h2 * { + font-size: 1em !important; +} + +li { + text-align: left !important; +} + +.widget, .pmenu { +border-bottom: none !important; +} diff --git a/sources/view/css/widgets.css b/sources/view/css/widgets.css new file mode 100644 index 00000000..c1b80dab --- /dev/null +++ b/sources/view/css/widgets.css @@ -0,0 +1,124 @@ +.widget { + margin-bottom: 10px; + padding: 10px; +} + +.widget h3 { + margin-top: 0px; +} + +.widget-input { + width: 100%; + border-top-right-radius: 0px; + border-bottom-right-radius: 0px; +} + +.tags { + word-wrap: break-word; +} + +/* suggest */ + +.suggest-widget-more { + margin-top: 10px; +} + +/* follow */ + +#side-follow-url { + margin-top: 5px; +} + +#side-follow-submit { + margin-top: 15px; +} + +/* notes */ + +#note-text { + padding: 5px; + width: 100%; + resize: vertical; + height: 250px; +} + +/* saved searches */ + +#saved-search-list { + margin-top: 2px; +} + + +/* affinity slider */ +#main-slider { + margin: 10px 7px 45px 7px; +} + +/* posted date */ + +.posted-date-selector-months { + margin: 2px 0px 0px 10px; +} + +#posted-date-selector li:not(:first-child) { + margin-top: 2px; +} + +#posted-date-selector-drop li:not(:first-child) { + margin-top: 2px; +} + +/* categories */ + + +/* group */ + +a.group-edit-tool { + z-index: 1; +} + +.group-edit-icon { + opacity: 0; +} + +li:hover .group-edit-icon { + opacity: 1; +} + +/* Chatrooms */ + +.chatroomlist td { + padding: 0 5px 0; +} + +/* ratings */ + +.directory-rating { + float: right; + margin-right: 5px; +} + +.rating-text-label { + margin-top: 30px; +} + +.directory-rating-text { + width: 90%; + margin-left: 5%; +} + +.directory-rating-submit { + margin-top: 15px; +} + + +/* tasklist */ + +.tasklist-tasks { + max-height: 300px; + overflow-y: auto; +} + +#tasklist-new-summary { + width: 250px; +} diff --git a/sources/view/de/htconfig.tpl b/sources/view/de/htconfig.tpl new file mode 100644 index 00000000..550b018f --- /dev/null +++ b/sources/view/de/htconfig.tpl @@ -0,0 +1,103 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Red Matrix"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// Recommend you leave this set to 1. Set to 0 to let people register without +// proving they own the email address they register with. + +$a->config['system']['verify_email'] = 1; + + +// Site access restrictions. By default we will create private sites. +// Your choices are ACCESS_PRIVATE, ACCESS_PAID, ACCESS_TIERED, and ACCESS_FREE. +// If you leave REGISTER_OPEN above, anybody may register on your +// site, however your site will not be listed anywhere as an open +// registration hub. We will use the system access policy (below) +// to determine whether or not to list your site in the directory +// as an open hub where anybody may create accounts. Your choice of +// paid, tiered, or free determines how these listings will be presented. + + +$a->config['system']['access_policy'] = ACCESS_PRIVATE; + +// If you operate a public site, you might wish that people are directed +// to a "sellpage" where you can describe for features or policies or service plans in depth. +// This must be an absolute URL beginning with http:// or https:// . + +$a->config['system']['sellpage'] = ''; + +// Maximum size of an imported message, 0 is unlimited +// FIXME - NOT currently implemented. + +$a->config['system']['max_import_size'] = 200000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + + +// PHP error logging setup +// Before doing this ensure that the webserver has permission +// to create and write to php.out in the top level Red directory, +// or change the name (below) to a file/path where this is allowed. + +// Uncomment the following 4 lines to turn on PHP error logging. +//error_reporting(E_ERROR | E_WARNING | E_PARSE ); +//ini_set('error_log','php.out'); +//ini_set('log_errors','1'); +//ini_set('display_errors', '0'); diff --git a/sources/view/de/lostpass_eml.tpl b/sources/view/de/lostpass_eml.tpl new file mode 100644 index 00000000..02a71b77 --- /dev/null +++ b/sources/view/de/lostpass_eml.tpl @@ -0,0 +1,30 @@ + +Hallo {{$username}}, +auf {{$sitename}} wurde eine Rücksetzung Deines Passwortes angefordert. +Bitte klicke auf den Link unten, um diese Anforderung zu bestätigen, +oder kopiere den Link und füge ihn in die Adresszeile Deines Browsers ein. + +Falls Du KEINE Rücksetzung Deines Passwortes angefordert hast, folge dem Link +NICHT! Ignoriere einfach diese E-Mail. + +Dein Passwort wird nicht geändert, wenn Du nicht auf den +Link klickst. + +Folge diesem Link, um Dein Passwort zurückzusetzen: + +{{$reset_link}} + +Du wirst dann eine E-Mail mit dem neuen Passwort bekommen. + +Du solltest das Passwort nach dem Einloggen in den Einstellungen ändern. + +Die Anmeldedetails lauten wie folgt: + +Adresse des Servers: {{$siteurl}} +Username: {{$email}} + + + + +Viele Grüße, +der Administrator von {{$sitename}} diff --git a/sources/view/de/messages.po b/sources/view/de/messages.po new file mode 100644 index 00000000..ef27fd16 --- /dev/null +++ b/sources/view/de/messages.po @@ -0,0 +1,8769 @@ +# Red Matrix Project +# Copyright (C) 2012-2014 the Red Matrix Project +# This file is distributed under the same license as the Red package. +# +# Translators: +# Alex , 2013 +# Alex , 2013 +# Balder , 2013 +# Balder , 2013 +# bavatar , 2013 +# JooBee , 2014 +# Einer von Vielen , 2013 +# Einer von Vielen , 2013 +# Ettore Atalan , 2014-2015 +# Frank Dieckmann , 2013 +# Frank Dieckmann , 2013 +# Kai , 2015 +# Oliver , 2013-2014 +# Phellmes , 2014 +# Steff , 2015 +# bavatar , 2013-2014 +# do.t , 2014 +# zottel , 2013-2015 +# sasiflo , 2014 +msgid "" +msgstr "" +"Project-Id-Version: Red Matrix\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-02-20 00:04-0800\n" +"PO-Revision-Date: 2015-02-27 09:55+0000\n" +"Last-Translator: zottel \n" +"Language-Team: German (http://www.transifex.com/projects/p/red-matrix/language/de/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: de\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../../include/dba/dba_driver.php:142 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "Kann die DNS-Informationen für den Datenbank-Server '%s' nicht finden" + +#: ../../include/photo/photo_driver.php:680 ../../include/photos.php:52 +#: ../../mod/profile_photo.php:143 ../../mod/profile_photo.php:302 +#: ../../mod/profile_photo.php:424 ../../mod/photos.php:91 +#: ../../mod/photos.php:625 +msgid "Profile Photos" +msgstr "Profilfotos" + +#: ../../include/photos.php:15 ../../include/attach.php:137 +#: ../../include/attach.php:184 ../../include/attach.php:247 +#: ../../include/attach.php:261 ../../include/attach.php:301 +#: ../../include/attach.php:315 ../../include/attach.php:339 +#: ../../include/attach.php:532 ../../include/attach.php:606 +#: ../../include/chat.php:116 ../../include/items.php:4072 +#: ../../mod/profile.php:64 ../../mod/profile.php:72 +#: ../../mod/achievements.php:30 ../../mod/editblock.php:65 +#: ../../mod/manage.php:6 ../../mod/api.php:26 ../../mod/api.php:31 +#: ../../mod/blocks.php:67 ../../mod/blocks.php:75 ../../mod/connedit.php:321 +#: ../../mod/editpost.php:13 ../../mod/profile_photo.php:264 +#: ../../mod/profile_photo.php:277 ../../mod/block.php:22 +#: ../../mod/block.php:72 ../../mod/network.php:12 ../../mod/events.php:219 +#: ../../mod/settings.php:560 ../../mod/group.php:9 ../../mod/setup.php:207 +#: ../../mod/common.php:35 ../../mod/suggest.php:26 +#: ../../mod/connections.php:169 ../../mod/item.php:197 ../../mod/item.php:205 +#: ../../mod/item.php:938 ../../mod/thing.php:247 ../../mod/thing.php:264 +#: ../../mod/thing.php:299 ../../mod/pdledit.php:21 ../../mod/appman.php:66 +#: ../../mod/authtest.php:13 ../../mod/editlayout.php:64 +#: ../../mod/editlayout.php:89 ../../mod/chat.php:90 ../../mod/chat.php:95 +#: ../../mod/editwebpage.php:64 ../../mod/editwebpage.php:86 +#: ../../mod/editwebpage.php:118 ../../mod/rate.php:110 +#: ../../mod/invite.php:13 ../../mod/invite.php:104 ../../mod/locs.php:77 +#: ../../mod/sources.php:66 ../../mod/menu.php:61 ../../mod/filestorage.php:18 +#: ../../mod/filestorage.php:72 ../../mod/filestorage.php:87 +#: ../../mod/filestorage.php:114 ../../mod/fsuggest.php:78 +#: ../../mod/poke.php:128 ../../mod/profiles.php:188 +#: ../../mod/profiles.php:576 ../../mod/viewsrc.php:14 +#: ../../mod/webpages.php:67 ../../mod/delegate.php:6 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +#: ../../mod/regmod.php:17 ../../mod/message.php:16 ../../mod/mitem.php:106 +#: ../../mod/mood.php:111 ../../mod/layouts.php:67 ../../mod/layouts.php:74 +#: ../../mod/layouts.php:85 ../../mod/like.php:178 ../../mod/mail.php:114 +#: ../../mod/notifications.php:66 ../../mod/new_channel.php:68 +#: ../../mod/new_channel.php:99 ../../mod/photos.php:68 ../../mod/page.php:28 +#: ../../mod/page.php:78 ../../mod/bookmarks.php:46 ../../mod/channel.php:90 +#: ../../mod/channel.php:199 ../../mod/channel.php:242 +#: ../../mod/register.php:72 ../../mod/service_limits.php:7 +#: ../../mod/sharedwithme.php:7 ../../index.php:190 ../../index.php:390 +msgid "Permission denied." +msgstr "Zugang verweigert" + +#: ../../include/photos.php:105 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "Bild überschreitet das Limit der Webseite von %lu bytes" + +#: ../../include/photos.php:112 +msgid "Image file is empty." +msgstr "Bilddatei ist leer." + +#: ../../include/photos.php:141 ../../mod/profile_photo.php:217 +msgid "Unable to process image" +msgstr "Kann Bild nicht verarbeiten" + +#: ../../include/photos.php:213 +msgid "Photo storage failed." +msgstr "Foto speichern schlug fehl" + +#: ../../include/photos.php:355 ../../include/conversation.php:1589 +msgid "Photo Albums" +msgstr "Fotoalben" + +#: ../../include/photos.php:359 +msgid "Upload New Photos" +msgstr "Lade neue Fotos hoch" + +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "Neuer Beitrag wurde erzeugt" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +msgstr "hat %s's Beitrag kommentiert" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "Neue Seite" + +#: ../../include/page_widgets.php:8 ../../include/page_widgets.php:36 +#: ../../include/RedDAV/RedBrowser.php:267 ../../include/ItemObject.php:100 +#: ../../include/apps.php:254 ../../include/menu.php:42 +#: ../../mod/editblock.php:143 ../../mod/blocks.php:132 +#: ../../mod/editpost.php:113 ../../mod/settings.php:645 +#: ../../mod/connections.php:382 ../../mod/connections.php:395 +#: ../../mod/connections.php:414 ../../mod/thing.php:233 +#: ../../mod/editlayout.php:139 ../../mod/editwebpage.php:174 +#: ../../mod/menu.php:78 ../../mod/webpages.php:162 ../../mod/layouts.php:167 +msgid "Edit" +msgstr "Bearbeiten" + +#: ../../include/page_widgets.php:39 ../../mod/blocks.php:135 +#: ../../mod/webpages.php:165 ../../mod/layouts.php:171 +msgid "View" +msgstr "Ansicht" + +#: ../../include/page_widgets.php:40 ../../include/ItemObject.php:677 +#: ../../include/conversation.php:1152 ../../mod/events.php:651 +#: ../../mod/webpages.php:166 ../../mod/photos.php:964 +msgid "Preview" +msgstr "Vorschau" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:167 +msgid "Actions" +msgstr "Aktionen" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:168 +msgid "Page Link" +msgstr "Seiten-Link" + +#: ../../include/page_widgets.php:43 ../../mod/webpages.php:169 +msgid "Title" +msgstr "Titel" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:170 +msgid "Created" +msgstr "Erstellt" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:171 +msgid "Edited" +msgstr "Geändert" + +#: ../../include/widgets.php:35 ../../include/taxonomy.php:255 +#: ../../include/contact_widgets.php:92 +msgid "Categories" +msgstr "Kategorien" + +#: ../../include/widgets.php:91 ../../include/nav.php:163 +#: ../../mod/apps.php:34 +msgid "Apps" +msgstr "Apps" + +#: ../../include/widgets.php:92 +msgid "System" +msgstr "System" + +#: ../../include/widgets.php:94 ../../include/conversation.php:1494 +msgid "Personal" +msgstr "Persönlich" + +#: ../../include/widgets.php:95 +msgid "Create Personal App" +msgstr "Persönliche App erstellen" + +#: ../../include/widgets.php:96 +msgid "Edit Personal App" +msgstr "Persönliche App bearbeiten" + +#: ../../include/widgets.php:136 ../../include/widgets.php:175 +#: ../../include/identity.php:840 ../../include/Contact.php:107 +#: ../../include/conversation.php:940 ../../mod/suggest.php:51 +#: ../../mod/directory.php:272 ../../mod/match.php:62 +msgid "Connect" +msgstr "Verbinden" + +#: ../../include/widgets.php:138 ../../mod/suggest.php:53 +msgid "Ignore/Hide" +msgstr "Ignorieren/Verstecken" + +#: ../../include/widgets.php:143 ../../mod/connections.php:268 +msgid "Suggestions" +msgstr "Vorschläge" + +#: ../../include/widgets.php:144 +msgid "See more..." +msgstr "Mehr anzeigen …" + +#: ../../include/widgets.php:166 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "Du bist %1$.0f von maximal %2$.0f erlaubten Verbindungen eingegangen." + +#: ../../include/widgets.php:172 +msgid "Add New Connection" +msgstr "Neue Verbindung hinzufügen" + +#: ../../include/widgets.php:173 +msgid "Enter the channel address" +msgstr "Adresse des Kanals eingeben" + +#: ../../include/widgets.php:174 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Beispiel: bob@beispiel.com, http://beispiel.com/barbara" + +#: ../../include/widgets.php:190 +msgid "Notes" +msgstr "Notizen" + +#: ../../include/widgets.php:192 ../../include/text.php:838 +#: ../../include/text.php:850 ../../mod/filer.php:50 ../../mod/rbmark.php:28 +#: ../../mod/rbmark.php:98 ../../mod/admin.php:1344 ../../mod/admin.php:1365 +msgid "Save" +msgstr "Speichern" + +#: ../../include/widgets.php:264 +msgid "Remove term" +msgstr "Eintrag löschen" + +#: ../../include/widgets.php:272 ../../include/features.php:72 +msgid "Saved Searches" +msgstr "Gespeicherte Suchanfragen" + +#: ../../include/widgets.php:273 ../../include/group.php:303 +msgid "add" +msgstr "hinzufügen" + +#: ../../include/widgets.php:302 ../../include/features.php:84 +#: ../../include/contact_widgets.php:57 +msgid "Saved Folders" +msgstr "Gespeicherte Ordner" + +#: ../../include/widgets.php:305 ../../include/contact_widgets.php:60 +#: ../../include/contact_widgets.php:95 +msgid "Everything" +msgstr "Alles" + +#: ../../include/widgets.php:347 +msgid "Archives" +msgstr "Archive" + +#: ../../include/widgets.php:425 +msgid "Refresh" +msgstr "Aktualisieren" + +#: ../../include/widgets.php:426 ../../mod/connedit.php:563 +msgid "Me" +msgstr "Ich" + +#: ../../include/widgets.php:427 ../../mod/connedit.php:566 +msgid "Best Friends" +msgstr "Beste Freunde" + +#: ../../include/widgets.php:428 ../../include/identity.php:387 +#: ../../include/identity.php:388 ../../include/identity.php:395 +#: ../../include/profile_selectors.php:80 ../../mod/connedit.php:567 +#: ../../mod/settings.php:335 ../../mod/settings.php:339 +#: ../../mod/settings.php:340 ../../mod/settings.php:343 +#: ../../mod/settings.php:354 +msgid "Friends" +msgstr "Freunde" + +#: ../../include/widgets.php:429 +msgid "Co-workers" +msgstr "Kollegen" + +#: ../../include/widgets.php:430 ../../mod/connedit.php:568 +msgid "Former Friends" +msgstr "ehem. Freunde" + +#: ../../include/widgets.php:431 ../../mod/connedit.php:569 +msgid "Acquaintances" +msgstr "Bekannte" + +#: ../../include/widgets.php:432 +msgid "Everybody" +msgstr "Jeder" + +#: ../../include/widgets.php:466 +msgid "Account settings" +msgstr "Konto-Einstellungen" + +#: ../../include/widgets.php:472 +msgid "Channel settings" +msgstr "Kanal-Einstellungen" + +#: ../../include/widgets.php:478 +msgid "Additional features" +msgstr "Zusätzliche Funktionen" + +#: ../../include/widgets.php:484 +msgid "Feature/Addon settings" +msgstr "Plugin-Einstellungen" + +#: ../../include/widgets.php:490 +msgid "Display settings" +msgstr "Anzeige-Einstellungen" + +#: ../../include/widgets.php:496 +msgid "Connected apps" +msgstr "Verbundene Apps" + +#: ../../include/widgets.php:502 +msgid "Export channel" +msgstr "Kanal exportieren" + +#: ../../include/widgets.php:511 ../../mod/connedit.php:627 +msgid "Connection Default Permissions" +msgstr "Standardzugriffsrechte für neue Verbindungen:" + +#: ../../include/widgets.php:519 +msgid "Premium Channel Settings" +msgstr "Premium-Kanal-Einstellungen" + +#: ../../include/widgets.php:527 ../../include/features.php:61 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "Kanal-Quellen" + +#: ../../include/widgets.php:535 ../../include/nav.php:210 +#: ../../include/apps.php:134 ../../mod/admin.php:956 ../../mod/admin.php:1161 +msgid "Settings" +msgstr "Einstellungen" + +#: ../../include/widgets.php:548 ../../mod/message.php:31 +#: ../../mod/mail.php:128 +msgid "Messages" +msgstr "Nachrichten" + +#: ../../include/widgets.php:551 +msgid "Check Mail" +msgstr "E-Mails abrufen" + +#: ../../include/widgets.php:556 ../../include/nav.php:201 +msgid "New Message" +msgstr "Neue Nachricht" + +#: ../../include/widgets.php:634 +msgid "Chat Rooms" +msgstr "Chaträume" + +#: ../../include/widgets.php:654 +msgid "Bookmarked Chatrooms" +msgstr "Gespeicherte Chatrooms" + +#: ../../include/widgets.php:674 +msgid "Suggested Chatrooms" +msgstr "Chatraum-Vorschläge" + +#: ../../include/widgets.php:801 ../../include/widgets.php:859 +msgid "photo/image" +msgstr "Foto/Bild" + +#: ../../include/widgets.php:954 ../../include/widgets.php:956 +msgid "Rate Me" +msgstr "Bewerte mich" + +#: ../../include/widgets.php:960 +msgid "View Ratings" +msgstr "Bewertungen ansehen" + +#: ../../include/widgets.php:971 +msgid "Public Hubs" +msgstr "Öffentliche Hubs" + +#: ../../include/enotify.php:41 +msgid "Red Matrix Notification" +msgstr "Red Matrix Benachrichtigung" + +#: ../../include/enotify.php:42 +msgid "redmatrix" +msgstr "redmatrix" + +#: ../../include/enotify.php:44 +msgid "Thank You," +msgstr "Danke." + +#: ../../include/enotify.php:46 +#, php-format +msgid "%s Administrator" +msgstr "der Administrator von %s" + +#: ../../include/enotify.php:81 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:85 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "[Red:Benachrichtigung] Neue Mail auf %s empfangen" + +#: ../../include/enotify.php:87 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "%1$s, %2$s hat Dir eine private Nachricht auf %3$s gesendet." + +#: ../../include/enotify.php:88 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s hat Dir %2$s geschickt." + +#: ../../include/enotify.php:88 +msgid "a private message" +msgstr "eine private Nachricht" + +#: ../../include/enotify.php:89 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Bitte besuche %s, um die private Nachricht anzusehen und/oder darauf zu antworten." + +#: ../../include/enotify.php:144 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "%1$s, %2$s hat [zrl=%3$s]einen %4$s[/zrl] kommentiert" + +#: ../../include/enotify.php:152 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "%1$s, %2$s hat [zrl=%3$s]%4$ss %5$s[/zrl] kommentiert" + +#: ../../include/enotify.php:161 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "%1$s, %2$s hat [zrl=%3$s]Deinen %4$s[/zrl] kommentiert" + +#: ../../include/enotify.php:172 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Red:Benachrichtigung] Kommentar in Unterhaltung #%1$d von %2$s" + +#: ../../include/enotify.php:173 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "%1$s, %2$s hat eine Unterhaltung kommentiert, der Du folgst." + +#: ../../include/enotify.php:176 ../../include/enotify.php:191 +#: ../../include/enotify.php:217 ../../include/enotify.php:236 +#: ../../include/enotify.php:250 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Bitte besuche %s, um die Unterhaltung anzusehen und/oder zu kommentieren." + +#: ../../include/enotify.php:182 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "[Red:Hinweis] %s schrieb auf Deine Pinnwand" + +#: ../../include/enotify.php:184 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "%1$s, %2$s hat auf Deine Pinnwand auf %3$s geschrieben" + +#: ../../include/enotify.php:186 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "%1$s, %2$s hat auf [zrl=%3$s]Deine Pinnwand[/zrl] geschrieben" + +#: ../../include/enotify.php:210 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "[Red:Benachrichtigung] %s hat Dich erwähnt" + +#: ../../include/enotify.php:211 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "%1$s, %2$s hat Dich auf %3$s erwähnt" + +#: ../../include/enotify.php:212 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "%1$s, %2$s [zrl=%3$s]hat Dich erwähnt[/zrl]." + +#: ../../include/enotify.php:225 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "[Red:Benachrichtigung] %1$s hat Dich angestupst" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "%1$s, %2$s hat Dich auf %3$s angestupst" + +#: ../../include/enotify.php:227 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "%1$s, %2$s [zrl=%2$s]hat Dich angestupst[/zrl]." + +#: ../../include/enotify.php:243 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "[Red:Benachrichtigung] %s hat Deinen Beitrag verschlagwortet" + +#: ../../include/enotify.php:244 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "%1$s, %2$s hat Deinen Beitrag auf %3$s verschlagwortet" + +#: ../../include/enotify.php:245 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "%1$s, %2$s hat [zrl=%3$s]Deinen Beitrag[/zrl] verschlagwortet" + +#: ../../include/enotify.php:257 +msgid "[Red:Notify] Introduction received" +msgstr "[Red:Benachrichtigung] Vorstellung erhalten" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "%1$s, Du hast eine neue Verbindungsanfrage von '%2$s' auf %3$s erhalten" + +#: ../../include/enotify.php:259 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "%1$s, Du hast [zrl=%2$s]eine neue Verbindungsanfrage[/zrl] von %3$s erhalten." + +#: ../../include/enotify.php:263 ../../include/enotify.php:282 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Du kannst Dir das Profil unter %s ansehen" + +#: ../../include/enotify.php:265 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "Bitte besuche %s , um die Verbindungsanfrage anzunehmen oder abzulehnen." + +#: ../../include/enotify.php:272 +msgid "[Red:Notify] Friend suggestion received" +msgstr "[Red:Benachrichtigung] Freundschaftsvorschlag erhalten" + +#: ../../include/enotify.php:273 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "%1$s, Du hast einen Kontaktvorschlag von „%2$s“ auf %3$s erhalten" + +#: ../../include/enotify.php:274 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from " +"%4$s." +msgstr "%1$s, Du hast [zrl=%2$s]einen Kontaktvorschlag[/zrl] für %3$s von %4$s erhalten." + +#: ../../include/enotify.php:280 +msgid "Name:" +msgstr "Name:" + +#: ../../include/enotify.php:281 +msgid "Photo:" +msgstr "Foto:" + +#: ../../include/enotify.php:284 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Bitte besuche %s um den Vorschlag zu akzeptieren oder abzulehnen." + +#: ../../include/enotify.php:499 +msgid "[Red:Notify]" +msgstr "[Red:Benachrichtigung]" + +#: ../../include/text.php:320 +msgid "prev" +msgstr "vorherige" + +#: ../../include/text.php:322 +msgid "first" +msgstr "erste" + +#: ../../include/text.php:351 +msgid "last" +msgstr "letzte" + +#: ../../include/text.php:354 +msgid "next" +msgstr "nächste" + +#: ../../include/text.php:366 +msgid "older" +msgstr "älter" + +#: ../../include/text.php:368 +msgid "newer" +msgstr "neuer" + +#: ../../include/text.php:751 +msgid "No connections" +msgstr "Keine Verbindungen" + +#: ../../include/text.php:767 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "%d Verbindung" +msgstr[1] "%d Verbindungen" + +#: ../../include/text.php:780 ../../mod/viewconnections.php:86 +msgid "View Connections" +msgstr "Verbindungen anzeigen" + +#: ../../include/text.php:837 ../../include/text.php:849 +#: ../../include/nav.php:165 ../../include/apps.php:147 +#: ../../mod/search.php:34 +msgid "Search" +msgstr "Suche" + +#: ../../include/text.php:916 +msgid "poke" +msgstr "anstupsen" + +#: ../../include/text.php:916 ../../include/conversation.php:243 +msgid "poked" +msgstr "stupste" + +#: ../../include/text.php:917 +msgid "ping" +msgstr "anpingen" + +#: ../../include/text.php:917 +msgid "pinged" +msgstr "pingte" + +#: ../../include/text.php:918 +msgid "prod" +msgstr "knuffen" + +#: ../../include/text.php:918 +msgid "prodded" +msgstr "knuffte" + +#: ../../include/text.php:919 +msgid "slap" +msgstr "ohrfeigen" + +#: ../../include/text.php:919 +msgid "slapped" +msgstr "ohrfeigte" + +#: ../../include/text.php:920 +msgid "finger" +msgstr "befummeln" + +#: ../../include/text.php:920 +msgid "fingered" +msgstr "befummelte" + +#: ../../include/text.php:921 +msgid "rebuff" +msgstr "eine Abfuhr erteilen" + +#: ../../include/text.php:921 +msgid "rebuffed" +msgstr "zurückgewiesen" + +#: ../../include/text.php:931 +msgid "happy" +msgstr "glücklich" + +#: ../../include/text.php:932 +msgid "sad" +msgstr "traurig" + +#: ../../include/text.php:933 +msgid "mellow" +msgstr "sanft" + +#: ../../include/text.php:934 +msgid "tired" +msgstr "müde" + +#: ../../include/text.php:935 +msgid "perky" +msgstr "frech" + +#: ../../include/text.php:936 +msgid "angry" +msgstr "sauer" + +#: ../../include/text.php:937 +msgid "stupified" +msgstr "verblüfft" + +#: ../../include/text.php:938 +msgid "puzzled" +msgstr "verwirrt" + +#: ../../include/text.php:939 +msgid "interested" +msgstr "interessiert" + +#: ../../include/text.php:940 +msgid "bitter" +msgstr "verbittert" + +#: ../../include/text.php:941 +msgid "cheerful" +msgstr "fröhlich" + +#: ../../include/text.php:942 +msgid "alive" +msgstr "lebendig" + +#: ../../include/text.php:943 +msgid "annoyed" +msgstr "verärgert" + +#: ../../include/text.php:944 +msgid "anxious" +msgstr "unruhig" + +#: ../../include/text.php:945 +msgid "cranky" +msgstr "schrullig" + +#: ../../include/text.php:946 +msgid "disturbed" +msgstr "verstört" + +#: ../../include/text.php:947 +msgid "frustrated" +msgstr "frustriert" + +#: ../../include/text.php:948 +msgid "depressed" +msgstr "deprimiert" + +#: ../../include/text.php:949 +msgid "motivated" +msgstr "motiviert" + +#: ../../include/text.php:950 +msgid "relaxed" +msgstr "entspannt" + +#: ../../include/text.php:951 +msgid "surprised" +msgstr "überrascht" + +#: ../../include/text.php:1117 +msgid "Monday" +msgstr "Montag" + +#: ../../include/text.php:1117 +msgid "Tuesday" +msgstr "Dienstag" + +#: ../../include/text.php:1117 +msgid "Wednesday" +msgstr "Mittwoch" + +#: ../../include/text.php:1117 +msgid "Thursday" +msgstr "Donnerstag" + +#: ../../include/text.php:1117 +msgid "Friday" +msgstr "Freitag" + +#: ../../include/text.php:1117 +msgid "Saturday" +msgstr "Samstag" + +#: ../../include/text.php:1117 +msgid "Sunday" +msgstr "Sonntag" + +#: ../../include/text.php:1121 +msgid "January" +msgstr "Januar" + +#: ../../include/text.php:1121 +msgid "February" +msgstr "Februar" + +#: ../../include/text.php:1121 +msgid "March" +msgstr "März" + +#: ../../include/text.php:1121 +msgid "April" +msgstr "April" + +#: ../../include/text.php:1121 +msgid "May" +msgstr "Mai" + +#: ../../include/text.php:1121 +msgid "June" +msgstr "Juni" + +#: ../../include/text.php:1121 +msgid "July" +msgstr "Juli" + +#: ../../include/text.php:1121 +msgid "August" +msgstr "August" + +#: ../../include/text.php:1121 +msgid "September" +msgstr "September" + +#: ../../include/text.php:1121 +msgid "October" +msgstr "Oktober" + +#: ../../include/text.php:1121 +msgid "November" +msgstr "November" + +#: ../../include/text.php:1121 +msgid "December" +msgstr "Dezember" + +#: ../../include/text.php:1199 +msgid "unknown.???" +msgstr "unbekannt.???" + +#: ../../include/text.php:1200 +msgid "bytes" +msgstr "Bytes" + +#: ../../include/text.php:1236 +msgid "remove category" +msgstr "Kategorie entfernen" + +#: ../../include/text.php:1305 +msgid "remove from file" +msgstr "aus der Datei entfernen" + +#: ../../include/text.php:1381 ../../include/text.php:1392 +#: ../../mod/connedit.php:635 +msgid "Click to open/close" +msgstr "Klicke zum Öffnen/Schließen" + +#: ../../include/text.php:1540 ../../mod/events.php:444 +msgid "Link to Source" +msgstr "Link zur Quelle" + +#: ../../include/text.php:1559 +msgid "Select a page layout: " +msgstr "Ein Seiten-Layout auswählen:" + +#: ../../include/text.php:1562 ../../include/text.php:1622 +msgid "default" +msgstr "Standard" + +#: ../../include/text.php:1595 +msgid "Page content type: " +msgstr "Content-Typ der Seite:" + +#: ../../include/text.php:1634 +msgid "Select an alternate language" +msgstr "Wähle eine alternative Sprache" + +#: ../../include/text.php:1753 ../../include/diaspora.php:1909 +#: ../../include/conversation.php:120 ../../mod/subthread.php:72 +#: ../../mod/subthread.php:174 ../../mod/tagger.php:43 ../../mod/like.php:335 +msgid "photo" +msgstr "Foto" + +#: ../../include/text.php:1756 ../../include/conversation.php:123 +#: ../../mod/tagger.php:47 ../../mod/like.php:337 +msgid "event" +msgstr "Termin" + +#: ../../include/text.php:1759 ../../include/diaspora.php:1909 +#: ../../include/conversation.php:148 ../../mod/subthread.php:72 +#: ../../mod/subthread.php:174 ../../mod/tagger.php:51 ../../mod/like.php:335 +msgid "status" +msgstr "Status" + +#: ../../include/text.php:1761 ../../include/conversation.php:150 +#: ../../mod/tagger.php:53 +msgid "comment" +msgstr "Kommentar" + +#: ../../include/text.php:1766 +msgid "activity" +msgstr "Aktivität" + +#: ../../include/text.php:2053 +msgid "Design" +msgstr "Design" + +#: ../../include/text.php:2056 +msgid "Blocks" +msgstr "Blöcke" + +#: ../../include/text.php:2057 +msgid "Menus" +msgstr "Menüs" + +#: ../../include/text.php:2058 +msgid "Layouts" +msgstr "Layouts" + +#: ../../include/text.php:2059 +msgid "Pages" +msgstr "Seiten" + +#: ../../include/text.php:2395 ../../include/RedDAV/RedBrowser.php:130 +msgid "Collection" +msgstr "Ordner" + +#: ../../include/attach.php:242 ../../include/attach.php:296 +msgid "Item was not found." +msgstr "Beitrag wurde nicht gefunden." + +#: ../../include/attach.php:352 +msgid "No source file." +msgstr "Keine Quelldatei." + +#: ../../include/attach.php:369 +msgid "Cannot locate file to replace" +msgstr "Kann Datei zum Ersetzen nicht finden" + +#: ../../include/attach.php:387 +msgid "Cannot locate file to revise/update" +msgstr "Kann Datei zum Prüfen/Aktualisieren nicht finden" + +#: ../../include/attach.php:398 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Datei überschreitet das Größen-Limit von %d" + +#: ../../include/attach.php:410 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "Die Größe Deiner Datei-Anhänge hat das Maximum von %1$.0f MByte erreicht." + +#: ../../include/attach.php:493 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "Datei-Upload fehlgeschlagen. Mögliche Systembegrenzung oder abgebrochener Prozess." + +#: ../../include/attach.php:505 +msgid "Stored file could not be verified. Upload failed." +msgstr "Gespeichert Datei konnte nicht verifiziert werden. Upload abgebrochen." + +#: ../../include/attach.php:547 ../../include/attach.php:564 +msgid "Path not available." +msgstr "Pfad nicht verfügbar." + +#: ../../include/attach.php:611 +msgid "Empty pathname" +msgstr "Leere Pfadangabe" + +#: ../../include/attach.php:627 +msgid "duplicate filename or path" +msgstr "doppelter Dateiname oder Pfad" + +#: ../../include/attach.php:651 +msgid "Path not found." +msgstr "Pfad nicht gefunden." + +#: ../../include/attach.php:702 +msgid "mkdir failed." +msgstr "mkdir fehlgeschlagen." + +#: ../../include/attach.php:706 +msgid "database storage failed." +msgstr "Speichern in der Datenbank fehlgeschlagen." + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "Dieses Element löschen?" + +#: ../../include/js_strings.php:6 ../../include/ItemObject.php:667 +#: ../../mod/photos.php:962 ../../mod/photos.php:1080 +msgid "Comment" +msgstr "Kommentar" + +#: ../../include/js_strings.php:7 ../../include/ItemObject.php:384 +msgid "[+] show all" +msgstr "[+] Alle anzeigen" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "[-] Weniger anzeigen" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "[+] aufklappen" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "[-] einklappen" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "Kennwort zu kurz" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "Kennwörter stimmen nicht überein" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:39 +msgid "everybody" +msgstr "alle" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "geheime Passphrase" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "Hinweis zur Passphrase" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "Achtung: Berechtigungen wurden verändert, aber noch nicht gespeichert." + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "Alle schließen" + +#: ../../include/js_strings.php:18 +msgid "Nothing new here" +msgstr "Nichts Neues hier" + +#: ../../include/js_strings.php:19 +msgid "Rate This Channel (this is public)" +msgstr "Diesen Kanal bewerten (öffentlich sichtbar)" + +#: ../../include/js_strings.php:20 ../../mod/rate.php:156 +msgid "Rating" +msgstr "Bewertung" + +#: ../../include/js_strings.php:21 +msgid "Describe (optional)" +msgstr "Beschreibung (optional)" + +#: ../../include/js_strings.php:22 ../../include/ItemObject.php:668 +#: ../../mod/xchan.php:11 ../../mod/connedit.php:653 ../../mod/connect.php:93 +#: ../../mod/events.php:654 ../../mod/settings.php:583 +#: ../../mod/settings.php:708 ../../mod/settings.php:737 +#: ../../mod/settings.php:760 ../../mod/settings.php:842 +#: ../../mod/settings.php:1038 ../../mod/group.php:81 ../../mod/setup.php:313 +#: ../../mod/setup.php:358 ../../mod/thing.php:284 ../../mod/thing.php:327 +#: ../../mod/pdledit.php:58 ../../mod/appman.php:99 ../../mod/import.php:504 +#: ../../mod/chat.php:177 ../../mod/chat.php:211 ../../mod/rate.php:167 +#: ../../mod/invite.php:142 ../../mod/locs.php:105 ../../mod/sources.php:104 +#: ../../mod/sources.php:138 ../../mod/filestorage.php:155 +#: ../../mod/fsuggest.php:108 ../../mod/poke.php:166 +#: ../../mod/profiles.php:667 ../../mod/admin.php:416 ../../mod/admin.php:728 +#: ../../mod/admin.php:864 ../../mod/admin.php:997 ../../mod/admin.php:1196 +#: ../../mod/admin.php:1283 ../../mod/mood.php:134 ../../mod/mail.php:355 +#: ../../mod/photos.php:565 ../../mod/photos.php:642 ../../mod/photos.php:923 +#: ../../mod/photos.php:963 ../../mod/photos.php:1081 ../../mod/poll.php:68 +#: ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Submit" +msgstr "Bestätigen" + +#: ../../include/js_strings.php:24 +msgid "timeago.prefixAgo" +msgstr "timeago.prefixAgo" + +#: ../../include/js_strings.php:25 +msgid "timeago.prefixFromNow" +msgstr " " + +#: ../../include/js_strings.php:26 +msgid "ago" +msgstr "her" + +#: ../../include/js_strings.php:27 +msgid "from now" +msgstr "von jetzt" + +#: ../../include/js_strings.php:28 +msgid "less than a minute" +msgstr "weniger als eine Minute" + +#: ../../include/js_strings.php:29 +msgid "about a minute" +msgstr "ungefähr eine Minute" + +#: ../../include/js_strings.php:30 +#, php-format +msgid "%d minutes" +msgstr "%d Minuten" + +#: ../../include/js_strings.php:31 +msgid "about an hour" +msgstr "ungefähr eine Stunde" + +#: ../../include/js_strings.php:32 +#, php-format +msgid "about %d hours" +msgstr "ungefähr %d Stunden" + +#: ../../include/js_strings.php:33 +msgid "a day" +msgstr "ein Tag" + +#: ../../include/js_strings.php:34 +#, php-format +msgid "%d days" +msgstr "%d Tage" + +#: ../../include/js_strings.php:35 +msgid "about a month" +msgstr "ungefähr ein Monat" + +#: ../../include/js_strings.php:36 +#, php-format +msgid "%d months" +msgstr "%d Monate" + +#: ../../include/js_strings.php:37 +msgid "about a year" +msgstr "ungefähr ein Jahr" + +#: ../../include/js_strings.php:38 +#, php-format +msgid "%d years" +msgstr "%d Jahre" + +#: ../../include/js_strings.php:39 +msgid " " +msgstr " " + +#: ../../include/js_strings.php:40 +msgid "timeago.numbers" +msgstr "timeago.numbers" + +#: ../../include/RedDAV/RedBrowser.php:106 +#: ../../include/RedDAV/RedBrowser.php:266 +msgid "parent" +msgstr "Ãœbergeordnetes Verzeichnis" + +#: ../../include/RedDAV/RedBrowser.php:133 +msgid "Principal" +msgstr "Prinzipal" + +#: ../../include/RedDAV/RedBrowser.php:136 +msgid "Addressbook" +msgstr "Adressbuch" + +#: ../../include/RedDAV/RedBrowser.php:139 +msgid "Calendar" +msgstr "Kalender" + +#: ../../include/RedDAV/RedBrowser.php:142 +msgid "Schedule Inbox" +msgstr "Posteingang für überwachte Kalender" + +#: ../../include/RedDAV/RedBrowser.php:145 +msgid "Schedule Outbox" +msgstr "Postausgang für überwachte Kalender" + +#: ../../include/RedDAV/RedBrowser.php:163 ../../include/apps.php:336 +#: ../../include/apps.php:387 ../../include/conversation.php:1019 +#: ../../mod/connedit.php:570 ../../mod/photos.php:681 +#: ../../mod/photos.php:1113 +msgid "Unknown" +msgstr "Unbekannt" + +#: ../../include/RedDAV/RedBrowser.php:225 +#, php-format +msgid "%1$s used" +msgstr "%1$s verwendet" + +#: ../../include/RedDAV/RedBrowser.php:230 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "%1$s von %2$s verwendet (%3$s%)" + +#: ../../include/RedDAV/RedBrowser.php:249 ../../include/nav.php:98 +#: ../../include/apps.php:135 ../../include/conversation.php:1595 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "Dateien" + +#: ../../include/RedDAV/RedBrowser.php:251 +msgid "Total" +msgstr "Summe" + +#: ../../include/RedDAV/RedBrowser.php:253 +msgid "Shared" +msgstr "Geteilt" + +#: ../../include/RedDAV/RedBrowser.php:254 +#: ../../include/RedDAV/RedBrowser.php:303 ../../mod/menu.php:100 +#: ../../mod/mitem.php:169 ../../mod/new_channel.php:121 +msgid "Create" +msgstr "Erstelle" + +#: ../../include/RedDAV/RedBrowser.php:255 +#: ../../include/RedDAV/RedBrowser.php:305 ../../mod/profile_photo.php:362 +#: ../../mod/photos.php:706 ../../mod/photos.php:1228 +msgid "Upload" +msgstr "Hochladen" + +#: ../../include/RedDAV/RedBrowser.php:262 ../../mod/settings.php:585 +#: ../../mod/settings.php:611 ../../mod/admin.php:871 +#: ../../mod/sharedwithme.php:100 +msgid "Name" +msgstr "Name" + +#: ../../include/RedDAV/RedBrowser.php:263 +msgid "Type" +msgstr "Typ" + +#: ../../include/RedDAV/RedBrowser.php:264 ../../mod/sharedwithme.php:101 +msgid "Size" +msgstr "Größe" + +#: ../../include/RedDAV/RedBrowser.php:265 ../../mod/sharedwithme.php:102 +msgid "Last Modified" +msgstr "Zuletzt geändert" + +#: ../../include/RedDAV/RedBrowser.php:268 ../../include/ItemObject.php:120 +#: ../../include/apps.php:255 ../../include/conversation.php:645 +#: ../../mod/connedit.php:533 ../../mod/settings.php:646 +#: ../../mod/group.php:176 ../../mod/thing.php:234 ../../mod/admin.php:735 +#: ../../mod/admin.php:866 ../../mod/photos.php:1044 +msgid "Delete" +msgstr "Löschen" + +#: ../../include/RedDAV/RedBrowser.php:302 +msgid "Create new folder" +msgstr "Neuen Ordner anlegen" + +#: ../../include/RedDAV/RedBrowser.php:304 +msgid "Upload file" +msgstr "Datei hochladen" + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "%1$ss Lesezeichen" + +#: ../../include/taxonomy.php:215 ../../include/taxonomy.php:234 +msgid "Tags" +msgstr "Schlagwörter" + +#: ../../include/taxonomy.php:274 +msgid "Keywords" +msgstr "Schlüsselwörter" + +#: ../../include/taxonomy.php:299 +msgid "have" +msgstr "habe" + +#: ../../include/taxonomy.php:299 +msgid "has" +msgstr "hat" + +#: ../../include/taxonomy.php:300 +msgid "want" +msgstr "will" + +#: ../../include/taxonomy.php:300 +msgid "wants" +msgstr "will" + +#: ../../include/taxonomy.php:301 ../../include/ItemObject.php:254 +msgid "like" +msgstr "mag" + +#: ../../include/taxonomy.php:301 +msgid "likes" +msgstr "gefällt" + +#: ../../include/taxonomy.php:302 ../../include/ItemObject.php:255 +msgid "dislike" +msgstr "verurteile" + +#: ../../include/taxonomy.php:302 +msgid "dislikes" +msgstr "missfällt" + +#: ../../include/taxonomy.php:385 ../../include/identity.php:1155 +#: ../../include/ItemObject.php:179 ../../include/conversation.php:1692 +#: ../../mod/photos.php:1001 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "Gefällt mir" +msgstr[1] "Gefällt mir" + +#: ../../include/features.php:38 +msgid "General Features" +msgstr "Allgemeine Funktionen" + +#: ../../include/features.php:40 +msgid "Content Expiration" +msgstr "Verfall von Inhalten" + +#: ../../include/features.php:40 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "Lösche Beiträge, Kommentare und/oder private Nachrichten automatisch zu einem zukünftigen Datum." + +#: ../../include/features.php:41 +msgid "Multiple Profiles" +msgstr "Mehrfachprofile" + +#: ../../include/features.php:41 +msgid "Ability to create multiple profiles" +msgstr "Mehrfachprofile anlegen können" + +#: ../../include/features.php:42 +msgid "Advanced Profiles" +msgstr "Erweiterte Profile" + +#: ../../include/features.php:42 +msgid "Additional profile sections and selections" +msgstr "Stellt zusätzliche Bereiche und Felder im Profil zur Verfügung" + +#: ../../include/features.php:43 +msgid "Profile Import/Export" +msgstr "Profil-Import/Export" + +#: ../../include/features.php:43 +msgid "Save and load profile details across sites/channels" +msgstr "Speichere Dein Profil, um es in einen anderen Kanal zu importieren" + +#: ../../include/features.php:44 +msgid "Web Pages" +msgstr "Webseiten" + +#: ../../include/features.php:44 +msgid "Provide managed web pages on your channel" +msgstr "Stelle verwaltete Webseiten in Deinem Kanal zur Verfügung" + +#: ../../include/features.php:45 +msgid "Private Notes" +msgstr "Private Notizen" + +#: ../../include/features.php:45 +msgid "Enables a tool to store notes and reminders" +msgstr "Werkzeug zum Speichern von Notizen und Erinnerungen aktivieren" + +#: ../../include/features.php:46 +msgid "Navigation Channel Select" +msgstr "Kanal-Auswahl in der Navigationsleiste" + +#: ../../include/features.php:46 +msgid "Change channels directly from within the navigation dropdown menu" +msgstr "Wechsle direkt über das Navigationsmenü zu anderen Kanälen" + +#: ../../include/features.php:50 +msgid "Extended Identity Sharing" +msgstr "Erweitertes Teilen von Identitäten" + +#: ../../include/features.php:50 +msgid "" +"Share your identity with all websites on the internet. When disabled, " +"identity is only shared with sites in the matrix." +msgstr "Teile Deine Identität mit allen Webseiten im Internet. Ist dies deaktiviert, wird Deine Identität nur mit Red-Servern geteilt." + +#: ../../include/features.php:51 +msgid "Expert Mode" +msgstr "Expertenmodus" + +#: ../../include/features.php:51 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "Aktiviere den Expertenmodus, um fortgeschrittene Konfigurationsoptionen zu aktivieren" + +#: ../../include/features.php:52 +msgid "Premium Channel" +msgstr "Premium-Kanal" + +#: ../../include/features.php:52 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "Ermöglicht es, Einschränkungen und Bedingungen für Verbindungen dieses Kanals festzulegen" + +#: ../../include/features.php:57 +msgid "Post Composition Features" +msgstr "Nachbearbeitungsfunktionen" + +#: ../../include/features.php:59 +msgid "Use Markdown" +msgstr "Markdown benutzen" + +#: ../../include/features.php:59 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "Erlaube die Verwendung von \"Markdown\"-Syntax zur Formatierung von Beiträgen" + +#: ../../include/features.php:60 +msgid "Large Photos" +msgstr "Große Fotos" + +#: ../../include/features.php:60 +msgid "" +"Include large (640px) photo thumbnails in posts. If not enabled, use small " +"(320px) photo thumbnails" +msgstr "Große Vorschaubilder (640px) in Beiträgen anzeigen. Ist das deaktiviert, werden kleine Vorschaubilder (320px) angezeigt." + +#: ../../include/features.php:61 +msgid "Automatically import channel content from other channels or feeds" +msgstr "Importiere automatisch Inhalte für diesen Kanal von anderen Kanälen oder Feeds" + +#: ../../include/features.php:62 +msgid "Even More Encryption" +msgstr "Noch mehr Verschlüsselung" + +#: ../../include/features.php:62 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "Erlaube optionale Verschlüsselung von Inhalten (Ende-zu-Ende mit geteiltem Sicherheitsschlüssel)" + +#: ../../include/features.php:63 +msgid "Enable voting tools" +msgstr "Umfragewerkzeuge aktivieren" + +#: ../../include/features.php:63 +msgid "Provide a class of post which others can vote on" +msgstr "Aktiviere die Umfragewerkzeuge, um anderen die Möglichkeit zu geben, Deinem Beitrag zuzustimmen, ihn abzulehnen oder sich zu enthalten. (Muss im Beitrag selbst noch aktiviert werden.)" + +#: ../../include/features.php:64 +msgid "Flag Adult Photos" +msgstr "Nicht jugendfreie Fotos markieren" + +#: ../../include/features.php:64 +msgid "Provide photo edit option to hide adult photos from default album view" +msgstr "Stellt eine Option zum Verstecken von Fotos mit nicht jugendfreien Inhalten in der Standard-Albumansicht bereit" + +#: ../../include/features.php:69 +msgid "Network and Stream Filtering" +msgstr "Netzwerk- und Stream-Filter" + +#: ../../include/features.php:70 +msgid "Search by Date" +msgstr "Suche nach Datum" + +#: ../../include/features.php:70 +msgid "Ability to select posts by date ranges" +msgstr "Möglichkeit, Beiträge nach Zeiträumen auszuwählen" + +#: ../../include/features.php:71 +msgid "Collections Filter" +msgstr "Filter für Sammlung" + +#: ../../include/features.php:71 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "Aktiviere nur Netzwerk-Beiträge von ausgewählten Sammlungen" + +#: ../../include/features.php:72 +msgid "Save search terms for re-use" +msgstr "Suchbegriffe zur Wiederverwendung abspeichern" + +#: ../../include/features.php:73 +msgid "Network Personal Tab" +msgstr "Persönlicher Netzwerkreiter" + +#: ../../include/features.php:73 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "Aktiviere Reiter nur für die Netzwerk-Beiträge, mit denen Du interagiert hast" + +#: ../../include/features.php:74 +msgid "Network New Tab" +msgstr "Netzwerkreiter Neu" + +#: ../../include/features.php:74 +msgid "Enable tab to display all new Network activity" +msgstr "Aktiviere Reiter, um alle neuen Netzwerkaktivitäten zu zeigen" + +#: ../../include/features.php:75 +msgid "Affinity Tool" +msgstr "Beziehungs-Tool" + +#: ../../include/features.php:75 +msgid "Filter stream activity by depth of relationships" +msgstr "Filter Aktivitätenstream nach Tiefe der Beziehung" + +#: ../../include/features.php:76 +msgid "Suggest Channels" +msgstr "Kanäle vorschlagen" + +#: ../../include/features.php:76 +msgid "Show channel suggestions" +msgstr "Kanalvorschläge anzeigen" + +#: ../../include/features.php:81 +msgid "Post/Comment Tools" +msgstr "Beitrag-/Kommentar-Tools" + +#: ../../include/features.php:82 +msgid "Tagging" +msgstr "Verschlagworten" + +#: ../../include/features.php:82 +msgid "Ability to tag existing posts" +msgstr "Möglichkeit, um existierende Beiträge zu verschlagworten" + +#: ../../include/features.php:83 +msgid "Post Categories" +msgstr "Beitrags-Kategorien" + +#: ../../include/features.php:83 +msgid "Add categories to your posts" +msgstr "Kategorien für Beiträge" + +#: ../../include/features.php:84 +msgid "Ability to file posts under folders" +msgstr "Möglichkeit, Beiträge in Verzeichnissen zu sammeln" + +#: ../../include/features.php:85 +msgid "Dislike Posts" +msgstr "Gefällt-mir-nicht Beiträge" + +#: ../../include/features.php:85 +msgid "Ability to dislike posts/comments" +msgstr "„Gefällt mir nicht“ ermöglichen" + +#: ../../include/features.php:86 +msgid "Star Posts" +msgstr "Beiträge mit Sternchen versehen" + +#: ../../include/features.php:86 +msgid "Ability to mark special posts with a star indicator" +msgstr "Möglichkeit, spezielle Beiträge mit Sternchen-Symbol zu markieren" + +#: ../../include/features.php:87 +msgid "Tag Cloud" +msgstr "Schlagwort-Wolke" + +#: ../../include/features.php:87 +msgid "Provide a personal tag cloud on your channel page" +msgstr "Persönliche Schlagwort-Wolke auf Deiner Kanal-Seite anzeigen" + +#: ../../include/auth.php:130 +msgid "Logged out." +msgstr "Ausgeloggt." + +#: ../../include/auth.php:271 +msgid "Failed authentication" +msgstr "Authentifizierung fehlgeschlagen" + +#: ../../include/auth.php:285 ../../mod/openid.php:190 +msgid "Login failed." +msgstr "Login fehlgeschlagen." + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Häufig" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Stündlich" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Zwei Mal am Tag" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Täglich" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Wöchentlich" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Monatlich" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:731 +#: ../../mod/admin.php:740 ../../boot.php:1554 +msgid "Email" +msgstr "E-Mail" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "LinkedIn" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/IM" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "Es hat früher schon einmal eine Sammlung mit diesem Namen existiert, die gelöscht wurde. Es könnten von damals noch Elemente (Beiträge, Dateien etc.) vorhanden sein, die allen jetzigen und zukünftigen Mitgliedern dieser Sammlung den Zugriff erlauben. Wenn das nicht Dein Plan war, erstelle bitte eine neue Sammlung mit einem anderen Namen." + +#: ../../include/group.php:235 +msgid "Default privacy group for new contacts" +msgstr "Standard-Sammlung für neue Kontakte" + +#: ../../include/group.php:254 ../../mod/admin.php:740 +msgid "All Channels" +msgstr "Alle Kanäle" + +#: ../../include/group.php:276 +msgid "edit" +msgstr "Bearbeiten" + +#: ../../include/group.php:298 +msgid "Collections" +msgstr "Sammlungen" + +#: ../../include/group.php:299 +msgid "Edit collection" +msgstr "Sammlung bearbeiten" + +#: ../../include/group.php:300 +msgid "Create a new collection" +msgstr "Neue Sammlung erzeugen" + +#: ../../include/group.php:301 +msgid "Channels not in any collection" +msgstr "Kanäle, die nicht in einer Sammlung sind" + +#: ../../include/identity.php:31 ../../mod/item.php:1078 +msgid "Unable to obtain identity information from database" +msgstr "Kann keine Identitäts-Informationen aus Datenbank beziehen" + +#: ../../include/identity.php:66 +msgid "Empty name" +msgstr "Namensfeld leer" + +#: ../../include/identity.php:68 +msgid "Name too long" +msgstr "Name ist zu lang" + +#: ../../include/identity.php:169 +msgid "No account identifier" +msgstr "Keine Account-Kennung" + +#: ../../include/identity.php:182 +msgid "Nickname is required." +msgstr "Spitzname ist erforderlich." + +#: ../../include/identity.php:196 +msgid "Reserved nickname. Please choose another." +msgstr "Reservierter Kurzname. Bitte wähle einen anderen." + +#: ../../include/identity.php:201 ../../include/dimport.php:34 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "Der Spitzname enthält nicht-unterstütze Zeichen oder wird bereits auf dieser Seite genutzt." + +#: ../../include/identity.php:283 +msgid "Unable to retrieve created identity" +msgstr "Kann die erstellte Identität nicht empfangen" + +#: ../../include/identity.php:343 +msgid "Default Profile" +msgstr "Standard-Profil" + +#: ../../include/identity.php:643 +msgid "Requested channel is not available." +msgstr "Angeforderte Kanal nicht verfügbar." + +#: ../../include/identity.php:691 ../../mod/profile.php:16 +#: ../../mod/achievements.php:11 ../../mod/editblock.php:29 +#: ../../mod/blocks.php:29 ../../mod/connect.php:13 ../../mod/hcard.php:8 +#: ../../mod/editlayout.php:28 ../../mod/editwebpage.php:28 +#: ../../mod/filestorage.php:53 ../../mod/webpages.php:29 +#: ../../mod/layouts.php:29 +msgid "Requested profile is not available." +msgstr "Erwünschte Profil ist nicht verfügbar." + +#: ../../include/identity.php:854 ../../mod/profiles.php:774 +msgid "Change profile photo" +msgstr "Profilfoto ändern" + +#: ../../include/identity.php:861 +msgid "Profiles" +msgstr "Profile" + +#: ../../include/identity.php:861 +msgid "Manage/edit profiles" +msgstr "Profile verwalten/bearbeiten" + +#: ../../include/identity.php:862 ../../mod/profiles.php:775 +msgid "Create New Profile" +msgstr "Neues Profil erstellen" + +#: ../../include/identity.php:865 ../../include/nav.php:95 +msgid "Edit Profile" +msgstr "Profile bearbeiten" + +#: ../../include/identity.php:878 ../../mod/profiles.php:786 +msgid "Profile Image" +msgstr "Profilfoto:" + +#: ../../include/identity.php:881 +msgid "visible to everybody" +msgstr "sichtbar für jeden" + +#: ../../include/identity.php:882 ../../mod/profiles.php:669 +#: ../../mod/profiles.php:790 +msgid "Edit visibility" +msgstr "Sichtbarkeit bearbeiten" + +#: ../../include/identity.php:894 ../../include/bb2diaspora.php:450 +#: ../../include/event.php:40 ../../mod/events.php:645 +#: ../../mod/directory.php:204 +msgid "Location:" +msgstr "Ort:" + +#: ../../include/identity.php:898 ../../include/identity.php:1139 +msgid "Gender:" +msgstr "Geschlecht:" + +#: ../../include/identity.php:899 ../../include/identity.php:1183 +msgid "Status:" +msgstr "Status:" + +#: ../../include/identity.php:900 ../../include/identity.php:1194 +msgid "Homepage:" +msgstr "Homepage:" + +#: ../../include/identity.php:901 +msgid "Online Now" +msgstr "gerade online" + +#: ../../include/identity.php:983 ../../include/identity.php:1063 +#: ../../mod/ping.php:324 +msgid "g A l F d" +msgstr "l, d. F, G:i \\U\\h\\r" + +#: ../../include/identity.php:984 ../../include/identity.php:1064 +msgid "F d" +msgstr "d. F" + +#: ../../include/identity.php:1029 ../../include/identity.php:1104 +#: ../../mod/ping.php:346 +msgid "[today]" +msgstr "[Heute]" + +#: ../../include/identity.php:1041 +msgid "Birthday Reminders" +msgstr "Geburtstags Erinnerungen" + +#: ../../include/identity.php:1042 +msgid "Birthdays this week:" +msgstr "Geburtstage in dieser Woche:" + +#: ../../include/identity.php:1097 +msgid "[No description]" +msgstr "[Keine Beschreibung]" + +#: ../../include/identity.php:1115 +msgid "Event Reminders" +msgstr "Termin-Erinnerungen" + +#: ../../include/identity.php:1116 +msgid "Events this week:" +msgstr "Termine in dieser Woche:" + +#: ../../include/identity.php:1129 ../../include/identity.php:1246 +#: ../../include/apps.php:138 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "Profil" + +#: ../../include/identity.php:1137 ../../mod/settings.php:1044 +msgid "Full Name:" +msgstr "Voller Name:" + +#: ../../include/identity.php:1144 +msgid "Like this channel" +msgstr "Dieser Kanal gefällt mir" + +#: ../../include/identity.php:1168 +msgid "j F, Y" +msgstr "j. F Y" + +#: ../../include/identity.php:1169 +msgid "j F" +msgstr "j. F" + +#: ../../include/identity.php:1176 +msgid "Birthday:" +msgstr "Geburtstag:" + +#: ../../include/identity.php:1180 +msgid "Age:" +msgstr "Alter:" + +#: ../../include/identity.php:1189 +#, php-format +msgid "for %1$d %2$s" +msgstr "seit %1$d %2$s" + +#: ../../include/identity.php:1192 ../../mod/profiles.php:691 +msgid "Sexual Preference:" +msgstr "Sexuelle Orientierung:" + +#: ../../include/identity.php:1196 ../../mod/profiles.php:693 +msgid "Hometown:" +msgstr "Heimatstadt:" + +#: ../../include/identity.php:1198 +msgid "Tags:" +msgstr "Schlagworte:" + +#: ../../include/identity.php:1200 ../../mod/profiles.php:694 +msgid "Political Views:" +msgstr "Politische Ansichten:" + +#: ../../include/identity.php:1202 +msgid "Religion:" +msgstr "Religion:" + +#: ../../include/identity.php:1204 +msgid "About:" +msgstr "Ãœber:" + +#: ../../include/identity.php:1206 +msgid "Hobbies/Interests:" +msgstr "Hobbys/Interessen:" + +#: ../../include/identity.php:1208 ../../mod/profiles.php:697 +msgid "Likes:" +msgstr "Gefällt:" + +#: ../../include/identity.php:1210 ../../mod/profiles.php:698 +msgid "Dislikes:" +msgstr "Gefällt nicht:" + +#: ../../include/identity.php:1212 +msgid "Contact information and Social Networks:" +msgstr "Kontaktinformation und soziale Netzwerke:" + +#: ../../include/identity.php:1214 +msgid "My other channels:" +msgstr "Meine anderen Kanäle:" + +#: ../../include/identity.php:1216 +msgid "Musical interests:" +msgstr "Musikalische Interessen:" + +#: ../../include/identity.php:1218 +msgid "Books, literature:" +msgstr "Bücher, Literatur:" + +#: ../../include/identity.php:1220 +msgid "Television:" +msgstr "Fernsehen:" + +#: ../../include/identity.php:1222 +msgid "Film/dance/culture/entertainment:" +msgstr "Film/Tanz/Kultur/Unterhaltung:" + +#: ../../include/identity.php:1224 +msgid "Love/Romance:" +msgstr "Liebe/Romantik:" + +#: ../../include/identity.php:1226 +msgid "Work/employment:" +msgstr "Arbeit/Anstellung:" + +#: ../../include/identity.php:1228 +msgid "School/education:" +msgstr "Schule/Ausbildung:" + +#: ../../include/identity.php:1248 +msgid "Like this thing" +msgstr "Gefällt mir" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "Kein Empfänger angegeben" + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "[no subject]" + +#: ../../include/message.php:45 +msgid "Unable to determine sender." +msgstr "Kann Absender nicht bestimmen." + +#: ../../include/message.php:200 +msgid "Stored post could not be verified." +msgstr "Gespeicherter Beitrag konnten nicht überprüft werden." + +#: ../../include/follow.php:28 +msgid "Channel is blocked on this site." +msgstr "Der Kanal ist auf dieser Seite blockiert " + +#: ../../include/follow.php:33 +msgid "Channel location missing." +msgstr "Adresse des Kanals fehlt." + +#: ../../include/follow.php:83 +msgid "Response from remote channel was incomplete." +msgstr "Antwort des entfernten Kanals war unvollständig." + +#: ../../include/follow.php:100 +msgid "Channel was deleted and no longer exists." +msgstr "Kanal wurde gelöscht und existiert nicht mehr." + +#: ../../include/follow.php:135 ../../include/follow.php:197 +msgid "Protocol disabled." +msgstr "Protokoll deaktiviert." + +#: ../../include/follow.php:170 +msgid "Channel discovery failed." +msgstr "Kanalsuche fehlgeschlagen" + +#: ../../include/follow.php:186 +msgid "local account not found." +msgstr "Lokales Konto nicht gefunden." + +#: ../../include/follow.php:215 +msgid "Cannot connect to yourself." +msgstr "Du kannst Dich nicht mit Dir selbst verbinden." + +#: ../../include/comanche.php:35 ../../mod/admin.php:357 +#: ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "Standard" + +#: ../../include/datetime.php:35 +msgid "Miscellaneous" +msgstr "Verschiedenes" + +#: ../../include/datetime.php:113 +msgid "YYYY-MM-DD or MM-DD" +msgstr "JJJJ-MM-TT oder MM-TT" + +#: ../../include/datetime.php:212 ../../mod/events.php:633 +#: ../../mod/appman.php:91 ../../mod/appman.php:92 +msgid "Required" +msgstr "Benötigt" + +#: ../../include/datetime.php:231 +msgid "never" +msgstr "Nie" + +#: ../../include/datetime.php:237 +msgid "less than a second ago" +msgstr "Vor weniger als einer Sekunde" + +#: ../../include/datetime.php:240 +msgid "year" +msgstr "Jahr" + +#: ../../include/datetime.php:240 +msgid "years" +msgstr "Jahre" + +#: ../../include/datetime.php:241 +msgid "month" +msgstr "Monat" + +#: ../../include/datetime.php:241 +msgid "months" +msgstr "Monate" + +#: ../../include/datetime.php:242 +msgid "week" +msgstr "Woche" + +#: ../../include/datetime.php:242 +msgid "weeks" +msgstr "Wochen" + +#: ../../include/datetime.php:243 +msgid "day" +msgstr "Tag" + +#: ../../include/datetime.php:243 +msgid "days" +msgstr "Tage" + +#: ../../include/datetime.php:244 +msgid "hour" +msgstr "Stunde" + +#: ../../include/datetime.php:244 +msgid "hours" +msgstr "Stunden" + +#: ../../include/datetime.php:245 +msgid "minute" +msgstr "Minute" + +#: ../../include/datetime.php:245 +msgid "minutes" +msgstr "Minuten" + +#: ../../include/datetime.php:246 +msgid "second" +msgstr "Sekunde" + +#: ../../include/datetime.php:246 +msgid "seconds" +msgstr "Sekunden" + +#: ../../include/datetime.php:255 +#, php-format +msgid "%1$d %2$s ago" +msgstr "vor %1$d %2$s" + +#: ../../include/datetime.php:463 +#, php-format +msgid "%1$s's birthday" +msgstr "%1$ss Geburtstag" + +#: ../../include/datetime.php:464 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "Alles Gute zum Geburtstag, %1$s" + +#: ../../include/bb2diaspora.php:349 +msgid "Attachments:" +msgstr "Anhänge:" + +#: ../../include/bb2diaspora.php:428 ../../include/event.php:11 +msgid "l F d, Y \\@ g:i A" +msgstr "l, d. F Y, H:i" + +#: ../../include/bb2diaspora.php:430 +msgid "Redmatrix event notification:" +msgstr "RedMatrix Termin-Benachrichtigung:" + +#: ../../include/bb2diaspora.php:434 ../../include/event.php:20 +msgid "Starts:" +msgstr "Beginnt:" + +#: ../../include/bb2diaspora.php:442 ../../include/event.php:30 +msgid "Finishes:" +msgstr "Endet:" + +#: ../../include/chat.php:10 +msgid "Missing room name" +msgstr "Der Chatraum hat keinen Namen" + +#: ../../include/chat.php:19 +msgid "Duplicate room name" +msgstr "Name des Chatraums bereits vergeben" + +#: ../../include/chat.php:68 ../../include/chat.php:76 +msgid "Invalid room specifier." +msgstr "Ungültiger Raumbezeichner." + +#: ../../include/chat.php:105 +msgid "Room not found." +msgstr "Chatraum konnte nicht gefunden werden." + +#: ../../include/chat.php:126 +msgid "Room is full" +msgstr "Der Raum ist voll" + +#: ../../include/nav.php:87 ../../include/nav.php:120 ../../boot.php:1551 +msgid "Logout" +msgstr "Abmelden" + +#: ../../include/nav.php:87 ../../include/nav.php:120 +msgid "End this session" +msgstr "Beende diese Sitzung" + +#: ../../include/nav.php:90 ../../include/nav.php:151 +msgid "Home" +msgstr "Home" + +#: ../../include/nav.php:90 +msgid "Your posts and conversations" +msgstr "Deine Beiträge und Unterhaltungen" + +#: ../../include/nav.php:91 ../../include/conversation.php:937 +#: ../../mod/connedit.php:484 ../../mod/connedit.php:634 +msgid "View Profile" +msgstr "Profil ansehen" + +#: ../../include/nav.php:91 +msgid "Your profile page" +msgstr "Deine Profilseite" + +#: ../../include/nav.php:93 +msgid "Edit Profiles" +msgstr "Profile bearbeiten" + +#: ../../include/nav.php:93 +msgid "Manage/Edit profiles" +msgstr "Profile verwalten" + +#: ../../include/nav.php:95 +msgid "Edit your profile" +msgstr "Profil bearbeiten" + +#: ../../include/nav.php:97 ../../include/apps.php:139 +#: ../../include/conversation.php:1586 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "Fotos" + +#: ../../include/nav.php:97 +msgid "Your photos" +msgstr "Deine Bilder" + +#: ../../include/nav.php:98 +msgid "Your files" +msgstr "Deine Dateien" + +#: ../../include/nav.php:103 ../../include/apps.php:146 +msgid "Chat" +msgstr "Chat" + +#: ../../include/nav.php:103 +msgid "Your chatrooms" +msgstr "Deine Chaträume" + +#: ../../include/nav.php:109 ../../include/apps.php:129 +#: ../../include/conversation.php:1621 +msgid "Bookmarks" +msgstr "Lesezeichen" + +#: ../../include/nav.php:109 +msgid "Your bookmarks" +msgstr "Deine Lesezeichen" + +#: ../../include/nav.php:113 ../../include/apps.php:136 +#: ../../include/conversation.php:1632 ../../mod/webpages.php:160 +msgid "Webpages" +msgstr "Webseiten" + +#: ../../include/nav.php:113 +msgid "Your webpages" +msgstr "Deine Webseiten" + +#: ../../include/nav.php:117 ../../include/apps.php:131 ../../boot.php:1552 +msgid "Login" +msgstr "Anmelden" + +#: ../../include/nav.php:117 +msgid "Sign in" +msgstr "Anmelden" + +#: ../../include/nav.php:134 +#, php-format +msgid "%s - click to logout" +msgstr "%s - Klick zum Abmelden" + +#: ../../include/nav.php:137 +msgid "Remote authentication" +msgstr "Ãœber Konto auf anderem Server einloggen" + +#: ../../include/nav.php:137 +msgid "Click to authenticate to your home hub" +msgstr "Klicke, um Dich über Deinen Heimat-Server zu authentifizieren" + +#: ../../include/nav.php:151 +msgid "Home Page" +msgstr "Homepage" + +#: ../../include/nav.php:155 ../../mod/register.php:224 ../../boot.php:1528 +msgid "Register" +msgstr "Registrieren" + +#: ../../include/nav.php:155 +msgid "Create an account" +msgstr "Erzeuge ein Konto" + +#: ../../include/nav.php:160 ../../include/apps.php:142 ../../mod/help.php:67 +#: ../../mod/help.php:72 +msgid "Help" +msgstr "Hilfe" + +#: ../../include/nav.php:160 +msgid "Help and documentation" +msgstr "Hilfe und Dokumentation" + +#: ../../include/nav.php:163 +msgid "Applications, utilities, links, games" +msgstr "Anwendungen (Apps), Zubehör, Links, Spiele" + +#: ../../include/nav.php:165 +msgid "Search site content" +msgstr "Durchsuche Seiten-Inhalt" + +#: ../../include/nav.php:168 ../../include/apps.php:141 +#: ../../mod/directory.php:334 +msgid "Directory" +msgstr "Verzeichnis" + +#: ../../include/nav.php:168 +msgid "Channel Directory" +msgstr "Kanal-Verzeichnis" + +#: ../../include/nav.php:182 ../../include/apps.php:133 +msgid "Matrix" +msgstr "Matrix" + +#: ../../include/nav.php:182 +msgid "Your matrix" +msgstr "Deine Matrix" + +#: ../../include/nav.php:183 +msgid "Mark all matrix notifications seen" +msgstr "Markiere alle Matrix-Benachrichtigungen als angesehen" + +#: ../../include/nav.php:185 ../../include/apps.php:137 +msgid "Channel Home" +msgstr "Mein Kanal" + +#: ../../include/nav.php:185 +msgid "Channel home" +msgstr "Mein Kanal" + +#: ../../include/nav.php:186 +msgid "Mark all channel notifications seen" +msgstr "Markiere alle Kanal-Benachrichtigungen als angesehen" + +#: ../../include/nav.php:189 ../../mod/connections.php:407 +msgid "Connections" +msgstr "Verbindungen" + +#: ../../include/nav.php:192 +msgid "Notices" +msgstr "Benachrichtigungen" + +#: ../../include/nav.php:192 +msgid "Notifications" +msgstr "Benachrichtigungen" + +#: ../../include/nav.php:193 +msgid "See all notifications" +msgstr "Alle Benachrichtigungen ansehen" + +#: ../../include/nav.php:194 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "Markiere alle System-Benachrichtigungen als gesehen" + +#: ../../include/nav.php:196 ../../include/apps.php:143 +msgid "Mail" +msgstr "Mail" + +#: ../../include/nav.php:196 +msgid "Private mail" +msgstr "Persönliche Mail" + +#: ../../include/nav.php:197 +msgid "See all private messages" +msgstr "Alle persönlichen Nachrichten ansehen" + +#: ../../include/nav.php:198 +msgid "Mark all private messages seen" +msgstr "Markiere alle persönlichen Nachrichten als gesehen" + +#: ../../include/nav.php:199 +msgid "Inbox" +msgstr "Eingang" + +#: ../../include/nav.php:200 +msgid "Outbox" +msgstr "Ausgang" + +#: ../../include/nav.php:204 ../../include/apps.php:140 +#: ../../mod/events.php:472 +msgid "Events" +msgstr "Termine" + +#: ../../include/nav.php:204 +msgid "Event Calendar" +msgstr "Terminkalender" + +#: ../../include/nav.php:205 +msgid "See all events" +msgstr "Alle Termine ansehen" + +#: ../../include/nav.php:206 +msgid "Mark all events seen" +msgstr "Markiere alle Termine als gesehen" + +#: ../../include/nav.php:208 ../../include/apps.php:132 +#: ../../mod/manage.php:148 +msgid "Channel Manager" +msgstr "Kanal-Manager" + +#: ../../include/nav.php:208 +msgid "Manage Your Channels" +msgstr "Verwalte Deine Kanäle" + +#: ../../include/nav.php:210 +msgid "Account/Channel Settings" +msgstr "Konto-/Kanal-Einstellungen" + +#: ../../include/nav.php:218 ../../mod/admin.php:123 +msgid "Admin" +msgstr "Administration" + +#: ../../include/nav.php:218 +msgid "Site Setup and Configuration" +msgstr "Seiten-Einrichtung und -Konfiguration" + +#: ../../include/nav.php:249 ../../include/conversation.php:842 +msgid "Loading..." +msgstr "Lädt ..." + +#: ../../include/nav.php:254 +msgid "@name, #tag, content" +msgstr "@Name, #Schlagwort, Text" + +#: ../../include/nav.php:255 +msgid "Please wait..." +msgstr "Bitte warten..." + +#: ../../include/security.php:357 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "Das Security-Token des Formulars war nicht korrekt. Das ist wahrscheinlich passiert, weil das Formular zu lange (>3 Stunden) offen war, bevor es abgeschickt wurde." + +#: ../../include/ItemObject.php:89 ../../include/conversation.php:652 +msgid "Private Message" +msgstr "Private Nachricht" + +#: ../../include/ItemObject.php:126 ../../include/conversation.php:644 +msgid "Select" +msgstr "Auswählen" + +#: ../../include/ItemObject.php:130 +msgid "Save to Folder" +msgstr "In Ordner speichern" + +#: ../../include/ItemObject.php:151 +msgid "I will attend" +msgstr "Ich werde teilnehmen" + +#: ../../include/ItemObject.php:151 +msgid "I will not attend" +msgstr "Ich werde nicht teilnehmen" + +#: ../../include/ItemObject.php:151 +msgid "I might attend" +msgstr "Ich werde vielleicht teilnehmen" + +#: ../../include/ItemObject.php:161 +msgid "I agree" +msgstr "Ich stimme zu" + +#: ../../include/ItemObject.php:161 +msgid "I disagree" +msgstr "Ich lehne ab" + +#: ../../include/ItemObject.php:161 +msgid "I abstain" +msgstr "Ich enthalte mich" + +#: ../../include/ItemObject.php:175 ../../include/ItemObject.php:187 +#: ../../include/conversation.php:1667 ../../mod/photos.php:997 +#: ../../mod/photos.php:1009 +msgid "View all" +msgstr "Alles anzeigen" + +#: ../../include/ItemObject.php:184 ../../include/conversation.php:1695 +#: ../../mod/photos.php:1006 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "Gefällt nicht" +msgstr[1] "Gefällt nicht" + +#: ../../include/ItemObject.php:212 +msgid "Add Star" +msgstr "Stern hinzufügen" + +#: ../../include/ItemObject.php:213 +msgid "Remove Star" +msgstr "Stern entfernen" + +#: ../../include/ItemObject.php:214 +msgid "Toggle Star Status" +msgstr "Markierungsstatus (Stern) umschalten" + +#: ../../include/ItemObject.php:218 +msgid "starred" +msgstr "markiert" + +#: ../../include/ItemObject.php:227 ../../include/conversation.php:659 +msgid "Message signature validated" +msgstr "Signatur überprüft" + +#: ../../include/ItemObject.php:228 ../../include/conversation.php:660 +msgid "Message signature incorrect" +msgstr "Signatur nicht korrekt" + +#: ../../include/ItemObject.php:236 +msgid "Add Tag" +msgstr "Tag hinzufügen" + +#: ../../include/ItemObject.php:254 ../../mod/photos.php:941 +msgid "I like this (toggle)" +msgstr "Mir gefällt das (Umschalter)" + +#: ../../include/ItemObject.php:255 ../../mod/photos.php:942 +msgid "I don't like this (toggle)" +msgstr "Mir gefällt das nicht (Umschalter)" + +#: ../../include/ItemObject.php:259 +msgid "Share This" +msgstr "Teilen" + +#: ../../include/ItemObject.php:259 +msgid "share" +msgstr "Teilen" + +#: ../../include/ItemObject.php:276 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d Kommentar" +msgstr[1] "%d Kommentare" + +#: ../../include/ItemObject.php:294 ../../include/ItemObject.php:295 +#, php-format +msgid "View %s's profile - %s" +msgstr "Schaue Dir %ss Profil an – %s" + +#: ../../include/ItemObject.php:298 +msgid "to" +msgstr "an" + +#: ../../include/ItemObject.php:299 +msgid "via" +msgstr "via" + +#: ../../include/ItemObject.php:300 +msgid "Wall-to-Wall" +msgstr "Wall-to-Wall" + +#: ../../include/ItemObject.php:301 +msgid "via Wall-To-Wall:" +msgstr "via Wall-To-Wall:" + +#: ../../include/ItemObject.php:312 ../../include/conversation.php:704 +#, php-format +msgid " from %s" +msgstr "von %s" + +#: ../../include/ItemObject.php:315 ../../include/conversation.php:707 +#, php-format +msgid "last edited: %s" +msgstr "zuletzt bearbeitet: %s" + +#: ../../include/ItemObject.php:316 ../../include/conversation.php:708 +#, php-format +msgid "Expires: %s" +msgstr "Verfällt: %s" + +#: ../../include/ItemObject.php:337 +msgid "Save Bookmarks" +msgstr "Favoriten speichern" + +#: ../../include/ItemObject.php:338 +msgid "Add to Calendar" +msgstr "Zum Kalender hinzufügen" + +#: ../../include/ItemObject.php:347 +msgid "Mark all seen" +msgstr "Alle als gelesen markieren" + +#: ../../include/ItemObject.php:353 ../../mod/photos.php:1125 +msgctxt "noun" +msgid "Likes" +msgstr "Gefällt mir" + +#: ../../include/ItemObject.php:354 ../../mod/photos.php:1126 +msgctxt "noun" +msgid "Dislikes" +msgstr "Gefällt nicht" + +#: ../../include/ItemObject.php:359 ../../include/acl_selectors.php:249 +#: ../../mod/photos.php:1131 +msgid "Close" +msgstr "Schließen" + +#: ../../include/ItemObject.php:364 ../../include/conversation.php:725 +#: ../../include/conversation.php:1198 ../../mod/editblock.php:152 +#: ../../mod/editpost.php:125 ../../mod/editlayout.php:148 +#: ../../mod/editwebpage.php:183 ../../mod/mail.php:241 ../../mod/mail.php:356 +#: ../../mod/photos.php:944 +msgid "Please wait" +msgstr "Bitte warten" + +#: ../../include/ItemObject.php:665 ../../mod/photos.php:960 +#: ../../mod/photos.php:1078 +msgid "This is you" +msgstr "Das bist Du" + +#: ../../include/ItemObject.php:669 +msgid "Bold" +msgstr "Fett" + +#: ../../include/ItemObject.php:670 +msgid "Italic" +msgstr "Kursiv" + +#: ../../include/ItemObject.php:671 +msgid "Underline" +msgstr "Unterstrichen" + +#: ../../include/ItemObject.php:672 +msgid "Quote" +msgstr "Zitat" + +#: ../../include/ItemObject.php:673 +msgid "Code" +msgstr "Code" + +#: ../../include/ItemObject.php:674 +msgid "Image" +msgstr "Bild" + +#: ../../include/ItemObject.php:675 +msgid "Link" +msgstr "Link" + +#: ../../include/ItemObject.php:676 +msgid "Video" +msgstr "Video" + +#: ../../include/ItemObject.php:680 ../../include/conversation.php:1224 +#: ../../mod/editpost.php:152 ../../mod/mail.php:247 ../../mod/mail.php:361 +msgid "Encrypt text" +msgstr "Text verschlüsseln" + +#: ../../include/activities.php:39 +msgid " and " +msgstr "und" + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "öffentliches Profil" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s hat %2$s auf “%3$s” geändert" + +#: ../../include/activities.php:57 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "Besuche %1$s's %2$s" + +#: ../../include/activities.php:60 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s hat ein aktualisiertes %2$s, %3$s wurde verändert." + +#: ../../include/dir_fns.php:96 +msgid "Directory Options" +msgstr "Verzeichnisoptionen" + +#: ../../include/dir_fns.php:97 +msgid "Alphabetic" +msgstr "alphabetisch" + +#: ../../include/dir_fns.php:98 +msgid "Reverse Alphabetic" +msgstr "Entgegengesetzt alphabetisch" + +#: ../../include/dir_fns.php:99 +msgid "Newest to Oldest" +msgstr "Neueste zuerst" + +#: ../../include/dir_fns.php:100 +msgid "Oldest to Newest" +msgstr "Älteste zuerst" + +#: ../../include/dir_fns.php:101 +msgid "Public Forums Only" +msgstr "Nur öffentliche Foren" + +#: ../../include/dir_fns.php:103 +msgid "Sort" +msgstr "Sortieren" + +#: ../../include/dir_fns.php:119 +msgid "Enable Safe Search" +msgstr "Sichere Suche einschalten" + +#: ../../include/dir_fns.php:121 +msgid "Disable Safe Search" +msgstr "Sichere Suche ausschalten" + +#: ../../include/dir_fns.php:123 +msgid "Safe Mode" +msgstr "Sicherer Modus" + +#: ../../include/items.php:382 ../../mod/subthread.php:49 +#: ../../mod/group.php:68 ../../mod/profperm.php:23 ../../mod/like.php:270 +#: ../../index.php:389 +msgid "Permission denied" +msgstr "Keine Berechtigung" + +#: ../../include/items.php:979 ../../include/items.php:1024 +msgid "(Unknown)" +msgstr "(Unbekannt)" + +#: ../../include/items.php:1181 +msgid "Visible to anybody on the internet." +msgstr "Für jeden im Internet sichtbar." + +#: ../../include/items.php:1183 +msgid "Visible to you only." +msgstr "Nur für Dich sichtbar." + +#: ../../include/items.php:1185 +msgid "Visible to anybody in this network." +msgstr "Für jedes Mitglied der RedMatrix sichtbar." + +#: ../../include/items.php:1187 +msgid "Visible to anybody authenticated." +msgstr "Für jeden sichtbar, der angemeldet ist." + +#: ../../include/items.php:1189 +#, php-format +msgid "Visible to anybody on %s." +msgstr "Für jeden auf %s sichtbar." + +#: ../../include/items.php:1191 +msgid "Visible to all connections." +msgstr "Für alle Verbindungen sichtbar." + +#: ../../include/items.php:1193 +msgid "Visible to approved connections." +msgstr "Nur für akzeptierte Verbindungen sichtbar." + +#: ../../include/items.php:1195 +msgid "Visible to specific connections." +msgstr "Sichtbar für bestimmte Verbindungen." + +#: ../../include/items.php:4002 ../../mod/thing.php:76 +#: ../../mod/display.php:32 ../../mod/filestorage.php:27 +#: ../../mod/viewsrc.php:20 ../../mod/admin.php:168 ../../mod/admin.php:901 +#: ../../mod/admin.php:1104 +msgid "Item not found." +msgstr "Element nicht gefunden." + +#: ../../include/items.php:4455 ../../mod/group.php:38 ../../mod/group.php:140 +msgid "Collection not found." +msgstr "Sammlung nicht gefunden" + +#: ../../include/items.php:4470 +msgid "Collection is empty." +msgstr "Sammlung ist leer." + +#: ../../include/items.php:4477 +#, php-format +msgid "Collection: %s" +msgstr "Sammlung: %s" + +#: ../../include/items.php:4488 +#, php-format +msgid "Connection: %s" +msgstr "Verbindung: %s" + +#: ../../include/items.php:4491 +msgid "Connection not found." +msgstr "Die Verbindung wurde nicht gefunden." + +#: ../../include/event.php:376 +msgid "This event has been added to your calendar." +msgstr "Dieser Termin wurde zu Deinem Kalender hinzugefügt" + +#: ../../include/Contact.php:124 +msgid "New window" +msgstr "Neues Fenster" + +#: ../../include/Contact.php:125 +msgid "Open the selected location in a different window or browser tab" +msgstr "Öffne die markierte Adresse in einem neuen Browser Fenster oder Tab" + +#: ../../include/Contact.php:215 ../../mod/admin.php:651 +#, php-format +msgid "User '%s' deleted" +msgstr "Benutzer '%s' gelöscht" + +#: ../../include/network.php:613 +msgid "view full size" +msgstr "In Vollbildansicht anschauen" + +#: ../../include/diaspora.php:1938 ../../include/conversation.php:164 +#: ../../mod/like.php:383 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "%1$s gefällt %2$ss %3$s" + +#: ../../include/bbcode.php:115 ../../include/bbcode.php:694 +#: ../../include/bbcode.php:697 ../../include/bbcode.php:702 +#: ../../include/bbcode.php:705 ../../include/bbcode.php:708 +#: ../../include/bbcode.php:711 ../../include/bbcode.php:716 +#: ../../include/bbcode.php:719 ../../include/bbcode.php:724 +#: ../../include/bbcode.php:727 ../../include/bbcode.php:730 +#: ../../include/bbcode.php:733 +msgid "Image/photo" +msgstr "Bild/Foto" + +#: ../../include/bbcode.php:150 ../../include/bbcode.php:744 +msgid "Encrypted content" +msgstr "Verschlüsselter Inhalt" + +#: ../../include/bbcode.php:168 +msgid "Install design element: " +msgstr "Design-Element installieren:" + +#: ../../include/bbcode.php:174 +msgid "QR code" +msgstr "QR-Code" + +#: ../../include/bbcode.php:223 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "%1$s schrieb den folgenden %2$s %3$s" + +#: ../../include/bbcode.php:225 +msgid "post" +msgstr "Beitrag" + +#: ../../include/bbcode.php:447 +msgid "Different viewers will see this text differently" +msgstr "Verschiedene Betrachter werden diesen Text unterschiedlich sehen" + +#: ../../include/bbcode.php:662 +msgid "$1 spoiler" +msgstr "$1 Spoiler" + +#: ../../include/bbcode.php:682 +msgid "$1 wrote:" +msgstr "$1 schrieb:" + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "%d Einladung verfügbar" +msgstr[1] "%d Einladungen verfügbar" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:420 +msgid "Advanced" +msgstr "Fortgeschritten" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "Finde Kanäle" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "Name oder Interessen eingeben" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "Verbinden/Folgen" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Beispiele: Robert Morgenstein, Angeln" + +#: ../../include/contact_widgets.php:26 ../../mod/connections.php:413 +#: ../../mod/directory.php:330 ../../mod/directory.php:335 +msgid "Find" +msgstr "Finde" + +#: ../../include/contact_widgets.php:27 ../../mod/suggest.php:59 +#: ../../mod/directory.php:334 +msgid "Channel Suggestions" +msgstr "Kanal-Vorschläge" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "Zufallsprofil" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "Lade Freunde ein" + +#: ../../include/contact_widgets.php:32 +msgid "Advanced example: name=fred and country=iceland" +msgstr "Fortgeschrittenes Beispiel: name=fred and country=iceland" + +#: ../../include/contact_widgets.php:125 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "%d gemeinsame Verbindung" +msgstr[1] "%d gemeinsame Verbindungen" + +#: ../../include/contact_widgets.php:130 +msgid "show more" +msgstr "mehr zeigen" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "Standard-Sichtbarkeit" + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "Anzeigen" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "Nicht anzeigen" + +#: ../../include/acl_selectors.php:248 ../../mod/events.php:652 +#: ../../mod/chat.php:209 ../../mod/filestorage.php:146 +#: ../../mod/photos.php:559 ../../mod/photos.php:916 +msgid "Permissions" +msgstr "Berechtigungen" + +#: ../../include/api.php:1081 +msgid "Public Timeline" +msgstr "Öffentliche Zeitleiste" + +#: ../../include/zot.php:673 +msgid "Invalid data packet" +msgstr "Ungültiges Datenpaket" + +#: ../../include/zot.php:689 +msgid "Unable to verify channel signature" +msgstr "Konnte die Signatur des Kanals nicht verifizieren" + +#: ../../include/zot.php:1961 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "Kann die Signatur der Seite von %s nicht verifizieren" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +msgid "Male" +msgstr "Männlich" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +msgid "Female" +msgstr "Weiblich" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Momentan männlich" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Momentan weiblich" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Größtenteils männlich" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Größtenteils weiblich" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transsexuell" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Zwischengeschlechtlich" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transsexuell" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Zwitter" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Geschlechtslos" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "unklar" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 ../../include/permissions.php:814 +msgid "Other" +msgstr "Andere" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Unentschieden" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "Männer" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "Frauen" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "Schwul" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "Lesbisch" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "Keine Bevorzugung" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "Bisexuell" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "Autosexuell" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "Enthaltsam" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "Jungfräulich" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "Abweichend" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "Fetisch" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "Unmengen" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "Sexlos" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "Single" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "Einsam" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "Verfügbar" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "Nicht verfügbar" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "Verguckt" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "Verknallt" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "Lerne gerade jemanden kennen" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "Treulos" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "Sexabhängig" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "Freunde/Begünstigte" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "Lose" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "Verlobt" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "Verheiratet" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "Gewissermaßen verheiratet" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "Partner" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "Lebensgemeinschaft" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "Informelle Ehe" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "Glücklich" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "Nicht Ausschau haltend" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "Swinger" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "Betrogen" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "Getrennt" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "Labil" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "Geschieden" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "Gewissermaßen geschieden" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "Verwitwet" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "Ungewiss" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "Es ist kompliziert" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "Interessiert mich nicht" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "Frag mich mal" + +#: ../../include/apps.php:128 +msgid "Site Admin" +msgstr "Hub-Administration" + +#: ../../include/apps.php:130 +msgid "Address Book" +msgstr "Adressbuch" + +#: ../../include/apps.php:144 ../../mod/mood.php:130 +msgid "Mood" +msgstr "Laune" + +#: ../../include/apps.php:145 ../../include/conversation.php:943 +msgid "Poke" +msgstr "Anstupsen" + +#: ../../include/apps.php:148 +msgid "Probe" +msgstr "Testen" + +#: ../../include/apps.php:149 +msgid "Suggest" +msgstr "Empfehlen" + +#: ../../include/apps.php:150 +msgid "Random Channel" +msgstr "Zufälliger Kanal" + +#: ../../include/apps.php:151 +msgid "Invite" +msgstr "Einladen" + +#: ../../include/apps.php:152 +msgid "Features" +msgstr "Funktionen" + +#: ../../include/apps.php:153 +msgid "Language" +msgstr "Sprache" + +#: ../../include/apps.php:154 +msgid "Post" +msgstr "Beitrag" + +#: ../../include/apps.php:155 +msgid "Profile Photo" +msgstr "Profilfoto" + +#: ../../include/apps.php:247 ../../mod/settings.php:81 +#: ../../mod/settings.php:609 +msgid "Update" +msgstr "Aktualisieren" + +#: ../../include/apps.php:247 +msgid "Install" +msgstr "Installieren" + +#: ../../include/apps.php:252 +msgid "Purchase" +msgstr "Kaufen" + +#: ../../include/account.php:23 +msgid "Not a valid email address" +msgstr "Ungültige E-Mail-Adresse" + +#: ../../include/account.php:25 +msgid "Your email domain is not among those allowed on this site" +msgstr "Deine E-Mail-Adresse ist dieser Seite nicht erlaubt" + +#: ../../include/account.php:31 +msgid "Your email address is already registered at this site." +msgstr "Deine E-Mail-Adresse ist auf dieser Seite bereits registriert." + +#: ../../include/account.php:64 +msgid "An invitation is required." +msgstr "Eine Einladung wird benötigt" + +#: ../../include/account.php:68 +msgid "Invitation could not be verified." +msgstr "Die Einladung konnte nicht bestätigt werden" + +#: ../../include/account.php:119 +msgid "Please enter the required information." +msgstr "Bitte gib die benötigten Informationen ein." + +#: ../../include/account.php:187 +msgid "Failed to store account information." +msgstr "Speichern der Account-Informationen fehlgeschlagen" + +#: ../../include/account.php:245 +#, php-format +msgid "Registration confirmation for %s" +msgstr "Registrierungsbestätigung für %s" + +#: ../../include/account.php:313 +#, php-format +msgid "Registration request at %s" +msgstr "Registrierungsanfrage auf %s" + +#: ../../include/account.php:315 ../../include/account.php:342 +#: ../../include/account.php:399 +msgid "Administrator" +msgstr "Administrator" + +#: ../../include/account.php:337 +msgid "your registration password" +msgstr "Dein Registrierungspasswort" + +#: ../../include/account.php:340 ../../include/account.php:397 +#, php-format +msgid "Registration details for %s" +msgstr "Registrierungsdetails für %s" + +#: ../../include/account.php:406 +msgid "Account approved." +msgstr "Account bestätigt." + +#: ../../include/account.php:440 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registrierung für %s widerrufen" + +#: ../../include/account.php:486 +msgid "Account verified. Please login." +msgstr "Konto geprüft. Bitte melde Dich an!" + +#: ../../include/account.php:674 ../../include/account.php:676 +msgid "Click here to upgrade." +msgstr "Klicke hier, um das Upgrade durchzuführen." + +#: ../../include/account.php:682 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Diese Aktion überschreitet die Grenzen Ihres Abonnements." + +#: ../../include/account.php:687 +msgid "This action is not available under your subscription plan." +msgstr "Diese Aktion ist in Ihrem Abonnement nicht verfügbar." + +#: ../../include/conversation.php:126 ../../mod/like.php:113 +msgid "channel" +msgstr "Kanal" + +#: ../../include/conversation.php:167 ../../mod/like.php:385 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "%1$s gefällt %2$ss %3$s nicht" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "%1$s ist jetzt mit %2$s verbunden" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "%1$s stupste %2$s an" + +#: ../../include/conversation.php:261 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "%1$s ist %2$s" + +#: ../../include/conversation.php:556 ../../mod/photos.php:978 +msgctxt "title" +msgid "Likes" +msgstr "Gefällt mir" + +#: ../../include/conversation.php:556 ../../mod/photos.php:978 +msgctxt "title" +msgid "Dislikes" +msgstr "Gefällt mir nicht" + +#: ../../include/conversation.php:557 ../../mod/photos.php:979 +msgctxt "title" +msgid "Agree" +msgstr "Zustimmungen" + +#: ../../include/conversation.php:557 ../../mod/photos.php:979 +msgctxt "title" +msgid "Disagree" +msgstr "Ablehnungen" + +#: ../../include/conversation.php:557 ../../mod/photos.php:979 +msgctxt "title" +msgid "Abstain" +msgstr "Enthaltungen" + +#: ../../include/conversation.php:558 ../../mod/photos.php:980 +msgctxt "title" +msgid "Attending" +msgstr "Zusagen" + +#: ../../include/conversation.php:558 ../../mod/photos.php:980 +msgctxt "title" +msgid "Not attending" +msgstr "Absagen" + +#: ../../include/conversation.php:558 ../../mod/photos.php:980 +msgctxt "title" +msgid "Might attend" +msgstr "Vielleicht" + +#: ../../include/conversation.php:680 +#, php-format +msgid "View %s's profile @ %s" +msgstr "%ss Profil auf %s ansehen" + +#: ../../include/conversation.php:695 +msgid "Categories:" +msgstr "Kategorien:" + +#: ../../include/conversation.php:696 +msgid "Filed under:" +msgstr "Gespeichert unter:" + +#: ../../include/conversation.php:723 +msgid "View in context" +msgstr "Im Zusammenhang anschauen" + +#: ../../include/conversation.php:838 +msgid "remove" +msgstr "lösche" + +#: ../../include/conversation.php:843 +msgid "Delete Selected Items" +msgstr "Lösche die ausgewählten Elemente" + +#: ../../include/conversation.php:934 +msgid "View Source" +msgstr "Quelle anzeigen" + +#: ../../include/conversation.php:935 +msgid "Follow Thread" +msgstr "Unterhaltung folgen" + +#: ../../include/conversation.php:936 +msgid "View Status" +msgstr "Status ansehen" + +#: ../../include/conversation.php:938 +msgid "View Photos" +msgstr "Fotos ansehen" + +#: ../../include/conversation.php:939 +msgid "Matrix Activity" +msgstr "Matrix-Aktivität" + +#: ../../include/conversation.php:941 +msgid "Edit Contact" +msgstr "Kontakt bearbeiten" + +#: ../../include/conversation.php:942 +msgid "Send PM" +msgstr "Sende PN" + +#: ../../include/conversation.php:1061 +#, php-format +msgid "%s likes this." +msgstr "%s gefällt das." + +#: ../../include/conversation.php:1061 +#, php-format +msgid "%s doesn't like this." +msgstr "%s gefällt das nicht." + +#: ../../include/conversation.php:1065 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "%2$d Person gefällt das." +msgstr[1] "%2$d Leuten gefällt das." + +#: ../../include/conversation.php:1067 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "%2$d Person gefällt das nicht." +msgstr[1] "%2$d Leuten gefällt das nicht." + +#: ../../include/conversation.php:1073 +msgid "and" +msgstr "und" + +#: ../../include/conversation.php:1076 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] "" +msgstr[1] ", und %d andere" + +#: ../../include/conversation.php:1077 +#, php-format +msgid "%s like this." +msgstr "%s gefällt das." + +#: ../../include/conversation.php:1077 +#, php-format +msgid "%s don't like this." +msgstr "%s gefällt das nicht." + +#: ../../include/conversation.php:1136 +msgid "Visible to everybody" +msgstr "Sichtbar für jeden" + +#: ../../include/conversation.php:1137 ../../mod/mail.php:174 +#: ../../mod/mail.php:289 +msgid "Please enter a link URL:" +msgstr "Gib eine URL ein:" + +#: ../../include/conversation.php:1138 +msgid "Please enter a video link/URL:" +msgstr "Gib einen Video-Link/URL ein:" + +#: ../../include/conversation.php:1139 +msgid "Please enter an audio link/URL:" +msgstr "Gib einen Audio-Link/URL ein:" + +#: ../../include/conversation.php:1140 +msgid "Tag term:" +msgstr "Schlagwort:" + +#: ../../include/conversation.php:1141 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "Speichern in Ordner:" + +#: ../../include/conversation.php:1142 +msgid "Where are you right now?" +msgstr "Wo bist Du jetzt grade?" + +#: ../../include/conversation.php:1143 ../../mod/editpost.php:52 +#: ../../mod/mail.php:175 ../../mod/mail.php:290 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "Verfällt YYYY-MM-DD HH;MM" + +#: ../../include/conversation.php:1170 ../../mod/editblock.php:198 +#: ../../mod/editlayout.php:193 ../../mod/editwebpage.php:230 +#: ../../mod/layouts.php:168 ../../mod/photos.php:943 +msgid "Share" +msgstr "Teilen" + +#: ../../include/conversation.php:1172 ../../mod/editwebpage.php:170 +msgid "Page link title" +msgstr "Seitentitel-Link" + +#: ../../include/conversation.php:1175 +msgid "Post as" +msgstr "Veröffentlichen als" + +#: ../../include/conversation.php:1176 ../../mod/editblock.php:144 +#: ../../mod/editpost.php:114 ../../mod/editlayout.php:140 +#: ../../mod/editwebpage.php:175 ../../mod/mail.php:238 ../../mod/mail.php:352 +msgid "Upload photo" +msgstr "Foto hochladen" + +#: ../../include/conversation.php:1177 +msgid "upload photo" +msgstr "Foto hochladen" + +#: ../../include/conversation.php:1178 ../../mod/editblock.php:145 +#: ../../mod/editpost.php:115 ../../mod/editlayout.php:141 +#: ../../mod/editwebpage.php:176 ../../mod/mail.php:239 ../../mod/mail.php:353 +msgid "Attach file" +msgstr "Datei anhängen" + +#: ../../include/conversation.php:1179 +msgid "attach file" +msgstr "Datei anfügen" + +#: ../../include/conversation.php:1180 ../../mod/editblock.php:146 +#: ../../mod/editpost.php:116 ../../mod/editlayout.php:142 +#: ../../mod/editwebpage.php:177 ../../mod/mail.php:240 ../../mod/mail.php:354 +msgid "Insert web link" +msgstr "Link einfügen" + +#: ../../include/conversation.php:1181 +msgid "web link" +msgstr "Web-Link" + +#: ../../include/conversation.php:1182 +msgid "Insert video link" +msgstr "Video-Link einfügen" + +#: ../../include/conversation.php:1183 +msgid "video link" +msgstr "Video-Link" + +#: ../../include/conversation.php:1184 +msgid "Insert audio link" +msgstr "Audio-Link einfügen" + +#: ../../include/conversation.php:1185 +msgid "audio link" +msgstr "Audio-Link" + +#: ../../include/conversation.php:1186 ../../mod/editblock.php:150 +#: ../../mod/editpost.php:120 ../../mod/editlayout.php:146 +#: ../../mod/editwebpage.php:181 +msgid "Set your location" +msgstr "Standort" + +#: ../../include/conversation.php:1187 +msgid "set location" +msgstr "Standort" + +#: ../../include/conversation.php:1188 ../../mod/editpost.php:122 +msgid "Toggle voting" +msgstr "Umfragewerkzeug aktivieren" + +#: ../../include/conversation.php:1191 ../../mod/editblock.php:151 +#: ../../mod/editpost.php:121 ../../mod/editlayout.php:147 +#: ../../mod/editwebpage.php:182 +msgid "Clear browser location" +msgstr "Browser-Standort löschen" + +#: ../../include/conversation.php:1192 +msgid "clear location" +msgstr "Standort löschen" + +#: ../../include/conversation.php:1194 ../../mod/editblock.php:164 +#: ../../mod/editpost.php:136 ../../mod/editlayout.php:159 +#: ../../mod/editwebpage.php:198 +msgid "Title (optional)" +msgstr "Titel (optional)" + +#: ../../include/conversation.php:1197 ../../mod/editblock.php:167 +#: ../../mod/editpost.php:138 ../../mod/editlayout.php:162 +#: ../../mod/editwebpage.php:200 +msgid "Categories (optional, comma-separated list)" +msgstr "Kategorien (optional, kommagetrennte Liste)" + +#: ../../include/conversation.php:1199 ../../mod/editblock.php:153 +#: ../../mod/editpost.php:126 ../../mod/editlayout.php:149 +#: ../../mod/editwebpage.php:184 +msgid "Permission settings" +msgstr "Berechtigungs-Einstellungen" + +#: ../../include/conversation.php:1200 +msgid "permissions" +msgstr "Berechtigungen" + +#: ../../include/conversation.php:1207 ../../mod/editblock.php:161 +#: ../../mod/editpost.php:133 ../../mod/editlayout.php:156 +#: ../../mod/editwebpage.php:193 +msgid "Public post" +msgstr "Öffentlicher Beitrag" + +#: ../../include/conversation.php:1209 ../../mod/editblock.php:168 +#: ../../mod/editpost.php:139 ../../mod/editlayout.php:163 +#: ../../mod/editwebpage.php:201 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Beispiel: bob@example.com, mary@example.com" + +#: ../../include/conversation.php:1222 ../../mod/editblock.php:178 +#: ../../mod/editpost.php:150 ../../mod/editlayout.php:173 +#: ../../mod/editwebpage.php:210 ../../mod/mail.php:245 ../../mod/mail.php:359 +msgid "Set expiration date" +msgstr "Verfallsdatum" + +#: ../../include/conversation.php:1226 ../../mod/editpost.php:154 +#: ../../mod/events.php:635 +msgid "OK" +msgstr "Ok" + +#: ../../include/conversation.php:1227 ../../mod/editpost.php:155 +#: ../../mod/events.php:634 ../../mod/fbrowser.php:82 +#: ../../mod/fbrowser.php:117 ../../mod/settings.php:584 +#: ../../mod/settings.php:610 ../../mod/tagrm.php:11 ../../mod/tagrm.php:134 +msgid "Cancel" +msgstr "Abbrechen" + +#: ../../include/conversation.php:1471 +msgid "Discover" +msgstr "Entdecken" + +#: ../../include/conversation.php:1474 +msgid "Imported public streams" +msgstr "Importierte öffentliche Beiträge" + +#: ../../include/conversation.php:1479 +msgid "Commented Order" +msgstr "Neueste Kommentare" + +#: ../../include/conversation.php:1482 +msgid "Sort by Comment Date" +msgstr "Nach Kommentardatum sortiert" + +#: ../../include/conversation.php:1486 +msgid "Posted Order" +msgstr "Neueste Beiträge" + +#: ../../include/conversation.php:1489 +msgid "Sort by Post Date" +msgstr "Nach Beitragsdatum sortiert" + +#: ../../include/conversation.php:1497 +msgid "Posts that mention or involve you" +msgstr "Beiträge mit Beteiligung Deinerseits" + +#: ../../include/conversation.php:1503 ../../mod/connections.php:212 +#: ../../mod/connections.php:225 ../../mod/menu.php:80 +msgid "New" +msgstr "Neu" + +#: ../../include/conversation.php:1506 +msgid "Activity Stream - by date" +msgstr "Activity Stream – nach Datum sortiert" + +#: ../../include/conversation.php:1512 +msgid "Starred" +msgstr "Markiert" + +#: ../../include/conversation.php:1515 +msgid "Favourite Posts" +msgstr "Markierte Beiträge" + +#: ../../include/conversation.php:1522 +msgid "Spam" +msgstr "Spam" + +#: ../../include/conversation.php:1525 +msgid "Posts flagged as SPAM" +msgstr "Nachrichten, die als SPAM markiert wurden" + +#: ../../include/conversation.php:1565 ../../mod/admin.php:870 +msgid "Channel" +msgstr "Kanal" + +#: ../../include/conversation.php:1568 +msgid "Status Messages and Posts" +msgstr "Statusnachrichten und Beiträge" + +#: ../../include/conversation.php:1577 +msgid "About" +msgstr "Ãœber" + +#: ../../include/conversation.php:1580 +msgid "Profile Details" +msgstr "Profil-Details" + +#: ../../include/conversation.php:1598 +msgid "Files and Storage" +msgstr "Dateien und Speicher" + +#: ../../include/conversation.php:1608 ../../include/conversation.php:1611 +msgid "Chatrooms" +msgstr "Chaträume" + +#: ../../include/conversation.php:1624 +msgid "Saved Bookmarks" +msgstr "Gespeicherte Lesezeichen" + +#: ../../include/conversation.php:1635 +msgid "Manage Webpages" +msgstr "Webseiten verwalten" + +#: ../../include/conversation.php:1698 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "Zusage" +msgstr[1] "Zusagen" + +#: ../../include/conversation.php:1701 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "Absage" +msgstr[1] "Absagen" + +#: ../../include/conversation.php:1704 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] " Unentschlossen" +msgstr[1] "Unentschlossene" + +#: ../../include/conversation.php:1707 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "Zustimmung" +msgstr[1] "Zustimmungen" + +#: ../../include/conversation.php:1710 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "Ablehnung" +msgstr[1] "Ablehnungen" + +#: ../../include/conversation.php:1713 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "Enthaltung" +msgstr[1] "Enthaltungen" + +#: ../../include/oembed.php:171 +msgid "Embedded content" +msgstr "Eingebetteter Inhalt" + +#: ../../include/oembed.php:180 +msgid "Embedding disabled" +msgstr "Einbetten ausgeschaltet" + +#: ../../include/permissions.php:26 +msgid "Can view my normal stream and posts" +msgstr "Kann meine normalen Beiträge sehen" + +#: ../../include/permissions.php:27 +msgid "Can view my default channel profile" +msgstr "Kann mein Standardprofil sehen" + +#: ../../include/permissions.php:28 +msgid "Can view my photo albums" +msgstr "Kann meine Fotoalben betrachten" + +#: ../../include/permissions.php:29 +msgid "Can view my connections" +msgstr "Kann meine Verbindungen sehen" + +#: ../../include/permissions.php:30 +msgid "Can view my file storage" +msgstr "Kann meine Dateiordner lesen" + +#: ../../include/permissions.php:31 +msgid "Can view my webpages" +msgstr "Kann meine Webseiten sehen" + +#: ../../include/permissions.php:34 +msgid "Can send me their channel stream and posts" +msgstr "Kann mir die Beiträge aus seinem/ihrem Kanal schicken" + +#: ../../include/permissions.php:35 +msgid "Can post on my channel page (\"wall\")" +msgstr "Kann auf meiner Kanal-Seite (\"wall\") Beiträge veröffentlichen" + +#: ../../include/permissions.php:36 +msgid "Can comment on or like my posts" +msgstr "Darf meine Beiträge kommentieren und mögen/nicht mögen" + +#: ../../include/permissions.php:37 +msgid "Can send me private mail messages" +msgstr "Kann mir private Nachrichten schicken" + +#: ../../include/permissions.php:38 +msgid "Can post photos to my photo albums" +msgstr "Kann Fotos in meinen Fotoalben veröffentlichen" + +#: ../../include/permissions.php:39 +msgid "Can like/dislike stuff" +msgstr "Kann andere Elemente mögen/nicht mögen" + +#: ../../include/permissions.php:39 +msgid "Profiles and things other than posts/comments" +msgstr "Profile und alles außer Beiträge und Kommentare" + +#: ../../include/permissions.php:41 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "Kann an alle meine Kontakte via @-Erwähnung Nachrichten weiterleiten" + +#: ../../include/permissions.php:41 +msgid "Advanced - useful for creating group forum channels" +msgstr "Fortgeschritten - sinnvoll, um Gruppen-Kanäle/-Foren zu erstellen" + +#: ../../include/permissions.php:42 +msgid "Can chat with me (when available)" +msgstr "Kann mit mir chatten (wenn verfügbar)" + +#: ../../include/permissions.php:43 +msgid "Can write to my file storage" +msgstr "Kann in meine Dateiordner schreiben" + +#: ../../include/permissions.php:44 +msgid "Can edit my webpages" +msgstr "Kann meine Webseiten bearbeiten" + +#: ../../include/permissions.php:46 +msgid "Can source my public posts in derived channels" +msgstr "Kann meine öffentlichen Beiträge als Quellen für Kanäle verwenden" + +#: ../../include/permissions.php:46 +msgid "Somewhat advanced - very useful in open communities" +msgstr "Etwas fortgeschritten – sehr nützlich in offenen Gemeinschaften" + +#: ../../include/permissions.php:48 +msgid "Can administer my channel resources" +msgstr "Kann meine Kanäle administrieren" + +#: ../../include/permissions.php:48 +msgid "" +"Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "Sehr fortgeschritten. Bearbeite das nur, wenn Du genau weißt, was Du tust" + +#: ../../include/permissions.php:810 +msgid "Social Networking" +msgstr "Soziales Netzwerk" + +#: ../../include/permissions.php:810 ../../include/permissions.php:811 +#: ../../include/permissions.php:812 +msgid "Mostly Public" +msgstr "Weitgehend öffentlich" + +#: ../../include/permissions.php:810 ../../include/permissions.php:811 +#: ../../include/permissions.php:812 +msgid "Restricted" +msgstr "Beschränkt" + +#: ../../include/permissions.php:810 ../../include/permissions.php:811 +msgid "Private" +msgstr "Privat" + +#: ../../include/permissions.php:811 +msgid "Community Forum" +msgstr "Forum" + +#: ../../include/permissions.php:812 +msgid "Feed Republish" +msgstr "Teilen von Feeds" + +#: ../../include/permissions.php:813 +msgid "Special Purpose" +msgstr "Für besondere Zwecke" + +#: ../../include/permissions.php:813 +msgid "Celebrity/Soapbox" +msgstr "Mitteilungs-Kanal (keine Kommentare)" + +#: ../../include/permissions.php:813 +msgid "Group Repository" +msgstr "Gruppenarchiv" + +#: ../../include/permissions.php:814 +msgid "Custom/Expert Mode" +msgstr "Benutzerdefiniert/Expertenmodus" + +#: ../../mod/achievements.php:34 +msgid "Some blurb about what to do when you're new here" +msgstr "Ein Hinweis, was man tun kann, wenn man neu hier ist" + +#: ../../mod/editblock.php:79 ../../mod/editblock.php:95 +#: ../../mod/editpost.php:20 ../../mod/editlayout.php:78 +#: ../../mod/editwebpage.php:77 +msgid "Item not found" +msgstr "Element nicht gefunden" + +#: ../../mod/editblock.php:115 +msgid "Edit Block" +msgstr "Block bearbeiten" + +#: ../../mod/editblock.php:125 +msgid "Delete block?" +msgstr "Block löschen?" + +#: ../../mod/editblock.php:147 ../../mod/editpost.php:117 +#: ../../mod/editlayout.php:143 ../../mod/editwebpage.php:178 +msgid "Insert YouTube video" +msgstr "YouTube-Video einfügen" + +#: ../../mod/editblock.php:148 ../../mod/editpost.php:118 +#: ../../mod/editlayout.php:144 ../../mod/editwebpage.php:179 +msgid "Insert Vorbis [.ogg] video" +msgstr "Vorbis [.ogg]-Video einfügen" + +#: ../../mod/editblock.php:149 ../../mod/editpost.php:119 +#: ../../mod/editlayout.php:145 ../../mod/editwebpage.php:180 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Vorbis [.ogg]-Audio einfügen" + +#: ../../mod/editblock.php:183 +msgid "Delete Block" +msgstr "Block löschen" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "Du hast %1$.0f von maximal %2$.0f erlaubten Kanälen eingerichtet." + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "Neuen Kanal anlegen" + +#: ../../mod/manage.php:149 +msgid "Current Channel" +msgstr "Aktueller Kanal" + +#: ../../mod/manage.php:151 +msgid "Switch to one of your channels by selecting it." +msgstr "Wechsle zu einem Deiner Kanäle, indem Du auf ihn klickst." + +#: ../../mod/manage.php:152 +msgid "Default Channel" +msgstr "Standard Kanal" + +#: ../../mod/manage.php:153 +msgid "Make Default" +msgstr "Zum Standard machen" + +#: ../../mod/manage.php:156 +#, php-format +msgid "%d new messages" +msgstr "%d neue Nachrichten" + +#: ../../mod/manage.php:157 +#, php-format +msgid "%d new introductions" +msgstr "%d neue Vorstellungen" + +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +msgstr "Xchan-Suche" + +#: ../../mod/xchan.php:9 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "Nach xchans oder Webbies (Kanal-Adressen) suchen, die wie folgt beginnen:" + +#: ../../mod/xchan.php:37 ../../mod/menu.php:136 ../../mod/mitem.php:111 +msgid "Not found." +msgstr "Nicht gefunden." + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Zugriff für die Anwendung autorisieren" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Trage folgenden Sicherheitscode in der Anwendung ein:" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Zum Weitermachen, bitte einloggen." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Möchtest Du dieser Anwendung erlauben, Deine Nachrichten und Kontakte abzurufen und/oder neue Nachrichten für Dich zu erstellen?" + +#: ../../mod/api.php:105 ../../mod/settings.php:974 ../../mod/settings.php:979 +#: ../../mod/settings.php:1064 ../../mod/admin.php:396 +msgid "Yes" +msgstr "Ja" + +#: ../../mod/api.php:106 ../../mod/settings.php:974 ../../mod/settings.php:979 +#: ../../mod/settings.php:1064 ../../mod/admin.php:394 +msgid "No" +msgstr "Nein" + +#: ../../mod/blocks.php:99 +msgid "Block Name" +msgstr "Block-Name" + +#: ../../mod/connedit.php:75 ../../mod/connections.php:37 +msgid "Could not access contact record." +msgstr "Konnte nicht auf den Kontakteintrag zugreifen." + +#: ../../mod/connedit.php:99 ../../mod/connections.php:51 +msgid "Could not locate selected profile." +msgstr "Gewähltes Profil nicht gefunden." + +#: ../../mod/connedit.php:204 ../../mod/connections.php:94 +msgid "Connection updated." +msgstr "Verbindung aktualisiert." + +#: ../../mod/connedit.php:206 ../../mod/connections.php:96 +msgid "Failed to update connection record." +msgstr "Konnte den Verbindungseintrag nicht aktualisieren." + +#: ../../mod/connedit.php:252 +msgid "is now connected to" +msgstr "ist jetzt verbunden mit" + +#: ../../mod/connedit.php:365 +msgid "Could not access address book record." +msgstr "Konnte nicht auf den Adressbuch-Eintrag zugreifen." + +#: ../../mod/connedit.php:379 +msgid "Refresh failed - channel is currently unavailable." +msgstr "Aktualisierung fehlgeschlagen – der Kanal ist im Moment nicht erreichbar." + +#: ../../mod/connedit.php:386 +msgid "Channel has been unblocked" +msgstr "Kanal nicht mehr blockiert" + +#: ../../mod/connedit.php:387 +msgid "Channel has been blocked" +msgstr "Kanal blockiert" + +#: ../../mod/connedit.php:391 ../../mod/connedit.php:403 +#: ../../mod/connedit.php:415 ../../mod/connedit.php:427 +#: ../../mod/connedit.php:443 +msgid "Unable to set address book parameters." +msgstr "Konnte die Adressbuch-Parameter nicht setzen." + +#: ../../mod/connedit.php:398 +msgid "Channel has been unignored" +msgstr "Kanal wird nicht mehr ignoriert" + +#: ../../mod/connedit.php:399 +msgid "Channel has been ignored" +msgstr "Kanal wird ignoriert" + +#: ../../mod/connedit.php:410 +msgid "Channel has been unarchived" +msgstr "Kanal wurde aus dem Archiv zurück geholt" + +#: ../../mod/connedit.php:411 +msgid "Channel has been archived" +msgstr "Kanal wurde archiviert" + +#: ../../mod/connedit.php:422 +msgid "Channel has been unhidden" +msgstr "Kanal wird nicht mehr versteckt" + +#: ../../mod/connedit.php:423 +msgid "Channel has been hidden" +msgstr "Kanal wurde versteckt" + +#: ../../mod/connedit.php:438 +msgid "Channel has been approved" +msgstr "Kanal wurde zugelassen" + +#: ../../mod/connedit.php:439 +msgid "Channel has been unapproved" +msgstr "Zulassung des Kanals entfernt" + +#: ../../mod/connedit.php:467 +msgid "Connection has been removed." +msgstr "Verbindung wurde gelöscht." + +#: ../../mod/connedit.php:487 +#, php-format +msgid "View %s's profile" +msgstr "%ss Profil ansehen" + +#: ../../mod/connedit.php:491 +msgid "Refresh Permissions" +msgstr "Zugriffsrechte neu laden" + +#: ../../mod/connedit.php:494 +msgid "Fetch updated permissions" +msgstr "Aktualisierte Zugriffsrechte abfragen" + +#: ../../mod/connedit.php:498 +msgid "Recent Activity" +msgstr "Kürzliche Aktivitäten" + +#: ../../mod/connedit.php:501 +msgid "View recent posts and comments" +msgstr "Betrachte die neuesten Beiträge und Kommentare" + +#: ../../mod/connedit.php:507 ../../mod/connedit.php:694 +#: ../../mod/admin.php:737 +msgid "Unblock" +msgstr "Freigeben" + +#: ../../mod/connedit.php:507 ../../mod/connedit.php:694 +#: ../../mod/admin.php:736 +msgid "Block" +msgstr "Blockieren" + +#: ../../mod/connedit.php:510 +msgid "Block (or Unblock) all communications with this connection" +msgstr "Jegliche Kommunikation mit dieser Verbindung blockieren/zulassen" + +#: ../../mod/connedit.php:514 ../../mod/connedit.php:695 +msgid "Unignore" +msgstr "Nicht ignorieren" + +#: ../../mod/connedit.php:514 ../../mod/connedit.php:695 +#: ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "Ignorieren" + +#: ../../mod/connedit.php:517 +msgid "Ignore (or Unignore) all inbound communications from this connection" +msgstr "Jegliche eingehende Kommunikation von dieser Verbindung ignorieren/zulassen" + +#: ../../mod/connedit.php:520 +msgid "Unarchive" +msgstr "Aus Archiv zurückholen" + +#: ../../mod/connedit.php:520 +msgid "Archive" +msgstr "Archivieren" + +#: ../../mod/connedit.php:523 +msgid "" +"Archive (or Unarchive) this connection - mark channel dead but keep content" +msgstr "Verbindung archivieren/aus dem Archiv zurückholen (Archiv = Kanal als erloschen markieren, aber die Beiträge behalten)" + +#: ../../mod/connedit.php:526 +msgid "Unhide" +msgstr "Wieder sichtbar machen" + +#: ../../mod/connedit.php:526 +msgid "Hide" +msgstr "Verstecken" + +#: ../../mod/connedit.php:529 +msgid "Hide or Unhide this connection from your other connections" +msgstr "Diese Verbindung vor anderen Verbindungen verstecken/zeigen" + +#: ../../mod/connedit.php:536 +msgid "Delete this connection" +msgstr "Verbindung löschen" + +#: ../../mod/connedit.php:611 ../../mod/connedit.php:649 +msgid "Approve this connection" +msgstr "Verbindung genehmigen" + +#: ../../mod/connedit.php:611 +msgid "Accept connection to allow communication" +msgstr "Akzeptiere die Verbindung, um Kommunikation zu ermöglichen" + +#: ../../mod/connedit.php:627 +#, php-format +msgid "Connections: settings for %s" +msgstr "Verbindungseinstellungen für %s" + +#: ../../mod/connedit.php:628 +msgid "Apply these permissions automatically" +msgstr "Diese Berechtigungen automatisch anwenden" + +#: ../../mod/connedit.php:632 +msgid "Apply the permissions indicated on this page to all new connections." +msgstr "Wende die auf dieser Seite gewählten Berechtigungen auf alle neuen Verbindungen an." + +#: ../../mod/connedit.php:636 +msgid "Slide to adjust your degree of friendship" +msgstr "Verschieben, um den Grad der Freundschaft zu einzustellen" + +#: ../../mod/connedit.php:637 ../../mod/rate.php:161 +msgid "Rating (this information is public)" +msgstr "Bewertung (öffentlich sichtbar)" + +#: ../../mod/connedit.php:638 ../../mod/rate.php:162 +msgid "Optionally explain your rating (this information is public)" +msgstr "Optional kannst du deine Bewertung erklären (öffentlich sichtbar)" + +#: ../../mod/connedit.php:645 +msgid "" +"Default permissions for your channel type have (just) been applied. They " +"have not yet been submitted. Please review the permissions on this page and " +"make any desired changes at this time. This new connection may not " +"be able to communicate with you until you submit this page, which will " +"install and apply the selected permissions." +msgstr "Die voreingestellten Zugriffsrechte der Kategorie Deines Kanals sind hier zu sehen, wurden aber noch nicht gespeichert. Bitte sieh Dir die Zugriffsrechte auf dieser Seite an und ändere sie, wenn Du willst. Dieser Kontakt kann evtl. nicht mit Dir kommunizieren, bevor Du nicht auf dieser Seite auf „Senden“ geklickt hast – erst dieser Klick speichert die gewünschten Zugriffsrechte." + +#: ../../mod/connedit.php:648 +msgid "inherited" +msgstr "geerbt" + +#: ../../mod/connedit.php:651 +msgid "Connection has no individual permissions!" +msgstr "Diese Verbindung hat keine individuellen Zugriffsrechte!" + +#: ../../mod/connedit.php:652 +msgid "" +"This may be appropriate based on your privacy " +"settings, though you may wish to review the \"Advanced Permissions\"." +msgstr "Abhängig von Deinen Privatsphäre-Einstellungen könnte das passen, eventuell solltest Du aber die „Zugriffsrechte für Fortgeschrittene“ überprüfen." + +#: ../../mod/connedit.php:654 +msgid "Profile Visibility" +msgstr "Sichtbarkeit des Profils" + +#: ../../mod/connedit.php:655 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Bitte wähle ein Profil, das wir %s zeigen sollen, wenn Deine Profilseite über eine verifizierte Verbindung aufgerufen wird." + +#: ../../mod/connedit.php:656 +msgid "Contact Information / Notes" +msgstr "Kontaktinformationen / Notizen" + +#: ../../mod/connedit.php:657 +msgid "Edit contact notes" +msgstr "Kontaktnotizen bearbeiten" + +#: ../../mod/connedit.php:659 +msgid "Their Settings" +msgstr "Deren Einstellungen" + +#: ../../mod/connedit.php:660 +msgid "My Settings" +msgstr "Meine Einstellungen" + +#: ../../mod/connedit.php:662 +msgid "" +"Default permissions for this channel type have (just) been applied. They " +"have not been saved and there are currently no stored default " +"permissions. Please review/edit the applied settings and click [Submit] to " +"finalize." +msgstr "Die voreingestellten Zugriffsrechte der Kategorie Deines Kanals sind hier zu sehen, wurden aber noch nicht gespeichert, und Du hast keine Voreinstellungen für die Zugriffsrechte von Verbindungen angelegt. Bitte sieht Dir die Einstellungen an, ändere sie bei Bedarf und klicke [Senden], um den Vorgang abzuschließen." + +#: ../../mod/connedit.php:663 +msgid "Clear/Disable Automatic Permissions" +msgstr "Automatische Berechtigungen abschalten/entfernen" + +#: ../../mod/connedit.php:664 +msgid "Forum Members" +msgstr "Forum Mitglieder" + +#: ../../mod/connedit.php:665 +msgid "Soapbox" +msgstr "Marktschreier" + +#: ../../mod/connedit.php:666 +msgid "Full Sharing (typical social network permissions)" +msgstr "Vollumfängliches Teilen (übliche Berechtigungen in sozialen Netzwerken)" + +#: ../../mod/connedit.php:667 +msgid "Cautious Sharing " +msgstr "Vorsichtiges Teilen" + +#: ../../mod/connedit.php:668 +msgid "Follow Only" +msgstr "Nur folgen" + +#: ../../mod/connedit.php:669 +msgid "Individual Permissions" +msgstr "Individuelle Zugriffsrechte" + +#: ../../mod/connedit.php:670 +msgid "" +"Some permissions may be inherited from your channel privacy settings, which have higher priority than " +"individual settings. Changing those inherited settings on this page will " +"have no effect." +msgstr "Einige Berechtigungen werden von den globalen Sicherheits- und Privatsphäre-Einstellungen dieses Kanals geerbt, die eine höhere Priorität haben als die Einstellungen bei einer Verbindung. Werden geerbte Einstellungen hier geändert, hat das keine Auswirkungen." + +#: ../../mod/connedit.php:671 +msgid "Advanced Permissions" +msgstr "Zugriffsrechte für Fortgeschrittene" + +#: ../../mod/connedit.php:672 +msgid "Simple Permissions (select one and submit)" +msgstr "Einfache Berechtigungs-Einstellungen (wähle eine aus und klicke auf Senden)" + +#: ../../mod/connedit.php:676 +#, php-format +msgid "Visit %s's profile - %s" +msgstr "%ss Profil besuchen - %s" + +#: ../../mod/connedit.php:677 +msgid "Block/Unblock contact" +msgstr "Kontakt blockieren/freigeben" + +#: ../../mod/connedit.php:678 +msgid "Ignore contact" +msgstr "Kontakt ignorieren" + +#: ../../mod/connedit.php:679 +msgid "Repair URL settings" +msgstr "URL-Einstellungen reparieren" + +#: ../../mod/connedit.php:680 +msgid "View conversations" +msgstr "Unterhaltungen anzeigen" + +#: ../../mod/connedit.php:682 +msgid "Delete contact" +msgstr "Kontakt löschen" + +#: ../../mod/connedit.php:686 +msgid "Last update:" +msgstr "Letzte Aktualisierung:" + +#: ../../mod/connedit.php:688 +msgid "Update public posts" +msgstr "Öffentliche Beiträge aktualisieren" + +#: ../../mod/connedit.php:690 +msgid "Update now" +msgstr "Jetzt aktualisieren" + +#: ../../mod/connedit.php:696 +msgid "Currently blocked" +msgstr "Derzeit blockiert" + +#: ../../mod/connedit.php:697 +msgid "Currently ignored" +msgstr "Derzeit ignoriert" + +#: ../../mod/connedit.php:698 +msgid "Currently archived" +msgstr "Derzeit archiviert" + +#: ../../mod/connedit.php:699 +msgid "Currently pending" +msgstr "Derzeit anstehend" + +#: ../../mod/home.php:48 +msgid "Red Matrix - "The Network"" +msgstr "RedMatrix – "Das Netzwerk"" + +#: ../../mod/home.php:101 +#, php-format +msgid "Welcome to %s" +msgstr "Willkommen auf %s" + +#: ../../mod/connect.php:56 ../../mod/connect.php:104 +msgid "Continue" +msgstr "Fortfahren" + +#: ../../mod/connect.php:85 +msgid "Premium Channel Setup" +msgstr "Premium-Kanal-Einrichtung" + +#: ../../mod/connect.php:87 +msgid "Enable premium channel connection restrictions" +msgstr "Einschränkungen für einen Premium-Kanal aktivieren" + +#: ../../mod/connect.php:88 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "Bitte gib Deine Nutzungsbedingungen ein, z.B. Paypal-Quittung, Richtlinien etc." + +#: ../../mod/connect.php:90 ../../mod/connect.php:110 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "Unter Umständen sind weitere Schritte oder die Bestätigung der folgenden Bedingungen vor dem Verbinden mit diesem Kanal nötig." + +#: ../../mod/connect.php:91 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "Potentielle Kontakte werden den folgenden Text sehen, bevor fortgefahren wird:" + +#: ../../mod/connect.php:92 ../../mod/connect.php:113 +msgid "" +"By continuing, I certify that I have complied with any instructions provided" +" on this page." +msgstr "Indem ich fortfahre, bestätige ich die Erfüllung aller Anweisungen auf dieser Seite." + +#: ../../mod/connect.php:101 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "(Der Kanal-Besitzer hat keine speziellen Anweisungen hinterlegt.)" + +#: ../../mod/connect.php:109 +msgid "Restricted or Premium Channel" +msgstr "Eingeschränkter oder Premium-Kanal" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "Element kann nicht bearbeitet werden." + +#: ../../mod/editpost.php:42 ../../mod/rpost.php:97 +msgid "Edit post" +msgstr "Bearbeite Beitrag" + +#: ../../mod/editpost.php:53 +msgid "Delete item?" +msgstr "Eintrag löschen?" + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "Element nicht verfügbar." + +#: ../../mod/probe.php:23 ../../mod/probe.php:29 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "Abrufen der URL gab einen Fehler zurück: %1$s" + +#: ../../mod/dav.php:121 +msgid "RedMatrix channel" +msgstr "RedMatrix-Kanal" + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "Bild hochgeladen, aber das Zurechtschneiden schlug fehl." + +#: ../../mod/profile_photo.php:162 +msgid "Image resize failed." +msgstr "Bild-Anpassung fehlgeschlagen." + +#: ../../mod/profile_photo.php:206 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Leere den Browser Cache oder nutze Umschalten-Neu Laden, falls das neue Foto nicht sofort angezeigt wird." + +#: ../../mod/profile_photo.php:233 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "Bild ist größer als das Limit von %d" + +#: ../../mod/profile_photo.php:242 +msgid "Unable to process image." +msgstr "Kann Bild nicht verarbeiten." + +#: ../../mod/profile_photo.php:291 ../../mod/profile_photo.php:340 +msgid "Photo not available." +msgstr "Foto nicht verfügbar." + +#: ../../mod/profile_photo.php:359 +msgid "Upload File:" +msgstr "Datei hochladen:" + +#: ../../mod/profile_photo.php:360 +msgid "Select a profile:" +msgstr "Wähle ein Profil:" + +#: ../../mod/profile_photo.php:361 +msgid "Upload Profile Photo" +msgstr "Lade neues Profilfoto hoch" + +#: ../../mod/profile_photo.php:366 ../../mod/settings.php:983 +msgid "or" +msgstr "oder" + +#: ../../mod/profile_photo.php:366 +msgid "skip this step" +msgstr "diesen Schritt überspringen" + +#: ../../mod/profile_photo.php:366 +msgid "select a photo from your photo albums" +msgstr "ein Foto aus meinen Fotoalben" + +#: ../../mod/profile_photo.php:382 +msgid "Crop Image" +msgstr "Bild zuschneiden" + +#: ../../mod/profile_photo.php:383 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Bitte schneide das Bild für eine optimale Anzeige passend zu." + +#: ../../mod/profile_photo.php:385 +msgid "Done Editing" +msgstr "Bearbeitung fertigstellen" + +#: ../../mod/profile_photo.php:428 +msgid "Image uploaded successfully." +msgstr "Bild erfolgreich hochgeladen." + +#: ../../mod/profile_photo.php:430 +msgid "Image upload failed." +msgstr "Hochladen des Bilds fehlgeschlagen." + +#: ../../mod/profile_photo.php:439 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "Reduzierung der Bildgröße [%s] fehlgeschlagen." + +#: ../../mod/block.php:27 ../../mod/page.php:33 +msgid "Invalid item." +msgstr "Ungültiges Element." + +#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:45 +msgid "Channel not found." +msgstr "Kanal nicht gefunden." + +#: ../../mod/block.php:75 ../../mod/help.php:79 ../../mod/display.php:102 +#: ../../mod/page.php:81 ../../index.php:241 +msgid "Page not found." +msgstr "Seite nicht gefunden." + +#: ../../mod/network.php:84 +msgid "No such group" +msgstr "Sammlung nicht gefunden" + +#: ../../mod/network.php:122 +msgid "Search Results For:" +msgstr "Suchergebnisse für:" + +#: ../../mod/network.php:176 +msgid "Collection is empty" +msgstr "Sammlung ist leer" + +#: ../../mod/network.php:184 +msgid "Collection: " +msgstr "Sammlung:" + +#: ../../mod/network.php:197 +msgid "Connection: " +msgstr "Verbindung:" + +#: ../../mod/network.php:200 +msgid "Invalid connection." +msgstr "Ungültige Verbindung." + +#: ../../mod/events.php:87 +msgid "Event can not end before it has started." +msgstr "Termin-Ende liegt vor dem Beginn." + +#: ../../mod/events.php:89 ../../mod/events.php:98 ../../mod/events.php:116 +msgid "Unable to generate preview." +msgstr "Vorschau konnte nicht erzeugt werden." + +#: ../../mod/events.php:96 +msgid "Event title and start time are required." +msgstr "Titel und Startzeit des Termins sind erforderlich." + +#: ../../mod/events.php:114 +msgid "Event not found." +msgstr "Termin nicht gefunden." + +#: ../../mod/events.php:396 +msgid "l, F j" +msgstr "l, j. F" + +#: ../../mod/events.php:418 +msgid "Edit event" +msgstr "Termin bearbeiten" + +#: ../../mod/events.php:419 +msgid "Delete event" +msgstr "Termin löschen" + +#: ../../mod/events.php:473 +msgid "Create New Event" +msgstr "Neuen Termin erstellen" + +#: ../../mod/events.php:474 ../../mod/photos.php:827 +msgid "Previous" +msgstr "Voriges" + +#: ../../mod/events.php:475 ../../mod/setup.php:265 ../../mod/photos.php:836 +msgid "Next" +msgstr "Nächste" + +#: ../../mod/events.php:476 +msgid "Export" +msgstr "Exportieren" + +#: ../../mod/events.php:504 +msgid "Event removed" +msgstr "Termin gelöscht" + +#: ../../mod/events.php:507 +msgid "Failed to remove event" +msgstr "Termin konnte nicht gelöscht werden" + +#: ../../mod/events.php:625 +msgid "Event details" +msgstr "Termin-Details" + +#: ../../mod/events.php:626 +msgid "Starting date and Title are required." +msgstr "Startdatum und Titel sind erforderlich." + +#: ../../mod/events.php:628 +msgid "Categories (comma-separated list)" +msgstr "Kategorien (Kommagetrennte Liste)" + +#: ../../mod/events.php:630 +msgid "Event Starts:" +msgstr "Termin beginnt:" + +#: ../../mod/events.php:637 +msgid "Finish date/time is not known or not relevant" +msgstr "Ende Datum/Zeit sind unbekannt oder unwichtig" + +#: ../../mod/events.php:639 +msgid "Event Finishes:" +msgstr "Termin endet:" + +#: ../../mod/events.php:641 ../../mod/events.php:642 +msgid "Adjust for viewer timezone" +msgstr "An die Zeitzone des Betrachters anpassen" + +#: ../../mod/events.php:641 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." +msgstr "Wichtig für Veranstaltungen die an bestimmten Orten stattfinden. Nicht sinnvoll für globale Feiertage / Ferien." + +#: ../../mod/events.php:643 +msgid "Description:" +msgstr "Beschreibung:" + +#: ../../mod/events.php:647 +msgid "Title:" +msgstr "Titel:" + +#: ../../mod/events.php:649 +msgid "Share this event" +msgstr "Den Termin teilen" + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "%1$s folgt nun %2$ss %3$s" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "Öffentliche Server" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration into the Red Matrix. All sites in" +" the matrix are interlinked so membership on any of them conveys membership " +"in the matrix as a whole. Some sites may require subscription or provide " +"tiered service plans. The provider links may provide " +"additional details." +msgstr "Die hier aufgeführten Server erlauben Dir, einen Account in der Red-Matrix anzulegen. Alle Server der Matrix sind miteinander verbunden, so dass die Mitgliedschaft auf einem Server eine Verbindung zu beliebigen anderen Servern der Matrix ermöglicht. Es könnte sein, dass einige dieser Server kostenpflichtig sind oder abgestufte, je nach Umfang kostenpflichtige Mitgliedschaften anbieten. Auf den jeweiligen Seiten könnten nähere Details dazu stehen." + +#: ../../mod/pubsites.php:25 +msgid "Rate this hub" +msgstr "Bewerte diesen Hub" + +#: ../../mod/pubsites.php:26 +msgid "Site URL" +msgstr "Server-URL" + +#: ../../mod/pubsites.php:26 +msgid "Access Type" +msgstr "Zugangstyp" + +#: ../../mod/pubsites.php:26 +msgid "Registration Policy" +msgstr "Registrierungsrichtlinien" + +#: ../../mod/pubsites.php:26 ../../mod/profiles.php:454 +msgid "Location" +msgstr "Ort" + +#: ../../mod/pubsites.php:26 +msgid "View hub ratings" +msgstr "Bewertungen dieses Hubs ansehen" + +#: ../../mod/pubsites.php:30 +msgid "Rate" +msgstr "Bewerten" + +#: ../../mod/pubsites.php:31 +msgid "View ratings" +msgstr "Bewertungen ansehen" + +#: ../../mod/settings.php:73 +msgid "Name is required" +msgstr "Name ist erforderlich" + +#: ../../mod/settings.php:77 +msgid "Key and Secret are required" +msgstr "Schlüssel und Geheimnis werden benötigt" + +#: ../../mod/settings.php:120 +msgid "Diaspora Policy Settings updated." +msgstr "Diaspora-Einstellungen aktualisiert." + +#: ../../mod/settings.php:228 +msgid "Passwords do not match. Password unchanged." +msgstr "Kennwörter stimmen nicht überein. Kennwort nicht verändert." + +#: ../../mod/settings.php:232 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Leere Kennwörter sind nicht erlaubt. Kennwort nicht verändert." + +#: ../../mod/settings.php:246 +msgid "Password changed." +msgstr "Kennwort geändert." + +#: ../../mod/settings.php:248 +msgid "Password update failed. Please try again." +msgstr "Kennwortänderung fehlgeschlagen. Bitte versuche es noch einmal." + +#: ../../mod/settings.php:262 +msgid "Not valid email." +msgstr "Keine gültige E-Mail Adresse." + +#: ../../mod/settings.php:265 +msgid "Protected email address. Cannot change to that email." +msgstr "Geschützte E-Mail Adresse. Diese kann nicht verändert werden." + +#: ../../mod/settings.php:274 +msgid "System failure storing new email. Please try again." +msgstr "Systemfehler während des Speicherns der neuen Mail. Bitte versuche es noch einmal." + +#: ../../mod/settings.php:513 +msgid "Settings updated." +msgstr "Einstellungen aktualisiert." + +#: ../../mod/settings.php:582 ../../mod/settings.php:608 +#: ../../mod/settings.php:644 +msgid "Add application" +msgstr "Anwendung hinzufügen" + +#: ../../mod/settings.php:585 +msgid "Name of application" +msgstr "Name der Anwendung" + +#: ../../mod/settings.php:586 ../../mod/settings.php:612 +msgid "Consumer Key" +msgstr "Consumer Key" + +#: ../../mod/settings.php:586 ../../mod/settings.php:587 +msgid "Automatically generated - change if desired. Max length 20" +msgstr "Automatisch erzeugt – ändern, falls erwünscht. Maximale Länge 20" + +#: ../../mod/settings.php:587 ../../mod/settings.php:613 +msgid "Consumer Secret" +msgstr "Consumer Secret" + +#: ../../mod/settings.php:588 ../../mod/settings.php:614 +msgid "Redirect" +msgstr "Umleitung" + +#: ../../mod/settings.php:588 +msgid "" +"Redirect URI - leave blank unless your application specifically requires " +"this" +msgstr "Umleitungs-URl – lasse das leer, solange Deine Anwendung es nicht explizit erfordert" + +#: ../../mod/settings.php:589 ../../mod/settings.php:615 +msgid "Icon url" +msgstr "Symbol-URL" + +#: ../../mod/settings.php:589 +msgid "Optional" +msgstr "Optional" + +#: ../../mod/settings.php:600 +msgid "You can't edit this application." +msgstr "Diese Anwendung kann nicht bearbeitet werden." + +#: ../../mod/settings.php:643 +msgid "Connected Apps" +msgstr "Verbundene Apps" + +#: ../../mod/settings.php:647 +msgid "Client key starts with" +msgstr "Client Key beginnt mit" + +#: ../../mod/settings.php:648 +msgid "No name" +msgstr "Kein Name" + +#: ../../mod/settings.php:649 +msgid "Remove authorization" +msgstr "Authorisierung aufheben" + +#: ../../mod/settings.php:663 +msgid "No feature settings configured" +msgstr "Keine Funktions-Einstellungen konfiguriert" + +#: ../../mod/settings.php:676 +msgid "Feature Settings" +msgstr "Funktions-Einstellungen" + +#: ../../mod/settings.php:679 +msgid "Diaspora Policy Settings" +msgstr "Diaspora-Einstellungen" + +#: ../../mod/settings.php:680 +msgid "Allow any Diaspora member to comment on your public posts." +msgstr "Allen Diaspora-Mitgliedern erlauben, Deine öffentlichen Beiträge zu kommentieren." + +#: ../../mod/settings.php:681 +msgid "Submit Diaspora Policy Settings" +msgstr "Diaspora-Einstellungen speichern" + +#: ../../mod/settings.php:704 +msgid "Account Settings" +msgstr "Konto-Einstellungen" + +#: ../../mod/settings.php:705 +msgid "Password Settings" +msgstr "Kennwort-Einstellungen" + +#: ../../mod/settings.php:706 +msgid "New Password:" +msgstr "Neues Passwort:" + +#: ../../mod/settings.php:707 +msgid "Confirm:" +msgstr "Bestätigen:" + +#: ../../mod/settings.php:707 +msgid "Leave password fields blank unless changing" +msgstr "Lasse die Passwort-Felder leer, außer Du möchtest das Passwort ändern" + +#: ../../mod/settings.php:709 ../../mod/settings.php:1045 +msgid "Email Address:" +msgstr "Email Adresse:" + +#: ../../mod/settings.php:710 ../../mod/removeaccount.php:61 +msgid "Remove Account" +msgstr "Konto entfernen" + +#: ../../mod/settings.php:711 +msgid "Remove this account from this server including all its channels" +msgstr "Lösche dieses Konto einschließlich aller zugehörigen Kanäle von diesem Server" + +#: ../../mod/settings.php:712 ../../mod/settings.php:1126 +msgid "Warning: This action is permanent and cannot be reversed." +msgstr "Achtung: Diese Aktion ist endgültig und kann nicht rückgängig gemacht werden." + +#: ../../mod/settings.php:728 +msgid "Off" +msgstr "Aus" + +#: ../../mod/settings.php:728 +msgid "On" +msgstr "An" + +#: ../../mod/settings.php:735 +msgid "Additional Features" +msgstr "Zusätzliche Funktionen" + +#: ../../mod/settings.php:759 +msgid "Connector Settings" +msgstr "Connector-Einstellungen" + +#: ../../mod/settings.php:798 +msgid "No special theme for mobile devices" +msgstr "Keine spezielle Theme für mobile Geräte" + +#: ../../mod/settings.php:801 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s – (experimentell)" + +#: ../../mod/settings.php:804 ../../mod/admin.php:367 +msgid "mobile" +msgstr "mobil" + +#: ../../mod/settings.php:840 +msgid "Display Settings" +msgstr "Anzeige-Einstellungen" + +#: ../../mod/settings.php:846 +msgid "Display Theme:" +msgstr "Anzeige-Theme:" + +#: ../../mod/settings.php:847 +msgid "Mobile Theme:" +msgstr "Mobile Theme:" + +#: ../../mod/settings.php:848 +msgid "Enable user zoom on mobile devices" +msgstr "Zoom auf Mobilgeräten aktivieren" + +#: ../../mod/settings.php:849 +msgid "Update browser every xx seconds" +msgstr "Browser alle xx Sekunden aktualisieren" + +#: ../../mod/settings.php:849 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Minimum 10 Sekunden, kein Maximum" + +#: ../../mod/settings.php:850 +msgid "Maximum number of conversations to load at any time:" +msgstr "Maximale Anzahl von Unterhaltungen, die auf einmal geladen werden sollen:" + +#: ../../mod/settings.php:850 +msgid "Maximum of 100 items" +msgstr "Maximum: 100 Beiträge" + +#: ../../mod/settings.php:851 +msgid "Don't show emoticons" +msgstr "Emoticons nicht anzeigen" + +#: ../../mod/settings.php:852 +msgid "Link post titles to source" +msgstr "Beitragstitel zum Originalbeitrag verlinken" + +#: ../../mod/settings.php:853 +msgid "System Page Layout Editor - (advanced)" +msgstr "System-Seitenlayout-Editor (für Experten)" + +#: ../../mod/settings.php:856 +msgid "Use blog/list mode on channel page" +msgstr "Blog-/Listenmodus auf der Kanalseite verwenden" + +#: ../../mod/settings.php:856 ../../mod/settings.php:857 +msgid "(comments displayed separately)" +msgstr "(Kommentare werden separat angezeigt)" + +#: ../../mod/settings.php:857 +msgid "Use blog/list mode on matrix page" +msgstr "Blog-/Listenmodus auf der Matrixseite verwenden" + +#: ../../mod/settings.php:858 +msgid "Channel page max height of content (in pixels)" +msgstr "Maximale Höhe von Beitragsblöcken auf der Kanalseite (in Pixeln)" + +#: ../../mod/settings.php:858 ../../mod/settings.php:859 +msgid "click to expand content exceeding this height" +msgstr "Blöcke, deren Inhalt diese Höhe überschreitet, können per Klick vergrößert werden." + +#: ../../mod/settings.php:859 +msgid "Matrix page max height of content (in pixels)" +msgstr "Maximale Höhe von Beitragsblöcken auf der Matrixseite (in Pixeln)" + +#: ../../mod/settings.php:893 +msgid "Nobody except yourself" +msgstr "Niemand außer Dir selbst" + +#: ../../mod/settings.php:894 +msgid "Only those you specifically allow" +msgstr "Nur die, denen Du es explizit erlaubst" + +#: ../../mod/settings.php:895 +msgid "Approved connections" +msgstr "Angenommene Verbindungen" + +#: ../../mod/settings.php:896 +msgid "Any connections" +msgstr "Beliebige Verbindungen" + +#: ../../mod/settings.php:897 +msgid "Anybody on this website" +msgstr "Jeder auf dieser Website" + +#: ../../mod/settings.php:898 +msgid "Anybody in this network" +msgstr "Alle Red-Nutzer" + +#: ../../mod/settings.php:899 +msgid "Anybody authenticated" +msgstr "Jeder authentifizierte" + +#: ../../mod/settings.php:900 +msgid "Anybody on the internet" +msgstr "Jeder im Internet" + +#: ../../mod/settings.php:974 +msgid "Publish your default profile in the network directory" +msgstr "Standard-Profil im Netzwerk-Verzeichnis veröffentlichen" + +#: ../../mod/settings.php:979 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "Dürfen wir Dich neuen Mitgliedern als potentiellen Kontakt vorschlagen?" + +#: ../../mod/settings.php:988 +msgid "Your channel address is" +msgstr "Deine Kanal-Adresse lautet" + +#: ../../mod/settings.php:1036 +msgid "Channel Settings" +msgstr "Kanal-Einstellungen" + +#: ../../mod/settings.php:1043 +msgid "Basic Settings" +msgstr "Grundeinstellungen" + +#: ../../mod/settings.php:1046 +msgid "Your Timezone:" +msgstr "Ihre Zeitzone:" + +#: ../../mod/settings.php:1047 +msgid "Default Post Location:" +msgstr "Standardstandort:" + +#: ../../mod/settings.php:1047 +msgid "Geographical location to display on your posts" +msgstr "Geografischer Ort, der bei Deinen Beiträgen angezeigt werden soll" + +#: ../../mod/settings.php:1048 +msgid "Use Browser Location:" +msgstr "Standort des Browsers verwenden:" + +#: ../../mod/settings.php:1050 +msgid "Adult Content" +msgstr "Nicht jugendfreie Inhalte" + +#: ../../mod/settings.php:1050 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "Dieser Kanal veröffentlicht regelmäßig Inhalte, die für Minderjährige ungeeignet sind. (Bitte markiere solche Inhalte mit dem Schlagwort #NSFW)" + +#: ../../mod/settings.php:1052 +msgid "Security and Privacy Settings" +msgstr "Sicherheits- und Datenschutz-Einstellungen" + +#: ../../mod/settings.php:1054 +msgid "Your permissions are already configured. Click to view/adjust" +msgstr "Deine Zugriffsrechte sind schon konfiguriert. Klicke hier, um sie zu betrachten oder zu ändern" + +#: ../../mod/settings.php:1056 +msgid "Hide my online presence" +msgstr "Meine Online-Präsenz verbergen" + +#: ../../mod/settings.php:1056 +msgid "Prevents displaying in your profile that you are online" +msgstr "Verhindert die Anzeige Deines Online-Status in deinem Profil" + +#: ../../mod/settings.php:1058 +msgid "Simple Privacy Settings:" +msgstr "Einfache Privatsphäre-Einstellungen" + +#: ../../mod/settings.php:1059 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "Komplett offen – extrem ungeschützt (mit großer Vorsicht verwenden!)" + +#: ../../mod/settings.php:1060 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "Typisch – Standard öffentlich, Privatsphäre, wo sie erwünscht ist (ähnlich den Einstellungen in sozialen Netzwerken, aber mit besser geschützter Privatsphäre)" + +#: ../../mod/settings.php:1061 +msgid "Private - default private, never open or public" +msgstr "Privat – Standard privat, nie offen oder öffentlich" + +#: ../../mod/settings.php:1062 +msgid "Blocked - default blocked to/from everybody" +msgstr "Blockiert – Alle standardmäßig blockiert" + +#: ../../mod/settings.php:1064 +msgid "Allow others to tag your posts" +msgstr "Erlaube anderen, Deine Beiträge zu verschlagworten" + +#: ../../mod/settings.php:1064 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "Wird oft von der Community genutzt um rückwirkend anstößigen Inhalt zu markieren" + +#: ../../mod/settings.php:1066 +msgid "Advanced Privacy Settings" +msgstr "Fortgeschrittene Privatsphäre-Einstellungen" + +#: ../../mod/settings.php:1068 +msgid "Expire other channel content after this many days" +msgstr "Den Inhalt anderer Kanäle nach dieser Anzahl Tage verfallen lassen" + +#: ../../mod/settings.php:1068 +msgid "0 or blank prevents expiration" +msgstr "0 oder kein Inhalt verhindern das Verfallen" + +#: ../../mod/settings.php:1069 +msgid "Maximum Friend Requests/Day:" +msgstr "Maximale Kontaktanfragen pro Tag:" + +#: ../../mod/settings.php:1069 +msgid "May reduce spam activity" +msgstr "Kann die Spam-Aktivität verringern" + +#: ../../mod/settings.php:1070 +msgid "Default Post Permissions" +msgstr "Standardeinstellungen für Beitrags-Zugriffsrechte" + +#: ../../mod/settings.php:1071 ../../mod/mitem.php:161 ../../mod/mitem.php:204 +msgid "(click to open/close)" +msgstr "(zum öffnen/schließen anklicken)" + +#: ../../mod/settings.php:1075 +msgid "Channel permissions category:" +msgstr "Zugriffsrechte-Kategorie des Kanals:" + +#: ../../mod/settings.php:1081 +msgid "Maximum private messages per day from unknown people:" +msgstr "Maximale Anzahl privater Nachrichten pro Tag von unbekannten Leuten:" + +#: ../../mod/settings.php:1081 +msgid "Useful to reduce spamming" +msgstr "Nützlich, um Spam zu verringern" + +#: ../../mod/settings.php:1084 +msgid "Notification Settings" +msgstr "Benachrichtigungs-Einstellungen" + +#: ../../mod/settings.php:1085 +msgid "By default post a status message when:" +msgstr "Sende standardmäßig Status-Nachrichten, wenn:" + +#: ../../mod/settings.php:1086 +msgid "accepting a friend request" +msgstr "Du eine Verbindungsanfrage annimmst" + +#: ../../mod/settings.php:1087 +msgid "joining a forum/community" +msgstr "Du einem Forum beitrittst" + +#: ../../mod/settings.php:1088 +msgid "making an interesting profile change" +msgstr "Du eine interessante Änderung an Deinem Profil vornimmst" + +#: ../../mod/settings.php:1089 +msgid "Send a notification email when:" +msgstr "Eine E-Mail-Benachrichtigung senden, wenn:" + +#: ../../mod/settings.php:1090 +msgid "You receive a connection request" +msgstr "Du eine Verbindungsanfrage erhältst" + +#: ../../mod/settings.php:1091 +msgid "Your connections are confirmed" +msgstr "Eine Verbindung bestätigt wurde" + +#: ../../mod/settings.php:1092 +msgid "Someone writes on your profile wall" +msgstr "Jemand auf Deine Pinnwand schreibt" + +#: ../../mod/settings.php:1093 +msgid "Someone writes a followup comment" +msgstr "Jemand einen Beitrag kommentiert" + +#: ../../mod/settings.php:1094 +msgid "You receive a private message" +msgstr "Du eine private Nachricht erhältst" + +#: ../../mod/settings.php:1095 +msgid "You receive a friend suggestion" +msgstr "Du einen Kontaktvorschlag erhältst" + +#: ../../mod/settings.php:1096 +msgid "You are tagged in a post" +msgstr "Du in einem Beitrag erwähnt wurdest" + +#: ../../mod/settings.php:1097 +msgid "You are poked/prodded/etc. in a post" +msgstr "Du in einem Beitrag angestupst/geknufft/o.ä. wurdest" + +#: ../../mod/settings.php:1100 +msgid "Show visual notifications including:" +msgstr "Visuelle Benachrichtigungen anzeigen für:" + +#: ../../mod/settings.php:1102 +msgid "Unseen matrix activity" +msgstr "Ungesehene Matrix-Aktivität" + +#: ../../mod/settings.php:1103 +msgid "Unseen channel activity" +msgstr "Ungesehene Kanal-Aktivität" + +#: ../../mod/settings.php:1104 +msgid "Unseen private messages" +msgstr "Ungelesene persönliche Nachrichten" + +#: ../../mod/settings.php:1104 ../../mod/settings.php:1109 +#: ../../mod/settings.php:1110 ../../mod/settings.php:1111 +msgid "Recommended" +msgstr "Empfohlen" + +#: ../../mod/settings.php:1105 +msgid "Upcoming events" +msgstr "Baldige Termine" + +#: ../../mod/settings.php:1106 +msgid "Events today" +msgstr "Heutige Termine" + +#: ../../mod/settings.php:1107 +msgid "Upcoming birthdays" +msgstr "Baldige Geburtstage" + +#: ../../mod/settings.php:1107 +msgid "Not available in all themes" +msgstr "Nicht in allen Themes verfügbar" + +#: ../../mod/settings.php:1108 +msgid "System (personal) notifications" +msgstr "System – (persönliche) Benachrichtigungen" + +#: ../../mod/settings.php:1109 +msgid "System info messages" +msgstr "System – Info-Nachrichten" + +#: ../../mod/settings.php:1110 +msgid "System critical alerts" +msgstr "System – kritische Warnungen" + +#: ../../mod/settings.php:1111 +msgid "New connections" +msgstr "Neue Verbindungen" + +#: ../../mod/settings.php:1112 +msgid "System Registrations" +msgstr "System – Registrierungen" + +#: ../../mod/settings.php:1113 +msgid "" +"Also show new wall posts, private messages and connections under Notices" +msgstr "Zeigt neue Pinnwand-Nachrichten, private Nachrichten und Verbindungen unter Benachrichtigungen an" + +#: ../../mod/settings.php:1115 +msgid "Notify me of events this many days in advance" +msgstr "Benachrichtige mich zu Terminen so viele Tage im Voraus" + +#: ../../mod/settings.php:1115 +msgid "Must be greater than 0" +msgstr "Muss größer als 0 sein" + +#: ../../mod/settings.php:1117 +msgid "Advanced Account/Page Type Settings" +msgstr "Erweiterte Account- und Seitenart-Einstellungen" + +#: ../../mod/settings.php:1118 +msgid "Change the behaviour of this account for special situations" +msgstr "Ändere das Verhalten dieses Accounts unter speziellen Umständen" + +#: ../../mod/settings.php:1121 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "Aktiviere den Expertenmodus (unter Settings > Zusätzliche Funktionen), um hier Einstellungen vorzunehmen!" + +#: ../../mod/settings.php:1122 +msgid "Miscellaneous Settings" +msgstr "Sonstige Einstellungen" + +#: ../../mod/settings.php:1124 +msgid "Personal menu to display in your channel pages" +msgstr "Eigenes Menü zur Anzeige auf den Seiten deines Kanals" + +#: ../../mod/settings.php:1125 +msgid "Remove this channel" +msgstr "Diesen Kanal löschen" + +#: ../../mod/cloud.php:120 +msgid "RedMatrix - Guests: Username: {your email address}, Password: +++" +msgstr "RedMatrix – Gäste: Username: {Deine E-Mail-Adresse}, Passwort: +++" + +#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94 +msgid "Tag removed" +msgstr "Schlagwort entfernt" + +#: ../../mod/tagrm.php:119 +msgid "Remove Item Tag" +msgstr "Schlagwort entfernen" + +#: ../../mod/tagrm.php:121 +msgid "Select a tag to remove: " +msgstr "Schlagwort zum Entfernen auswählen:" + +#: ../../mod/tagrm.php:133 ../../mod/delegate.php:130 ../../mod/photos.php:873 +msgid "Remove" +msgstr "Entferne" + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "Sammlung erstellt." + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "Sammlung kann nicht erstellt werden." + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "Sammlung aktualisiert." + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "Erstelle eine Sammlung von Kanälen." + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "Name der Sammlung:" + +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "Mitglieder sind sichtbar für andere Kanäle" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "Sammlung gelöscht." + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "Löschen der Sammlung nicht möglich." + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "Sammlung-Editor" + +#: ../../mod/group.php:196 +msgid "Members" +msgstr "Mitglieder" + +#: ../../mod/group.php:198 +msgid "All Connected Channels" +msgstr "Alle verbundenen Kanäle" + +#: ../../mod/group.php:233 +msgid "Click on a channel to add or remove." +msgstr "Wähle einen Kanal zum hinzufügen oder entfernen aus." + +#: ../../mod/siteinfo.php:93 +#, php-format +msgid "Version %s" +msgstr "Version %s" + +#: ../../mod/siteinfo.php:114 +msgid "Installed plugins/addons/apps:" +msgstr "Installierte Plugins/Addons/Apps" + +#: ../../mod/siteinfo.php:127 +msgid "No installed plugins/addons/apps" +msgstr "Keine installierten Plugins/Addons/Apps" + +#: ../../mod/siteinfo.php:136 +msgid "Red" +msgstr "Red" + +#: ../../mod/siteinfo.php:137 +msgid "" +"This is a hub of the Red Matrix - a global cooperative network of " +"decentralized privacy enhanced websites." +msgstr "Dieser Hub ist Teil der RedMatrix – eines globalen, kooperativen Netzwerks aus dezentralen Websites, die Rücksicht auf Deine Privatsphäre nehmen." + +#: ../../mod/siteinfo.php:139 +msgid "Tag: " +msgstr "Schlagwort: " + +#: ../../mod/siteinfo.php:141 +msgid "Last background fetch: " +msgstr "Letzter Hintergrundabruf:" + +#: ../../mod/siteinfo.php:144 +msgid "Running at web location" +msgstr "Erreichbar unter der Web-Adresse" + +#: ../../mod/siteinfo.php:145 +msgid "" +"Please visit RedMatrix.me to learn more" +" about the Red Matrix." +msgstr "Bitte besuchen Sie RedMatrix.me, um mehr über RedMatrix zu erfahren." + +#: ../../mod/siteinfo.php:146 +msgid "Bug reports and issues: please visit" +msgstr "Probleme oder Fehler gefunden? Bitte besuche" + +#: ../../mod/siteinfo.php:149 +msgid "" +"Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot " +"com" +msgstr "Vorschläge, Lob, usw.: E-Mail an 'redmatrix' at librelist - dot - com" + +#: ../../mod/siteinfo.php:151 +msgid "Site Administrators" +msgstr "Administratoren" + +#: ../../mod/help.php:49 ../../mod/help.php:55 ../../mod/help.php:61 +msgid "Help:" +msgstr "Hilfe:" + +#: ../../mod/help.php:76 ../../index.php:238 +msgid "Not Found" +msgstr "Nicht gefunden" + +#: ../../mod/setup.php:166 +msgid "Red Matrix Server - Setup" +msgstr "Red Matrix Server - Installation" + +#: ../../mod/setup.php:172 +msgid "Could not connect to database." +msgstr "Kann nicht mit der Datenbank verbinden." + +#: ../../mod/setup.php:176 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "Konnte die angegebene Webseiten-URL nicht erreichen. Möglicherweise ein Problem mit dem SSL-Zertifikat oder dem DNS." + +#: ../../mod/setup.php:183 +msgid "Could not create table." +msgstr "Kann Tabelle nicht erstellen." + +#: ../../mod/setup.php:189 +msgid "Your site database has been installed." +msgstr "Die Datenbank Deines Hubs wurde installiert." + +#: ../../mod/setup.php:194 +msgid "" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." +msgstr "Möglicherweise musst Du die Datei install/schema_xxx.sql manuell mit Hilfe eines Datenkbank-Clients importieren." + +#: ../../mod/setup.php:195 ../../mod/setup.php:264 ../../mod/setup.php:662 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "Lies die Datei \"install/INSTALL.txt\"." + +#: ../../mod/setup.php:261 +msgid "System check" +msgstr "Systemprüfung" + +#: ../../mod/setup.php:266 +msgid "Check again" +msgstr "Bitte nochmal prüfen" + +#: ../../mod/setup.php:289 +msgid "Database connection" +msgstr "Datenbank Verbindung" + +#: ../../mod/setup.php:290 +msgid "" +"In order to install Red Matrix we need to know how to connect to your " +"database." +msgstr "Um die Red-Matrix installieren zu können, müssen wir wissen, wie wir eine Verbindung zu Deiner Datenbank aufbauen können." + +#: ../../mod/setup.php:291 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Bitte kontaktiere Deinen Hosting-Provider oder Administrator, falls Du Fragen zu diesen Einstellungen hast." + +#: ../../mod/setup.php:292 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "Die Datenbank, die Du weiter unten angibst, sollte bereits existieren. Sollte das noch nicht der Fall sein, erzeuge sie bitte bevor Du fortfährst." + +#: ../../mod/setup.php:296 +msgid "Database Server Name" +msgstr "Datenbank-Servername" + +#: ../../mod/setup.php:296 +msgid "Default is localhost" +msgstr "Standard ist localhost" + +#: ../../mod/setup.php:297 +msgid "Database Port" +msgstr "Datenbank-Port" + +#: ../../mod/setup.php:297 +msgid "Communication port number - use 0 for default" +msgstr "Port-Nummer für die Kommunikation – verwende 0 für die Standardeinstellung" + +#: ../../mod/setup.php:298 +msgid "Database Login Name" +msgstr "Datenbank-Benutzername" + +#: ../../mod/setup.php:299 +msgid "Database Login Password" +msgstr "Datenbank-Kennwort" + +#: ../../mod/setup.php:300 +msgid "Database Name" +msgstr "Datenbank-Name" + +#: ../../mod/setup.php:301 +msgid "Database Type" +msgstr "Datenbanktyp" + +#: ../../mod/setup.php:303 ../../mod/setup.php:347 +msgid "Site administrator email address" +msgstr "E-Mail Adresse des Seiten-Administrators" + +#: ../../mod/setup.php:303 ../../mod/setup.php:347 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "Die E-Mail-Adresse Deines Accounts muss dieser Adresse entsprechen, damit Du Zugriff zur Administrations-Seite erhältst." + +#: ../../mod/setup.php:304 ../../mod/setup.php:349 +msgid "Website URL" +msgstr "Server-URL" + +#: ../../mod/setup.php:304 ../../mod/setup.php:349 +msgid "Please use SSL (https) URL if available." +msgstr "Nutze wenn möglich eine SSL-URL (https)." + +#: ../../mod/setup.php:307 ../../mod/setup.php:352 +msgid "Please select a default timezone for your website" +msgstr "Standard-Zeitzone für Deinen Server" + +#: ../../mod/setup.php:335 +msgid "Site settings" +msgstr "Seiteneinstellungen" + +#: ../../mod/setup.php:395 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Konnte die Kommandozeilen-Version von PHP nicht im PATH des Web-Servers finden." + +#: ../../mod/setup.php:396 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "Ohne Kommandozeilen-Version von PHP auf dem Server wirst Du nicht in der Lage sein, Hintergrundprozesse via cron auszuführen." + +#: ../../mod/setup.php:400 +msgid "PHP executable path" +msgstr "PHP Pfad zu ausführbarer Datei" + +#: ../../mod/setup.php:400 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Gib den vollen Pfad zum PHP-Interpreter an. Du kannst dieses Feld frei lassen und mit der Installation fortfahren." + +#: ../../mod/setup.php:405 +msgid "Command line PHP" +msgstr "PHP Befehlszeile" + +#: ../../mod/setup.php:414 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "Bei der Kommandozeilen-Version von PHP auf Deinem System ist \"register_argc_argv\" nicht aktiviert." + +#: ../../mod/setup.php:415 +msgid "This is required for message delivery to work." +msgstr "Das wird benötigt, damit die Auslieferung von Nachrichten funktioniert." + +#: ../../mod/setup.php:417 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/setup.php:438 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Fehler: Die „openssl_pkey_new“-Funktion auf diesem System ist nicht in der Lage, Schlüssel für die Verschlüsselung zu erzeugen." + +#: ../../mod/setup.php:439 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Wenn Du Windows verwendest, findest Du unter http://www.php.net/manual/en/openssl.installation.php eine Installationsanleitung." + +#: ../../mod/setup.php:441 +msgid "Generate encryption keys" +msgstr "Verschlüsselungsschlüssel generieren" + +#: ../../mod/setup.php:448 +msgid "libCurl PHP module" +msgstr "libCurl-PHP-Modul" + +#: ../../mod/setup.php:449 +msgid "GD graphics PHP module" +msgstr "GD-Grafik-PHP-Modul" + +#: ../../mod/setup.php:450 +msgid "OpenSSL PHP module" +msgstr "OpenSSL-PHP-Modul" + +#: ../../mod/setup.php:451 +msgid "mysqli or postgres PHP module" +msgstr "mysqli oder postgres PHP-Modul" + +#: ../../mod/setup.php:452 +msgid "mb_string PHP module" +msgstr "mb_string-PHP-Modul" + +#: ../../mod/setup.php:453 +msgid "mcrypt PHP module" +msgstr "mcrypt-PHP-Modul" + +#: ../../mod/setup.php:458 ../../mod/setup.php:460 +msgid "Apache mod_rewrite module" +msgstr "Apache-mod_rewrite-Modul" + +#: ../../mod/setup.php:458 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Fehler: Das Apache-Modul mod-rewrite wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:464 ../../mod/setup.php:467 +msgid "proc_open" +msgstr "proc_open" + +#: ../../mod/setup.php:464 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "Fehler: proc_open wird benötigt, ist aber entweder nicht installiert oder wurde in der php.ini deaktiviert" + +#: ../../mod/setup.php:472 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Fehler: Das PHP-Modul libCURL wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:476 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Fehler: Das PHP-Modul GD-Grafik mit JPEG-Unterstützung wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:480 +msgid "Error: openssl PHP module required but not installed." +msgstr "Fehler: Das PHP-Modul openssl wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:484 +msgid "" +"Error: mysqli or postgres PHP module required but neither are installed." +msgstr "Fehler: Das mysqli oder postgres PHP-Modul ist erforderlich, aber keines von beiden ist installiert." + +#: ../../mod/setup.php:488 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Fehler: Das PHP-Modul mb_string wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:492 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "Fehler: Das PHP-Modul mcrypt wird benötigt, ist aber nicht installiert." + +#: ../../mod/setup.php:508 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "Der Installations-Assistent muss in der Lage sein, die Datei \".htconfig.php\" im Stammverzeichnis des Web-Servers anzulegen, ist er aber nicht." + +#: ../../mod/setup.php:509 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Meist liegt das daran, dass der Nutzer, unter dem der Web-Server läuft, keine Schreibrechte in dem Verzeichnis hat – selbst wenn Du selbst das darfst." + +#: ../../mod/setup.php:510 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "Am Schluss dieses Vorgangs wird ein Text generiert, den Du unter dem Dateinamen .htconfig.php im Stammverzeichnis Deiner Red-Installation speichern musst." + +#: ../../mod/setup.php:511 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "Alternativ kannst Du diesen Schritt überspringen und die Installation manuell vornehmen. Lies dazu die Datei install/INSTALL.txt." + +#: ../../mod/setup.php:514 +msgid ".htconfig.php is writable" +msgstr ".htconfig.php ist beschreibbar" + +#: ../../mod/setup.php:524 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "Red verwendet Smarty3 um Vorlagen für die Webdarstellung zu übersetzen. Smarty3 übersetzt diese Vorlagen nach PHP, um die Darstellung zu beschleunigen." + +#: ../../mod/setup.php:525 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "Um diese kompilierten Vorlagen speichern zu können, braucht der Web-Server Schreibzugriff auf das Verzeichnis %s unterhalb des Red-Installationsverzeichnisses." + +#: ../../mod/setup.php:526 ../../mod/setup.php:544 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "Bitte stelle sicher, dass der Nutzer, unter dem der Web-Server läuft (z.B. www-data), Schreibzugriff auf dieses Verzeichnis hat." + +#: ../../mod/setup.php:527 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "Hinweis: Aus Sicherheitsgründen sollte der Web-Server nur auf %s Schreibrechte haben, nicht auf die Template-Dateien (.tpl), die das Verzeichnis enthält." + +#: ../../mod/setup.php:530 +#, php-format +msgid "%s is writable" +msgstr "%s ist beschreibbar" + +#: ../../mod/setup.php:543 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to" +" have write access to the store directory under the Red top level folder" +msgstr "Red benutzt das Verzeichnis store, um hochgeladene Dateien zu speichern. Der Web-Server benötigt Schreibrechte für dieses Verzeichnis direkt unterhalb des Red-Stammverzeichnisses" + +#: ../../mod/setup.php:547 +msgid "store is writable" +msgstr "store ist schreibbar" + +#: ../../mod/setup.php:577 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access" +" to this site." +msgstr "Das SSL-Zertifikat konnte nicht validiert werden. Korrigiere das Zertifikat oder deaktiviere den HTTPS-Zugriff auf diesen Server." + +#: ../../mod/setup.php:578 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "Wenn Du via HTTPS auf Deinen Server zugreifen möchtest, also Verbindungen über den Port 443 möglich sein sollen, ist ein SSL-Zertifikat einer Zertifizierungsstelle (CA) notwendig, das von den Browsern ohne Sicherheitsabfrage akzeptiert wird. Die Verwendung eines selbst signierten Zertifikates ist nicht möglich." + +#: ../../mod/setup.php:579 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "Diese Einschränkung wurde eingebaut, weil Deine öffentlichen Beiträge zum Beispiel Verweise auf Bilder auf Deinem eigenen Hub enthalten können." + +#: ../../mod/setup.php:580 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "Wenn Dein Zertifikat nicht von jedem Browser akzeptiert wird, erhalten die Mitglieder anderer Red-Server (die mit korrekten Zertifikaten ausgestattet sind) Sicherheits-Warnmeldungen, obwohl sie gar nicht direkt auf Deinem Server unterwegs sind (zum Beispiel, wenn ein Bild aus einem Deiner Beiträge angezeigt wird)." + +#: ../../mod/setup.php:581 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "Dies kann Probleme für andere Nutzer (nicht nur auf Deinem eigenen Server) verursachen, so dass wir auf dieser Forderung bestehen müssen." + +#: ../../mod/setup.php:582 +msgid "" +"Providers are available that issue free certificates which are browser-" +"valid." +msgstr "Es gibt einige Zertifizierungsstellen (CAs), bei denen solche Zertifikate kostenlos zu haben sind." + +#: ../../mod/setup.php:584 +msgid "SSL certificate validation" +msgstr "SSL Zertifikatverifizierung" + +#: ../../mod/setup.php:590 +msgid "" +"Url rewrite in .htaccess is not working. Check your server " +"configuration.Test: " +msgstr "Das Umschreiben von URLs (rewrite) per .htaccess funktioniert nicht. Bitte prüfe die Server-Konfiguration. Test:" + +#: ../../mod/setup.php:592 +msgid "Url rewrite is working" +msgstr "Url rewrite funktioniert" + +#: ../../mod/setup.php:602 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "Die Datenbank-Konfigurationsdatei „.htconfig.php“ konnte nicht geschrieben werden. Bitte verwende den unten angegebenen Text, um die Konfigurationsdatei im Stammverzeichnis des Webservers anzulegen." + +#: ../../mod/setup.php:625 +msgid "Errors encountered creating database tables." +msgstr "Fehler beim Anlegen der Datenbank-Tabellen aufgetreten." + +#: ../../mod/setup.php:660 +msgid "

    What next

    " +msgstr "

    Was als Nächstes

    " + +#: ../../mod/setup.php:661 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "WICHTIG: Du musst [manuell] einen Cronjob für den Poller einrichten." + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "Kein Kanal." + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "Gemeinsame Verbindungen" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "Keine gemeinsamen Verbindungen." + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "Keine Vorschläge vorhanden. Wenn das ein neuer Server ist, versuche es in 24 Stunden noch einmal." + +#: ../../mod/connections.php:192 ../../mod/connections.php:293 +msgid "Blocked" +msgstr "Blockiert" + +#: ../../mod/connections.php:197 ../../mod/connections.php:300 +msgid "Ignored" +msgstr "Ignoriert" + +#: ../../mod/connections.php:202 ../../mod/connections.php:314 +msgid "Hidden" +msgstr "Versteckt" + +#: ../../mod/connections.php:207 ../../mod/connections.php:307 +msgid "Archived" +msgstr "Archiviert" + +#: ../../mod/connections.php:231 ../../mod/connections.php:246 +msgid "All" +msgstr "Alle" + +#: ../../mod/connections.php:271 +msgid "Suggest new connections" +msgstr "Neue Verbindungen vorschlagen" + +#: ../../mod/connections.php:274 +msgid "New Connections" +msgstr "Neue Verbindungen" + +#: ../../mod/connections.php:277 +msgid "Show pending (new) connections" +msgstr "Ausstehende (neue) Verbindungsanfragen anzeigen" + +#: ../../mod/connections.php:280 ../../mod/profperm.php:139 +msgid "All Connections" +msgstr "Alle Verbindungen" + +#: ../../mod/connections.php:283 +msgid "Show all connections" +msgstr "Alle Verbindungen anzeigen" + +#: ../../mod/connections.php:286 +msgid "Unblocked" +msgstr "Freigegeben" + +#: ../../mod/connections.php:289 +msgid "Only show unblocked connections" +msgstr "Nur freigegebene Verbindungen anzeigen" + +#: ../../mod/connections.php:296 +msgid "Only show blocked connections" +msgstr "Nur blockierte Verbindungen anzeigen" + +#: ../../mod/connections.php:303 +msgid "Only show ignored connections" +msgstr "Nur ignorierte Verbindungen anzeigen" + +#: ../../mod/connections.php:310 +msgid "Only show archived connections" +msgstr "Nur archivierte Verbindungen anzeigen" + +#: ../../mod/connections.php:317 +msgid "Only show hidden connections" +msgstr "Nur versteckte Verbindungen anzeigen" + +#: ../../mod/connections.php:372 +#, php-format +msgid "%1$s [%2$s]" +msgstr "%1$s [%2$s]" + +#: ../../mod/connections.php:373 +msgid "Edit connection" +msgstr "Verbindung bearbeiten" + +#: ../../mod/connections.php:411 +msgid "Search your connections" +msgstr "Verbindungen durchsuchen" + +#: ../../mod/connections.php:412 +msgid "Finding: " +msgstr "Ergebnisse:" + +#: ../../mod/impel.php:33 +msgid "webpage" +msgstr "Webseite" + +#: ../../mod/impel.php:38 +msgid "block" +msgstr "Block" + +#: ../../mod/impel.php:43 +msgid "layout" +msgstr "Layout" + +#: ../../mod/impel.php:117 +#, php-format +msgid "%s element installed" +msgstr "Element für %s installiert" + +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s hat %2$ss %3$s mit %4$s verschlagwortet" + +#: ../../mod/item.php:165 +msgid "Unable to locate original post." +msgstr "Originalbeitrag nicht gefunden." + +#: ../../mod/item.php:424 +msgid "Empty post discarded." +msgstr "Leeren Beitrag verworfen." + +#: ../../mod/item.php:466 +msgid "Executable content type not permitted to this channel." +msgstr "Ausführbarer Content-Typ ist für diesen Kanal nicht freigegeben." + +#: ../../mod/item.php:865 +msgid "System error. Post not saved." +msgstr "Systemfehler. Beitrag nicht gespeichert." + +#: ../../mod/item.php:1083 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "Du hast die maximale Anzahl von %1$.0f Beiträgen erreicht." + +#: ../../mod/item.php:1089 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "Du hast die maximale Anzahl von %1$.0f Webseiten erreicht." + +#: ../../mod/search.php:13 ../../mod/display.php:9 ../../mod/ratings.php:82 +#: ../../mod/directory.php:22 ../../mod/viewconnections.php:17 +#: ../../mod/photos.php:429 +msgid "Public access denied." +msgstr "Öffentlicher Zugang verweigert." + +#: ../../mod/thing.php:96 +msgid "Thing updated" +msgstr "Sache aktualisiert" + +#: ../../mod/thing.php:156 +msgid "Object store: failed" +msgstr "Speichern des Objekts fehlgeschlagen" + +#: ../../mod/thing.php:160 +msgid "Thing added" +msgstr "Sache hinzugefügt" + +#: ../../mod/thing.php:180 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "OBJ: %1$s %2$s %3$s" + +#: ../../mod/thing.php:232 +msgid "Show Thing" +msgstr "Sache anzeigen" + +#: ../../mod/thing.php:239 +msgid "item not found." +msgstr "Eintrag nicht gefunden" + +#: ../../mod/thing.php:270 +msgid "Edit Thing" +msgstr "Sache bearbeiten" + +#: ../../mod/thing.php:272 ../../mod/thing.php:319 +msgid "Select a profile" +msgstr "Wähle ein Profil" + +#: ../../mod/thing.php:276 ../../mod/thing.php:322 +msgid "Post an activity" +msgstr "Aktivitätsnachricht senden" + +#: ../../mod/thing.php:276 ../../mod/thing.php:322 +msgid "Only sends to viewers of the applicable profile" +msgstr "Nur an Betrachter des ausgewählten Profils senden" + +#: ../../mod/thing.php:278 ../../mod/thing.php:324 +msgid "Name of thing e.g. something" +msgstr "Name der Sache, z. B. irgendwas" + +#: ../../mod/thing.php:280 ../../mod/thing.php:325 +msgid "URL of thing (optional)" +msgstr "URL der Sache (optional)" + +#: ../../mod/thing.php:282 ../../mod/thing.php:326 +msgid "URL for photo of thing (optional)" +msgstr "URL eines Fotos der Sache (optional)" + +#: ../../mod/thing.php:317 +msgid "Add Thing to your Profile" +msgstr "Die Sache Deinem Profil hinzufügen" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "Abwesend" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "Online" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "Kanal hinzugefügt." + +#: ../../mod/notify.php:53 ../../mod/notifications.php:94 +msgid "No more system notifications." +msgstr "Keine System-Benachrichtigungen mehr." + +#: ../../mod/notify.php:57 ../../mod/notifications.php:98 +msgid "System Notifications" +msgstr "System-Benachrichtigungen" + +#: ../../mod/acl.php:231 +msgid "network" +msgstr "Netzwerk" + +#: ../../mod/acl.php:241 +msgid "RSS" +msgstr "RSS" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "Layout aktualisiert." + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "Systemseitenbeschreibung bearbeiten" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "Layout nicht gefunden." + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "Modulname:" + +#: ../../mod/pdledit.php:55 ../../mod/layouts.php:107 +msgid "Layout Help" +msgstr "Layout-Hilfe" + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "App installiert." + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "Fehlerhafte App." + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "Code einbetten" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "App bearbeiten" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "App erstellen" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "Name der App" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "Ort (URL) der App" + +#: ../../mod/appman.php:93 ../../mod/rbmark.php:95 +msgid "Description" +msgstr "Beschreibung" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "URL zum Icon" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "80 x 80 Pixel – optional" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "Versions-ID" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "Preis der App" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "Ort (URL), um die App zu kaufen" + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "– auswählen –" + +#: ../../mod/import.php:25 +#, php-format +msgid "Your service plan only allows %d channels." +msgstr "Dein Vertrag erlaubt nur %d Kanäle." + +#: ../../mod/import.php:51 +msgid "Nothing to import." +msgstr "Nichts zu importieren." + +#: ../../mod/import.php:75 +msgid "Unable to download data from old server" +msgstr "Daten können vom alten Server nicht heruntergeladen werden" + +#: ../../mod/import.php:81 +msgid "Imported file is empty." +msgstr "Die importierte Datei ist leer." + +#: ../../mod/import.php:106 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "Kann keinen doppelten Kanal-Identifikator auf diesem System erzeugen (Spitzname oder Hash schon belegt). Import fehlgeschlagen." + +#: ../../mod/import.php:127 +msgid "Unable to create a unique channel address. Import failed." +msgstr "Es war nicht möglich, eine eindeutige Kanal-Adresse zu erzeugen. Der Import ist fehlgeschlagen." + +#: ../../mod/import.php:147 +msgid "Channel clone failed. Import failed." +msgstr "Klonen des Kanals fehlgeschlagen. Import fehlgeschlagen." + +#: ../../mod/import.php:157 +msgid "Cloned channel not found. Import failed." +msgstr "Geklonter Kanal nicht gefunden. Import fehlgeschlagen." + +#: ../../mod/import.php:475 +msgid "Import completed." +msgstr "Import abgeschlossen." + +#: ../../mod/import.php:487 +msgid "You must be logged in to use this feature." +msgstr "Du musst angemeldet sein um diese Funktion zu nutzen." + +#: ../../mod/import.php:492 +msgid "Import Channel" +msgstr "Kanal importieren" + +#: ../../mod/import.php:493 +msgid "" +"Use this form to import an existing channel from a different server/hub. You" +" may retrieve the channel identity from the old server/hub via the network " +"or provide an export file. Only identity and connections/relationships will " +"be imported. Importation of content is not yet available." +msgstr "Verwende dieses Formular, um einen existierenden Kanal von einem anderen Red-Server zu importieren. Du kannst den Kanal direkt vom bisherigen Red-Server über das Netzwerk importieren oder eine exportierte Sicherheitskopie benutzen. Es werden ausschließlich die Identität und die Verbindungen/Beziehungen importiert. Das Importieren von Inhalten ist derzeit nicht möglich." + +#: ../../mod/import.php:494 +msgid "File to Upload" +msgstr "Hochzuladende Datei:" + +#: ../../mod/import.php:495 +msgid "Or provide the old server/hub details" +msgstr "Oder gib die Details Deines bisherigen Red-Servers ein" + +#: ../../mod/import.php:496 +msgid "Your old identity address (xyz@example.com)" +msgstr "Bisherige Kanal-Adresse (xyz@example.com)" + +#: ../../mod/import.php:497 +msgid "Your old login email address" +msgstr "Deine alte Login-E-Mail-Adresse" + +#: ../../mod/import.php:498 +msgid "Your old login password" +msgstr "Dein altes Passwort" + +#: ../../mod/import.php:499 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be" +" able to post from either location, but only one can be marked as the " +"primary location for files, photos, and media." +msgstr "Egal, welche Option Du wählst – bitte lege fest, ob dieser Server die neue primäre Adresse dieses Kanals sein soll, oder ob der bisherige Red-Server diese Rolle weiterhin wahrnimmt. Du kannst von beiden Servern aus posten, aber nur einer kann der primäre Ort Deiner Dateien, Fotos und Medien sein." + +#: ../../mod/import.php:500 +msgid "Make this hub my primary location" +msgstr "Dieser Red-Server ist mein primärer Server." + +#: ../../mod/import.php:501 +msgid "Import existing posts if possible" +msgstr "Existierende Beiträge importieren, falls möglich" + +#: ../../mod/editlayout.php:108 +msgid "Edit Layout" +msgstr "Layout bearbeiten" + +#: ../../mod/editlayout.php:117 +msgid "Delete layout?" +msgstr "Layout löschen?" + +#: ../../mod/editlayout.php:178 +msgid "Delete Layout" +msgstr "Layout löschen" + +#: ../../mod/chat.php:19 ../../mod/channel.php:25 +msgid "You must be logged in to see this page." +msgstr "Du musst angemeldet sein, um diese Seite betrachten zu können." + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "Chatraum nicht gefunden" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "Raum verlassen" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "Diesen Raum löschen" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "Ich bin gerade nicht da" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "Ich bin online" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "Lesezeichen für diesen Raum setzen" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "Neuer Chatraum" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "Name des Chatraums" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "%1$ss Chaträume" + +#: ../../mod/editwebpage.php:140 +msgid "Edit Webpage" +msgstr "Webseite bearbeiten" + +#: ../../mod/editwebpage.php:150 +msgid "Delete webpage?" +msgstr "Webseite löschen?" + +#: ../../mod/editwebpage.php:215 +msgid "Delete Webpage" +msgstr "Webseite löschen" + +#: ../../mod/dirsearch.php:20 ../../mod/regdir.php:22 +msgid "This site is not a directory server" +msgstr "Diese Website ist kein Verzeichnis-Server" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "Kein gültiges Konto gefunden." + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "Zurücksetzen des Passworts eingeleitet. Schau in Deine E-Mails." + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "Nutzer (%s)" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "Passwort-Rücksetzung auf %s angefordert" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "Die Anfrage konnte nicht verifiziert werden. (Vielleicht hast Du schon einmal auf den Link in der E-Mail geklickt?) Passwort-Rücksetzung fehlgeschlagen." + +#: ../../mod/lostpass.php:85 ../../boot.php:1560 +msgid "Password Reset" +msgstr "Zurücksetzen des Kennworts" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "Dein Passwort wurde wie angefordert neu erstellt." + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "Dein neues Passwort lautet" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "Speichere oder kopiere Dein neues Passwort – und dann" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "Klicke hier, um dich anzumelden" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Dein Passwort kann unter Einstellungen nach einer erfolgreichen Anmeldung geändert werden." + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "Auf %s wurde Dein Passwort geändert" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "Kennwort vergessen?" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Gib Deine E-Mail-Adresse ein, um Dein Passwort zurücksetzen zu lassen. Du erhältst dann weitere Anweisungen per E-Mail." + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "E-Mail Adresse" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "Zurücksetzen" + +#: ../../mod/rate.php:157 +msgid "Website:" +msgstr "Webseite:" + +#: ../../mod/rate.php:160 +#, php-format +msgid "Remote Channel [%s] (not yet known on this site)" +msgstr "Kanal [%s] (auf diesem Server noch unbekannt)" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "Einladungslimit überschritten." + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s : Keine gültige Email Adresse." + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "Schließe Dich uns an und werde Teil der Red-Matrix" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Einladungslimit überschritten. Bitte kontaktiere den Administrator Deines Red-Servers." + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : Nachricht konnte nicht zugestellt werden." + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d Nachricht gesendet." +msgstr[1] "%d Nachrichten gesendet." + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "Du hast keine weiteren verfügbare Einladungen" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "Einladungen senden" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "Email-Adressen eintragen, eine pro Zeile:" + +#: ../../mod/invite.php:131 ../../mod/mail.php:235 ../../mod/mail.php:348 +msgid "Your message:" +msgstr "Deine Nachricht:" + +#: ../../mod/invite.php:132 +msgid "Please join my community on RedMatrix." +msgstr "Schließe Dich uns in der RedMatrix an!" + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "Gib folgenden Einladungs-Code ein:" + +#: ../../mod/invite.php:135 +msgid "1. Register at any RedMatrix location (they are all inter-connected)" +msgstr "1. Registriere Dich auf irgendeinem RedMatrix-Server (sie sind alle miteinander verbunden)" + +#: ../../mod/invite.php:137 +msgid "2. Enter my RedMatrix network address into the site searchbar." +msgstr "2. Gib meine RedMatrix-Adresse im Suchfeld ein." + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "oder besuche" + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "3. Klicke auf [Verbinden]" + +#: ../../mod/locs.php:21 ../../mod/locs.php:52 +msgid "Location not found." +msgstr "Klon nicht gefunden." + +#: ../../mod/locs.php:56 +msgid "Primary location cannot be removed." +msgstr "Der primäre Klon kann nicht gelöscht werden." + +#: ../../mod/locs.php:88 +msgid "No locations found." +msgstr "Keine Klon-Adressen gefunden." + +#: ../../mod/locs.php:101 +msgid "Manage Channel Locations" +msgstr "Klon-Adressen verwalten" + +#: ../../mod/locs.php:102 +msgid "Location (address)" +msgstr "URL (Adresse)" + +#: ../../mod/locs.php:103 +msgid "Primary Location" +msgstr "Primärer Klon" + +#: ../../mod/locs.php:104 +msgid "Drop location" +msgstr "Klon löschen" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "Konnte die Quelle nicht anlegen. Kein Kanal ausgewählt." + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "Quelle erstellt." + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "Quelle aktualisiert." + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "*" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "Externe Inhaltsquellen für Deinen Kanal verwalten." + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "Neue Quelle" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "Importiere alle oder ausgewählte Inhalte des folgenden Kanals in diesen Kanal und verteile sie gemäß der Einstellungen dieses Kanals." + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "Importiere nur Beiträge, die folgende Wörter (eines pro Zeile) enthalten" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "Leer lassen, um alle öffentlichen Beiträge zu importieren" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:112 +msgid "Channel Name" +msgstr "Name des Kanals" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "Quelle nicht gefunden." + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "Quelle bearbeiten" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "Quelle löschen" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "Quelle gelöscht" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "Konnte die Quelle nicht löschen." + +#: ../../mod/menu.php:31 +msgid "Menu updated." +msgstr "Menü aktualisiert." + +#: ../../mod/menu.php:35 +msgid "Unable to update menu." +msgstr "Kann Menü nicht aktualisieren." + +#: ../../mod/menu.php:40 +msgid "Menu created." +msgstr "Menü erstellt." + +#: ../../mod/menu.php:44 +msgid "Unable to create menu." +msgstr "Kann Menü nicht erstellen." + +#: ../../mod/menu.php:76 +msgid "Manage Menus" +msgstr "Menüs verwalten" + +#: ../../mod/menu.php:79 +msgid "Drop" +msgstr "Löschen" + +#: ../../mod/menu.php:81 +msgid "Bookmarks allowed" +msgstr "Lesezeichen erlaubt" + +#: ../../mod/menu.php:82 +msgid "Create a new menu" +msgstr "Neues Menü erstellen" + +#: ../../mod/menu.php:83 +msgid "Delete this menu" +msgstr "Lösche dieses Menü" + +#: ../../mod/menu.php:84 ../../mod/menu.php:125 +msgid "Edit menu contents" +msgstr "Bearbeite Menü Inhalte" + +#: ../../mod/menu.php:85 +msgid "Edit this menu" +msgstr "Dieses Menü bearbeiten" + +#: ../../mod/menu.php:96 +msgid "New Menu" +msgstr "Neues Menü" + +#: ../../mod/menu.php:97 ../../mod/menu.php:126 +msgid "Menu name" +msgstr "Menü Name" + +#: ../../mod/menu.php:97 ../../mod/menu.php:126 +msgid "Must be unique, only seen by you" +msgstr "Muss eindeutig sein, ist aber nur für Dich sichtbar" + +#: ../../mod/menu.php:98 ../../mod/menu.php:127 +msgid "Menu title" +msgstr "Menü Titel" + +#: ../../mod/menu.php:98 ../../mod/menu.php:127 +msgid "Menu title as seen by others" +msgstr "Menü Titel wie er von anderen gesehen wird" + +#: ../../mod/menu.php:99 ../../mod/menu.php:128 +msgid "Allow bookmarks" +msgstr "Erlaube Lesezeichen" + +#: ../../mod/menu.php:99 ../../mod/menu.php:128 +msgid "Menu may be used to store saved bookmarks" +msgstr "Im Menü können gespeicherte Lesezeichen abgelegt werden" + +#: ../../mod/menu.php:108 ../../mod/mitem.php:24 +msgid "Menu not found." +msgstr "Menü nicht gefunden" + +#: ../../mod/menu.php:114 +msgid "Menu deleted." +msgstr "Menü gelöscht." + +#: ../../mod/menu.php:116 +msgid "Menu could not be deleted." +msgstr "Menü konnte nicht gelöscht werden." + +#: ../../mod/menu.php:122 +msgid "Edit Menu" +msgstr "Menü bearbeiten" + +#: ../../mod/menu.php:124 +msgid "Add or remove entries to this menu" +msgstr "Einträge zu diesem Menü hinzufügen oder entfernen" + +#: ../../mod/menu.php:130 ../../mod/mitem.php:213 +msgid "Modify" +msgstr "Ändern" + +#: ../../mod/filestorage.php:81 +msgid "Permission Denied." +msgstr "Zugriff verweigert." + +#: ../../mod/filestorage.php:97 +msgid "File not found." +msgstr "Datei nicht gefunden." + +#: ../../mod/filestorage.php:140 +msgid "Edit file permissions" +msgstr "Dateiberechtigungen bearbeiten" + +#: ../../mod/filestorage.php:149 +msgid "Set/edit permissions" +msgstr "Berechtigungen setzen/ändern" + +#: ../../mod/filestorage.php:150 +msgid "Include all files and sub folders" +msgstr "Alle Dateien und Unterverzeichnisse einbinden" + +#: ../../mod/filestorage.php:151 +msgid "Return to file list" +msgstr "Zurück zur Dateiliste" + +#: ../../mod/filestorage.php:153 +msgid "Copy/paste this code to attach file to a post" +msgstr "Diesen Code kopieren und einfügen, um die Datei an einen Beitrag anzuhängen" + +#: ../../mod/filestorage.php:154 +msgid "Copy/paste this URL to link file from a web page" +msgstr "Diese URL verwenden, um von einer Webseite aus auf die Datei zu verlinken" + +#: ../../mod/filestorage.php:156 +msgid "Attach this file to a new post" +msgstr "Diese Datei an einen neuen Beitrag anhängen" + +#: ../../mod/filestorage.php:157 +msgid "Show URL to this file" +msgstr "URL zu dieser Datei anzeigen" + +#: ../../mod/filestorage.php:158 +msgid "Do not show in shared with me folder of your connections" +msgstr "Nicht im Ordner „Dateien, die mit mir geteilt wurden“ meiner Verbindungen anzeigen" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "Kontakt nicht gefunden" + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Freundschaftsempfehlung senden." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Kontakte vorschlagen" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Schlage %s einen Kontakt vor" + +#: ../../mod/magic.php:70 +msgid "Hub not found." +msgstr "Server nicht gefunden." + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "Anstupsen/Knuffen" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "Stupse Leute an oder mache anderes mit ihnen" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "Empfänger" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "Wähle, was Du mit dem/r Empfänger/in tun willst" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "Diesen Beitrag privat machen" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "Ungültiger Profil-Identifikator" + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "Profil-Sichtbarkeits-Editor" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "Klicke auf einen Kontakt, um ihn hinzuzufügen oder zu entfernen." + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "Sichtbar für" + +#: ../../mod/lockview.php:31 +msgid "Remote privacy information not available." +msgstr "Privatsphäre-Einstellungen anderer Nutzer sind nicht verfügbar." + +#: ../../mod/lockview.php:52 +msgid "Visible to:" +msgstr "Sichtbar für:" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:174 +#: ../../mod/profiles.php:231 ../../mod/profiles.php:600 +msgid "Profile not found." +msgstr "Profil nicht gefunden." + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "Profil gelöscht." + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "Profil-" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "Neues Profil erstellt." + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "Profil kann nicht geklont werden." + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "Dieses Profil kann nicht exportiert werden." + +#: ../../mod/profiles.php:241 +msgid "Profile Name is required." +msgstr "Profil-Name erforderlich." + +#: ../../mod/profiles.php:404 +msgid "Marital Status" +msgstr "Familienstand" + +#: ../../mod/profiles.php:408 +msgid "Romantic Partner" +msgstr "Romantische Partner" + +#: ../../mod/profiles.php:412 +msgid "Likes" +msgstr "Gefällt" + +#: ../../mod/profiles.php:416 +msgid "Dislikes" +msgstr "Gefällt nicht" + +#: ../../mod/profiles.php:420 +msgid "Work/Employment" +msgstr "Arbeit/Anstellung" + +#: ../../mod/profiles.php:423 +msgid "Religion" +msgstr "Religion" + +#: ../../mod/profiles.php:427 +msgid "Political Views" +msgstr "Politische Ansichten" + +#: ../../mod/profiles.php:431 +msgid "Gender" +msgstr "Geschlecht" + +#: ../../mod/profiles.php:435 +msgid "Sexual Preference" +msgstr "Sexuelle Orientierung" + +#: ../../mod/profiles.php:439 +msgid "Homepage" +msgstr "Webseite" + +#: ../../mod/profiles.php:443 +msgid "Interests" +msgstr "Hobbys/Interessen" + +#: ../../mod/profiles.php:447 ../../mod/admin.php:871 +msgid "Address" +msgstr "Adresse" + +#: ../../mod/profiles.php:537 +msgid "Profile updated." +msgstr "Profil aktualisiert." + +#: ../../mod/profiles.php:626 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "Deine Kontaktliste vor Betrachtern dieses Profils verbergen?" + +#: ../../mod/profiles.php:666 +msgid "Edit Profile Details" +msgstr "Bearbeite Profil-Details" + +#: ../../mod/profiles.php:668 +msgid "View this profile" +msgstr "Dieses Profil ansehen" + +#: ../../mod/profiles.php:670 +msgid "Change Profile Photo" +msgstr "Profilfoto ändern" + +#: ../../mod/profiles.php:671 +msgid "Create a new profile using these settings" +msgstr "Neues Profil anlegen und diese Einstellungen übernehmen" + +#: ../../mod/profiles.php:672 +msgid "Clone this profile" +msgstr "Dieses Profil klonen" + +#: ../../mod/profiles.php:673 +msgid "Delete this profile" +msgstr "Dieses Profil löschen" + +#: ../../mod/profiles.php:675 +msgid "Import profile from file" +msgstr "Profil aus einer Datei importieren" + +#: ../../mod/profiles.php:676 +msgid "Export profile to file" +msgstr "Profil in eine Datei exportieren" + +#: ../../mod/profiles.php:677 +msgid "Profile Name:" +msgstr "Profilname:" + +#: ../../mod/profiles.php:678 +msgid "Your Full Name:" +msgstr "Dein voller Name:" + +#: ../../mod/profiles.php:679 +msgid "Title/Description:" +msgstr "Titel/Beschreibung:" + +#: ../../mod/profiles.php:680 +msgid "Your Gender:" +msgstr "Dein Geschlecht:" + +#: ../../mod/profiles.php:681 +msgid "Birthday :" +msgstr "Geburtstag:" + +#: ../../mod/profiles.php:682 +msgid "Street Address:" +msgstr "Straße und Hausnummer:" + +#: ../../mod/profiles.php:683 +msgid "Locality/City:" +msgstr "Wohnort:" + +#: ../../mod/profiles.php:684 +msgid "Postal/Zip Code:" +msgstr "Postleitzahl:" + +#: ../../mod/profiles.php:685 +msgid "Country:" +msgstr "Land:" + +#: ../../mod/profiles.php:686 +msgid "Region/State:" +msgstr "Region/Bundesstaat:" + +#: ../../mod/profiles.php:687 +msgid " Marital Status:" +msgstr " Beziehungsstatus:" + +#: ../../mod/profiles.php:688 +msgid "Who: (if applicable)" +msgstr "Wer: (falls anwendbar)" + +#: ../../mod/profiles.php:689 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Beispiele: cathy123, Cathy Williams, cathy@example.com" + +#: ../../mod/profiles.php:690 +msgid "Since [date]:" +msgstr "Seit [Datum]:" + +#: ../../mod/profiles.php:692 +msgid "Homepage URL:" +msgstr "Homepage URL:" + +#: ../../mod/profiles.php:695 +msgid "Religious Views:" +msgstr "Religiöse Ansichten:" + +#: ../../mod/profiles.php:696 +msgid "Keywords:" +msgstr "Schlüsselwörter:" + +#: ../../mod/profiles.php:699 +msgid "Example: fishing photography software" +msgstr "Beispiel: Angeln Fotografie Software" + +#: ../../mod/profiles.php:700 +msgid "Used in directory listings" +msgstr "Wird in Verzeichnis-Auflistungen verwendet" + +#: ../../mod/profiles.php:701 +msgid "Tell us about yourself..." +msgstr "Erzähle uns ein wenig von Dir …" + +#: ../../mod/profiles.php:702 +msgid "Hobbies/Interests" +msgstr "Hobbys/Interessen" + +#: ../../mod/profiles.php:703 +msgid "Contact information and Social Networks" +msgstr "Kontaktinformation und soziale Netzwerke" + +#: ../../mod/profiles.php:704 +msgid "My other channels" +msgstr "Meine anderen Kanäle" + +#: ../../mod/profiles.php:705 +msgid "Musical interests" +msgstr "Musikalische Interessen" + +#: ../../mod/profiles.php:706 +msgid "Books, literature" +msgstr "Bücher, Literatur" + +#: ../../mod/profiles.php:707 +msgid "Television" +msgstr "Fernsehen" + +#: ../../mod/profiles.php:708 +msgid "Film/dance/culture/entertainment" +msgstr "Film/Tanz/Kultur/Unterhaltung" + +#: ../../mod/profiles.php:709 +msgid "Love/romance" +msgstr "Liebe/Romantik" + +#: ../../mod/profiles.php:710 +msgid "Work/employment" +msgstr "Arbeit/Anstellung" + +#: ../../mod/profiles.php:711 +msgid "School/education" +msgstr "Schule/Ausbildung" + +#: ../../mod/profiles.php:717 +msgid "This is your default profile." +msgstr "Das ist Dein Standardprofil." + +#: ../../mod/profiles.php:728 ../../mod/directory.php:188 +msgid "Age: " +msgstr "Alter:" + +#: ../../mod/profiles.php:771 +msgid "Edit/Manage Profiles" +msgstr "Profile bearbeiten/verwalten" + +#: ../../mod/profiles.php:772 +msgid "Add profile things" +msgstr "Sachen zum Profil hinzufügen" + +#: ../../mod/profiles.php:773 +msgid "Include desirable objects in your profile" +msgstr "Binde begehrenswerte Dinge in Dein Profil ein" + +#: ../../mod/ratings.php:69 +msgid "No ratings" +msgstr "Keine Bewertungen" + +#: ../../mod/ratings.php:99 +msgid "Ratings" +msgstr "Bewertungen" + +#: ../../mod/ratings.php:100 +msgid "Rating: " +msgstr "Bewertung: " + +#: ../../mod/ratings.php:101 +msgid "Website: " +msgstr "Webseite: " + +#: ../../mod/ratings.php:103 +msgid "Description: " +msgstr "Beschreibung: " + +#: ../../mod/delegate.php:95 +msgid "No potential page delegates located." +msgstr "Keine potentiellen Bevollmächtigten für die Seite gefunden." + +#: ../../mod/delegate.php:121 +msgid "Delegate Page Management" +msgstr "Delegiere das Management für diese Seite" + +#: ../../mod/delegate.php:123 +msgid "" +"Delegates are able to manage all aspects of this account/page except for " +"basic account settings. Please do not delegate your personal account to " +"anybody that you do not trust completely." +msgstr "Bevollmächtigte sind in der Lage, alle Aspekte dieses Kontos/dieser Seite zu verwalten, abgesehen von den Grundeinstellungen des Kontos. Gib niemandem eine Bevollmächtigung für Deinen privaten Account, dem Du nicht absolut vertraust!" + +#: ../../mod/delegate.php:124 +msgid "Existing Page Managers" +msgstr "Vorhandene Seitenmanager" + +#: ../../mod/delegate.php:126 +msgid "Existing Page Delegates" +msgstr "Vorhandene Bevollmächtigte für die Seite" + +#: ../../mod/delegate.php:128 +msgid "Potential Delegates" +msgstr "Potentielle Bevollmächtigte" + +#: ../../mod/delegate.php:131 +msgid "Add" +msgstr "Hinzufügen" + +#: ../../mod/delegate.php:132 +msgid "No entries." +msgstr "Keine Einträge." + +#: ../../mod/directory.php:194 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "%d Bewertung" +msgstr[1] "%d Bewertungen" + +#: ../../mod/directory.php:206 +msgid "Gender: " +msgstr "Geschlecht:" + +#: ../../mod/directory.php:208 +msgid "Status: " +msgstr "Status:" + +#: ../../mod/directory.php:210 +msgid "Homepage: " +msgstr "Webseite:" + +#: ../../mod/directory.php:213 +msgid "Hometown: " +msgstr "Wohnort:" + +#: ../../mod/directory.php:215 +msgid "About: " +msgstr "Ãœber:" + +#: ../../mod/directory.php:273 +msgid "Public Forum:" +msgstr "Öffentliches Forum:" + +#: ../../mod/directory.php:276 +msgid "Keywords: " +msgstr "Schlüsselwörter:" + +#: ../../mod/directory.php:331 +msgid "Finding:" +msgstr "Ergebnisse:" + +#: ../../mod/directory.php:336 +msgid "next page" +msgstr "nächste Seite" + +#: ../../mod/directory.php:336 +msgid "previous page" +msgstr "vorherige Seite" + +#: ../../mod/directory.php:353 +msgid "No entries (some entries may be hidden)." +msgstr "Keine Einträge gefunden (einige könnten versteckt sein)." + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "Lesezeichenordner wählen" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "Lesezeichen speichern" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "URL des Lesezeichens" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "Oder gib einen neuen Namen für den Lesezeichenordner ein" + +#: ../../mod/uexport.php:33 ../../mod/uexport.php:34 +msgid "Export Channel" +msgstr "Kanal exportieren" + +#: ../../mod/uexport.php:35 +msgid "" +"Export your basic channel information to a small file. This acts as a " +"backup of your connections, permissions, profile and basic data, which can " +"be used to import your data to a new hub, but\tdoes not contain your " +"content." +msgstr "Exportiert die grundlegenden Kanal-Informationen in eine kleine Datei. Diese stellt eine Sicherung Deiner Verbindungen, Berechtigungen, Profile und Basisdaten bereit, die für den Import auf einem anderen Hub verwendet werden kann, aber nicht die Beiträge Deines Kanals enthält." + +#: ../../mod/uexport.php:36 +msgid "Export Content" +msgstr "Kanal und Inhalte exportieren" + +#: ../../mod/uexport.php:37 +msgid "" +"Export your channel information and all the content to a JSON backup. This " +"backs up all of your connections, permissions, profile data and all of your " +"content, but is generally not suitable for importing a channel to a new hub " +"as this file may be VERY large. Please be patient - it may take several " +"minutes for this download to begin." +msgstr "Exportiert Deine Kanal-Informationen sowie alle zugehörigen Inhalte in eine JSON-Sicherungsdatei. Die sichert alle Verbindungen, Berechtigungen, Profildaten und Inhalte Deines Kanals, ist aber nicht unbedingt für den Import eines Kanals auf einem anderen Hub geeignet, da die Datei SEHR groß werden kann. Bitte habe ein wenig Geduld – es kann mehrere Minuten dauern, bis der Download startet." + +#: ../../mod/viewconnections.php:58 +msgid "No connections." +msgstr "Keine Verbindungen." + +#: ../../mod/viewconnections.php:71 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "%ss Profil [%s] besuchen" + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "Ungültige Signatur des Ziels" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "Theme-Einstellungen aktualisiert." + +#: ../../mod/admin.php:97 ../../mod/admin.php:415 +msgid "Site" +msgstr "Seite" + +#: ../../mod/admin.php:98 +msgid "Accounts" +msgstr "Konten" + +#: ../../mod/admin.php:99 ../../mod/admin.php:863 +msgid "Channels" +msgstr "Kanäle" + +#: ../../mod/admin.php:100 ../../mod/admin.php:954 ../../mod/admin.php:996 +msgid "Plugins" +msgstr "Plug-Ins" + +#: ../../mod/admin.php:101 ../../mod/admin.php:1159 ../../mod/admin.php:1195 +msgid "Themes" +msgstr "Themes" + +#: ../../mod/admin.php:102 ../../mod/admin.php:517 +msgid "Server" +msgstr "Server" + +#: ../../mod/admin.php:103 +msgid "Profile Config" +msgstr "Profilkonfiguration" + +#: ../../mod/admin.php:104 +msgid "DB updates" +msgstr "DB-Aktualisierungen" + +#: ../../mod/admin.php:118 ../../mod/admin.php:125 ../../mod/admin.php:1282 +msgid "Logs" +msgstr "Protokolle" + +#: ../../mod/admin.php:124 +msgid "Plugin Features" +msgstr "Plug-In Funktionen" + +#: ../../mod/admin.php:126 +msgid "User registrations waiting for confirmation" +msgstr "Nutzer-Anmeldungen, die auf Bestätigung warten" + +#: ../../mod/admin.php:206 +msgid "Message queues" +msgstr "Nachrichten-Warteschlangen" + +#: ../../mod/admin.php:211 ../../mod/admin.php:414 ../../mod/admin.php:516 +#: ../../mod/admin.php:726 ../../mod/admin.php:862 ../../mod/admin.php:953 +#: ../../mod/admin.php:995 ../../mod/admin.php:1158 ../../mod/admin.php:1194 +#: ../../mod/admin.php:1281 +msgid "Administration" +msgstr "Administration" + +#: ../../mod/admin.php:212 +msgid "Summary" +msgstr "Zusammenfassung" + +#: ../../mod/admin.php:214 +msgid "Registered users" +msgstr "Registrierte Benutzer" + +#: ../../mod/admin.php:216 ../../mod/admin.php:520 +msgid "Pending registrations" +msgstr "Ausstehende Registrierungen" + +#: ../../mod/admin.php:217 +msgid "Version" +msgstr "Version" + +#: ../../mod/admin.php:219 ../../mod/admin.php:521 +msgid "Active plugins" +msgstr "Aktive Plug-Ins" + +#: ../../mod/admin.php:330 +msgid "Site settings updated." +msgstr "Site-Einstellungen aktualisiert." + +#: ../../mod/admin.php:369 +msgid "experimental" +msgstr "experimentell" + +#: ../../mod/admin.php:371 +msgid "unsupported" +msgstr "nicht unterstützt" + +#: ../../mod/admin.php:395 +msgid "Yes - with approval" +msgstr "Ja - mit Zustimmung" + +#: ../../mod/admin.php:401 +msgid "My site is not a public server" +msgstr "Mein Server ist kein öffentlicher Server" + +#: ../../mod/admin.php:402 +msgid "My site has paid access only" +msgstr "Mein Server erlaubt nur bezahlten Zugang" + +#: ../../mod/admin.php:403 +msgid "My site has free access only" +msgstr "Mein Server erlaubt ausschließlich freien Zugang" + +#: ../../mod/admin.php:404 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "Mein Server bietet kostenlose Konten mit der Möglichkeit zu bezahlten Upgrades" + +#: ../../mod/admin.php:417 ../../mod/register.php:207 +msgid "Registration" +msgstr "Registrierung" + +#: ../../mod/admin.php:418 +msgid "File upload" +msgstr "Dateiupload" + +#: ../../mod/admin.php:419 +msgid "Policies" +msgstr "Richtlinien" + +#: ../../mod/admin.php:424 +msgid "Site name" +msgstr "Seitenname" + +#: ../../mod/admin.php:425 +msgid "Banner/Logo" +msgstr "Banner/Logo" + +#: ../../mod/admin.php:426 +msgid "Administrator Information" +msgstr "Administrator-Informationen" + +#: ../../mod/admin.php:426 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "Kontaktinformationen für Administratoren des Servers. Wird auf der siteinfo-Seite angezeigt. BBCode kann verwendet werden." + +#: ../../mod/admin.php:427 +msgid "System language" +msgstr "System-Sprache" + +#: ../../mod/admin.php:428 +msgid "System theme" +msgstr "System-Theme" + +#: ../../mod/admin.php:428 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "Standard-System-Theme – kann durch Nutzerprofile überschieben werden – Theme-Einstellungen ändern" + +#: ../../mod/admin.php:429 +msgid "Mobile system theme" +msgstr "Mobile System-Theme:" + +#: ../../mod/admin.php:429 +msgid "Theme for mobile devices" +msgstr "Theme für mobile Geräte" + +#: ../../mod/admin.php:431 +msgid "Enable Diaspora Protocol" +msgstr "Diaspora-Protokoll aktivieren" + +#: ../../mod/admin.php:431 +msgid "Communicate with Diaspora and Friendica - experimental" +msgstr "Kommunikation mit Diaspora und Friendica – experimentell" + +#: ../../mod/admin.php:432 +msgid "Allow Feeds as Connections" +msgstr "Feeds als Verbindungen erlauben" + +#: ../../mod/admin.php:432 +msgid "(Heavy system resource usage)" +msgstr "(führt zu hoher Systemlast)" + +#: ../../mod/admin.php:433 +msgid "Maximum image size" +msgstr "Maximale Bildgröße" + +#: ../../mod/admin.php:433 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Maximale Größe hochgeladener Bilder in Bytes. Standard ist 0 (keine Einschränkung)." + +#: ../../mod/admin.php:434 +msgid "Does this site allow new member registration?" +msgstr "Erlaubt dieser Server die Registrierung neuer Nutzer?" + +#: ../../mod/admin.php:435 +msgid "Which best describes the types of account offered by this hub?" +msgstr "Was ist die passendste Beschreibung der Konten auf diesem Hub?" + +#: ../../mod/admin.php:436 +msgid "Register text" +msgstr "Registrierungstext" + +#: ../../mod/admin.php:436 +msgid "Will be displayed prominently on the registration page." +msgstr "Wird gut sichtbar auf der Registrierungs-Seite angezeigt." + +#: ../../mod/admin.php:437 +msgid "Accounts abandoned after x days" +msgstr "Konten gelten nach X Tagen als unbenutzt" + +#: ../../mod/admin.php:437 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "Verschwende keine Systemressourcen auf das Pollen von externen Seiten, wenn das Konto nicht mehr benutzt wird. Trage hier 0 für kein zeitliches Limit." + +#: ../../mod/admin.php:438 +msgid "Allowed friend domains" +msgstr "Erlaubte Domains für Kontakte" + +#: ../../mod/admin.php:438 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "Liste der Domains, die für Freundschaften erlaubt sind, durch Kommas getrennt. Platzhalter werden akzeptiert. Leer lassen, um alle Domains zu erlauben." + +#: ../../mod/admin.php:439 +msgid "Allowed email domains" +msgstr "Erlaubte Domains für E-Mails" + +#: ../../mod/admin.php:439 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "Liste der Domains, die für E-Mail-Adressen bei der Registrierung erlaubt sind, durch Kommas getrennt. Platzhalter werden akzeptiert. Leer lassen, um alle Domains zu erlauben." + +#: ../../mod/admin.php:440 +msgid "Not allowed email domains" +msgstr "Nicht erlaubte Domains für E-Mails" + +#: ../../mod/admin.php:440 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for" +" registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "Domains in E-Mail-Adressen, die keine Erlaubnis erhalten, sich auf Deinem Hub zu registrieren. Mehrere Domains können durch Kommas getrennt werden. Platzhalter (*/?) sind möglich. Keine Eingabe bedeutet keine Einschränkung, unabhängig davon, ob unter erlaubte Domains etwas eingegeben wurde." + +#: ../../mod/admin.php:441 +msgid "Block public" +msgstr "Öffentlichen Zugriff blockieren" + +#: ../../mod/admin.php:441 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Zugriff auf sonst öffentliche persönliche Seiten blockieren, wenn man nicht eingeloggt ist." + +#: ../../mod/admin.php:442 +msgid "Verify Email Addresses" +msgstr "E-Mail-Adressen überprüfen" + +#: ../../mod/admin.php:442 +msgid "" +"Check to verify email addresses used in account registration (recommended)." +msgstr "Aktivieren, um die Ãœberprüfung von E-Mail-Adressen bei der Registrierung von Benutzerkonten zu aktivieren (empfohlen)." + +#: ../../mod/admin.php:443 +msgid "Force publish" +msgstr "Veröffentlichung erzwingen" + +#: ../../mod/admin.php:443 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Die Veröffentlichung aller Profile dieses Servers im Verzeichnis erzwingen." + +#: ../../mod/admin.php:444 +msgid "Disable discovery tab" +msgstr "Den „Entdecken“-Reiter ausblenden" + +#: ../../mod/admin.php:444 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "Entferne den „Entdecken“-Reiter aus der Matrix-Seite, in dem öffentliche Inhalte angezeigt werden, die von anderen RedMatrix-Hubs geholt wurden." + +#: ../../mod/admin.php:445 +msgid "No login on Homepage" +msgstr "Kein Login auf der Homepage" + +#: ../../mod/admin.php:445 +msgid "" +"Check to hide the login form from your sites homepage when visitors arrive " +"who are not logged in (e.g. when you put the content of the homepage in via " +"the site channel)." +msgstr "Aktivieren, um das Login-Formular auf der Startseite der Seite zu verbergen (z.B. weil es das Layout der Homepage des Seiten-Kanals stört)." + +#: ../../mod/admin.php:447 +msgid "Proxy user" +msgstr "Proxy Benutzer" + +#: ../../mod/admin.php:448 +msgid "Proxy URL" +msgstr "Proxy URL" + +#: ../../mod/admin.php:449 +msgid "Network timeout" +msgstr "Netzwerk-Timeout" + +#: ../../mod/admin.php:449 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "Wert in Sekunden. 0 für unbegrenzt (nicht empfohlen)." + +#: ../../mod/admin.php:450 +msgid "Delivery interval" +msgstr "Auslieferung Intervall" + +#: ../../mod/admin.php:450 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Verzögere im Hintergrund laufende Auslieferungsprozesse um die angegebene Anzahl Sekunden, um die Systemlast zu verringern. Empfehlungen: 4-5 für Shared Hosts, 2-3 für VPS, 0-1 für große dedizierte Server." + +#: ../../mod/admin.php:451 +msgid "Poll interval" +msgstr "Abfrageintervall" + +#: ../../mod/admin.php:451 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Verzögere Hintergrundprozesse um diese Anzahl Sekunden, um die Systemlast zu reduzieren. Bei 0 wird das Auslieferungsintervall verwendet." + +#: ../../mod/admin.php:452 +msgid "Maximum Load Average" +msgstr "Maximales Load Average" + +#: ../../mod/admin.php:452 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Maximale Systemlast, bevor Verteil- und Empfangsprozesse verschoben werden – Standard 50" + +#: ../../mod/admin.php:508 +msgid "No server found" +msgstr "Kein Server gefunden" + +#: ../../mod/admin.php:515 ../../mod/admin.php:740 +msgid "ID" +msgstr "ID" + +#: ../../mod/admin.php:515 +msgid "for channel" +msgstr "für Kanal" + +#: ../../mod/admin.php:515 +msgid "on server" +msgstr "auf Server" + +#: ../../mod/admin.php:515 +msgid "Status" +msgstr "Status" + +#: ../../mod/admin.php:536 +msgid "Update has been marked successful" +msgstr "Update wurde als erfolgreich markiert" + +#: ../../mod/admin.php:546 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "Ausführen von %s fehlgeschlagen. Ãœberprüfe die Systemprotokolle." + +#: ../../mod/admin.php:549 +#, php-format +msgid "Update %s was successfully applied." +msgstr "Update %s wurde erfolgreich ausgeführt." + +#: ../../mod/admin.php:553 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "Update %s lieferte keinen Rückgabewert. Erfolg unbekannt." + +#: ../../mod/admin.php:556 +#, php-format +msgid "Update function %s could not be found." +msgstr "Update-Funktion %s konnte nicht gefunden werden." + +#: ../../mod/admin.php:571 +msgid "No failed updates." +msgstr "Keine fehlgeschlagenen Aktualisierungen." + +#: ../../mod/admin.php:575 +msgid "Failed Updates" +msgstr "Fehlgeschlagene Aktualisierungen" + +#: ../../mod/admin.php:577 +msgid "Mark success (if update was manually applied)" +msgstr "Als erfolgreich markieren (wenn das Update manuell ausgeführt wurde)" + +#: ../../mod/admin.php:578 +msgid "Attempt to execute this update step automatically" +msgstr "Versuche, diesen Updateschritt automatisch auszuführen" + +#: ../../mod/admin.php:604 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s Nutzer blockiert/freigegeben" +msgstr[1] "%s Nutzer blockiert/freigegeben" + +#: ../../mod/admin.php:611 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s Nutzer gelöscht" +msgstr[1] "%s Nutzer gelöscht" + +#: ../../mod/admin.php:640 +msgid "Account not found" +msgstr "Konto nicht gefunden" + +#: ../../mod/admin.php:660 +#, php-format +msgid "User '%s' unblocked" +msgstr "Benutzer '%s' freigegeben" + +#: ../../mod/admin.php:660 +#, php-format +msgid "User '%s' blocked" +msgstr "Benutzer '%s' blockiert" + +#: ../../mod/admin.php:727 ../../mod/admin.php:739 +msgid "Users" +msgstr "Benutzer" + +#: ../../mod/admin.php:729 ../../mod/admin.php:865 +msgid "select all" +msgstr "Alle auswählen" + +#: ../../mod/admin.php:730 +msgid "User registrations waiting for confirm" +msgstr "Neuanmeldungen, die auf Deine Bestätigung warten" + +#: ../../mod/admin.php:731 +msgid "Request date" +msgstr "Antragsdatum" + +#: ../../mod/admin.php:732 +msgid "No registrations." +msgstr "Keine Registrierungen." + +#: ../../mod/admin.php:733 +msgid "Approve" +msgstr "Genehmigen" + +#: ../../mod/admin.php:734 +msgid "Deny" +msgstr "Verweigern" + +#: ../../mod/admin.php:740 +msgid "Register date" +msgstr "Registrierungs-Datum" + +#: ../../mod/admin.php:740 +msgid "Last login" +msgstr "Letzte Anmeldung" + +#: ../../mod/admin.php:740 +msgid "Expires" +msgstr "Verfällt" + +#: ../../mod/admin.php:740 +msgid "Service Class" +msgstr "Service-Klasse" + +#: ../../mod/admin.php:742 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Die markierten Nutzer werden gelöscht!\\n\\nAlles, was diese Nutzer auf dieser Seite veröffentlicht haben, wird endgültig gelöscht!\\n\\nBist Du sicher?" + +#: ../../mod/admin.php:743 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Der Nutzer {0} wird gelöscht!\\n\\nAlles, was dieser Nutzer auf dieser Seite veröffentlicht hat, wird endgültig gelöscht werden!\\n\\nBist Du sicher?" + +#: ../../mod/admin.php:776 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channels censored/uncensored" +msgstr[0] "%s Kanal gesperrt/freigegeben" +msgstr[1] "%s Kanäle gesperrt/freigegeben" + +#: ../../mod/admin.php:783 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "%s Kanal gelöscht" +msgstr[1] "%s Kanäle gelöscht" + +#: ../../mod/admin.php:802 +msgid "Channel not found" +msgstr "Kanal nicht gefunden" + +#: ../../mod/admin.php:813 +#, php-format +msgid "Channel '%s' deleted" +msgstr "Kanal '%s' gelöscht" + +#: ../../mod/admin.php:824 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "Kanal '%s' freigegeben" + +#: ../../mod/admin.php:824 +#, php-format +msgid "Channel '%s' censored" +msgstr "Kanal '%s' gesperrt" + +#: ../../mod/admin.php:867 +msgid "Censor" +msgstr "Sperren" + +#: ../../mod/admin.php:868 +msgid "Uncensor" +msgstr "Freigeben" + +#: ../../mod/admin.php:871 +msgid "UID" +msgstr "UID" + +#: ../../mod/admin.php:873 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Alle ausgewählten Kanäle werden gelöscht!\\n\\nAlles was von diesen Kanälen auf diesem Server geschrieben wurde, wird dauerhaft gelöscht!\\n\\nBist Du sicher?" + +#: ../../mod/admin.php:874 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Der Kanal {0} wird gelöscht!\\n\\nAlles was von diesem Kanal auf diesem Server geschrieben wurde, wird gelöscht!\\n\\nBist Du sicher?" + +#: ../../mod/admin.php:913 +#, php-format +msgid "Plugin %s disabled." +msgstr "Plug-In %s deaktiviert." + +#: ../../mod/admin.php:917 +#, php-format +msgid "Plugin %s enabled." +msgstr "Plug-In %s aktiviert." + +#: ../../mod/admin.php:927 ../../mod/admin.php:1129 +msgid "Disable" +msgstr "Deaktivieren" + +#: ../../mod/admin.php:929 ../../mod/admin.php:1131 +msgid "Enable" +msgstr "Aktivieren" + +#: ../../mod/admin.php:955 ../../mod/admin.php:1160 +msgid "Toggle" +msgstr "Umschalten" + +#: ../../mod/admin.php:963 ../../mod/admin.php:1170 +msgid "Author: " +msgstr "Autor: " + +#: ../../mod/admin.php:964 ../../mod/admin.php:1171 +msgid "Maintainer: " +msgstr "Betreuer:" + +#: ../../mod/admin.php:1093 +msgid "No themes found." +msgstr "Keine Theme gefunden." + +#: ../../mod/admin.php:1152 +msgid "Screenshot" +msgstr "Bildschirmfoto" + +#: ../../mod/admin.php:1200 +msgid "[Experimental]" +msgstr "[Experimentell]" + +#: ../../mod/admin.php:1201 +msgid "[Unsupported]" +msgstr "[Nicht unterstützt]" + +#: ../../mod/admin.php:1228 +msgid "Log settings updated." +msgstr "Protokoll-Einstellungen aktualisiert." + +#: ../../mod/admin.php:1284 +msgid "Clear" +msgstr "Leeren" + +#: ../../mod/admin.php:1290 +msgid "Debugging" +msgstr "Debugging" + +#: ../../mod/admin.php:1291 +msgid "Log file" +msgstr "Protokolldatei" + +#: ../../mod/admin.php:1291 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "Muss für den Web-Server schreibbar sein. Relativ zum Red-Stammverzeichnis." + +#: ../../mod/admin.php:1292 +msgid "Log level" +msgstr "Protokollstufe" + +#: ../../mod/admin.php:1339 +msgid "New Profile Field" +msgstr "Neues Profilfeld" + +#: ../../mod/admin.php:1340 ../../mod/admin.php:1361 +msgid "Field nickname" +msgstr "Kurzname für das Feld" + +#: ../../mod/admin.php:1340 ../../mod/admin.php:1361 +msgid "System name of field" +msgstr "Systemname des Feldes" + +#: ../../mod/admin.php:1341 ../../mod/admin.php:1362 +msgid "Input type" +msgstr "Art des Inhalts" + +#: ../../mod/admin.php:1342 ../../mod/admin.php:1363 +msgid "Field Name" +msgstr "Feldname" + +#: ../../mod/admin.php:1342 ../../mod/admin.php:1363 +msgid "Label on profile pages" +msgstr "Bezeichnung auf Profilseiten" + +#: ../../mod/admin.php:1343 ../../mod/admin.php:1364 +msgid "Help text" +msgstr "Hilfetext" + +#: ../../mod/admin.php:1343 ../../mod/admin.php:1364 +msgid "Additional info (optional)" +msgstr "Zusätzliche Informationen (optional)" + +#: ../../mod/admin.php:1354 +msgid "Field definition not found" +msgstr "Feld-Definition nicht gefunden" + +#: ../../mod/admin.php:1360 +msgid "Edit Profile Field" +msgstr "Profilfeld bearbeiten" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "Konnte Deinen Server nicht finden." + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "Veröffentlichung erfolgreich." + +#: ../../mod/post.php:229 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please" +" logout and retry." +msgstr "Fern-Authentifizierung blockiert. Du bist lokal auf diesem Server angemeldet. Bitte melde Dich ab und versuche es erneut." + +#: ../../mod/post.php:261 ../../mod/openid.php:72 ../../mod/openid.php:180 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "Willkommen %s. Entfernte Authentifizierung erfolgreich." + +#: ../../mod/regmod.php:11 +msgid "Please login." +msgstr "Bitte melde dich an." + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Das Löschen von Konten innerhalb 48 Stunden nachdem deren Passwort geändert wurde ist nicht erlaubt." + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "Dieses Konto löschen" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This will completely remove this account including all its channels from the" +" network. Once this has been done it is not recoverable." +msgstr "Hiermit wird dieses Nutzerkonto einschließlich all seiner Kanäle komplett aus dem Netzwerk entfernt. Dieser Vorgang kann nicht rückgängig gemacht werden." + +#: ../../mod/removeaccount.php:59 ../../mod/removeme.php:59 +msgid "Please enter your password for verification:" +msgstr "Bitte gib zur Bestätigung Dein Passwort ein:" + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "Dieses Konto, all seine Kanäle sowie alle Kanal-Klone aus dem Netzwerk löschen" + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "Standardmäßig werden nur die Kanalklone auf diesem RedMatrix-Hub aus dem Netzwerk entfernt" + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +#: ../../mod/update_home.php:21 +msgid "[Embedded content - reload page to view]" +msgstr "[Eingebettete Inhalte – lade die Seite neu, um sie anzuzeigen]" + +#: ../../mod/wall_upload.php:35 +msgid "Wall Photos" +msgstr "Wall Fotos" + +#: ../../mod/match.php:16 +msgid "Profile Match" +msgstr "Profil-Ãœbereinstimmungen" + +#: ../../mod/match.php:24 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "Keine Schlüsselwörter für den Abgleich gefunden. Bitte füge Schlüsselwörter zu Deinem Standardprofil hinzu." + +#: ../../mod/match.php:61 +msgid "is interested in:" +msgstr "interessiert sich für:" + +#: ../../mod/match.php:69 +msgid "No matches" +msgstr "Keine Ãœbereinstimmungen" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "Unterhaltung gelöscht." + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "Keine Nachrichten." + +#: ../../mod/message.php:72 ../../mod/mail.php:336 +msgid "Delete conversation" +msgstr "Unterhaltung löschen" + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "D, d. M Y - G:i" + +#: ../../mod/mitem.php:67 +msgid "Menu element updated." +msgstr "Menü-Element aktualisiert." + +#: ../../mod/mitem.php:71 +msgid "Unable to update menu element." +msgstr "Kann Menü-Element nicht aktualisieren." + +#: ../../mod/mitem.php:77 +msgid "Menu element added." +msgstr "Menü-Bestandteil hinzugefügt." + +#: ../../mod/mitem.php:81 +msgid "Unable to add menu element." +msgstr "Kann Menü-Bestandteil nicht hinzufügen." + +#: ../../mod/mitem.php:127 +msgid "Manage Menu Elements" +msgstr "Menü-Bestandteile verwalten" + +#: ../../mod/mitem.php:130 +msgid "Edit menu" +msgstr "Menü bearbeiten" + +#: ../../mod/mitem.php:133 +msgid "Edit element" +msgstr "Bestandteil bearbeiten" + +#: ../../mod/mitem.php:134 +msgid "Drop element" +msgstr "Bestandteil löschen" + +#: ../../mod/mitem.php:135 +msgid "New element" +msgstr "Neues Bestandteil" + +#: ../../mod/mitem.php:136 +msgid "Edit this menu container" +msgstr "Diesen Menü-Container bearbeiten" + +#: ../../mod/mitem.php:137 +msgid "Add menu element" +msgstr "Menüelement hinzufügen" + +#: ../../mod/mitem.php:138 +msgid "Delete this menu item" +msgstr "Lösche dieses Menü-Bestandteil" + +#: ../../mod/mitem.php:139 +msgid "Edit this menu item" +msgstr "Bearbeite dieses Menü-Bestandteil" + +#: ../../mod/mitem.php:158 +msgid "New Menu Element" +msgstr "Neues Menü-Bestandteil" + +#: ../../mod/mitem.php:160 ../../mod/mitem.php:203 +msgid "Menu Item Permissions" +msgstr "Zugriffsrechte des Menü-Elements" + +#: ../../mod/mitem.php:163 ../../mod/mitem.php:207 +msgid "Link text" +msgstr "Link Text" + +#: ../../mod/mitem.php:164 ../../mod/mitem.php:208 +msgid "URL of link" +msgstr "URL des Links" + +#: ../../mod/mitem.php:165 ../../mod/mitem.php:209 +msgid "Use RedMatrix magic-auth if available" +msgstr "Verwende die automatische RedMatrix-Authentifizierung (magic-auth), wenn verfügbar" + +#: ../../mod/mitem.php:166 ../../mod/mitem.php:210 +msgid "Open link in new window" +msgstr "Öffne Link in neuem Fenster" + +#: ../../mod/mitem.php:168 ../../mod/mitem.php:212 +msgid "Order in list" +msgstr "Reihenfolge in der Liste" + +#: ../../mod/mitem.php:168 ../../mod/mitem.php:212 +msgid "Higher numbers will sink to bottom of listing" +msgstr "Größere Nummern werden weiter unten in der Auflistung einsortiert" + +#: ../../mod/mitem.php:181 +msgid "Menu item not found." +msgstr "Menü-Bestandteil nicht gefunden." + +#: ../../mod/mitem.php:190 +msgid "Menu item deleted." +msgstr "Menü-Bestandteil gelöscht." + +#: ../../mod/mitem.php:192 +msgid "Menu item could not be deleted." +msgstr "Menü-Bestandteil kann nicht gelöscht werden." + +#: ../../mod/mitem.php:201 +msgid "Edit Menu Element" +msgstr "Bearbeite Menü-Bestandteil" + +#: ../../mod/mood.php:131 +msgid "Set your current mood and tell your friends" +msgstr "Wähle Deine aktuelle Stimmung und teile sie mit Deinen Freunden" + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "Stimmen gesamt" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "Durchschnittliche Bewertung" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Innerhalb von 48 Stunden nach einer Änderung des Passworts können keine Kanäle gelöscht werden." + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "Diesen Kanal löschen" + +#: ../../mod/removeme.php:58 +msgid "" +"This will completely remove this channel from the network. Once this has " +"been done it is not recoverable." +msgstr "Hiermit wird dieser Kanal komplett aus dem Netzwerk gelöscht. Einmal eingeleitet, kann dieser Prozess nicht wieder rückgängig gemacht werden." + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "Lösche diesen Kanal und all seine Klone aus dem Netzwerk" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "Standardmäßig wird der Kanal nur auf diesem Server gelöscht, seine Klone verbleiben im Netzwerk" + +#: ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "Kanal löschen" + +#: ../../mod/layouts.php:110 +msgid "Help with this feature" +msgstr "Hilfe zu dieser Funktion" + +#: ../../mod/layouts.php:130 +msgid "Layout Name" +msgstr "Layout-Name" + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "Mögen/Nicht mögen" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "Diese Aktion kann nur von Mitgliedern ausgeführt werden." + +#: ../../mod/like.php:21 +msgid "" +"Please login with your RedMatrix ID or register as a new RedMatrix member to continue." +msgstr "Bitte melde Dich mit Deiner RedMatrix-ID an oder registriere Dich als neues Mitglied der RedMatrix, um fortzufahren." + +#: ../../mod/like.php:101 ../../mod/like.php:128 ../../mod/like.php:166 +msgid "Invalid request." +msgstr "Ungültige Anfrage." + +#: ../../mod/like.php:143 +msgid "thing" +msgstr "Sache" + +#: ../../mod/like.php:189 +msgid "Channel unavailable." +msgstr "Kanal nicht vorhanden." + +#: ../../mod/like.php:228 +msgid "Previous action reversed." +msgstr "Die vorherige Aktion wurde rückgängig gemacht." + +#: ../../mod/like.php:387 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" +msgstr "%1$s stimmt %2$ss %3$s zu" + +#: ../../mod/like.php:389 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" +msgstr "%1$s lehnt %2$ss %3$s ab" + +#: ../../mod/like.php:391 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" +msgstr "%1$s enthält sich zu %2$ss %3$s" + +#: ../../mod/like.php:393 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "%1$s nimmt an %2$ss %3$s teil" + +#: ../../mod/like.php:395 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "%1$s nimmt an %2$ss %3$s nicht teil" + +#: ../../mod/like.php:397 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "%1$s nimmt vielleicht an %2$ss %3$s teil" + +#: ../../mod/like.php:481 +msgid "Action completed." +msgstr "Aktion durchgeführt." + +#: ../../mod/like.php:482 +msgid "Thank you." +msgstr "Vielen Dank." + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "Konnte den Empfänger nicht finden." + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "Die Kommunikation mit dem ausgewählten Kanal ist fehlgeschlagen." + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "Verifizierung des angeforderten Kanals fehlgeschlagen." + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "Der ausgewählte Kanal hat Einschränkungen bzgl. privater Nachrichten. Senden fehlgeschlagen." + +#: ../../mod/mail.php:139 +msgid "Message deleted." +msgstr "Nachricht gelöscht." + +#: ../../mod/mail.php:156 +msgid "Message recalled." +msgstr "Nachricht widerrufen." + +#: ../../mod/mail.php:225 +msgid "Send Private Message" +msgstr "Private Nachricht senden" + +#: ../../mod/mail.php:226 ../../mod/mail.php:343 +msgid "To:" +msgstr "An:" + +#: ../../mod/mail.php:231 ../../mod/mail.php:345 +msgid "Subject:" +msgstr "Betreff:" + +#: ../../mod/mail.php:242 +msgid "Send" +msgstr "Absenden" + +#: ../../mod/mail.php:269 +msgid "Message not found." +msgstr "Nachricht nicht gefunden." + +#: ../../mod/mail.php:312 +msgid "Delete message" +msgstr "Nachricht löschen" + +#: ../../mod/mail.php:313 +msgid "Recall message" +msgstr "Nachricht widerrufen" + +#: ../../mod/mail.php:315 +msgid "Message has been recalled." +msgstr "Die Nachricht wurde widerrufen." + +#: ../../mod/mail.php:332 +msgid "Private Conversation" +msgstr "Private Unterhaltung" + +#: ../../mod/mail.php:338 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Keine sichere Kommunikation verfügbar. Eventuell kannst Du auf der Profilseite des Absenders antworten." + +#: ../../mod/mail.php:342 +msgid "Send Reply" +msgstr "Antwort senden" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Ungültiger Anfrage-Identifikator." + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "Verwerfen" + +#: ../../mod/new_channel.php:109 +msgid "Add a Channel" +msgstr "Kanal hinzufügen" + +#: ../../mod/new_channel.php:110 +msgid "" +"A channel is your own collection of related web pages. A channel can be used" +" to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "Ein Kanal ist Deine eigene Sammlung von zusammengehörigen Webseiten. Ein Kanal kann genutzt werden, um ein Social-Network-Profil, ein Blog, eine Gesprächsgruppe oder ein Forum, Promi-Seiten und vieles mehr zu erstellen. Du kannst so viele Kanäle erstellen, wie es der Betreiber Deines Hubs zulässt." + +#: ../../mod/new_channel.php:113 +msgid "Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " +msgstr "Beispiele: „Horst Weidinger“, „Lisa und ihr Meerschweinchen“, „Fußball“, „Segelflieger-Forum“ " + +#: ../../mod/new_channel.php:114 +msgid "Choose a short nickname" +msgstr "Wähle einen kurzen Spitznamen" + +#: ../../mod/new_channel.php:115 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "Dein Spitzname wird verwendet, um eine leicht zu merkende Kanal-Adresse (ähnlich einer E-Mail-Adresse) zu erzeugen, die Du mit anderen austauschen kannst." + +#: ../../mod/new_channel.php:116 +msgid "Or import an existing channel from another location" +msgstr "Oder importiere einen bestehenden Kanal von einem anderen Server" + +#: ../../mod/new_channel.php:118 +msgid "" +"Please choose a channel type (such as social networking or community forum) " +"and privacy requirements so we can select the best permissions for you" +msgstr "Wähle einen Kanaltyp (wie Soziales Netzwerk oder Forum) und Privatsphäre-Vorgaben, so dass wir die passenden Kanal-Zugriffsrechte für Dich setzen können" + +#: ../../mod/new_channel.php:119 +msgid "Channel Type" +msgstr "Kanaltyp" + +#: ../../mod/new_channel.php:119 +msgid "Read more about roles" +msgstr "Mehr Informationen über Rollen" + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "OpenID Protokollfehler. Keine ID zurückgegeben." + +#: ../../mod/photos.php:77 +msgid "Page owner information could not be retrieved." +msgstr "Informationen über den Besitzer der Seite konnten nicht gefunden werden." + +#: ../../mod/photos.php:97 +msgid "Album not found." +msgstr "Album nicht gefunden." + +#: ../../mod/photos.php:119 ../../mod/photos.php:643 +msgid "Delete Album" +msgstr "Album löschen" + +#: ../../mod/photos.php:159 ../../mod/photos.php:924 +msgid "Delete Photo" +msgstr "Foto löschen" + +#: ../../mod/photos.php:440 +msgid "No photos selected" +msgstr "Keine Fotos ausgewählt" + +#: ../../mod/photos.php:484 +msgid "Access to this item is restricted." +msgstr "Der Zugriff auf dieses Foto ist eingeschränkt." + +#: ../../mod/photos.php:523 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgstr "%1$.2f MB von %2$.2f MB Foto-Speicher belegt." + +#: ../../mod/photos.php:526 +#, php-format +msgid "%1$.2f MB photo storage used." +msgstr "%1$.2f MB Foto-Speicher belegt." + +#: ../../mod/photos.php:550 +msgid "Upload Photos" +msgstr "Fotos hochladen" + +#: ../../mod/photos.php:554 ../../mod/photos.php:636 ../../mod/photos.php:909 +msgid "Enter a new album name" +msgstr "Gib einen Namen für ein neues Album ein" + +#: ../../mod/photos.php:555 ../../mod/photos.php:637 ../../mod/photos.php:910 +msgid "or select an existing one (doubleclick)" +msgstr "oder wähle ein bereits vorhandenes aus (Doppelklick)" + +#: ../../mod/photos.php:556 +msgid "Do not show a status post for this upload" +msgstr "Keine Statusnachricht für diesen Upload anzeigen" + +#: ../../mod/photos.php:584 +msgid "Album name could not be decoded" +msgstr "Albumname konnte nicht dekodiert werden" + +#: ../../mod/photos.php:625 ../../mod/photos.php:1149 +#: ../../mod/photos.php:1165 +msgid "Contact Photos" +msgstr "Kontakt-Bilder" + +#: ../../mod/photos.php:649 +msgid "Show Newest First" +msgstr "Neueste zuerst anzeigen" + +#: ../../mod/photos.php:651 +msgid "Show Oldest First" +msgstr "Älteste zuerst anzeigen" + +#: ../../mod/photos.php:675 ../../mod/photos.php:1197 +msgid "View Photo" +msgstr "Foto ansehen" + +#: ../../mod/photos.php:704 +msgid "Edit Album" +msgstr "Album bearbeiten" + +#: ../../mod/photos.php:749 +msgid "Permission denied. Access to this item may be restricted." +msgstr "Berechtigung verweigert. Der Zugriff ist wahrscheinlich eingeschränkt worden." + +#: ../../mod/photos.php:751 +msgid "Photo not available" +msgstr "Foto nicht verfügbar" + +#: ../../mod/photos.php:809 +msgid "Use as profile photo" +msgstr "Als Profilfoto verwenden" + +#: ../../mod/photos.php:816 +msgid "Private Photo" +msgstr "Privates Foto" + +#: ../../mod/photos.php:831 +msgid "View Full Size" +msgstr "In voller Größe anzeigen" + +#: ../../mod/photos.php:903 +msgid "Edit photo" +msgstr "Foto bearbeiten" + +#: ../../mod/photos.php:905 +msgid "Rotate CW (right)" +msgstr "Drehen im UZS (rechts)" + +#: ../../mod/photos.php:906 +msgid "Rotate CCW (left)" +msgstr "Drehen gegen UZS (links)" + +#: ../../mod/photos.php:913 +msgid "Caption" +msgstr "Bildunterschrift" + +#: ../../mod/photos.php:915 +msgid "Add a Tag" +msgstr "Schlagwort hinzufügen" + +#: ../../mod/photos.php:919 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +msgstr "Beispiele: @ben, @Karl_Prester, @lieschen@example.com" + +#: ../../mod/photos.php:922 +msgid "Flag as adult in album view" +msgstr "In der Albumansicht als nicht jugendfrei markieren" + +#: ../../mod/photos.php:1114 +msgid "In This Photo:" +msgstr "Auf diesem Foto:" + +#: ../../mod/photos.php:1203 +msgid "View Album" +msgstr "Album ansehen" + +#: ../../mod/photos.php:1226 +msgid "Recent Photos" +msgstr "Neueste Fotos" + +#: ../../mod/ping.php:263 +msgid "sent you a private message" +msgstr "hat Dir eine private Nachricht geschickt" + +#: ../../mod/ping.php:314 +msgid "added your channel" +msgstr "hat deinen Kanal hinzugefügt" + +#: ../../mod/ping.php:355 +msgid "posted an event" +msgstr "hat einen Termin veröffentlicht" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "Lesezeichen hinzugefügt" + +#: ../../mod/bookmarks.php:60 +msgid "My Bookmarks" +msgstr "Meine Lesezeichen" + +#: ../../mod/bookmarks.php:71 +msgid "My Connections Bookmarks" +msgstr "Lesezeichen meiner Kontakte" + +#: ../../mod/channel.php:87 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "Unzureichende Zugriffsrechte. Die Anfrage wurde zur Profil-Seite umgeleitet." + +#: ../../mod/register.php:44 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "Maximale Anzahl täglicher Neuanmeldungen erreicht. Bitte versuche es morgen noch einmal." + +#: ../../mod/register.php:50 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "Bitte stimme den Nutzungsbedingungen zu. Registrierung fehlgeschlagen." + +#: ../../mod/register.php:84 +msgid "Passwords do not match." +msgstr "Passwörter stimmen nicht überein." + +#: ../../mod/register.php:117 +msgid "" +"Registration successful. Please check your email for validation " +"instructions." +msgstr "Registrierung erfolgreich. Eine E-Mail mit weiteren Anweisungen wurde an Dich gesendet." + +#: ../../mod/register.php:123 +msgid "Your registration is pending approval by the site owner." +msgstr "Deine Registrierung muss noch vom Betreiber der Seite freigegeben werden." + +#: ../../mod/register.php:126 +msgid "Your registration can not be processed." +msgstr "Deine Registrierung konnte nicht verarbeitet werden." + +#: ../../mod/register.php:163 +msgid "Registration on this site/hub is by approval only." +msgstr "Anmeldungen auf diesem Server erfordern Zustimmung durch den Administrator" + +#: ../../mod/register.php:164 +msgid "Register at another affiliated site/hub" +msgstr "Registrierung auf einem anderen, angeschlossenen Server" + +#: ../../mod/register.php:174 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "Die maximale Anzahl täglicher Registrierungen auf diesem Server wurde überschritten. Bitte versuche es morgen noch einmal." + +#: ../../mod/register.php:185 +msgid "Terms of Service" +msgstr "Nutzungsbedingungen" + +#: ../../mod/register.php:191 +#, php-format +msgid "I accept the %s for this website" +msgstr "Ich akzeptiere die %s für diese Webseite" + +#: ../../mod/register.php:193 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "Ich bin älter als 13 Jahre und akzeptiere die %s dieser Webseite" + +#: ../../mod/register.php:212 +msgid "Membership on this site is by invitation only." +msgstr "Mitgliedschaft auf dieser Seite ist nur nach vorheriger Einladung möglich." + +#: ../../mod/register.php:213 +msgid "Please enter your invitation code" +msgstr "Bitte trage Deinen Einladungs-Code ein" + +#: ../../mod/register.php:216 +msgid "Your email address" +msgstr "Ihre E-Mail Adresse" + +#: ../../mod/register.php:217 +msgid "Choose a password" +msgstr "Passwort" + +#: ../../mod/register.php:218 +msgid "Please re-enter your password" +msgstr "Bitte gib Dein Passwort noch einmal ein" + +#: ../../mod/rmagic.php:38 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Wir haben ein Problem mit der OpenID festgestellt, mit der Du Dich anmelden wolltest. Bitte überprüfe sie noch einmal." + +#: ../../mod/rmagic.php:38 +msgid "The error message was:" +msgstr "Die Fehlermeldung war:" + +#: ../../mod/rmagic.php:42 +msgid "Authentication failed." +msgstr "Authentifizierung fehlgeschlagen." + +#: ../../mod/rmagic.php:82 +msgid "Remote Authentication" +msgstr "Entfernte Authentifizierung" + +#: ../../mod/rmagic.php:83 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "Deine Kanal-Adresse (z. B. channel@example.com)" + +#: ../../mod/rmagic.php:84 +msgid "Authenticate" +msgstr "Authentifizieren" + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "Umfrage" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "Ergebnisse" + +#: ../../mod/service_limits.php:19 +msgid "No service class restrictions found." +msgstr "Keine Dienstklassenbeschränkungen gefunden." + +#: ../../mod/sharedwithme.php:99 +msgid "Files: shared with me" +msgstr "Dateien, die mit mir geteilt wurden" + +#: ../../mod/sharedwithme.php:103 +msgid "Remove all files" +msgstr "Alle Dateien löschen" + +#: ../../mod/sharedwithme.php:104 +msgid "Remove this file" +msgstr "Diese Datei löschen" + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "Standard-Schema" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "Sans-Serif" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "Monospace" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Theme settings" +msgstr "Theme-Einstellungen" + +#: ../../view/theme/apw/php/config.php:260 +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Set scheme" +msgstr "Schema" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set font-size for posts and comments" +msgstr "Schriftgröße für Beiträge und Kommentare" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "Schriftart" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "Icon-Set" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "Ausmaß der großen Schatten (Voreinstellung 15px 15px 15px)" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "Ausmaß der kleinen Schatten (Voreinstellung 5px 5px 5px)" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "Farbe der Schatten (Voreinstellung #000)" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "Ecken-Radius (Voreinstellung 5px)" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "Zeilenhöhe in Beiträgen und Kommentaren" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "Hintergrundbild" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "Hintergrunddatei" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "Hintergrundfarbe" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "Hintergrundbild für die Section" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "Hintergrundfarbe für die Section" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "Farbe für Beiträge – Hex benutzen" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "Farbe für Links – Hex benutzen" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "Maximale Breite von Beiträgen (Voreinstellung 400px)" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "Minimale Breite von Beiträgen (Voreinstellung 240px)" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "Breite des \"generic content wrapper\" (Voreinstellung 48%)" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "Schriftfarbe – Hex benutzen" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "Größe des Hintergrund-Elements" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "Deckkraft der Beiträge" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "Nur Beitragsvorschau anzeigen" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "Zeige die Seitenleiste auf der Kanal-Seite" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "Farbe der Navigationsleiste" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "Beitragsfluss" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "Linker Rand des Section Elements" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "Rechter Rand des Section Elements" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "Breite der Section" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "Linker Rand des Aside-Elements" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "Rechter Rand des Aside-Elements" + +#: ../../view/theme/redbasic/php/config.php:84 +msgid "Light (Red Matrix default)" +msgstr "Hell (RedMatrix-Voreinstellung)" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Narrow navbar" +msgstr "Schmale Navigationsleiste" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar background color" +msgstr "Hintergrundfarbe der Navigationsleiste" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation bar gradient top color" +msgstr "Farbverlauf der Navigationsleiste: Farbe oben" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation bar gradient bottom color" +msgstr "Farbverlauf der Navigationsleiste: Farbe unten" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation active button gradient top color" +msgstr "Navigations-Button aktiv: Farbe für Farbverlauf oben" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation active button gradient bottom color" +msgstr "Navigations-Button aktiv: Farbe für Farbverlauf unten" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar border color " +msgstr "Farbe für den Rand der Navigationsleiste" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "Navigation bar icon color " +msgstr "Farbe für die Icons der Navigationsleiste" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Navigation bar active icon color " +msgstr "Farbe für aktive Icons der Navigationsleiste" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "link color" +msgstr "Farbe für Links" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set font-color for banner" +msgstr "Farbe der Schrift des Banners" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color" +msgstr "Hintergrundfarbe" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background image" +msgstr "Hintergrundbild" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the background color of items" +msgstr "Hintergrundfarbe für Beiträge" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the background color of comments" +msgstr "Hintergrundfarbe für Kommentare" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the border color of comments" +msgstr "Farbe des Randes von Kommentaren" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the indent for comments" +msgstr "Einzugsbreite für Kommentare" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set the basic color for item icons" +msgstr "Grundfarbe für Beitrags-Icons" + +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set the hover color for item icons" +msgstr "Farbe für Beitrags-Icons unter dem Mauszeiger" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-size for the entire application" +msgstr "Schriftgröße für die gesamte Anwendung" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set font-color for posts and comments" +msgstr "Schriftfarbe für Beiträge und Kommentare" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set radius of corners" +msgstr "Ecken-Radius" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Set shadow depth of photos" +msgstr "Schattentiefe von Fotos" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set maximum width of conversation regions" +msgstr "Maximalbreite der Unterhaltungsbereiche" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Center conversation regions" +msgstr "Konversationsbereich zentrieren" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "Mindest-Deckkraft der Navigationsleiste ( - versteckt sie)" + +#: ../../view/theme/redbasic/php/config.php:131 +msgid "Set size of conversation author photo" +msgstr "Größe der Avatare von Themenstartern" + +#: ../../view/theme/redbasic/php/config.php:132 +msgid "Set size of followup author photos" +msgstr "Größe der Avatare von Kommentatoren" + +#: ../../view/theme/redbasic/php/config.php:133 +msgid "Sloppy photo albums" +msgstr "Schräge Fotoalben" + +#: ../../view/theme/redbasic/php/config.php:133 +msgid "Are you a clean desk or a messy desk person?" +msgstr "Bist Du jemand, der einen aufgeräumten Schreibtisch hat, oder eher einen chaotischen?" + +#: ../../boot.php:1357 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "Aktualisierung %s fehlgeschlagen. Details in den Fehlerprotokollen." + +#: ../../boot.php:1360 +#, php-format +msgid "Update Error at %s" +msgstr "Aktualisierungsfehler auf %s" + +#: ../../boot.php:1527 +msgid "" +"Create an account to access services and applications within the Red Matrix" +msgstr "Erstelle einen Account, um Anwendungen und Dienste innerhalb der Red-Matrix verwenden zu können." + +#: ../../boot.php:1555 +msgid "Password" +msgstr "Kennwort" + +#: ../../boot.php:1556 +msgid "Remember me" +msgstr "Angaben speichern" + +#: ../../boot.php:1559 +msgid "Forgot your password?" +msgstr "Passwort vergessen?" + +#: ../../boot.php:1674 +msgid "permission denied" +msgstr "Zugriff verweigert" + +#: ../../boot.php:1675 +msgid "Got Zot?" +msgstr "Haste schon Zot?" + +#: ../../boot.php:2158 +msgid "toggle mobile" +msgstr "auf/von mobile Ansicht wechseln" diff --git a/sources/view/de/passchanged_eml.tpl b/sources/view/de/passchanged_eml.tpl new file mode 100644 index 00000000..95805f67 --- /dev/null +++ b/sources/view/de/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Hallo {{$username}}, + Dein Passwort wurde wie gewünscht geändert. Bitte nimm diese +Information zu Deinen Unterlagen (oder ändere Dein Passwort sofort auf +etwas, an das Du Dich erinnern kannst). + + +Deine Anmeldedetails lauten wie folgt: + +Web-Adresse des Servers: {{$siteurl}} +Username: {{$email}} +Passwort: {{$new_password}} + +Du solltest das Passwort nach dem Einloggen in den Einstellungen ändern. + + +Mit freundlichen Grüßen, + der Administrator von {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/de/register_open_eml.tpl b/sources/view/de/register_open_eml.tpl new file mode 100644 index 00000000..ce96d2ec --- /dev/null +++ b/sources/view/de/register_open_eml.tpl @@ -0,0 +1,19 @@ + +Auf {{$sitename}} für diese E-Mail-Adresse ein Konto angelegt. +Die Anmeldedetails lauten wie folgt: + +Adresse des Servers: {{$siteurl}} +Username: {{$email}} +Passwort: (das Passwort, das Du während des Registrierungsvorgangs angegeben hast) + +Falls das Konto ohne Dein Wissen erstellt wurde und Du es löschen möchtest, kannst Du auf der +Login-Seite des Servers das Passwort zurücksetzen lassen. Mit dem neuen Passwort kannst Du +Dich einloggen und dann auf der Einstellungen-Seite das Konto löschen. Bitte +entschuldige die Unannehmlichkeit. + +Danke, und herzlich Willkommen auf {{$sitename}}! + +Viele Grüße, + der Administrator von {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/de/register_verify_eml.tpl b/sources/view/de/register_verify_eml.tpl new file mode 100644 index 00000000..4da21265 --- /dev/null +++ b/sources/view/de/register_verify_eml.tpl @@ -0,0 +1,24 @@ + +Eine neuer Benutzer hat sich auf {{$sitename}} registriert und benötigt +Deine Freigabe. + + +Die Anmeldedetails lauten wie folgt: + +Adresse des Servers: {{$siteurl}} +Username: {{$email}} +IP-Adresse: {{$details}} + +Um die Anfrage zu bestätigen besuche bitte folgenden Link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +Um die Anfrage abzulehnen und das Konto zu entfernen besuche bitte: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Vielen Dank. diff --git a/sources/view/de/strings.php b/sources/view/de/strings.php new file mode 100644 index 00000000..2679e9eb --- /dev/null +++ b/sources/view/de/strings.php @@ -0,0 +1,2079 @@ +strings["Cannot locate DNS info for database server '%s'"] = "Kann die DNS-Informationen für den Datenbank-Server '%s' nicht finden"; +$a->strings["Profile Photos"] = "Profilfotos"; +$a->strings["Permission denied."] = "Zugang verweigert"; +$a->strings["Image exceeds website size limit of %lu bytes"] = "Bild überschreitet das Limit der Webseite von %lu bytes"; +$a->strings["Image file is empty."] = "Bilddatei ist leer."; +$a->strings["Unable to process image"] = "Kann Bild nicht verarbeiten"; +$a->strings["Photo storage failed."] = "Foto speichern schlug fehl"; +$a->strings["Photo Albums"] = "Fotoalben"; +$a->strings["Upload New Photos"] = "Lade neue Fotos hoch"; +$a->strings["created a new post"] = "Neuer Beitrag wurde erzeugt"; +$a->strings["commented on %s's post"] = "hat %s's Beitrag kommentiert"; +$a->strings["New Page"] = "Neue Seite"; +$a->strings["Edit"] = "Bearbeiten"; +$a->strings["View"] = "Ansicht"; +$a->strings["Preview"] = "Vorschau"; +$a->strings["Actions"] = "Aktionen"; +$a->strings["Page Link"] = "Seiten-Link"; +$a->strings["Title"] = "Titel"; +$a->strings["Created"] = "Erstellt"; +$a->strings["Edited"] = "Geändert"; +$a->strings["Categories"] = "Kategorien"; +$a->strings["Apps"] = "Apps"; +$a->strings["System"] = "System"; +$a->strings["Personal"] = "Persönlich"; +$a->strings["Create Personal App"] = "Persönliche App erstellen"; +$a->strings["Edit Personal App"] = "Persönliche App bearbeiten"; +$a->strings["Connect"] = "Verbinden"; +$a->strings["Ignore/Hide"] = "Ignorieren/Verstecken"; +$a->strings["Suggestions"] = "Vorschläge"; +$a->strings["See more..."] = "Mehr anzeigen …"; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = "Du bist %1$.0f von maximal %2$.0f erlaubten Verbindungen eingegangen."; +$a->strings["Add New Connection"] = "Neue Verbindung hinzufügen"; +$a->strings["Enter the channel address"] = "Adresse des Kanals eingeben"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Beispiel: bob@beispiel.com, http://beispiel.com/barbara"; +$a->strings["Notes"] = "Notizen"; +$a->strings["Save"] = "Speichern"; +$a->strings["Remove term"] = "Eintrag löschen"; +$a->strings["Saved Searches"] = "Gespeicherte Suchanfragen"; +$a->strings["add"] = "hinzufügen"; +$a->strings["Saved Folders"] = "Gespeicherte Ordner"; +$a->strings["Everything"] = "Alles"; +$a->strings["Archives"] = "Archive"; +$a->strings["Refresh"] = "Aktualisieren"; +$a->strings["Me"] = "Ich"; +$a->strings["Best Friends"] = "Beste Freunde"; +$a->strings["Friends"] = "Freunde"; +$a->strings["Co-workers"] = "Kollegen"; +$a->strings["Former Friends"] = "ehem. Freunde"; +$a->strings["Acquaintances"] = "Bekannte"; +$a->strings["Everybody"] = "Jeder"; +$a->strings["Account settings"] = "Konto-Einstellungen"; +$a->strings["Channel settings"] = "Kanal-Einstellungen"; +$a->strings["Additional features"] = "Zusätzliche Funktionen"; +$a->strings["Feature/Addon settings"] = "Plugin-Einstellungen"; +$a->strings["Display settings"] = "Anzeige-Einstellungen"; +$a->strings["Connected apps"] = "Verbundene Apps"; +$a->strings["Export channel"] = "Kanal exportieren"; +$a->strings["Connection Default Permissions"] = "Standardzugriffsrechte für neue Verbindungen:"; +$a->strings["Premium Channel Settings"] = "Premium-Kanal-Einstellungen"; +$a->strings["Channel Sources"] = "Kanal-Quellen"; +$a->strings["Settings"] = "Einstellungen"; +$a->strings["Messages"] = "Nachrichten"; +$a->strings["Check Mail"] = "E-Mails abrufen"; +$a->strings["New Message"] = "Neue Nachricht"; +$a->strings["Chat Rooms"] = "Chaträume"; +$a->strings["Bookmarked Chatrooms"] = "Gespeicherte Chatrooms"; +$a->strings["Suggested Chatrooms"] = "Chatraum-Vorschläge"; +$a->strings["photo/image"] = "Foto/Bild"; +$a->strings["Rate Me"] = "Bewerte mich"; +$a->strings["View Ratings"] = "Bewertungen ansehen"; +$a->strings["Public Hubs"] = "Öffentliche Hubs"; +$a->strings["Red Matrix Notification"] = "Red Matrix Benachrichtigung"; +$a->strings["redmatrix"] = "redmatrix"; +$a->strings["Thank You,"] = "Danke."; +$a->strings["%s Administrator"] = "der Administrator von %s"; +$a->strings["%s "] = "%s "; +$a->strings["[Red:Notify] New mail received at %s"] = "[Red:Benachrichtigung] Neue Mail auf %s empfangen"; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s hat Dir eine private Nachricht auf %3\$s gesendet."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s hat Dir %2\$s geschickt."; +$a->strings["a private message"] = "eine private Nachricht"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Bitte besuche %s, um die private Nachricht anzusehen und/oder darauf zu antworten."; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s hat [zrl=%3\$s]einen %4\$s[/zrl] kommentiert"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s hat [zrl=%3\$s]%4\$ss %5\$s[/zrl] kommentiert"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s hat [zrl=%3\$s]Deinen %4\$s[/zrl] kommentiert"; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red:Benachrichtigung] Kommentar in Unterhaltung #%1\$d von %2\$s"; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s hat eine Unterhaltung kommentiert, der Du folgst."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Bitte besuche %s, um die Unterhaltung anzusehen und/oder zu kommentieren."; +$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Hinweis] %s schrieb auf Deine Pinnwand"; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s hat auf Deine Pinnwand auf %3\$s geschrieben"; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s hat auf [zrl=%3\$s]Deine Pinnwand[/zrl] geschrieben"; +$a->strings["[Red:Notify] %s tagged you"] = "[Red:Benachrichtigung] %s hat Dich erwähnt"; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s hat Dich auf %3\$s erwähnt"; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]hat Dich erwähnt[/zrl]."; +$a->strings["[Red:Notify] %1\$s poked you"] = "[Red:Benachrichtigung] %1\$s hat Dich angestupst"; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s hat Dich auf %3\$s angestupst"; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]hat Dich angestupst[/zrl]."; +$a->strings["[Red:Notify] %s tagged your post"] = "[Red:Benachrichtigung] %s hat Deinen Beitrag verschlagwortet"; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s hat Deinen Beitrag auf %3\$s verschlagwortet"; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s hat [zrl=%3\$s]Deinen Beitrag[/zrl] verschlagwortet"; +$a->strings["[Red:Notify] Introduction received"] = "[Red:Benachrichtigung] Vorstellung erhalten"; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, Du hast eine neue Verbindungsanfrage von '%2\$s' auf %3\$s erhalten"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, Du hast [zrl=%2\$s]eine neue Verbindungsanfrage[/zrl] von %3\$s erhalten."; +$a->strings["You may visit their profile at %s"] = "Du kannst Dir das Profil unter %s ansehen"; +$a->strings["Please visit %s to approve or reject the connection request."] = "Bitte besuche %s , um die Verbindungsanfrage anzunehmen oder abzulehnen."; +$a->strings["[Red:Notify] Friend suggestion received"] = "[Red:Benachrichtigung] Freundschaftsvorschlag erhalten"; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, Du hast einen Kontaktvorschlag von „%2\$s“ auf %3\$s erhalten"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, Du hast [zrl=%2\$s]einen Kontaktvorschlag[/zrl] für %3\$s von %4\$s erhalten."; +$a->strings["Name:"] = "Name:"; +$a->strings["Photo:"] = "Foto:"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Bitte besuche %s um den Vorschlag zu akzeptieren oder abzulehnen."; +$a->strings["[Red:Notify]"] = "[Red:Benachrichtigung]"; +$a->strings["prev"] = "vorherige"; +$a->strings["first"] = "erste"; +$a->strings["last"] = "letzte"; +$a->strings["next"] = "nächste"; +$a->strings["older"] = "älter"; +$a->strings["newer"] = "neuer"; +$a->strings["No connections"] = "Keine Verbindungen"; +$a->strings["%d Connection"] = array( + 0 => "%d Verbindung", + 1 => "%d Verbindungen", +); +$a->strings["View Connections"] = "Verbindungen anzeigen"; +$a->strings["Search"] = "Suche"; +$a->strings["poke"] = "anstupsen"; +$a->strings["poked"] = "stupste"; +$a->strings["ping"] = "anpingen"; +$a->strings["pinged"] = "pingte"; +$a->strings["prod"] = "knuffen"; +$a->strings["prodded"] = "knuffte"; +$a->strings["slap"] = "ohrfeigen"; +$a->strings["slapped"] = "ohrfeigte"; +$a->strings["finger"] = "befummeln"; +$a->strings["fingered"] = "befummelte"; +$a->strings["rebuff"] = "eine Abfuhr erteilen"; +$a->strings["rebuffed"] = "zurückgewiesen"; +$a->strings["happy"] = "glücklich"; +$a->strings["sad"] = "traurig"; +$a->strings["mellow"] = "sanft"; +$a->strings["tired"] = "müde"; +$a->strings["perky"] = "frech"; +$a->strings["angry"] = "sauer"; +$a->strings["stupified"] = "verblüfft"; +$a->strings["puzzled"] = "verwirrt"; +$a->strings["interested"] = "interessiert"; +$a->strings["bitter"] = "verbittert"; +$a->strings["cheerful"] = "fröhlich"; +$a->strings["alive"] = "lebendig"; +$a->strings["annoyed"] = "verärgert"; +$a->strings["anxious"] = "unruhig"; +$a->strings["cranky"] = "schrullig"; +$a->strings["disturbed"] = "verstört"; +$a->strings["frustrated"] = "frustriert"; +$a->strings["depressed"] = "deprimiert"; +$a->strings["motivated"] = "motiviert"; +$a->strings["relaxed"] = "entspannt"; +$a->strings["surprised"] = "überrascht"; +$a->strings["Monday"] = "Montag"; +$a->strings["Tuesday"] = "Dienstag"; +$a->strings["Wednesday"] = "Mittwoch"; +$a->strings["Thursday"] = "Donnerstag"; +$a->strings["Friday"] = "Freitag"; +$a->strings["Saturday"] = "Samstag"; +$a->strings["Sunday"] = "Sonntag"; +$a->strings["January"] = "Januar"; +$a->strings["February"] = "Februar"; +$a->strings["March"] = "März"; +$a->strings["April"] = "April"; +$a->strings["May"] = "Mai"; +$a->strings["June"] = "Juni"; +$a->strings["July"] = "Juli"; +$a->strings["August"] = "August"; +$a->strings["September"] = "September"; +$a->strings["October"] = "Oktober"; +$a->strings["November"] = "November"; +$a->strings["December"] = "Dezember"; +$a->strings["unknown.???"] = "unbekannt.???"; +$a->strings["bytes"] = "Bytes"; +$a->strings["remove category"] = "Kategorie entfernen"; +$a->strings["remove from file"] = "aus der Datei entfernen"; +$a->strings["Click to open/close"] = "Klicke zum Öffnen/Schließen"; +$a->strings["Link to Source"] = "Link zur Quelle"; +$a->strings["Select a page layout: "] = "Ein Seiten-Layout auswählen:"; +$a->strings["default"] = "Standard"; +$a->strings["Page content type: "] = "Content-Typ der Seite:"; +$a->strings["Select an alternate language"] = "Wähle eine alternative Sprache"; +$a->strings["photo"] = "Foto"; +$a->strings["event"] = "Termin"; +$a->strings["status"] = "Status"; +$a->strings["comment"] = "Kommentar"; +$a->strings["activity"] = "Aktivität"; +$a->strings["Design"] = "Design"; +$a->strings["Blocks"] = "Blöcke"; +$a->strings["Menus"] = "Menüs"; +$a->strings["Layouts"] = "Layouts"; +$a->strings["Pages"] = "Seiten"; +$a->strings["Collection"] = "Ordner"; +$a->strings["Item was not found."] = "Beitrag wurde nicht gefunden."; +$a->strings["No source file."] = "Keine Quelldatei."; +$a->strings["Cannot locate file to replace"] = "Kann Datei zum Ersetzen nicht finden"; +$a->strings["Cannot locate file to revise/update"] = "Kann Datei zum Prüfen/Aktualisieren nicht finden"; +$a->strings["File exceeds size limit of %d"] = "Datei überschreitet das Größen-Limit von %d"; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Die Größe Deiner Datei-Anhänge hat das Maximum von %1$.0f MByte erreicht."; +$a->strings["File upload failed. Possible system limit or action terminated."] = "Datei-Upload fehlgeschlagen. Mögliche Systembegrenzung oder abgebrochener Prozess."; +$a->strings["Stored file could not be verified. Upload failed."] = "Gespeichert Datei konnte nicht verifiziert werden. Upload abgebrochen."; +$a->strings["Path not available."] = "Pfad nicht verfügbar."; +$a->strings["Empty pathname"] = "Leere Pfadangabe"; +$a->strings["duplicate filename or path"] = "doppelter Dateiname oder Pfad"; +$a->strings["Path not found."] = "Pfad nicht gefunden."; +$a->strings["mkdir failed."] = "mkdir fehlgeschlagen."; +$a->strings["database storage failed."] = "Speichern in der Datenbank fehlgeschlagen."; +$a->strings["Delete this item?"] = "Dieses Element löschen?"; +$a->strings["Comment"] = "Kommentar"; +$a->strings["[+] show all"] = "[+] Alle anzeigen"; +$a->strings["[-] show less"] = "[-] Weniger anzeigen"; +$a->strings["[+] expand"] = "[+] aufklappen"; +$a->strings["[-] collapse"] = "[-] einklappen"; +$a->strings["Password too short"] = "Kennwort zu kurz"; +$a->strings["Passwords do not match"] = "Kennwörter stimmen nicht überein"; +$a->strings["everybody"] = "alle"; +$a->strings["Secret Passphrase"] = "geheime Passphrase"; +$a->strings["Passphrase hint"] = "Hinweis zur Passphrase"; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = "Achtung: Berechtigungen wurden verändert, aber noch nicht gespeichert."; +$a->strings["close all"] = "Alle schließen"; +$a->strings["Nothing new here"] = "Nichts Neues hier"; +$a->strings["Rate This Channel (this is public)"] = "Diesen Kanal bewerten (öffentlich sichtbar)"; +$a->strings["Rating"] = "Bewertung"; +$a->strings["Describe (optional)"] = "Beschreibung (optional)"; +$a->strings["Submit"] = "Bestätigen"; +$a->strings["timeago.prefixAgo"] = "timeago.prefixAgo"; +$a->strings["timeago.prefixFromNow"] = " "; +$a->strings["ago"] = "her"; +$a->strings["from now"] = "von jetzt"; +$a->strings["less than a minute"] = "weniger als eine Minute"; +$a->strings["about a minute"] = "ungefähr eine Minute"; +$a->strings["%d minutes"] = "%d Minuten"; +$a->strings["about an hour"] = "ungefähr eine Stunde"; +$a->strings["about %d hours"] = "ungefähr %d Stunden"; +$a->strings["a day"] = "ein Tag"; +$a->strings["%d days"] = "%d Tage"; +$a->strings["about a month"] = "ungefähr ein Monat"; +$a->strings["%d months"] = "%d Monate"; +$a->strings["about a year"] = "ungefähr ein Jahr"; +$a->strings["%d years"] = "%d Jahre"; +$a->strings[" "] = " "; +$a->strings["timeago.numbers"] = "timeago.numbers"; +$a->strings["parent"] = "Ãœbergeordnetes Verzeichnis"; +$a->strings["Principal"] = "Prinzipal"; +$a->strings["Addressbook"] = "Adressbuch"; +$a->strings["Calendar"] = "Kalender"; +$a->strings["Schedule Inbox"] = "Posteingang für überwachte Kalender"; +$a->strings["Schedule Outbox"] = "Postausgang für überwachte Kalender"; +$a->strings["Unknown"] = "Unbekannt"; +$a->strings["%1\$s used"] = "%1\$s verwendet"; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = "%1\$s von %2\$s verwendet (%3\$s%)"; +$a->strings["Files"] = "Dateien"; +$a->strings["Total"] = "Summe"; +$a->strings["Shared"] = "Geteilt"; +$a->strings["Create"] = "Erstelle"; +$a->strings["Upload"] = "Hochladen"; +$a->strings["Name"] = "Name"; +$a->strings["Type"] = "Typ"; +$a->strings["Size"] = "Größe"; +$a->strings["Last Modified"] = "Zuletzt geändert"; +$a->strings["Delete"] = "Löschen"; +$a->strings["Create new folder"] = "Neuen Ordner anlegen"; +$a->strings["Upload file"] = "Datei hochladen"; +$a->strings["%1\$s's bookmarks"] = "%1\$ss Lesezeichen"; +$a->strings["Tags"] = "Schlagwörter"; +$a->strings["Keywords"] = "Schlüsselwörter"; +$a->strings["have"] = "habe"; +$a->strings["has"] = "hat"; +$a->strings["want"] = "will"; +$a->strings["wants"] = "will"; +$a->strings["like"] = "mag"; +$a->strings["likes"] = "gefällt"; +$a->strings["dislike"] = "verurteile"; +$a->strings["dislikes"] = "missfällt"; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "Gefällt mir", + 1 => "Gefällt mir", +); +$a->strings["General Features"] = "Allgemeine Funktionen"; +$a->strings["Content Expiration"] = "Verfall von Inhalten"; +$a->strings["Remove posts/comments and/or private messages at a future time"] = "Lösche Beiträge, Kommentare und/oder private Nachrichten automatisch zu einem zukünftigen Datum."; +$a->strings["Multiple Profiles"] = "Mehrfachprofile"; +$a->strings["Ability to create multiple profiles"] = "Mehrfachprofile anlegen können"; +$a->strings["Advanced Profiles"] = "Erweiterte Profile"; +$a->strings["Additional profile sections and selections"] = "Stellt zusätzliche Bereiche und Felder im Profil zur Verfügung"; +$a->strings["Profile Import/Export"] = "Profil-Import/Export"; +$a->strings["Save and load profile details across sites/channels"] = "Speichere Dein Profil, um es in einen anderen Kanal zu importieren"; +$a->strings["Web Pages"] = "Webseiten"; +$a->strings["Provide managed web pages on your channel"] = "Stelle verwaltete Webseiten in Deinem Kanal zur Verfügung"; +$a->strings["Private Notes"] = "Private Notizen"; +$a->strings["Enables a tool to store notes and reminders"] = "Werkzeug zum Speichern von Notizen und Erinnerungen aktivieren"; +$a->strings["Navigation Channel Select"] = "Kanal-Auswahl in der Navigationsleiste"; +$a->strings["Change channels directly from within the navigation dropdown menu"] = "Wechsle direkt über das Navigationsmenü zu anderen Kanälen"; +$a->strings["Extended Identity Sharing"] = "Erweitertes Teilen von Identitäten"; +$a->strings["Share your identity with all websites on the internet. When disabled, identity is only shared with sites in the matrix."] = "Teile Deine Identität mit allen Webseiten im Internet. Ist dies deaktiviert, wird Deine Identität nur mit Red-Servern geteilt."; +$a->strings["Expert Mode"] = "Expertenmodus"; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = "Aktiviere den Expertenmodus, um fortgeschrittene Konfigurationsoptionen zu aktivieren"; +$a->strings["Premium Channel"] = "Premium-Kanal"; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = "Ermöglicht es, Einschränkungen und Bedingungen für Verbindungen dieses Kanals festzulegen"; +$a->strings["Post Composition Features"] = "Nachbearbeitungsfunktionen"; +$a->strings["Use Markdown"] = "Markdown benutzen"; +$a->strings["Allow use of \"Markdown\" to format posts"] = "Erlaube die Verwendung von \"Markdown\"-Syntax zur Formatierung von Beiträgen"; +$a->strings["Large Photos"] = "Große Fotos"; +$a->strings["Include large (640px) photo thumbnails in posts. If not enabled, use small (320px) photo thumbnails"] = "Große Vorschaubilder (640px) in Beiträgen anzeigen. Ist das deaktiviert, werden kleine Vorschaubilder (320px) angezeigt."; +$a->strings["Automatically import channel content from other channels or feeds"] = "Importiere automatisch Inhalte für diesen Kanal von anderen Kanälen oder Feeds"; +$a->strings["Even More Encryption"] = "Noch mehr Verschlüsselung"; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = "Erlaube optionale Verschlüsselung von Inhalten (Ende-zu-Ende mit geteiltem Sicherheitsschlüssel)"; +$a->strings["Enable voting tools"] = "Umfragewerkzeuge aktivieren"; +$a->strings["Provide a class of post which others can vote on"] = "Aktiviere die Umfragewerkzeuge, um anderen die Möglichkeit zu geben, Deinem Beitrag zuzustimmen, ihn abzulehnen oder sich zu enthalten. (Muss im Beitrag selbst noch aktiviert werden.)"; +$a->strings["Flag Adult Photos"] = "Nicht jugendfreie Fotos markieren"; +$a->strings["Provide photo edit option to hide adult photos from default album view"] = "Stellt eine Option zum Verstecken von Fotos mit nicht jugendfreien Inhalten in der Standard-Albumansicht bereit"; +$a->strings["Network and Stream Filtering"] = "Netzwerk- und Stream-Filter"; +$a->strings["Search by Date"] = "Suche nach Datum"; +$a->strings["Ability to select posts by date ranges"] = "Möglichkeit, Beiträge nach Zeiträumen auszuwählen"; +$a->strings["Collections Filter"] = "Filter für Sammlung"; +$a->strings["Enable widget to display Network posts only from selected collections"] = "Aktiviere nur Netzwerk-Beiträge von ausgewählten Sammlungen"; +$a->strings["Save search terms for re-use"] = "Suchbegriffe zur Wiederverwendung abspeichern"; +$a->strings["Network Personal Tab"] = "Persönlicher Netzwerkreiter"; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = "Aktiviere Reiter nur für die Netzwerk-Beiträge, mit denen Du interagiert hast"; +$a->strings["Network New Tab"] = "Netzwerkreiter Neu"; +$a->strings["Enable tab to display all new Network activity"] = "Aktiviere Reiter, um alle neuen Netzwerkaktivitäten zu zeigen"; +$a->strings["Affinity Tool"] = "Beziehungs-Tool"; +$a->strings["Filter stream activity by depth of relationships"] = "Filter Aktivitätenstream nach Tiefe der Beziehung"; +$a->strings["Suggest Channels"] = "Kanäle vorschlagen"; +$a->strings["Show channel suggestions"] = "Kanalvorschläge anzeigen"; +$a->strings["Post/Comment Tools"] = "Beitrag-/Kommentar-Tools"; +$a->strings["Tagging"] = "Verschlagworten"; +$a->strings["Ability to tag existing posts"] = "Möglichkeit, um existierende Beiträge zu verschlagworten"; +$a->strings["Post Categories"] = "Beitrags-Kategorien"; +$a->strings["Add categories to your posts"] = "Kategorien für Beiträge"; +$a->strings["Ability to file posts under folders"] = "Möglichkeit, Beiträge in Verzeichnissen zu sammeln"; +$a->strings["Dislike Posts"] = "Gefällt-mir-nicht Beiträge"; +$a->strings["Ability to dislike posts/comments"] = "„Gefällt mir nicht“ ermöglichen"; +$a->strings["Star Posts"] = "Beiträge mit Sternchen versehen"; +$a->strings["Ability to mark special posts with a star indicator"] = "Möglichkeit, spezielle Beiträge mit Sternchen-Symbol zu markieren"; +$a->strings["Tag Cloud"] = "Schlagwort-Wolke"; +$a->strings["Provide a personal tag cloud on your channel page"] = "Persönliche Schlagwort-Wolke auf Deiner Kanal-Seite anzeigen"; +$a->strings["Logged out."] = "Ausgeloggt."; +$a->strings["Failed authentication"] = "Authentifizierung fehlgeschlagen"; +$a->strings["Login failed."] = "Login fehlgeschlagen."; +$a->strings["Frequently"] = "Häufig"; +$a->strings["Hourly"] = "Stündlich"; +$a->strings["Twice daily"] = "Zwei Mal am Tag"; +$a->strings["Daily"] = "Täglich"; +$a->strings["Weekly"] = "Wöchentlich"; +$a->strings["Monthly"] = "Monatlich"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Email"] = "E-Mail"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "LinkedIn"; +$a->strings["XMPP/IM"] = "XMPP/IM"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "Es hat früher schon einmal eine Sammlung mit diesem Namen existiert, die gelöscht wurde. Es könnten von damals noch Elemente (Beiträge, Dateien etc.) vorhanden sein, die allen jetzigen und zukünftigen Mitgliedern dieser Sammlung den Zugriff erlauben. Wenn das nicht Dein Plan war, erstelle bitte eine neue Sammlung mit einem anderen Namen."; +$a->strings["Default privacy group for new contacts"] = "Standard-Sammlung für neue Kontakte"; +$a->strings["All Channels"] = "Alle Kanäle"; +$a->strings["edit"] = "Bearbeiten"; +$a->strings["Collections"] = "Sammlungen"; +$a->strings["Edit collection"] = "Sammlung bearbeiten"; +$a->strings["Create a new collection"] = "Neue Sammlung erzeugen"; +$a->strings["Channels not in any collection"] = "Kanäle, die nicht in einer Sammlung sind"; +$a->strings["Unable to obtain identity information from database"] = "Kann keine Identitäts-Informationen aus Datenbank beziehen"; +$a->strings["Empty name"] = "Namensfeld leer"; +$a->strings["Name too long"] = "Name ist zu lang"; +$a->strings["No account identifier"] = "Keine Account-Kennung"; +$a->strings["Nickname is required."] = "Spitzname ist erforderlich."; +$a->strings["Reserved nickname. Please choose another."] = "Reservierter Kurzname. Bitte wähle einen anderen."; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = "Der Spitzname enthält nicht-unterstütze Zeichen oder wird bereits auf dieser Seite genutzt."; +$a->strings["Unable to retrieve created identity"] = "Kann die erstellte Identität nicht empfangen"; +$a->strings["Default Profile"] = "Standard-Profil"; +$a->strings["Requested channel is not available."] = "Angeforderte Kanal nicht verfügbar."; +$a->strings["Requested profile is not available."] = "Erwünschte Profil ist nicht verfügbar."; +$a->strings["Change profile photo"] = "Profilfoto ändern"; +$a->strings["Profiles"] = "Profile"; +$a->strings["Manage/edit profiles"] = "Profile verwalten/bearbeiten"; +$a->strings["Create New Profile"] = "Neues Profil erstellen"; +$a->strings["Edit Profile"] = "Profile bearbeiten"; +$a->strings["Profile Image"] = "Profilfoto:"; +$a->strings["visible to everybody"] = "sichtbar für jeden"; +$a->strings["Edit visibility"] = "Sichtbarkeit bearbeiten"; +$a->strings["Location:"] = "Ort:"; +$a->strings["Gender:"] = "Geschlecht:"; +$a->strings["Status:"] = "Status:"; +$a->strings["Homepage:"] = "Homepage:"; +$a->strings["Online Now"] = "gerade online"; +$a->strings["g A l F d"] = "l, d. F, G:i \\U\\h\\r"; +$a->strings["F d"] = "d. F"; +$a->strings["[today]"] = "[Heute]"; +$a->strings["Birthday Reminders"] = "Geburtstags Erinnerungen"; +$a->strings["Birthdays this week:"] = "Geburtstage in dieser Woche:"; +$a->strings["[No description]"] = "[Keine Beschreibung]"; +$a->strings["Event Reminders"] = "Termin-Erinnerungen"; +$a->strings["Events this week:"] = "Termine in dieser Woche:"; +$a->strings["Profile"] = "Profil"; +$a->strings["Full Name:"] = "Voller Name:"; +$a->strings["Like this channel"] = "Dieser Kanal gefällt mir"; +$a->strings["j F, Y"] = "j. F Y"; +$a->strings["j F"] = "j. F"; +$a->strings["Birthday:"] = "Geburtstag:"; +$a->strings["Age:"] = "Alter:"; +$a->strings["for %1\$d %2\$s"] = "seit %1\$d %2\$s"; +$a->strings["Sexual Preference:"] = "Sexuelle Orientierung:"; +$a->strings["Hometown:"] = "Heimatstadt:"; +$a->strings["Tags:"] = "Schlagworte:"; +$a->strings["Political Views:"] = "Politische Ansichten:"; +$a->strings["Religion:"] = "Religion:"; +$a->strings["About:"] = "Ãœber:"; +$a->strings["Hobbies/Interests:"] = "Hobbys/Interessen:"; +$a->strings["Likes:"] = "Gefällt:"; +$a->strings["Dislikes:"] = "Gefällt nicht:"; +$a->strings["Contact information and Social Networks:"] = "Kontaktinformation und soziale Netzwerke:"; +$a->strings["My other channels:"] = "Meine anderen Kanäle:"; +$a->strings["Musical interests:"] = "Musikalische Interessen:"; +$a->strings["Books, literature:"] = "Bücher, Literatur:"; +$a->strings["Television:"] = "Fernsehen:"; +$a->strings["Film/dance/culture/entertainment:"] = "Film/Tanz/Kultur/Unterhaltung:"; +$a->strings["Love/Romance:"] = "Liebe/Romantik:"; +$a->strings["Work/employment:"] = "Arbeit/Anstellung:"; +$a->strings["School/education:"] = "Schule/Ausbildung:"; +$a->strings["Like this thing"] = "Gefällt mir"; +$a->strings["No recipient provided."] = "Kein Empfänger angegeben"; +$a->strings["[no subject]"] = "[no subject]"; +$a->strings["Unable to determine sender."] = "Kann Absender nicht bestimmen."; +$a->strings["Stored post could not be verified."] = "Gespeicherter Beitrag konnten nicht überprüft werden."; +$a->strings["Channel is blocked on this site."] = "Der Kanal ist auf dieser Seite blockiert "; +$a->strings["Channel location missing."] = "Adresse des Kanals fehlt."; +$a->strings["Response from remote channel was incomplete."] = "Antwort des entfernten Kanals war unvollständig."; +$a->strings["Channel was deleted and no longer exists."] = "Kanal wurde gelöscht und existiert nicht mehr."; +$a->strings["Protocol disabled."] = "Protokoll deaktiviert."; +$a->strings["Channel discovery failed."] = "Kanalsuche fehlgeschlagen"; +$a->strings["local account not found."] = "Lokales Konto nicht gefunden."; +$a->strings["Cannot connect to yourself."] = "Du kannst Dich nicht mit Dir selbst verbinden."; +$a->strings["Default"] = "Standard"; +$a->strings["Miscellaneous"] = "Verschiedenes"; +$a->strings["YYYY-MM-DD or MM-DD"] = "JJJJ-MM-TT oder MM-TT"; +$a->strings["Required"] = "Benötigt"; +$a->strings["never"] = "Nie"; +$a->strings["less than a second ago"] = "Vor weniger als einer Sekunde"; +$a->strings["year"] = "Jahr"; +$a->strings["years"] = "Jahre"; +$a->strings["month"] = "Monat"; +$a->strings["months"] = "Monate"; +$a->strings["week"] = "Woche"; +$a->strings["weeks"] = "Wochen"; +$a->strings["day"] = "Tag"; +$a->strings["days"] = "Tage"; +$a->strings["hour"] = "Stunde"; +$a->strings["hours"] = "Stunden"; +$a->strings["minute"] = "Minute"; +$a->strings["minutes"] = "Minuten"; +$a->strings["second"] = "Sekunde"; +$a->strings["seconds"] = "Sekunden"; +$a->strings["%1\$d %2\$s ago"] = "vor %1\$d %2\$s"; +$a->strings["%1\$s's birthday"] = "%1\$ss Geburtstag"; +$a->strings["Happy Birthday %1\$s"] = "Alles Gute zum Geburtstag, %1\$s"; +$a->strings["Attachments:"] = "Anhänge:"; +$a->strings["l F d, Y \\@ g:i A"] = "l, d. F Y, H:i"; +$a->strings["Redmatrix event notification:"] = "RedMatrix Termin-Benachrichtigung:"; +$a->strings["Starts:"] = "Beginnt:"; +$a->strings["Finishes:"] = "Endet:"; +$a->strings["Missing room name"] = "Der Chatraum hat keinen Namen"; +$a->strings["Duplicate room name"] = "Name des Chatraums bereits vergeben"; +$a->strings["Invalid room specifier."] = "Ungültiger Raumbezeichner."; +$a->strings["Room not found."] = "Chatraum konnte nicht gefunden werden."; +$a->strings["Room is full"] = "Der Raum ist voll"; +$a->strings["Logout"] = "Abmelden"; +$a->strings["End this session"] = "Beende diese Sitzung"; +$a->strings["Home"] = "Home"; +$a->strings["Your posts and conversations"] = "Deine Beiträge und Unterhaltungen"; +$a->strings["View Profile"] = "Profil ansehen"; +$a->strings["Your profile page"] = "Deine Profilseite"; +$a->strings["Edit Profiles"] = "Profile bearbeiten"; +$a->strings["Manage/Edit profiles"] = "Profile verwalten"; +$a->strings["Edit your profile"] = "Profil bearbeiten"; +$a->strings["Photos"] = "Fotos"; +$a->strings["Your photos"] = "Deine Bilder"; +$a->strings["Your files"] = "Deine Dateien"; +$a->strings["Chat"] = "Chat"; +$a->strings["Your chatrooms"] = "Deine Chaträume"; +$a->strings["Bookmarks"] = "Lesezeichen"; +$a->strings["Your bookmarks"] = "Deine Lesezeichen"; +$a->strings["Webpages"] = "Webseiten"; +$a->strings["Your webpages"] = "Deine Webseiten"; +$a->strings["Login"] = "Anmelden"; +$a->strings["Sign in"] = "Anmelden"; +$a->strings["%s - click to logout"] = "%s - Klick zum Abmelden"; +$a->strings["Remote authentication"] = "Ãœber Konto auf anderem Server einloggen"; +$a->strings["Click to authenticate to your home hub"] = "Klicke, um Dich über Deinen Heimat-Server zu authentifizieren"; +$a->strings["Home Page"] = "Homepage"; +$a->strings["Register"] = "Registrieren"; +$a->strings["Create an account"] = "Erzeuge ein Konto"; +$a->strings["Help"] = "Hilfe"; +$a->strings["Help and documentation"] = "Hilfe und Dokumentation"; +$a->strings["Applications, utilities, links, games"] = "Anwendungen (Apps), Zubehör, Links, Spiele"; +$a->strings["Search site content"] = "Durchsuche Seiten-Inhalt"; +$a->strings["Directory"] = "Verzeichnis"; +$a->strings["Channel Directory"] = "Kanal-Verzeichnis"; +$a->strings["Matrix"] = "Matrix"; +$a->strings["Your matrix"] = "Deine Matrix"; +$a->strings["Mark all matrix notifications seen"] = "Markiere alle Matrix-Benachrichtigungen als angesehen"; +$a->strings["Channel Home"] = "Mein Kanal"; +$a->strings["Channel home"] = "Mein Kanal"; +$a->strings["Mark all channel notifications seen"] = "Markiere alle Kanal-Benachrichtigungen als angesehen"; +$a->strings["Connections"] = "Verbindungen"; +$a->strings["Notices"] = "Benachrichtigungen"; +$a->strings["Notifications"] = "Benachrichtigungen"; +$a->strings["See all notifications"] = "Alle Benachrichtigungen ansehen"; +$a->strings["Mark all system notifications seen"] = "Markiere alle System-Benachrichtigungen als gesehen"; +$a->strings["Mail"] = "Mail"; +$a->strings["Private mail"] = "Persönliche Mail"; +$a->strings["See all private messages"] = "Alle persönlichen Nachrichten ansehen"; +$a->strings["Mark all private messages seen"] = "Markiere alle persönlichen Nachrichten als gesehen"; +$a->strings["Inbox"] = "Eingang"; +$a->strings["Outbox"] = "Ausgang"; +$a->strings["Events"] = "Termine"; +$a->strings["Event Calendar"] = "Terminkalender"; +$a->strings["See all events"] = "Alle Termine ansehen"; +$a->strings["Mark all events seen"] = "Markiere alle Termine als gesehen"; +$a->strings["Channel Manager"] = "Kanal-Manager"; +$a->strings["Manage Your Channels"] = "Verwalte Deine Kanäle"; +$a->strings["Account/Channel Settings"] = "Konto-/Kanal-Einstellungen"; +$a->strings["Admin"] = "Administration"; +$a->strings["Site Setup and Configuration"] = "Seiten-Einrichtung und -Konfiguration"; +$a->strings["Loading..."] = "Lädt ..."; +$a->strings["@name, #tag, content"] = "@Name, #Schlagwort, Text"; +$a->strings["Please wait..."] = "Bitte warten..."; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "Das Security-Token des Formulars war nicht korrekt. Das ist wahrscheinlich passiert, weil das Formular zu lange (>3 Stunden) offen war, bevor es abgeschickt wurde."; +$a->strings["Private Message"] = "Private Nachricht"; +$a->strings["Select"] = "Auswählen"; +$a->strings["Save to Folder"] = "In Ordner speichern"; +$a->strings["I will attend"] = "Ich werde teilnehmen"; +$a->strings["I will not attend"] = "Ich werde nicht teilnehmen"; +$a->strings["I might attend"] = "Ich werde vielleicht teilnehmen"; +$a->strings["I agree"] = "Ich stimme zu"; +$a->strings["I disagree"] = "Ich lehne ab"; +$a->strings["I abstain"] = "Ich enthalte mich"; +$a->strings["View all"] = "Alles anzeigen"; +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "Gefällt nicht", + 1 => "Gefällt nicht", +); +$a->strings["Add Star"] = "Stern hinzufügen"; +$a->strings["Remove Star"] = "Stern entfernen"; +$a->strings["Toggle Star Status"] = "Markierungsstatus (Stern) umschalten"; +$a->strings["starred"] = "markiert"; +$a->strings["Message signature validated"] = "Signatur überprüft"; +$a->strings["Message signature incorrect"] = "Signatur nicht korrekt"; +$a->strings["Add Tag"] = "Tag hinzufügen"; +$a->strings["I like this (toggle)"] = "Mir gefällt das (Umschalter)"; +$a->strings["I don't like this (toggle)"] = "Mir gefällt das nicht (Umschalter)"; +$a->strings["Share This"] = "Teilen"; +$a->strings["share"] = "Teilen"; +$a->strings["%d comment"] = array( + 0 => "%d Kommentar", + 1 => "%d Kommentare", +); +$a->strings["View %s's profile - %s"] = "Schaue Dir %ss Profil an – %s"; +$a->strings["to"] = "an"; +$a->strings["via"] = "via"; +$a->strings["Wall-to-Wall"] = "Wall-to-Wall"; +$a->strings["via Wall-To-Wall:"] = "via Wall-To-Wall:"; +$a->strings[" from %s"] = "von %s"; +$a->strings["last edited: %s"] = "zuletzt bearbeitet: %s"; +$a->strings["Expires: %s"] = "Verfällt: %s"; +$a->strings["Save Bookmarks"] = "Favoriten speichern"; +$a->strings["Add to Calendar"] = "Zum Kalender hinzufügen"; +$a->strings["Mark all seen"] = "Alle als gelesen markieren"; +$a->strings["__ctx:noun__ Likes"] = "Gefällt mir"; +$a->strings["__ctx:noun__ Dislikes"] = "Gefällt nicht"; +$a->strings["Close"] = "Schließen"; +$a->strings["Please wait"] = "Bitte warten"; +$a->strings["This is you"] = "Das bist Du"; +$a->strings["Bold"] = "Fett"; +$a->strings["Italic"] = "Kursiv"; +$a->strings["Underline"] = "Unterstrichen"; +$a->strings["Quote"] = "Zitat"; +$a->strings["Code"] = "Code"; +$a->strings["Image"] = "Bild"; +$a->strings["Link"] = "Link"; +$a->strings["Video"] = "Video"; +$a->strings["Encrypt text"] = "Text verschlüsseln"; +$a->strings[" and "] = "und"; +$a->strings["public profile"] = "öffentliches Profil"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s hat %2\$s auf “%3\$s” geändert"; +$a->strings["Visit %1\$s's %2\$s"] = "Besuche %1\$s's %2\$s"; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s hat ein aktualisiertes %2\$s, %3\$s wurde verändert."; +$a->strings["Directory Options"] = "Verzeichnisoptionen"; +$a->strings["Alphabetic"] = "alphabetisch"; +$a->strings["Reverse Alphabetic"] = "Entgegengesetzt alphabetisch"; +$a->strings["Newest to Oldest"] = "Neueste zuerst"; +$a->strings["Oldest to Newest"] = "Älteste zuerst"; +$a->strings["Public Forums Only"] = "Nur öffentliche Foren"; +$a->strings["Sort"] = "Sortieren"; +$a->strings["Enable Safe Search"] = "Sichere Suche einschalten"; +$a->strings["Disable Safe Search"] = "Sichere Suche ausschalten"; +$a->strings["Safe Mode"] = "Sicherer Modus"; +$a->strings["Permission denied"] = "Keine Berechtigung"; +$a->strings["(Unknown)"] = "(Unbekannt)"; +$a->strings["Visible to anybody on the internet."] = "Für jeden im Internet sichtbar."; +$a->strings["Visible to you only."] = "Nur für Dich sichtbar."; +$a->strings["Visible to anybody in this network."] = "Für jedes Mitglied der RedMatrix sichtbar."; +$a->strings["Visible to anybody authenticated."] = "Für jeden sichtbar, der angemeldet ist."; +$a->strings["Visible to anybody on %s."] = "Für jeden auf %s sichtbar."; +$a->strings["Visible to all connections."] = "Für alle Verbindungen sichtbar."; +$a->strings["Visible to approved connections."] = "Nur für akzeptierte Verbindungen sichtbar."; +$a->strings["Visible to specific connections."] = "Sichtbar für bestimmte Verbindungen."; +$a->strings["Item not found."] = "Element nicht gefunden."; +$a->strings["Collection not found."] = "Sammlung nicht gefunden"; +$a->strings["Collection is empty."] = "Sammlung ist leer."; +$a->strings["Collection: %s"] = "Sammlung: %s"; +$a->strings["Connection: %s"] = "Verbindung: %s"; +$a->strings["Connection not found."] = "Die Verbindung wurde nicht gefunden."; +$a->strings["This event has been added to your calendar."] = "Dieser Termin wurde zu Deinem Kalender hinzugefügt"; +$a->strings["New window"] = "Neues Fenster"; +$a->strings["Open the selected location in a different window or browser tab"] = "Öffne die markierte Adresse in einem neuen Browser Fenster oder Tab"; +$a->strings["User '%s' deleted"] = "Benutzer '%s' gelöscht"; +$a->strings["view full size"] = "In Vollbildansicht anschauen"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s gefällt %2\$ss %3\$s"; +$a->strings["Image/photo"] = "Bild/Foto"; +$a->strings["Encrypted content"] = "Verschlüsselter Inhalt"; +$a->strings["Install design element: "] = "Design-Element installieren:"; +$a->strings["QR code"] = "QR-Code"; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s schrieb den folgenden %2\$s %3\$s"; +$a->strings["post"] = "Beitrag"; +$a->strings["Different viewers will see this text differently"] = "Verschiedene Betrachter werden diesen Text unterschiedlich sehen"; +$a->strings["$1 spoiler"] = "$1 Spoiler"; +$a->strings["$1 wrote:"] = "$1 schrieb:"; +$a->strings["%d invitation available"] = array( + 0 => "%d Einladung verfügbar", + 1 => "%d Einladungen verfügbar", +); +$a->strings["Advanced"] = "Fortgeschritten"; +$a->strings["Find Channels"] = "Finde Kanäle"; +$a->strings["Enter name or interest"] = "Name oder Interessen eingeben"; +$a->strings["Connect/Follow"] = "Verbinden/Folgen"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Beispiele: Robert Morgenstein, Angeln"; +$a->strings["Find"] = "Finde"; +$a->strings["Channel Suggestions"] = "Kanal-Vorschläge"; +$a->strings["Random Profile"] = "Zufallsprofil"; +$a->strings["Invite Friends"] = "Lade Freunde ein"; +$a->strings["Advanced example: name=fred and country=iceland"] = "Fortgeschrittenes Beispiel: name=fred and country=iceland"; +$a->strings["%d connection in common"] = array( + 0 => "%d gemeinsame Verbindung", + 1 => "%d gemeinsame Verbindungen", +); +$a->strings["show more"] = "mehr zeigen"; +$a->strings["Visible to your default audience"] = "Standard-Sichtbarkeit"; +$a->strings["Show"] = "Anzeigen"; +$a->strings["Don't show"] = "Nicht anzeigen"; +$a->strings["Permissions"] = "Berechtigungen"; +$a->strings["Public Timeline"] = "Öffentliche Zeitleiste"; +$a->strings["Invalid data packet"] = "Ungültiges Datenpaket"; +$a->strings["Unable to verify channel signature"] = "Konnte die Signatur des Kanals nicht verifizieren"; +$a->strings["Unable to verify site signature for %s"] = "Kann die Signatur der Seite von %s nicht verifizieren"; +$a->strings["Male"] = "Männlich"; +$a->strings["Female"] = "Weiblich"; +$a->strings["Currently Male"] = "Momentan männlich"; +$a->strings["Currently Female"] = "Momentan weiblich"; +$a->strings["Mostly Male"] = "Größtenteils männlich"; +$a->strings["Mostly Female"] = "Größtenteils weiblich"; +$a->strings["Transgender"] = "Transsexuell"; +$a->strings["Intersex"] = "Zwischengeschlechtlich"; +$a->strings["Transsexual"] = "Transsexuell"; +$a->strings["Hermaphrodite"] = "Zwitter"; +$a->strings["Neuter"] = "Geschlechtslos"; +$a->strings["Non-specific"] = "unklar"; +$a->strings["Other"] = "Andere"; +$a->strings["Undecided"] = "Unentschieden"; +$a->strings["Males"] = "Männer"; +$a->strings["Females"] = "Frauen"; +$a->strings["Gay"] = "Schwul"; +$a->strings["Lesbian"] = "Lesbisch"; +$a->strings["No Preference"] = "Keine Bevorzugung"; +$a->strings["Bisexual"] = "Bisexuell"; +$a->strings["Autosexual"] = "Autosexuell"; +$a->strings["Abstinent"] = "Enthaltsam"; +$a->strings["Virgin"] = "Jungfräulich"; +$a->strings["Deviant"] = "Abweichend"; +$a->strings["Fetish"] = "Fetisch"; +$a->strings["Oodles"] = "Unmengen"; +$a->strings["Nonsexual"] = "Sexlos"; +$a->strings["Single"] = "Single"; +$a->strings["Lonely"] = "Einsam"; +$a->strings["Available"] = "Verfügbar"; +$a->strings["Unavailable"] = "Nicht verfügbar"; +$a->strings["Has crush"] = "Verguckt"; +$a->strings["Infatuated"] = "Verknallt"; +$a->strings["Dating"] = "Lerne gerade jemanden kennen"; +$a->strings["Unfaithful"] = "Treulos"; +$a->strings["Sex Addict"] = "Sexabhängig"; +$a->strings["Friends/Benefits"] = "Freunde/Begünstigte"; +$a->strings["Casual"] = "Lose"; +$a->strings["Engaged"] = "Verlobt"; +$a->strings["Married"] = "Verheiratet"; +$a->strings["Imaginarily married"] = "Gewissermaßen verheiratet"; +$a->strings["Partners"] = "Partner"; +$a->strings["Cohabiting"] = "Lebensgemeinschaft"; +$a->strings["Common law"] = "Informelle Ehe"; +$a->strings["Happy"] = "Glücklich"; +$a->strings["Not looking"] = "Nicht Ausschau haltend"; +$a->strings["Swinger"] = "Swinger"; +$a->strings["Betrayed"] = "Betrogen"; +$a->strings["Separated"] = "Getrennt"; +$a->strings["Unstable"] = "Labil"; +$a->strings["Divorced"] = "Geschieden"; +$a->strings["Imaginarily divorced"] = "Gewissermaßen geschieden"; +$a->strings["Widowed"] = "Verwitwet"; +$a->strings["Uncertain"] = "Ungewiss"; +$a->strings["It's complicated"] = "Es ist kompliziert"; +$a->strings["Don't care"] = "Interessiert mich nicht"; +$a->strings["Ask me"] = "Frag mich mal"; +$a->strings["Site Admin"] = "Hub-Administration"; +$a->strings["Address Book"] = "Adressbuch"; +$a->strings["Mood"] = "Laune"; +$a->strings["Poke"] = "Anstupsen"; +$a->strings["Probe"] = "Testen"; +$a->strings["Suggest"] = "Empfehlen"; +$a->strings["Random Channel"] = "Zufälliger Kanal"; +$a->strings["Invite"] = "Einladen"; +$a->strings["Features"] = "Funktionen"; +$a->strings["Language"] = "Sprache"; +$a->strings["Post"] = "Beitrag"; +$a->strings["Profile Photo"] = "Profilfoto"; +$a->strings["Update"] = "Aktualisieren"; +$a->strings["Install"] = "Installieren"; +$a->strings["Purchase"] = "Kaufen"; +$a->strings["Not a valid email address"] = "Ungültige E-Mail-Adresse"; +$a->strings["Your email domain is not among those allowed on this site"] = "Deine E-Mail-Adresse ist dieser Seite nicht erlaubt"; +$a->strings["Your email address is already registered at this site."] = "Deine E-Mail-Adresse ist auf dieser Seite bereits registriert."; +$a->strings["An invitation is required."] = "Eine Einladung wird benötigt"; +$a->strings["Invitation could not be verified."] = "Die Einladung konnte nicht bestätigt werden"; +$a->strings["Please enter the required information."] = "Bitte gib die benötigten Informationen ein."; +$a->strings["Failed to store account information."] = "Speichern der Account-Informationen fehlgeschlagen"; +$a->strings["Registration confirmation for %s"] = "Registrierungsbestätigung für %s"; +$a->strings["Registration request at %s"] = "Registrierungsanfrage auf %s"; +$a->strings["Administrator"] = "Administrator"; +$a->strings["your registration password"] = "Dein Registrierungspasswort"; +$a->strings["Registration details for %s"] = "Registrierungsdetails für %s"; +$a->strings["Account approved."] = "Account bestätigt."; +$a->strings["Registration revoked for %s"] = "Registrierung für %s widerrufen"; +$a->strings["Account verified. Please login."] = "Konto geprüft. Bitte melde Dich an!"; +$a->strings["Click here to upgrade."] = "Klicke hier, um das Upgrade durchzuführen."; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Diese Aktion überschreitet die Grenzen Ihres Abonnements."; +$a->strings["This action is not available under your subscription plan."] = "Diese Aktion ist in Ihrem Abonnement nicht verfügbar."; +$a->strings["channel"] = "Kanal"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s gefällt %2\$ss %3\$s nicht"; +$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s ist jetzt mit %2\$s verbunden"; +$a->strings["%1\$s poked %2\$s"] = "%1\$s stupste %2\$s an"; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s ist %2\$s"; +$a->strings["__ctx:title__ Likes"] = "Gefällt mir"; +$a->strings["__ctx:title__ Dislikes"] = "Gefällt mir nicht"; +$a->strings["__ctx:title__ Agree"] = "Zustimmungen"; +$a->strings["__ctx:title__ Disagree"] = "Ablehnungen"; +$a->strings["__ctx:title__ Abstain"] = "Enthaltungen"; +$a->strings["__ctx:title__ Attending"] = "Zusagen"; +$a->strings["__ctx:title__ Not attending"] = "Absagen"; +$a->strings["__ctx:title__ Might attend"] = "Vielleicht"; +$a->strings["View %s's profile @ %s"] = "%ss Profil auf %s ansehen"; +$a->strings["Categories:"] = "Kategorien:"; +$a->strings["Filed under:"] = "Gespeichert unter:"; +$a->strings["View in context"] = "Im Zusammenhang anschauen"; +$a->strings["remove"] = "lösche"; +$a->strings["Delete Selected Items"] = "Lösche die ausgewählten Elemente"; +$a->strings["View Source"] = "Quelle anzeigen"; +$a->strings["Follow Thread"] = "Unterhaltung folgen"; +$a->strings["View Status"] = "Status ansehen"; +$a->strings["View Photos"] = "Fotos ansehen"; +$a->strings["Matrix Activity"] = "Matrix-Aktivität"; +$a->strings["Edit Contact"] = "Kontakt bearbeiten"; +$a->strings["Send PM"] = "Sende PN"; +$a->strings["%s likes this."] = "%s gefällt das."; +$a->strings["%s doesn't like this."] = "%s gefällt das nicht."; +$a->strings["%2\$d people like this."] = array( + 0 => "%2\$d Person gefällt das.", + 1 => "%2\$d Leuten gefällt das.", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "%2\$d Person gefällt das nicht.", + 1 => "%2\$d Leuten gefällt das nicht.", +); +$a->strings["and"] = "und"; +$a->strings[", and %d other people"] = array( + 0 => "", + 1 => ", und %d andere", +); +$a->strings["%s like this."] = "%s gefällt das."; +$a->strings["%s don't like this."] = "%s gefällt das nicht."; +$a->strings["Visible to everybody"] = "Sichtbar für jeden"; +$a->strings["Please enter a link URL:"] = "Gib eine URL ein:"; +$a->strings["Please enter a video link/URL:"] = "Gib einen Video-Link/URL ein:"; +$a->strings["Please enter an audio link/URL:"] = "Gib einen Audio-Link/URL ein:"; +$a->strings["Tag term:"] = "Schlagwort:"; +$a->strings["Save to Folder:"] = "Speichern in Ordner:"; +$a->strings["Where are you right now?"] = "Wo bist Du jetzt grade?"; +$a->strings["Expires YYYY-MM-DD HH:MM"] = "Verfällt YYYY-MM-DD HH;MM"; +$a->strings["Share"] = "Teilen"; +$a->strings["Page link title"] = "Seitentitel-Link"; +$a->strings["Post as"] = "Veröffentlichen als"; +$a->strings["Upload photo"] = "Foto hochladen"; +$a->strings["upload photo"] = "Foto hochladen"; +$a->strings["Attach file"] = "Datei anhängen"; +$a->strings["attach file"] = "Datei anfügen"; +$a->strings["Insert web link"] = "Link einfügen"; +$a->strings["web link"] = "Web-Link"; +$a->strings["Insert video link"] = "Video-Link einfügen"; +$a->strings["video link"] = "Video-Link"; +$a->strings["Insert audio link"] = "Audio-Link einfügen"; +$a->strings["audio link"] = "Audio-Link"; +$a->strings["Set your location"] = "Standort"; +$a->strings["set location"] = "Standort"; +$a->strings["Toggle voting"] = "Umfragewerkzeug aktivieren"; +$a->strings["Clear browser location"] = "Browser-Standort löschen"; +$a->strings["clear location"] = "Standort löschen"; +$a->strings["Title (optional)"] = "Titel (optional)"; +$a->strings["Categories (optional, comma-separated list)"] = "Kategorien (optional, kommagetrennte Liste)"; +$a->strings["Permission settings"] = "Berechtigungs-Einstellungen"; +$a->strings["permissions"] = "Berechtigungen"; +$a->strings["Public post"] = "Öffentlicher Beitrag"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Beispiel: bob@example.com, mary@example.com"; +$a->strings["Set expiration date"] = "Verfallsdatum"; +$a->strings["OK"] = "Ok"; +$a->strings["Cancel"] = "Abbrechen"; +$a->strings["Discover"] = "Entdecken"; +$a->strings["Imported public streams"] = "Importierte öffentliche Beiträge"; +$a->strings["Commented Order"] = "Neueste Kommentare"; +$a->strings["Sort by Comment Date"] = "Nach Kommentardatum sortiert"; +$a->strings["Posted Order"] = "Neueste Beiträge"; +$a->strings["Sort by Post Date"] = "Nach Beitragsdatum sortiert"; +$a->strings["Posts that mention or involve you"] = "Beiträge mit Beteiligung Deinerseits"; +$a->strings["New"] = "Neu"; +$a->strings["Activity Stream - by date"] = "Activity Stream – nach Datum sortiert"; +$a->strings["Starred"] = "Markiert"; +$a->strings["Favourite Posts"] = "Markierte Beiträge"; +$a->strings["Spam"] = "Spam"; +$a->strings["Posts flagged as SPAM"] = "Nachrichten, die als SPAM markiert wurden"; +$a->strings["Channel"] = "Kanal"; +$a->strings["Status Messages and Posts"] = "Statusnachrichten und Beiträge"; +$a->strings["About"] = "Ãœber"; +$a->strings["Profile Details"] = "Profil-Details"; +$a->strings["Files and Storage"] = "Dateien und Speicher"; +$a->strings["Chatrooms"] = "Chaträume"; +$a->strings["Saved Bookmarks"] = "Gespeicherte Lesezeichen"; +$a->strings["Manage Webpages"] = "Webseiten verwalten"; +$a->strings["__ctx:noun__ Attending"] = array( + 0 => "Zusage", + 1 => "Zusagen", +); +$a->strings["__ctx:noun__ Not Attending"] = array( + 0 => "Absage", + 1 => "Absagen", +); +$a->strings["__ctx:noun__ Undecided"] = array( + 0 => " Unentschlossen", + 1 => "Unentschlossene", +); +$a->strings["__ctx:noun__ Agree"] = array( + 0 => "Zustimmung", + 1 => "Zustimmungen", +); +$a->strings["__ctx:noun__ Disagree"] = array( + 0 => "Ablehnung", + 1 => "Ablehnungen", +); +$a->strings["__ctx:noun__ Abstain"] = array( + 0 => "Enthaltung", + 1 => "Enthaltungen", +); +$a->strings["Embedded content"] = "Eingebetteter Inhalt"; +$a->strings["Embedding disabled"] = "Einbetten ausgeschaltet"; +$a->strings["Can view my normal stream and posts"] = "Kann meine normalen Beiträge sehen"; +$a->strings["Can view my default channel profile"] = "Kann mein Standardprofil sehen"; +$a->strings["Can view my photo albums"] = "Kann meine Fotoalben betrachten"; +$a->strings["Can view my connections"] = "Kann meine Verbindungen sehen"; +$a->strings["Can view my file storage"] = "Kann meine Dateiordner lesen"; +$a->strings["Can view my webpages"] = "Kann meine Webseiten sehen"; +$a->strings["Can send me their channel stream and posts"] = "Kann mir die Beiträge aus seinem/ihrem Kanal schicken"; +$a->strings["Can post on my channel page (\"wall\")"] = "Kann auf meiner Kanal-Seite (\"wall\") Beiträge veröffentlichen"; +$a->strings["Can comment on or like my posts"] = "Darf meine Beiträge kommentieren und mögen/nicht mögen"; +$a->strings["Can send me private mail messages"] = "Kann mir private Nachrichten schicken"; +$a->strings["Can post photos to my photo albums"] = "Kann Fotos in meinen Fotoalben veröffentlichen"; +$a->strings["Can like/dislike stuff"] = "Kann andere Elemente mögen/nicht mögen"; +$a->strings["Profiles and things other than posts/comments"] = "Profile und alles außer Beiträge und Kommentare"; +$a->strings["Can forward to all my channel contacts via post @mentions"] = "Kann an alle meine Kontakte via @-Erwähnung Nachrichten weiterleiten"; +$a->strings["Advanced - useful for creating group forum channels"] = "Fortgeschritten - sinnvoll, um Gruppen-Kanäle/-Foren zu erstellen"; +$a->strings["Can chat with me (when available)"] = "Kann mit mir chatten (wenn verfügbar)"; +$a->strings["Can write to my file storage"] = "Kann in meine Dateiordner schreiben"; +$a->strings["Can edit my webpages"] = "Kann meine Webseiten bearbeiten"; +$a->strings["Can source my public posts in derived channels"] = "Kann meine öffentlichen Beiträge als Quellen für Kanäle verwenden"; +$a->strings["Somewhat advanced - very useful in open communities"] = "Etwas fortgeschritten – sehr nützlich in offenen Gemeinschaften"; +$a->strings["Can administer my channel resources"] = "Kann meine Kanäle administrieren"; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Sehr fortgeschritten. Bearbeite das nur, wenn Du genau weißt, was Du tust"; +$a->strings["Social Networking"] = "Soziales Netzwerk"; +$a->strings["Mostly Public"] = "Weitgehend öffentlich"; +$a->strings["Restricted"] = "Beschränkt"; +$a->strings["Private"] = "Privat"; +$a->strings["Community Forum"] = "Forum"; +$a->strings["Feed Republish"] = "Teilen von Feeds"; +$a->strings["Special Purpose"] = "Für besondere Zwecke"; +$a->strings["Celebrity/Soapbox"] = "Mitteilungs-Kanal (keine Kommentare)"; +$a->strings["Group Repository"] = "Gruppenarchiv"; +$a->strings["Custom/Expert Mode"] = "Benutzerdefiniert/Expertenmodus"; +$a->strings["Some blurb about what to do when you're new here"] = "Ein Hinweis, was man tun kann, wenn man neu hier ist"; +$a->strings["Item not found"] = "Element nicht gefunden"; +$a->strings["Edit Block"] = "Block bearbeiten"; +$a->strings["Delete block?"] = "Block löschen?"; +$a->strings["Insert YouTube video"] = "YouTube-Video einfügen"; +$a->strings["Insert Vorbis [.ogg] video"] = "Vorbis [.ogg]-Video einfügen"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Vorbis [.ogg]-Audio einfügen"; +$a->strings["Delete Block"] = "Block löschen"; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Du hast %1$.0f von maximal %2$.0f erlaubten Kanälen eingerichtet."; +$a->strings["Create a new channel"] = "Neuen Kanal anlegen"; +$a->strings["Current Channel"] = "Aktueller Kanal"; +$a->strings["Switch to one of your channels by selecting it."] = "Wechsle zu einem Deiner Kanäle, indem Du auf ihn klickst."; +$a->strings["Default Channel"] = "Standard Kanal"; +$a->strings["Make Default"] = "Zum Standard machen"; +$a->strings["%d new messages"] = "%d neue Nachrichten"; +$a->strings["%d new introductions"] = "%d neue Vorstellungen"; +$a->strings["Xchan Lookup"] = "Xchan-Suche"; +$a->strings["Lookup xchan beginning with (or webbie): "] = "Nach xchans oder Webbies (Kanal-Adressen) suchen, die wie folgt beginnen:"; +$a->strings["Not found."] = "Nicht gefunden."; +$a->strings["Authorize application connection"] = "Zugriff für die Anwendung autorisieren"; +$a->strings["Return to your app and insert this Securty Code:"] = "Trage folgenden Sicherheitscode in der Anwendung ein:"; +$a->strings["Please login to continue."] = "Zum Weitermachen, bitte einloggen."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Möchtest Du dieser Anwendung erlauben, Deine Nachrichten und Kontakte abzurufen und/oder neue Nachrichten für Dich zu erstellen?"; +$a->strings["Yes"] = "Ja"; +$a->strings["No"] = "Nein"; +$a->strings["Block Name"] = "Block-Name"; +$a->strings["Could not access contact record."] = "Konnte nicht auf den Kontakteintrag zugreifen."; +$a->strings["Could not locate selected profile."] = "Gewähltes Profil nicht gefunden."; +$a->strings["Connection updated."] = "Verbindung aktualisiert."; +$a->strings["Failed to update connection record."] = "Konnte den Verbindungseintrag nicht aktualisieren."; +$a->strings["is now connected to"] = "ist jetzt verbunden mit"; +$a->strings["Could not access address book record."] = "Konnte nicht auf den Adressbuch-Eintrag zugreifen."; +$a->strings["Refresh failed - channel is currently unavailable."] = "Aktualisierung fehlgeschlagen – der Kanal ist im Moment nicht erreichbar."; +$a->strings["Channel has been unblocked"] = "Kanal nicht mehr blockiert"; +$a->strings["Channel has been blocked"] = "Kanal blockiert"; +$a->strings["Unable to set address book parameters."] = "Konnte die Adressbuch-Parameter nicht setzen."; +$a->strings["Channel has been unignored"] = "Kanal wird nicht mehr ignoriert"; +$a->strings["Channel has been ignored"] = "Kanal wird ignoriert"; +$a->strings["Channel has been unarchived"] = "Kanal wurde aus dem Archiv zurück geholt"; +$a->strings["Channel has been archived"] = "Kanal wurde archiviert"; +$a->strings["Channel has been unhidden"] = "Kanal wird nicht mehr versteckt"; +$a->strings["Channel has been hidden"] = "Kanal wurde versteckt"; +$a->strings["Channel has been approved"] = "Kanal wurde zugelassen"; +$a->strings["Channel has been unapproved"] = "Zulassung des Kanals entfernt"; +$a->strings["Connection has been removed."] = "Verbindung wurde gelöscht."; +$a->strings["View %s's profile"] = "%ss Profil ansehen"; +$a->strings["Refresh Permissions"] = "Zugriffsrechte neu laden"; +$a->strings["Fetch updated permissions"] = "Aktualisierte Zugriffsrechte abfragen"; +$a->strings["Recent Activity"] = "Kürzliche Aktivitäten"; +$a->strings["View recent posts and comments"] = "Betrachte die neuesten Beiträge und Kommentare"; +$a->strings["Unblock"] = "Freigeben"; +$a->strings["Block"] = "Blockieren"; +$a->strings["Block (or Unblock) all communications with this connection"] = "Jegliche Kommunikation mit dieser Verbindung blockieren/zulassen"; +$a->strings["Unignore"] = "Nicht ignorieren"; +$a->strings["Ignore"] = "Ignorieren"; +$a->strings["Ignore (or Unignore) all inbound communications from this connection"] = "Jegliche eingehende Kommunikation von dieser Verbindung ignorieren/zulassen"; +$a->strings["Unarchive"] = "Aus Archiv zurückholen"; +$a->strings["Archive"] = "Archivieren"; +$a->strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = "Verbindung archivieren/aus dem Archiv zurückholen (Archiv = Kanal als erloschen markieren, aber die Beiträge behalten)"; +$a->strings["Unhide"] = "Wieder sichtbar machen"; +$a->strings["Hide"] = "Verstecken"; +$a->strings["Hide or Unhide this connection from your other connections"] = "Diese Verbindung vor anderen Verbindungen verstecken/zeigen"; +$a->strings["Delete this connection"] = "Verbindung löschen"; +$a->strings["Approve this connection"] = "Verbindung genehmigen"; +$a->strings["Accept connection to allow communication"] = "Akzeptiere die Verbindung, um Kommunikation zu ermöglichen"; +$a->strings["Connections: settings for %s"] = "Verbindungseinstellungen für %s"; +$a->strings["Apply these permissions automatically"] = "Diese Berechtigungen automatisch anwenden"; +$a->strings["Apply the permissions indicated on this page to all new connections."] = "Wende die auf dieser Seite gewählten Berechtigungen auf alle neuen Verbindungen an."; +$a->strings["Slide to adjust your degree of friendship"] = "Verschieben, um den Grad der Freundschaft zu einzustellen"; +$a->strings["Rating (this information is public)"] = "Bewertung (öffentlich sichtbar)"; +$a->strings["Optionally explain your rating (this information is public)"] = "Optional kannst du deine Bewertung erklären (öffentlich sichtbar)"; +$a->strings["Default permissions for your channel type have (just) been applied. They have not yet been submitted. Please review the permissions on this page and make any desired changes at this time. This new connection may not be able to communicate with you until you submit this page, which will install and apply the selected permissions."] = "Die voreingestellten Zugriffsrechte der Kategorie Deines Kanals sind hier zu sehen, wurden aber noch nicht gespeichert. Bitte sieh Dir die Zugriffsrechte auf dieser Seite an und ändere sie, wenn Du willst. Dieser Kontakt kann evtl. nicht mit Dir kommunizieren, bevor Du nicht auf dieser Seite auf „Senden“ geklickt hast – erst dieser Klick speichert die gewünschten Zugriffsrechte."; +$a->strings["inherited"] = "geerbt"; +$a->strings["Connection has no individual permissions!"] = "Diese Verbindung hat keine individuellen Zugriffsrechte!"; +$a->strings["This may be appropriate based on your privacy settings, though you may wish to review the \"Advanced Permissions\"."] = "Abhängig von Deinen Privatsphäre-Einstellungen könnte das passen, eventuell solltest Du aber die „Zugriffsrechte für Fortgeschrittene“ überprüfen."; +$a->strings["Profile Visibility"] = "Sichtbarkeit des Profils"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Bitte wähle ein Profil, das wir %s zeigen sollen, wenn Deine Profilseite über eine verifizierte Verbindung aufgerufen wird."; +$a->strings["Contact Information / Notes"] = "Kontaktinformationen / Notizen"; +$a->strings["Edit contact notes"] = "Kontaktnotizen bearbeiten"; +$a->strings["Their Settings"] = "Deren Einstellungen"; +$a->strings["My Settings"] = "Meine Einstellungen"; +$a->strings["Default permissions for this channel type have (just) been applied. They have not been saved and there are currently no stored default permissions. Please review/edit the applied settings and click [Submit] to finalize."] = "Die voreingestellten Zugriffsrechte der Kategorie Deines Kanals sind hier zu sehen, wurden aber noch nicht gespeichert, und Du hast keine Voreinstellungen für die Zugriffsrechte von Verbindungen angelegt. Bitte sieht Dir die Einstellungen an, ändere sie bei Bedarf und klicke [Senden], um den Vorgang abzuschließen."; +$a->strings["Clear/Disable Automatic Permissions"] = "Automatische Berechtigungen abschalten/entfernen"; +$a->strings["Forum Members"] = "Forum Mitglieder"; +$a->strings["Soapbox"] = "Marktschreier"; +$a->strings["Full Sharing (typical social network permissions)"] = "Vollumfängliches Teilen (übliche Berechtigungen in sozialen Netzwerken)"; +$a->strings["Cautious Sharing "] = "Vorsichtiges Teilen"; +$a->strings["Follow Only"] = "Nur folgen"; +$a->strings["Individual Permissions"] = "Individuelle Zugriffsrechte"; +$a->strings["Some permissions may be inherited from your channel privacy settings, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect."] = "Einige Berechtigungen werden von den globalen Sicherheits- und Privatsphäre-Einstellungen dieses Kanals geerbt, die eine höhere Priorität haben als die Einstellungen bei einer Verbindung. Werden geerbte Einstellungen hier geändert, hat das keine Auswirkungen."; +$a->strings["Advanced Permissions"] = "Zugriffsrechte für Fortgeschrittene"; +$a->strings["Simple Permissions (select one and submit)"] = "Einfache Berechtigungs-Einstellungen (wähle eine aus und klicke auf Senden)"; +$a->strings["Visit %s's profile - %s"] = "%ss Profil besuchen - %s"; +$a->strings["Block/Unblock contact"] = "Kontakt blockieren/freigeben"; +$a->strings["Ignore contact"] = "Kontakt ignorieren"; +$a->strings["Repair URL settings"] = "URL-Einstellungen reparieren"; +$a->strings["View conversations"] = "Unterhaltungen anzeigen"; +$a->strings["Delete contact"] = "Kontakt löschen"; +$a->strings["Last update:"] = "Letzte Aktualisierung:"; +$a->strings["Update public posts"] = "Öffentliche Beiträge aktualisieren"; +$a->strings["Update now"] = "Jetzt aktualisieren"; +$a->strings["Currently blocked"] = "Derzeit blockiert"; +$a->strings["Currently ignored"] = "Derzeit ignoriert"; +$a->strings["Currently archived"] = "Derzeit archiviert"; +$a->strings["Currently pending"] = "Derzeit anstehend"; +$a->strings["Red Matrix - "The Network""] = "RedMatrix – "Das Netzwerk""; +$a->strings["Welcome to %s"] = "Willkommen auf %s"; +$a->strings["Continue"] = "Fortfahren"; +$a->strings["Premium Channel Setup"] = "Premium-Kanal-Einrichtung"; +$a->strings["Enable premium channel connection restrictions"] = "Einschränkungen für einen Premium-Kanal aktivieren"; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Bitte gib Deine Nutzungsbedingungen ein, z.B. Paypal-Quittung, Richtlinien etc."; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Unter Umständen sind weitere Schritte oder die Bestätigung der folgenden Bedingungen vor dem Verbinden mit diesem Kanal nötig."; +$a->strings["Potential connections will then see the following text before proceeding:"] = "Potentielle Kontakte werden den folgenden Text sehen, bevor fortgefahren wird:"; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "Indem ich fortfahre, bestätige ich die Erfüllung aller Anweisungen auf dieser Seite."; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(Der Kanal-Besitzer hat keine speziellen Anweisungen hinterlegt.)"; +$a->strings["Restricted or Premium Channel"] = "Eingeschränkter oder Premium-Kanal"; +$a->strings["Item is not editable"] = "Element kann nicht bearbeitet werden."; +$a->strings["Edit post"] = "Bearbeite Beitrag"; +$a->strings["Delete item?"] = "Eintrag löschen?"; +$a->strings["Item not available."] = "Element nicht verfügbar."; +$a->strings["Fetching URL returns error: %1\$s"] = "Abrufen der URL gab einen Fehler zurück: %1\$s"; +$a->strings["RedMatrix channel"] = "RedMatrix-Kanal"; +$a->strings["Image uploaded but image cropping failed."] = "Bild hochgeladen, aber das Zurechtschneiden schlug fehl."; +$a->strings["Image resize failed."] = "Bild-Anpassung fehlgeschlagen."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Leere den Browser Cache oder nutze Umschalten-Neu Laden, falls das neue Foto nicht sofort angezeigt wird."; +$a->strings["Image exceeds size limit of %d"] = "Bild ist größer als das Limit von %d"; +$a->strings["Unable to process image."] = "Kann Bild nicht verarbeiten."; +$a->strings["Photo not available."] = "Foto nicht verfügbar."; +$a->strings["Upload File:"] = "Datei hochladen:"; +$a->strings["Select a profile:"] = "Wähle ein Profil:"; +$a->strings["Upload Profile Photo"] = "Lade neues Profilfoto hoch"; +$a->strings["or"] = "oder"; +$a->strings["skip this step"] = "diesen Schritt überspringen"; +$a->strings["select a photo from your photo albums"] = "ein Foto aus meinen Fotoalben"; +$a->strings["Crop Image"] = "Bild zuschneiden"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Bitte schneide das Bild für eine optimale Anzeige passend zu."; +$a->strings["Done Editing"] = "Bearbeitung fertigstellen"; +$a->strings["Image uploaded successfully."] = "Bild erfolgreich hochgeladen."; +$a->strings["Image upload failed."] = "Hochladen des Bilds fehlgeschlagen."; +$a->strings["Image size reduction [%s] failed."] = "Reduzierung der Bildgröße [%s] fehlgeschlagen."; +$a->strings["Invalid item."] = "Ungültiges Element."; +$a->strings["Channel not found."] = "Kanal nicht gefunden."; +$a->strings["Page not found."] = "Seite nicht gefunden."; +$a->strings["No such group"] = "Sammlung nicht gefunden"; +$a->strings["Search Results For:"] = "Suchergebnisse für:"; +$a->strings["Collection is empty"] = "Sammlung ist leer"; +$a->strings["Collection: "] = "Sammlung:"; +$a->strings["Connection: "] = "Verbindung:"; +$a->strings["Invalid connection."] = "Ungültige Verbindung."; +$a->strings["Event can not end before it has started."] = "Termin-Ende liegt vor dem Beginn."; +$a->strings["Unable to generate preview."] = "Vorschau konnte nicht erzeugt werden."; +$a->strings["Event title and start time are required."] = "Titel und Startzeit des Termins sind erforderlich."; +$a->strings["Event not found."] = "Termin nicht gefunden."; +$a->strings["l, F j"] = "l, j. F"; +$a->strings["Edit event"] = "Termin bearbeiten"; +$a->strings["Delete event"] = "Termin löschen"; +$a->strings["Create New Event"] = "Neuen Termin erstellen"; +$a->strings["Previous"] = "Voriges"; +$a->strings["Next"] = "Nächste"; +$a->strings["Export"] = "Exportieren"; +$a->strings["Event removed"] = "Termin gelöscht"; +$a->strings["Failed to remove event"] = "Termin konnte nicht gelöscht werden"; +$a->strings["Event details"] = "Termin-Details"; +$a->strings["Starting date and Title are required."] = "Startdatum und Titel sind erforderlich."; +$a->strings["Categories (comma-separated list)"] = "Kategorien (Kommagetrennte Liste)"; +$a->strings["Event Starts:"] = "Termin beginnt:"; +$a->strings["Finish date/time is not known or not relevant"] = "Ende Datum/Zeit sind unbekannt oder unwichtig"; +$a->strings["Event Finishes:"] = "Termin endet:"; +$a->strings["Adjust for viewer timezone"] = "An die Zeitzone des Betrachters anpassen"; +$a->strings["Important for events that happen in a particular place. Not practical for global holidays."] = "Wichtig für Veranstaltungen die an bestimmten Orten stattfinden. Nicht sinnvoll für globale Feiertage / Ferien."; +$a->strings["Description:"] = "Beschreibung:"; +$a->strings["Title:"] = "Titel:"; +$a->strings["Share this event"] = "Den Termin teilen"; +$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s folgt nun %2\$ss %3\$s"; +$a->strings["Public Sites"] = "Öffentliche Server"; +$a->strings["The listed sites allow public registration into the Red Matrix. All sites in the matrix are interlinked so membership on any of them conveys membership in the matrix as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = "Die hier aufgeführten Server erlauben Dir, einen Account in der Red-Matrix anzulegen. Alle Server der Matrix sind miteinander verbunden, so dass die Mitgliedschaft auf einem Server eine Verbindung zu beliebigen anderen Servern der Matrix ermöglicht. Es könnte sein, dass einige dieser Server kostenpflichtig sind oder abgestufte, je nach Umfang kostenpflichtige Mitgliedschaften anbieten. Auf den jeweiligen Seiten könnten nähere Details dazu stehen."; +$a->strings["Rate this hub"] = "Bewerte diesen Hub"; +$a->strings["Site URL"] = "Server-URL"; +$a->strings["Access Type"] = "Zugangstyp"; +$a->strings["Registration Policy"] = "Registrierungsrichtlinien"; +$a->strings["Location"] = "Ort"; +$a->strings["View hub ratings"] = "Bewertungen dieses Hubs ansehen"; +$a->strings["Rate"] = "Bewerten"; +$a->strings["View ratings"] = "Bewertungen ansehen"; +$a->strings["Name is required"] = "Name ist erforderlich"; +$a->strings["Key and Secret are required"] = "Schlüssel und Geheimnis werden benötigt"; +$a->strings["Diaspora Policy Settings updated."] = "Diaspora-Einstellungen aktualisiert."; +$a->strings["Passwords do not match. Password unchanged."] = "Kennwörter stimmen nicht überein. Kennwort nicht verändert."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Leere Kennwörter sind nicht erlaubt. Kennwort nicht verändert."; +$a->strings["Password changed."] = "Kennwort geändert."; +$a->strings["Password update failed. Please try again."] = "Kennwortänderung fehlgeschlagen. Bitte versuche es noch einmal."; +$a->strings["Not valid email."] = "Keine gültige E-Mail Adresse."; +$a->strings["Protected email address. Cannot change to that email."] = "Geschützte E-Mail Adresse. Diese kann nicht verändert werden."; +$a->strings["System failure storing new email. Please try again."] = "Systemfehler während des Speicherns der neuen Mail. Bitte versuche es noch einmal."; +$a->strings["Settings updated."] = "Einstellungen aktualisiert."; +$a->strings["Add application"] = "Anwendung hinzufügen"; +$a->strings["Name of application"] = "Name der Anwendung"; +$a->strings["Consumer Key"] = "Consumer Key"; +$a->strings["Automatically generated - change if desired. Max length 20"] = "Automatisch erzeugt – ändern, falls erwünscht. Maximale Länge 20"; +$a->strings["Consumer Secret"] = "Consumer Secret"; +$a->strings["Redirect"] = "Umleitung"; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = "Umleitungs-URl – lasse das leer, solange Deine Anwendung es nicht explizit erfordert"; +$a->strings["Icon url"] = "Symbol-URL"; +$a->strings["Optional"] = "Optional"; +$a->strings["You can't edit this application."] = "Diese Anwendung kann nicht bearbeitet werden."; +$a->strings["Connected Apps"] = "Verbundene Apps"; +$a->strings["Client key starts with"] = "Client Key beginnt mit"; +$a->strings["No name"] = "Kein Name"; +$a->strings["Remove authorization"] = "Authorisierung aufheben"; +$a->strings["No feature settings configured"] = "Keine Funktions-Einstellungen konfiguriert"; +$a->strings["Feature Settings"] = "Funktions-Einstellungen"; +$a->strings["Diaspora Policy Settings"] = "Diaspora-Einstellungen"; +$a->strings["Allow any Diaspora member to comment on your public posts."] = "Allen Diaspora-Mitgliedern erlauben, Deine öffentlichen Beiträge zu kommentieren."; +$a->strings["Submit Diaspora Policy Settings"] = "Diaspora-Einstellungen speichern"; +$a->strings["Account Settings"] = "Konto-Einstellungen"; +$a->strings["Password Settings"] = "Kennwort-Einstellungen"; +$a->strings["New Password:"] = "Neues Passwort:"; +$a->strings["Confirm:"] = "Bestätigen:"; +$a->strings["Leave password fields blank unless changing"] = "Lasse die Passwort-Felder leer, außer Du möchtest das Passwort ändern"; +$a->strings["Email Address:"] = "Email Adresse:"; +$a->strings["Remove Account"] = "Konto entfernen"; +$a->strings["Remove this account from this server including all its channels"] = "Lösche dieses Konto einschließlich aller zugehörigen Kanäle von diesem Server"; +$a->strings["Warning: This action is permanent and cannot be reversed."] = "Achtung: Diese Aktion ist endgültig und kann nicht rückgängig gemacht werden."; +$a->strings["Off"] = "Aus"; +$a->strings["On"] = "An"; +$a->strings["Additional Features"] = "Zusätzliche Funktionen"; +$a->strings["Connector Settings"] = "Connector-Einstellungen"; +$a->strings["No special theme for mobile devices"] = "Keine spezielle Theme für mobile Geräte"; +$a->strings["%s - (Experimental)"] = "%s – (experimentell)"; +$a->strings["mobile"] = "mobil"; +$a->strings["Display Settings"] = "Anzeige-Einstellungen"; +$a->strings["Display Theme:"] = "Anzeige-Theme:"; +$a->strings["Mobile Theme:"] = "Mobile Theme:"; +$a->strings["Enable user zoom on mobile devices"] = "Zoom auf Mobilgeräten aktivieren"; +$a->strings["Update browser every xx seconds"] = "Browser alle xx Sekunden aktualisieren"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Minimum 10 Sekunden, kein Maximum"; +$a->strings["Maximum number of conversations to load at any time:"] = "Maximale Anzahl von Unterhaltungen, die auf einmal geladen werden sollen:"; +$a->strings["Maximum of 100 items"] = "Maximum: 100 Beiträge"; +$a->strings["Don't show emoticons"] = "Emoticons nicht anzeigen"; +$a->strings["Link post titles to source"] = "Beitragstitel zum Originalbeitrag verlinken"; +$a->strings["System Page Layout Editor - (advanced)"] = "System-Seitenlayout-Editor (für Experten)"; +$a->strings["Use blog/list mode on channel page"] = "Blog-/Listenmodus auf der Kanalseite verwenden"; +$a->strings["(comments displayed separately)"] = "(Kommentare werden separat angezeigt)"; +$a->strings["Use blog/list mode on matrix page"] = "Blog-/Listenmodus auf der Matrixseite verwenden"; +$a->strings["Channel page max height of content (in pixels)"] = "Maximale Höhe von Beitragsblöcken auf der Kanalseite (in Pixeln)"; +$a->strings["click to expand content exceeding this height"] = "Blöcke, deren Inhalt diese Höhe überschreitet, können per Klick vergrößert werden."; +$a->strings["Matrix page max height of content (in pixels)"] = "Maximale Höhe von Beitragsblöcken auf der Matrixseite (in Pixeln)"; +$a->strings["Nobody except yourself"] = "Niemand außer Dir selbst"; +$a->strings["Only those you specifically allow"] = "Nur die, denen Du es explizit erlaubst"; +$a->strings["Approved connections"] = "Angenommene Verbindungen"; +$a->strings["Any connections"] = "Beliebige Verbindungen"; +$a->strings["Anybody on this website"] = "Jeder auf dieser Website"; +$a->strings["Anybody in this network"] = "Alle Red-Nutzer"; +$a->strings["Anybody authenticated"] = "Jeder authentifizierte"; +$a->strings["Anybody on the internet"] = "Jeder im Internet"; +$a->strings["Publish your default profile in the network directory"] = "Standard-Profil im Netzwerk-Verzeichnis veröffentlichen"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Dürfen wir Dich neuen Mitgliedern als potentiellen Kontakt vorschlagen?"; +$a->strings["Your channel address is"] = "Deine Kanal-Adresse lautet"; +$a->strings["Channel Settings"] = "Kanal-Einstellungen"; +$a->strings["Basic Settings"] = "Grundeinstellungen"; +$a->strings["Your Timezone:"] = "Ihre Zeitzone:"; +$a->strings["Default Post Location:"] = "Standardstandort:"; +$a->strings["Geographical location to display on your posts"] = "Geografischer Ort, der bei Deinen Beiträgen angezeigt werden soll"; +$a->strings["Use Browser Location:"] = "Standort des Browsers verwenden:"; +$a->strings["Adult Content"] = "Nicht jugendfreie Inhalte"; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = "Dieser Kanal veröffentlicht regelmäßig Inhalte, die für Minderjährige ungeeignet sind. (Bitte markiere solche Inhalte mit dem Schlagwort #NSFW)"; +$a->strings["Security and Privacy Settings"] = "Sicherheits- und Datenschutz-Einstellungen"; +$a->strings["Your permissions are already configured. Click to view/adjust"] = "Deine Zugriffsrechte sind schon konfiguriert. Klicke hier, um sie zu betrachten oder zu ändern"; +$a->strings["Hide my online presence"] = "Meine Online-Präsenz verbergen"; +$a->strings["Prevents displaying in your profile that you are online"] = "Verhindert die Anzeige Deines Online-Status in deinem Profil"; +$a->strings["Simple Privacy Settings:"] = "Einfache Privatsphäre-Einstellungen"; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = "Komplett offen – extrem ungeschützt (mit großer Vorsicht verwenden!)"; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = "Typisch – Standard öffentlich, Privatsphäre, wo sie erwünscht ist (ähnlich den Einstellungen in sozialen Netzwerken, aber mit besser geschützter Privatsphäre)"; +$a->strings["Private - default private, never open or public"] = "Privat – Standard privat, nie offen oder öffentlich"; +$a->strings["Blocked - default blocked to/from everybody"] = "Blockiert – Alle standardmäßig blockiert"; +$a->strings["Allow others to tag your posts"] = "Erlaube anderen, Deine Beiträge zu verschlagworten"; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = "Wird oft von der Community genutzt um rückwirkend anstößigen Inhalt zu markieren"; +$a->strings["Advanced Privacy Settings"] = "Fortgeschrittene Privatsphäre-Einstellungen"; +$a->strings["Expire other channel content after this many days"] = "Den Inhalt anderer Kanäle nach dieser Anzahl Tage verfallen lassen"; +$a->strings["0 or blank prevents expiration"] = "0 oder kein Inhalt verhindern das Verfallen"; +$a->strings["Maximum Friend Requests/Day:"] = "Maximale Kontaktanfragen pro Tag:"; +$a->strings["May reduce spam activity"] = "Kann die Spam-Aktivität verringern"; +$a->strings["Default Post Permissions"] = "Standardeinstellungen für Beitrags-Zugriffsrechte"; +$a->strings["(click to open/close)"] = "(zum öffnen/schließen anklicken)"; +$a->strings["Channel permissions category:"] = "Zugriffsrechte-Kategorie des Kanals:"; +$a->strings["Maximum private messages per day from unknown people:"] = "Maximale Anzahl privater Nachrichten pro Tag von unbekannten Leuten:"; +$a->strings["Useful to reduce spamming"] = "Nützlich, um Spam zu verringern"; +$a->strings["Notification Settings"] = "Benachrichtigungs-Einstellungen"; +$a->strings["By default post a status message when:"] = "Sende standardmäßig Status-Nachrichten, wenn:"; +$a->strings["accepting a friend request"] = "Du eine Verbindungsanfrage annimmst"; +$a->strings["joining a forum/community"] = "Du einem Forum beitrittst"; +$a->strings["making an interesting profile change"] = "Du eine interessante Änderung an Deinem Profil vornimmst"; +$a->strings["Send a notification email when:"] = "Eine E-Mail-Benachrichtigung senden, wenn:"; +$a->strings["You receive a connection request"] = "Du eine Verbindungsanfrage erhältst"; +$a->strings["Your connections are confirmed"] = "Eine Verbindung bestätigt wurde"; +$a->strings["Someone writes on your profile wall"] = "Jemand auf Deine Pinnwand schreibt"; +$a->strings["Someone writes a followup comment"] = "Jemand einen Beitrag kommentiert"; +$a->strings["You receive a private message"] = "Du eine private Nachricht erhältst"; +$a->strings["You receive a friend suggestion"] = "Du einen Kontaktvorschlag erhältst"; +$a->strings["You are tagged in a post"] = "Du in einem Beitrag erwähnt wurdest"; +$a->strings["You are poked/prodded/etc. in a post"] = "Du in einem Beitrag angestupst/geknufft/o.ä. wurdest"; +$a->strings["Show visual notifications including:"] = "Visuelle Benachrichtigungen anzeigen für:"; +$a->strings["Unseen matrix activity"] = "Ungesehene Matrix-Aktivität"; +$a->strings["Unseen channel activity"] = "Ungesehene Kanal-Aktivität"; +$a->strings["Unseen private messages"] = "Ungelesene persönliche Nachrichten"; +$a->strings["Recommended"] = "Empfohlen"; +$a->strings["Upcoming events"] = "Baldige Termine"; +$a->strings["Events today"] = "Heutige Termine"; +$a->strings["Upcoming birthdays"] = "Baldige Geburtstage"; +$a->strings["Not available in all themes"] = "Nicht in allen Themes verfügbar"; +$a->strings["System (personal) notifications"] = "System – (persönliche) Benachrichtigungen"; +$a->strings["System info messages"] = "System – Info-Nachrichten"; +$a->strings["System critical alerts"] = "System – kritische Warnungen"; +$a->strings["New connections"] = "Neue Verbindungen"; +$a->strings["System Registrations"] = "System – Registrierungen"; +$a->strings["Also show new wall posts, private messages and connections under Notices"] = "Zeigt neue Pinnwand-Nachrichten, private Nachrichten und Verbindungen unter Benachrichtigungen an"; +$a->strings["Notify me of events this many days in advance"] = "Benachrichtige mich zu Terminen so viele Tage im Voraus"; +$a->strings["Must be greater than 0"] = "Muss größer als 0 sein"; +$a->strings["Advanced Account/Page Type Settings"] = "Erweiterte Account- und Seitenart-Einstellungen"; +$a->strings["Change the behaviour of this account for special situations"] = "Ändere das Verhalten dieses Accounts unter speziellen Umständen"; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = "Aktiviere den Expertenmodus (unter Settings > Zusätzliche Funktionen), um hier Einstellungen vorzunehmen!"; +$a->strings["Miscellaneous Settings"] = "Sonstige Einstellungen"; +$a->strings["Personal menu to display in your channel pages"] = "Eigenes Menü zur Anzeige auf den Seiten deines Kanals"; +$a->strings["Remove this channel"] = "Diesen Kanal löschen"; +$a->strings["RedMatrix - Guests: Username: {your email address}, Password: +++"] = "RedMatrix – Gäste: Username: {Deine E-Mail-Adresse}, Passwort: +++"; +$a->strings["Tag removed"] = "Schlagwort entfernt"; +$a->strings["Remove Item Tag"] = "Schlagwort entfernen"; +$a->strings["Select a tag to remove: "] = "Schlagwort zum Entfernen auswählen:"; +$a->strings["Remove"] = "Entferne"; +$a->strings["Collection created."] = "Sammlung erstellt."; +$a->strings["Could not create collection."] = "Sammlung kann nicht erstellt werden."; +$a->strings["Collection updated."] = "Sammlung aktualisiert."; +$a->strings["Create a collection of channels."] = "Erstelle eine Sammlung von Kanälen."; +$a->strings["Collection Name: "] = "Name der Sammlung:"; +$a->strings["Members are visible to other channels"] = "Mitglieder sind sichtbar für andere Kanäle"; +$a->strings["Collection removed."] = "Sammlung gelöscht."; +$a->strings["Unable to remove collection."] = "Löschen der Sammlung nicht möglich."; +$a->strings["Collection Editor"] = "Sammlung-Editor"; +$a->strings["Members"] = "Mitglieder"; +$a->strings["All Connected Channels"] = "Alle verbundenen Kanäle"; +$a->strings["Click on a channel to add or remove."] = "Wähle einen Kanal zum hinzufügen oder entfernen aus."; +$a->strings["Version %s"] = "Version %s"; +$a->strings["Installed plugins/addons/apps:"] = "Installierte Plugins/Addons/Apps"; +$a->strings["No installed plugins/addons/apps"] = "Keine installierten Plugins/Addons/Apps"; +$a->strings["Red"] = "Red"; +$a->strings["This is a hub of the Red Matrix - a global cooperative network of decentralized privacy enhanced websites."] = "Dieser Hub ist Teil der RedMatrix – eines globalen, kooperativen Netzwerks aus dezentralen Websites, die Rücksicht auf Deine Privatsphäre nehmen."; +$a->strings["Tag: "] = "Schlagwort: "; +$a->strings["Last background fetch: "] = "Letzter Hintergrundabruf:"; +$a->strings["Running at web location"] = "Erreichbar unter der Web-Adresse"; +$a->strings["Please visit RedMatrix.me to learn more about the Red Matrix."] = "Bitte besuchen Sie RedMatrix.me, um mehr über RedMatrix zu erfahren."; +$a->strings["Bug reports and issues: please visit"] = "Probleme oder Fehler gefunden? Bitte besuche"; +$a->strings["Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot com"] = "Vorschläge, Lob, usw.: E-Mail an 'redmatrix' at librelist - dot - com"; +$a->strings["Site Administrators"] = "Administratoren"; +$a->strings["Help:"] = "Hilfe:"; +$a->strings["Not Found"] = "Nicht gefunden"; +$a->strings["Red Matrix Server - Setup"] = "Red Matrix Server - Installation"; +$a->strings["Could not connect to database."] = "Kann nicht mit der Datenbank verbinden."; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "Konnte die angegebene Webseiten-URL nicht erreichen. Möglicherweise ein Problem mit dem SSL-Zertifikat oder dem DNS."; +$a->strings["Could not create table."] = "Kann Tabelle nicht erstellen."; +$a->strings["Your site database has been installed."] = "Die Datenbank Deines Hubs wurde installiert."; +$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Möglicherweise musst Du die Datei install/schema_xxx.sql manuell mit Hilfe eines Datenkbank-Clients importieren."; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Lies die Datei \"install/INSTALL.txt\"."; +$a->strings["System check"] = "Systemprüfung"; +$a->strings["Check again"] = "Bitte nochmal prüfen"; +$a->strings["Database connection"] = "Datenbank Verbindung"; +$a->strings["In order to install Red Matrix we need to know how to connect to your database."] = "Um die Red-Matrix installieren zu können, müssen wir wissen, wie wir eine Verbindung zu Deiner Datenbank aufbauen können."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Bitte kontaktiere Deinen Hosting-Provider oder Administrator, falls Du Fragen zu diesen Einstellungen hast."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Die Datenbank, die Du weiter unten angibst, sollte bereits existieren. Sollte das noch nicht der Fall sein, erzeuge sie bitte bevor Du fortfährst."; +$a->strings["Database Server Name"] = "Datenbank-Servername"; +$a->strings["Default is localhost"] = "Standard ist localhost"; +$a->strings["Database Port"] = "Datenbank-Port"; +$a->strings["Communication port number - use 0 for default"] = "Port-Nummer für die Kommunikation – verwende 0 für die Standardeinstellung"; +$a->strings["Database Login Name"] = "Datenbank-Benutzername"; +$a->strings["Database Login Password"] = "Datenbank-Kennwort"; +$a->strings["Database Name"] = "Datenbank-Name"; +$a->strings["Database Type"] = "Datenbanktyp"; +$a->strings["Site administrator email address"] = "E-Mail Adresse des Seiten-Administrators"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "Die E-Mail-Adresse Deines Accounts muss dieser Adresse entsprechen, damit Du Zugriff zur Administrations-Seite erhältst."; +$a->strings["Website URL"] = "Server-URL"; +$a->strings["Please use SSL (https) URL if available."] = "Nutze wenn möglich eine SSL-URL (https)."; +$a->strings["Please select a default timezone for your website"] = "Standard-Zeitzone für Deinen Server"; +$a->strings["Site settings"] = "Seiteneinstellungen"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Konnte die Kommandozeilen-Version von PHP nicht im PATH des Web-Servers finden."; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Ohne Kommandozeilen-Version von PHP auf dem Server wirst Du nicht in der Lage sein, Hintergrundprozesse via cron auszuführen."; +$a->strings["PHP executable path"] = "PHP Pfad zu ausführbarer Datei"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Gib den vollen Pfad zum PHP-Interpreter an. Du kannst dieses Feld frei lassen und mit der Installation fortfahren."; +$a->strings["Command line PHP"] = "PHP Befehlszeile"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "Bei der Kommandozeilen-Version von PHP auf Deinem System ist \"register_argc_argv\" nicht aktiviert."; +$a->strings["This is required for message delivery to work."] = "Das wird benötigt, damit die Auslieferung von Nachrichten funktioniert."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Fehler: Die „openssl_pkey_new“-Funktion auf diesem System ist nicht in der Lage, Schlüssel für die Verschlüsselung zu erzeugen."; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Wenn Du Windows verwendest, findest Du unter http://www.php.net/manual/en/openssl.installation.php eine Installationsanleitung."; +$a->strings["Generate encryption keys"] = "Verschlüsselungsschlüssel generieren"; +$a->strings["libCurl PHP module"] = "libCurl-PHP-Modul"; +$a->strings["GD graphics PHP module"] = "GD-Grafik-PHP-Modul"; +$a->strings["OpenSSL PHP module"] = "OpenSSL-PHP-Modul"; +$a->strings["mysqli or postgres PHP module"] = "mysqli oder postgres PHP-Modul"; +$a->strings["mb_string PHP module"] = "mb_string-PHP-Modul"; +$a->strings["mcrypt PHP module"] = "mcrypt-PHP-Modul"; +$a->strings["Apache mod_rewrite module"] = "Apache-mod_rewrite-Modul"; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Fehler: Das Apache-Modul mod-rewrite wird benötigt, ist aber nicht installiert."; +$a->strings["proc_open"] = "proc_open"; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Fehler: proc_open wird benötigt, ist aber entweder nicht installiert oder wurde in der php.ini deaktiviert"; +$a->strings["Error: libCURL PHP module required but not installed."] = "Fehler: Das PHP-Modul libCURL wird benötigt, ist aber nicht installiert."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Fehler: Das PHP-Modul GD-Grafik mit JPEG-Unterstützung wird benötigt, ist aber nicht installiert."; +$a->strings["Error: openssl PHP module required but not installed."] = "Fehler: Das PHP-Modul openssl wird benötigt, ist aber nicht installiert."; +$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Fehler: Das mysqli oder postgres PHP-Modul ist erforderlich, aber keines von beiden ist installiert."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Fehler: Das PHP-Modul mb_string wird benötigt, ist aber nicht installiert."; +$a->strings["Error: mcrypt PHP module required but not installed."] = "Fehler: Das PHP-Modul mcrypt wird benötigt, ist aber nicht installiert."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = "Der Installations-Assistent muss in der Lage sein, die Datei \".htconfig.php\" im Stammverzeichnis des Web-Servers anzulegen, ist er aber nicht."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Meist liegt das daran, dass der Nutzer, unter dem der Web-Server läuft, keine Schreibrechte in dem Verzeichnis hat – selbst wenn Du selbst das darfst."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Am Schluss dieses Vorgangs wird ein Text generiert, den Du unter dem Dateinamen .htconfig.php im Stammverzeichnis Deiner Red-Installation speichern musst."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Alternativ kannst Du diesen Schritt überspringen und die Installation manuell vornehmen. Lies dazu die Datei install/INSTALL.txt."; +$a->strings[".htconfig.php is writable"] = ".htconfig.php ist beschreibbar"; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red verwendet Smarty3 um Vorlagen für die Webdarstellung zu übersetzen. Smarty3 übersetzt diese Vorlagen nach PHP, um die Darstellung zu beschleunigen."; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "Um diese kompilierten Vorlagen speichern zu können, braucht der Web-Server Schreibzugriff auf das Verzeichnis %s unterhalb des Red-Installationsverzeichnisses."; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Bitte stelle sicher, dass der Nutzer, unter dem der Web-Server läuft (z.B. www-data), Schreibzugriff auf dieses Verzeichnis hat."; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Hinweis: Aus Sicherheitsgründen sollte der Web-Server nur auf %s Schreibrechte haben, nicht auf die Template-Dateien (.tpl), die das Verzeichnis enthält."; +$a->strings["%s is writable"] = "%s ist beschreibbar"; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red benutzt das Verzeichnis store, um hochgeladene Dateien zu speichern. Der Web-Server benötigt Schreibrechte für dieses Verzeichnis direkt unterhalb des Red-Stammverzeichnisses"; +$a->strings["store is writable"] = "store ist schreibbar"; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "Das SSL-Zertifikat konnte nicht validiert werden. Korrigiere das Zertifikat oder deaktiviere den HTTPS-Zugriff auf diesen Server."; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Wenn Du via HTTPS auf Deinen Server zugreifen möchtest, also Verbindungen über den Port 443 möglich sein sollen, ist ein SSL-Zertifikat einer Zertifizierungsstelle (CA) notwendig, das von den Browsern ohne Sicherheitsabfrage akzeptiert wird. Die Verwendung eines selbst signierten Zertifikates ist nicht möglich."; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Diese Einschränkung wurde eingebaut, weil Deine öffentlichen Beiträge zum Beispiel Verweise auf Bilder auf Deinem eigenen Hub enthalten können."; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Wenn Dein Zertifikat nicht von jedem Browser akzeptiert wird, erhalten die Mitglieder anderer Red-Server (die mit korrekten Zertifikaten ausgestattet sind) Sicherheits-Warnmeldungen, obwohl sie gar nicht direkt auf Deinem Server unterwegs sind (zum Beispiel, wenn ein Bild aus einem Deiner Beiträge angezeigt wird)."; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Dies kann Probleme für andere Nutzer (nicht nur auf Deinem eigenen Server) verursachen, so dass wir auf dieser Forderung bestehen müssen."; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Es gibt einige Zertifizierungsstellen (CAs), bei denen solche Zertifikate kostenlos zu haben sind."; +$a->strings["SSL certificate validation"] = "SSL Zertifikatverifizierung"; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "Das Umschreiben von URLs (rewrite) per .htaccess funktioniert nicht. Bitte prüfe die Server-Konfiguration. Test:"; +$a->strings["Url rewrite is working"] = "Url rewrite funktioniert"; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Die Datenbank-Konfigurationsdatei „.htconfig.php“ konnte nicht geschrieben werden. Bitte verwende den unten angegebenen Text, um die Konfigurationsdatei im Stammverzeichnis des Webservers anzulegen."; +$a->strings["Errors encountered creating database tables."] = "Fehler beim Anlegen der Datenbank-Tabellen aufgetreten."; +$a->strings["

    What next

    "] = "

    Was als Nächstes

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "WICHTIG: Du musst [manuell] einen Cronjob für den Poller einrichten."; +$a->strings["No channel."] = "Kein Kanal."; +$a->strings["Common connections"] = "Gemeinsame Verbindungen"; +$a->strings["No connections in common."] = "Keine gemeinsamen Verbindungen."; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Keine Vorschläge vorhanden. Wenn das ein neuer Server ist, versuche es in 24 Stunden noch einmal."; +$a->strings["Blocked"] = "Blockiert"; +$a->strings["Ignored"] = "Ignoriert"; +$a->strings["Hidden"] = "Versteckt"; +$a->strings["Archived"] = "Archiviert"; +$a->strings["All"] = "Alle"; +$a->strings["Suggest new connections"] = "Neue Verbindungen vorschlagen"; +$a->strings["New Connections"] = "Neue Verbindungen"; +$a->strings["Show pending (new) connections"] = "Ausstehende (neue) Verbindungsanfragen anzeigen"; +$a->strings["All Connections"] = "Alle Verbindungen"; +$a->strings["Show all connections"] = "Alle Verbindungen anzeigen"; +$a->strings["Unblocked"] = "Freigegeben"; +$a->strings["Only show unblocked connections"] = "Nur freigegebene Verbindungen anzeigen"; +$a->strings["Only show blocked connections"] = "Nur blockierte Verbindungen anzeigen"; +$a->strings["Only show ignored connections"] = "Nur ignorierte Verbindungen anzeigen"; +$a->strings["Only show archived connections"] = "Nur archivierte Verbindungen anzeigen"; +$a->strings["Only show hidden connections"] = "Nur versteckte Verbindungen anzeigen"; +$a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]"; +$a->strings["Edit connection"] = "Verbindung bearbeiten"; +$a->strings["Search your connections"] = "Verbindungen durchsuchen"; +$a->strings["Finding: "] = "Ergebnisse:"; +$a->strings["webpage"] = "Webseite"; +$a->strings["block"] = "Block"; +$a->strings["layout"] = "Layout"; +$a->strings["%s element installed"] = "Element für %s installiert"; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s hat %2\$ss %3\$s mit %4\$s verschlagwortet"; +$a->strings["Unable to locate original post."] = "Originalbeitrag nicht gefunden."; +$a->strings["Empty post discarded."] = "Leeren Beitrag verworfen."; +$a->strings["Executable content type not permitted to this channel."] = "Ausführbarer Content-Typ ist für diesen Kanal nicht freigegeben."; +$a->strings["System error. Post not saved."] = "Systemfehler. Beitrag nicht gespeichert."; +$a->strings["You have reached your limit of %1$.0f top level posts."] = "Du hast die maximale Anzahl von %1$.0f Beiträgen erreicht."; +$a->strings["You have reached your limit of %1$.0f webpages."] = "Du hast die maximale Anzahl von %1$.0f Webseiten erreicht."; +$a->strings["Public access denied."] = "Öffentlicher Zugang verweigert."; +$a->strings["Thing updated"] = "Sache aktualisiert"; +$a->strings["Object store: failed"] = "Speichern des Objekts fehlgeschlagen"; +$a->strings["Thing added"] = "Sache hinzugefügt"; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = "OBJ: %1\$s %2\$s %3\$s"; +$a->strings["Show Thing"] = "Sache anzeigen"; +$a->strings["item not found."] = "Eintrag nicht gefunden"; +$a->strings["Edit Thing"] = "Sache bearbeiten"; +$a->strings["Select a profile"] = "Wähle ein Profil"; +$a->strings["Post an activity"] = "Aktivitätsnachricht senden"; +$a->strings["Only sends to viewers of the applicable profile"] = "Nur an Betrachter des ausgewählten Profils senden"; +$a->strings["Name of thing e.g. something"] = "Name der Sache, z. B. irgendwas"; +$a->strings["URL of thing (optional)"] = "URL der Sache (optional)"; +$a->strings["URL for photo of thing (optional)"] = "URL eines Fotos der Sache (optional)"; +$a->strings["Add Thing to your Profile"] = "Die Sache Deinem Profil hinzufügen"; +$a->strings["Away"] = "Abwesend"; +$a->strings["Online"] = "Online"; +$a->strings["Channel added."] = "Kanal hinzugefügt."; +$a->strings["No more system notifications."] = "Keine System-Benachrichtigungen mehr."; +$a->strings["System Notifications"] = "System-Benachrichtigungen"; +$a->strings["network"] = "Netzwerk"; +$a->strings["RSS"] = "RSS"; +$a->strings["Layout updated."] = "Layout aktualisiert."; +$a->strings["Edit System Page Description"] = "Systemseitenbeschreibung bearbeiten"; +$a->strings["Layout not found."] = "Layout nicht gefunden."; +$a->strings["Module Name:"] = "Modulname:"; +$a->strings["Layout Help"] = "Layout-Hilfe"; +$a->strings["App installed."] = "App installiert."; +$a->strings["Malformed app."] = "Fehlerhafte App."; +$a->strings["Embed code"] = "Code einbetten"; +$a->strings["Edit App"] = "App bearbeiten"; +$a->strings["Create App"] = "App erstellen"; +$a->strings["Name of app"] = "Name der App"; +$a->strings["Location (URL) of app"] = "Ort (URL) der App"; +$a->strings["Description"] = "Beschreibung"; +$a->strings["Photo icon URL"] = "URL zum Icon"; +$a->strings["80 x 80 pixels - optional"] = "80 x 80 Pixel – optional"; +$a->strings["Version ID"] = "Versions-ID"; +$a->strings["Price of app"] = "Preis der App"; +$a->strings["Location (URL) to purchase app"] = "Ort (URL), um die App zu kaufen"; +$a->strings["- select -"] = "– auswählen –"; +$a->strings["Your service plan only allows %d channels."] = "Dein Vertrag erlaubt nur %d Kanäle."; +$a->strings["Nothing to import."] = "Nichts zu importieren."; +$a->strings["Unable to download data from old server"] = "Daten können vom alten Server nicht heruntergeladen werden"; +$a->strings["Imported file is empty."] = "Die importierte Datei ist leer."; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "Kann keinen doppelten Kanal-Identifikator auf diesem System erzeugen (Spitzname oder Hash schon belegt). Import fehlgeschlagen."; +$a->strings["Unable to create a unique channel address. Import failed."] = "Es war nicht möglich, eine eindeutige Kanal-Adresse zu erzeugen. Der Import ist fehlgeschlagen."; +$a->strings["Channel clone failed. Import failed."] = "Klonen des Kanals fehlgeschlagen. Import fehlgeschlagen."; +$a->strings["Cloned channel not found. Import failed."] = "Geklonter Kanal nicht gefunden. Import fehlgeschlagen."; +$a->strings["Import completed."] = "Import abgeschlossen."; +$a->strings["You must be logged in to use this feature."] = "Du musst angemeldet sein um diese Funktion zu nutzen."; +$a->strings["Import Channel"] = "Kanal importieren"; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = "Verwende dieses Formular, um einen existierenden Kanal von einem anderen Red-Server zu importieren. Du kannst den Kanal direkt vom bisherigen Red-Server über das Netzwerk importieren oder eine exportierte Sicherheitskopie benutzen. Es werden ausschließlich die Identität und die Verbindungen/Beziehungen importiert. Das Importieren von Inhalten ist derzeit nicht möglich."; +$a->strings["File to Upload"] = "Hochzuladende Datei:"; +$a->strings["Or provide the old server/hub details"] = "Oder gib die Details Deines bisherigen Red-Servers ein"; +$a->strings["Your old identity address (xyz@example.com)"] = "Bisherige Kanal-Adresse (xyz@example.com)"; +$a->strings["Your old login email address"] = "Deine alte Login-E-Mail-Adresse"; +$a->strings["Your old login password"] = "Dein altes Passwort"; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Egal, welche Option Du wählst – bitte lege fest, ob dieser Server die neue primäre Adresse dieses Kanals sein soll, oder ob der bisherige Red-Server diese Rolle weiterhin wahrnimmt. Du kannst von beiden Servern aus posten, aber nur einer kann der primäre Ort Deiner Dateien, Fotos und Medien sein."; +$a->strings["Make this hub my primary location"] = "Dieser Red-Server ist mein primärer Server."; +$a->strings["Import existing posts if possible"] = "Existierende Beiträge importieren, falls möglich"; +$a->strings["Edit Layout"] = "Layout bearbeiten"; +$a->strings["Delete layout?"] = "Layout löschen?"; +$a->strings["Delete Layout"] = "Layout löschen"; +$a->strings["You must be logged in to see this page."] = "Du musst angemeldet sein, um diese Seite betrachten zu können."; +$a->strings["Room not found"] = "Chatraum nicht gefunden"; +$a->strings["Leave Room"] = "Raum verlassen"; +$a->strings["Delete This Room"] = "Diesen Raum löschen"; +$a->strings["I am away right now"] = "Ich bin gerade nicht da"; +$a->strings["I am online"] = "Ich bin online"; +$a->strings["Bookmark this room"] = "Lesezeichen für diesen Raum setzen"; +$a->strings["New Chatroom"] = "Neuer Chatraum"; +$a->strings["Chatroom Name"] = "Name des Chatraums"; +$a->strings["%1\$s's Chatrooms"] = "%1\$ss Chaträume"; +$a->strings["Edit Webpage"] = "Webseite bearbeiten"; +$a->strings["Delete webpage?"] = "Webseite löschen?"; +$a->strings["Delete Webpage"] = "Webseite löschen"; +$a->strings["This site is not a directory server"] = "Diese Website ist kein Verzeichnis-Server"; +$a->strings["No valid account found."] = "Kein gültiges Konto gefunden."; +$a->strings["Password reset request issued. Check your email."] = "Zurücksetzen des Passworts eingeleitet. Schau in Deine E-Mails."; +$a->strings["Site Member (%s)"] = "Nutzer (%s)"; +$a->strings["Password reset requested at %s"] = "Passwort-Rücksetzung auf %s angefordert"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Die Anfrage konnte nicht verifiziert werden. (Vielleicht hast Du schon einmal auf den Link in der E-Mail geklickt?) Passwort-Rücksetzung fehlgeschlagen."; +$a->strings["Password Reset"] = "Zurücksetzen des Kennworts"; +$a->strings["Your password has been reset as requested."] = "Dein Passwort wurde wie angefordert neu erstellt."; +$a->strings["Your new password is"] = "Dein neues Passwort lautet"; +$a->strings["Save or copy your new password - and then"] = "Speichere oder kopiere Dein neues Passwort – und dann"; +$a->strings["click here to login"] = "Klicke hier, um dich anzumelden"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Dein Passwort kann unter Einstellungen nach einer erfolgreichen Anmeldung geändert werden."; +$a->strings["Your password has changed at %s"] = "Auf %s wurde Dein Passwort geändert"; +$a->strings["Forgot your Password?"] = "Kennwort vergessen?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Gib Deine E-Mail-Adresse ein, um Dein Passwort zurücksetzen zu lassen. Du erhältst dann weitere Anweisungen per E-Mail."; +$a->strings["Email Address"] = "E-Mail Adresse"; +$a->strings["Reset"] = "Zurücksetzen"; +$a->strings["Website:"] = "Webseite:"; +$a->strings["Remote Channel [%s] (not yet known on this site)"] = "Kanal [%s] (auf diesem Server noch unbekannt)"; +$a->strings["Total invitation limit exceeded."] = "Einladungslimit überschritten."; +$a->strings["%s : Not a valid email address."] = "%s : Keine gültige Email Adresse."; +$a->strings["Please join us on Red"] = "Schließe Dich uns an und werde Teil der Red-Matrix"; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = "Einladungslimit überschritten. Bitte kontaktiere den Administrator Deines Red-Servers."; +$a->strings["%s : Message delivery failed."] = "%s : Nachricht konnte nicht zugestellt werden."; +$a->strings["%d message sent."] = array( + 0 => "%d Nachricht gesendet.", + 1 => "%d Nachrichten gesendet.", +); +$a->strings["You have no more invitations available"] = "Du hast keine weiteren verfügbare Einladungen"; +$a->strings["Send invitations"] = "Einladungen senden"; +$a->strings["Enter email addresses, one per line:"] = "Email-Adressen eintragen, eine pro Zeile:"; +$a->strings["Your message:"] = "Deine Nachricht:"; +$a->strings["Please join my community on RedMatrix."] = "Schließe Dich uns in der RedMatrix an!"; +$a->strings["You will need to supply this invitation code: "] = "Gib folgenden Einladungs-Code ein:"; +$a->strings["1. Register at any RedMatrix location (they are all inter-connected)"] = "1. Registriere Dich auf irgendeinem RedMatrix-Server (sie sind alle miteinander verbunden)"; +$a->strings["2. Enter my RedMatrix network address into the site searchbar."] = "2. Gib meine RedMatrix-Adresse im Suchfeld ein."; +$a->strings["or visit "] = "oder besuche"; +$a->strings["3. Click [Connect]"] = "3. Klicke auf [Verbinden]"; +$a->strings["Location not found."] = "Klon nicht gefunden."; +$a->strings["Primary location cannot be removed."] = "Der primäre Klon kann nicht gelöscht werden."; +$a->strings["No locations found."] = "Keine Klon-Adressen gefunden."; +$a->strings["Manage Channel Locations"] = "Klon-Adressen verwalten"; +$a->strings["Location (address)"] = "URL (Adresse)"; +$a->strings["Primary Location"] = "Primärer Klon"; +$a->strings["Drop location"] = "Klon löschen"; +$a->strings["Failed to create source. No channel selected."] = "Konnte die Quelle nicht anlegen. Kein Kanal ausgewählt."; +$a->strings["Source created."] = "Quelle erstellt."; +$a->strings["Source updated."] = "Quelle aktualisiert."; +$a->strings["*"] = "*"; +$a->strings["Manage remote sources of content for your channel."] = "Externe Inhaltsquellen für Deinen Kanal verwalten."; +$a->strings["New Source"] = "Neue Quelle"; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importiere alle oder ausgewählte Inhalte des folgenden Kanals in diesen Kanal und verteile sie gemäß der Einstellungen dieses Kanals."; +$a->strings["Only import content with these words (one per line)"] = "Importiere nur Beiträge, die folgende Wörter (eines pro Zeile) enthalten"; +$a->strings["Leave blank to import all public content"] = "Leer lassen, um alle öffentlichen Beiträge zu importieren"; +$a->strings["Channel Name"] = "Name des Kanals"; +$a->strings["Source not found."] = "Quelle nicht gefunden."; +$a->strings["Edit Source"] = "Quelle bearbeiten"; +$a->strings["Delete Source"] = "Quelle löschen"; +$a->strings["Source removed"] = "Quelle gelöscht"; +$a->strings["Unable to remove source."] = "Konnte die Quelle nicht löschen."; +$a->strings["Menu updated."] = "Menü aktualisiert."; +$a->strings["Unable to update menu."] = "Kann Menü nicht aktualisieren."; +$a->strings["Menu created."] = "Menü erstellt."; +$a->strings["Unable to create menu."] = "Kann Menü nicht erstellen."; +$a->strings["Manage Menus"] = "Menüs verwalten"; +$a->strings["Drop"] = "Löschen"; +$a->strings["Bookmarks allowed"] = "Lesezeichen erlaubt"; +$a->strings["Create a new menu"] = "Neues Menü erstellen"; +$a->strings["Delete this menu"] = "Lösche dieses Menü"; +$a->strings["Edit menu contents"] = "Bearbeite Menü Inhalte"; +$a->strings["Edit this menu"] = "Dieses Menü bearbeiten"; +$a->strings["New Menu"] = "Neues Menü"; +$a->strings["Menu name"] = "Menü Name"; +$a->strings["Must be unique, only seen by you"] = "Muss eindeutig sein, ist aber nur für Dich sichtbar"; +$a->strings["Menu title"] = "Menü Titel"; +$a->strings["Menu title as seen by others"] = "Menü Titel wie er von anderen gesehen wird"; +$a->strings["Allow bookmarks"] = "Erlaube Lesezeichen"; +$a->strings["Menu may be used to store saved bookmarks"] = "Im Menü können gespeicherte Lesezeichen abgelegt werden"; +$a->strings["Menu not found."] = "Menü nicht gefunden"; +$a->strings["Menu deleted."] = "Menü gelöscht."; +$a->strings["Menu could not be deleted."] = "Menü konnte nicht gelöscht werden."; +$a->strings["Edit Menu"] = "Menü bearbeiten"; +$a->strings["Add or remove entries to this menu"] = "Einträge zu diesem Menü hinzufügen oder entfernen"; +$a->strings["Modify"] = "Ändern"; +$a->strings["Permission Denied."] = "Zugriff verweigert."; +$a->strings["File not found."] = "Datei nicht gefunden."; +$a->strings["Edit file permissions"] = "Dateiberechtigungen bearbeiten"; +$a->strings["Set/edit permissions"] = "Berechtigungen setzen/ändern"; +$a->strings["Include all files and sub folders"] = "Alle Dateien und Unterverzeichnisse einbinden"; +$a->strings["Return to file list"] = "Zurück zur Dateiliste"; +$a->strings["Copy/paste this code to attach file to a post"] = "Diesen Code kopieren und einfügen, um die Datei an einen Beitrag anzuhängen"; +$a->strings["Copy/paste this URL to link file from a web page"] = "Diese URL verwenden, um von einer Webseite aus auf die Datei zu verlinken"; +$a->strings["Attach this file to a new post"] = "Diese Datei an einen neuen Beitrag anhängen"; +$a->strings["Show URL to this file"] = "URL zu dieser Datei anzeigen"; +$a->strings["Do not show in shared with me folder of your connections"] = "Nicht im Ordner „Dateien, die mit mir geteilt wurden“ meiner Verbindungen anzeigen"; +$a->strings["Contact not found."] = "Kontakt nicht gefunden"; +$a->strings["Friend suggestion sent."] = "Freundschaftsempfehlung senden."; +$a->strings["Suggest Friends"] = "Kontakte vorschlagen"; +$a->strings["Suggest a friend for %s"] = "Schlage %s einen Kontakt vor"; +$a->strings["Hub not found."] = "Server nicht gefunden."; +$a->strings["Poke/Prod"] = "Anstupsen/Knuffen"; +$a->strings["poke, prod or do other things to somebody"] = "Stupse Leute an oder mache anderes mit ihnen"; +$a->strings["Recipient"] = "Empfänger"; +$a->strings["Choose what you wish to do to recipient"] = "Wähle, was Du mit dem/r Empfänger/in tun willst"; +$a->strings["Make this post private"] = "Diesen Beitrag privat machen"; +$a->strings["Invalid profile identifier."] = "Ungültiger Profil-Identifikator"; +$a->strings["Profile Visibility Editor"] = "Profil-Sichtbarkeits-Editor"; +$a->strings["Click on a contact to add or remove."] = "Klicke auf einen Kontakt, um ihn hinzuzufügen oder zu entfernen."; +$a->strings["Visible To"] = "Sichtbar für"; +$a->strings["Remote privacy information not available."] = "Privatsphäre-Einstellungen anderer Nutzer sind nicht verfügbar."; +$a->strings["Visible to:"] = "Sichtbar für:"; +$a->strings["Profile not found."] = "Profil nicht gefunden."; +$a->strings["Profile deleted."] = "Profil gelöscht."; +$a->strings["Profile-"] = "Profil-"; +$a->strings["New profile created."] = "Neues Profil erstellt."; +$a->strings["Profile unavailable to clone."] = "Profil kann nicht geklont werden."; +$a->strings["Profile unavailable to export."] = "Dieses Profil kann nicht exportiert werden."; +$a->strings["Profile Name is required."] = "Profil-Name erforderlich."; +$a->strings["Marital Status"] = "Familienstand"; +$a->strings["Romantic Partner"] = "Romantische Partner"; +$a->strings["Likes"] = "Gefällt"; +$a->strings["Dislikes"] = "Gefällt nicht"; +$a->strings["Work/Employment"] = "Arbeit/Anstellung"; +$a->strings["Religion"] = "Religion"; +$a->strings["Political Views"] = "Politische Ansichten"; +$a->strings["Gender"] = "Geschlecht"; +$a->strings["Sexual Preference"] = "Sexuelle Orientierung"; +$a->strings["Homepage"] = "Webseite"; +$a->strings["Interests"] = "Hobbys/Interessen"; +$a->strings["Address"] = "Adresse"; +$a->strings["Profile updated."] = "Profil aktualisiert."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "Deine Kontaktliste vor Betrachtern dieses Profils verbergen?"; +$a->strings["Edit Profile Details"] = "Bearbeite Profil-Details"; +$a->strings["View this profile"] = "Dieses Profil ansehen"; +$a->strings["Change Profile Photo"] = "Profilfoto ändern"; +$a->strings["Create a new profile using these settings"] = "Neues Profil anlegen und diese Einstellungen übernehmen"; +$a->strings["Clone this profile"] = "Dieses Profil klonen"; +$a->strings["Delete this profile"] = "Dieses Profil löschen"; +$a->strings["Import profile from file"] = "Profil aus einer Datei importieren"; +$a->strings["Export profile to file"] = "Profil in eine Datei exportieren"; +$a->strings["Profile Name:"] = "Profilname:"; +$a->strings["Your Full Name:"] = "Dein voller Name:"; +$a->strings["Title/Description:"] = "Titel/Beschreibung:"; +$a->strings["Your Gender:"] = "Dein Geschlecht:"; +$a->strings["Birthday :"] = "Geburtstag:"; +$a->strings["Street Address:"] = "Straße und Hausnummer:"; +$a->strings["Locality/City:"] = "Wohnort:"; +$a->strings["Postal/Zip Code:"] = "Postleitzahl:"; +$a->strings["Country:"] = "Land:"; +$a->strings["Region/State:"] = "Region/Bundesstaat:"; +$a->strings[" Marital Status:"] = " Beziehungsstatus:"; +$a->strings["Who: (if applicable)"] = "Wer: (falls anwendbar)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Beispiele: cathy123, Cathy Williams, cathy@example.com"; +$a->strings["Since [date]:"] = "Seit [Datum]:"; +$a->strings["Homepage URL:"] = "Homepage URL:"; +$a->strings["Religious Views:"] = "Religiöse Ansichten:"; +$a->strings["Keywords:"] = "Schlüsselwörter:"; +$a->strings["Example: fishing photography software"] = "Beispiel: Angeln Fotografie Software"; +$a->strings["Used in directory listings"] = "Wird in Verzeichnis-Auflistungen verwendet"; +$a->strings["Tell us about yourself..."] = "Erzähle uns ein wenig von Dir …"; +$a->strings["Hobbies/Interests"] = "Hobbys/Interessen"; +$a->strings["Contact information and Social Networks"] = "Kontaktinformation und soziale Netzwerke"; +$a->strings["My other channels"] = "Meine anderen Kanäle"; +$a->strings["Musical interests"] = "Musikalische Interessen"; +$a->strings["Books, literature"] = "Bücher, Literatur"; +$a->strings["Television"] = "Fernsehen"; +$a->strings["Film/dance/culture/entertainment"] = "Film/Tanz/Kultur/Unterhaltung"; +$a->strings["Love/romance"] = "Liebe/Romantik"; +$a->strings["Work/employment"] = "Arbeit/Anstellung"; +$a->strings["School/education"] = "Schule/Ausbildung"; +$a->strings["This is your default profile."] = "Das ist Dein Standardprofil."; +$a->strings["Age: "] = "Alter:"; +$a->strings["Edit/Manage Profiles"] = "Profile bearbeiten/verwalten"; +$a->strings["Add profile things"] = "Sachen zum Profil hinzufügen"; +$a->strings["Include desirable objects in your profile"] = "Binde begehrenswerte Dinge in Dein Profil ein"; +$a->strings["No ratings"] = "Keine Bewertungen"; +$a->strings["Ratings"] = "Bewertungen"; +$a->strings["Rating: "] = "Bewertung: "; +$a->strings["Website: "] = "Webseite: "; +$a->strings["Description: "] = "Beschreibung: "; +$a->strings["No potential page delegates located."] = "Keine potentiellen Bevollmächtigten für die Seite gefunden."; +$a->strings["Delegate Page Management"] = "Delegiere das Management für diese Seite"; +$a->strings["Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely."] = "Bevollmächtigte sind in der Lage, alle Aspekte dieses Kontos/dieser Seite zu verwalten, abgesehen von den Grundeinstellungen des Kontos. Gib niemandem eine Bevollmächtigung für Deinen privaten Account, dem Du nicht absolut vertraust!"; +$a->strings["Existing Page Managers"] = "Vorhandene Seitenmanager"; +$a->strings["Existing Page Delegates"] = "Vorhandene Bevollmächtigte für die Seite"; +$a->strings["Potential Delegates"] = "Potentielle Bevollmächtigte"; +$a->strings["Add"] = "Hinzufügen"; +$a->strings["No entries."] = "Keine Einträge."; +$a->strings["%d rating"] = array( + 0 => "%d Bewertung", + 1 => "%d Bewertungen", +); +$a->strings["Gender: "] = "Geschlecht:"; +$a->strings["Status: "] = "Status:"; +$a->strings["Homepage: "] = "Webseite:"; +$a->strings["Hometown: "] = "Wohnort:"; +$a->strings["About: "] = "Ãœber:"; +$a->strings["Public Forum:"] = "Öffentliches Forum:"; +$a->strings["Keywords: "] = "Schlüsselwörter:"; +$a->strings["Finding:"] = "Ergebnisse:"; +$a->strings["next page"] = "nächste Seite"; +$a->strings["previous page"] = "vorherige Seite"; +$a->strings["No entries (some entries may be hidden)."] = "Keine Einträge gefunden (einige könnten versteckt sein)."; +$a->strings["Select a bookmark folder"] = "Lesezeichenordner wählen"; +$a->strings["Save Bookmark"] = "Lesezeichen speichern"; +$a->strings["URL of bookmark"] = "URL des Lesezeichens"; +$a->strings["Or enter new bookmark folder name"] = "Oder gib einen neuen Namen für den Lesezeichenordner ein"; +$a->strings["Export Channel"] = "Kanal exportieren"; +$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = "Exportiert die grundlegenden Kanal-Informationen in eine kleine Datei. Diese stellt eine Sicherung Deiner Verbindungen, Berechtigungen, Profile und Basisdaten bereit, die für den Import auf einem anderen Hub verwendet werden kann, aber nicht die Beiträge Deines Kanals enthält."; +$a->strings["Export Content"] = "Kanal und Inhalte exportieren"; +$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = "Exportiert Deine Kanal-Informationen sowie alle zugehörigen Inhalte in eine JSON-Sicherungsdatei. Die sichert alle Verbindungen, Berechtigungen, Profildaten und Inhalte Deines Kanals, ist aber nicht unbedingt für den Import eines Kanals auf einem anderen Hub geeignet, da die Datei SEHR groß werden kann. Bitte habe ein wenig Geduld – es kann mehrere Minuten dauern, bis der Download startet."; +$a->strings["No connections."] = "Keine Verbindungen."; +$a->strings["Visit %s's profile [%s]"] = "%ss Profil [%s] besuchen"; +$a->strings["invalid target signature"] = "Ungültige Signatur des Ziels"; +$a->strings["Theme settings updated."] = "Theme-Einstellungen aktualisiert."; +$a->strings["Site"] = "Seite"; +$a->strings["Accounts"] = "Konten"; +$a->strings["Channels"] = "Kanäle"; +$a->strings["Plugins"] = "Plug-Ins"; +$a->strings["Themes"] = "Themes"; +$a->strings["Server"] = "Server"; +$a->strings["Profile Config"] = "Profilkonfiguration"; +$a->strings["DB updates"] = "DB-Aktualisierungen"; +$a->strings["Logs"] = "Protokolle"; +$a->strings["Plugin Features"] = "Plug-In Funktionen"; +$a->strings["User registrations waiting for confirmation"] = "Nutzer-Anmeldungen, die auf Bestätigung warten"; +$a->strings["Message queues"] = "Nachrichten-Warteschlangen"; +$a->strings["Administration"] = "Administration"; +$a->strings["Summary"] = "Zusammenfassung"; +$a->strings["Registered users"] = "Registrierte Benutzer"; +$a->strings["Pending registrations"] = "Ausstehende Registrierungen"; +$a->strings["Version"] = "Version"; +$a->strings["Active plugins"] = "Aktive Plug-Ins"; +$a->strings["Site settings updated."] = "Site-Einstellungen aktualisiert."; +$a->strings["experimental"] = "experimentell"; +$a->strings["unsupported"] = "nicht unterstützt"; +$a->strings["Yes - with approval"] = "Ja - mit Zustimmung"; +$a->strings["My site is not a public server"] = "Mein Server ist kein öffentlicher Server"; +$a->strings["My site has paid access only"] = "Mein Server erlaubt nur bezahlten Zugang"; +$a->strings["My site has free access only"] = "Mein Server erlaubt ausschließlich freien Zugang"; +$a->strings["My site offers free accounts with optional paid upgrades"] = "Mein Server bietet kostenlose Konten mit der Möglichkeit zu bezahlten Upgrades"; +$a->strings["Registration"] = "Registrierung"; +$a->strings["File upload"] = "Dateiupload"; +$a->strings["Policies"] = "Richtlinien"; +$a->strings["Site name"] = "Seitenname"; +$a->strings["Banner/Logo"] = "Banner/Logo"; +$a->strings["Administrator Information"] = "Administrator-Informationen"; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = "Kontaktinformationen für Administratoren des Servers. Wird auf der siteinfo-Seite angezeigt. BBCode kann verwendet werden."; +$a->strings["System language"] = "System-Sprache"; +$a->strings["System theme"] = "System-Theme"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "Standard-System-Theme – kann durch Nutzerprofile überschieben werden – Theme-Einstellungen ändern"; +$a->strings["Mobile system theme"] = "Mobile System-Theme:"; +$a->strings["Theme for mobile devices"] = "Theme für mobile Geräte"; +$a->strings["Enable Diaspora Protocol"] = "Diaspora-Protokoll aktivieren"; +$a->strings["Communicate with Diaspora and Friendica - experimental"] = "Kommunikation mit Diaspora und Friendica – experimentell"; +$a->strings["Allow Feeds as Connections"] = "Feeds als Verbindungen erlauben"; +$a->strings["(Heavy system resource usage)"] = "(führt zu hoher Systemlast)"; +$a->strings["Maximum image size"] = "Maximale Bildgröße"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Maximale Größe hochgeladener Bilder in Bytes. Standard ist 0 (keine Einschränkung)."; +$a->strings["Does this site allow new member registration?"] = "Erlaubt dieser Server die Registrierung neuer Nutzer?"; +$a->strings["Which best describes the types of account offered by this hub?"] = "Was ist die passendste Beschreibung der Konten auf diesem Hub?"; +$a->strings["Register text"] = "Registrierungstext"; +$a->strings["Will be displayed prominently on the registration page."] = "Wird gut sichtbar auf der Registrierungs-Seite angezeigt."; +$a->strings["Accounts abandoned after x days"] = "Konten gelten nach X Tagen als unbenutzt"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "Verschwende keine Systemressourcen auf das Pollen von externen Seiten, wenn das Konto nicht mehr benutzt wird. Trage hier 0 für kein zeitliches Limit."; +$a->strings["Allowed friend domains"] = "Erlaubte Domains für Kontakte"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "Liste der Domains, die für Freundschaften erlaubt sind, durch Kommas getrennt. Platzhalter werden akzeptiert. Leer lassen, um alle Domains zu erlauben."; +$a->strings["Allowed email domains"] = "Erlaubte Domains für E-Mails"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "Liste der Domains, die für E-Mail-Adressen bei der Registrierung erlaubt sind, durch Kommas getrennt. Platzhalter werden akzeptiert. Leer lassen, um alle Domains zu erlauben."; +$a->strings["Not allowed email domains"] = "Nicht erlaubte Domains für E-Mails"; +$a->strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = "Domains in E-Mail-Adressen, die keine Erlaubnis erhalten, sich auf Deinem Hub zu registrieren. Mehrere Domains können durch Kommas getrennt werden. Platzhalter (*/?) sind möglich. Keine Eingabe bedeutet keine Einschränkung, unabhängig davon, ob unter erlaubte Domains etwas eingegeben wurde."; +$a->strings["Block public"] = "Öffentlichen Zugriff blockieren"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Zugriff auf sonst öffentliche persönliche Seiten blockieren, wenn man nicht eingeloggt ist."; +$a->strings["Verify Email Addresses"] = "E-Mail-Adressen überprüfen"; +$a->strings["Check to verify email addresses used in account registration (recommended)."] = "Aktivieren, um die Ãœberprüfung von E-Mail-Adressen bei der Registrierung von Benutzerkonten zu aktivieren (empfohlen)."; +$a->strings["Force publish"] = "Veröffentlichung erzwingen"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Die Veröffentlichung aller Profile dieses Servers im Verzeichnis erzwingen."; +$a->strings["Disable discovery tab"] = "Den „Entdecken“-Reiter ausblenden"; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = "Entferne den „Entdecken“-Reiter aus der Matrix-Seite, in dem öffentliche Inhalte angezeigt werden, die von anderen RedMatrix-Hubs geholt wurden."; +$a->strings["No login on Homepage"] = "Kein Login auf der Homepage"; +$a->strings["Check to hide the login form from your sites homepage when visitors arrive who are not logged in (e.g. when you put the content of the homepage in via the site channel)."] = "Aktivieren, um das Login-Formular auf der Startseite der Seite zu verbergen (z.B. weil es das Layout der Homepage des Seiten-Kanals stört)."; +$a->strings["Proxy user"] = "Proxy Benutzer"; +$a->strings["Proxy URL"] = "Proxy URL"; +$a->strings["Network timeout"] = "Netzwerk-Timeout"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "Wert in Sekunden. 0 für unbegrenzt (nicht empfohlen)."; +$a->strings["Delivery interval"] = "Auslieferung Intervall"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Verzögere im Hintergrund laufende Auslieferungsprozesse um die angegebene Anzahl Sekunden, um die Systemlast zu verringern. Empfehlungen: 4-5 für Shared Hosts, 2-3 für VPS, 0-1 für große dedizierte Server."; +$a->strings["Poll interval"] = "Abfrageintervall"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Verzögere Hintergrundprozesse um diese Anzahl Sekunden, um die Systemlast zu reduzieren. Bei 0 wird das Auslieferungsintervall verwendet."; +$a->strings["Maximum Load Average"] = "Maximales Load Average"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Maximale Systemlast, bevor Verteil- und Empfangsprozesse verschoben werden – Standard 50"; +$a->strings["No server found"] = "Kein Server gefunden"; +$a->strings["ID"] = "ID"; +$a->strings["for channel"] = "für Kanal"; +$a->strings["on server"] = "auf Server"; +$a->strings["Status"] = "Status"; +$a->strings["Update has been marked successful"] = "Update wurde als erfolgreich markiert"; +$a->strings["Executing %s failed. Check system logs."] = "Ausführen von %s fehlgeschlagen. Ãœberprüfe die Systemprotokolle."; +$a->strings["Update %s was successfully applied."] = "Update %s wurde erfolgreich ausgeführt."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "Update %s lieferte keinen Rückgabewert. Erfolg unbekannt."; +$a->strings["Update function %s could not be found."] = "Update-Funktion %s konnte nicht gefunden werden."; +$a->strings["No failed updates."] = "Keine fehlgeschlagenen Aktualisierungen."; +$a->strings["Failed Updates"] = "Fehlgeschlagene Aktualisierungen"; +$a->strings["Mark success (if update was manually applied)"] = "Als erfolgreich markieren (wenn das Update manuell ausgeführt wurde)"; +$a->strings["Attempt to execute this update step automatically"] = "Versuche, diesen Updateschritt automatisch auszuführen"; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "%s Nutzer blockiert/freigegeben", + 1 => "%s Nutzer blockiert/freigegeben", +); +$a->strings["%s user deleted"] = array( + 0 => "%s Nutzer gelöscht", + 1 => "%s Nutzer gelöscht", +); +$a->strings["Account not found"] = "Konto nicht gefunden"; +$a->strings["User '%s' unblocked"] = "Benutzer '%s' freigegeben"; +$a->strings["User '%s' blocked"] = "Benutzer '%s' blockiert"; +$a->strings["Users"] = "Benutzer"; +$a->strings["select all"] = "Alle auswählen"; +$a->strings["User registrations waiting for confirm"] = "Neuanmeldungen, die auf Deine Bestätigung warten"; +$a->strings["Request date"] = "Antragsdatum"; +$a->strings["No registrations."] = "Keine Registrierungen."; +$a->strings["Approve"] = "Genehmigen"; +$a->strings["Deny"] = "Verweigern"; +$a->strings["Register date"] = "Registrierungs-Datum"; +$a->strings["Last login"] = "Letzte Anmeldung"; +$a->strings["Expires"] = "Verfällt"; +$a->strings["Service Class"] = "Service-Klasse"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Die markierten Nutzer werden gelöscht!\\n\\nAlles, was diese Nutzer auf dieser Seite veröffentlicht haben, wird endgültig gelöscht!\\n\\nBist Du sicher?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Der Nutzer {0} wird gelöscht!\\n\\nAlles, was dieser Nutzer auf dieser Seite veröffentlicht hat, wird endgültig gelöscht werden!\\n\\nBist Du sicher?"; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "%s Kanal gesperrt/freigegeben", + 1 => "%s Kanäle gesperrt/freigegeben", +); +$a->strings["%s channel deleted"] = array( + 0 => "%s Kanal gelöscht", + 1 => "%s Kanäle gelöscht", +); +$a->strings["Channel not found"] = "Kanal nicht gefunden"; +$a->strings["Channel '%s' deleted"] = "Kanal '%s' gelöscht"; +$a->strings["Channel '%s' uncensored"] = "Kanal '%s' freigegeben"; +$a->strings["Channel '%s' censored"] = "Kanal '%s' gesperrt"; +$a->strings["Censor"] = "Sperren"; +$a->strings["Uncensor"] = "Freigeben"; +$a->strings["UID"] = "UID"; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = "Alle ausgewählten Kanäle werden gelöscht!\\n\\nAlles was von diesen Kanälen auf diesem Server geschrieben wurde, wird dauerhaft gelöscht!\\n\\nBist Du sicher?"; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = "Der Kanal {0} wird gelöscht!\\n\\nAlles was von diesem Kanal auf diesem Server geschrieben wurde, wird gelöscht!\\n\\nBist Du sicher?"; +$a->strings["Plugin %s disabled."] = "Plug-In %s deaktiviert."; +$a->strings["Plugin %s enabled."] = "Plug-In %s aktiviert."; +$a->strings["Disable"] = "Deaktivieren"; +$a->strings["Enable"] = "Aktivieren"; +$a->strings["Toggle"] = "Umschalten"; +$a->strings["Author: "] = "Autor: "; +$a->strings["Maintainer: "] = "Betreuer:"; +$a->strings["No themes found."] = "Keine Theme gefunden."; +$a->strings["Screenshot"] = "Bildschirmfoto"; +$a->strings["[Experimental]"] = "[Experimentell]"; +$a->strings["[Unsupported]"] = "[Nicht unterstützt]"; +$a->strings["Log settings updated."] = "Protokoll-Einstellungen aktualisiert."; +$a->strings["Clear"] = "Leeren"; +$a->strings["Debugging"] = "Debugging"; +$a->strings["Log file"] = "Protokolldatei"; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = "Muss für den Web-Server schreibbar sein. Relativ zum Red-Stammverzeichnis."; +$a->strings["Log level"] = "Protokollstufe"; +$a->strings["New Profile Field"] = "Neues Profilfeld"; +$a->strings["Field nickname"] = "Kurzname für das Feld"; +$a->strings["System name of field"] = "Systemname des Feldes"; +$a->strings["Input type"] = "Art des Inhalts"; +$a->strings["Field Name"] = "Feldname"; +$a->strings["Label on profile pages"] = "Bezeichnung auf Profilseiten"; +$a->strings["Help text"] = "Hilfetext"; +$a->strings["Additional info (optional)"] = "Zusätzliche Informationen (optional)"; +$a->strings["Field definition not found"] = "Feld-Definition nicht gefunden"; +$a->strings["Edit Profile Field"] = "Profilfeld bearbeiten"; +$a->strings["Unable to find your hub."] = "Konnte Deinen Server nicht finden."; +$a->strings["Post successful."] = "Veröffentlichung erfolgreich."; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "Fern-Authentifizierung blockiert. Du bist lokal auf diesem Server angemeldet. Bitte melde Dich ab und versuche es erneut."; +$a->strings["Welcome %s. Remote authentication successful."] = "Willkommen %s. Entfernte Authentifizierung erfolgreich."; +$a->strings["Please login."] = "Bitte melde dich an."; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = "Das Löschen von Konten innerhalb 48 Stunden nachdem deren Passwort geändert wurde ist nicht erlaubt."; +$a->strings["Remove This Account"] = "Dieses Konto löschen"; +$a->strings["This will completely remove this account including all its channels from the network. Once this has been done it is not recoverable."] = "Hiermit wird dieses Nutzerkonto einschließlich all seiner Kanäle komplett aus dem Netzwerk entfernt. Dieser Vorgang kann nicht rückgängig gemacht werden."; +$a->strings["Please enter your password for verification:"] = "Bitte gib zur Bestätigung Dein Passwort ein:"; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = "Dieses Konto, all seine Kanäle sowie alle Kanal-Klone aus dem Netzwerk löschen"; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = "Standardmäßig werden nur die Kanalklone auf diesem RedMatrix-Hub aus dem Netzwerk entfernt"; +$a->strings["[Embedded content - reload page to view]"] = "[Eingebettete Inhalte – lade die Seite neu, um sie anzuzeigen]"; +$a->strings["Wall Photos"] = "Wall Fotos"; +$a->strings["Profile Match"] = "Profil-Ãœbereinstimmungen"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "Keine Schlüsselwörter für den Abgleich gefunden. Bitte füge Schlüsselwörter zu Deinem Standardprofil hinzu."; +$a->strings["is interested in:"] = "interessiert sich für:"; +$a->strings["No matches"] = "Keine Ãœbereinstimmungen"; +$a->strings["Conversation removed."] = "Unterhaltung gelöscht."; +$a->strings["No messages."] = "Keine Nachrichten."; +$a->strings["Delete conversation"] = "Unterhaltung löschen"; +$a->strings["D, d M Y - g:i A"] = "D, d. M Y - G:i"; +$a->strings["Menu element updated."] = "Menü-Element aktualisiert."; +$a->strings["Unable to update menu element."] = "Kann Menü-Element nicht aktualisieren."; +$a->strings["Menu element added."] = "Menü-Bestandteil hinzugefügt."; +$a->strings["Unable to add menu element."] = "Kann Menü-Bestandteil nicht hinzufügen."; +$a->strings["Manage Menu Elements"] = "Menü-Bestandteile verwalten"; +$a->strings["Edit menu"] = "Menü bearbeiten"; +$a->strings["Edit element"] = "Bestandteil bearbeiten"; +$a->strings["Drop element"] = "Bestandteil löschen"; +$a->strings["New element"] = "Neues Bestandteil"; +$a->strings["Edit this menu container"] = "Diesen Menü-Container bearbeiten"; +$a->strings["Add menu element"] = "Menüelement hinzufügen"; +$a->strings["Delete this menu item"] = "Lösche dieses Menü-Bestandteil"; +$a->strings["Edit this menu item"] = "Bearbeite dieses Menü-Bestandteil"; +$a->strings["New Menu Element"] = "Neues Menü-Bestandteil"; +$a->strings["Menu Item Permissions"] = "Zugriffsrechte des Menü-Elements"; +$a->strings["Link text"] = "Link Text"; +$a->strings["URL of link"] = "URL des Links"; +$a->strings["Use RedMatrix magic-auth if available"] = "Verwende die automatische RedMatrix-Authentifizierung (magic-auth), wenn verfügbar"; +$a->strings["Open link in new window"] = "Öffne Link in neuem Fenster"; +$a->strings["Order in list"] = "Reihenfolge in der Liste"; +$a->strings["Higher numbers will sink to bottom of listing"] = "Größere Nummern werden weiter unten in der Auflistung einsortiert"; +$a->strings["Menu item not found."] = "Menü-Bestandteil nicht gefunden."; +$a->strings["Menu item deleted."] = "Menü-Bestandteil gelöscht."; +$a->strings["Menu item could not be deleted."] = "Menü-Bestandteil kann nicht gelöscht werden."; +$a->strings["Edit Menu Element"] = "Bearbeite Menü-Bestandteil"; +$a->strings["Set your current mood and tell your friends"] = "Wähle Deine aktuelle Stimmung und teile sie mit Deinen Freunden"; +$a->strings["Total votes"] = "Stimmen gesamt"; +$a->strings["Average Rating"] = "Durchschnittliche Bewertung"; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "Innerhalb von 48 Stunden nach einer Änderung des Passworts können keine Kanäle gelöscht werden."; +$a->strings["Remove This Channel"] = "Diesen Kanal löschen"; +$a->strings["This will completely remove this channel from the network. Once this has been done it is not recoverable."] = "Hiermit wird dieser Kanal komplett aus dem Netzwerk gelöscht. Einmal eingeleitet, kann dieser Prozess nicht wieder rückgängig gemacht werden."; +$a->strings["Remove this channel and all its clones from the network"] = "Lösche diesen Kanal und all seine Klone aus dem Netzwerk"; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = "Standardmäßig wird der Kanal nur auf diesem Server gelöscht, seine Klone verbleiben im Netzwerk"; +$a->strings["Remove Channel"] = "Kanal löschen"; +$a->strings["Help with this feature"] = "Hilfe zu dieser Funktion"; +$a->strings["Layout Name"] = "Layout-Name"; +$a->strings["Like/Dislike"] = "Mögen/Nicht mögen"; +$a->strings["This action is restricted to members."] = "Diese Aktion kann nur von Mitgliedern ausgeführt werden."; +$a->strings["Please login with your RedMatrix ID or register as a new RedMatrix member to continue."] = "Bitte melde Dich mit Deiner RedMatrix-ID an oder registriere Dich als neues Mitglied der RedMatrix, um fortzufahren."; +$a->strings["Invalid request."] = "Ungültige Anfrage."; +$a->strings["thing"] = "Sache"; +$a->strings["Channel unavailable."] = "Kanal nicht vorhanden."; +$a->strings["Previous action reversed."] = "Die vorherige Aktion wurde rückgängig gemacht."; +$a->strings["%1\$s agrees with %2\$s's %3\$s"] = "%1\$s stimmt %2\$ss %3\$s zu"; +$a->strings["%1\$s doesn't agree with %2\$s's %3\$s"] = "%1\$s lehnt %2\$ss %3\$s ab"; +$a->strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = "%1\$s enthält sich zu %2\$ss %3\$s"; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%1\$s nimmt an %2\$ss %3\$s teil"; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%1\$s nimmt an %2\$ss %3\$s nicht teil"; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%1\$s nimmt vielleicht an %2\$ss %3\$s teil"; +$a->strings["Action completed."] = "Aktion durchgeführt."; +$a->strings["Thank you."] = "Vielen Dank."; +$a->strings["Unable to lookup recipient."] = "Konnte den Empfänger nicht finden."; +$a->strings["Unable to communicate with requested channel."] = "Die Kommunikation mit dem ausgewählten Kanal ist fehlgeschlagen."; +$a->strings["Cannot verify requested channel."] = "Verifizierung des angeforderten Kanals fehlgeschlagen."; +$a->strings["Selected channel has private message restrictions. Send failed."] = "Der ausgewählte Kanal hat Einschränkungen bzgl. privater Nachrichten. Senden fehlgeschlagen."; +$a->strings["Message deleted."] = "Nachricht gelöscht."; +$a->strings["Message recalled."] = "Nachricht widerrufen."; +$a->strings["Send Private Message"] = "Private Nachricht senden"; +$a->strings["To:"] = "An:"; +$a->strings["Subject:"] = "Betreff:"; +$a->strings["Send"] = "Absenden"; +$a->strings["Message not found."] = "Nachricht nicht gefunden."; +$a->strings["Delete message"] = "Nachricht löschen"; +$a->strings["Recall message"] = "Nachricht widerrufen"; +$a->strings["Message has been recalled."] = "Die Nachricht wurde widerrufen."; +$a->strings["Private Conversation"] = "Private Unterhaltung"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Keine sichere Kommunikation verfügbar. Eventuell kannst Du auf der Profilseite des Absenders antworten."; +$a->strings["Send Reply"] = "Antwort senden"; +$a->strings["Invalid request identifier."] = "Ungültiger Anfrage-Identifikator."; +$a->strings["Discard"] = "Verwerfen"; +$a->strings["Add a Channel"] = "Kanal hinzufügen"; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = "Ein Kanal ist Deine eigene Sammlung von zusammengehörigen Webseiten. Ein Kanal kann genutzt werden, um ein Social-Network-Profil, ein Blog, eine Gesprächsgruppe oder ein Forum, Promi-Seiten und vieles mehr zu erstellen. Du kannst so viele Kanäle erstellen, wie es der Betreiber Deines Hubs zulässt."; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = "Beispiele: „Horst Weidinger“, „Lisa und ihr Meerschweinchen“, „Fußball“, „Segelflieger-Forum“ "; +$a->strings["Choose a short nickname"] = "Wähle einen kurzen Spitznamen"; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "Dein Spitzname wird verwendet, um eine leicht zu merkende Kanal-Adresse (ähnlich einer E-Mail-Adresse) zu erzeugen, die Du mit anderen austauschen kannst."; +$a->strings["Or import an existing channel from another location"] = "Oder importiere einen bestehenden Kanal von einem anderen Server"; +$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = "Wähle einen Kanaltyp (wie Soziales Netzwerk oder Forum) und Privatsphäre-Vorgaben, so dass wir die passenden Kanal-Zugriffsrechte für Dich setzen können"; +$a->strings["Channel Type"] = "Kanaltyp"; +$a->strings["Read more about roles"] = "Mehr Informationen über Rollen"; +$a->strings["OpenID protocol error. No ID returned."] = "OpenID Protokollfehler. Keine ID zurückgegeben."; +$a->strings["Page owner information could not be retrieved."] = "Informationen über den Besitzer der Seite konnten nicht gefunden werden."; +$a->strings["Album not found."] = "Album nicht gefunden."; +$a->strings["Delete Album"] = "Album löschen"; +$a->strings["Delete Photo"] = "Foto löschen"; +$a->strings["No photos selected"] = "Keine Fotos ausgewählt"; +$a->strings["Access to this item is restricted."] = "Der Zugriff auf dieses Foto ist eingeschränkt."; +$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "%1$.2f MB von %2$.2f MB Foto-Speicher belegt."; +$a->strings["%1$.2f MB photo storage used."] = "%1$.2f MB Foto-Speicher belegt."; +$a->strings["Upload Photos"] = "Fotos hochladen"; +$a->strings["Enter a new album name"] = "Gib einen Namen für ein neues Album ein"; +$a->strings["or select an existing one (doubleclick)"] = "oder wähle ein bereits vorhandenes aus (Doppelklick)"; +$a->strings["Do not show a status post for this upload"] = "Keine Statusnachricht für diesen Upload anzeigen"; +$a->strings["Album name could not be decoded"] = "Albumname konnte nicht dekodiert werden"; +$a->strings["Contact Photos"] = "Kontakt-Bilder"; +$a->strings["Show Newest First"] = "Neueste zuerst anzeigen"; +$a->strings["Show Oldest First"] = "Älteste zuerst anzeigen"; +$a->strings["View Photo"] = "Foto ansehen"; +$a->strings["Edit Album"] = "Album bearbeiten"; +$a->strings["Permission denied. Access to this item may be restricted."] = "Berechtigung verweigert. Der Zugriff ist wahrscheinlich eingeschränkt worden."; +$a->strings["Photo not available"] = "Foto nicht verfügbar"; +$a->strings["Use as profile photo"] = "Als Profilfoto verwenden"; +$a->strings["Private Photo"] = "Privates Foto"; +$a->strings["View Full Size"] = "In voller Größe anzeigen"; +$a->strings["Edit photo"] = "Foto bearbeiten"; +$a->strings["Rotate CW (right)"] = "Drehen im UZS (rechts)"; +$a->strings["Rotate CCW (left)"] = "Drehen gegen UZS (links)"; +$a->strings["Caption"] = "Bildunterschrift"; +$a->strings["Add a Tag"] = "Schlagwort hinzufügen"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Beispiele: @ben, @Karl_Prester, @lieschen@example.com"; +$a->strings["Flag as adult in album view"] = "In der Albumansicht als nicht jugendfrei markieren"; +$a->strings["In This Photo:"] = "Auf diesem Foto:"; +$a->strings["View Album"] = "Album ansehen"; +$a->strings["Recent Photos"] = "Neueste Fotos"; +$a->strings["sent you a private message"] = "hat Dir eine private Nachricht geschickt"; +$a->strings["added your channel"] = "hat deinen Kanal hinzugefügt"; +$a->strings["posted an event"] = "hat einen Termin veröffentlicht"; +$a->strings["Bookmark added"] = "Lesezeichen hinzugefügt"; +$a->strings["My Bookmarks"] = "Meine Lesezeichen"; +$a->strings["My Connections Bookmarks"] = "Lesezeichen meiner Kontakte"; +$a->strings["Insufficient permissions. Request redirected to profile page."] = "Unzureichende Zugriffsrechte. Die Anfrage wurde zur Profil-Seite umgeleitet."; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Maximale Anzahl täglicher Neuanmeldungen erreicht. Bitte versuche es morgen noch einmal."; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Bitte stimme den Nutzungsbedingungen zu. Registrierung fehlgeschlagen."; +$a->strings["Passwords do not match."] = "Passwörter stimmen nicht überein."; +$a->strings["Registration successful. Please check your email for validation instructions."] = "Registrierung erfolgreich. Eine E-Mail mit weiteren Anweisungen wurde an Dich gesendet."; +$a->strings["Your registration is pending approval by the site owner."] = "Deine Registrierung muss noch vom Betreiber der Seite freigegeben werden."; +$a->strings["Your registration can not be processed."] = "Deine Registrierung konnte nicht verarbeitet werden."; +$a->strings["Registration on this site/hub is by approval only."] = "Anmeldungen auf diesem Server erfordern Zustimmung durch den Administrator"; +$a->strings["Register at another affiliated site/hub"] = "Registrierung auf einem anderen, angeschlossenen Server"; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Die maximale Anzahl täglicher Registrierungen auf diesem Server wurde überschritten. Bitte versuche es morgen noch einmal."; +$a->strings["Terms of Service"] = "Nutzungsbedingungen"; +$a->strings["I accept the %s for this website"] = "Ich akzeptiere die %s für diese Webseite"; +$a->strings["I am over 13 years of age and accept the %s for this website"] = "Ich bin älter als 13 Jahre und akzeptiere die %s dieser Webseite"; +$a->strings["Membership on this site is by invitation only."] = "Mitgliedschaft auf dieser Seite ist nur nach vorheriger Einladung möglich."; +$a->strings["Please enter your invitation code"] = "Bitte trage Deinen Einladungs-Code ein"; +$a->strings["Your email address"] = "Ihre E-Mail Adresse"; +$a->strings["Choose a password"] = "Passwort"; +$a->strings["Please re-enter your password"] = "Bitte gib Dein Passwort noch einmal ein"; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Wir haben ein Problem mit der OpenID festgestellt, mit der Du Dich anmelden wolltest. Bitte überprüfe sie noch einmal."; +$a->strings["The error message was:"] = "Die Fehlermeldung war:"; +$a->strings["Authentication failed."] = "Authentifizierung fehlgeschlagen."; +$a->strings["Remote Authentication"] = "Entfernte Authentifizierung"; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Deine Kanal-Adresse (z. B. channel@example.com)"; +$a->strings["Authenticate"] = "Authentifizieren"; +$a->strings["Poll"] = "Umfrage"; +$a->strings["View Results"] = "Ergebnisse"; +$a->strings["No service class restrictions found."] = "Keine Dienstklassenbeschränkungen gefunden."; +$a->strings["Files: shared with me"] = "Dateien, die mit mir geteilt wurden"; +$a->strings["Remove all files"] = "Alle Dateien löschen"; +$a->strings["Remove this file"] = "Diese Datei löschen"; +$a->strings["Schema Default"] = "Standard-Schema"; +$a->strings["Sans-Serif"] = "Sans-Serif"; +$a->strings["Monospace"] = "Monospace"; +$a->strings["Theme settings"] = "Theme-Einstellungen"; +$a->strings["Set scheme"] = "Schema"; +$a->strings["Set font-size for posts and comments"] = "Schriftgröße für Beiträge und Kommentare"; +$a->strings["Set font face"] = "Schriftart"; +$a->strings["Set iconset"] = "Icon-Set"; +$a->strings["Set big shadow size, default 15px 15px 15px"] = "Ausmaß der großen Schatten (Voreinstellung 15px 15px 15px)"; +$a->strings["Set small shadow size, default 5px 5px 5px"] = "Ausmaß der kleinen Schatten (Voreinstellung 5px 5px 5px)"; +$a->strings["Set shadow color, default #000"] = "Farbe der Schatten (Voreinstellung #000)"; +$a->strings["Set radius size, default 5px"] = "Ecken-Radius (Voreinstellung 5px)"; +$a->strings["Set line-height for posts and comments"] = "Zeilenhöhe in Beiträgen und Kommentaren"; +$a->strings["Set background image"] = "Hintergrundbild"; +$a->strings["Set background attachment"] = "Hintergrunddatei"; +$a->strings["Set background color"] = "Hintergrundfarbe"; +$a->strings["Set section background image"] = "Hintergrundbild für die Section"; +$a->strings["Set section background color"] = "Hintergrundfarbe für die Section"; +$a->strings["Set color of items - use hex"] = "Farbe für Beiträge – Hex benutzen"; +$a->strings["Set color of links - use hex"] = "Farbe für Links – Hex benutzen"; +$a->strings["Set max-width for items. Default 400px"] = "Maximale Breite von Beiträgen (Voreinstellung 400px)"; +$a->strings["Set min-width for items. Default 240px"] = "Minimale Breite von Beiträgen (Voreinstellung 240px)"; +$a->strings["Set the generic content wrapper width. Default 48%"] = "Breite des \"generic content wrapper\" (Voreinstellung 48%)"; +$a->strings["Set color of fonts - use hex"] = "Schriftfarbe – Hex benutzen"; +$a->strings["Set background-size element"] = "Größe des Hintergrund-Elements"; +$a->strings["Item opacity"] = "Deckkraft der Beiträge"; +$a->strings["Display post previews only"] = "Nur Beitragsvorschau anzeigen"; +$a->strings["Display side bar on channel page"] = "Zeige die Seitenleiste auf der Kanal-Seite"; +$a->strings["Colour of the navigation bar"] = "Farbe der Navigationsleiste"; +$a->strings["Item float"] = "Beitragsfluss"; +$a->strings["Left offset of the section element"] = "Linker Rand des Section Elements"; +$a->strings["Right offset of the section element"] = "Rechter Rand des Section Elements"; +$a->strings["Section width"] = "Breite der Section"; +$a->strings["Left offset of the aside"] = "Linker Rand des Aside-Elements"; +$a->strings["Right offset of the aside element"] = "Rechter Rand des Aside-Elements"; +$a->strings["Light (Red Matrix default)"] = "Hell (RedMatrix-Voreinstellung)"; +$a->strings["Narrow navbar"] = "Schmale Navigationsleiste"; +$a->strings["Navigation bar background color"] = "Hintergrundfarbe der Navigationsleiste"; +$a->strings["Navigation bar gradient top color"] = "Farbverlauf der Navigationsleiste: Farbe oben"; +$a->strings["Navigation bar gradient bottom color"] = "Farbverlauf der Navigationsleiste: Farbe unten"; +$a->strings["Navigation active button gradient top color"] = "Navigations-Button aktiv: Farbe für Farbverlauf oben"; +$a->strings["Navigation active button gradient bottom color"] = "Navigations-Button aktiv: Farbe für Farbverlauf unten"; +$a->strings["Navigation bar border color "] = "Farbe für den Rand der Navigationsleiste"; +$a->strings["Navigation bar icon color "] = "Farbe für die Icons der Navigationsleiste"; +$a->strings["Navigation bar active icon color "] = "Farbe für aktive Icons der Navigationsleiste"; +$a->strings["link color"] = "Farbe für Links"; +$a->strings["Set font-color for banner"] = "Farbe der Schrift des Banners"; +$a->strings["Set the background color"] = "Hintergrundfarbe"; +$a->strings["Set the background image"] = "Hintergrundbild"; +$a->strings["Set the background color of items"] = "Hintergrundfarbe für Beiträge"; +$a->strings["Set the background color of comments"] = "Hintergrundfarbe für Kommentare"; +$a->strings["Set the border color of comments"] = "Farbe des Randes von Kommentaren"; +$a->strings["Set the indent for comments"] = "Einzugsbreite für Kommentare"; +$a->strings["Set the basic color for item icons"] = "Grundfarbe für Beitrags-Icons"; +$a->strings["Set the hover color for item icons"] = "Farbe für Beitrags-Icons unter dem Mauszeiger"; +$a->strings["Set font-size for the entire application"] = "Schriftgröße für die gesamte Anwendung"; +$a->strings["Set font-color for posts and comments"] = "Schriftfarbe für Beiträge und Kommentare"; +$a->strings["Set radius of corners"] = "Ecken-Radius"; +$a->strings["Set shadow depth of photos"] = "Schattentiefe von Fotos"; +$a->strings["Set maximum width of conversation regions"] = "Maximalbreite der Unterhaltungsbereiche"; +$a->strings["Center conversation regions"] = "Konversationsbereich zentrieren"; +$a->strings["Set minimum opacity of nav bar - to hide it"] = "Mindest-Deckkraft der Navigationsleiste ( - versteckt sie)"; +$a->strings["Set size of conversation author photo"] = "Größe der Avatare von Themenstartern"; +$a->strings["Set size of followup author photos"] = "Größe der Avatare von Kommentatoren"; +$a->strings["Sloppy photo albums"] = "Schräge Fotoalben"; +$a->strings["Are you a clean desk or a messy desk person?"] = "Bist Du jemand, der einen aufgeräumten Schreibtisch hat, oder eher einen chaotischen?"; +$a->strings["Update %s failed. See error logs."] = "Aktualisierung %s fehlgeschlagen. Details in den Fehlerprotokollen."; +$a->strings["Update Error at %s"] = "Aktualisierungsfehler auf %s"; +$a->strings["Create an account to access services and applications within the Red Matrix"] = "Erstelle einen Account, um Anwendungen und Dienste innerhalb der Red-Matrix verwenden zu können."; +$a->strings["Password"] = "Kennwort"; +$a->strings["Remember me"] = "Angaben speichern"; +$a->strings["Forgot your password?"] = "Passwort vergessen?"; +$a->strings["permission denied"] = "Zugriff verweigert"; +$a->strings["Got Zot?"] = "Haste schon Zot?"; +$a->strings["toggle mobile"] = "auf/von mobile Ansicht wechseln"; diff --git a/sources/view/de/update_fail_eml.tpl b/sources/view/de/update_fail_eml.tpl new file mode 100644 index 00000000..ca1a4985 --- /dev/null +++ b/sources/view/de/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hallo, +ich bin der Webserver für {{$sitename}}; + +Die RedMatrix-Entwickler haben kürzlich das Update {{$update}} veröffentlicht, +aber als ich versuchte, es zu installieren, ging irgendwas furchtbar schief. +Das muss so bald als möglich gelöst werden und erfordert einen manuellen Eingriff. +Bitte kontaktiere einen Red-Entwickler, wenn Du nicht weißt, wie Du das Problem +selbst beheben kannst. Meine Datenbank ist eventuell ungültig. + +Die Fehlermeldung ist '{{$error}}'. + +Bitte entschuldige die Unannehmlichkeit, + Dein Web-Server auf {{$siteurl}} \ No newline at end of file diff --git a/sources/view/en-au/htconfig.tpl b/sources/view/en-au/htconfig.tpl new file mode 100644 index 00000000..c3bef0de --- /dev/null +++ b/sources/view/en-au/htconfig.tpl @@ -0,0 +1,98 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + + +// Site access restrictions. By default we will create private sites. +// Your choices are ACCESS_PRIVATE, ACCESS_PAID, ACCESS_TIERED, and ACCESS_FREE. +// If you leave REGISTER_OPEN above, anybody may register on your +// site, however your site will not be listed anywhere as an open +// registration hub. We will use the system access policy (below) +// to determine whether or not to list your site in the directory +// as an open hub where anybody may create accounts. Your choice of +// paid, tiered, or free determines how these listings will be presented. + + +$a->config['system']['access_policy'] = ACCESS_PRIVATE; + +// If you operate a public site, you might wish that people are directed +// to a "sellpage" where you can describe for features or policies or service plans in depth. +// This must be an absolute URL beginning with http:// or https:// . + +$a->config['system']['sellpage'] = ''; + +// Maximum size of an imported message, 0 is unlimited +// FIXME - NOT currently implemented. + +$a->config['system']['max_import_size'] = 200000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + + +// PHP error logging setup +// Before doing this ensure that the webserver has permission +// to create and write to php.out in the top level Red directory, +// or change the name (below) to a file/path where this is allowed. + +// Uncomment the following 4 lines to turn on PHP error logging. +//error_reporting(E_ERROR | E_WARNING | E_PARSE ); +//ini_set('error_log','php.out'); +//ini_set('log_errors','1'); +//ini_set('display_errors', '0'); diff --git a/sources/view/en-au/lostpass_eml.tpl b/sources/view/en-au/lostpass_eml.tpl new file mode 100644 index 00000000..3b79d279 --- /dev/null +++ b/sources/view/en-au/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Dear {{$username}}, + A request was recently received at {{$sitename}} to reset your account +password. In order to confirm this request, please select the verification link +below or paste it into your web browser address bar. + +If you did NOT request this change, please DO NOT follow the link +provided and ignore and/or delete this email. + +Your password will not be changed unless we can verify that you +issued this request. + +Follow this link to verify your identity: + +{{$reset_link}} + +You will then receive a follow-up message containing the new password. + +You may change that password from your account settings page after logging in. + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + + + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-au/passchanged_eml.tpl b/sources/view/en-au/passchanged_eml.tpl new file mode 100644 index 00000000..0d94be3c --- /dev/null +++ b/sources/view/en-au/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Dear {{$username}}, + Your password has been changed as requested. Please retain this +information for your records (or change your password immediately to +something that you will remember). + + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +Password: {{$new_password}} + +You may change that password from your account settings page after logging in. + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-au/register_open_eml.tpl b/sources/view/en-au/register_open_eml.tpl new file mode 100644 index 00000000..4b397201 --- /dev/null +++ b/sources/view/en-au/register_open_eml.tpl @@ -0,0 +1,19 @@ + +An account has been created at {{$sitename}} for this email address. +The login details are as follows: + +Site Location: {{$siteurl}} +Login: {{$email}} +Password: (the password which was provided during registration) + +If this account was created without your knowledge and is not desired, you may +visit this site and reset the password. This will allow you to remove the +account from the links on the Settings page, and we +apologise for any inconvenience. + +Thank you and welcome to {{$sitename}}. + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-au/register_verify_eml.tpl b/sources/view/en-au/register_verify_eml.tpl new file mode 100644 index 00000000..85d9a12d --- /dev/null +++ b/sources/view/en-au/register_verify_eml.tpl @@ -0,0 +1,25 @@ + +A new user registration request was received at {{$sitename}} which requires +your approval. + + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +IP Address: {{$details}} + +To approve this request please visit the following link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en-au/register_verify_member.tpl b/sources/view/en-au/register_verify_member.tpl new file mode 100644 index 00000000..d1e34be6 --- /dev/null +++ b/sources/view/en-au/register_verify_member.tpl @@ -0,0 +1,25 @@ + +Thank you for registering at {{$sitename}}. + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + +Login with the password you chose at registration. + +We need to verify your email address in order to give you full access. + +If you registered this account, please visit the following link: + +{{$siteurl}}/regver/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en-au/strings.php b/sources/view/en-au/strings.php new file mode 100644 index 00000000..db383f50 --- /dev/null +++ b/sources/view/en-au/strings.php @@ -0,0 +1,5 @@ +strings['Welcome %s. Remote authentication successful.'] = "G'day %s. Remote authentication successful"; + + diff --git a/sources/view/en-au/update_fail_eml.tpl b/sources/view/en-au/update_fail_eml.tpl new file mode 100644 index 00000000..61f44b1e --- /dev/null +++ b/sources/view/en-au/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hey, +I'm the web server at {{$sitename}}; + +The Hubzilla developers released update {{$update}} recently, +but when I tried to install it, something went terribly wrong. +This needs to be fixed soon and it requires human intervention. +Please contact a Red developer if you can not figure out how to +fix it on your own. My database might be invalid. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/en-gb/htconfig.tpl b/sources/view/en-gb/htconfig.tpl new file mode 100644 index 00000000..c3bef0de --- /dev/null +++ b/sources/view/en-gb/htconfig.tpl @@ -0,0 +1,98 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + + +// Site access restrictions. By default we will create private sites. +// Your choices are ACCESS_PRIVATE, ACCESS_PAID, ACCESS_TIERED, and ACCESS_FREE. +// If you leave REGISTER_OPEN above, anybody may register on your +// site, however your site will not be listed anywhere as an open +// registration hub. We will use the system access policy (below) +// to determine whether or not to list your site in the directory +// as an open hub where anybody may create accounts. Your choice of +// paid, tiered, or free determines how these listings will be presented. + + +$a->config['system']['access_policy'] = ACCESS_PRIVATE; + +// If you operate a public site, you might wish that people are directed +// to a "sellpage" where you can describe for features or policies or service plans in depth. +// This must be an absolute URL beginning with http:// or https:// . + +$a->config['system']['sellpage'] = ''; + +// Maximum size of an imported message, 0 is unlimited +// FIXME - NOT currently implemented. + +$a->config['system']['max_import_size'] = 200000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + + +// PHP error logging setup +// Before doing this ensure that the webserver has permission +// to create and write to php.out in the top level Red directory, +// or change the name (below) to a file/path where this is allowed. + +// Uncomment the following 4 lines to turn on PHP error logging. +//error_reporting(E_ERROR | E_WARNING | E_PARSE ); +//ini_set('error_log','php.out'); +//ini_set('log_errors','1'); +//ini_set('display_errors', '0'); diff --git a/sources/view/en-gb/lostpass_eml.tpl b/sources/view/en-gb/lostpass_eml.tpl new file mode 100644 index 00000000..3b79d279 --- /dev/null +++ b/sources/view/en-gb/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Dear {{$username}}, + A request was recently received at {{$sitename}} to reset your account +password. In order to confirm this request, please select the verification link +below or paste it into your web browser address bar. + +If you did NOT request this change, please DO NOT follow the link +provided and ignore and/or delete this email. + +Your password will not be changed unless we can verify that you +issued this request. + +Follow this link to verify your identity: + +{{$reset_link}} + +You will then receive a follow-up message containing the new password. + +You may change that password from your account settings page after logging in. + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + + + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-gb/passchanged_eml.tpl b/sources/view/en-gb/passchanged_eml.tpl new file mode 100644 index 00000000..0d94be3c --- /dev/null +++ b/sources/view/en-gb/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Dear {{$username}}, + Your password has been changed as requested. Please retain this +information for your records (or change your password immediately to +something that you will remember). + + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +Password: {{$new_password}} + +You may change that password from your account settings page after logging in. + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-gb/register_open_eml.tpl b/sources/view/en-gb/register_open_eml.tpl new file mode 100644 index 00000000..4b397201 --- /dev/null +++ b/sources/view/en-gb/register_open_eml.tpl @@ -0,0 +1,19 @@ + +An account has been created at {{$sitename}} for this email address. +The login details are as follows: + +Site Location: {{$siteurl}} +Login: {{$email}} +Password: (the password which was provided during registration) + +If this account was created without your knowledge and is not desired, you may +visit this site and reset the password. This will allow you to remove the +account from the links on the Settings page, and we +apologise for any inconvenience. + +Thank you and welcome to {{$sitename}}. + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en-gb/register_verify_eml.tpl b/sources/view/en-gb/register_verify_eml.tpl new file mode 100644 index 00000000..85d9a12d --- /dev/null +++ b/sources/view/en-gb/register_verify_eml.tpl @@ -0,0 +1,25 @@ + +A new user registration request was received at {{$sitename}} which requires +your approval. + + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +IP Address: {{$details}} + +To approve this request please visit the following link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en-gb/register_verify_member.tpl b/sources/view/en-gb/register_verify_member.tpl new file mode 100644 index 00000000..d1e34be6 --- /dev/null +++ b/sources/view/en-gb/register_verify_member.tpl @@ -0,0 +1,25 @@ + +Thank you for registering at {{$sitename}}. + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + +Login with the password you chose at registration. + +We need to verify your email address in order to give you full access. + +If you registered this account, please visit the following link: + +{{$siteurl}}/regver/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en-gb/strings.php b/sources/view/en-gb/strings.php new file mode 100644 index 00000000..1cac5673 --- /dev/null +++ b/sources/view/en-gb/strings.php @@ -0,0 +1,31 @@ +strings["Set shadow color, default #000"] = "Set shadow colour, default #000"; +$a->strings["Set background color"] = "Set background colour"; +$a->strings["Set section background color"] = "Set section background colour"; +$a->strings["Set color of items - use hex"] = "Set colour of items - use hex"; +$a->strings["Set color of links - use hex"] = "Set colour of links - use hex"; +$a->strings["Set color of fonts - use hex"] = "Set colour of fonts - use hex"; +$a->strings["Navigation bar background color"] = "Navigation bar background colour"; +$a->strings["Navigation bar gradient top color"] = "Navigation bar gradient top colour"; +$a->strings["Navigation bar gradient bottom color"] = "Navigation bar gradient bottom colour"; +$a->strings["Navigation active button gradient top color"] = "Navigation active button gradient top colour"; +$a->strings["Navigation active button gradient bottom color"] = "Navigation active button gradient bottom colour"; +$a->strings["Navigation bar border color "] = "Navigation bar border colour "; +$a->strings["Navigation bar icon color "] = "Navigation bar icon colour "; +$a->strings["Navigation bar active icon color "] = "Navigation bar active icon colour "; +$a->strings["link color"] = "link colour"; +$a->strings["Set font-color for banner"] = "Set font-colour for banner"; +$a->strings["Set the background color"] = "Set the background colour"; +$a->strings["Set the background color of items"] = "Set the background colour of items"; +$a->strings["Set the background color of comments"] = "Set the background colour of comments"; +$a->strings["Set the border color of comments"] = "Set the border colour of comments"; +$a->strings["Set the basic color for item icons"] = "Set the basic colour for item icons"; +$a->strings["Set the hover color for item icons"] = "Set the hover colour for item icons"; +$a->strings["Set font-color for posts and comments"] = "Set font-colour for posts and comments"; +$a->strings["Authorize application connection"] = "Authorise application connection"; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Do you want to authorise this application to access your posts and contacts, and/or create new posts for you?"; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "If your certificate is not recognised, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."; +$a->strings["This is a hub of the Hubzilla - a global cooperative network of decentralized privacy enhanced websites."] = "This is a hub of the Hubzilla - a global cooperative network of decentralised privacy enhanced websites."; +$a->strings["You are cordially invited to join me and some other close friends on the Hubzilla - a revolutionary new decentralized communication and information tool."] = "You are cordially invited to join me and some other close friends on the Hubzilla - a revolutionary new decentralised communication and information tool."; +$a->strings["l F d, Y \\@ g:i A"] = "l j F, Y \\@ G:i"; +$a->strings["D, d M Y - g:i A"] = "D, d M Y - G:i"; diff --git a/sources/view/en-gb/update_fail_eml.tpl b/sources/view/en-gb/update_fail_eml.tpl new file mode 100644 index 00000000..61f44b1e --- /dev/null +++ b/sources/view/en-gb/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hey, +I'm the web server at {{$sitename}}; + +The Hubzilla developers released update {{$update}} recently, +but when I tried to install it, something went terribly wrong. +This needs to be fixed soon and it requires human intervention. +Please contact a Red developer if you can not figure out how to +fix it on your own. My database might be invalid. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/en/cert_bad_eml.tpl b/sources/view/en/cert_bad_eml.tpl new file mode 100644 index 00000000..e42b9696 --- /dev/null +++ b/sources/view/en/cert_bad_eml.tpl @@ -0,0 +1,20 @@ +This is the webserver at {{$sitename}}; + +A routine check indicates the SSL certificate for this website is +not valid. Your website cannot fully participate in the Hubzilla +until this is resolved. Please check your certificate and with your +certificate provider or service provider to ensure it is "browser valid" +and installed correctly. Self-signed certificates are NOT SUPPORTED +and NOT ALLOWED in the Hubzilla. + +The check is performed by fetching a URL from your website with strict +SSL checking enabled, and if this fails, checking again with SSL +checks disabled. It's possible a transient error could produce this +message, but if any recent configuration changes have been made, +or if you receive this message more than once, please check your +certificate. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/en/cron_bad_eml.tpl b/sources/view/en/cron_bad_eml.tpl new file mode 100644 index 00000000..ce30dae7 --- /dev/null +++ b/sources/view/en/cron_bad_eml.tpl @@ -0,0 +1,17 @@ +This is the webserver at {{$sitename}}; + +A routine check indicates the scheduled maintenance tasks on this +website are not running. Please review your "cron" jobs or the +equivalent mechanism on your operating system and ensure these are +running. Please review the INSTALL instructions if you are seeing +this message for the first time. If these maintenance tasks have +been running normally until now, please check to see if anything +may have gone wrong to account for them not running currently. +This check is run approximately every three days. + +The error message is '{{$error}}'. + +The last successful execution was '{{$lastdate}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/en/htconfig.tpl b/sources/view/en/htconfig.tpl new file mode 100644 index 00000000..c6357b3a --- /dev/null +++ b/sources/view/en/htconfig.tpl @@ -0,0 +1,103 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// Recommend you leave this set to 1. Set to 0 to let people register without +// proving they own the email address they register with. + +$a->config['system']['verify_email'] = 1; + + +// Site access restrictions. By default we will create private sites. +// Your choices are ACCESS_PRIVATE, ACCESS_PAID, ACCESS_TIERED, and ACCESS_FREE. +// If you leave REGISTER_OPEN above, anybody may register on your +// site, however your site will not be listed anywhere as an open +// registration hub. We will use the system access policy (below) +// to determine whether or not to list your site in the directory +// as an open hub where anybody may create accounts. Your choice of +// paid, tiered, or free determines how these listings will be presented. + + +$a->config['system']['access_policy'] = ACCESS_PRIVATE; + +// If you operate a public site, you might wish that people are directed +// to a "sellpage" where you can describe for features or policies or service plans in depth. +// This must be an absolute URL beginning with http:// or https:// . + +$a->config['system']['sellpage'] = ''; + +// Maximum size of an imported message, 0 is unlimited + +$a->config['system']['max_import_size'] = 200000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + + +// PHP error logging setup +// Before doing this ensure that the webserver has permission +// to create and write to php.out in the top level Red directory, +// or change the name (below) to a file/path where this is allowed. + +// Uncomment the following 4 lines to turn on PHP error logging. +//error_reporting(E_ERROR | E_WARNING | E_PARSE ); +//ini_set('error_log','php.out'); +//ini_set('log_errors','1'); +//ini_set('display_errors', '0'); diff --git a/sources/view/en/lostpass_eml.tpl b/sources/view/en/lostpass_eml.tpl new file mode 100644 index 00000000..3b79d279 --- /dev/null +++ b/sources/view/en/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Dear {{$username}}, + A request was recently received at {{$sitename}} to reset your account +password. In order to confirm this request, please select the verification link +below or paste it into your web browser address bar. + +If you did NOT request this change, please DO NOT follow the link +provided and ignore and/or delete this email. + +Your password will not be changed unless we can verify that you +issued this request. + +Follow this link to verify your identity: + +{{$reset_link}} + +You will then receive a follow-up message containing the new password. + +You may change that password from your account settings page after logging in. + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + + + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en/passchanged_eml.tpl b/sources/view/en/passchanged_eml.tpl new file mode 100644 index 00000000..0d94be3c --- /dev/null +++ b/sources/view/en/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Dear {{$username}}, + Your password has been changed as requested. Please retain this +information for your records (or change your password immediately to +something that you will remember). + + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +Password: {{$new_password}} + +You may change that password from your account settings page after logging in. + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en/register_open_eml.tpl b/sources/view/en/register_open_eml.tpl new file mode 100644 index 00000000..4b397201 --- /dev/null +++ b/sources/view/en/register_open_eml.tpl @@ -0,0 +1,19 @@ + +An account has been created at {{$sitename}} for this email address. +The login details are as follows: + +Site Location: {{$siteurl}} +Login: {{$email}} +Password: (the password which was provided during registration) + +If this account was created without your knowledge and is not desired, you may +visit this site and reset the password. This will allow you to remove the +account from the links on the Settings page, and we +apologise for any inconvenience. + +Thank you and welcome to {{$sitename}}. + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/en/register_verify_eml.tpl b/sources/view/en/register_verify_eml.tpl new file mode 100644 index 00000000..85d9a12d --- /dev/null +++ b/sources/view/en/register_verify_eml.tpl @@ -0,0 +1,25 @@ + +A new user registration request was received at {{$sitename}} which requires +your approval. + + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +IP Address: {{$details}} + +To approve this request please visit the following link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en/register_verify_member.tpl b/sources/view/en/register_verify_member.tpl new file mode 100644 index 00000000..d1e34be6 --- /dev/null +++ b/sources/view/en/register_verify_member.tpl @@ -0,0 +1,25 @@ + +Thank you for registering at {{$sitename}}. + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + +Login with the password you chose at registration. + +We need to verify your email address in order to give you full access. + +If you registered this account, please visit the following link: + +{{$siteurl}}/regver/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/en/update_fail_eml.tpl b/sources/view/en/update_fail_eml.tpl new file mode 100644 index 00000000..61f44b1e --- /dev/null +++ b/sources/view/en/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hey, +I'm the web server at {{$sitename}}; + +The Hubzilla developers released update {{$update}} recently, +but when I tried to install it, something went terribly wrong. +This needs to be fixed soon and it requires human intervention. +Please contact a Red developer if you can not figure out how to +fix it on your own. My database might be invalid. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/eo/htconfig.tpl b/sources/view/eo/htconfig.tpl new file mode 100644 index 00000000..cc4087f9 --- /dev/null +++ b/sources/view/eo/htconfig.tpl @@ -0,0 +1,70 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// Maximum size of an imported message, 0 is unlimited + +$a->config['system']['max_import_size'] = 200000; + +// maximum size of uploaded photos + +$a->config['system']['maximagesize'] = 8000000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + diff --git a/sources/view/eo/lostpass_eml.tpl b/sources/view/eo/lostpass_eml.tpl new file mode 100644 index 00000000..3b79d279 --- /dev/null +++ b/sources/view/eo/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Dear {{$username}}, + A request was recently received at {{$sitename}} to reset your account +password. In order to confirm this request, please select the verification link +below or paste it into your web browser address bar. + +If you did NOT request this change, please DO NOT follow the link +provided and ignore and/or delete this email. + +Your password will not be changed unless we can verify that you +issued this request. + +Follow this link to verify your identity: + +{{$reset_link}} + +You will then receive a follow-up message containing the new password. + +You may change that password from your account settings page after logging in. + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} + + + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/eo/messages.po b/sources/view/eo/messages.po new file mode 100644 index 00000000..7fd842bb --- /dev/null +++ b/sources/view/eo/messages.po @@ -0,0 +1,7714 @@ +# FRIENDICA Distributed Social Network +# Copyright (C) 2010, 2011 the Friendica Project +# This file is distributed under the same license as the Friendica package. +# +# Translators: +# Diego Souza , 2012. +# Martin Schmitt , 2012. +msgid "" +msgstr "" +"Project-Id-Version: friendica\n" +"Report-Msgid-Bugs-To: http://bugs.friendica.com/\n" +"POT-Creation-Date: 2012-06-30 10:00-0700\n" +"PO-Revision-Date: 2012-07-01 16:55+0000\n" +"Last-Translator: Martin Schmitt \n" +"Language-Team: Esperanto (http://www.transifex.com/projects/p/friendica/language/eo/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: eo\n" +"Plural-Forms: nplurals=2; plural=(n != 1)\n" + +#: ../../mod/oexchange.php:25 +msgid "Post successful." +msgstr "Sukcese afiÅita." + +#: ../../mod/update_notes.php:41 ../../mod/update_community.php:18 +#: ../../mod/update_network.php:22 ../../mod/update_profile.php:41 +msgid "[Embedded content - reload page to view]" +msgstr "[Enigita enhavo - reÅargu paÄon por spekti Äin]" + +#: ../../mod/crepair.php:102 +msgid "Contact settings applied." +msgstr "Kontaktagordoj estas konservita." + +#: ../../mod/crepair.php:104 +msgid "Contact update failed." +msgstr "Äœisdatigo de kontakto malsukcesis." + +#: ../../mod/crepair.php:115 ../../mod/wall_attach.php:44 +#: ../../mod/fsuggest.php:78 ../../mod/events.php:140 ../../mod/api.php:26 +#: ../../mod/api.php:31 ../../mod/photos.php:135 ../../mod/photos.php:951 +#: ../../mod/editpost.php:10 ../../mod/install.php:151 +#: ../../mod/notifications.php:66 ../../mod/contacts.php:145 +#: ../../mod/settings.php:106 ../../mod/settings.php:537 +#: ../../mod/settings.php:542 ../../mod/manage.php:86 ../../mod/network.php:6 +#: ../../mod/notes.php:20 ../../mod/wallmessage.php:9 +#: ../../mod/wallmessage.php:33 ../../mod/wallmessage.php:79 +#: ../../mod/wallmessage.php:103 ../../mod/attach.php:33 +#: ../../mod/group.php:19 ../../mod/viewconnections.php:22 +#: ../../mod/register.php:38 ../../mod/regmod.php:116 ../../mod/item.php:124 +#: ../../mod/item.php:140 ../../mod/profile_photo.php:19 +#: ../../mod/profile_photo.php:141 ../../mod/profile_photo.php:152 +#: ../../mod/profile_photo.php:165 ../../mod/message.php:45 +#: ../../mod/message.php:97 ../../mod/allfriends.php:9 +#: ../../mod/nogroup.php:25 ../../mod/wall_upload.php:53 +#: ../../mod/follow.php:9 ../../mod/display.php:138 ../../mod/profiles.php:7 +#: ../../mod/profiles.php:400 ../../mod/delegate.php:6 +#: ../../mod/suggest.php:28 ../../mod/invite.php:13 ../../mod/invite.php:81 +#: ../../mod/dfrn_confirm.php:53 ../../addon/facebook/facebook.php:508 +#: ../../addon/facebook/facebook.php:514 ../../addon/dav/layout.fnk.php:353 +#: ../../include/items.php:3455 ../../index.php:309 +msgid "Permission denied." +msgstr "Malpermesita." + +#: ../../mod/crepair.php:129 ../../mod/fsuggest.php:20 +#: ../../mod/fsuggest.php:92 ../../mod/dfrn_confirm.php:118 +msgid "Contact not found." +msgstr "Kontakto ne trovita." + +#: ../../mod/crepair.php:135 +msgid "Repair Contact Settings" +msgstr "Ripari kontaktagordoj." + +#: ../../mod/crepair.php:137 +msgid "" +"WARNING: This is highly advanced and if you enter incorrect" +" information your communications with this contact may stop working." +msgstr "AVERTO: Tio estas tre altnivela kaj se vi entajpus malÄustan informojn, komunikado kun la kontakto eble ne plu funkcios." + +#: ../../mod/crepair.php:138 +msgid "" +"Please use your browser 'Back' button now if you are " +"uncertain what to do on this page." +msgstr "Bonvolu klaki 'malantaÅ­en' en via retesplorilo nun se vi ne scias kion faru ĉi tie." + +#: ../../mod/crepair.php:144 +msgid "Return to contact editor" +msgstr "Reen al kontakta redaktilo" + +#: ../../mod/crepair.php:148 ../../mod/settings.php:557 +#: ../../mod/settings.php:583 ../../mod/admin.php:659 ../../mod/admin.php:668 +msgid "Name" +msgstr "Nomo" + +#: ../../mod/crepair.php:149 +msgid "Account Nickname" +msgstr "KaÅnomo de la konto" + +#: ../../mod/crepair.php:150 +msgid "@Tagname - overrides Name/Nickname" +msgstr "@Marknomo - Transpasas nomon/kaÅnomon" + +#: ../../mod/crepair.php:151 +msgid "Account URL" +msgstr "Adreso de la konto" + +#: ../../mod/crepair.php:152 +msgid "Friend Request URL" +msgstr "Kontaktpeta adreso" + +#: ../../mod/crepair.php:153 +msgid "Friend Confirm URL" +msgstr "Kontaktkonfirma adreso" + +#: ../../mod/crepair.php:154 +msgid "Notification Endpoint URL" +msgstr "Finpunkta adreso por atentigoj" + +#: ../../mod/crepair.php:155 +msgid "Poll/Feed URL" +msgstr "Adreso de fluo" + +#: ../../mod/crepair.php:156 +msgid "New photo from this URL" +msgstr "Nova bildo el tiu adreso" + +#: ../../mod/crepair.php:166 ../../mod/fsuggest.php:107 +#: ../../mod/events.php:436 ../../mod/photos.php:986 ../../mod/photos.php:1057 +#: ../../mod/photos.php:1303 ../../mod/photos.php:1343 +#: ../../mod/photos.php:1383 ../../mod/photos.php:1414 +#: ../../mod/install.php:246 ../../mod/install.php:284 +#: ../../mod/localtime.php:45 ../../mod/contacts.php:343 +#: ../../mod/settings.php:555 ../../mod/settings.php:709 +#: ../../mod/settings.php:770 ../../mod/settings.php:971 +#: ../../mod/group.php:85 ../../mod/message.php:216 ../../mod/message.php:410 +#: ../../mod/admin.php:420 ../../mod/admin.php:656 ../../mod/admin.php:792 +#: ../../mod/admin.php:991 ../../mod/admin.php:1078 ../../mod/profiles.php:569 +#: ../../mod/invite.php:119 ../../addon/fromgplus/fromgplus.php:40 +#: ../../addon/facebook/facebook.php:617 +#: ../../addon/snautofollow/snautofollow.php:64 +#: ../../addon/yourls/yourls.php:76 ../../addon/ljpost/ljpost.php:93 +#: ../../addon/nsfw/nsfw.php:57 ../../addon/page/page.php:208 +#: ../../addon/planets/planets.php:158 +#: ../../addon/uhremotestorage/uhremotestorage.php:89 +#: ../../addon/randplace/randplace.php:177 ../../addon/dwpost/dwpost.php:93 +#: ../../addon/drpost/drpost.php:110 ../../addon/startpage/startpage.php:92 +#: ../../addon/geonames/geonames.php:187 ../../addon/oembed.old/oembed.php:41 +#: ../../addon/impressum/impressum.php:82 +#: ../../addon/notimeline/notimeline.php:64 ../../addon/blockem/blockem.php:57 +#: ../../addon/qcomment/qcomment.php:61 +#: ../../addon/openstreetmap/openstreetmap.php:70 +#: ../../addon/libertree/libertree.php:90 ../../addon/mathjax/mathjax.php:42 +#: ../../addon/editplain/editplain.php:84 ../../addon/blackout/blackout.php:98 +#: ../../addon/gravatar/gravatar.php:86 +#: ../../addon/pageheader/pageheader.php:55 ../../addon/ijpost/ijpost.php:93 +#: ../../addon/jappixmini/jappixmini.php:302 +#: ../../addon/statusnet/statusnet.php:278 +#: ../../addon/statusnet/statusnet.php:292 +#: ../../addon/statusnet/statusnet.php:318 +#: ../../addon/statusnet/statusnet.php:325 +#: ../../addon/statusnet/statusnet.php:353 +#: ../../addon/statusnet/statusnet.php:567 ../../addon/tumblr/tumblr.php:90 +#: ../../addon/numfriends/numfriends.php:85 ../../addon/gnot/gnot.php:88 +#: ../../addon/wppost/wppost.php:110 ../../addon/showmore/showmore.php:48 +#: ../../addon/piwik/piwik.php:89 ../../addon/twitter/twitter.php:180 +#: ../../addon/twitter/twitter.php:209 ../../addon/twitter/twitter.php:387 +#: ../../addon/irc/irc.php:55 ../../addon/blogger/blogger.php:102 +#: ../../addon/posterous/posterous.php:103 +#: ../../view/theme/cleanzero/config.php:80 +#: ../../view/theme/diabook/theme.php:757 +#: ../../view/theme/diabook/config.php:190 +#: ../../view/theme/quattro/config.php:52 ../../view/theme/dispy/config.php:70 +#: ../../include/conversation.php:580 +msgid "Submit" +msgstr "Sendi" + +#: ../../mod/help.php:30 +msgid "Help:" +msgstr "Helpo:" + +#: ../../mod/help.php:34 ../../addon/dav/layout.fnk.php:116 +#: ../../include/nav.php:86 +msgid "Help" +msgstr "Helpo" + +#: ../../mod/help.php:38 ../../index.php:218 +msgid "Not Found" +msgstr "Ne trovita" + +#: ../../mod/help.php:41 ../../index.php:221 +msgid "Page not found." +msgstr "PaÄo ne trovita" + +#: ../../mod/wall_attach.php:58 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Dosiero estas pli granda ol la limito de %d" + +#: ../../mod/wall_attach.php:99 ../../mod/wall_attach.php:110 +msgid "File upload failed." +msgstr "AlÅutado malsukcesis." + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Amikosugesto sendita." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Sugesti amikojn" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Sugesti amikon por %s" + +#: ../../mod/events.php:66 +msgid "Event title and start time are required." +msgstr "Titolo kaj starttempo estas bezonataj por la okazo." + +#: ../../mod/events.php:260 +msgid "l, F j" +msgstr "l, F j" + +#: ../../mod/events.php:282 +msgid "Edit event" +msgstr "Redakti okazon" + +#: ../../mod/events.php:304 ../../include/text.php:1065 +msgid "link to source" +msgstr "ligilo al fonto" + +#: ../../mod/events.php:328 ../../view/theme/diabook/theme.php:131 +#: ../../include/nav.php:52 ../../boot.php:1559 +msgid "Events" +msgstr "Okazoj" + +#: ../../mod/events.php:329 +msgid "Create New Event" +msgstr "Krei novan okazon" + +#: ../../mod/events.php:330 ../../addon/dav/layout.fnk.php:154 +msgid "Previous" +msgstr "antaÅ­a" + +#: ../../mod/events.php:331 ../../mod/install.php:205 +#: ../../addon/dav/layout.fnk.php:157 +msgid "Next" +msgstr "sekva" + +#: ../../mod/events.php:404 +msgid "hour:minute" +msgstr "horo:minuto" + +#: ../../mod/events.php:414 +msgid "Event details" +msgstr "Detaloj de okazo" + +#: ../../mod/events.php:415 +#, php-format +msgid "Format is %s %s. Starting date and Title are required." +msgstr "Format is %s %s. Titolo kaj starttempo estas bezonataj." + +#: ../../mod/events.php:417 +msgid "Event Starts:" +msgstr "Okazo startas:" + +#: ../../mod/events.php:417 ../../mod/events.php:431 +msgid "Required" +msgstr "Bezonata" + +#: ../../mod/events.php:420 +msgid "Finish date/time is not known or not relevant" +msgstr "Fina dato/tempo ne estas konata aÅ­ ne bezonata" + +#: ../../mod/events.php:422 +msgid "Event Finishes:" +msgstr "Okazo finas:" + +#: ../../mod/events.php:425 +msgid "Adjust for viewer timezone" +msgstr "Agordi al horzono de la leganto" + +#: ../../mod/events.php:427 +msgid "Description:" +msgstr "Priskribo" + +#: ../../mod/events.php:429 ../../include/event.php:40 +#: ../../include/bb2diaspora.php:357 ../../boot.php:1136 +msgid "Location:" +msgstr "Loko:" + +#: ../../mod/events.php:431 +msgid "Title:" +msgstr "Titolo:" + +#: ../../mod/events.php:433 +msgid "Share this event" +msgstr "Kunhavigi la okazon" + +#: ../../mod/tagrm.php:11 ../../mod/tagrm.php:94 +#: ../../mod/dfrn_request.php:845 ../../mod/settings.php:556 +#: ../../mod/settings.php:582 ../../addon/js_upload/js_upload.php:45 +msgid "Cancel" +msgstr "Nuligi" + +#: ../../mod/tagrm.php:41 +msgid "Tag removed" +msgstr "Marko forviÅita" + +#: ../../mod/tagrm.php:79 +msgid "Remove Item Tag" +msgstr "ForviÅi markon" + +#: ../../mod/tagrm.php:81 +msgid "Select a tag to remove: " +msgstr "Elektu forviÅontan markon:" + +#: ../../mod/tagrm.php:93 ../../mod/delegate.php:130 +msgid "Remove" +msgstr "ForviÅi" + +#: ../../mod/dfrn_poll.php:94 ../../mod/dfrn_poll.php:522 +#, php-format +msgid "%s welcomes %s" +msgstr "%s salutas %s" + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Rajtigi programkonekton" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Reiru al via programo kaj entajpu la securecan kodon:" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Bonvolu ensaluti por pluigi." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Ĉu rajtigi ĉi tiun programon por atingi viajn afiÅojn kaj kontaktojn kaj/aÅ­ krei novajn afiÅojn?" + +#: ../../mod/api.php:105 ../../mod/dfrn_request.php:833 +#: ../../mod/settings.php:887 ../../mod/settings.php:893 +#: ../../mod/settings.php:901 ../../mod/settings.php:905 +#: ../../mod/settings.php:910 ../../mod/settings.php:916 +#: ../../mod/settings.php:922 ../../mod/settings.php:928 +#: ../../mod/settings.php:958 ../../mod/settings.php:959 +#: ../../mod/settings.php:960 ../../mod/settings.php:961 +#: ../../mod/settings.php:962 ../../mod/register.php:234 +#: ../../mod/profiles.php:546 +msgid "Yes" +msgstr "Jes" + +#: ../../mod/api.php:106 ../../mod/dfrn_request.php:834 +#: ../../mod/settings.php:887 ../../mod/settings.php:893 +#: ../../mod/settings.php:901 ../../mod/settings.php:905 +#: ../../mod/settings.php:910 ../../mod/settings.php:916 +#: ../../mod/settings.php:922 ../../mod/settings.php:928 +#: ../../mod/settings.php:958 ../../mod/settings.php:959 +#: ../../mod/settings.php:960 ../../mod/settings.php:961 +#: ../../mod/settings.php:962 ../../mod/register.php:235 +#: ../../mod/profiles.php:547 +msgid "No" +msgstr "Ne" + +#: ../../mod/photos.php:46 ../../boot.php:1553 +msgid "Photo Albums" +msgstr "Bildalbumoj" + +#: ../../mod/photos.php:54 ../../mod/photos.php:156 ../../mod/photos.php:965 +#: ../../mod/photos.php:1049 ../../mod/photos.php:1064 +#: ../../mod/photos.php:1492 ../../mod/photos.php:1504 +#: ../../addon/communityhome/communityhome.php:110 +#: ../../view/theme/diabook/theme.php:598 +msgid "Contact Photos" +msgstr "Kontaktbildoj" + +#: ../../mod/photos.php:61 ../../mod/photos.php:1074 ../../mod/photos.php:1542 +msgid "Upload New Photos" +msgstr "AlÅuti novajn bildojn" + +#: ../../mod/photos.php:72 ../../mod/settings.php:21 +msgid "everybody" +msgstr "ĉiuj" + +#: ../../mod/photos.php:145 +msgid "Contact information unavailable" +msgstr "Kontaktoj informoj ne disponeblas" + +#: ../../mod/photos.php:156 ../../mod/photos.php:660 ../../mod/photos.php:1049 +#: ../../mod/photos.php:1064 ../../mod/profile_photo.php:60 +#: ../../mod/profile_photo.php:67 ../../mod/profile_photo.php:74 +#: ../../mod/profile_photo.php:176 ../../mod/profile_photo.php:254 +#: ../../mod/profile_photo.php:263 +#: ../../addon/communityhome/communityhome.php:111 +#: ../../view/theme/diabook/theme.php:599 ../../include/user.php:304 +#: ../../include/user.php:311 ../../include/user.php:318 +msgid "Profile Photos" +msgstr "Profilbildoj" + +#: ../../mod/photos.php:166 +msgid "Album not found." +msgstr "Albumo ne trovita." + +#: ../../mod/photos.php:184 ../../mod/photos.php:1058 +msgid "Delete Album" +msgstr "ForviÅi albumon" + +#: ../../mod/photos.php:247 ../../mod/photos.php:1304 +msgid "Delete Photo" +msgstr "ForviÅi bildon" + +#: ../../mod/photos.php:591 +msgid "was tagged in a" +msgstr "estas markita en" + +#: ../../mod/photos.php:591 ../../mod/like.php:144 ../../mod/tagger.php:70 +#: ../../addon/communityhome/communityhome.php:163 +#: ../../view/theme/diabook/theme.php:570 ../../include/text.php:1317 +#: ../../include/diaspora.php:1710 ../../include/conversation.php:53 +#: ../../include/conversation.php:126 +msgid "photo" +msgstr "bildo" + +#: ../../mod/photos.php:591 +msgid "by" +msgstr "de" + +#: ../../mod/photos.php:696 ../../addon/js_upload/js_upload.php:315 +msgid "Image exceeds size limit of " +msgstr "Bildo estas pli granda ol la limito de" + +#: ../../mod/photos.php:704 +msgid "Image file is empty." +msgstr "Bilddosiero estas malplena." + +#: ../../mod/photos.php:736 ../../mod/profile_photo.php:126 +#: ../../mod/wall_upload.php:99 +msgid "Unable to process image." +msgstr "Ne eblas procedi la bildon." + +#: ../../mod/photos.php:757 ../../mod/profile_photo.php:259 +#: ../../mod/wall_upload.php:118 +msgid "Image upload failed." +msgstr "AlÅuto de bildo malsukcesis." + +#: ../../mod/photos.php:843 ../../mod/community.php:16 +#: ../../mod/dfrn_request.php:759 ../../mod/viewconnections.php:17 +#: ../../mod/display.php:7 ../../mod/search.php:71 ../../mod/directory.php:29 +msgid "Public access denied." +msgstr "Publika atingo ne permesita." + +#: ../../mod/photos.php:853 +msgid "No photos selected" +msgstr "Neniu bildoj elektita" + +#: ../../mod/photos.php:932 +msgid "Access to this item is restricted." +msgstr "Atingo al tio elemento estas limigita." + +#: ../../mod/photos.php:996 +#, php-format +msgid "You have used %1$.2f Mbytes of %2$.2f Mbytes photo storage." +msgstr "Vi uzas %1$.2f MB de %2$.2f MB bildkonservejo." + +#: ../../mod/photos.php:999 +#, php-format +msgid "You have used %1$.2f Mbytes of photo storage." +msgstr "Vi uzas %1$.2f MB de bildkonservejo." + +#: ../../mod/photos.php:1005 +msgid "Upload Photos" +msgstr "AlÅuti bildojn" + +#: ../../mod/photos.php:1009 ../../mod/photos.php:1053 +msgid "New album name: " +msgstr "Nomo por nova albumo:" + +#: ../../mod/photos.php:1010 +msgid "or existing album name: " +msgstr "aÅ­ nomo de estanta albumo:" + +#: ../../mod/photos.php:1011 +msgid "Do not show a status post for this upload" +msgstr "Ne kreu statan afiÅon por tio alÅuto." + +#: ../../mod/photos.php:1013 ../../mod/photos.php:1299 +msgid "Permissions" +msgstr "Permesoj" + +#: ../../mod/photos.php:1068 +msgid "Edit Album" +msgstr "Redakti albumon" + +#: ../../mod/photos.php:1092 ../../mod/photos.php:1525 +msgid "View Photo" +msgstr "Vidi bildon" + +#: ../../mod/photos.php:1127 +msgid "Permission denied. Access to this item may be restricted." +msgstr "Malpermesita. Atingo al tio elemento eble estas limigita." + +#: ../../mod/photos.php:1129 +msgid "Photo not available" +msgstr "La bildo ne disponeblas" + +#: ../../mod/photos.php:1179 +msgid "View photo" +msgstr "Vidi bildon" + +#: ../../mod/photos.php:1179 +msgid "Edit photo" +msgstr "Redakti bildon" + +#: ../../mod/photos.php:1180 +msgid "Use as profile photo" +msgstr "Uzi kiel profilbildo" + +#: ../../mod/photos.php:1186 ../../include/conversation.php:490 +msgid "Private Message" +msgstr "Privata mesaÄo" + +#: ../../mod/photos.php:1208 +msgid "View Full Size" +msgstr "Vidi plengrande " + +#: ../../mod/photos.php:1276 +msgid "Tags: " +msgstr "Markoj:" + +#: ../../mod/photos.php:1279 +msgid "[Remove any tag]" +msgstr "[ForviÅi iun markon]" + +#: ../../mod/photos.php:1289 +msgid "Rotate CW (right)" +msgstr "Turni horloÄdirekte (dekstren)" + +#: ../../mod/photos.php:1290 +msgid "Rotate CCW (left)" +msgstr "Turni kontraÅ­horloÄdirekte (maldekstren)" + +#: ../../mod/photos.php:1292 +msgid "New album name" +msgstr "Nova nomo de albumo" + +#: ../../mod/photos.php:1295 +msgid "Caption" +msgstr "Apudskribo" + +#: ../../mod/photos.php:1297 +msgid "Add a Tag" +msgstr "Aldoni markon" + +#: ../../mod/photos.php:1301 +msgid "" +"Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" +msgstr "Ekzemple: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" + +#: ../../mod/photos.php:1321 ../../include/conversation.php:554 +msgid "I like this (toggle)" +msgstr "Mi Åatas tion (Åalti)" + +#: ../../mod/photos.php:1322 ../../include/conversation.php:555 +msgid "I don't like this (toggle)" +msgstr "Mi malÅatas tion(Åalti)" + +#: ../../mod/photos.php:1323 ../../include/conversation.php:993 +msgid "Share" +msgstr "Kunhavigi" + +#: ../../mod/photos.php:1324 ../../mod/editpost.php:104 +#: ../../mod/wallmessage.php:145 ../../mod/message.php:215 +#: ../../mod/message.php:411 ../../include/conversation.php:371 +#: ../../include/conversation.php:731 ../../include/conversation.php:1012 +msgid "Please wait" +msgstr "Bonvolu atendi" + +#: ../../mod/photos.php:1340 ../../mod/photos.php:1380 +#: ../../mod/photos.php:1411 ../../include/conversation.php:577 +msgid "This is you" +msgstr "Tiu estas vi" + +#: ../../mod/photos.php:1342 ../../mod/photos.php:1382 +#: ../../mod/photos.php:1413 ../../include/conversation.php:579 +#: ../../boot.php:528 +msgid "Comment" +msgstr "Komenti" + +#: ../../mod/photos.php:1344 ../../mod/editpost.php:125 +#: ../../include/conversation.php:589 ../../include/conversation.php:1030 +msgid "Preview" +msgstr "AntaÅ­rigardi" + +#: ../../mod/photos.php:1441 ../../mod/settings.php:618 +#: ../../mod/settings.php:707 ../../mod/group.php:168 ../../mod/admin.php:663 +#: ../../include/conversation.php:328 ../../include/conversation.php:609 +msgid "Delete" +msgstr "ForviÅi" + +#: ../../mod/photos.php:1531 +msgid "View Album" +msgstr "Vidi albumon" + +#: ../../mod/photos.php:1540 +msgid "Recent Photos" +msgstr "Ì‚Ä´usaj bildoj" + +#: ../../mod/community.php:21 +msgid "Not available." +msgstr "Ne disponebla." + +#: ../../mod/community.php:30 ../../view/theme/diabook/theme.php:133 +#: ../../include/nav.php:101 +msgid "Community" +msgstr "Komunumo" + +#: ../../mod/community.php:61 ../../mod/search.php:144 +msgid "No results." +msgstr "Nenion trovita." + +#: ../../mod/friendica.php:55 +msgid "This is Friendica, version" +msgstr "Tio estas Friendica en la versio" + +#: ../../mod/friendica.php:56 +msgid "running at web location" +msgstr "instalita ĉe la adreso" + +#: ../../mod/friendica.php:58 +msgid "" +"Please visit Friendica.com to learn " +"more about the Friendica project." +msgstr "Bonvolu iri al Friendica.com por lerni pli pri la projekto Friendica" + +#: ../../mod/friendica.php:60 +msgid "Bug reports and issues: please visit" +msgstr "Cimraportoj kaj atendindaĵo: bonvolu iri al" + +#: ../../mod/friendica.php:61 +msgid "" +"Suggestions, praise, donations, etc. - please email \"Info\" at Friendica - " +"dot com" +msgstr "Sugestoj, laÅ­doj, donacoj ktp - bonvolu sendi mesÄon al \"Info\" ĉe Friendica - punkto com" + +#: ../../mod/friendica.php:75 +msgid "Installed plugins/addons/apps:" +msgstr "Instalitaj kromprogramoj/programoj:" + +#: ../../mod/friendica.php:88 +msgid "No installed plugins/addons/apps" +msgstr "Neniom da instalitaj aldonaĵoj/programoj" + +#: ../../mod/editpost.php:17 ../../mod/editpost.php:27 +msgid "Item not found" +msgstr "Elemento ne trovita" + +#: ../../mod/editpost.php:36 +msgid "Edit post" +msgstr "Redakti afiÅon" + +#: ../../mod/editpost.php:80 ../../include/conversation.php:979 +msgid "Post to Email" +msgstr "Sendi per retpoÅto" + +#: ../../mod/editpost.php:95 ../../mod/settings.php:617 +#: ../../include/conversation.php:596 +msgid "Edit" +msgstr "Redakti" + +#: ../../mod/editpost.php:96 ../../mod/wallmessage.php:143 +#: ../../mod/message.php:213 ../../mod/message.php:408 +#: ../../include/conversation.php:994 +msgid "Upload photo" +msgstr "AlÅuti bildon" + +#: ../../mod/editpost.php:97 ../../include/conversation.php:996 +msgid "Attach file" +msgstr "Kunligi dosieron" + +#: ../../mod/editpost.php:98 ../../mod/wallmessage.php:144 +#: ../../mod/message.php:214 ../../mod/message.php:409 +#: ../../include/conversation.php:998 +msgid "Insert web link" +msgstr "Enmeti retan adreson" + +#: ../../mod/editpost.php:99 +msgid "Insert YouTube video" +msgstr "Enmeti videton ĉe YouTube" + +#: ../../mod/editpost.php:100 +msgid "Insert Vorbis [.ogg] video" +msgstr "Enmeti videton en formato Vorbis [.ogg]" + +#: ../../mod/editpost.php:101 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Enmeti sonon en formato Vorbis [.ogg]" + +#: ../../mod/editpost.php:102 ../../include/conversation.php:1004 +msgid "Set your location" +msgstr "Agordi vian lokon" + +#: ../../mod/editpost.php:103 ../../include/conversation.php:1006 +msgid "Clear browser location" +msgstr "ForviÅu retesplorilan lokon" + +#: ../../mod/editpost.php:105 ../../include/conversation.php:1013 +msgid "Permission settings" +msgstr "Permesagordoj" + +#: ../../mod/editpost.php:113 ../../include/conversation.php:1022 +msgid "CC: email addresses" +msgstr "CC: retpoÅtadresojn" + +#: ../../mod/editpost.php:114 ../../include/conversation.php:1023 +msgid "Public post" +msgstr "Publika afiÅo" + +#: ../../mod/editpost.php:117 ../../include/conversation.php:1009 +msgid "Set title" +msgstr "Redakti titolon" + +#: ../../mod/editpost.php:119 ../../include/conversation.php:1011 +msgid "Categories (comma-separated list)" +msgstr "Kategorioj (disigita per komo)" + +#: ../../mod/editpost.php:120 ../../include/conversation.php:1025 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Ekzemple: bob@example.com, mary@example.com" + +#: ../../mod/dfrn_request.php:93 +msgid "This introduction has already been accepted." +msgstr "Tia prezento jam estas akceptita" + +#: ../../mod/dfrn_request.php:118 ../../mod/dfrn_request.php:512 +msgid "Profile location is not valid or does not contain profile information." +msgstr "La adreso de la profilo ne validas aÅ­ ne enhavas profilinformojn." + +#: ../../mod/dfrn_request.php:123 ../../mod/dfrn_request.php:517 +msgid "Warning: profile location has no identifiable owner name." +msgstr "Averto: La adreso de la profilo ne enhavas identeblan personan nomon." + +#: ../../mod/dfrn_request.php:125 ../../mod/dfrn_request.php:519 +msgid "Warning: profile location has no profile photo." +msgstr "Averto: La adreso de la profilo ne enhavas bildon." + +#: ../../mod/dfrn_request.php:128 ../../mod/dfrn_request.php:522 +#, php-format +msgid "%d required parameter was not found at the given location" +msgid_plural "%d required parameters were not found at the given location" +msgstr[0] "%d bezonataj parametroj ne trovita ĉe la donata adreso." +msgstr[1] "%d bezonataj parametroj ne trovita ĉe la donata adreso." + +#: ../../mod/dfrn_request.php:170 +msgid "Introduction complete." +msgstr "Prezento sukcesis." + +#: ../../mod/dfrn_request.php:209 +msgid "Unrecoverable protocol error." +msgstr "NeÄustigebla eraro en protokolo." + +#: ../../mod/dfrn_request.php:237 +msgid "Profile unavailable." +msgstr "Profilo ne estas disponebla." + +#: ../../mod/dfrn_request.php:262 +#, php-format +msgid "%s has received too many connection requests today." +msgstr "%s hodiaÅ­ ricevis tro multe da konektpetoj." + +#: ../../mod/dfrn_request.php:263 +msgid "Spam protection measures have been invoked." +msgstr "KontraÅ­spamilo estas aktivita." + +#: ../../mod/dfrn_request.php:264 +msgid "Friends are advised to please try again in 24 hours." +msgstr "Amikoj, vi bonvolu ripeti post 24 horoj." + +#: ../../mod/dfrn_request.php:326 +msgid "Invalid locator" +msgstr "Nevalida adreso." + +#: ../../mod/dfrn_request.php:335 +msgid "Invalid email address." +msgstr "Nevalida repoÅtadreso." + +#: ../../mod/dfrn_request.php:361 +msgid "This account has not been configured for email. Request failed." +msgstr "La konto ne estas agordita por retpoÅto. La peto malsukcesis." + +#: ../../mod/dfrn_request.php:457 +msgid "Unable to resolve your name at the provided location." +msgstr "Via nomo ne troveblas al la donita adreso." + +#: ../../mod/dfrn_request.php:470 +msgid "You have already introduced yourself here." +msgstr "Vi vin jam prezentis tie." + +#: ../../mod/dfrn_request.php:474 +#, php-format +msgid "Apparently you are already friends with %s." +msgstr "Åœajnas kvazaÅ­ vi jam amikiÄis kun %s." + +#: ../../mod/dfrn_request.php:495 +msgid "Invalid profile URL." +msgstr "Nevalida adreso de profilo." + +#: ../../mod/dfrn_request.php:501 ../../include/follow.php:27 +msgid "Disallowed profile URL." +msgstr "Malpermesita adreso de profilo." + +#: ../../mod/dfrn_request.php:570 ../../mod/contacts.php:122 +msgid "Failed to update contact record." +msgstr "Äœisdatigo de via kontaktrikordo malsukcesis." + +#: ../../mod/dfrn_request.php:591 +msgid "Your introduction has been sent." +msgstr "Via prezento estas sendita." + +#: ../../mod/dfrn_request.php:644 +msgid "Please login to confirm introduction." +msgstr "Bonvolu ensaluti por jesigi la prezenton." + +#: ../../mod/dfrn_request.php:658 +msgid "" +"Incorrect identity currently logged in. Please login to " +"this profile." +msgstr "MalÄusta identaĵo ensalutata. Bonvolu ensaluti en tiun profilon." + +#: ../../mod/dfrn_request.php:669 +msgid "Hide this contact" +msgstr "KaÅi tiun kontakton" + +#: ../../mod/dfrn_request.php:672 +#, php-format +msgid "Welcome home %s." +msgstr "Bonvenon hejme, %s." + +#: ../../mod/dfrn_request.php:673 +#, php-format +msgid "Please confirm your introduction/connection request to %s." +msgstr "Bonvolu konfirmi vian prezenton / kontaktpeton al %s." + +#: ../../mod/dfrn_request.php:674 +msgid "Confirm" +msgstr "Konfirmi." + +#: ../../mod/dfrn_request.php:715 ../../include/items.php:2881 +msgid "[Name Withheld]" +msgstr "[KaÅita nomo]" + +#: ../../mod/dfrn_request.php:808 +msgid "" +"Please enter your 'Identity Address' from one of the following supported " +"communications networks:" +msgstr "Bonvolu entajpi vian 'Identecan Adreson' de iu de tiuj subtenataj komunikaj retejoj: " + +#: ../../mod/dfrn_request.php:824 +msgid "Connect as an email follower (Coming soon)" +msgstr "Konektu kiel retpoÅta sekvanto (BaldaÅ­ venos)" + +#: ../../mod/dfrn_request.php:826 +msgid "" +"If you are not yet a member of the free social web, follow this link to find a public" +" Friendica site and join us today." +msgstr "Se vi ne estas membro de la libra interkona reto, sekvu ĉi-ligilon por trovi publikan Friendica retejon kaj aliÄi kun ni hodiaÅ­." + +#: ../../mod/dfrn_request.php:829 +msgid "Friend/Connection Request" +msgstr "Prezento / Konektpeto" + +#: ../../mod/dfrn_request.php:830 +msgid "" +"Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, " +"testuser@identi.ca" +msgstr "Ekzemploj: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca" + +#: ../../mod/dfrn_request.php:831 +msgid "Please answer the following:" +msgstr "Bonvolu respondi:" + +#: ../../mod/dfrn_request.php:832 +#, php-format +msgid "Does %s know you?" +msgstr "Ĉu %s konas vin?" + +#: ../../mod/dfrn_request.php:835 +msgid "Add a personal note:" +msgstr "Aldoni personan noton:" + +#: ../../mod/dfrn_request.php:837 ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../mod/dfrn_request.php:838 +msgid "StatusNet/Federated Social Web" +msgstr "StatusNet/Federaciaj interkonaj retejoj" + +#: ../../mod/dfrn_request.php:839 ../../mod/settings.php:652 +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../mod/dfrn_request.php:840 +#, php-format +msgid "" +" - please do not use this form. Instead, enter %s into your Diaspora search" +" bar." +msgstr " - bonvolu ne uzi ĉi formo. AnstataÅ­e, entajpu %s en la Diaspora serĉilo." + +#: ../../mod/dfrn_request.php:841 +msgid "Your Identity Address:" +msgstr "Via identeca adreso:" + +#: ../../mod/dfrn_request.php:844 +msgid "Submit Request" +msgstr "Sendi peton" + +#: ../../mod/install.php:117 +msgid "Friendica Social Communications Server - Setup" +msgstr "Friendica Interkona Komunikada Servilo - Instalo" + +#: ../../mod/install.php:123 +msgid "Could not connect to database." +msgstr "Ne eblas konekti la datumbazon." + +#: ../../mod/install.php:127 +msgid "Could not create table." +msgstr "Ne eblas krei tabelon." + +#: ../../mod/install.php:133 +msgid "Your Friendica site database has been installed." +msgstr "La datumbazo de vi Friendica retjo estas instalita." + +#: ../../mod/install.php:138 +msgid "" +"You may need to import the file \"database.sql\" manually using phpmyadmin " +"or mysql." +msgstr "Vi bezonas mane importi la dosieron \"database.sql\" per phpmyadmin aÅ­ mysql." + +#: ../../mod/install.php:139 ../../mod/install.php:204 +#: ../../mod/install.php:489 +msgid "Please see the file \"INSTALL.txt\"." +msgstr "Bonvolu legi la dosieron \"INSTALL.txt\"." + +#: ../../mod/install.php:201 +msgid "System check" +msgstr "Sistema kontrolo" + +#: ../../mod/install.php:206 +msgid "Check again" +msgstr "Ree kontroli" + +#: ../../mod/install.php:225 +msgid "Database connection" +msgstr "Datumbaza konekto" + +#: ../../mod/install.php:226 +msgid "" +"In order to install Friendica we need to know how to connect to your " +"database." +msgstr "Por instali Friendica, ni bezonas scii kiel konekti al via datumbazo." + +#: ../../mod/install.php:227 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Bonvolu kontakti vian servilprovizanton aÅ­ administranton se vi havas demandoj pri ĉi tiaj agordoj." + +#: ../../mod/install.php:228 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "La datumbazo nomata malsupren jam ekzistu. Se Äi ne ekzistas, bonvolu unue krei Äin antaÅ­ progresi." + +#: ../../mod/install.php:232 +msgid "Database Server Name" +msgstr "Nomo de datumbaza servilo." + +#: ../../mod/install.php:233 +msgid "Database Login Name" +msgstr "Salutnomo ĉe la datumbazo." + +#: ../../mod/install.php:234 +msgid "Database Login Password" +msgstr "Pasvorto ĉe la datumbazo." + +#: ../../mod/install.php:235 +msgid "Database Name" +msgstr "Nomo de la datumbazo." + +#: ../../mod/install.php:236 ../../mod/install.php:275 +msgid "Site administrator email address" +msgstr "RetpoÅtadreso de la reteja administranto" + +#: ../../mod/install.php:236 ../../mod/install.php:275 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "La repoÅtadreso de via konto bezonas esti la sama por uzi la TTTa administrilo." + +#: ../../mod/install.php:240 ../../mod/install.php:278 +msgid "Please select a default timezone for your website" +msgstr "Bonvolu elekti defaÅ­ltan horzonon por via retejo." + +#: ../../mod/install.php:265 +msgid "Site settings" +msgstr "Retejaj agordoj" + +#: ../../mod/install.php:318 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Komanda linia versio de PHP ne trovita en $PATH de la retservilo." + +#: ../../mod/install.php:319 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron. See 'Activating scheduled tasks'" +msgstr "Se vi ne havas komandlinian version de PHP sur la servilo, vi ne eblas plenumi fonan planitan enketon per cron. Bonvolu legi 'Activating scheduled tasks'" + +#: ../../mod/install.php:323 +msgid "PHP executable path" +msgstr "Vojo de la komanda linia versio de PHP" + +#: ../../mod/install.php:323 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Entajpu la plenan vojon al la php komandodosiero. Vi eblas lasi tion malplena por pluigi la instalado." + +#: ../../mod/install.php:328 +msgid "Command line PHP" +msgstr "komanda linia versio de PHP" + +#: ../../mod/install.php:337 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "En via komanda linia versio de PHP je via sistemo, \"register_argc_argv\" ne estas aktivita." + +#: ../../mod/install.php:338 +msgid "This is required for message delivery to work." +msgstr "Tio estas bezonata por la livero de mesaÄoj." + +#: ../../mod/install.php:340 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/install.php:361 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Eraro: La funkcio \"openssl_pkey_new\" je tia sistemo ne eblas generi ĉifroÅlosilojn." + +#: ../../mod/install.php:362 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Se la operaciumo sistemo estas Windows, bonvolu legi: http://www.php.net/manual/en/openssl.installation.php" + +#: ../../mod/install.php:364 +msgid "Generate encryption keys" +msgstr "Generi ĉifroÅlosilojn" + +#: ../../mod/install.php:371 +msgid "libCurl PHP module" +msgstr "PHP modulo libCurl" + +#: ../../mod/install.php:372 +msgid "GD graphics PHP module" +msgstr "PHP modulo GD" + +#: ../../mod/install.php:373 +msgid "OpenSSL PHP module" +msgstr "PHP modulo OpenSSL" + +#: ../../mod/install.php:374 +msgid "mysqli PHP module" +msgstr "PHP modulo mysqli" + +#: ../../mod/install.php:375 +msgid "mb_string PHP module" +msgstr "PHP modulo mb_string" + +#: ../../mod/install.php:380 ../../mod/install.php:382 +msgid "Apache mod_rewrite module" +msgstr "Apache mod_rewrite modulo" + +#: ../../mod/install.php:380 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Eraro: La modulo mod_rewrite en la Apache retservilo estas bezonata sed ne instalita." + +#: ../../mod/install.php:388 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Eraro: La modulo libCURL en PHP estas bezonata sed ne instalita." + +#: ../../mod/install.php:392 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Eraro: La modulo GD en PHP kun subteno por JPEG estas bezonata sed ne instalita." + +#: ../../mod/install.php:396 +msgid "Error: openssl PHP module required but not installed." +msgstr "Eraro: La modulo OpenSSL en PHP estas bezonata sed ne instalita." + +#: ../../mod/install.php:400 +msgid "Error: mysqli PHP module required but not installed." +msgstr "Eraro: La modulo mysqli en PHP estas bezonata sed ne instalita." + +#: ../../mod/install.php:404 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Eraro: La modulo mb_string en PHP estas bezonata sed ne instalita." + +#: ../../mod/install.php:421 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "La reta instalilo bezonas skribi dosieron nomata \".htconfig.php\" en la baza dosierujo de la retservilo, sed ne sukcesis." + +#: ../../mod/install.php:422 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Tio ĉi plej ofte estas agordo rilate al permesoj, ĉar la servilo eble ne povas skribi en via dosierujo, eĉ se vi mem povas skribi." + +#: ../../mod/install.php:423 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Friendica top folder." +msgstr "Post la fino de tiu proceduro, ni donos al vi tekston por konservi en dosiero .htconfig.php en via baza Friendica dosierujo." + +#: ../../mod/install.php:424 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"INSTALL.txt\" for instructions." +msgstr "Vi ankaÅ­ povas preterpasi tiun proceduron kaj fari permanan instaladon. Bonvolu legi la dosieron \"INSTALL.txt\" por trovi instrukciojn." + +#: ../../mod/install.php:427 +msgid ".htconfig.php is writable" +msgstr ".htconfig.php estas skribebla." + +#: ../../mod/install.php:439 +msgid "" +"Url rewrite in .htaccess is not working. Check your server configuration." +msgstr "Url rewrite en .htaccess ne funkcias. Kontrolu la agordojn de la servilo." + +#: ../../mod/install.php:441 +msgid "Url rewrite is working" +msgstr "URL rewrite funkcias." + +#: ../../mod/install.php:451 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "Ne povis skribi la datumbaza agordoj en la dosiero \".htconfig.php\". Bonvolu uzi la inkluzivan tekston por krei agordan dosieron en la baza dosierujo de la retservilo." + +#: ../../mod/install.php:476 +msgid "Errors encountered creating database tables." +msgstr "Okazis eraroj dum la kreado de tabeloj en la datumbazo." + +#: ../../mod/install.php:487 +msgid "

    What next

    " +msgstr "

    Kio sekvas nun?

    " + +#: ../../mod/install.php:488 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "GRAVA: Vi bezonas [mane] agordi planitan taskon por la Friendica poller." + +#: ../../mod/localtime.php:12 ../../include/event.php:11 +#: ../../include/bb2diaspora.php:335 +msgid "l F d, Y \\@ g:i A" +msgstr "l F d, Y \\@ g:i A" + +#: ../../mod/localtime.php:24 +msgid "Time Conversion" +msgstr "Konverto de tempo" + +#: ../../mod/localtime.php:26 +msgid "" +"Friendika provides this service for sharing events with other networks and " +"friends in unknown timezones." +msgstr "Friendica provizas tiun servon por kunhavigi okazojn kun aliaj retoj kaj amikoj en aliaj horzonoj." + +#: ../../mod/localtime.php:30 +#, php-format +msgid "UTC time: %s" +msgstr "UTC horo: %s" + +#: ../../mod/localtime.php:33 +#, php-format +msgid "Current timezone: %s" +msgstr "Aktuala horzono: %s" + +#: ../../mod/localtime.php:36 +#, php-format +msgid "Converted localtime: %s" +msgstr "Konvertita loka horo: %s" + +#: ../../mod/localtime.php:41 +msgid "Please select your timezone:" +msgstr "Bonvolu elekti vian horzonon:" + +#: ../../mod/match.php:12 +msgid "Profile Match" +msgstr "Kongrua profilo" + +#: ../../mod/match.php:20 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "Neniom da kategoriaj vortoj kongruas. Bonvolu aldoni kategoriajn vortojn al via defaÅ­lta profilo." + +#: ../../mod/match.php:57 +msgid "is interested in:" +msgstr "interesiÄas pri:" + +#: ../../mod/match.php:58 ../../mod/suggest.php:59 +#: ../../include/contact_widgets.php:9 ../../boot.php:1080 +msgid "Connect" +msgstr "Konekti" + +#: ../../mod/match.php:65 ../../mod/dirfind.php:60 +msgid "No matches" +msgstr "Nenio estas trovita" + +#: ../../mod/lockview.php:39 +msgid "Remote privacy information not available." +msgstr "Informoj pri fora privateca ne estas disponebla." + +#: ../../mod/lockview.php:43 +msgid "Visible to:" +msgstr "Videbla al:" + +#: ../../mod/home.php:26 ../../addon/communityhome/communityhome.php:179 +#, php-format +msgid "Welcome to %s" +msgstr "Bonvenon ĉe %s" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Nevalida peta identigilo." + +#: ../../mod/notifications.php:35 ../../mod/notifications.php:161 +#: ../../mod/notifications.php:207 +msgid "Discard" +msgstr "ForviÅi" + +#: ../../mod/notifications.php:51 ../../mod/notifications.php:160 +#: ../../mod/notifications.php:206 ../../mod/contacts.php:316 +#: ../../mod/contacts.php:370 +msgid "Ignore" +msgstr "Ignori" + +#: ../../mod/notifications.php:75 +msgid "System" +msgstr "Sistemo" + +#: ../../mod/notifications.php:80 ../../include/nav.php:113 +msgid "Network" +msgstr "Reto" + +#: ../../mod/notifications.php:85 ../../mod/network.php:300 +msgid "Personal" +msgstr "Propra" + +#: ../../mod/notifications.php:90 ../../view/theme/diabook/theme.php:127 +#: ../../include/nav.php:77 ../../include/nav.php:115 +msgid "Home" +msgstr "Hejmo" + +#: ../../mod/notifications.php:95 ../../include/nav.php:121 +msgid "Introductions" +msgstr "Prezentoj" + +#: ../../mod/notifications.php:100 ../../mod/message.php:105 +#: ../../include/nav.php:128 +msgid "Messages" +msgstr "MesaÄoj" + +#: ../../mod/notifications.php:119 +msgid "Show Ignored Requests" +msgstr "Montri ignoritajn petojn" + +#: ../../mod/notifications.php:119 +msgid "Hide Ignored Requests" +msgstr "KaÅi ignoritajn petojn" + +#: ../../mod/notifications.php:145 ../../mod/notifications.php:191 +msgid "Notification type: " +msgstr "Tipo de atentigo:" + +#: ../../mod/notifications.php:146 +msgid "Friend Suggestion" +msgstr "Amikosugestoj" + +#: ../../mod/notifications.php:148 +#, php-format +msgid "suggested by %s" +msgstr "sugestita de %s" + +#: ../../mod/notifications.php:153 ../../mod/notifications.php:200 +#: ../../mod/contacts.php:376 +msgid "Hide this contact from others" +msgstr "KaÅi ĉi tiun kontakton al aliaj" + +#: ../../mod/notifications.php:154 ../../mod/notifications.php:201 +msgid "Post a new friend activity" +msgstr "AfiÅi novan amikecan aktivecon" + +#: ../../mod/notifications.php:154 ../../mod/notifications.php:201 +msgid "if applicable" +msgstr "se aplikebla" + +#: ../../mod/notifications.php:157 ../../mod/notifications.php:204 +#: ../../mod/admin.php:661 +msgid "Approve" +msgstr "Aprobi" + +#: ../../mod/notifications.php:177 +msgid "Claims to be known to you: " +msgstr "Pensas ke vi konas ilin:" + +#: ../../mod/notifications.php:177 +msgid "yes" +msgstr "jes" + +#: ../../mod/notifications.php:177 +msgid "no" +msgstr "ne" + +#: ../../mod/notifications.php:184 +msgid "Approve as: " +msgstr "Aprobi kiel:" + +#: ../../mod/notifications.php:185 +msgid "Friend" +msgstr "Amiko" + +#: ../../mod/notifications.php:186 +msgid "Sharer" +msgstr "Kunhaviganto" + +#: ../../mod/notifications.php:186 +msgid "Fan/Admirer" +msgstr "Fanatikulo/Admiranto" + +#: ../../mod/notifications.php:192 +msgid "Friend/Connect Request" +msgstr "Kontaktpeto" + +#: ../../mod/notifications.php:192 +msgid "New Follower" +msgstr "Nova abonanto" + +#: ../../mod/notifications.php:213 +msgid "No introductions." +msgstr "Neniom da prezentoj" + +#: ../../mod/notifications.php:216 ../../include/nav.php:122 +msgid "Notifications" +msgstr "Atentigoj" + +#: ../../mod/notifications.php:253 ../../mod/notifications.php:378 +#: ../../mod/notifications.php:465 +#, php-format +msgid "%s liked %s's post" +msgstr "%s Åatis la afiÅon de %s" + +#: ../../mod/notifications.php:262 ../../mod/notifications.php:387 +#: ../../mod/notifications.php:474 +#, php-format +msgid "%s disliked %s's post" +msgstr "%s malÅatis la afiÅon de %s" + +#: ../../mod/notifications.php:276 ../../mod/notifications.php:401 +#: ../../mod/notifications.php:488 +#, php-format +msgid "%s is now friends with %s" +msgstr "%s amikiÄis kun %s" + +#: ../../mod/notifications.php:283 ../../mod/notifications.php:408 +#, php-format +msgid "%s created a new post" +msgstr "%s kreis novan afiÅon" + +#: ../../mod/notifications.php:284 ../../mod/notifications.php:409 +#: ../../mod/notifications.php:497 +#, php-format +msgid "%s commented on %s's post" +msgstr "%s komentis pri la afiÅo de %s" + +#: ../../mod/notifications.php:298 +msgid "No more network notifications." +msgstr "Ne pli da retaj atentigoj." + +#: ../../mod/notifications.php:302 +msgid "Network Notifications" +msgstr "Retaj Atentigoj" + +#: ../../mod/notifications.php:328 ../../mod/notify.php:61 +msgid "No more system notifications." +msgstr "Ne pli da sistemaj atentigoj." + +#: ../../mod/notifications.php:332 ../../mod/notify.php:65 +msgid "System Notifications" +msgstr "Sistemaj Atentigoj" + +#: ../../mod/notifications.php:423 +msgid "No more personal notifications." +msgstr "Ne pli da personaj atentigoj" + +#: ../../mod/notifications.php:427 +msgid "Personal Notifications" +msgstr "Personaj Atentigoj" + +#: ../../mod/notifications.php:504 +msgid "No more home notifications." +msgstr "Ne pli da hejmrilataj atentigoj." + +#: ../../mod/notifications.php:508 +msgid "Home Notifications" +msgstr "Hejmrilataj atentigoj" + +#: ../../mod/contacts.php:83 ../../mod/contacts.php:163 +msgid "Could not access contact record." +msgstr "Ne eblis atingi kontaktrikordo." + +#: ../../mod/contacts.php:97 +msgid "Could not locate selected profile." +msgstr "Ne trovis elektitan profilon." + +#: ../../mod/contacts.php:120 +msgid "Contact updated." +msgstr "Kontakto estas Äisdatigita." + +#: ../../mod/contacts.php:185 +msgid "Contact has been blocked" +msgstr "Kontakto estas blokita." + +#: ../../mod/contacts.php:185 +msgid "Contact has been unblocked" +msgstr "Kontakto estas malblokita." + +#: ../../mod/contacts.php:199 +msgid "Contact has been ignored" +msgstr "Kontakto estas ignorita." + +#: ../../mod/contacts.php:199 +msgid "Contact has been unignored" +msgstr "Kontakto estas malignorita." + +#: ../../mod/contacts.php:215 +msgid "Contact has been archived" +msgstr "Enarkivigis kontakton" + +#: ../../mod/contacts.php:215 +msgid "Contact has been unarchived" +msgstr "Elarkivigis kontakton" + +#: ../../mod/contacts.php:228 +msgid "Contact has been removed." +msgstr "Kontakto estas forigita." + +#: ../../mod/contacts.php:258 +#, php-format +msgid "You are mutual friends with %s" +msgstr "Vi estas reciproka amiko de %s" + +#: ../../mod/contacts.php:262 +#, php-format +msgid "You are sharing with %s" +msgstr "Vi kunhavigas kun %s" + +#: ../../mod/contacts.php:267 +#, php-format +msgid "%s is sharing with you" +msgstr "%s kunhavigas kun vi" + +#: ../../mod/contacts.php:284 +msgid "Private communications are not available for this contact." +msgstr "Privataj komunikadoj ne disponeblas por ĉi tiu kontakto." + +#: ../../mod/contacts.php:287 +msgid "Never" +msgstr "Neniam" + +#: ../../mod/contacts.php:291 +msgid "(Update was successful)" +msgstr "(Äœisdatigo sukcesis.)" + +#: ../../mod/contacts.php:291 +msgid "(Update was not successful)" +msgstr "(Äœisdatigo malsukcesis.)" + +#: ../../mod/contacts.php:293 +msgid "Suggest friends" +msgstr "Sugesti amikojn" + +#: ../../mod/contacts.php:297 +#, php-format +msgid "Network type: %s" +msgstr "Reta tipo: %s" + +#: ../../mod/contacts.php:300 ../../include/contact_widgets.php:183 +#, php-format +msgid "%d contact in common" +msgid_plural "%d contacts in common" +msgstr[0] "%d komuna kontakto" +msgstr[1] "%d komunaj kontaktoj" + +#: ../../mod/contacts.php:305 +msgid "View all contacts" +msgstr "Vidi ĉiujn kontaktojn" + +#: ../../mod/contacts.php:310 ../../mod/contacts.php:369 +#: ../../mod/admin.php:665 +msgid "Unblock" +msgstr "Malbloki" + +#: ../../mod/contacts.php:310 ../../mod/contacts.php:369 +#: ../../mod/admin.php:664 +msgid "Block" +msgstr "Bloki" + +#: ../../mod/contacts.php:313 +msgid "Toggle Blocked status" +msgstr "Åœalti/malÅalti Blokitan staton" + +#: ../../mod/contacts.php:316 ../../mod/contacts.php:370 +msgid "Unignore" +msgstr "Malignori" + +#: ../../mod/contacts.php:319 +msgid "Toggle Ignored status" +msgstr "Åœalti/malÅalti Ignoritan staton" + +#: ../../mod/contacts.php:323 +msgid "Unarchive" +msgstr "Elarkivigi" + +#: ../../mod/contacts.php:323 +msgid "Archive" +msgstr "Enarkivigi" + +#: ../../mod/contacts.php:326 +msgid "Toggle Archive status" +msgstr "Åœalti/malÅalti Enarkivigitan staton" + +#: ../../mod/contacts.php:329 +msgid "Repair" +msgstr "Ripari" + +#: ../../mod/contacts.php:332 +msgid "Advanced Contact Settings" +msgstr "Specialaj Kontaktagordoj" + +#: ../../mod/contacts.php:338 +msgid "Communications lost with this contact!" +msgstr "Mi perdis la kommunikadon kun tiu kontakto!" + +#: ../../mod/contacts.php:341 +msgid "Contact Editor" +msgstr "Kontakta redaktilo." + +#: ../../mod/contacts.php:344 +msgid "Profile Visibility" +msgstr "Videbleco de profilo" + +#: ../../mod/contacts.php:345 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Bonvolu elekti la profilon kiu vi volas montri al %s aspektinde kiam sekure aspektante vian profilon." + +#: ../../mod/contacts.php:346 +msgid "Contact Information / Notes" +msgstr "Kontaktaj informoj / Notoj" + +#: ../../mod/contacts.php:347 +msgid "Edit contact notes" +msgstr "Redakti kontaktnotojn" + +#: ../../mod/contacts.php:352 ../../mod/contacts.php:544 +#: ../../mod/viewconnections.php:62 ../../mod/nogroup.php:40 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Viziti la profilon de %s [%s]" + +#: ../../mod/contacts.php:353 +msgid "Block/Unblock contact" +msgstr "Bloki/Malbloki kontakton" + +#: ../../mod/contacts.php:354 +msgid "Ignore contact" +msgstr "Ignori kontakton" + +#: ../../mod/contacts.php:355 +msgid "Repair URL settings" +msgstr "Ripari URL agordoj" + +#: ../../mod/contacts.php:356 +msgid "View conversations" +msgstr "Vidi konversaciojn" + +#: ../../mod/contacts.php:358 +msgid "Delete contact" +msgstr "ForviÅi kontakton" + +#: ../../mod/contacts.php:362 +msgid "Last update:" +msgstr "Plej ĵusa Äisdatigo:" + +#: ../../mod/contacts.php:364 +msgid "Update public posts" +msgstr "Äœisdatigi publikajn afiÅojn" + +#: ../../mod/contacts.php:366 ../../mod/admin.php:1136 +msgid "Update now" +msgstr "Äœisdatigi nun" + +#: ../../mod/contacts.php:373 +msgid "Currently blocked" +msgstr "Nuntempe blokata" + +#: ../../mod/contacts.php:374 +msgid "Currently ignored" +msgstr "Nuntempe ignorata" + +#: ../../mod/contacts.php:375 +msgid "Currently archived" +msgstr "Nuntempe enarkivigita" + +#: ../../mod/contacts.php:376 +msgid "" +"Replies/likes to your public posts may still be visible" +msgstr "Rispondoj/Åataĵo al viaj publikaj afiÅoj eble plu estos videbla" + +#: ../../mod/contacts.php:429 +msgid "Suggestions" +msgstr "Sugestoj" + +#: ../../mod/contacts.php:432 +msgid "Suggest potential friends" +msgstr "Sugesti amikojn" + +#: ../../mod/contacts.php:435 ../../mod/group.php:191 +msgid "All Contacts" +msgstr "Ĉiuj Kontaktoj" + +#: ../../mod/contacts.php:438 +msgid "Show all contacts" +msgstr "Montri ĉiujn kontaktojn" + +#: ../../mod/contacts.php:441 +msgid "Unblocked" +msgstr "Malblokita" + +#: ../../mod/contacts.php:444 +msgid "Only show unblocked contacts" +msgstr "Nur montri neblokitajn kontaktojn" + +#: ../../mod/contacts.php:448 +msgid "Blocked" +msgstr "Blokita" + +#: ../../mod/contacts.php:451 +msgid "Only show blocked contacts" +msgstr "Nur montri blokitajn kontaktojn" + +#: ../../mod/contacts.php:455 +msgid "Ignored" +msgstr "Ignorita" + +#: ../../mod/contacts.php:458 +msgid "Only show ignored contacts" +msgstr "Nur montri ignoritajn kontaktojn" + +#: ../../mod/contacts.php:462 +msgid "Archived" +msgstr "Enarkivigita" + +#: ../../mod/contacts.php:465 +msgid "Only show archived contacts" +msgstr "Nur montri enarkivigitajn kontaktojn" + +#: ../../mod/contacts.php:469 +msgid "Hidden" +msgstr "KaÅita" + +#: ../../mod/contacts.php:472 +msgid "Only show hidden contacts" +msgstr "Nur montri kaÅitajn kontaktojn" + +#: ../../mod/contacts.php:520 +msgid "Mutual Friendship" +msgstr "Reciproka amikeco" + +#: ../../mod/contacts.php:524 +msgid "is a fan of yours" +msgstr "estas admiranto de vi" + +#: ../../mod/contacts.php:528 +msgid "you are a fan of" +msgstr "vi estas admiranto de" + +#: ../../mod/contacts.php:545 ../../mod/nogroup.php:41 +msgid "Edit contact" +msgstr "Redakti kontakton" + +#: ../../mod/contacts.php:566 ../../view/theme/diabook/theme.php:129 +#: ../../include/nav.php:139 +msgid "Contacts" +msgstr "Kontaktoj" + +#: ../../mod/contacts.php:570 +msgid "Search your contacts" +msgstr "Serĉi viajn kontaktojn" + +#: ../../mod/contacts.php:571 ../../mod/directory.php:57 +msgid "Finding: " +msgstr "Trovata:" + +#: ../../mod/contacts.php:572 ../../mod/directory.php:59 +#: ../../include/contact_widgets.php:33 +msgid "Find" +msgstr "Trovi" + +#: ../../mod/lostpass.php:16 +msgid "No valid account found." +msgstr "Ne trovis validan konton." + +#: ../../mod/lostpass.php:32 +msgid "Password reset request issued. Check your email." +msgstr "Eldonis riparadon de pasvorto. Legu vian retpoÅton." + +#: ../../mod/lostpass.php:43 +#, php-format +msgid "Password reset requested at %s" +msgstr "Pasvorta riparado petita je %s" + +#: ../../mod/lostpass.php:45 ../../mod/lostpass.php:107 +#: ../../mod/register.php:90 ../../mod/register.php:144 +#: ../../mod/regmod.php:54 ../../mod/dfrn_confirm.php:752 +#: ../../addon/facebook/facebook.php:700 +#: ../../addon/facebook/facebook.php:1190 +#: ../../addon/public_server/public_server.php:62 +#: ../../addon/testdrive/testdrive.php:67 ../../include/items.php:2890 +#: ../../boot.php:730 +msgid "Administrator" +msgstr "Administranto" + +#: ../../mod/lostpass.php:65 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "Ne povis konfirmi la peton. (Eble vi sendis Äin antaÅ­.) Pasvorta riparado malsukcesis." + +#: ../../mod/lostpass.php:83 ../../boot.php:862 +msgid "Password Reset" +msgstr "Pasvorta riparado" + +#: ../../mod/lostpass.php:84 +msgid "Your password has been reset as requested." +msgstr "Via pasvorto estis riparita laÅ­ via peto." + +#: ../../mod/lostpass.php:85 +msgid "Your new password is" +msgstr "Via nova pasvorto estas" + +#: ../../mod/lostpass.php:86 +msgid "Save or copy your new password - and then" +msgstr "Memorigi vian novan pasvorton - kaj poste" + +#: ../../mod/lostpass.php:87 +msgid "click here to login" +msgstr "klaku ĉi tie por ensaluti" + +#: ../../mod/lostpass.php:88 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Vi povas Åangi vian pasvorton sur la paÄo agordoj kiam vi sukcese ensalutis." + +#: ../../mod/lostpass.php:119 +msgid "Forgot your Password?" +msgstr "Ĉu vi forgesis vian pasvorton?" + +#: ../../mod/lostpass.php:120 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Entajpu vian retpoÅtadreson kaj sendu por pasvorta riparado. Poste, bonvolu legi vian retpoÅton por trovi pliajn instrukciojn." + +#: ../../mod/lostpass.php:121 +msgid "Nickname or Email: " +msgstr "Salutnomo aÅ­ retpoÅtadreso: " + +#: ../../mod/lostpass.php:122 +msgid "Reset" +msgstr "Repari" + +#: ../../mod/settings.php:50 ../../include/nav.php:137 +msgid "Account settings" +msgstr "Konto" + +#: ../../mod/settings.php:55 +msgid "Display settings" +msgstr "Ekrano" + +#: ../../mod/settings.php:61 +msgid "Connector settings" +msgstr "Konektiloj" + +#: ../../mod/settings.php:66 +msgid "Plugin settings" +msgstr "Kromprogramoj" + +#: ../../mod/settings.php:71 +msgid "Connected apps" +msgstr "Konektitaj programoj" + +#: ../../mod/settings.php:76 +msgid "Export personal data" +msgstr "Eksporto" + +#: ../../mod/settings.php:81 +msgid "Remove account" +msgstr "Forigi konton" + +#: ../../mod/settings.php:89 ../../mod/admin.php:751 ../../mod/admin.php:956 +#: ../../addon/dav/layout.fnk.php:116 ../../addon/mathjax/mathjax.php:36 +#: ../../view/theme/diabook/theme.php:643 +#: ../../view/theme/diabook/theme.php:773 ../../include/nav.php:137 +msgid "Settings" +msgstr "Agordoj" + +#: ../../mod/settings.php:133 +msgid "Missing some important data!" +msgstr "Mankas importantaj datumoj!" + +#: ../../mod/settings.php:136 ../../mod/settings.php:581 +msgid "Update" +msgstr "Äœisdatigi" + +#: ../../mod/settings.php:241 +msgid "Failed to connect with email account using the settings provided." +msgstr "Ne sukcesis konekti al retpoÅtkonto kun la provizitaj agordoj." + +#: ../../mod/settings.php:246 +msgid "Email settings updated." +msgstr "RetpoÅtagordoj Äisdatigita" + +#: ../../mod/settings.php:305 +msgid "Passwords do not match. Password unchanged." +msgstr "La pasvortoj ne estas egala. Pasvorto ne ÅanÄita." + +#: ../../mod/settings.php:310 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Malplenaj pasvortoj ne estas permesita. Pasvorto ne ÅanÄita." + +#: ../../mod/settings.php:321 +msgid "Password changed." +msgstr "Pasvorto ÅanÄita." + +#: ../../mod/settings.php:323 +msgid "Password update failed. Please try again." +msgstr "Äœisdatigo de pasvorto malsukcesis. Bonvolu provi refoje." + +#: ../../mod/settings.php:386 +msgid " Please use a shorter name." +msgstr " Bonvolu uzi pli mallongan nomon." + +#: ../../mod/settings.php:388 +msgid " Name too short." +msgstr " Nomo estas tro mallonga." + +#: ../../mod/settings.php:394 +msgid " Not valid email." +msgstr " RepoÅtadreso ne validas." + +#: ../../mod/settings.php:396 +msgid " Cannot change to that email." +msgstr " Ne povas ÅanÄi al tio retpoÅtadreso." + +#: ../../mod/settings.php:450 +msgid "Private forum has no privacy permissions. Using default privacy group." +msgstr "Privata forumo ne havas privatecajn agordojn. DefaÅ­lta privateca grupo estas uzata." + +#: ../../mod/settings.php:454 +msgid "Private forum has no privacy permissions and no default privacy group." +msgstr "Privata forumo havas nek privatecajn agordojn nek defaÅ­ltan privatecan grupon." + +#: ../../mod/settings.php:484 ../../addon/facebook/facebook.php:493 +#: ../../addon/impressum/impressum.php:77 +#: ../../addon/openstreetmap/openstreetmap.php:80 +#: ../../addon/mathjax/mathjax.php:66 ../../addon/piwik/piwik.php:105 +#: ../../addon/twitter/twitter.php:382 +msgid "Settings updated." +msgstr "Agordoj Äisdatigita." + +#: ../../mod/settings.php:554 ../../mod/settings.php:580 +#: ../../mod/settings.php:616 +msgid "Add application" +msgstr "Aldoni programon" + +#: ../../mod/settings.php:558 ../../mod/settings.php:584 +#: ../../addon/statusnet/statusnet.php:561 +msgid "Consumer Key" +msgstr "Åœlosilo de kliento" + +#: ../../mod/settings.php:559 ../../mod/settings.php:585 +#: ../../addon/statusnet/statusnet.php:560 +msgid "Consumer Secret" +msgstr "Sekreto de kliento" + +#: ../../mod/settings.php:560 ../../mod/settings.php:586 +msgid "Redirect" +msgstr "Alidirekto" + +#: ../../mod/settings.php:561 ../../mod/settings.php:587 +msgid "Icon url" +msgstr "Piktograma adreso" + +#: ../../mod/settings.php:572 +msgid "You can't edit this application." +msgstr "Ĉi tio programo ne estas redaktebla." + +#: ../../mod/settings.php:615 +msgid "Connected Apps" +msgstr "Konektitaj Programoj" + +#: ../../mod/settings.php:619 +msgid "Client key starts with" +msgstr "Åœlosilo de kliento komencas kun" + +#: ../../mod/settings.php:620 +msgid "No name" +msgstr "Neniu nomo" + +#: ../../mod/settings.php:621 +msgid "Remove authorization" +msgstr "ForviÅi rajtigon" + +#: ../../mod/settings.php:632 +msgid "No Plugin settings configured" +msgstr "Neniom da kromprogramoagordoj farita" + +#: ../../mod/settings.php:640 ../../addon/widgets/widgets.php:123 +msgid "Plugin Settings" +msgstr "Kromprogramoagordoj" + +#: ../../mod/settings.php:652 ../../mod/settings.php:653 +#, php-format +msgid "Built-in support for %s connectivity is %s" +msgstr "Integrita subteno por %s koneto estas %s" + +#: ../../mod/settings.php:652 ../../mod/settings.php:653 +msgid "enabled" +msgstr "Åaltita" + +#: ../../mod/settings.php:652 ../../mod/settings.php:653 +msgid "disabled" +msgstr "malÅaltita" + +#: ../../mod/settings.php:653 +msgid "StatusNet" +msgstr "StatusNet" + +#: ../../mod/settings.php:685 +msgid "Email access is disabled on this site." +msgstr "RetpoÅta atingo ne disponeblas ĉi tie." + +#: ../../mod/settings.php:691 +msgid "Connector Settings" +msgstr "Konektiloagordoj" + +#: ../../mod/settings.php:696 +msgid "Email/Mailbox Setup" +msgstr "Agordoj pri RetpoÅto" + +#: ../../mod/settings.php:697 +msgid "" +"If you wish to communicate with email contacts using this service " +"(optional), please specify how to connect to your mailbox." +msgstr "Se vi volas uzi ĉi tiun servon por komuniki per retpoÅto (nedeviga), bonvolu specifi kiel konekti al vian retpoÅtkonton." + +#: ../../mod/settings.php:698 +msgid "Last successful email check:" +msgstr "Plej ĵusa sukcesa kontrolo de poÅto:" + +#: ../../mod/settings.php:700 +msgid "IMAP server name:" +msgstr "Nomo de IMAP servilo:" + +#: ../../mod/settings.php:701 +msgid "IMAP port:" +msgstr "Numero de IMAP pordo:" + +#: ../../mod/settings.php:702 +msgid "Security:" +msgstr "Sekureco:" + +#: ../../mod/settings.php:702 ../../mod/settings.php:707 +msgid "None" +msgstr "Nenio" + +#: ../../mod/settings.php:703 +msgid "Email login name:" +msgstr "RetpoÅta salutnomo:" + +#: ../../mod/settings.php:704 +msgid "Email password:" +msgstr "RetpoÅta pasvorto:" + +#: ../../mod/settings.php:705 +msgid "Reply-to address:" +msgstr "Responda adreso (Reply-to):" + +#: ../../mod/settings.php:706 +msgid "Send public posts to all email contacts:" +msgstr "Sendu publikajn afiÅojn al ĉiuj retpoÅtkontaktoj:" + +#: ../../mod/settings.php:707 +msgid "Action after import:" +msgstr "Ago post la importado:" + +#: ../../mod/settings.php:707 +msgid "Mark as seen" +msgstr "Marki kiel legita" + +#: ../../mod/settings.php:707 +msgid "Move to folder" +msgstr "Movi al dosierujo" + +#: ../../mod/settings.php:708 +msgid "Move to folder:" +msgstr "Movi al dosierujo:" + +#: ../../mod/settings.php:768 +msgid "Display Settings" +msgstr "Ekranagordoj" + +#: ../../mod/settings.php:774 +msgid "Display Theme:" +msgstr "Vidiga etoso:" + +#: ../../mod/settings.php:775 +msgid "Update browser every xx seconds" +msgstr "Äœisdatigu retesplorilon ĉiu xxx sekundoj" + +#: ../../mod/settings.php:775 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Minimume 10 sekundoj, sen maksimumo" + +#: ../../mod/settings.php:776 +msgid "Number of items to display on the network page:" +msgstr "Kvanto da elementoj kiuj estos montrata ĉe la reto paÄo." + +#: ../../mod/settings.php:776 +msgid "Maximum of 100 items" +msgstr "Maksimume 100 eroj" + +#: ../../mod/settings.php:777 +msgid "Don't show emoticons" +msgstr "Ne montru ridetulojn" + +#: ../../mod/settings.php:848 +msgid "Normal Account Page" +msgstr "Normala KontopaÄo" + +#: ../../mod/settings.php:849 +msgid "This account is a normal personal profile" +msgstr "Tiu konto estas normala persona profilo" + +#: ../../mod/settings.php:852 +msgid "Soapbox Page" +msgstr "Soapbox PaÄo" + +#: ../../mod/settings.php:853 +msgid "Automatically approve all connection/friend requests as read-only fans" +msgstr "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel nurlegaj admirantoj" + +#: ../../mod/settings.php:856 +msgid "Community Forum/Celebrity Account" +msgstr "Komunuma Forumo/Eminentula Konto" + +#: ../../mod/settings.php:857 +msgid "" +"Automatically approve all connection/friend requests as read-write fans" +msgstr "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel admirantoj kapable legi kaj skribi" + +#: ../../mod/settings.php:860 +msgid "Automatic Friend Page" +msgstr "AÅ­tomata Amiko PaÄo" + +#: ../../mod/settings.php:861 +msgid "Automatically approve all connection/friend requests as friends" +msgstr "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel amikoj" + +#: ../../mod/settings.php:864 +msgid "Private Forum [Experimental]" +msgstr "Privata Forumo [eksperimenta]" + +#: ../../mod/settings.php:865 +msgid "Private forum - approved members only" +msgstr "Privata forumo - nur por aprobitaj membroj" + +#: ../../mod/settings.php:877 +msgid "OpenID:" +msgstr "OpenID:" + +#: ../../mod/settings.php:877 +msgid "(Optional) Allow this OpenID to login to this account." +msgstr "(Nedeviga) Permesi atingon al la konton al ĉi tio OpenID." + +#: ../../mod/settings.php:887 +msgid "Publish your default profile in your local site directory?" +msgstr "Publikigi vian defaÅ­ltan profilon en la loka reteja katalogo?" + +#: ../../mod/settings.php:893 +msgid "Publish your default profile in the global social directory?" +msgstr "Publikigi vian defaÅ­ltan profilon en la tutmonda interkona katalogo?" + +#: ../../mod/settings.php:901 +msgid "Hide your contact/friend list from viewers of your default profile?" +msgstr "KaÅi vian liston de kontaktoj/amiko al spektantoj de via defaÅ­lta profilo?" + +#: ../../mod/settings.php:905 +msgid "Hide your profile details from unknown viewers?" +msgstr "KaÅi viajn profilajn detalojn al nekonataj spektantoj?" + +#: ../../mod/settings.php:910 +msgid "Allow friends to post to your profile page?" +msgstr "Ĉu amikoj povu afiÅi al via profilo?" + +#: ../../mod/settings.php:916 +msgid "Allow friends to tag your posts?" +msgstr "Ĉu amikoj povu aldoni markojn al viaj afiÅoj?" + +#: ../../mod/settings.php:922 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "Ĉu ni povu sugesti vin kiel amiko al novaj membroj?" + +#: ../../mod/settings.php:928 +msgid "Permit unknown people to send you private mail?" +msgstr "Permesigi nekonatulojn sendi retpoÅton al vi?" + +#: ../../mod/settings.php:936 +msgid "Profile is not published." +msgstr "Profilo ne estas publika." + +#: ../../mod/settings.php:939 ../../mod/profile_photo.php:213 +msgid "or" +msgstr "aÅ­" + +#: ../../mod/settings.php:944 +msgid "Your Identity Address is" +msgstr "Via identeca adreso estas" + +#: ../../mod/settings.php:955 +msgid "Automatically expire posts after this many days:" +msgstr "Automatike senvalidigi afiÅojn post tiom da tagoj:" + +#: ../../mod/settings.php:955 +msgid "If empty, posts will not expire. Expired posts will be deleted" +msgstr "Se malplena, afiÅoj neniam senvalidiÄos. Senvalidigitajn afiÅon estos forviÅata" + +#: ../../mod/settings.php:956 +msgid "Advanced expiration settings" +msgstr "Detalaj agordoj rilate al senvalidiÄo" + +#: ../../mod/settings.php:957 +msgid "Advanced Expiration" +msgstr "Detala senvalidiÄo" + +#: ../../mod/settings.php:958 +msgid "Expire posts:" +msgstr "Senvalidigi afiÅojn:" + +#: ../../mod/settings.php:959 +msgid "Expire personal notes:" +msgstr "Senvalidigi personajn notojn:" + +#: ../../mod/settings.php:960 +msgid "Expire starred posts:" +msgstr "Senvalidigi steligitajn afiÅojn:" + +#: ../../mod/settings.php:961 +msgid "Expire photos:" +msgstr "Senvalidigi bildojn:" + +#: ../../mod/settings.php:962 +msgid "Only expire posts by others:" +msgstr "Nur senvalidigi afiÅojn de aliaj: " + +#: ../../mod/settings.php:969 +msgid "Account Settings" +msgstr "Kontoagordoj" + +#: ../../mod/settings.php:977 +msgid "Password Settings" +msgstr "Agordoj pri Pasvorto" + +#: ../../mod/settings.php:978 +msgid "New Password:" +msgstr "Nova pasvorto:" + +#: ../../mod/settings.php:979 +msgid "Confirm:" +msgstr "Konfirmi:" + +#: ../../mod/settings.php:979 +msgid "Leave password fields blank unless changing" +msgstr "Lasu pasvortkampojn malplenaj se vi ne ÅanÄas la pasvorton." + +#: ../../mod/settings.php:983 +msgid "Basic Settings" +msgstr "Bazaj Agordoj" + +#: ../../mod/settings.php:984 ../../include/profile_advanced.php:15 +msgid "Full Name:" +msgstr "Plena Nomo:" + +#: ../../mod/settings.php:985 +msgid "Email Address:" +msgstr "RetpoÅtadreso:" + +#: ../../mod/settings.php:986 +msgid "Your Timezone:" +msgstr "Via Horzono:" + +#: ../../mod/settings.php:987 +msgid "Default Post Location:" +msgstr "DefaÅ­lta Loko por AfiÅoj:" + +#: ../../mod/settings.php:988 +msgid "Use Browser Location:" +msgstr "Uzu Lokon laÅ­ Retesplorilo:" + +#: ../../mod/settings.php:991 +msgid "Security and Privacy Settings" +msgstr "Agordoj pri Sekureco kaj Privateco" + +#: ../../mod/settings.php:993 +msgid "Maximum Friend Requests/Day:" +msgstr "Taga maksimumo da kontaktpetoj:" + +#: ../../mod/settings.php:993 ../../mod/settings.php:1012 +msgid "(to prevent spam abuse)" +msgstr "(por malhelpi spamaĵojn)" + +#: ../../mod/settings.php:994 +msgid "Default Post Permissions" +msgstr "DefaÅ­ltaj permesoj por afiÅoj" + +#: ../../mod/settings.php:995 +msgid "(click to open/close)" +msgstr "(klaku por malfermi/fermi)" + +#: ../../mod/settings.php:1012 +msgid "Maximum private messages per day from unknown people:" +msgstr "Taga maksimumo da privataj mesaÄoj." + +#: ../../mod/settings.php:1015 +msgid "Notification Settings" +msgstr "Agordoj pri Atentigoj" + +#: ../../mod/settings.php:1016 +msgid "By default post a status message when:" +msgstr "DefaÅ­lte afiÅi statmesaÄon okaze de:" + +#: ../../mod/settings.php:1017 +msgid "accepting a friend request" +msgstr "akcepti kontaktpeton" + +#: ../../mod/settings.php:1018 +msgid "joining a forum/community" +msgstr "aliÄi forumon/komunumon" + +#: ../../mod/settings.php:1019 +msgid "making an interesting profile change" +msgstr "fari interesan profilÅanÄon" + +#: ../../mod/settings.php:1020 +msgid "Send a notification email when:" +msgstr "Sendu atentiga repoÅton se:" + +#: ../../mod/settings.php:1021 +msgid "You receive an introduction" +msgstr "Vi ricevas inviton" + +#: ../../mod/settings.php:1022 +msgid "Your introductions are confirmed" +msgstr "Viaj prezentoj estas konfirmata." + +#: ../../mod/settings.php:1023 +msgid "Someone writes on your profile wall" +msgstr "Iu skribas je via profila muro." + +#: ../../mod/settings.php:1024 +msgid "Someone writes a followup comment" +msgstr "Iu skribas sekvan komenton" + +#: ../../mod/settings.php:1025 +msgid "You receive a private message" +msgstr "Vi ricevas privatan mesaÄon." + +#: ../../mod/settings.php:1026 +msgid "You receive a friend suggestion" +msgstr "Vi ricevas amikosugeston" + +#: ../../mod/settings.php:1027 +msgid "You are tagged in a post" +msgstr "Vi estas markita en afiÅon" + +#: ../../mod/settings.php:1030 +msgid "Advanced Account/Page Type Settings" +msgstr "Detalaj Agordoj pri Tipo de Konto/PaÄo." + +#: ../../mod/settings.php:1031 +msgid "Change the behaviour of this account for special situations" +msgstr "Agordi la teniÄon de la konto en specialaj situacioj" + +#: ../../mod/manage.php:90 +msgid "Manage Identities and/or Pages" +msgstr "Administri identecojn kaj/aÅ­ paÄojn." + +#: ../../mod/manage.php:93 +msgid "" +"Toggle between different identities or community/group pages which share " +"your account details or which you have been granted \"manage\" permissions" +msgstr "Åœalti inter aliaj identecojn aj komunumaj/grupaj paÄoj kiuj kunhavas viajn kontajn detalojn au por kiuj vi havas \"administranto\" permesojn." + +#: ../../mod/manage.php:95 +msgid "Select an identity to manage: " +msgstr "Elektu identencon por administrado:" + +#: ../../mod/network.php:97 +msgid "Search Results For:" +msgstr "Rezultoj de la serĉado pri:" + +#: ../../mod/network.php:137 ../../mod/search.php:16 +msgid "Remove term" +msgstr "ForviÅu terminon" + +#: ../../mod/network.php:146 ../../mod/search.php:13 +msgid "Saved Searches" +msgstr "Konservitaj Serĉadoj" + +#: ../../mod/network.php:147 ../../include/group.php:244 +msgid "add" +msgstr "aldoni" + +#: ../../mod/network.php:287 +msgid "Commented Order" +msgstr "Komenta Ordo" + +#: ../../mod/network.php:290 +msgid "Sort by Comment Date" +msgstr "Ordigi laÅ­ Dato de Komento" + +#: ../../mod/network.php:293 +msgid "Posted Order" +msgstr "AfiÅita Ordo" + +#: ../../mod/network.php:296 +msgid "Sort by Post Date" +msgstr "Ordigi laÅ­ Dato de AfiÅado" + +#: ../../mod/network.php:303 +msgid "Posts that mention or involve you" +msgstr "AfiÅoj menciantaj vin aÅ­ pri vi" + +#: ../../mod/network.php:306 +msgid "New" +msgstr "Nova" + +#: ../../mod/network.php:309 +msgid "Activity Stream - by date" +msgstr "Fluo de Aktiveco - laÅ­ dato" + +#: ../../mod/network.php:312 +msgid "Starred" +msgstr "Steligita" + +#: ../../mod/network.php:315 +msgid "Favourite Posts" +msgstr "Favorigitaj AfiÅoj" + +#: ../../mod/network.php:318 +msgid "Shared Links" +msgstr "Kunhavigitaj Ligiloj" + +#: ../../mod/network.php:321 +msgid "Interesting Links" +msgstr "Interesaj Ligiloj" + +#: ../../mod/network.php:388 +#, php-format +msgid "Warning: This group contains %s member from an insecure network." +msgid_plural "" +"Warning: This group contains %s members from an insecure network." +msgstr[0] "Averto: La grupo enhavas %s membron el nesekuraj retejoj." +msgstr[1] "Averto: La grupo enhavas %s membrojn el nesekuraj retejoj." + +#: ../../mod/network.php:391 +msgid "Private messages to this group are at risk of public disclosure." +msgstr "La privateco de privataj mesaÄoj al ĉi tiu grupo ne ĉiam estas garantita." + +#: ../../mod/network.php:436 +msgid "No such group" +msgstr "Grupo ne estas trovita" + +#: ../../mod/network.php:447 +msgid "Group is empty" +msgstr "Grupo estas malplena" + +#: ../../mod/network.php:451 +msgid "Group: " +msgstr "Grupo:" + +#: ../../mod/network.php:461 +msgid "Contact: " +msgstr "Kontakto:" + +#: ../../mod/network.php:463 +msgid "Private messages to this person are at risk of public disclosure." +msgstr "La privateco de privataj mesaÄoj al ĉi tiu persono ne ĉiam estas garantita." + +#: ../../mod/network.php:468 +msgid "Invalid contact." +msgstr "Nevalida kontakto." + +#: ../../mod/notes.php:44 ../../boot.php:1565 +msgid "Personal Notes" +msgstr "Personaj Notoj" + +#: ../../mod/notes.php:63 ../../mod/filer.php:30 +#: ../../addon/facebook/facebook.php:768 +#: ../../addon/privacy_image_cache/privacy_image_cache.php:187 +#: ../../addon/dav/layout.fnk.php:384 ../../include/text.php:652 +msgid "Save" +msgstr "Konservi" + +#: ../../mod/wallmessage.php:42 ../../mod/wallmessage.php:112 +#, php-format +msgid "Number of daily wall messages for %s exceeded. Message failed." +msgstr "Number of daily wall messages for %s exceeded. MessaÄo malsukcesis." + +#: ../../mod/wallmessage.php:56 ../../mod/message.php:66 +msgid "No recipient selected." +msgstr "Neniom da ricevontoj." + +#: ../../mod/wallmessage.php:59 +msgid "Unable to check your home location." +msgstr "Ne eblas kontroli vian hejmlokon." + +#: ../../mod/wallmessage.php:62 ../../mod/message.php:73 +msgid "Message could not be sent." +msgstr "Ne povas sendi la mesaÄon." + +#: ../../mod/wallmessage.php:65 ../../mod/message.php:76 +msgid "Message collection failure." +msgstr "Malsukcese provis kolekti mesaÄojn." + +#: ../../mod/wallmessage.php:68 ../../mod/message.php:79 +msgid "Message sent." +msgstr "MesaÄo estas sendita." + +#: ../../mod/wallmessage.php:86 ../../mod/wallmessage.php:95 +msgid "No recipient." +msgstr "Neniom da ricevontoj." + +#: ../../mod/wallmessage.php:124 ../../mod/message.php:172 +#: ../../include/conversation.php:947 +msgid "Please enter a link URL:" +msgstr "Bonvolu entajpu adreson de ligilo:" + +#: ../../mod/wallmessage.php:131 ../../mod/message.php:200 +msgid "Send Private Message" +msgstr "Sendi Privatan MesaÄon" + +#: ../../mod/wallmessage.php:132 +#, php-format +msgid "" +"If you wish for %s to respond, please check that the privacy settings on " +"your site allow private mail from unknown senders." +msgstr "Se vi deziras ke %s respondu, bonvolu kontroli ke la privatecaj agordoj je via retejo permesas privatajn mesaÄojn de nekonataj sendantoj." + +#: ../../mod/wallmessage.php:133 ../../mod/message.php:201 +#: ../../mod/message.php:399 +msgid "To:" +msgstr "Al:" + +#: ../../mod/wallmessage.php:134 ../../mod/message.php:206 +#: ../../mod/message.php:401 +msgid "Subject:" +msgstr "Temo:" + +#: ../../mod/wallmessage.php:140 ../../mod/message.php:210 +#: ../../mod/message.php:404 ../../mod/invite.php:113 +msgid "Your message:" +msgstr "Via mesaÄo:" + +#: ../../mod/newmember.php:6 +msgid "Welcome to Friendica" +msgstr "Bonvenon ĉe Friendica" + +#: ../../mod/newmember.php:8 +msgid "New Member Checklist" +msgstr "Kontrololisto por Novaj Membroj" + +#: ../../mod/newmember.php:12 +msgid "" +"We would like to offer some tips and links to help make your experience " +"enjoyable. Click any item to visit the relevant page. A link to this page " +"will be visible from your home page for two weeks after your initial " +"registration and then will quietly disappear." +msgstr "Lasu nin oferi al vi kelkajn konsolojn kaj ligilojn por plifaciligi vian komencon. Klaku iun elementon por viziti la rilatan paÄon. Ligilo al ĉi tiu paÄo videblos en via hejmpaÄo dum du semajnojn post via komenca membriÄo. Post du semajnoj, la ligilo silente malaperos. " + +#: ../../mod/newmember.php:16 +msgid "" +"On your Quick Start page - find a brief introduction to your " +"profile and network tabs, connect to Facebook, make some new connections, " +"and find some groups to join." +msgstr "Je via Rapida Starto paÄo - trovu mallongan enigon pri via profilo kaj la reto folioj, konektu al Facebook, faru novajn konektojn kaj trovu aliÄindajn grupojn." + +#: ../../mod/newmember.php:18 +msgid "" +"On your Settings page - change your initial password. Also make a " +"note of your Identity Address. This looks just like an email address - and " +"will be useful in making friends on the free social web." +msgstr "Bonvolu ÅanÄi vian pasvorton ĉe Agordoj. Krome, memorigu vian identadreson. Äœi aspektas kiel retpoÅtadreso kaj estas bezonata por konekti al novaj amikon en la libera interkona reto." + +#: ../../mod/newmember.php:20 +msgid "" +"Review the other settings, particularly the privacy settings. An unpublished" +" directory listing is like having an unlisted phone number. In general, you " +"should probably publish your listing - unless all of your friends and " +"potential friends know exactly how to find you." +msgstr "Kontrolu la aliajn agordojn, precipe la privatecajn agordojn. Nepublikigita profilo similas al havi telefonnumberon ne registrata en iu telefonlibro. Äœenerale vi eble volas publikigi vian profilon. Alie, viaj amikoj kaj estontaj amikoj bezonas scii kiel rekte trovi vin." + +#: ../../mod/newmember.php:22 +msgid "" +"Upload a profile photo if you have not done so already. Studies have shown " +"that people with real photos of themselves are ten times more likely to make" +" friends than people who do not." +msgstr "EnÅuti profilbildon se vi ankoraÅ­ ne havas Äin. LaÅ­ studoj, homoj kun realaj biloj de si mem trovas novajn amikon duope pli probable ol homoj sen reala bildo." + +#: ../../mod/newmember.php:25 +msgid "" +"Authorise the Facebook Connector if you currently have a Facebook account " +"and we will (optionally) import all your Facebook friends and conversations." +msgstr "Rajtigu la Facebook Konektilon se vi nuntempe havas Facebook konton, kaj ni (nedeviga) enportu viajn Facebook amikojn kaj konversaciojn." + +#: ../../mod/newmember.php:27 +msgid "" +"If this is your own personal server, installing the Facebook addon " +"may ease your transition to the free social web." +msgstr "Se ĉi tiu estas via propra TTT servilo, instali la Facebook kromprogramon eble plifaciligos la transpason al la libera interkona reto." + +#: ../../mod/newmember.php:32 +msgid "" +"Enter your email access information on your Connector Settings page if you " +"wish to import and interact with friends or mailing lists from your email " +"INBOX" +msgstr "Entajpu la akreditaĵojn por via retpoÅtkonto en la konektilagordoj se vi volas importi aÅ­ interagi kun amikoj aÅ­ dissendlistoj pere de via retkesto." + +#: ../../mod/newmember.php:34 +msgid "" +"Edit your default profile to your liking. Review the " +"settings for hiding your list of friends and hiding the profile from unknown" +" visitors." +msgstr "Redakti viajn defaÅ­ltan profilon kiel vi Åatas Äin. Kontrolu la agordojn por kaÅi vian kontaktliston aÅ­ kaÅi vian profilon al nekonataj vizitantoj." + +#: ../../mod/newmember.php:36 +msgid "" +"Set some public keywords for your default profile which describe your " +"interests. We may be able to find other people with similar interests and " +"suggest friendships." +msgstr "Aldonu publikajn Ålosilvortojn al via defaÅ­lta profilo, kiuj priskribas viajn interesojn. Ni eble povas trovi aliajn uzantojn kun similaj interesoj kaj sugesti amikojn." + +#: ../../mod/newmember.php:38 +msgid "" +"Your Contacts page is your gateway to managing friendships and connecting " +"with friends on other networks. Typically you enter their address or site " +"URL in the Add New Contact dialog." +msgstr "Via kontaktpaÄo estas via portalo por administri amikojn kaj konekti kun amikoj en aliaj retoj. Vi kutime entajpas iliajn adreson aÅ­ URL adreso en la Aldonu Novan Kontakton dialogon." + +#: ../../mod/newmember.php:40 +msgid "" +"The Directory page lets you find other people in this network or other " +"federated sites. Look for a Connect or Follow link on " +"their profile page. Provide your own Identity Address if requested." +msgstr "Ĉe la Katalogo vi povas trovi aliajn homojn en ĉi tiu retejo, au en aliaj federaciaj retejoj. Elrigardi al Konekti aÅ­ Sekvi ligiloj ĉe iliaj profilo. Donu vian propran Identecan Adreson se la retejo demandas Äin." + +#: ../../mod/newmember.php:42 +msgid "" +"On the side panel of the Contacts page are several tools to find new " +"friends. We can match people by interest, look up people by name or " +"interest, and provide suggestions based on network relationships. On a brand" +" new site, friend suggestions will usually begin to be populated within 24 " +"hours." +msgstr "En la flanka strio de la Kontaktoj paÄo troviÄas kelkajn helpilojn por trovi novajn amikojn. Ni povas automate trovi amikojn per interesoj, serĉu ilin per nomo aÅ­ intereso kaj faras sugestojn baze de estantaj kontaktoj. Ĉe nova instalita retejo, la unuaj sugestoj kutime aperas post 24 horoj." + +#: ../../mod/newmember.php:44 +msgid "" +"Once you have made some friends, organize them into private conversation " +"groups from the sidebar of your Contacts page and then you can interact with" +" each group privately on your Network page." +msgstr "Kiam vi trovis kelkajn novajn amikojn, ordigi ilin en grupoj por privata komunikado en la flanka strio de via Kontaktoj paÄo, kaj vi povas private komuniki kun ili je via Reto paÄo." + +#: ../../mod/newmember.php:46 +msgid "" +"Our help pages may be consulted for detail on other program" +" features and resources." +msgstr "Niaj Helpo paÄoj enhavas pli da detaloj pri aliaj programaj trajtoj." + +#: ../../mod/attach.php:8 +msgid "Item not available." +msgstr "Elemento ne disponeblas." + +#: ../../mod/attach.php:20 +msgid "Item was not found." +msgstr "Elemento ne trovita." + +#: ../../mod/group.php:29 +msgid "Group created." +msgstr "Grupo estas kreita." + +#: ../../mod/group.php:35 +msgid "Could not create group." +msgstr "Ne povas krei grupon." + +#: ../../mod/group.php:47 ../../mod/group.php:137 +msgid "Group not found." +msgstr "Grupo ne estas trovita." + +#: ../../mod/group.php:60 +msgid "Group name changed." +msgstr "La nomo de la grupo estas ÅanÄita." + +#: ../../mod/group.php:72 ../../mod/profperm.php:19 ../../index.php:308 +msgid "Permission denied" +msgstr "Malpermesita" + +#: ../../mod/group.php:90 +msgid "Create a group of contacts/friends." +msgstr "Krei grupon da kontaktoj/amikoj." + +#: ../../mod/group.php:91 ../../mod/group.php:177 +msgid "Group Name: " +msgstr "Nomo de la grupo:" + +#: ../../mod/group.php:110 +msgid "Group removed." +msgstr "Grupo estas forviÅita." + +#: ../../mod/group.php:112 +msgid "Unable to remove group." +msgstr "Ne eblas forviÅi grupon." + +#: ../../mod/group.php:176 +msgid "Group Editor" +msgstr "Grupa redaktilo" + +#: ../../mod/group.php:189 +msgid "Members" +msgstr "Anoj" + +#: ../../mod/group.php:221 ../../mod/profperm.php:105 +msgid "Click on a contact to add or remove." +msgstr "Klaku kontakton por aldoni aÅ­ forviÅi." + +#: ../../mod/profperm.php:25 ../../mod/profperm.php:55 +msgid "Invalid profile identifier." +msgstr "Nevaliada profila identigilo." + +#: ../../mod/profperm.php:101 +msgid "Profile Visibility Editor" +msgstr "Redaktilo por profila videbleco." + +#: ../../mod/profperm.php:103 ../../view/theme/diabook/theme.php:128 +#: ../../include/profile_advanced.php:7 ../../include/profile_advanced.php:84 +#: ../../include/nav.php:50 ../../boot.php:1544 +msgid "Profile" +msgstr "Profilo" + +#: ../../mod/profperm.php:114 +msgid "Visible To" +msgstr "Videbla Al" + +#: ../../mod/profperm.php:130 +msgid "All Contacts (with secure profile access)" +msgstr "Ĉiuj Kontaktoj (kun sekura atingo al la profilo)" + +#: ../../mod/viewconnections.php:39 +msgid "No contacts." +msgstr "Neniu kontaktojn." + +#: ../../mod/viewconnections.php:76 ../../include/text.php:589 +msgid "View Contacts" +msgstr "Vidi Kontaktojn" + +#: ../../mod/register.php:88 ../../mod/regmod.php:52 +#, php-format +msgid "Registration details for %s" +msgstr "Detaloj de la registrado por %s" + +#: ../../mod/register.php:96 +msgid "" +"Registration successful. Please check your email for further instructions." +msgstr "Registrado sukcesis. Bonvolu kontroli vian retpoÅton por pli da instruoj." + +#: ../../mod/register.php:100 +msgid "Failed to send email message. Here is the message that failed." +msgstr "Malsukcesis sendi retpoÅton. Jen la malsukcesa mesaÄo." + +#: ../../mod/register.php:105 +msgid "Your registration can not be processed." +msgstr "Mi ne povas prilabori vian registradon." + +#: ../../mod/register.php:142 +#, php-format +msgid "Registration request at %s" +msgstr "Peto de registrado al %s" + +#: ../../mod/register.php:151 +msgid "Your registration is pending approval by the site owner." +msgstr "Via registrado bezonas apropbon de la administranto." + +#: ../../mod/register.php:189 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "La retejo transiras la maksimuman kvanton da ĉiutagaj kontaj registradoj. Bonvolu provi denove morgaÅ­." + +#: ../../mod/register.php:215 +msgid "" +"You may (optionally) fill in this form via OpenID by supplying your OpenID " +"and clicking 'Register'." +msgstr "Vi ankaÅ­ (nedeviga) povas plenigi la formularon per OpenID se vi provizas vian OpenID adreson kaj klakas 'Registri'." + +#: ../../mod/register.php:216 +msgid "" +"If you are not familiar with OpenID, please leave that field blank and fill " +"in the rest of the items." +msgstr "Se vi ne konas OpenID, bonvolu lasi tiun kampon malplena kaj entajpu la aliajn elementojn." + +#: ../../mod/register.php:217 +msgid "Your OpenID (optional): " +msgstr "Via OpenID (nedeviga):" + +#: ../../mod/register.php:231 +msgid "Include your profile in member directory?" +msgstr "Aldoni vian profilon al la membrokatalogo?" + +#: ../../mod/register.php:251 +msgid "Membership on this site is by invitation only." +msgstr "MembriÄi ĉi tie nur eblas laÅ­ invito." + +#: ../../mod/register.php:252 +msgid "Your invitation ID: " +msgstr "Via invita idento: " + +#: ../../mod/register.php:255 ../../mod/admin.php:421 +msgid "Registration" +msgstr "Registrado" + +#: ../../mod/register.php:263 +msgid "Your Full Name (e.g. Joe Smith): " +msgstr "Via Plena Nomo (e.g. Joe Smith): " + +#: ../../mod/register.php:264 +msgid "Your Email Address: " +msgstr "Via RetpoÅtadreso: " + +#: ../../mod/register.php:265 +msgid "" +"Choose a profile nickname. This must begin with a text character. Your " +"profile address on this site will then be " +"'nickname@$sitename'." +msgstr "Elektu kaÅnomon por la profilo. Tiu bezonas komenci kun teksta litero. Poste, via profila adreso ĉi tie estos: 'kaÅnomo@$sitename'." + +#: ../../mod/register.php:266 +msgid "Choose a nickname: " +msgstr "Elektu kaÅnomon: " + +#: ../../mod/register.php:269 ../../include/nav.php:81 ../../boot.php:828 +msgid "Register" +msgstr "Registri" + +#: ../../mod/dirfind.php:26 +msgid "People Search" +msgstr "Serĉi Membrojn" + +#: ../../mod/like.php:144 ../../mod/like.php:301 ../../mod/tagger.php:70 +#: ../../addon/facebook/facebook.php:1584 +#: ../../addon/communityhome/communityhome.php:158 +#: ../../addon/communityhome/communityhome.php:167 +#: ../../view/theme/diabook/theme.php:565 +#: ../../view/theme/diabook/theme.php:574 ../../include/diaspora.php:1710 +#: ../../include/conversation.php:48 ../../include/conversation.php:57 +#: ../../include/conversation.php:121 ../../include/conversation.php:130 +msgid "status" +msgstr "staton" + +#: ../../mod/like.php:161 ../../addon/facebook/facebook.php:1588 +#: ../../addon/communityhome/communityhome.php:172 +#: ../../view/theme/diabook/theme.php:579 ../../include/diaspora.php:1726 +#: ../../include/conversation.php:65 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "%1$s Åatas la %3$s de %2$s" + +#: ../../mod/like.php:163 ../../include/conversation.php:68 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "%1$s malÅatas la %3$s de %2$s" + +#: ../../mod/notice.php:15 ../../mod/viewsrc.php:15 ../../mod/admin.php:159 +#: ../../mod/admin.php:700 ../../mod/admin.php:899 ../../mod/display.php:37 +#: ../../mod/display.php:142 ../../include/items.php:3334 +msgid "Item not found." +msgstr "Elemento ne estas trovita." + +#: ../../mod/viewsrc.php:7 +msgid "Access denied." +msgstr "Atingo nepermesita." + +#: ../../mod/fbrowser.php:25 ../../view/theme/diabook/theme.php:130 +#: ../../include/nav.php:51 ../../boot.php:1550 +msgid "Photos" +msgstr "Bildoj" + +#: ../../mod/fbrowser.php:96 +msgid "Files" +msgstr "Dosieroj" + +#: ../../mod/regmod.php:61 +msgid "Account approved." +msgstr "Konto aprobita." + +#: ../../mod/regmod.php:98 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registraĵo por %s senvalidigita." + +#: ../../mod/regmod.php:110 +msgid "Please login." +msgstr "Bonvolu ensaluti." + +#: ../../mod/item.php:89 +msgid "Unable to locate original post." +msgstr "Ne eblas trovi originalan afiÅon." + +#: ../../mod/item.php:258 +msgid "Empty post discarded." +msgstr "ForviÅis malplenan afiÅon." + +#: ../../mod/item.php:379 ../../mod/wall_upload.php:115 +#: ../../mod/wall_upload.php:124 ../../mod/wall_upload.php:131 +#: ../../include/message.php:144 +msgid "Wall Photos" +msgstr "Muraj Bildoj" + +#: ../../mod/item.php:784 +msgid "System error. Post not saved." +msgstr "Sistema eraro. AfiÅo ne registrita." + +#: ../../mod/item.php:809 +#, php-format +msgid "" +"This message was sent to you by %s, a member of the Friendica social " +"network." +msgstr "Ĉi mesaÄo estas sendita al vi de %s, membro de la Friendica interkona reto." + +#: ../../mod/item.php:811 +#, php-format +msgid "You may visit them online at %s" +msgstr "Vi povas viziti ilin rete ĉe %s" + +#: ../../mod/item.php:812 +msgid "" +"Please contact the sender by replying to this post if you do not wish to " +"receive these messages." +msgstr "Bonvolu rispondi al ĉi mesaÄo kaj kontaktu la sendinto se vi ne volas ricevi tiujn mesaÄojn." + +#: ../../mod/item.php:814 +#, php-format +msgid "%s posted an update." +msgstr "%s publikigis afiÅon." + +#: ../../mod/profile_photo.php:30 +msgid "Image uploaded but image cropping failed." +msgstr "Bildo estas alÅutita, sed malsukcesis tranĉi la bildon." + +#: ../../mod/profile_photo.php:63 ../../mod/profile_photo.php:70 +#: ../../mod/profile_photo.php:77 ../../mod/profile_photo.php:266 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "Malsukcesis malpligrandigi [%s] la bildon." + +#: ../../mod/profile_photo.php:91 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "ReÅarÄu la paÄon au malplenigu la kaÅmemoro de la retesplorilo se la nova bildo ne tuj aperas." + +#: ../../mod/profile_photo.php:101 +msgid "Unable to process image" +msgstr "Ne eblas procezi bildon." + +#: ../../mod/profile_photo.php:117 ../../mod/wall_upload.php:77 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "Bildo estas pli granda ol la limito %d" + +#: ../../mod/profile_photo.php:209 +msgid "Upload File:" +msgstr "AlÅuti dosieron:" + +#: ../../mod/profile_photo.php:210 +msgid "Upload Profile Photo" +msgstr "AlÅuti profilbildon" + +#: ../../mod/profile_photo.php:211 +msgid "Upload" +msgstr "AlÅuti" + +#: ../../mod/profile_photo.php:213 +msgid "skip this step" +msgstr "Preterpasi tian paÅon" + +#: ../../mod/profile_photo.php:213 +msgid "select a photo from your photo albums" +msgstr "elekti bildon el viaj albumoj" + +#: ../../mod/profile_photo.php:226 +msgid "Crop Image" +msgstr "Stuci Bildon" + +#: ../../mod/profile_photo.php:227 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Bonvolu agordi la stuco de la bildo por optimuma aspekto." + +#: ../../mod/profile_photo.php:229 +msgid "Done Editing" +msgstr "Finigi Redaktado" + +#: ../../mod/profile_photo.php:257 +msgid "Image uploaded successfully." +msgstr "Bildo estas sukcese enÅutita." + +#: ../../mod/hcard.php:10 +msgid "No profile" +msgstr "Neniu profilo" + +#: ../../mod/removeme.php:45 ../../mod/removeme.php:48 +msgid "Remove My Account" +msgstr "Forigi Mian Konton" + +#: ../../mod/removeme.php:46 +msgid "" +"This will completely remove your account. Once this has been done it is not " +"recoverable." +msgstr "Tio tute forigos vian konton. Kiam farita, la konto ne estas restaÅ­rebla." + +#: ../../mod/removeme.php:47 +msgid "Please enter your password for verification:" +msgstr "Bonvolu entajpi vian pasvorton por kontrolado:" + +#: ../../mod/message.php:9 ../../include/nav.php:131 +msgid "New Message" +msgstr "Nova MesaÄo" + +#: ../../mod/message.php:70 +msgid "Unable to locate contact information." +msgstr "Ne eblas trovi kontaktajn informojn." + +#: ../../mod/message.php:120 +msgid "Message deleted." +msgstr "MesaÄo estas forviÅita." + +#: ../../mod/message.php:150 +msgid "Conversation removed." +msgstr "Dialogo estas forviÅita." + +#: ../../mod/message.php:247 +msgid "No messages." +msgstr "Neniom da mesaÄoj." + +#: ../../mod/message.php:254 +#, php-format +msgid "Unknown sender - %s" +msgstr "Nekonata sendanto - %s" + +#: ../../mod/message.php:257 +#, php-format +msgid "You and %s" +msgstr "Vi kaj %s" + +#: ../../mod/message.php:260 +#, php-format +msgid "%s and You" +msgstr "%s kaj vi" + +#: ../../mod/message.php:270 ../../mod/message.php:392 +msgid "Delete conversation" +msgstr "ForviÅi dialogon" + +#: ../../mod/message.php:273 +msgid "D, d M Y - g:i A" +msgstr "D, d M Y - g:i A" + +#: ../../mod/message.php:275 +#, php-format +msgid "%d message" +msgid_plural "%d messages" +msgstr[0] "%d mesaÄo" +msgstr[1] "%d mesaÄoj" + +#: ../../mod/message.php:310 +msgid "Message not available." +msgstr "MesaÄo nedisponebla." + +#: ../../mod/message.php:375 +msgid "Delete message" +msgstr "ForviÅu mesaÄon" + +#: ../../mod/message.php:394 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Sekura komunikado ne disponeblas. Vi eble povus respondi sur la profilpaÄo de la sendanto." + +#: ../../mod/message.php:398 +msgid "Send Reply" +msgstr "Respondi" + +#: ../../mod/allfriends.php:34 +#, php-format +msgid "Friends of %s" +msgstr "Amikoj de %s" + +#: ../../mod/allfriends.php:40 +msgid "No friends to display." +msgstr "Neniom da amiko al montri." + +#: ../../mod/admin.php:55 +msgid "Theme settings updated." +msgstr "Gisdatigis agordojn pri etosoj." + +#: ../../mod/admin.php:96 ../../mod/admin.php:419 +msgid "Site" +msgstr "Retejo" + +#: ../../mod/admin.php:97 ../../mod/admin.php:655 ../../mod/admin.php:667 +msgid "Users" +msgstr "Uzantoj" + +#: ../../mod/admin.php:98 ../../mod/admin.php:749 ../../mod/admin.php:791 +msgid "Plugins" +msgstr "Kromprogramoj" + +#: ../../mod/admin.php:99 ../../mod/admin.php:954 ../../mod/admin.php:990 +msgid "Themes" +msgstr "Etosoj" + +#: ../../mod/admin.php:100 +msgid "DB updates" +msgstr "DB Äisdatigoj" + +#: ../../mod/admin.php:115 ../../mod/admin.php:122 ../../mod/admin.php:1077 +msgid "Logs" +msgstr "Protokoloj" + +#: ../../mod/admin.php:120 ../../include/nav.php:146 +msgid "Admin" +msgstr "Administrado" + +#: ../../mod/admin.php:121 +msgid "Plugin Features" +msgstr "Kromprogramaj Trajtoj" + +#: ../../mod/admin.php:123 +msgid "User registrations waiting for confirmation" +msgstr "Uzantaj registradoj atendante konfirmon" + +#: ../../mod/admin.php:183 ../../mod/admin.php:637 +msgid "Normal Account" +msgstr "Normala konto" + +#: ../../mod/admin.php:184 ../../mod/admin.php:638 +msgid "Soapbox Account" +msgstr "Soapbox Konto" + +#: ../../mod/admin.php:185 ../../mod/admin.php:639 +msgid "Community/Celebrity Account" +msgstr "Komunuma/eminentula Konto" + +#: ../../mod/admin.php:186 ../../mod/admin.php:640 +msgid "Automatic Friend Account" +msgstr "AÅ­tomata Amika Konto" + +#: ../../mod/admin.php:205 +msgid "Message queues" +msgstr "MesaÄvicoj" + +#: ../../mod/admin.php:210 ../../mod/admin.php:418 ../../mod/admin.php:654 +#: ../../mod/admin.php:748 ../../mod/admin.php:790 ../../mod/admin.php:953 +#: ../../mod/admin.php:989 ../../mod/admin.php:1076 +msgid "Administration" +msgstr "Administrado" + +#: ../../mod/admin.php:211 +msgid "Summary" +msgstr "Resumo" + +#: ../../mod/admin.php:213 +msgid "Registered users" +msgstr "Registrataj uzantoj" + +#: ../../mod/admin.php:215 +msgid "Pending registrations" +msgstr "Okazontaj registradoj" + +#: ../../mod/admin.php:216 +msgid "Version" +msgstr "Versio" + +#: ../../mod/admin.php:218 +msgid "Active plugins" +msgstr "Åœaltitaj kromprogramoj" + +#: ../../mod/admin.php:357 +msgid "Site settings updated." +msgstr "Äœisdatigis retejaj agordoj." + +#: ../../mod/admin.php:405 +msgid "Closed" +msgstr "Ferma" + +#: ../../mod/admin.php:406 +msgid "Requires approval" +msgstr "Bezonas aprobon" + +#: ../../mod/admin.php:407 +msgid "Open" +msgstr "Malferma" + +#: ../../mod/admin.php:411 +msgid "No SSL policy, links will track page SSL state" +msgstr "Sen SSL strategio. Ligiloj sekvos la SSL staton de la paÄo." + +#: ../../mod/admin.php:412 +msgid "Force all links to use SSL" +msgstr "Devigi ke ĉiuj ligiloj uzu SSL." + +#: ../../mod/admin.php:413 +msgid "Self-signed certificate, use SSL for local links only (discouraged)" +msgstr "Memsubskribita atestilo, nur uzu SSL por lokaj ligiloj (malkuraÄigata)" + +#: ../../mod/admin.php:422 +msgid "File upload" +msgstr "AlÅuto" + +#: ../../mod/admin.php:423 +msgid "Policies" +msgstr "Politiko" + +#: ../../mod/admin.php:424 +msgid "Advanced" +msgstr "Altnivela" + +#: ../../mod/admin.php:428 ../../addon/statusnet/statusnet.php:558 +msgid "Site name" +msgstr "Nomo de retejo" + +#: ../../mod/admin.php:429 +msgid "Banner/Logo" +msgstr "Emblemo" + +#: ../../mod/admin.php:430 +msgid "System language" +msgstr "Sistema lingvo" + +#: ../../mod/admin.php:431 +msgid "System theme" +msgstr "Sistema etoso" + +#: ../../mod/admin.php:431 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "DefaÅ­lta sistema etoso - transpasebla de uzantprofiloj - redakti agordoj pri etosoj" + +#: ../../mod/admin.php:432 +msgid "SSL link policy" +msgstr "Strategio por SSL ligiloj" + +#: ../../mod/admin.php:432 +msgid "Determines whether generated links should be forced to use SSL" +msgstr "Difinas ĉu generotaj ligiloj devige uzu SSL." + +#: ../../mod/admin.php:433 +msgid "Maximum image size" +msgstr "Maksimuma bildgrando" + +#: ../../mod/admin.php:433 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Maksimuma grando en bajtoj por alÅutotaj bildoj. DefaÅ­lte 0, kio signifas neniu limito." + +#: ../../mod/admin.php:435 +msgid "Register policy" +msgstr "Interkonsento pri registrado" + +#: ../../mod/admin.php:436 +msgid "Register text" +msgstr "Interkonsento teksto" + +#: ../../mod/admin.php:436 +msgid "Will be displayed prominently on the registration page." +msgstr "Tio estos eminente montrata en la registro paÄo." + +#: ../../mod/admin.php:437 +msgid "Accounts abandoned after x days" +msgstr "Kontoj forlasitaj post x tagoj" + +#: ../../mod/admin.php:437 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "Mi ne malÅparu energion por enketi aliajn retejojn pri forlasitaj kontoj. Entajpu 0 por ne uzi templimo." + +#: ../../mod/admin.php:438 +msgid "Allowed friend domains" +msgstr "Permesitaj amikaj domainoj" + +#: ../../mod/admin.php:438 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "Perkome disigita listo da domajnoj kiuj rajtas konstrui amikecojn kun ĉi tiu retejo. Ä´okeroj eblas. Malplena por rajtigi ĉiujn ajn domajnojn." + +#: ../../mod/admin.php:439 +msgid "Allowed email domains" +msgstr "Permesitaj retpoÅtaj domajnoj" + +#: ../../mod/admin.php:439 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "Perkome disigita listo da domajnoj kiuj uzeblas kiel retpoÅtaj adresoj en novaj registradoj. Ä´okeroj eblas. Malplena por rajtigi ĉiujn ajn domajnojn." + +#: ../../mod/admin.php:440 +msgid "Block public" +msgstr "Bloki publike" + +#: ../../mod/admin.php:440 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Elektu por bloki publikan atingon al ĉiuj alie publikajn paÄojn en ĉi tiu retejo kiam vi ne estas ensalutita." + +#: ../../mod/admin.php:441 +msgid "Force publish" +msgstr "Devigi publikigon" + +#: ../../mod/admin.php:441 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Elektu por devigi la registradon en la loka katalogo al ĉiuj profiloj en ĉi tiu retejo." + +#: ../../mod/admin.php:442 +msgid "Global directory update URL" +msgstr "Äœenerala adreso por Äisdatigi la katalogon" + +#: ../../mod/admin.php:442 +msgid "" +"URL to update the global directory. If this is not set, the global directory" +" is completely unavailable to the application." +msgstr "URL adreso por Äisdatigi la tutmondan katalogon. Se ne agordita, la tutmonda katatolge tute ne disponeblas al la programo." + +#: ../../mod/admin.php:444 +msgid "Block multiple registrations" +msgstr "Bloki pluroblajn registradojn." + +#: ../../mod/admin.php:444 +msgid "Disallow users to register additional accounts for use as pages." +msgstr "Malpermesi al uzantoj la permeson por registri pluajn kontojn kiel paÄoj." + +#: ../../mod/admin.php:445 +msgid "OpenID support" +msgstr "Subteno por OpenID" + +#: ../../mod/admin.php:445 +msgid "OpenID support for registration and logins." +msgstr "Subteni OpenID por registrado kaj ensaluto." + +#: ../../mod/admin.php:446 +msgid "Fullname check" +msgstr "Kontroli plenan nomon" + +#: ../../mod/admin.php:446 +msgid "" +"Force users to register with a space between firstname and lastname in Full " +"name, as an antispam measure" +msgstr "Kiel kontraÅ­spamilo, devigi uzantoj al registrado kun spaceto inter la persona nomo kaj la familia nomo." + +#: ../../mod/admin.php:447 +msgid "UTF-8 Regular expressions" +msgstr "UTF-8 regulaj exprimoj" + +#: ../../mod/admin.php:447 +msgid "Use PHP UTF8 regular expressions" +msgstr "Uzi PHP UTF8 regulajn esprimojn." + +#: ../../mod/admin.php:448 +msgid "Show Community Page" +msgstr "Montri Komunuma PaÄo" + +#: ../../mod/admin.php:448 +msgid "" +"Display a Community page showing all recent public postings on this site." +msgstr "Montri komunuma paÄo kun ĉiuj ĵusaj afiÅoj en ĉi tiu retejo." + +#: ../../mod/admin.php:449 +msgid "Enable OStatus support" +msgstr "Åœalti subtenon por OStatus" + +#: ../../mod/admin.php:449 +msgid "" +"Provide built-in OStatus (identi.ca, status.net, etc.) compatibility. All " +"communications in OStatus are public, so privacy warnings will be " +"occasionally displayed." +msgstr "Provizi integritan OStatus (identi.ca, status.net ktp) subtenon. Ĉiuj komunikadoj en OStatus estas publikaj, do privatecaj avertoj aperos de tempo al tempo." + +#: ../../mod/admin.php:450 +msgid "Enable Diaspora support" +msgstr "Åœalti subtenon por Diaspora" + +#: ../../mod/admin.php:450 +msgid "Provide built-in Diaspora network compatibility." +msgstr "Provizi integritan Diaspora subtenon." + +#: ../../mod/admin.php:451 +msgid "Only allow Friendica contacts" +msgstr "Nur permesigi Friendica kontaktojn" + +#: ../../mod/admin.php:451 +msgid "" +"All contacts must use Friendica protocols. All other built-in communication " +"protocols disabled." +msgstr "Ĉiuj kontaktoj devas uzi Friendica protokolojn. Ĉiuj aliaj komunikaj protokoloj malaktivita." + +#: ../../mod/admin.php:452 +msgid "Verify SSL" +msgstr "Kontroli SSL" + +#: ../../mod/admin.php:452 +msgid "" +"If you wish, you can turn on strict certificate checking. This will mean you" +" cannot connect (at all) to self-signed SSL sites." +msgstr "Se vi deziras, vi povas aktivigi severan kontroladon de SSL atestiloj. Pro tio, vie (tute) ne eblos konekti al SSL retejoj kun memsubskribitaj atestiloj." + +#: ../../mod/admin.php:453 +msgid "Proxy user" +msgstr "Uzantnomo por retperanto" + +#: ../../mod/admin.php:454 +msgid "Proxy URL" +msgstr "URL adreso de retperanto" + +#: ../../mod/admin.php:455 +msgid "Network timeout" +msgstr "Reta tempolimo" + +#: ../../mod/admin.php:455 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "Valoro en sekundoj. Uzu 0 por mallimitigi (ne rekomendata)." + +#: ../../mod/admin.php:456 +msgid "Delivery interval" +msgstr "Intervalo de liverado" + +#: ../../mod/admin.php:456 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Malfruigi fonan liveradon dum tiom da sekundoj por malpliigi la Åargon de la sistemo. Rekomendoj: 4-5 por komunaj serviloj, 2-3 por virtualaj privataj serviloj, 0-1 por grandaj dediĉitaj serviloj." + +#: ../../mod/admin.php:457 +msgid "Poll interval" +msgstr "Enketintervalo" + +#: ../../mod/admin.php:457 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Malfruigi fonajn enketprocesojn je tiom da sekundoj por malpliigi la Åargon de la sistemo. Se 0, uzas la liverintervalon." + +#: ../../mod/admin.php:458 +msgid "Maximum Load Average" +msgstr "Maksimuma Meza SistemÅargo" + +#: ../../mod/admin.php:458 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Maksimuma sistemÅargo post kiu livero- kaj enketprocesoj estos prokrastinataj. - DefaÅ­lte 50." + +#: ../../mod/admin.php:472 +msgid "Update has been marked successful" +msgstr "Äœisdatigo estas markita sukcesa" + +#: ../../mod/admin.php:482 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "Ne sukcesis plenumi %s. Kontrolu la sistemprotokolojn." + +#: ../../mod/admin.php:485 +#, php-format +msgid "Update %s was successfully applied." +msgstr "Sukcese aplikis la Äisdatigo %s." + +#: ../../mod/admin.php:489 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "Äœisdatigo %s ne liveris elirstaton. " + +#: ../../mod/admin.php:492 +#, php-format +msgid "Update function %s could not be found." +msgstr "Ne troveblas Äisdatigo funkcio %s." + +#: ../../mod/admin.php:507 +msgid "No failed updates." +msgstr "Neniom da malsukcesaj Äisdatigoj." + +#: ../../mod/admin.php:511 +msgid "Failed Updates" +msgstr "Malsukcesaj Äœisdatigoj" + +#: ../../mod/admin.php:512 +msgid "" +"This does not include updates prior to 1139, which did not return a status." +msgstr "Ne inkluzivas Äisdatigojn antaÅ­ 1139, kiuj ne liveris elirstaton." + +#: ../../mod/admin.php:513 +msgid "Mark success (if update was manually applied)" +msgstr "Marki sukcesa (se la Äisdatigo estas instalita mane)" + +#: ../../mod/admin.php:514 +msgid "Attempt to execute this update step automatically" +msgstr "Provi automate plenumi ĉi tian paÅon de la Äisdatigo." + +#: ../../mod/admin.php:539 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "Blokis/malblokis %s uzanton" +msgstr[1] "Blokis/malblokis %s uzantojn" + +#: ../../mod/admin.php:546 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s uzanto forviÅita" +msgstr[1] "%s uzanto forviÅitaj" + +#: ../../mod/admin.php:585 +#, php-format +msgid "User '%s' deleted" +msgstr "Uzanto '%s' forviÅita" + +#: ../../mod/admin.php:593 +#, php-format +msgid "User '%s' unblocked" +msgstr "Uzanto '%s' malblokita" + +#: ../../mod/admin.php:593 +#, php-format +msgid "User '%s' blocked" +msgstr "Uzanto '%s' blokita" + +#: ../../mod/admin.php:657 +msgid "select all" +msgstr "elekti ĉiujn" + +#: ../../mod/admin.php:658 +msgid "User registrations waiting for confirm" +msgstr "RegistriÄoj atendante aprobon" + +#: ../../mod/admin.php:659 +msgid "Request date" +msgstr "Dato de peto" + +#: ../../mod/admin.php:659 ../../mod/admin.php:668 +#: ../../include/contact_selectors.php:79 +msgid "Email" +msgstr "RetpoÅto" + +#: ../../mod/admin.php:660 +msgid "No registrations." +msgstr "Neniom da registriÄoj." + +#: ../../mod/admin.php:662 +msgid "Deny" +msgstr "Negi" + +#: ../../mod/admin.php:668 +msgid "Register date" +msgstr "Dato de registrado" + +#: ../../mod/admin.php:668 +msgid "Last login" +msgstr "Plej ĵusa ensaluto" + +#: ../../mod/admin.php:668 +msgid "Last item" +msgstr "Plej ĵusa elemento" + +#: ../../mod/admin.php:668 +msgid "Account" +msgstr "Konto" + +#: ../../mod/admin.php:670 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "La elektitaj uzantkontoj estas forviÅotaj!\\n\\nĈiuj elementoj kiujn ili afiÅis je la retpaÄo estos permanente forviÅitaj.\\n\\nĈu vi certas?" + +#: ../../mod/admin.php:671 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "La uzanto {0} estas forviÅota!\\n\\nĈiuj elementoj kiujn li afiÅis je la retpaÄo estos permanente forviÅitaj.\\n\\nĈu vi certas?" + +#: ../../mod/admin.php:712 +#, php-format +msgid "Plugin %s disabled." +msgstr "Kromprogramo %s estas malÅaltita." + +#: ../../mod/admin.php:716 +#, php-format +msgid "Plugin %s enabled." +msgstr "Kromprogramo %s estas Åaltita." + +#: ../../mod/admin.php:726 ../../mod/admin.php:924 +msgid "Disable" +msgstr "MalÅalti" + +#: ../../mod/admin.php:728 ../../mod/admin.php:926 +msgid "Enable" +msgstr "Åœalti" + +#: ../../mod/admin.php:750 ../../mod/admin.php:955 +msgid "Toggle" +msgstr "Åœalti/MalÅalti" + +#: ../../mod/admin.php:758 ../../mod/admin.php:965 +msgid "Author: " +msgstr "AÅ­toro: " + +#: ../../mod/admin.php:759 ../../mod/admin.php:966 +msgid "Maintainer: " +msgstr "Prizorganto: " + +#: ../../mod/admin.php:888 +msgid "No themes found." +msgstr "Ne trovis etosojn." + +#: ../../mod/admin.php:947 +msgid "Screenshot" +msgstr "Ekrankopio" + +#: ../../mod/admin.php:995 +msgid "[Experimental]" +msgstr "[Eksperimenta]" + +#: ../../mod/admin.php:996 +msgid "[Unsupported]" +msgstr "[Nesubtenata]" + +#: ../../mod/admin.php:1023 +msgid "Log settings updated." +msgstr "Protokolagordoj Äisdatigitaj." + +#: ../../mod/admin.php:1079 +msgid "Clear" +msgstr "ForviÅi" + +#: ../../mod/admin.php:1085 +msgid "Debugging" +msgstr "Sencimigado" + +#: ../../mod/admin.php:1086 +msgid "Log file" +msgstr "Protokolo" + +#: ../../mod/admin.php:1086 +msgid "" +"Must be writable by web server. Relative to your Friendica top-level " +"directory." +msgstr "Devas esti skribebla de la retservilo. Relativa al via plej supra Friendica dosierujo." + +#: ../../mod/admin.php:1087 +msgid "Log level" +msgstr "Protokolnivelo" + +#: ../../mod/admin.php:1137 +msgid "Close" +msgstr "Fermi" + +#: ../../mod/admin.php:1143 +msgid "FTP Host" +msgstr "FTP Servilo" + +#: ../../mod/admin.php:1144 +msgid "FTP Path" +msgstr "FTP Vojo" + +#: ../../mod/admin.php:1145 +msgid "FTP User" +msgstr "FTP Uzanto" + +#: ../../mod/admin.php:1146 +msgid "FTP Password" +msgstr "FTP Pasvorto" + +#: ../../mod/profile.php:21 ../../boot.php:993 +msgid "Requested profile is not available." +msgstr "La petita profilo ne disponeblas." + +#: ../../mod/profile.php:141 ../../mod/display.php:75 +msgid "Access to this profile has been restricted." +msgstr "Atingo al ĉi tio profilo estas limitigita" + +#: ../../mod/profile.php:166 +msgid "Tips for New Members" +msgstr "Konsilo por novaj membroj" + +#: ../../mod/ping.php:185 +msgid "{0} wants to be your friend" +msgstr "{0} volas amikiÄi kun vi" + +#: ../../mod/ping.php:190 +msgid "{0} sent you a message" +msgstr "{0} sendis mesaÄon al vi" + +#: ../../mod/ping.php:195 +msgid "{0} requested registration" +msgstr "{0} petis registradon" + +#: ../../mod/ping.php:201 +#, php-format +msgid "{0} commented %s's post" +msgstr "{0} komentis pri la afiÅo de %s" + +#: ../../mod/ping.php:206 +#, php-format +msgid "{0} liked %s's post" +msgstr "{0} satis la afiÅon de %s" + +#: ../../mod/ping.php:211 +#, php-format +msgid "{0} disliked %s's post" +msgstr "{0} malÅatis la afiÅon de %s" + +#: ../../mod/ping.php:216 +#, php-format +msgid "{0} is now friends with %s" +msgstr "{0} amikiÄis kun %s" + +#: ../../mod/ping.php:221 +msgid "{0} posted" +msgstr "{0} afiÅis" + +#: ../../mod/ping.php:226 +#, php-format +msgid "{0} tagged %s's post with #%s" +msgstr "{0} markis la afiÅon de %s kun #%s" + +#: ../../mod/ping.php:232 +msgid "{0} mentioned you in a post" +msgstr "{0} menciis vin en afiÅo" + +#: ../../mod/nogroup.php:58 +msgid "Contacts who are not members of a group" +msgstr "Kontaktoj kiuj ne estas en iu grupo" + +#: ../../mod/openid.php:24 +msgid "OpenID protocol error. No ID returned." +msgstr "Eraro en OpenID protokolo. Ne resendis identecon." + +#: ../../mod/openid.php:53 +msgid "" +"Account not found and OpenID registration is not permitted on this site." +msgstr "Ne trovis kontoj, kaj registrado per OpenID estas malpermesita ĉi tie." + +#: ../../mod/openid.php:93 ../../include/auth.php:99 +#: ../../include/auth.php:162 +msgid "Login failed." +msgstr "Ensalutado malsukcesis." + +#: ../../mod/follow.php:27 +msgid "Contact added" +msgstr "Aldonis kontakton" + +#: ../../mod/common.php:42 +msgid "Common Friends" +msgstr "Komunaj Amikoj" + +#: ../../mod/common.php:78 +msgid "No contacts in common." +msgstr "Neniom da komunaj kontaktoj." + +#: ../../mod/display.php:135 +msgid "Item has been removed." +msgstr "Elemento estas forviÅita." + +#: ../../mod/apps.php:4 +msgid "Applications" +msgstr "Programoj" + +#: ../../mod/apps.php:7 +msgid "No installed applications." +msgstr "Neniom da instalitaj programoj." + +#: ../../mod/search.php:83 ../../include/text.php:649 +#: ../../include/text.php:650 ../../include/nav.php:91 +msgid "Search" +msgstr "Serĉi" + +#: ../../mod/profiles.php:21 ../../mod/profiles.php:410 +#: ../../mod/profiles.php:524 ../../mod/dfrn_confirm.php:62 +msgid "Profile not found." +msgstr "Profilo ne trovita." + +#: ../../mod/profiles.php:31 +msgid "Profile Name is required." +msgstr "Nomo de profilo estas bezonata." + +#: ../../mod/profiles.php:155 +msgid "Marital Status" +msgstr "Amrilata Stato" + +#: ../../mod/profiles.php:159 +msgid "Romantic Partner" +msgstr "Kora Partnero" + +#: ../../mod/profiles.php:163 +msgid "Likes" +msgstr "Åœatoj" + +#: ../../mod/profiles.php:167 +msgid "Dislikes" +msgstr "MalÅatoj" + +#: ../../mod/profiles.php:171 +msgid "Work/Employment" +msgstr "Laboro" + +#: ../../mod/profiles.php:174 +msgid "Religion" +msgstr "Religio" + +#: ../../mod/profiles.php:178 +msgid "Political Views" +msgstr "Politikaj Opinioj" + +#: ../../mod/profiles.php:182 +msgid "Gender" +msgstr "Sekso" + +#: ../../mod/profiles.php:186 +msgid "Sexual Preference" +msgstr "Seksa Prefero" + +#: ../../mod/profiles.php:190 +msgid "Homepage" +msgstr "HejmpaÄo" + +#: ../../mod/profiles.php:194 +msgid "Interests" +msgstr "Interesoj" + +#: ../../mod/profiles.php:198 +msgid "Address" +msgstr "Adreso" + +#: ../../mod/profiles.php:205 ../../addon/dav/layout.fnk.php:310 +msgid "Location" +msgstr "Loko" + +#: ../../mod/profiles.php:288 +msgid "Profile updated." +msgstr "Profilo Äisdatigita." + +#: ../../mod/profiles.php:355 +msgid " and " +msgstr " kaj " + +#: ../../mod/profiles.php:363 +msgid "public profile" +msgstr "publika profilo" + +#: ../../mod/profiles.php:366 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s ÅanÄis %2$s al “%3$s”" + +#: ../../mod/profiles.php:367 +#, php-format +msgid " - Visit %1$s's %2$s" +msgstr " - Vizitu la %2$s de %1$s" + +#: ../../mod/profiles.php:370 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s havas Äisdatigigan %2$s, ÅanÄas %3$s." + +#: ../../mod/profiles.php:429 +msgid "Profile deleted." +msgstr "Profilo forviÅita." + +#: ../../mod/profiles.php:447 ../../mod/profiles.php:481 +msgid "Profile-" +msgstr "Profilo-" + +#: ../../mod/profiles.php:466 ../../mod/profiles.php:508 +msgid "New profile created." +msgstr "Nova profilo kreita." + +#: ../../mod/profiles.php:487 +msgid "Profile unavailable to clone." +msgstr "Ne eblas kopii profilon." + +#: ../../mod/profiles.php:545 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "KaÅi vian liston de kontaktoj/amikoj al vidantoj de ĉi-tio profilo?" + +#: ../../mod/profiles.php:568 +msgid "Edit Profile Details" +msgstr "Redakti Detalojn de Profilo" + +#: ../../mod/profiles.php:570 +msgid "View this profile" +msgstr "Vidi la profilon." + +#: ../../mod/profiles.php:571 +msgid "Create a new profile using these settings" +msgstr "Krei novan profilon kun tiaj agordoj" + +#: ../../mod/profiles.php:572 +msgid "Clone this profile" +msgstr "Kopii ĉi tiun profilon" + +#: ../../mod/profiles.php:573 +msgid "Delete this profile" +msgstr "ForviÅi ĉi tiun profilon" + +#: ../../mod/profiles.php:574 +msgid "Profile Name:" +msgstr "Nomo de Profilo:" + +#: ../../mod/profiles.php:575 +msgid "Your Full Name:" +msgstr "Via Plena Nomo:" + +#: ../../mod/profiles.php:576 +msgid "Title/Description:" +msgstr "Titolo/Priskribo:" + +#: ../../mod/profiles.php:577 +msgid "Your Gender:" +msgstr "Via Sekso:" + +#: ../../mod/profiles.php:578 +#, php-format +msgid "Birthday (%s):" +msgstr "NaskiÄtago (%s):" + +#: ../../mod/profiles.php:579 +msgid "Street Address:" +msgstr "Adreso:" + +#: ../../mod/profiles.php:580 +msgid "Locality/City:" +msgstr "Urbo:" + +#: ../../mod/profiles.php:581 +msgid "Postal/Zip Code:" +msgstr "PoÅtkodo:" + +#: ../../mod/profiles.php:582 +msgid "Country:" +msgstr "Lando:" + +#: ../../mod/profiles.php:583 +msgid "Region/State:" +msgstr "Åœtato:" + +#: ../../mod/profiles.php:584 +msgid " Marital Status:" +msgstr " Civita Stato:" + +#: ../../mod/profiles.php:585 +msgid "Who: (if applicable)" +msgstr "Kiu (se aplikeble):" + +#: ../../mod/profiles.php:586 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Ekzemploj: cathy123, Cathy Williams, cathy@example.com" + +#: ../../mod/profiles.php:587 +msgid "Since [date]:" +msgstr "Ekde [dato]:" + +#: ../../mod/profiles.php:588 ../../include/profile_advanced.php:46 +msgid "Sexual Preference:" +msgstr "Seksa Prefero:" + +#: ../../mod/profiles.php:589 +msgid "Homepage URL:" +msgstr "Adreso de HejmpaÄo:" + +#: ../../mod/profiles.php:590 ../../include/profile_advanced.php:50 +msgid "Hometown:" +msgstr "Hejmurbo:" + +#: ../../mod/profiles.php:591 ../../include/profile_advanced.php:54 +msgid "Political Views:" +msgstr "Politikaj Opinioj:" + +#: ../../mod/profiles.php:592 +msgid "Religious Views:" +msgstr "Religiaj Opinioj:" + +#: ../../mod/profiles.php:593 +msgid "Public Keywords:" +msgstr "Publikaj Ålosilvortoj:" + +#: ../../mod/profiles.php:594 +msgid "Private Keywords:" +msgstr "Privataj Ålosilvortoj:" + +#: ../../mod/profiles.php:595 ../../include/profile_advanced.php:62 +msgid "Likes:" +msgstr "Åœatoj:" + +#: ../../mod/profiles.php:596 ../../include/profile_advanced.php:64 +msgid "Dislikes:" +msgstr "MalÅatoj:" + +#: ../../mod/profiles.php:597 +msgid "Example: fishing photography software" +msgstr "Ekzemple: fiÅkapti fotografio programaro" + +#: ../../mod/profiles.php:598 +msgid "(Used for suggesting potential friends, can be seen by others)" +msgstr "(Por sugesti amikoj. Videbla al aliaj.)" + +#: ../../mod/profiles.php:599 +msgid "(Used for searching profiles, never shown to others)" +msgstr "(Por serĉi profilojn. Neniam videbla al aliaj.)" + +#: ../../mod/profiles.php:600 +msgid "Tell us about yourself..." +msgstr "Diru al ni pri vi..." + +#: ../../mod/profiles.php:601 +msgid "Hobbies/Interests" +msgstr "Åœatokupoj/Interesoj" + +#: ../../mod/profiles.php:602 +msgid "Contact information and Social Networks" +msgstr "Kontaktaj informoj kaj Interkonaj Retejoj" + +#: ../../mod/profiles.php:603 +msgid "Musical interests" +msgstr "Muzikaj interesoj" + +#: ../../mod/profiles.php:604 +msgid "Books, literature" +msgstr "Libroj, literaturo" + +#: ../../mod/profiles.php:605 +msgid "Television" +msgstr "Televido" + +#: ../../mod/profiles.php:606 +msgid "Film/dance/culture/entertainment" +msgstr "Filmoj/dancoj/arto/amuzaĵoj" + +#: ../../mod/profiles.php:607 +msgid "Love/romance" +msgstr "Amo/romanco" + +#: ../../mod/profiles.php:608 +msgid "Work/employment" +msgstr "Laboro" + +#: ../../mod/profiles.php:609 +msgid "School/education" +msgstr "Lernejo/eduko" + +#: ../../mod/profiles.php:614 +msgid "" +"This is your public profile.
    It may " +"be visible to anybody using the internet." +msgstr "Ĉi tio estas via publika profilo. Äœi eble estas videbla al ĉiuj en interreto. " + +#: ../../mod/profiles.php:624 ../../mod/directory.php:111 +msgid "Age: " +msgstr "AÄo:" + +#: ../../mod/profiles.php:663 +msgid "Edit/Manage Profiles" +msgstr "Redakti/administri Profilojn" + +#: ../../mod/profiles.php:664 ../../boot.php:1102 +msgid "Change profile photo" +msgstr "ÅœanÄi profilbildon" + +#: ../../mod/profiles.php:665 ../../boot.php:1103 +msgid "Create New Profile" +msgstr "Krei novan profilon" + +#: ../../mod/profiles.php:676 ../../boot.php:1113 +msgid "Profile Image" +msgstr "Profilbildo" + +#: ../../mod/profiles.php:678 ../../boot.php:1116 +msgid "visible to everybody" +msgstr "videbla al ĉiuj" + +#: ../../mod/profiles.php:679 ../../boot.php:1117 +msgid "Edit visibility" +msgstr "Redakti videblecon" + +#: ../../mod/filer.php:29 ../../include/conversation.php:951 +msgid "Save to Folder:" +msgstr "Konservi en Dosierujo:" + +#: ../../mod/filer.php:29 +msgid "- select -" +msgstr "- elekti -" + +#: ../../mod/tagger.php:103 ../../include/conversation.php:138 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s markis la %3$s de %2$s kun %4$s" + +#: ../../mod/delegate.php:95 +msgid "No potential page delegates located." +msgstr "Ne trovis delegiteblajn paÄojn." + +#: ../../mod/delegate.php:121 +msgid "Delegate Page Management" +msgstr "Administrado de Delegitajn PaÄojn" + +#: ../../mod/delegate.php:123 +msgid "" +"Delegates are able to manage all aspects of this account/page except for " +"basic account settings. Please do not delegate your personal account to " +"anybody that you do not trust completely." +msgstr "Delegitoj povas administri ĉiujn ecojn de la konto/paÄo, escepte bazaj kontoagordoj. Bonvolu ne delegitigi vian personan konton al iu al kiu vi ne plene fidas." + +#: ../../mod/delegate.php:124 +msgid "Existing Page Managers" +msgstr "Estantaj Administrantoj de la PaÄo" + +#: ../../mod/delegate.php:126 +msgid "Existing Page Delegates" +msgstr "Estantaj Delegitoj de la PaÄo" + +#: ../../mod/delegate.php:128 +msgid "Potential Delegates" +msgstr "Eblaj Delegitoj" + +#: ../../mod/delegate.php:131 +msgid "Add" +msgstr "Aldoni" + +#: ../../mod/delegate.php:132 +msgid "No entries." +msgstr "Neniom da afiÅoj." + +#: ../../mod/suggest.php:38 ../../view/theme/diabook/theme.php:626 +#: ../../include/contact_widgets.php:34 +msgid "Friend Suggestions" +msgstr "Amikosugestoj" + +#: ../../mod/suggest.php:44 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "Neniu sugestoj disponeblas. Se ĉi tiu estas nova retejo, bonvolu reprovi post 24 horoj." + +#: ../../mod/suggest.php:61 +msgid "Ignore/Hide" +msgstr "Ignori/KaÅi" + +#: ../../mod/directory.php:47 ../../view/theme/diabook/theme.php:624 +msgid "Global Directory" +msgstr "Tutmonda Katalogo" + +#: ../../mod/directory.php:55 +msgid "Find on this site" +msgstr "Trovi en ĉi retejo" + +#: ../../mod/directory.php:58 +msgid "Site Directory" +msgstr "Reteja Katalogo" + +#: ../../mod/directory.php:114 +msgid "Gender: " +msgstr "Sekso:" + +#: ../../mod/directory.php:140 +msgid "No entries (some entries may be hidden)." +msgstr "Neniom da afiÅoj (kelkaj afiÅoj eble ne estas videbla)." + +#: ../../mod/invite.php:35 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s: Ne estas valida retpoÅtadreso." + +#: ../../mod/invite.php:59 +msgid "Please join us on Friendica" +msgstr "Bonvolu aliÄi kun ni ĉe Friendica" + +#: ../../mod/invite.php:69 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s: La livero de la mesaÄo malsukcesis." + +#: ../../mod/invite.php:73 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "Sendis %d mesaÄon." +msgstr[1] "Sendis %d mesaÄojn." + +#: ../../mod/invite.php:92 +msgid "You have no more invitations available" +msgstr "Vi ne plu disponeblas invitaĵojn" + +#: ../../mod/invite.php:100 +#, php-format +msgid "" +"Visit %s for a list of public sites that you can join. Friendica members on " +"other sites can all connect with each other, as well as with members of many" +" other social networks." +msgstr "Vizitu %s por listo de publikaj retejoj kie vi povas aliÄi. Anoj de Friendica ĉe aliaj retejoj povas konekti unu kun la alian, kaj ankaÅ­ kun membroj de multaj aliaj retejoj." + +#: ../../mod/invite.php:102 +#, php-format +msgid "" +"To accept this invitation, please visit and register at %s or any other " +"public Friendica website." +msgstr "Por akcepti ĉi tiu invito, bonvolu viziti kaj registriÄi ĉe %s au alia publika Friendica retejo." + +#: ../../mod/invite.php:103 +#, php-format +msgid "" +"Friendica sites all inter-connect to create a huge privacy-enhanced social " +"web that is owned and controlled by its members. They can also connect with " +"many traditional social networks. See %s for a list of alternate Friendica " +"sites you can join." +msgstr "Ĉiuj Friendica retejoj interkonektiÄas kaj kune faras grandan altprivatecan interkonan reton, kiun posedas kaj kontrolas Äiaj membroj. Ili ankaÅ­ povas konekti kun multe de tradiciaj interkonaj retejoj. Vidu %s por listo de publikaj retejoj kie vi povas aliÄi." + +#: ../../mod/invite.php:106 +msgid "" +"Our apologies. This system is not currently configured to connect with other" +" public sites or invite members." +msgstr "Senkulpigu nin. La sistemo nuntempe ne estas agordita por konekti al aliaj retejoj au inviti membrojn." + +#: ../../mod/invite.php:111 +msgid "Send invitations" +msgstr "Sendi invitojn" + +#: ../../mod/invite.php:112 +msgid "Enter email addresses, one per line:" +msgstr "Entajpu retpoÅtadresojn, po unu por ĉiu linio." + +#: ../../mod/invite.php:114 +msgid "" +"You are cordially invited to join me and other close friends on Friendica - " +"and help us to create a better social web." +msgstr "Ni bonkore invitas vin aliÄi kun ni kaj aliaj bonaj amikoj ĉe Friendica. Helpu nin krei pli bonan interkonan reton." + +#: ../../mod/invite.php:116 +msgid "You will need to supply this invitation code: $invite_code" +msgstr "Vi bezonas ĉi-tiun invitkodon: $invite_code" + +#: ../../mod/invite.php:116 +msgid "" +"Once you have registered, please connect with me via my profile page at:" +msgstr "Kiam vi registris, bonvolu konekti al mi pere de mi profilo ĉe: " + +#: ../../mod/invite.php:118 +msgid "" +"For more information about the Friendica project and why we feel it is " +"important, please visit http://friendica.com" +msgstr "Por pli da informoj pri Friendica, kaj kial ni pensas ke Äi estas grava, bonvolu viziti http://friendica.com" + +#: ../../mod/dfrn_confirm.php:119 +msgid "" +"This may occasionally happen if contact was requested by both persons and it" +" has already been approved." +msgstr "Tio ĉi okazis de tempo al tempo se ambaÅ­ personoj petas kontakton ka Äi jam estas aprobita." + +#: ../../mod/dfrn_confirm.php:237 +msgid "Response from remote site was not understood." +msgstr "Ne komprenis la rispondon de la fora retejo." + +#: ../../mod/dfrn_confirm.php:246 +msgid "Unexpected response from remote site: " +msgstr "Neatendita rispondo de la fora retejo:" + +#: ../../mod/dfrn_confirm.php:254 +msgid "Confirmation completed successfully." +msgstr "Konfirmo sukcese kompletigita." + +#: ../../mod/dfrn_confirm.php:256 ../../mod/dfrn_confirm.php:270 +#: ../../mod/dfrn_confirm.php:277 +msgid "Remote site reported: " +msgstr "La fora retejo raportis:" + +#: ../../mod/dfrn_confirm.php:268 +msgid "Temporary failure. Please wait and try again." +msgstr "Dumtempa eraro. Bonvolu atendi kaj provi refoje." + +#: ../../mod/dfrn_confirm.php:275 +msgid "Introduction failed or was revoked." +msgstr "La prezento malsukcesis au estas revokita." + +#: ../../mod/dfrn_confirm.php:420 +msgid "Unable to set contact photo." +msgstr "Neeblas agordi la kontaktbildo." + +#: ../../mod/dfrn_confirm.php:477 ../../include/diaspora.php:510 +#: ../../include/conversation.php:101 +#, php-format +msgid "%1$s is now friends with %2$s" +msgstr "%1$s amikiÄis kun %2$s" + +#: ../../mod/dfrn_confirm.php:562 +#, php-format +msgid "No user record found for '%s' " +msgstr "Ne trovis uzanton '%s' " + +#: ../../mod/dfrn_confirm.php:572 +msgid "Our site encryption key is apparently messed up." +msgstr "Åœajnas kvazaÅ­ la ĉifroÅlosilo de nia retejo estas fuÅita." + +#: ../../mod/dfrn_confirm.php:583 +msgid "Empty site URL was provided or URL could not be decrypted by us." +msgstr "Malplena adreso de retejo provizita, aÅ­ ni ne povis malĉifri la adreson." + +#: ../../mod/dfrn_confirm.php:604 +msgid "Contact record was not found for you on our site." +msgstr "Kontakto ne trovita por vi en via retejo." + +#: ../../mod/dfrn_confirm.php:618 +#, php-format +msgid "Site public key not available in contact record for URL %s." +msgstr "Publika Ålosilo de retejo ne disponeblas en la kontaktrikordo por la URL adreso %s." + +#: ../../mod/dfrn_confirm.php:638 +msgid "" +"The ID provided by your system is a duplicate on our system. It should work " +"if you try again." +msgstr "La identeco provizita de via sistemo estas duoblo ĉe nia sistemo. Äœi eble funkcias se vi provas refoje." + +#: ../../mod/dfrn_confirm.php:649 +msgid "Unable to set your contact credentials on our system." +msgstr "Ne sukcesis agordi la legitimaĵojn de via kontakto ĉe nia sistemo." + +#: ../../mod/dfrn_confirm.php:716 +msgid "Unable to update your contact profile details on our system" +msgstr "Neeblas Äisdatigi viajn profildetalojn ĉe nia sistemo." + +#: ../../mod/dfrn_confirm.php:750 +#, php-format +msgid "Connection accepted at %s" +msgstr "Konekto akceptita je %s" + +#: ../../mod/dfrn_confirm.php:799 +#, php-format +msgid "%1$s has joined %2$s" +msgstr "%1$s aliÄis al %2$s" + +#: ../../addon/fromgplus/fromgplus.php:29 +msgid "Google+ Import Settings" +msgstr "Google+ Importo" + +#: ../../addon/fromgplus/fromgplus.php:32 +msgid "Enable Google+ Import" +msgstr "Aktivigi Äœoogle+ Importon" + +#: ../../addon/fromgplus/fromgplus.php:35 +msgid "Google Account ID" +msgstr "Google Konto ID" + +#: ../../addon/fromgplus/fromgplus.php:55 +msgid "Google+ Import Settings saved." +msgstr "Konservis Agordojn por Google+ Importo." + +#: ../../addon/facebook/facebook.php:521 +msgid "Facebook disabled" +msgstr "Facebook malÅaltita" + +#: ../../addon/facebook/facebook.php:526 +msgid "Updating contacts" +msgstr "Mi Äisdatigas la kontaktojn." + +#: ../../addon/facebook/facebook.php:549 +msgid "Facebook API key is missing." +msgstr "La API Ålosilo de Facebook ne estas konata ĉi tie." + +#: ../../addon/facebook/facebook.php:556 +msgid "Facebook Connect" +msgstr "Kontekto al Facebook" + +#: ../../addon/facebook/facebook.php:562 +msgid "Install Facebook connector for this account." +msgstr "Instali la Facebook konektilo por ĉi tiu konto." + +#: ../../addon/facebook/facebook.php:569 +msgid "Remove Facebook connector" +msgstr "Forigi la Facebook konektilon." + +#: ../../addon/facebook/facebook.php:574 +msgid "" +"Re-authenticate [This is necessary whenever your Facebook password is " +"changed.]" +msgstr "ReaÅ­tentiÄi [Tio estas bezonata ĉiam kiam vi ÅanÄis vian pasvorton ĉe Facebook.]" + +#: ../../addon/facebook/facebook.php:581 +msgid "Post to Facebook by default" +msgstr "Ĉiam afiÅi al Facebook." + +#: ../../addon/facebook/facebook.php:587 +msgid "" +"Facebook friend linking has been disabled on this site. The following " +"settings will have no effect." +msgstr "Ligado kun Facebook amikoj estas malaktivita ĉe tiu retejo. La sekvantaj agordoj do ne havas validecon." + +#: ../../addon/facebook/facebook.php:591 +msgid "" +"Facebook friend linking has been disabled on this site. If you disable it, " +"you will be unable to re-enable it." +msgstr "Ligado kun Facebook amikoj estas malaktivita ĉe tiu retejo. Se vi malÅaltas Äin, vi ne eblos ree Åalti Äin." + +#: ../../addon/facebook/facebook.php:594 +msgid "Link all your Facebook friends and conversations on this website" +msgstr "Alligu ĉiujn viajn Facebook amikojn kaj konversaciojn je ĉi-tiu retejo." + +#: ../../addon/facebook/facebook.php:596 +msgid "" +"Facebook conversations consist of your profile wall and your friend" +" stream." +msgstr "Facebok konversacioj konsistas el via profilmuro kaj la fluo de viaj amikoj." + +#: ../../addon/facebook/facebook.php:597 +msgid "On this website, your Facebook friend stream is only visible to you." +msgstr "Je ĉi-tiu retejo, la fluo de viaj amikoj ĉe Facebook nur videblas al vi." + +#: ../../addon/facebook/facebook.php:598 +msgid "" +"The following settings determine the privacy of your Facebook profile wall " +"on this website." +msgstr "La sekvontaj agordoj difinas la privatecon de via Facebook profilmuro je ĉi-tiu retejo." + +#: ../../addon/facebook/facebook.php:602 +msgid "" +"On this website your Facebook profile wall conversations will only be " +"visible to you" +msgstr "Je ĉi-tiu retejo, la conversacioj sur via Facebook profilmuro nur videblas al vi." + +#: ../../addon/facebook/facebook.php:607 +msgid "Do not import your Facebook profile wall conversations" +msgstr "Ne importi konversaciojn de via Facebook profilmuro" + +#: ../../addon/facebook/facebook.php:609 +msgid "" +"If you choose to link conversations and leave both of these boxes unchecked," +" your Facebook profile wall will be merged with your profile wall on this " +"website and your privacy settings on this website will be used to determine " +"who may see the conversations." +msgstr "Se vi elektas alligi conversaciojn kaj ne elektas tiujn butonojn, via Facebook profilmuro estas kunigota kun via profilmuro ĉi tie. Viaj privatecaj agordoj ĉi tie difinos kiu povas vidi la coversaciojn." + +#: ../../addon/facebook/facebook.php:614 +msgid "Comma separated applications to ignore" +msgstr "Ignorotaj programoj, disigita per komo" + +#: ../../addon/facebook/facebook.php:698 +msgid "Problems with Facebook Real-Time Updates" +msgstr "Problemoj kun Facebook Realtempaj Äœisdatigoj" + +#: ../../addon/facebook/facebook.php:726 +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../addon/facebook/facebook.php:727 +msgid "Facebook Connector Settings" +msgstr "Agordoj por la Facebook konektilo" + +#: ../../addon/facebook/facebook.php:742 +msgid "Facebook API Key" +msgstr "Facebook API Ålosilo" + +#: ../../addon/facebook/facebook.php:752 +msgid "" +"Error: it appears that you have specified the App-ID and -Secret in your " +".htconfig.php file. As long as they are specified there, they cannot be set " +"using this form.

    " +msgstr "Eraro: Åœajnas kvazaÅ­ vi agordis la App-ID kaj la sekreton en via .htconfig.php dosiero. Kiam ili estas agordita tie, vi ne povas agordi Äin en tiu ĉi formo.

    " + +#: ../../addon/facebook/facebook.php:757 +msgid "" +"Error: the given API Key seems to be incorrect (the application access token" +" could not be retrieved)." +msgstr "Eraro: La API Ålosilo aspektas malÄusta (ne eblas ricevi la programa atingoĵetono)." + +#: ../../addon/facebook/facebook.php:759 +msgid "The given API Key seems to work correctly." +msgstr "La API Ålosilo Åajne Äuste funkcias." + +#: ../../addon/facebook/facebook.php:761 +msgid "" +"The correctness of the API Key could not be detected. Somthing strange's " +"going on." +msgstr "Ne povis kontroli la Äustecon de la API Ålosilo. Ia stranga afero okazas. " + +#: ../../addon/facebook/facebook.php:764 +msgid "App-ID / API-Key" +msgstr "Programo ID / API Åœlosilo" + +#: ../../addon/facebook/facebook.php:765 +msgid "Application secret" +msgstr "Programo sekreto" + +#: ../../addon/facebook/facebook.php:766 +#, php-format +msgid "Polling Interval in minutes (minimum %1$s minutes)" +msgstr "Intervalo de enketo en minutoj (minimume %1$s minutoj)" + +#: ../../addon/facebook/facebook.php:767 +msgid "" +"Synchronize comments (no comments on Facebook are missed, at the cost of " +"increased system load)" +msgstr "Sinkronigi komentojn (vi ricevas ĉiujn komentojn de Facebook, sed la Åargo de la sistemo iom kreskas)" + +#: ../../addon/facebook/facebook.php:771 +msgid "Real-Time Updates" +msgstr "Realtempaj Äœisdatigoj" + +#: ../../addon/facebook/facebook.php:775 +msgid "Real-Time Updates are activated." +msgstr "Realtempaj Äœisdatigoj estas Åaltita" + +#: ../../addon/facebook/facebook.php:776 +msgid "Deactivate Real-Time Updates" +msgstr "MalÅalti Realtempaj Äœisdatigoj" + +#: ../../addon/facebook/facebook.php:778 +msgid "Real-Time Updates not activated." +msgstr "Realtempaj Äœisdatigoj estas malÅaltita" + +#: ../../addon/facebook/facebook.php:778 +msgid "Activate Real-Time Updates" +msgstr "Åœalti Realtempaj Äœisdatigoj" + +#: ../../addon/facebook/facebook.php:797 ../../addon/dav/layout.fnk.php:360 +msgid "The new values have been saved." +msgstr "Konservis novajn valorojn." + +#: ../../addon/facebook/facebook.php:821 +msgid "Post to Facebook" +msgstr "AfiÅi al Facebook" + +#: ../../addon/facebook/facebook.php:919 +msgid "" +"Post to Facebook cancelled because of multi-network access permission " +"conflict." +msgstr "AfiÅado al Facebook nuligita ĉar okazis konflikto en la multretpermesoj." + +#: ../../addon/facebook/facebook.php:1139 +msgid "View on Friendica" +msgstr "Vidi ĉe Friendica" + +#: ../../addon/facebook/facebook.php:1172 +msgid "Facebook post failed. Queued for retry." +msgstr "Malsukcesis afiÅi ĉe Facebook. Enigita en vico." + +#: ../../addon/facebook/facebook.php:1212 +msgid "Your Facebook connection became invalid. Please Re-authenticate." +msgstr "Via Facbook konekto iÄis nevalida. Bonvolu reaÅ­tentiÄi." + +#: ../../addon/facebook/facebook.php:1213 +msgid "Facebook connection became invalid" +msgstr "Facebook konekto iÄis nevalida." + +#: ../../addon/facebook/facebook.php:1214 +#, php-format +msgid "" +"Hi %1$s,\n" +"\n" +"The connection between your accounts on %2$s and Facebook became invalid. This usually happens after you change your Facebook-password. To enable the connection again, you have to %3$sre-authenticate the Facebook-connector%4$s." +msgstr "Saluton %1$s,\n\nla kontekto inter viaj kontoj ĉe %2$s kaj Facebook malvalidiÄis. Tio kutime okazas post kiam via Åangas vian pasvorton ĉe Facebook. Por reaktivigi la konekto, vi bezonas %3$sreaÅ­tentiÄi la Facebook konektilon%4$s." + +#: ../../addon/snautofollow/snautofollow.php:32 +msgid "StatusNet AutoFollow settings updated." +msgstr "Äœidatigis StatusNet AutoFollow agordojn." + +#: ../../addon/snautofollow/snautofollow.php:56 +msgid "StatusNet AutoFollow Settings" +msgstr "StatusNet AutoFollow agordoj" + +#: ../../addon/snautofollow/snautofollow.php:58 +msgid "Automatically follow any StatusNet followers/mentioners" +msgstr "AÅ­tomate sekvu ĉiujn StatusNet sekvantojn/menciantojn." + +#: ../../addon/privacy_image_cache/privacy_image_cache.php:184 +msgid "Lifetime of the cache (in hours)" +msgstr "VivodaÅ­ro de kaÅmemoro (horoj)" + +#: ../../addon/privacy_image_cache/privacy_image_cache.php:189 +msgid "Cache Statistics" +msgstr "Statistikoj pri kaÅmemoro" + +#: ../../addon/privacy_image_cache/privacy_image_cache.php:192 +msgid "Number of items" +msgstr "Kvanto da eroj" + +#: ../../addon/privacy_image_cache/privacy_image_cache.php:194 +msgid "Size of the cache" +msgstr "Grando de la kaÅmemoro" + +#: ../../addon/privacy_image_cache/privacy_image_cache.php:196 +msgid "Delete the whole cache" +msgstr "ForviÅi la kaÅmemoron" + +#: ../../addon/widgets/widget_like.php:58 +#, php-format +msgid "%d person likes this" +msgid_plural "%d people like this" +msgstr[0] "%d homo Åatas tiun" +msgstr[1] "%d homoj Åatas tiun" + +#: ../../addon/widgets/widget_like.php:61 +#, php-format +msgid "%d person doesn't like this" +msgid_plural "%d people don't like this" +msgstr[0] "%d homo malÅatas tiun" +msgstr[1] "%d homo malÅatas tiun" + +#: ../../addon/widgets/widget_friendheader.php:40 +msgid "Get added to this list!" +msgstr "IÄu membro de ĉi tiu listo!" + +#: ../../addon/widgets/widgets.php:56 +msgid "Generate new key" +msgstr "Generi novan ĉifroÅlosilon" + +#: ../../addon/widgets/widgets.php:59 +msgid "Widgets key" +msgstr "Åœlosilo por fenestraĵoj" + +#: ../../addon/widgets/widgets.php:61 +msgid "Widgets available" +msgstr "Disponeblaj fenestraĵoj" + +#: ../../addon/widgets/widget_friends.php:40 +msgid "Connect on Friendica!" +msgstr "Konekti ĉe Friendica!" + +#: ../../addon/yourls/yourls.php:55 +msgid "YourLS Settings" +msgstr "\"YourLS\" Agordoj" + +#: ../../addon/yourls/yourls.php:57 +msgid "URL: http://" +msgstr "URL adreso: http://" + +#: ../../addon/yourls/yourls.php:62 +msgid "Username:" +msgstr "Salutnomo:" + +#: ../../addon/yourls/yourls.php:67 +msgid "Password:" +msgstr "Pasvorto:" + +#: ../../addon/yourls/yourls.php:72 +msgid "Use SSL " +msgstr "Uzi SSL " + +#: ../../addon/yourls/yourls.php:92 +msgid "yourls Settings saved." +msgstr "Konservis la agordojn de YourLS." + +#: ../../addon/ljpost/ljpost.php:39 +msgid "Post to LiveJournal" +msgstr "AfiÅi ĉe LiveJournal" + +#: ../../addon/ljpost/ljpost.php:70 +msgid "LiveJournal Post Settings" +msgstr "Agordoj pri afiÅoj ĉe LiveJournal" + +#: ../../addon/ljpost/ljpost.php:72 +msgid "Enable LiveJournal Post Plugin" +msgstr "Åœalti la LiveJournal-afiÅo kromprogramon." + +#: ../../addon/ljpost/ljpost.php:77 +msgid "LiveJournal username" +msgstr "LiveJournal Salutnomo" + +#: ../../addon/ljpost/ljpost.php:82 +msgid "LiveJournal password" +msgstr "LiveJournal pasvorto" + +#: ../../addon/ljpost/ljpost.php:87 +msgid "Post to LiveJournal by default" +msgstr "DefaÅ­lte afiÅi al LiveJournal" + +#: ../../addon/nsfw/nsfw.php:47 +msgid "Not Safe For Work (General Purpose Content Filter) settings" +msgstr "Not Safe For Work (Äenerala filtrilo por enhavoj) agordoj" + +#: ../../addon/nsfw/nsfw.php:49 +msgid "" +"This plugin looks in posts for the words/text you specify below, and " +"collapses any content containing those keywords so it is not displayed at " +"inappropriate times, such as sexual innuendo that may be improper in a work " +"setting. It is polite and recommended to tag any content containing nudity " +"with #NSFW. This filter can also match any other word/text you specify, and" +" can thereby be used as a general purpose content filter." +msgstr "Tiu kromprogramo serĉas la malsupre agordatajn vortojn en afiÅoj kaj malvidebligis ilin se ili enhavas iun vorton. Tiel, afiÅoj ne montriÄis kiuj enhavas maladekvatan enhavon, ekzemple seksumaj aferoj, kiuj ne estas adekvata, ekzemple en la laborejo. En la reto, oni kutime markas tiajn afiÅojn #NSFW - Not Safe For Work - ne adekvata por la laborejo. La filtrilo ankaÅ­ serĉas ĉiujn vortojn kiujn vi agordas kaj tial funkcias kiel Äenerala filtrilo." + +#: ../../addon/nsfw/nsfw.php:50 +msgid "Enable Content filter" +msgstr "Åœalti la filtrilo por la enhavo" + +#: ../../addon/nsfw/nsfw.php:53 +msgid "Comma separated list of keywords to hide" +msgstr "Perkome disigita listo da kaÅontaj Ålosilvortoj" + +#: ../../addon/nsfw/nsfw.php:58 +msgid "Use /expression/ to provide regular expressions" +msgstr "Uzu /expr/ por provizi regulajn esprimojn." + +#: ../../addon/nsfw/nsfw.php:74 +msgid "NSFW Settings saved." +msgstr "NSFW agordoj konservitaj." + +#: ../../addon/nsfw/nsfw.php:121 +#, php-format +msgid "%s - Click to open/close" +msgstr "%s - Klaku por malfermi/fermi" + +#: ../../addon/page/page.php:61 ../../addon/page/page.php:91 +msgid "Forums" +msgstr "Forumoj" + +#: ../../addon/page/page.php:76 ../../addon/page/page.php:110 +#: ../../addon/showmore/showmore.php:87 ../../include/contact_widgets.php:188 +#: ../../include/conversation.php:476 ../../boot.php:529 +msgid "show more" +msgstr "montri pli" + +#: ../../addon/page/page.php:129 +msgid "Forums:" +msgstr "Forumoj:" + +#: ../../addon/page/page.php:163 +msgid "Page settings updated." +msgstr "PaÄajn agordojn Äisdatigita." + +#: ../../addon/page/page.php:192 +msgid "Page Settings" +msgstr "PaÄaj Agordoj" + +#: ../../addon/page/page.php:194 +msgid "How many forums to display on sidebar without paging" +msgstr "Montri tiom da forumoj en la flanka strio sen paÄigo" + +#: ../../addon/page/page.php:197 +msgid "Randomise Page/Forum list" +msgstr "Hazardigi la liston de PaÄoj/Forumoj" + +#: ../../addon/page/page.php:200 +msgid "Show pages/forums on profile page" +msgstr "Montri paÄojn/forumojn sur la profilpaÄo" + +#: ../../addon/planets/planets.php:150 +msgid "Planets Settings" +msgstr "Agordo pri Planets" + +#: ../../addon/planets/planets.php:152 +msgid "Enable Planets Plugin" +msgstr "Åœalti la Planets kromprogamon" + +#: ../../addon/communityhome/communityhome.php:28 +#: ../../addon/communityhome/communityhome.php:34 +#: ../../addon/communityhome/twillingham/communityhome.php:28 +#: ../../addon/communityhome/twillingham/communityhome.php:34 +#: ../../include/nav.php:64 ../../boot.php:849 +msgid "Login" +msgstr "Ensaluti" + +#: ../../addon/communityhome/communityhome.php:29 +#: ../../addon/communityhome/twillingham/communityhome.php:29 +msgid "OpenID" +msgstr "OpenID" + +#: ../../addon/communityhome/communityhome.php:38 +#: ../../addon/communityhome/twillingham/communityhome.php:38 +msgid "Latest users" +msgstr "Ä´usaj uzantoj" + +#: ../../addon/communityhome/communityhome.php:81 +#: ../../addon/communityhome/twillingham/communityhome.php:81 +msgid "Most active users" +msgstr "Plej aktivaj uzantoj" + +#: ../../addon/communityhome/communityhome.php:98 +msgid "Latest photos" +msgstr "Ä´usaj bildoj" + +#: ../../addon/communityhome/communityhome.php:133 +msgid "Latest likes" +msgstr "Ä´usaj Åatitaĵoj" + +#: ../../addon/communityhome/communityhome.php:155 +#: ../../view/theme/diabook/theme.php:562 ../../include/text.php:1315 +#: ../../include/conversation.php:45 ../../include/conversation.php:118 +msgid "event" +msgstr "okazo" + +#: ../../addon/dav/common/wdcal_configuration.php:126 +msgid "U.S. Time Format (mm/dd/YYYY)" +msgstr "Usona datformato (mm/dd/YYYY)" + +#: ../../addon/dav/common/wdcal_configuration.php:205 +msgid "German Time Format (dd.mm.YYYY)" +msgstr "Germana datformato (dd.mm.YYYY)" + +#: ../../addon/dav/common/calendar.fnk.php:517 +#: ../../addon/dav/common/calendar.fnk.php:533 +#: ../../addon/dav/layout.fnk.php:200 +msgid "Error" +msgstr "Eraro" + +#: ../../addon/dav/common/calendar.fnk.php:568 +#: ../../addon/dav/common/calendar.fnk.php:637 +#: ../../addon/dav/common/calendar.fnk.php:664 +#: ../../addon/dav/layout.fnk.php:231 +msgid "No access" +msgstr "No access" + +#: ../../addon/dav/layout.fnk.php:119 +msgid "New event" +msgstr "Nova okazo" + +#: ../../addon/dav/layout.fnk.php:123 +msgid "Today" +msgstr "HodiaÅ­" + +#: ../../addon/dav/layout.fnk.php:132 +msgid "Day" +msgstr "Tago" + +#: ../../addon/dav/layout.fnk.php:139 +msgid "Week" +msgstr "Semajno" + +#: ../../addon/dav/layout.fnk.php:146 +msgid "Month" +msgstr "Monato" + +#: ../../addon/dav/layout.fnk.php:151 +msgid "Reload" +msgstr "ReÅargi" + +#: ../../addon/dav/layout.fnk.php:162 +msgid "Date" +msgstr "Dato" + +#: ../../addon/dav/layout.fnk.php:224 +msgid "Not found" +msgstr "Ne trovita" + +#: ../../addon/dav/layout.fnk.php:292 ../../addon/dav/layout.fnk.php:365 +msgid "Go back to the calendar" +msgstr "Iri reen al la kalendaro" + +#: ../../addon/dav/layout.fnk.php:300 +msgid "Starts" +msgstr "Komencas" + +#: ../../addon/dav/layout.fnk.php:305 +msgid "Ends" +msgstr "Finas" + +#: ../../addon/dav/layout.fnk.php:312 +msgid "Description" +msgstr "Priskribo" + +#: ../../addon/dav/layout.fnk.php:315 +msgid "Notification" +msgstr "Atentigo" + +#: ../../addon/dav/layout.fnk.php:324 +msgid "Minutes" +msgstr "Minutoj" + +#: ../../addon/dav/layout.fnk.php:327 +msgid "Hours" +msgstr "Horoj" + +#: ../../addon/dav/layout.fnk.php:330 +msgid "Days" +msgstr "Tagoj" + +#: ../../addon/dav/layout.fnk.php:331 +msgid "before" +msgstr "antaÅ­" + +#: ../../addon/dav/layout.fnk.php:367 +msgid "Calendar Settings" +msgstr "Kalendaraj Agordoj" + +#: ../../addon/dav/layout.fnk.php:373 +msgid "Date format" +msgstr "Datformato" + +#: ../../addon/dav/layout.fnk.php:382 +msgid "Time zone" +msgstr "Horzono" + +#: ../../addon/dav/layout.fnk.php:387 +msgid "Limitations" +msgstr "Limigoj" + +#: ../../addon/dav/layout.fnk.php:391 +msgid "Warning" +msgstr "Averto" + +#: ../../addon/dav/layout.fnk.php:395 +msgid "Synchronization (iPhone, Thunderbird Lightning, Android, ...)" +msgstr "Sinkronigo (iPhone, Thunderbird Lightning, Android, ...)" + +#: ../../addon/dav/layout.fnk.php:402 +msgid "Synchronizing this calendar with the iPhone" +msgstr "Sinkronigi tiun kalendaron kun la iPhone" + +#: ../../addon/dav/layout.fnk.php:413 +msgid "Synchronizing your Friendica-Contacts with the iPhone" +msgstr "Sinkronigi viajn Friendica kontaktojn kun la iPhone" + +#: ../../addon/dav/dav_carddav_backend_friendica_community.inc.php:37 +msgid "Friendica-Contacts" +msgstr "Friendica Kontaktoj" + +#: ../../addon/dav/dav_carddav_backend_friendica_community.inc.php:38 +msgid "Your Friendica-Contacts" +msgstr "Viaj Friendica Kontaktoj" + +#: ../../addon/dav/main.php:244 +msgid "Calendar" +msgstr "Kalendaro" + +#: ../../addon/dav/main.php:247 +msgid "Extended calendar with CalDAV-support" +msgstr "Etendita kalendaro kun CalDAV subteno" + +#: ../../addon/dav/main.php:263 +msgid "The database tables have been installed." +msgstr "La tabeloj estas instalita en la datumbazo" + +#: ../../addon/dav/main.php:264 +msgid "An error occurred during the installation." +msgstr "Eraro okazis dum instalado" + +#: ../../addon/dav/main.php:280 +msgid "No system-wide settings yet." +msgstr "AnkoraÅ­ ne disponablas tutsistemaj agordoj" + +#: ../../addon/dav/main.php:283 +msgid "Database status" +msgstr "Stato de datumbazo" + +#: ../../addon/dav/main.php:286 +msgid "Installed" +msgstr "Instalita" + +#: ../../addon/dav/main.php:289 +msgid "Upgrade needed" +msgstr "Äœisdatigo bezonata" + +#: ../../addon/dav/main.php:289 +msgid "Upgrade" +msgstr "Äœisdatigo" + +#: ../../addon/dav/main.php:292 +msgid "Not installed" +msgstr "Ne instalita" + +#: ../../addon/dav/main.php:292 +msgid "Install" +msgstr "Instali" + +#: ../../addon/dav/main.php:297 +msgid "Troubleshooting" +msgstr "Problemsolvado" + +#: ../../addon/dav/main.php:298 +msgid "Manual creation of the database tables:" +msgstr "Mana kreado de tabeloj en la datumbazo:" + +#: ../../addon/dav/main.php:299 +msgid "Show SQL-statements" +msgstr "Montru SQL ordonojn" + +#: ../../addon/dav/calendar.friendica.fnk.php:151 +msgid "Private Calendar" +msgstr "Privata kalendaro" + +#: ../../addon/dav/calendar.friendica.fnk.php:158 +msgid "Friendica Events: Mine" +msgstr "Friendica Okazoj: Miaj" + +#: ../../addon/dav/calendar.friendica.fnk.php:161 +msgid "Friendica Events: Contacts" +msgstr "Friendica Okazoj: De Kontaktoj" + +#: ../../addon/uhremotestorage/uhremotestorage.php:84 +#, php-format +msgid "" +"Allow to use your friendica id (%s) to connecto to external unhosted-enabled" +" storage (like ownCloud). See RemoteStorage" +" WebFinger" +msgstr "Permesi vian identecon ĉe Friendica (%s) por konekti al eksteraj konservejoj subtenata de unhosted (ekz. OwnCloud). Vidu RemoteStorage WebFinger" + +#: ../../addon/uhremotestorage/uhremotestorage.php:85 +msgid "Template URL (with {category})" +msgstr "URL adreso de Åablono (kun {category})" + +#: ../../addon/uhremotestorage/uhremotestorage.php:86 +msgid "OAuth end-point" +msgstr "OAuth finpunkto" + +#: ../../addon/uhremotestorage/uhremotestorage.php:87 +msgid "Api" +msgstr "Api" + +#: ../../addon/membersince/membersince.php:18 +msgid "Member since:" +msgstr "Membro ekde:" + +#: ../../addon/tictac/tictac.php:20 +msgid "Three Dimensional Tic-Tac-Toe" +msgstr "Tri-dimensia Tiktakto" + +#: ../../addon/tictac/tictac.php:53 +msgid "3D Tic-Tac-Toe" +msgstr "3D Tiktakto" + +#: ../../addon/tictac/tictac.php:58 +msgid "New game" +msgstr "Nova ludo" + +#: ../../addon/tictac/tictac.php:59 +msgid "New game with handicap" +msgstr "Nova ludo kun handikapo" + +#: ../../addon/tictac/tictac.php:60 +msgid "" +"Three dimensional tic-tac-toe is just like the traditional game except that " +"it is played on multiple levels simultaneously. " +msgstr "Tri-dimensia tiktakto similas la tradician ludon, sed estas ludata sur pluraj ebenoj dum la sama tempo." + +#: ../../addon/tictac/tictac.php:61 +msgid "" +"In this case there are three levels. You win by getting three in a row on " +"any level, as well as up, down, and diagonally across the different levels." +msgstr "Ĉi-kaze ekzistas tri ebenoj. Vi venkas vicigante tri signojn en una vico, en la sama ebeno, same kiel supren, malsupren aÅ­ diagonale, trans la ebenoj." + +#: ../../addon/tictac/tictac.php:63 +msgid "" +"The handicap game disables the center position on the middle level because " +"the player claiming this square often has an unfair advantage." +msgstr "La ludo kun handikapo malvalidigas la mezan pozicion sur la meza ebeno, ĉar la ludisto kio okupas ĉi tiun pozicion ĉiam havas avantaÄon." + +#: ../../addon/tictac/tictac.php:182 +msgid "You go first..." +msgstr "Estas via vico unue." + +#: ../../addon/tictac/tictac.php:187 +msgid "I'm going first this time..." +msgstr "Ĉi-tempe, unue estas mia vico." + +#: ../../addon/tictac/tictac.php:193 +msgid "You won!" +msgstr "Vi venkis!" + +#: ../../addon/tictac/tictac.php:199 ../../addon/tictac/tictac.php:224 +msgid "\"Cat\" game!" +msgstr "Sendecida ludo!" + +#: ../../addon/tictac/tictac.php:222 +msgid "I won!" +msgstr "Mi venkis!" + +#: ../../addon/randplace/randplace.php:169 +msgid "Randplace Settings" +msgstr "Randplace agordoj." + +#: ../../addon/randplace/randplace.php:171 +msgid "Enable Randplace Plugin" +msgstr "Aktivigi la Randplace kromprogramon." + +#: ../../addon/dwpost/dwpost.php:39 +msgid "Post to Dreamwidth" +msgstr "AfiÅi al Dreamwidth" + +#: ../../addon/dwpost/dwpost.php:70 +msgid "Dreamwidth Post Settings" +msgstr "Agordoj por AfiÅoj al Dreamwidth" + +#: ../../addon/dwpost/dwpost.php:72 +msgid "Enable dreamwidth Post Plugin" +msgstr "Åœalti la Dreamwidth Kromprogramon" + +#: ../../addon/dwpost/dwpost.php:77 +msgid "dreamwidth username" +msgstr "Dreamwidth salutnomo" + +#: ../../addon/dwpost/dwpost.php:82 +msgid "dreamwidth password" +msgstr "Dreamwidth pasvorto" + +#: ../../addon/dwpost/dwpost.php:87 +msgid "Post to dreamwidth by default" +msgstr "DefaÅ­lte afiÅi al Dreamwidth" + +#: ../../addon/drpost/drpost.php:35 +msgid "Post to Drupal" +msgstr "AfiÅi al Drupal" + +#: ../../addon/drpost/drpost.php:72 +msgid "Drupal Post Settings" +msgstr "Agordoj por Drupal AfiÅoj" + +#: ../../addon/drpost/drpost.php:74 +msgid "Enable Drupal Post Plugin" +msgstr "Åœalti la Drupal-afiÅo Kromprogramon" + +#: ../../addon/drpost/drpost.php:79 +msgid "Drupal username" +msgstr "Drupal salutnomo" + +#: ../../addon/drpost/drpost.php:84 +msgid "Drupal password" +msgstr "Drupal pasvorto" + +#: ../../addon/drpost/drpost.php:89 +msgid "Post Type - article,page,or blog" +msgstr "Tipo de AfiÅoj - article, page, aÅ­ blog" + +#: ../../addon/drpost/drpost.php:94 +msgid "Drupal site URL" +msgstr "URL adreso de Drupal retejo" + +#: ../../addon/drpost/drpost.php:99 +msgid "Drupal site uses clean URLS" +msgstr "Drupal retejo uzas purajn URL adresojn" + +#: ../../addon/drpost/drpost.php:104 +msgid "Post to Drupal by default" +msgstr "DefaÅ­lte afiÅi ĉe Drupal" + +#: ../../addon/drpost/drpost.php:184 ../../addon/wppost/wppost.php:201 +#: ../../addon/blogger/blogger.php:172 ../../addon/posterous/posterous.php:189 +msgid "Post from Friendica" +msgstr "AfiÅo de Friendica" + +#: ../../addon/startpage/startpage.php:83 +msgid "Startpage Settings" +msgstr "StartpaÄaj Agordoj" + +#: ../../addon/startpage/startpage.php:85 +msgid "Home page to load after login - leave blank for profile wall" +msgstr "HejmpaÄo Åargonta post la ensaluto - Lasu malplena por profilmuro." + +#: ../../addon/startpage/startpage.php:88 +msgid "Examples: "network" or "notifications/system"" +msgstr "Ekzemple: "network" aÅ­ "notifications/system"" + +#: ../../addon/geonames/geonames.php:143 +msgid "Geonames settings updated." +msgstr "Äœidatigis la Geonames agordojn." + +#: ../../addon/geonames/geonames.php:179 +msgid "Geonames Settings" +msgstr "Geonames Agordoj" + +#: ../../addon/geonames/geonames.php:181 +msgid "Enable Geonames Plugin" +msgstr "Åœalti la Geonames Kromprogramon" + +#: ../../addon/public_server/public_server.php:126 +#: ../../addon/testdrive/testdrive.php:94 +#, php-format +msgid "Your account on %s will expire in a few days." +msgstr "Via konto ĉe %s senvalidiÄos post kelkaj tagoj." + +#: ../../addon/public_server/public_server.php:127 +msgid "Your Friendica account is about to expire." +msgstr "Via konto ĉe Friendica baldaÅ­ senvalidiÄos." + +#: ../../addon/public_server/public_server.php:128 +#, php-format +msgid "" +"Hi %1$s,\n" +"\n" +"Your account on %2$s will expire in less than five days. You may keep your account by logging in at least once every 30 days" +msgstr "Saluton %1$s,\n\nVia konto ĉe %2$s senvalidiÄos post malpli ol kvin tagoj. Vi povas konservi vian konton se vi ensalutas almenaÅ­ ĉiujn 30 tagojn. " + +#: ../../addon/js_upload/js_upload.php:43 +msgid "Upload a file" +msgstr "AlÅuti dosieron" + +#: ../../addon/js_upload/js_upload.php:44 +msgid "Drop files here to upload" +msgstr "Åœovmeti dosierojn ĉi tie por alÅuti ilin." + +#: ../../addon/js_upload/js_upload.php:46 +msgid "Failed" +msgstr "Malsukcesi" + +#: ../../addon/js_upload/js_upload.php:297 +msgid "No files were uploaded." +msgstr "Neniom da dosieroj alÅutita." + +#: ../../addon/js_upload/js_upload.php:303 +msgid "Uploaded file is empty" +msgstr "AlÅutita dosiero estas malplena." + +#: ../../addon/js_upload/js_upload.php:326 +msgid "File has an invalid extension, it should be one of " +msgstr "Dosiero havas nevalidan sufikson. Äœi estu unu de " + +#: ../../addon/js_upload/js_upload.php:337 +msgid "Upload was cancelled, or server error encountered" +msgstr "AlÅutado estas nuligita aÅ­ okazis eraro sur la servilo" + +#: ../../addon/oembed.old/oembed.php:30 +msgid "OEmbed settings updated" +msgstr "Äœisdatigis OEmbed agordojn" + +#: ../../addon/oembed.old/oembed.php:43 +msgid "Use OEmbed for YouTube videos" +msgstr "Uzi OEmbed por YouTube videtoj" + +#: ../../addon/oembed.old/oembed.php:71 +msgid "URL to embed:" +msgstr "Enigi la URL adreson:" + +#: ../../addon/impressum/impressum.php:36 +msgid "Impressum" +msgstr "Kolofono" + +#: ../../addon/impressum/impressum.php:49 +#: ../../addon/impressum/impressum.php:51 +#: ../../addon/impressum/impressum.php:83 +msgid "Site Owner" +msgstr "Proprietulo de la paÄo" + +#: ../../addon/impressum/impressum.php:49 +#: ../../addon/impressum/impressum.php:87 +msgid "Email Address" +msgstr "RetpoÅta Adreso" + +#: ../../addon/impressum/impressum.php:54 +#: ../../addon/impressum/impressum.php:85 +msgid "Postal Address" +msgstr "PoÅta Adreso" + +#: ../../addon/impressum/impressum.php:60 +msgid "" +"The impressum addon needs to be configured!
    Please add at least the " +"owner variable to your config file. For other variables please " +"refer to the README file of the addon." +msgstr "La kolofono (impressum) kromprogramo bezonas agordojn!
    Bonvolu aldoni minimume la owner variablon al via agorda dosiero. Por aliaj variabloj, bonvolu legi la README dosieron de la kromprogramo." + +#: ../../addon/impressum/impressum.php:83 +msgid "The page operators name." +msgstr "La nomo de la funkciigisto de la retejo." + +#: ../../addon/impressum/impressum.php:84 +msgid "Site Owners Profile" +msgstr "Profilo de la Proprietulo de la Retejo" + +#: ../../addon/impressum/impressum.php:84 +msgid "Profile address of the operator." +msgstr "La profilo de la funkciigisto de la retejo." + +#: ../../addon/impressum/impressum.php:85 +msgid "How to contact the operator via snail mail. You can use BBCode here." +msgstr "Kiel poÅte kontakti la funkciigisto de la retejo. Vi eblas uzi BBCode ĉi tie." + +#: ../../addon/impressum/impressum.php:86 +msgid "Notes" +msgstr "Notoj" + +#: ../../addon/impressum/impressum.php:86 +msgid "" +"Additional notes that are displayed beneath the contact information. You can" +" use BBCode here." +msgstr "Pli da notoj kiuj aperas sub la kontaktinformoj. Vi eblas uzi BBCode ĉi tie." + +#: ../../addon/impressum/impressum.php:87 +msgid "How to contact the operator via email. (will be displayed obfuscated)" +msgstr "Kiel kontakti la funkciigiston de la retejo per retpoÅto. (montriÄos vuale) " + +#: ../../addon/impressum/impressum.php:88 +msgid "Footer note" +msgstr "PaÄpiednoto" + +#: ../../addon/impressum/impressum.php:88 +msgid "Text for the footer. You can use BBCode here." +msgstr "Teksto por la paÄpiedo. Vie eblas uzi BBCode ĉi tie." + +#: ../../addon/buglink/buglink.php:15 +msgid "Report Bug" +msgstr "Skribi cimraporton" + +#: ../../addon/notimeline/notimeline.php:32 +msgid "No Timeline settings updated." +msgstr "No Timeline agordojn Äisdatigita." + +#: ../../addon/notimeline/notimeline.php:56 +msgid "No Timeline Settings" +msgstr "No Timeline Agordoj" + +#: ../../addon/notimeline/notimeline.php:58 +msgid "Disable Archive selector on profile wall" +msgstr "Malaktivigi la Arkivo elektilo sur la profilmuro" + +#: ../../addon/blockem/blockem.php:51 +msgid "\"Blockem\" Settings" +msgstr "\"Blockem\" Agordoj" + +#: ../../addon/blockem/blockem.php:53 +msgid "Comma separated profile URLS to block" +msgstr "Blokotaj URL adresoj, disigita per komo" + +#: ../../addon/blockem/blockem.php:70 +msgid "BLOCKEM Settings saved." +msgstr "Konservis Agordojn de BLOCKEM." + +#: ../../addon/blockem/blockem.php:105 +#, php-format +msgid "Blocked %s - Click to open/close" +msgstr "%s blokita - Klaku por malfermi/fermi" + +#: ../../addon/blockem/blockem.php:160 +msgid "Unblock Author" +msgstr "Malbloki AÅ­toron" + +#: ../../addon/blockem/blockem.php:162 +msgid "Block Author" +msgstr "Bloki AÅ­toron" + +#: ../../addon/blockem/blockem.php:194 +msgid "blockem settings updated" +msgstr "Äœisdatigis la blockem agordojn" + +#: ../../addon/qcomment/qcomment.php:51 +msgid ":-)" +msgstr ":-)" + +#: ../../addon/qcomment/qcomment.php:51 +msgid ":-(" +msgstr ":-(" + +#: ../../addon/qcomment/qcomment.php:51 +msgid "lol" +msgstr "lol" + +#: ../../addon/qcomment/qcomment.php:54 +msgid "Quick Comment Settings" +msgstr "Agordoj pri Rapidaj Komentoj" + +#: ../../addon/qcomment/qcomment.php:56 +msgid "" +"Quick comments are found near comment boxes, sometimes hidden. Click them to" +" provide simple replies." +msgstr "Rapidaj komentoj troviÄas apud komentkampoj, kelkfoje kaÅita. Klaku ilin por provizi simplajn rispondojn." + +#: ../../addon/qcomment/qcomment.php:57 +msgid "Enter quick comments, one per line" +msgstr "Entajpu rapidaj komentoj, po unu je linio." + +#: ../../addon/qcomment/qcomment.php:75 +msgid "Quick Comment settings saved." +msgstr "Konservis agordojn pri rapidaj komentoj." + +#: ../../addon/openstreetmap/openstreetmap.php:71 +msgid "Tile Server URL" +msgstr "Adreso de Kahelservilo" + +#: ../../addon/openstreetmap/openstreetmap.php:71 +msgid "" +"A list of public tile servers" +msgstr "Listo de publikaj kahelserviloj" + +#: ../../addon/openstreetmap/openstreetmap.php:72 +msgid "Default zoom" +msgstr "DefaÅ­lta zoma faktoro" + +#: ../../addon/openstreetmap/openstreetmap.php:72 +msgid "The default zoom level. (1:world, 18:highest)" +msgstr "La defaÅ­lta zoma faktoro. (1:tutmonda, 18:plej proksima)" + +#: ../../addon/libertree/libertree.php:36 +msgid "Post to libertree" +msgstr "AfiÅi al libertree" + +#: ../../addon/libertree/libertree.php:67 +msgid "libertree Post Settings" +msgstr "Agordoj por AfiÅoj ĉe libertree" + +#: ../../addon/libertree/libertree.php:69 +msgid "Enable Libertree Post Plugin" +msgstr "Aktivigi Kromprogramon por AfiÅoj ĉe libertree" + +#: ../../addon/libertree/libertree.php:74 +msgid "Libertree API token" +msgstr "Libertree API ĵetono" + +#: ../../addon/libertree/libertree.php:79 +msgid "Libertree site URL" +msgstr "URL adreso de libertree retejo:" + +#: ../../addon/libertree/libertree.php:84 +msgid "Post to Libertree by default" +msgstr "DefaÅ­lte afiÅi ĉe Libertree" + +#: ../../addon/mathjax/mathjax.php:37 +msgid "" +"The MathJax addon renders mathematical formulae written using the LaTeX " +"syntax surrounded by the usual $$ or an eqnarray block in the postings of " +"your wall,network tab and private mail." +msgstr "La Mathjax kromprogramo bildigas matematikajn formulojn skribitajn en la LaTeX sintakso, cirkaÅ­igita de la komuna $$ aÅ­ eqnarray bloko en afiÅoj ĉe via muro, Reto folio kaj privataj mesaÄoj." + +#: ../../addon/mathjax/mathjax.php:38 +msgid "Use the MathJax renderer" +msgstr "Ĉu uzi la Mathjax bildigilo" + +#: ../../addon/mathjax/mathjax.php:74 +msgid "MathJax Base URL" +msgstr "Mathjax Baza URL Adreso" + +#: ../../addon/mathjax/mathjax.php:74 +msgid "" +"The URL for the javascript file that should be included to use MathJax. Can " +"be either the MathJax CDN or another installation of MathJax." +msgstr "La URL adreso por la javascript dosiero kiu estas inkluzivigonta por uzi Mathjaz. Eblas esti aÅ­ la Mathjax CDN aÅ­ alia Mathjax instalo." + +#: ../../addon/editplain/editplain.php:46 +msgid "Editplain settings updated." +msgstr "Äœisdatigis la Editplain agordojn." + +#: ../../addon/editplain/editplain.php:76 +msgid "Editplain Settings" +msgstr "Agordoj por Editplain" + +#: ../../addon/editplain/editplain.php:78 +msgid "Disable richtext status editor" +msgstr "MalÅalti la riĉteksto-redaktilon" + +#: ../../addon/gravatar/gravatar.php:71 +msgid "generic profile image" +msgstr "komuna profilbildo" + +#: ../../addon/gravatar/gravatar.php:72 +msgid "random geometric pattern" +msgstr "loteca geometria skemo" + +#: ../../addon/gravatar/gravatar.php:73 +msgid "monster face" +msgstr "monstrobildo" + +#: ../../addon/gravatar/gravatar.php:74 +msgid "computer generated face" +msgstr "komputita vizaÄo" + +#: ../../addon/gravatar/gravatar.php:75 +msgid "retro arcade style face" +msgstr "retrostila videoludstila vizaÄo" + +#: ../../addon/gravatar/gravatar.php:87 +msgid "Default avatar image" +msgstr "DefaÅ­lta avatarbildo" + +#: ../../addon/gravatar/gravatar.php:87 +msgid "Select default avatar image if none was found at Gravatar. See README" +msgstr "Elektu defaÅ­ltan avatarbildon se neniu troviÄis ĉe Gravatar. Vidu README." + +#: ../../addon/gravatar/gravatar.php:88 +msgid "Rating of images" +msgstr "Pritakso de bildoj" + +#: ../../addon/gravatar/gravatar.php:88 +msgid "Select the appropriate avatar rating for your site. See README" +msgstr "Elektu la Äustan pritakson de via avataro por via retejo. Vidu README." + +#: ../../addon/gravatar/gravatar.php:102 +msgid "Gravatar settings updated." +msgstr "Gravatar agordoj Äisdatigitaj." + +#: ../../addon/testdrive/testdrive.php:95 +msgid "Your Friendica test account is about to expire." +msgstr "Via Friendica provkonto baldaÅ­ malaktiviÄos." + +#: ../../addon/testdrive/testdrive.php:96 +#, php-format +msgid "" +"Hi %1$s,\n" +"\n" +"Your test account on %2$s will expire in less than five days. We hope you enjoyed this test drive and use this opportunity to find a permanent Friendica website for your integrated social communications. A list of public sites is available at http://dir.friendica.com/siteinfo - and for more information on setting up your own Friendica server please see the Friendica project website at http://friendica.com." +msgstr "Saluton %1$s,\n\nVia testkonto ĉe %2$s senvalidiÄos post malpli ol kvin tagoj. Vi esperas ke vi Äuis la teston kaj baldaÅ­ trovosÄustan Friendica retejon por via integrita sociala komunikado. Listo de publikaj retejoj troviÄas ĉe http://dir.friendica.com/siteinfo - kaj por pli da informoj pri kiel instali vian propran Friendica servilon, bonvolu viziti la retejon de la Friendica projekton ĉe http://friendica.com." + +#: ../../addon/pageheader/pageheader.php:50 +msgid "\"pageheader\" Settings" +msgstr "\"pageheader\" Agordoj" + +#: ../../addon/pageheader/pageheader.php:68 +msgid "pageheader Settings saved." +msgstr "Konservis Agordojn de pageheader." + +#: ../../addon/ijpost/ijpost.php:39 +msgid "Post to Insanejournal" +msgstr "AfiÅi al Insanejournal" + +#: ../../addon/ijpost/ijpost.php:70 +msgid "InsaneJournal Post Settings" +msgstr "Agordoj pri Insaenejournal AfiÅoj" + +#: ../../addon/ijpost/ijpost.php:72 +msgid "Enable InsaneJournal Post Plugin" +msgstr "Åœalti la InsaneJournal afiÅo kromprogramon." + +#: ../../addon/ijpost/ijpost.php:77 +msgid "InsaneJournal username" +msgstr "Salutnomo ĉe InsaneJournal" + +#: ../../addon/ijpost/ijpost.php:82 +msgid "InsaneJournal password" +msgstr "Pasvorto ĉe InsaneJournal" + +#: ../../addon/ijpost/ijpost.php:87 +msgid "Post to InsaneJournal by default" +msgstr "DefaÅ­lte afiÅi ĉe InsaneJournal" + +#: ../../addon/viewsrc/viewsrc.php:37 +msgid "View Source" +msgstr "Vidi Fonton" + +#: ../../addon/statusnet/statusnet.php:134 +msgid "Post to StatusNet" +msgstr "AfiÅi ĉe StatusNet" + +#: ../../addon/statusnet/statusnet.php:176 +msgid "" +"Please contact your site administrator.
    The provided API URL is not " +"valid." +msgstr "Bonvolu kontaki vian retejan administranton.
    La API URL adreso ne validas." + +#: ../../addon/statusnet/statusnet.php:204 +msgid "We could not contact the StatusNet API with the Path you entered." +msgstr "Ni ne povis trovi la StatusNet API kun la vojo kiun vi entajpis." + +#: ../../addon/statusnet/statusnet.php:232 +msgid "StatusNet settings updated." +msgstr "StatusNet agordoj Äisdatigita." + +#: ../../addon/statusnet/statusnet.php:257 +msgid "StatusNet Posting Settings" +msgstr "Agordoj por StausNet afiÅoj" + +#: ../../addon/statusnet/statusnet.php:271 +msgid "Globally Available StatusNet OAuthKeys" +msgstr "Äœeneralaj disponeblaj StatusNet OAuth Ålosiloj" + +#: ../../addon/statusnet/statusnet.php:272 +msgid "" +"There are preconfigured OAuth key pairs for some StatusNet servers " +"available. If you are useing one of them, please use these credentials. If " +"not feel free to connect to any other StatusNet instance (see below)." +msgstr "Disponeblas antaÅ­agorditaj Ålosilparoj por kelkaj StatusNet serviloj. Se via uzas iun de iu, bonvolu uzi unun de tiuj legitimaĵojn. Se ne, bonvolu konekti al iu alia StatusNet servilo (vidu malsupre)." + +#: ../../addon/statusnet/statusnet.php:280 +msgid "Provide your own OAuth Credentials" +msgstr "Provizi viajn proprajn OAuth legitimaĵojn" + +#: ../../addon/statusnet/statusnet.php:281 +msgid "" +"No consumer key pair for StatusNet found. Register your Friendica Account as" +" an desktop client on your StatusNet account, copy the consumer key pair " +"here and enter the API base root.
    Before you register your own OAuth " +"key pair ask the administrator if there is already a key pair for this " +"Friendica installation at your favorited StatusNet installation." +msgstr "Ne trovis klientajn Ålosilojn por StatusNet. Registru vian Friendica konton kiel klientkomputilo/desktop client en via StausNet konto. Kopiu la klientajn Ålosilojn ĉi tien kaj entajpu la baza API radiko.
    AntaÅ­ vi registros viajn proprajn OAuth Ålosilojn, demandu al la administranto ĉu jam ekzistas Ålosiloj por ĉi-tiu Friendia retejo je via StatusNet retejo." + +#: ../../addon/statusnet/statusnet.php:283 +msgid "OAuth Consumer Key" +msgstr "OAuth Åœlosilo de Kliento" + +#: ../../addon/statusnet/statusnet.php:286 +msgid "OAuth Consumer Secret" +msgstr "OAuth Sekreto de Kliento" + +#: ../../addon/statusnet/statusnet.php:289 +msgid "Base API Path (remember the trailing /)" +msgstr "Baza vojo al la API (ne forgesu la finan /)" + +#: ../../addon/statusnet/statusnet.php:310 +msgid "" +"To connect to your StatusNet account click the button below to get a " +"security code from StatusNet which you have to copy into the input box below" +" and submit the form. Only your public posts will be posted" +" to StatusNet." +msgstr "Por konekti al vian konton ĉe StatusNet, klaku la malsupran butonon por atingi sekurecan kodon de StatusNet, kiun vi devas alglui en la malsupra kampo kaj sendi la formon. Nur viaj publikaj afiÅoj estos afiÅota al StatusNet." + +#: ../../addon/statusnet/statusnet.php:311 +msgid "Log in with StatusNet" +msgstr "Ensaluti kun StatusNet." + +#: ../../addon/statusnet/statusnet.php:313 +msgid "Copy the security code from StatusNet here" +msgstr "Alglui la kodon de StatusNet ĉi tie:" + +#: ../../addon/statusnet/statusnet.php:319 +msgid "Cancel Connection Process" +msgstr "Nuligi Konektadon" + +#: ../../addon/statusnet/statusnet.php:321 +msgid "Current StatusNet API is" +msgstr "La nuna StatusNet API estas" + +#: ../../addon/statusnet/statusnet.php:322 +msgid "Cancel StatusNet Connection" +msgstr "Nuligi Konekton al StatusNet" + +#: ../../addon/statusnet/statusnet.php:333 ../../addon/twitter/twitter.php:189 +msgid "Currently connected to: " +msgstr "Konektita al:" + +#: ../../addon/statusnet/statusnet.php:334 +msgid "" +"If enabled all your public postings can be posted to the " +"associated StatusNet account. You can choose to do so by default (here) or " +"for every posting separately in the posting options when writing the entry." +msgstr "Kiam Åaltita, ĉiuj publikaj afiÅoj de vi ankaÅ­ eblas esti afiÅota al la asociigita StatusNet konto. Vi povas elekti Äin defaÅ­lte (ĉi tie) au unuope por ĉiuj afiÅoj kiam vi skribos ilin." + +#: ../../addon/statusnet/statusnet.php:336 +msgid "" +"Note: Due your privacy settings (Hide your profile " +"details from unknown viewers?) the link potentially included in public " +"postings relayed to StatusNet will lead the visitor to a blank page " +"informing the visitor that the access to your profile has been restricted." +msgstr "Averto: LaÅ­ viaj privatecaj agordoj (KaÅi viajn profilajn detalojn al nekonataj spektantoj?), la ligilo en publikaj afiÅoj plusendata al StatusNet gvidas vizitontojn al malplena paÄo sciigante ilin ke atingo al via profilo estas lmitigita." + +#: ../../addon/statusnet/statusnet.php:339 +msgid "Allow posting to StatusNet" +msgstr "Permesi afiÅojn al StatusNet" + +#: ../../addon/statusnet/statusnet.php:342 +msgid "Send public postings to StatusNet by default" +msgstr "DefaÅ­lte sendi publikajn afiÅojn al StatusNet" + +#: ../../addon/statusnet/statusnet.php:345 +msgid "Send linked #-tags and @-names to StatusNet" +msgstr "Sendi ligitajn #-etikedojn kaj @-nomon al StatusNet" + +#: ../../addon/statusnet/statusnet.php:350 ../../addon/twitter/twitter.php:206 +msgid "Clear OAuth configuration" +msgstr "ForviÅi OAuth agordojn" + +#: ../../addon/statusnet/statusnet.php:559 +msgid "API URL" +msgstr "API URL adreso" + +#: ../../addon/infiniteimprobabilitydrive/infiniteimprobabilitydrive.php:19 +msgid "Infinite Improbability Drive" +msgstr "Senfina Probableca Pelilo" + +#: ../../addon/tumblr/tumblr.php:36 +msgid "Post to Tumblr" +msgstr "AfiÅi al Tumblr" + +#: ../../addon/tumblr/tumblr.php:67 +msgid "Tumblr Post Settings" +msgstr "Agordoj pri afiÅoj ĉe Tumblr" + +#: ../../addon/tumblr/tumblr.php:69 +msgid "Enable Tumblr Post Plugin" +msgstr "Åœalti la kromprogramon por Tumblr afiÅoj" + +#: ../../addon/tumblr/tumblr.php:74 +msgid "Tumblr login" +msgstr "Salutnomo ĉe Tumblr" + +#: ../../addon/tumblr/tumblr.php:79 +msgid "Tumblr password" +msgstr "Pasvorto ĉe Tumblr" + +#: ../../addon/tumblr/tumblr.php:84 +msgid "Post to Tumblr by default" +msgstr "DefaÅ­lte afiÅi ĉe Tumblr" + +#: ../../addon/numfriends/numfriends.php:46 +msgid "Numfriends settings updated." +msgstr "Äœisdatigis agordojn por Numfriends." + +#: ../../addon/numfriends/numfriends.php:77 +msgid "Numfriends Settings" +msgstr "Agordoj por Numfriends" + +#: ../../addon/numfriends/numfriends.php:79 +msgid "How many contacts to display on profile sidebar" +msgstr "Kiom da kontaktoj mi montru en la flanka strio" + +#: ../../addon/gnot/gnot.php:48 +msgid "Gnot settings updated." +msgstr "Äœisdatigis Gnot agordojn." + +#: ../../addon/gnot/gnot.php:79 +msgid "Gnot Settings" +msgstr "Agordoj por Gnot" + +#: ../../addon/gnot/gnot.php:81 +msgid "" +"Allows threading of email comment notifications on Gmail and anonymising the" +" subject line." +msgstr "Permesas la ĉenadon de retpoÅtaj atentigoj pri komentoj ĉe Gmail kan anonimigado de la temlinio." + +#: ../../addon/gnot/gnot.php:82 +msgid "Enable this plugin/addon?" +msgstr "Åœalti tiun kromprogramon?" + +#: ../../addon/gnot/gnot.php:97 +#, php-format +msgid "[Friendica:Notify] Comment to conversation #%d" +msgstr "[Friendica:Atentigo] Komento pri konversacio #%d" + +#: ../../addon/wppost/wppost.php:42 +msgid "Post to Wordpress" +msgstr "AfiÅi al Wordpress" + +#: ../../addon/wppost/wppost.php:76 +msgid "WordPress Post Settings" +msgstr "Agordoj por WordPress afiÅojn" + +#: ../../addon/wppost/wppost.php:78 +msgid "Enable WordPress Post Plugin" +msgstr "Åœalti la Wordpress-afiÅo kromprogramon" + +#: ../../addon/wppost/wppost.php:83 +msgid "WordPress username" +msgstr "WordPress salutnomo" + +#: ../../addon/wppost/wppost.php:88 +msgid "WordPress password" +msgstr "WordPress pasvorto" + +#: ../../addon/wppost/wppost.php:93 +msgid "WordPress API URL" +msgstr "Wordpress API URL adreso" + +#: ../../addon/wppost/wppost.php:98 +msgid "Post to WordPress by default" +msgstr "DefaÅ­lte afiÅi al WordPress" + +#: ../../addon/wppost/wppost.php:103 +msgid "Provide a backlink to the Friendica post" +msgstr "Provizi re-ligilon al la Friendica afiÅo" + +#: ../../addon/wppost/wppost.php:207 +msgid "Read the original post and comment stream on Friendica" +msgstr "Legi la originalan afiÅon kaj komentfluo ĉe Friendica" + +#: ../../addon/showmore/showmore.php:38 +msgid "\"Show more\" Settings" +msgstr "\"Montri pli\" agordoj" + +#: ../../addon/showmore/showmore.php:41 +msgid "Enable Show More" +msgstr "Åœalti \"montri pli\"" + +#: ../../addon/showmore/showmore.php:44 +msgid "Cutting posts after how much characters" +msgstr "Limitigi afiÅojn al kiom da literoj" + +#: ../../addon/showmore/showmore.php:65 +msgid "Show More Settings saved." +msgstr "Konservis \"montri pli\" agordojn." + +#: ../../addon/piwik/piwik.php:79 +msgid "" +"This website is tracked using the Piwik " +"analytics tool." +msgstr "Ĉi retejo uzas Piwik kiel retuma analizilo." + +#: ../../addon/piwik/piwik.php:82 +#, php-format +msgid "" +"If you do not want that your visits are logged this way you can" +" set a cookie to prevent Piwik from tracking further visits of the site " +"(opt-out)." +msgstr "Se ni ne protokolu viajn vizitojn tiel, vi povas agordi kuketon por malpermesi Piwik al plu protokoli pliajn vizitojn (mem-for-elekti / opt-out)." + +#: ../../addon/piwik/piwik.php:90 +msgid "Piwik Base URL" +msgstr "Piwik baza URL adreso" + +#: ../../addon/piwik/piwik.php:90 +msgid "" +"Absolute path to your Piwik installation. (without protocol (http/s), with " +"trailing slash)" +msgstr "Absoluta vojo al via Piwik instalo. (sen protokolo (http/s), inkluzive vosta oblikva streketo)" + +#: ../../addon/piwik/piwik.php:91 +msgid "Site ID" +msgstr "Reteja idento" + +#: ../../addon/piwik/piwik.php:92 +msgid "Show opt-out cookie link?" +msgstr "Montru ligilon al kuketo por mem-for-elekti (opt-out)?" + +#: ../../addon/piwik/piwik.php:93 +msgid "Asynchronous tracking" +msgstr "Nesinkrona spurado." + +#: ../../addon/twitter/twitter.php:73 +msgid "Post to Twitter" +msgstr "AfiÅi ĉe Twitter" + +#: ../../addon/twitter/twitter.php:122 +msgid "Twitter settings updated." +msgstr "Äœisdatigis Twitter agordojn." + +#: ../../addon/twitter/twitter.php:146 +msgid "Twitter Posting Settings" +msgstr "Agordoj por afiÅi ĉe Twitter" + +#: ../../addon/twitter/twitter.php:153 +msgid "" +"No consumer key pair for Twitter found. Please contact your site " +"administrator." +msgstr "Ne trovis klientajn Ålosilojn por Twitter. Bonvolu kontakti vian retejan administranton." + +#: ../../addon/twitter/twitter.php:172 +msgid "" +"At this Friendica instance the Twitter plugin was enabled but you have not " +"yet connected your account to your Twitter account. To do so click the " +"button below to get a PIN from Twitter which you have to copy into the input" +" box below and submit the form. Only your public posts will" +" be posted to Twitter." +msgstr "Je ĉi tiu Friendica retejo, la Twitter kromprogramo jam estas Åaltita, sed via konto anokoraÅ­ ne estas konektita kun via Twitter konto. Por fari tion, klaku la supran butonon por atingi nombrokodon de Twitter, kion vi kopiu en la supran eniga ĉelo, kaj sendu la formularon. Nur viaj publikaj afiÅoj estas plusendota al Twitter. " + +#: ../../addon/twitter/twitter.php:173 +msgid "Log in with Twitter" +msgstr "Ensaluti kun Twitter" + +#: ../../addon/twitter/twitter.php:175 +msgid "Copy the PIN from Twitter here" +msgstr "Alglui la PIN de Twitter ĉi tie" + +#: ../../addon/twitter/twitter.php:190 +msgid "" +"If enabled all your public postings can be posted to the " +"associated Twitter account. You can choose to do so by default (here) or for" +" every posting separately in the posting options when writing the entry." +msgstr "Kiam Åaltita, ĉiuj publikaj afiÅoj de vi ankaÅ­ eblas esti afiÅota al la asociigita Twitter konto. Vi povas elekti Äin defaÅ­lte (ĉi tie) au unuope por ĉiuj afiÅoj kiam vi skribos ilin." + +#: ../../addon/twitter/twitter.php:192 +msgid "" +"Note: Due your privacy settings (Hide your profile " +"details from unknown viewers?) the link potentially included in public " +"postings relayed to Twitter will lead the visitor to a blank page informing " +"the visitor that the access to your profile has been restricted." +msgstr "Averto: LaÅ­ viaj privatecaj agordoj (KaÅi viajn profilajn detalojn al nekonataj spektantoj?), la ligilo en publikaj afiÅoj plusendata al Twitter gvidas vizitontojn al malplena paÄo sciigante ilin ke atingo al via profilo estas lmitigita." + +#: ../../addon/twitter/twitter.php:195 +msgid "Allow posting to Twitter" +msgstr "Permesi afiÅojn al Twitter" + +#: ../../addon/twitter/twitter.php:198 +msgid "Send public postings to Twitter by default" +msgstr "DefaÅ­lte sendi publikajn afiÅojn al Twitter" + +#: ../../addon/twitter/twitter.php:201 +msgid "Send linked #-tags and @-names to Twitter" +msgstr "Sendi ligitajn #-etikedojn kaj @-nomon al Twitter" + +#: ../../addon/twitter/twitter.php:389 +msgid "Consumer key" +msgstr "Åœlosilo de Kliento" + +#: ../../addon/twitter/twitter.php:390 +msgid "Consumer secret" +msgstr "Sekreto de Kliento" + +#: ../../addon/irc/irc.php:44 +msgid "IRC Settings" +msgstr "IRC Agordoj" + +#: ../../addon/irc/irc.php:46 +msgid "Channel(s) to auto connect (comma separated)" +msgstr "AÅ­tomate konektiÄi al la kanalo(j) (disigita per komo)" + +#: ../../addon/irc/irc.php:51 +msgid "Popular Channels (comma separated)" +msgstr "Popularaj kanaloj (disigita per komo)" + +#: ../../addon/irc/irc.php:69 +msgid "IRC settings saved." +msgstr "IRC agordoj konservitaj." + +#: ../../addon/irc/irc.php:74 +msgid "IRC Chatroom" +msgstr "IRC babilejo" + +#: ../../addon/irc/irc.php:96 +msgid "Popular Channels" +msgstr "Popularaj Kanaloj" + +#: ../../addon/blogger/blogger.php:42 +msgid "Post to blogger" +msgstr "AfiÅi al blogger" + +#: ../../addon/blogger/blogger.php:74 +msgid "Blogger Post Settings" +msgstr "Agordo pri Blogger AfiÅoj" + +#: ../../addon/blogger/blogger.php:76 +msgid "Enable Blogger Post Plugin" +msgstr "Åœalti la Blogger afiÅo kromprogramon" + +#: ../../addon/blogger/blogger.php:81 +msgid "Blogger username" +msgstr "Blogger uzantonomo" + +#: ../../addon/blogger/blogger.php:86 +msgid "Blogger password" +msgstr "Blogger pasvorto" + +#: ../../addon/blogger/blogger.php:91 +msgid "Blogger API URL" +msgstr "Blogger API URL" + +#: ../../addon/blogger/blogger.php:96 +msgid "Post to Blogger by default" +msgstr "DefaÅ­lte afiÅi al Blogger" + +#: ../../addon/posterous/posterous.php:37 +msgid "Post to Posterous" +msgstr "AfiÅi al Posterous" + +#: ../../addon/posterous/posterous.php:70 +msgid "Posterous Post Settings" +msgstr "Agordoj pri afiÅoj ĉe Posterous" + +#: ../../addon/posterous/posterous.php:72 +msgid "Enable Posterous Post Plugin" +msgstr "Åœalti la Poserous-afiÅo kromprogramon" + +#: ../../addon/posterous/posterous.php:77 +msgid "Posterous login" +msgstr "Posterous salutnomo" + +#: ../../addon/posterous/posterous.php:82 +msgid "Posterous password" +msgstr "Posterous pasvorto" + +#: ../../addon/posterous/posterous.php:87 +msgid "Posterous site ID" +msgstr "Idento de Posterous retejo" + +#: ../../addon/posterous/posterous.php:92 +msgid "Posterous API token" +msgstr "API ĵetono de Posterous retejo" + +#: ../../addon/posterous/posterous.php:97 +msgid "Post to Posterous by default" +msgstr "DefaÅ­lte afiÅi al Posterous" + +#: ../../view/theme/cleanzero/config.php:82 +#: ../../view/theme/diabook/config.php:192 +#: ../../view/theme/quattro/config.php:54 ../../view/theme/dispy/config.php:72 +msgid "Theme settings" +msgstr "Agordoj pri la etoso" + +#: ../../view/theme/cleanzero/config.php:83 +msgid "Set resize level for images in posts and comments (width and height)" +msgstr "Agordi la regrandignivelo por bildoj en afiÅoj kaj komentoj (larÄo kaj alto)" + +#: ../../view/theme/cleanzero/config.php:84 +#: ../../view/theme/diabook/config.php:193 +#: ../../view/theme/dispy/config.php:73 +msgid "Set font-size for posts and comments" +msgstr "Agordi la tiparan grandon por afiÅoj kaj komentoj" + +#: ../../view/theme/cleanzero/config.php:85 +msgid "Set theme width" +msgstr "Agordi la larÄo por la etoso" + +#: ../../view/theme/cleanzero/config.php:86 +#: ../../view/theme/quattro/config.php:56 +msgid "Color scheme" +msgstr "Kolorskemo" + +#: ../../view/theme/diabook/theme.php:127 ../../include/nav.php:49 +#: ../../include/nav.php:115 +msgid "Your posts and conversations" +msgstr "Viaj afiÅoj kaj komunikadoj" + +#: ../../view/theme/diabook/theme.php:128 ../../include/nav.php:50 +msgid "Your profile page" +msgstr "Via profilo" + +#: ../../view/theme/diabook/theme.php:129 +msgid "Your contacts" +msgstr "Viaj kontaktoj" + +#: ../../view/theme/diabook/theme.php:130 ../../include/nav.php:51 +msgid "Your photos" +msgstr "Viaj bildoj" + +#: ../../view/theme/diabook/theme.php:131 ../../include/nav.php:52 +msgid "Your events" +msgstr "Viaj okazoj" + +#: ../../view/theme/diabook/theme.php:132 ../../include/nav.php:53 +msgid "Personal notes" +msgstr "Personaj notoj" + +#: ../../view/theme/diabook/theme.php:132 ../../include/nav.php:53 +msgid "Your personal photos" +msgstr "Viaj personaj bildoj" + +#: ../../view/theme/diabook/theme.php:134 +#: ../../view/theme/diabook/theme.php:643 +#: ../../view/theme/diabook/theme.php:747 +#: ../../view/theme/diabook/config.php:201 +msgid "Community Pages" +msgstr "Komunumaj paÄoj" + +#: ../../view/theme/diabook/theme.php:490 +#: ../../view/theme/diabook/theme.php:749 +#: ../../view/theme/diabook/config.php:203 +msgid "Community Profiles" +msgstr "Komunumaj Profiloj" + +#: ../../view/theme/diabook/theme.php:511 +#: ../../view/theme/diabook/theme.php:754 +#: ../../view/theme/diabook/config.php:208 +msgid "Last users" +msgstr "Ä´usaj uzantoj" + +#: ../../view/theme/diabook/theme.php:540 +#: ../../view/theme/diabook/theme.php:756 +#: ../../view/theme/diabook/config.php:210 +msgid "Last likes" +msgstr "Ä´usaj Åatitaj elementoj" + +#: ../../view/theme/diabook/theme.php:585 +#: ../../view/theme/diabook/theme.php:755 +#: ../../view/theme/diabook/config.php:209 +msgid "Last photos" +msgstr "Ä´usaj bildoj" + +#: ../../view/theme/diabook/theme.php:622 +#: ../../view/theme/diabook/theme.php:752 +#: ../../view/theme/diabook/config.php:206 +msgid "Find Friends" +msgstr "Trovi Amikojn" + +#: ../../view/theme/diabook/theme.php:623 +msgid "Local Directory" +msgstr "Loka Katalogo" + +#: ../../view/theme/diabook/theme.php:625 ../../include/contact_widgets.php:35 +msgid "Similar Interests" +msgstr "Similaj Interesoj" + +#: ../../view/theme/diabook/theme.php:627 ../../include/contact_widgets.php:37 +msgid "Invite Friends" +msgstr "Inviti amikojn" + +#: ../../view/theme/diabook/theme.php:678 +#: ../../view/theme/diabook/theme.php:748 +#: ../../view/theme/diabook/config.php:202 +msgid "Earth Layers" +msgstr "Tertavoloj (Earth Layers)" + +#: ../../view/theme/diabook/theme.php:683 +msgid "Set zoomfactor for Earth Layers" +msgstr "Agordi zoman faktoron por Tertavoloj" + +#: ../../view/theme/diabook/theme.php:684 +#: ../../view/theme/diabook/config.php:199 +msgid "Set longitude (X) for Earth Layers" +msgstr "Agordi longitudon (X) por Tertavoloj" + +#: ../../view/theme/diabook/theme.php:685 +#: ../../view/theme/diabook/config.php:200 +msgid "Set latitude (Y) for Earth Layers" +msgstr "Agordi latitudon (Y) por Tertavoloj" + +#: ../../view/theme/diabook/theme.php:698 +#: ../../view/theme/diabook/theme.php:750 +#: ../../view/theme/diabook/config.php:204 +msgid "Help or @NewHere ?" +msgstr "Helpu aÅ­ @NewHere ?" + +#: ../../view/theme/diabook/theme.php:705 +#: ../../view/theme/diabook/theme.php:751 +#: ../../view/theme/diabook/config.php:205 +msgid "Connect Services" +msgstr "Konekti Servojn" + +#: ../../view/theme/diabook/theme.php:712 +#: ../../view/theme/diabook/theme.php:753 +msgid "Last Tweets" +msgstr "Ä´usaj Pepaĵoj" + +#: ../../view/theme/diabook/theme.php:715 +#: ../../view/theme/diabook/config.php:197 +msgid "Set twitter search term" +msgstr "Agordi Twitter serĉtekston" + +#: ../../view/theme/diabook/theme.php:735 +#: ../../view/theme/diabook/theme.php:736 +#: ../../view/theme/diabook/theme.php:737 +#: ../../view/theme/diabook/theme.php:738 +#: ../../view/theme/diabook/theme.php:739 +#: ../../view/theme/diabook/theme.php:740 +#: ../../view/theme/diabook/theme.php:741 +#: ../../view/theme/diabook/theme.php:742 +#: ../../view/theme/diabook/theme.php:743 +#: ../../view/theme/diabook/theme.php:744 ../../include/acl_selectors.php:288 +msgid "don't show" +msgstr "kaÅi" + +#: ../../view/theme/diabook/theme.php:735 +#: ../../view/theme/diabook/theme.php:736 +#: ../../view/theme/diabook/theme.php:737 +#: ../../view/theme/diabook/theme.php:738 +#: ../../view/theme/diabook/theme.php:739 +#: ../../view/theme/diabook/theme.php:740 +#: ../../view/theme/diabook/theme.php:741 +#: ../../view/theme/diabook/theme.php:742 +#: ../../view/theme/diabook/theme.php:743 +#: ../../view/theme/diabook/theme.php:744 ../../include/acl_selectors.php:287 +msgid "show" +msgstr "montri" + +#: ../../view/theme/diabook/theme.php:745 +msgid "Show/hide boxes at right-hand column:" +msgstr "KaÅi/montri kestojn ĉe dekstra kolumno:" + +#: ../../view/theme/diabook/config.php:194 +#: ../../view/theme/dispy/config.php:74 +msgid "Set line-height for posts and comments" +msgstr "Agordi la linigrandon por afiÅoj kaj komentoj" + +#: ../../view/theme/diabook/config.php:195 +msgid "Set resolution for middle column" +msgstr "Agordi la distingivon por la meza kolumno" + +#: ../../view/theme/diabook/config.php:196 +msgid "Set color scheme" +msgstr "Agordi Kolorskemon" + +#: ../../view/theme/diabook/config.php:198 +msgid "Set zoomfactor for Earth Layer" +msgstr "Agordi zoman faktoron de Tertavolo" + +#: ../../view/theme/diabook/config.php:207 +msgid "Last tweets" +msgstr "Ä´usaj pepaĵoj" + +#: ../../view/theme/quattro/config.php:55 +msgid "Alignment" +msgstr "Äœisrandigo" + +#: ../../view/theme/quattro/config.php:55 +msgid "Left" +msgstr "Maldekstren" + +#: ../../view/theme/quattro/config.php:55 +msgid "Center" +msgstr "Centren" + +#: ../../view/theme/dispy/config.php:75 +msgid "Set colour scheme" +msgstr "Agordi Kolorskemon" + +#: ../../include/profile_advanced.php:17 ../../boot.php:1138 +msgid "Gender:" +msgstr "Sekso:" + +#: ../../include/profile_advanced.php:22 +msgid "j F, Y" +msgstr "j F, Y" + +#: ../../include/profile_advanced.php:23 +msgid "j F" +msgstr "j F" + +#: ../../include/profile_advanced.php:30 +msgid "Birthday:" +msgstr "NaskiÄtago:" + +#: ../../include/profile_advanced.php:34 +msgid "Age:" +msgstr "AÄo:" + +#: ../../include/profile_advanced.php:37 ../../boot.php:1141 +msgid "Status:" +msgstr "Stato:" + +#: ../../include/profile_advanced.php:43 +#, php-format +msgid "for %1$d %2$s" +msgstr "por %1$d %2$s" + +#: ../../include/profile_advanced.php:48 ../../boot.php:1143 +msgid "Homepage:" +msgstr "HejmpaÄo:" + +#: ../../include/profile_advanced.php:52 +msgid "Tags:" +msgstr "Markoj:" + +#: ../../include/profile_advanced.php:56 +msgid "Religion:" +msgstr "Religio:" + +#: ../../include/profile_advanced.php:58 +msgid "About:" +msgstr "Pri:" + +#: ../../include/profile_advanced.php:60 +msgid "Hobbies/Interests:" +msgstr "Åœatokupoj/Interesoj:" + +#: ../../include/profile_advanced.php:67 +msgid "Contact information and Social Networks:" +msgstr "Kontaktinformoj kaj Interkonaj Retejoj:" + +#: ../../include/profile_advanced.php:69 +msgid "Musical interests:" +msgstr "Muzaikaj interesoj:" + +#: ../../include/profile_advanced.php:71 +msgid "Books, literature:" +msgstr "Libroj, literaturo:" + +#: ../../include/profile_advanced.php:73 +msgid "Television:" +msgstr "Televido:" + +#: ../../include/profile_advanced.php:75 +msgid "Film/dance/culture/entertainment:" +msgstr "Filmoj/dancoj/arto/amuzaĵoj:" + +#: ../../include/profile_advanced.php:77 +msgid "Love/Romance:" +msgstr "Amo/romanco:" + +#: ../../include/profile_advanced.php:79 +msgid "Work/employment:" +msgstr "Laboro:" + +#: ../../include/profile_advanced.php:81 +msgid "School/education:" +msgstr "Lernejo/eduko:" + +#: ../../include/contact_selectors.php:32 +msgid "Unknown | Not categorised" +msgstr "Nekonata | Nekatorigita" + +#: ../../include/contact_selectors.php:33 +msgid "Block immediately" +msgstr "Bloki tuj" + +#: ../../include/contact_selectors.php:34 +msgid "Shady, spammer, self-marketer" +msgstr "Suspekta, spamisto, memmerkatisto" + +#: ../../include/contact_selectors.php:35 +msgid "Known to me, but no opinion" +msgstr "Konata al mi, sed mi ne havas opinion" + +#: ../../include/contact_selectors.php:36 +msgid "OK, probably harmless" +msgstr "OK, verÅajne sendanÄera" + +#: ../../include/contact_selectors.php:37 +msgid "Reputable, has my trust" +msgstr "Fidinda laÅ­ mi" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Ofte" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Ĉiuhore" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Duope ĉiutage" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Ĉiutage" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Ĉiusemajne" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Ĉiumonate" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "LinkedIn" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/TujmesaÄilo" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/profile_selectors.php:6 +msgid "Male" +msgstr "Vira" + +#: ../../include/profile_selectors.php:6 +msgid "Female" +msgstr "Ina" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Nuntempe Vira" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Nuntempe Ina" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Ĉefe Vira" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Ĉefe Ina" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transgenra" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Interseksa" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transseksa" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Hermafrodita" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "NeÅ­tra" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "Nespecifa" + +#: ../../include/profile_selectors.php:6 +msgid "Other" +msgstr "Alia" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Nedecida" + +#: ../../include/profile_selectors.php:23 +msgid "Males" +msgstr "Viroj" + +#: ../../include/profile_selectors.php:23 +msgid "Females" +msgstr "Inoj" + +#: ../../include/profile_selectors.php:23 +msgid "Gay" +msgstr "Geja" + +#: ../../include/profile_selectors.php:23 +msgid "Lesbian" +msgstr "Lesba" + +#: ../../include/profile_selectors.php:23 +msgid "No Preference" +msgstr "Neniu Prefero" + +#: ../../include/profile_selectors.php:23 +msgid "Bisexual" +msgstr "AmbaÅ­seksema" + +#: ../../include/profile_selectors.php:23 +msgid "Autosexual" +msgstr "Memseksema" + +#: ../../include/profile_selectors.php:23 +msgid "Abstinent" +msgstr "Abstinema" + +#: ../../include/profile_selectors.php:23 +msgid "Virgin" +msgstr "Virgulino" + +#: ../../include/profile_selectors.php:23 +msgid "Deviant" +msgstr "Devia" + +#: ../../include/profile_selectors.php:23 +msgid "Fetish" +msgstr "Fetiĉo" + +#: ../../include/profile_selectors.php:23 +msgid "Oodles" +msgstr "Amasa" + +#: ../../include/profile_selectors.php:23 +msgid "Nonsexual" +msgstr "Neseksa" + +#: ../../include/profile_selectors.php:42 +msgid "Single" +msgstr "Sola" + +#: ../../include/profile_selectors.php:42 +msgid "Lonely" +msgstr "Soleca" + +#: ../../include/profile_selectors.php:42 +msgid "Available" +msgstr "Havebla" + +#: ../../include/profile_selectors.php:42 +msgid "Unavailable" +msgstr "Nehavebla" + +#: ../../include/profile_selectors.php:42 +msgid "Has crush" +msgstr "Sekrete enamiÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Infatuated" +msgstr "Blinda amo" + +#: ../../include/profile_selectors.php:42 +msgid "Dating" +msgstr "Rendevuanta" + +#: ../../include/profile_selectors.php:42 +msgid "Unfaithful" +msgstr "Malfidela" + +#: ../../include/profile_selectors.php:42 +msgid "Sex Addict" +msgstr "Seksmaniulo" + +#: ../../include/profile_selectors.php:42 ../../include/user.php:278 +msgid "Friends" +msgstr "Amikoj" + +#: ../../include/profile_selectors.php:42 +msgid "Friends/Benefits" +msgstr "Amikoj/AvantaÄoj" + +#: ../../include/profile_selectors.php:42 +msgid "Casual" +msgstr "Neformala" + +#: ../../include/profile_selectors.php:42 +msgid "Engaged" +msgstr "Fianĉiginta" + +#: ../../include/profile_selectors.php:42 +msgid "Married" +msgstr "EdziÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Imaginarily married" +msgstr "Image edziÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Partners" +msgstr "Geparuloj" + +#: ../../include/profile_selectors.php:42 +msgid "Cohabiting" +msgstr "KunloÄanta" + +#: ../../include/profile_selectors.php:42 +msgid "Common law" +msgstr "Registrita partnereco " + +#: ../../include/profile_selectors.php:42 +msgid "Happy" +msgstr "Feliĉa" + +#: ../../include/profile_selectors.php:42 +msgid "Not looking" +msgstr "Ne interesiÄis" + +#: ../../include/profile_selectors.php:42 +msgid "Swinger" +msgstr "Swinger" + +#: ../../include/profile_selectors.php:42 +msgid "Betrayed" +msgstr "Trompita" + +#: ../../include/profile_selectors.php:42 +msgid "Separated" +msgstr "DisiÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Unstable" +msgstr "Malfirma" + +#: ../../include/profile_selectors.php:42 +msgid "Divorced" +msgstr "EksedziÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Imaginarily divorced" +msgstr "Image eksedziÄinta" + +#: ../../include/profile_selectors.php:42 +msgid "Widowed" +msgstr "Vidva" + +#: ../../include/profile_selectors.php:42 +msgid "Uncertain" +msgstr "Ne certa" + +#: ../../include/profile_selectors.php:42 +msgid "It's complicated" +msgstr "Estas komplika" + +#: ../../include/profile_selectors.php:42 +msgid "Don't care" +msgstr "Egala" + +#: ../../include/profile_selectors.php:42 +msgid "Ask me" +msgstr "Demandu min" + +#: ../../include/event.php:20 ../../include/bb2diaspora.php:341 +msgid "Starts:" +msgstr "Ekas:" + +#: ../../include/event.php:30 ../../include/bb2diaspora.php:349 +msgid "Finishes:" +msgstr "Finas:" + +#: ../../include/delivery.php:456 ../../include/notifier.php:678 +msgid "(no subject)" +msgstr "(neniu temo)" + +#: ../../include/delivery.php:463 ../../include/enotify.php:26 +#: ../../include/notifier.php:685 +msgid "noreply" +msgstr "nerespondi" + +#: ../../include/Scrape.php:572 +msgid " on Last.fm" +msgstr " ĉe Last.fm" + +#: ../../include/text.php:243 +msgid "prev" +msgstr "antaÅ­a" + +#: ../../include/text.php:245 +msgid "first" +msgstr "unua" + +#: ../../include/text.php:274 +msgid "last" +msgstr "lasta" + +#: ../../include/text.php:277 +msgid "next" +msgstr "sekvanta" + +#: ../../include/text.php:568 +msgid "No contacts" +msgstr "Neniu kontaktoj" + +#: ../../include/text.php:577 +#, php-format +msgid "%d Contact" +msgid_plural "%d Contacts" +msgstr[0] "%d Kontakto" +msgstr[1] "%d Kontaktoj" + +#: ../../include/text.php:835 +msgid "Monday" +msgstr "Lundo" + +#: ../../include/text.php:835 +msgid "Tuesday" +msgstr "Mardo" + +#: ../../include/text.php:835 +msgid "Wednesday" +msgstr "Merkredo" + +#: ../../include/text.php:835 +msgid "Thursday" +msgstr "Ä´aÅ­do" + +#: ../../include/text.php:835 +msgid "Friday" +msgstr "Vendredo" + +#: ../../include/text.php:835 +msgid "Saturday" +msgstr "Sabato" + +#: ../../include/text.php:835 +msgid "Sunday" +msgstr "Dimanĉo" + +#: ../../include/text.php:839 +msgid "January" +msgstr "Januaro" + +#: ../../include/text.php:839 +msgid "February" +msgstr "Februaro" + +#: ../../include/text.php:839 +msgid "March" +msgstr "Marto" + +#: ../../include/text.php:839 +msgid "April" +msgstr "Aprilo" + +#: ../../include/text.php:839 +msgid "May" +msgstr "Majo" + +#: ../../include/text.php:839 +msgid "June" +msgstr "Junio" + +#: ../../include/text.php:839 +msgid "July" +msgstr "Julio" + +#: ../../include/text.php:839 +msgid "August" +msgstr "AÅ­gusto" + +#: ../../include/text.php:839 +msgid "September" +msgstr "Septembro" + +#: ../../include/text.php:839 +msgid "October" +msgstr "Oktobro" + +#: ../../include/text.php:839 +msgid "November" +msgstr "Novembro" + +#: ../../include/text.php:839 +msgid "December" +msgstr "Decembro" + +#: ../../include/text.php:925 +msgid "bytes" +msgstr "bajtoj" + +#: ../../include/text.php:945 ../../include/text.php:960 +msgid "remove" +msgstr "forviÅi" + +#: ../../include/text.php:945 ../../include/text.php:960 +msgid "[remove]" +msgstr "[forviÅi]" + +#: ../../include/text.php:948 +msgid "Categories:" +msgstr "Kategorioj:" + +#: ../../include/text.php:963 +msgid "Filed under:" +msgstr "Enarkivigita kiel:" + +#: ../../include/text.php:979 ../../include/text.php:991 +msgid "Click to open/close" +msgstr "Klaku por malfermi/fermi" + +#: ../../include/text.php:1097 ../../include/user.php:236 +msgid "default" +msgstr "defaÅ­lta" + +#: ../../include/text.php:1109 +msgid "Select an alternate language" +msgstr "Elekti alian lingvon" + +#: ../../include/text.php:1319 +msgid "activity" +msgstr "aktiveco" + +#: ../../include/text.php:1321 +msgid "comment" +msgstr "komento" + +#: ../../include/text.php:1322 +msgid "post" +msgstr "afiÅo" + +#: ../../include/text.php:1477 +msgid "Item filed" +msgstr "Enarkivigis elementon " + +#: ../../include/diaspora.php:593 +msgid "Sharing notification from Diaspora network" +msgstr "Antentigo pri kunhavigado de la Diaspora reto" + +#: ../../include/diaspora.php:2085 +msgid "Attachments:" +msgstr "Kunsendaĵoj:" + +#: ../../include/network.php:839 +msgid "view full size" +msgstr "vidi plengrande" + +#: ../../include/oembed.php:135 +msgid "Embedded content" +msgstr "Enigita enhavo" + +#: ../../include/oembed.php:144 +msgid "Embedding disabled" +msgstr "MalÅaltita enigitado" + +#: ../../include/group.php:25 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "Revivigis malnovan grupon kun la sama nomo. Permesoj por estantaj elementoj eble estas validaj por la grupo kaj estontaj membroj. Se tiu ne estas kiun vi atendis, bonvolu krei alian grupon kun alia nomo." + +#: ../../include/group.php:176 +msgid "Default privacy group for new contacts" +msgstr "DefaÅ­lta privateca grupo por novaj kontaktoj" + +#: ../../include/group.php:195 +msgid "Everybody" +msgstr "Ĉiuj" + +#: ../../include/group.php:218 +msgid "edit" +msgstr "redakti" + +#: ../../include/group.php:239 +msgid "Groups" +msgstr "Grupoj" + +#: ../../include/group.php:240 +msgid "Edit group" +msgstr "Redakti grupon" + +#: ../../include/group.php:241 +msgid "Create a new group" +msgstr "Krei novan grupon" + +#: ../../include/group.php:242 +msgid "Contacts not in any group" +msgstr "Kontaktoj en neniu grupo" + +#: ../../include/nav.php:46 ../../boot.php:848 +msgid "Logout" +msgstr "Elsaluti" + +#: ../../include/nav.php:46 +msgid "End this session" +msgstr "Fini ĉi-tiun seancon" + +#: ../../include/nav.php:49 ../../boot.php:1538 +msgid "Status" +msgstr "Stato" + +#: ../../include/nav.php:64 +msgid "Sign in" +msgstr "Ensaluti" + +#: ../../include/nav.php:77 +msgid "Home Page" +msgstr "HejmpaÄo" + +#: ../../include/nav.php:81 +msgid "Create an account" +msgstr "Krei konton" + +#: ../../include/nav.php:86 +msgid "Help and documentation" +msgstr "Helpo kaj dokumentado" + +#: ../../include/nav.php:89 +msgid "Apps" +msgstr "Programoj" + +#: ../../include/nav.php:89 +msgid "Addon applications, utilities, games" +msgstr "Kromprogramoj, utilaĵoj, ludiloj" + +#: ../../include/nav.php:91 +msgid "Search site content" +msgstr "Serĉu la retejon" + +#: ../../include/nav.php:101 +msgid "Conversations on this site" +msgstr "Konversacioj je ĉi-tiu retejo" + +#: ../../include/nav.php:103 +msgid "Directory" +msgstr "Katalogo" + +#: ../../include/nav.php:103 +msgid "People directory" +msgstr "Katalogo de homoj" + +#: ../../include/nav.php:113 +msgid "Conversations from your friends" +msgstr "Konversacioj de viaj amikoj" + +#: ../../include/nav.php:121 +msgid "Friend Requests" +msgstr "Kontaktpetoj" + +#: ../../include/nav.php:123 +msgid "See all notifications" +msgstr "Vidu ĉiujn atentigojn" + +#: ../../include/nav.php:124 +msgid "Mark all system notifications seen" +msgstr "Marki ĉiujn atentigojn legita" + +#: ../../include/nav.php:128 +msgid "Private mail" +msgstr "Privata poÅto" + +#: ../../include/nav.php:129 +msgid "Inbox" +msgstr "Enirkesto" + +#: ../../include/nav.php:130 +msgid "Outbox" +msgstr "Elirkesto" + +#: ../../include/nav.php:134 +msgid "Manage" +msgstr "Administri" + +#: ../../include/nav.php:134 +msgid "Manage other pages" +msgstr "Administri aliajn paÄojn" + +#: ../../include/nav.php:138 ../../boot.php:1096 +msgid "Profiles" +msgstr "Profiloj" + +#: ../../include/nav.php:138 ../../boot.php:1096 +msgid "Manage/edit profiles" +msgstr "Administri/redakti profilojn" + +#: ../../include/nav.php:139 +msgid "Manage/edit friends and contacts" +msgstr "Administri/redakti amikojn kaj kontaktojn" + +#: ../../include/nav.php:146 +msgid "Site setup and configuration" +msgstr "Agordoj pri la retejo" + +#: ../../include/nav.php:170 +msgid "Nothing new here" +msgstr "Estas neniu nova ĉi tie" + +#: ../../include/contact_widgets.php:6 +msgid "Add New Contact" +msgstr "Aldonu Novan Kontakton" + +#: ../../include/contact_widgets.php:7 +msgid "Enter address or web location" +msgstr "Entajpu adreson aÅ­ retlokon" + +#: ../../include/contact_widgets.php:8 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Ekzemple: bob@example.com, http://example.com/barbara" + +#: ../../include/contact_widgets.php:23 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "Disponeblas %d invito" +msgstr[1] "Disponeblas %d invitoj" + +#: ../../include/contact_widgets.php:29 +msgid "Find People" +msgstr "Trovi Homojn" + +#: ../../include/contact_widgets.php:30 +msgid "Enter name or interest" +msgstr "Entajpu nomon aÅ­ intereson" + +#: ../../include/contact_widgets.php:31 +msgid "Connect/Follow" +msgstr "Konekti/Aboni" + +#: ../../include/contact_widgets.php:32 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Ekzemple: Robert Morgenstein, Fishing" + +#: ../../include/contact_widgets.php:36 +msgid "Random Profile" +msgstr "Hazarda Profilo" + +#: ../../include/contact_widgets.php:68 +msgid "Networks" +msgstr "Retoj" + +#: ../../include/contact_widgets.php:71 +msgid "All Networks" +msgstr "Ĉiuj Retoj" + +#: ../../include/contact_widgets.php:98 +msgid "Saved Folders" +msgstr "Konservitaj Dosierujoj" + +#: ../../include/contact_widgets.php:101 ../../include/contact_widgets.php:129 +msgid "Everything" +msgstr "Ĉio" + +#: ../../include/contact_widgets.php:126 +msgid "Categories" +msgstr "Kategorioj" + +#: ../../include/auth.php:36 +msgid "Logged out." +msgstr "Elsalutita." + +#: ../../include/auth.php:115 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Okazis problemo ensalutinta kun via OpenID. Bonvolu kontroli la ID." + +#: ../../include/auth.php:115 +msgid "The error message was:" +msgstr "La erarmesaÄo estis:" + +#: ../../include/datetime.php:43 ../../include/datetime.php:45 +msgid "Miscellaneous" +msgstr "Diversaj" + +#: ../../include/datetime.php:131 ../../include/datetime.php:263 +msgid "year" +msgstr "jaro" + +#: ../../include/datetime.php:136 ../../include/datetime.php:264 +msgid "month" +msgstr "monato" + +#: ../../include/datetime.php:141 ../../include/datetime.php:266 +msgid "day" +msgstr "tago" + +#: ../../include/datetime.php:254 +msgid "never" +msgstr "neniam" + +#: ../../include/datetime.php:260 +msgid "less than a second ago" +msgstr "antaÅ­ malpli ol unu sekundo" + +#: ../../include/datetime.php:263 +msgid "years" +msgstr "jaroj" + +#: ../../include/datetime.php:264 +msgid "months" +msgstr "monatoj" + +#: ../../include/datetime.php:265 +msgid "week" +msgstr "semajno" + +#: ../../include/datetime.php:265 +msgid "weeks" +msgstr "semajnoj" + +#: ../../include/datetime.php:266 +msgid "days" +msgstr "tagoj" + +#: ../../include/datetime.php:267 +msgid "hour" +msgstr "horo" + +#: ../../include/datetime.php:267 +msgid "hours" +msgstr "horoj" + +#: ../../include/datetime.php:268 +msgid "minute" +msgstr "minuto" + +#: ../../include/datetime.php:268 +msgid "minutes" +msgstr "minutoj" + +#: ../../include/datetime.php:269 +msgid "second" +msgstr "sekundo" + +#: ../../include/datetime.php:269 +msgid "seconds" +msgstr "sekundoj" + +#: ../../include/datetime.php:278 +#, php-format +msgid "%1$d %2$s ago" +msgstr "antaÅ­ %1$d %2$s" + +#: ../../include/datetime.php:450 ../../include/items.php:1460 +#, php-format +msgid "%s's birthday" +msgstr "NaskiÄtago de %s" + +#: ../../include/datetime.php:451 ../../include/items.php:1461 +#, php-format +msgid "Happy Birthday %s" +msgstr "Feliĉan NaskiÄtagon al %s" + +#: ../../include/onepoll.php:399 +msgid "From: " +msgstr "De: " + +#: ../../include/bbcode.php:216 ../../include/bbcode.php:236 +msgid "$1 wrote:" +msgstr "$1 skribis:" + +#: ../../include/bbcode.php:251 ../../include/bbcode.php:328 +msgid "Image/photo" +msgstr "Bildo" + +#: ../../include/dba.php:41 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "Ne trovis DNS informojn por datumbaza servilo '%s'." + +#: ../../include/message.php:15 ../../include/message.php:171 +msgid "[no subject]" +msgstr "[neniu temo]" + +#: ../../include/acl_selectors.php:286 +msgid "Visible to everybody" +msgstr "Videbla al ĉiuj" + +#: ../../include/enotify.php:14 +msgid "Friendica Notification" +msgstr "Friendica Atentigo" + +#: ../../include/enotify.php:17 +msgid "Thank You," +msgstr "Dankon," + +#: ../../include/enotify.php:19 +#, php-format +msgid "%s Administrator" +msgstr "%s Administranto" + +#: ../../include/enotify.php:38 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:42 +#, php-format +msgid "[Friendica:Notify] New mail received at %s" +msgstr "[Friendica:Atentigo] Ricevis novan retpoÅton ĉe %s" + +#: ../../include/enotify.php:44 +#, php-format +msgid "%1$s sent you a new private message at %2$s." +msgstr "%1$s sendis al vi novan privatan mesaÄon ĉe %2$s." + +#: ../../include/enotify.php:45 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s sendis al vi %2$s." + +#: ../../include/enotify.php:45 +msgid "a private message" +msgstr "privatan mesaÄon" + +#: ../../include/enotify.php:46 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Bonvolu viziti %s por vidi aÅ­ respondi viajn privatajn mesaÄojn." + +#: ../../include/enotify.php:73 +#, php-format +msgid "%1$s commented on [url=%2$s]a %3$s[/url]" +msgstr "%1$s komentis pri [url=%2$s]%3$s[/url]" + +#: ../../include/enotify.php:80 +#, php-format +msgid "%1$s commented on [url=%2$s]%3$s's %4$s[/url]" +msgstr "%1$s komentis pri [url=%2$s]%4$s de %3$s[/url]" + +#: ../../include/enotify.php:88 +#, php-format +msgid "%1$s commented on [url=%2$s]your %3$s[/url]" +msgstr "%1$s komentis pri [url=%2$s]via %3$s[/url]" + +#: ../../include/enotify.php:98 +#, php-format +msgid "[Friendica:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Friendica:Atentigo] Komento pri konversacio #%1$d de %2$s" + +#: ../../include/enotify.php:99 +#, php-format +msgid "%s commented on an item/conversation you have been following." +msgstr "%s komentis pri elemento/konversacio kiun vi sekvas." + +#: ../../include/enotify.php:102 ../../include/enotify.php:117 +#: ../../include/enotify.php:130 ../../include/enotify.php:143 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Bonvolu viziti %s por vidi aÅ­ respondi la konversacion." + +#: ../../include/enotify.php:109 +#, php-format +msgid "[Friendica:Notify] %s posted to your profile wall" +msgstr "[Friendica:Atentigo] %s afiÅis al via profilmuro" + +#: ../../include/enotify.php:111 +#, php-format +msgid "%1$s posted to your profile wall at %2$s" +msgstr "%1$s skribis al via profilmuro ĉe %2$s" + +#: ../../include/enotify.php:113 +#, php-format +msgid "%1$s posted to [url=%2s]your wall[/url]" +msgstr "%1$s afiÅis al [url=%2s]via muro[/url]" + +#: ../../include/enotify.php:124 +#, php-format +msgid "[Friendica:Notify] %s tagged you" +msgstr "[Friendica:Atentigo] %s markis vin" + +#: ../../include/enotify.php:125 +#, php-format +msgid "%1$s tagged you at %2$s" +msgstr "%1$s markis vin ĉe %2$s" + +#: ../../include/enotify.php:126 +#, php-format +msgid "%1$s [url=%2$s]tagged you[/url]." +msgstr "%1$s [url=%2$s]markis vin[/url]." + +#: ../../include/enotify.php:137 +#, php-format +msgid "[Friendica:Notify] %s tagged your post" +msgstr "[Friendica:Atentigo] %s markis vian afiÅon" + +#: ../../include/enotify.php:138 +#, php-format +msgid "%1$s tagged your post at %2$s" +msgstr "%1$s markis vian afiÅon ĉe %2$s" + +#: ../../include/enotify.php:139 +#, php-format +msgid "%1$s tagged [url=%2$s]your post[/url]" +msgstr "%1$s markis [url=%2$s]vian afiÅon[/url]" + +#: ../../include/enotify.php:150 +msgid "[Friendica:Notify] Introduction received" +msgstr "[Friendica:Atentigo] Ricevis prezenton" + +#: ../../include/enotify.php:151 +#, php-format +msgid "You've received an introduction from '%1$s' at %2$s" +msgstr "Vi ricevis prezenton de '%1$s' ĉe %2$s" + +#: ../../include/enotify.php:152 +#, php-format +msgid "You've received [url=%1$s]an introduction[/url] from %2$s." +msgstr "Vi ricevis [url=%1$s]prezenton[/url] de %2$s." + +#: ../../include/enotify.php:155 ../../include/enotify.php:173 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Vi povas vidi la profilon de li aÅ­ Åi ĉe %s" + +#: ../../include/enotify.php:157 +#, php-format +msgid "Please visit %s to approve or reject the introduction." +msgstr "Bonvolu viziti %s por aprobi aÅ­ malaprobi la prezenton." + +#: ../../include/enotify.php:164 +msgid "[Friendica:Notify] Friend suggestion received" +msgstr "[Friendica:Atentigo] Ricevis amikosugeston" + +#: ../../include/enotify.php:165 +#, php-format +msgid "You've received a friend suggestion from '%1$s' at %2$s" +msgstr "Vi ricevis amikosugeston de '%1$s' ĉe %2$s" + +#: ../../include/enotify.php:166 +#, php-format +msgid "" +"You've received [url=%1$s]a friend suggestion[/url] for %2$s from %3$s." +msgstr "Vi ricevis [url=%1$s]amikosugeston[/url] pri %2$s de %3$s." + +#: ../../include/enotify.php:171 +msgid "Name:" +msgstr "Nomo:" + +#: ../../include/enotify.php:172 +msgid "Photo:" +msgstr "Bildo:" + +#: ../../include/enotify.php:175 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Bonvolu viziti %s por aprobi aÅ­ malaprobi la sugeston." + +#: ../../include/follow.php:32 +msgid "Connect URL missing." +msgstr "Ne ekzistas URL adreso por konekti." + +#: ../../include/follow.php:59 +msgid "" +"This site is not configured to allow communications with other networks." +msgstr "Tiu retpaÄo ne permesas komunikadon kun aliaj retoj." + +#: ../../include/follow.php:60 ../../include/follow.php:80 +msgid "No compatible communication protocols or feeds were discovered." +msgstr "Ne malkovris kongruajn protokolojn por komunikado aÅ­ fluojn." + +#: ../../include/follow.php:78 +msgid "The profile address specified does not provide adequate information." +msgstr "La specifita profiladreso ne enhavas sufiĉe da informoj." + +#: ../../include/follow.php:82 +msgid "An author or name was not found." +msgstr "Ne trovis aÅ­toron aÅ­ nomon." + +#: ../../include/follow.php:84 +msgid "No browser URL could be matched to this address." +msgstr "Neniu retuma URL adreso kongruas al la adreso." + +#: ../../include/follow.php:86 +msgid "" +"Unable to match @-style Identity Address with a known protocol or email " +"contact." +msgstr "Ne eblas kongrui @-stilan identecon adreson al iu konata protokolo au retpoÅtadreso." + +#: ../../include/follow.php:87 +msgid "Use mailto: in front of address to force email check." +msgstr "Uzu mailto: antaÅ­ la adreso por devigi la testadon per retpoÅto." + +#: ../../include/follow.php:93 +msgid "" +"The profile address specified belongs to a network which has been disabled " +"on this site." +msgstr "Tiu profila adreso apartenas al retejo kiu estas maÅaltita je ĉi tiu retejo." + +#: ../../include/follow.php:103 +msgid "" +"Limited profile. This person will be unable to receive direct/personal " +"notifications from you." +msgstr "Profilo limigata. Ĉi persono ne eblos ricevi rektajn/personajn atentigojn de vi. " + +#: ../../include/follow.php:205 +msgid "Unable to retrieve contact information." +msgstr "Ne eblas ricevi kontaktinformojn." + +#: ../../include/follow.php:259 +msgid "following" +msgstr "sekvanta" + +#: ../../include/items.php:2888 +msgid "A new person is sharing with you at " +msgstr "Nova persono kunhavigas kun vi ĉe " + +#: ../../include/items.php:2888 +msgid "You have a new follower at " +msgstr "Vi havas novan sekvanton ĉe " + +#: ../../include/items.php:3520 +msgid "Archives" +msgstr "Arkivoj" + +#: ../../include/user.php:38 +msgid "An invitation is required." +msgstr "Invio bezonata." + +#: ../../include/user.php:43 +msgid "Invitation could not be verified." +msgstr "Ne povis kontroli la inviton." + +#: ../../include/user.php:51 +msgid "Invalid OpenID url" +msgstr "Nevalida OpenID adreso" + +#: ../../include/user.php:66 +msgid "Please enter the required information." +msgstr "Bonvolu entajpi la bezonatajn informojn." + +#: ../../include/user.php:80 +msgid "Please use a shorter name." +msgstr "Bonvolu uzi pli mallongan nomon." + +#: ../../include/user.php:82 +msgid "Name too short." +msgstr "Nomo estas tro mallonga." + +#: ../../include/user.php:97 +msgid "That doesn't appear to be your full (First Last) name." +msgstr "Tio Åajne ne estas via plena (persona, familia) nomo." + +#: ../../include/user.php:102 +msgid "Your email domain is not among those allowed on this site." +msgstr "Via retpoÅtodomajno ne estas permesita ĉi tie." + +#: ../../include/user.php:105 +msgid "Not a valid email address." +msgstr "Nevalida retpoÅtadreso." + +#: ../../include/user.php:115 +msgid "Cannot use that email." +msgstr "Neuzebla retpoÅtadreso." + +#: ../../include/user.php:121 +msgid "" +"Your \"nickname\" can only contain \"a-z\", \"0-9\", \"-\", and \"_\", and " +"must also begin with a letter." +msgstr "Via kaÅnomo nur povas enhavi \"a-z\", \"0-9\", \"-\", kaj \"_\". Äœi ankaÅ­ devas komenci kun litero." + +#: ../../include/user.php:127 ../../include/user.php:225 +msgid "Nickname is already registered. Please choose another." +msgstr "Tio kaÅnomo jam estas registrita. Bonvolu elekti alian." + +#: ../../include/user.php:137 +msgid "" +"Nickname was once registered here and may not be re-used. Please choose " +"another." +msgstr "Tiu kaÅnomo iam estis registrita ĉi tie kaj ne ree uzeblas. Bonvolu elekti alian." + +#: ../../include/user.php:153 +msgid "SERIOUS ERROR: Generation of security keys failed." +msgstr "GRAVA ERARO: La generacio de sekurecaj ĉifroÅlosiloj malsukcesis." + +#: ../../include/user.php:211 +msgid "An error occurred during registration. Please try again." +msgstr "Eraro okazis dum registrado. Bonvolu provi denove." + +#: ../../include/user.php:246 +msgid "An error occurred creating your default profile. Please try again." +msgstr "Eraro okazi dum kreado de via defaÅ­lta profilo. Bonvolu provi denove." + +#: ../../include/security.php:21 +msgid "Welcome " +msgstr "Bonvenon " + +#: ../../include/security.php:22 +msgid "Please upload a profile photo." +msgstr "Bonvolu alÅuti profilbildon." + +#: ../../include/security.php:25 +msgid "Welcome back " +msgstr "Bonvenon " + +#: ../../include/security.php:329 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "La sekuriga ĵetono de la formo estis malÄusta. Tio verÅajne okazis ĉar la formo estis malfermita dum tro longa tempo (>3 horoj) antaÅ­ la sendado." + +#: ../../include/Contact.php:111 +msgid "stopped following" +msgstr "ne plu sekvas" + +#: ../../include/Contact.php:218 ../../include/conversation.php:842 +msgid "View Status" +msgstr "Vidi Staton" + +#: ../../include/Contact.php:219 ../../include/conversation.php:843 +msgid "View Profile" +msgstr "Vidi Profilon" + +#: ../../include/Contact.php:220 ../../include/conversation.php:844 +msgid "View Photos" +msgstr "Vidi Bildojn" + +#: ../../include/Contact.php:221 ../../include/Contact.php:234 +#: ../../include/conversation.php:845 +msgid "Network Posts" +msgstr "Enretaj AfiÅoj" + +#: ../../include/Contact.php:222 ../../include/Contact.php:234 +#: ../../include/conversation.php:846 +msgid "Edit Contact" +msgstr "Redakti Kontakton" + +#: ../../include/Contact.php:223 ../../include/Contact.php:234 +#: ../../include/conversation.php:847 +msgid "Send PM" +msgstr "Sendi PM" + +#: ../../include/conversation.php:163 +msgid "post/item" +msgstr "afiÅo/elemento" + +#: ../../include/conversation.php:164 +#, php-format +msgid "%1$s marked %2$s's %3$s as favorite" +msgstr "%1$s markis la %3$s de %2$s kiel preferita." + +#: ../../include/conversation.php:327 ../../include/conversation.php:608 +msgid "Select" +msgstr "Elekti" + +#: ../../include/conversation.php:344 ../../include/conversation.php:701 +#: ../../include/conversation.php:702 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Vidi la profilon de %s ĉe %s" + +#: ../../include/conversation.php:354 ../../include/conversation.php:713 +#, php-format +msgid "%s from %s" +msgstr "%s de %s" + +#: ../../include/conversation.php:369 +msgid "View in context" +msgstr "Vidi kun kunteksto" + +#: ../../include/conversation.php:475 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d komento" +msgstr[1] "%d komentoj" + +#: ../../include/conversation.php:554 +msgid "like" +msgstr "Åati" + +#: ../../include/conversation.php:555 +msgid "dislike" +msgstr "malÅati" + +#: ../../include/conversation.php:557 +msgid "Share this" +msgstr "Kunhavigi ĉi tiun" + +#: ../../include/conversation.php:557 +msgid "share" +msgstr "kunhavigi" + +#: ../../include/conversation.php:581 +msgid "Bold" +msgstr "Grasa" + +#: ../../include/conversation.php:582 +msgid "Italic" +msgstr "Kursiva" + +#: ../../include/conversation.php:583 +msgid "Underline" +msgstr "Substreki" + +#: ../../include/conversation.php:584 +msgid "Quote" +msgstr "Citaĵo" + +#: ../../include/conversation.php:585 +msgid "Code" +msgstr "Kodo" + +#: ../../include/conversation.php:586 +msgid "Image" +msgstr "Bildo" + +#: ../../include/conversation.php:587 +msgid "Link" +msgstr "Ligilo" + +#: ../../include/conversation.php:588 +msgid "Video" +msgstr "Video" + +#: ../../include/conversation.php:621 +msgid "add star" +msgstr "aldoni stelon" + +#: ../../include/conversation.php:622 +msgid "remove star" +msgstr "forpreni stelon" + +#: ../../include/conversation.php:623 +msgid "toggle star status" +msgstr "Åalti/malÅalti steloÅtato" + +#: ../../include/conversation.php:626 +msgid "starred" +msgstr "steligita" + +#: ../../include/conversation.php:627 +msgid "add tag" +msgstr "aldoni markon" + +#: ../../include/conversation.php:631 +msgid "save to folder" +msgstr "konservi en dosierujo" + +#: ../../include/conversation.php:703 +msgid "to" +msgstr "al" + +#: ../../include/conversation.php:704 +msgid "Wall-to-Wall" +msgstr "Muro-al-Muro" + +#: ../../include/conversation.php:705 +msgid "via Wall-To-Wall:" +msgstr "per Muro-al-Muro:" + +#: ../../include/conversation.php:750 +msgid "Delete Selected Items" +msgstr "ForviÅi Elektitajn Elementojn" + +#: ../../include/conversation.php:905 +#, php-format +msgid "%s likes this." +msgstr "%s Åatas tiun." + +#: ../../include/conversation.php:905 +#, php-format +msgid "%s doesn't like this." +msgstr "%s malÅatas tiun." + +#: ../../include/conversation.php:909 +#, php-format +msgid "%2$d people like this." +msgstr "%2$d homoj Åatas tiun." + +#: ../../include/conversation.php:911 +#, php-format +msgid "%2$d people don't like this." +msgstr "%2$d homojmalÅatas tiun." + +#: ../../include/conversation.php:917 +msgid "and" +msgstr "kaj" + +#: ../../include/conversation.php:920 +#, php-format +msgid ", and %d other people" +msgstr ", kaj %d aliaj homoj." + +#: ../../include/conversation.php:921 +#, php-format +msgid "%s like this." +msgstr "%s Åatas tiun." + +#: ../../include/conversation.php:921 +#, php-format +msgid "%s don't like this." +msgstr "%s malÅatas tiun." + +#: ../../include/conversation.php:946 +msgid "Visible to everybody" +msgstr "Videbla al ĉiuj" + +#: ../../include/conversation.php:948 +msgid "Please enter a video link/URL:" +msgstr "Bonvolu entajpi ligilon/adreson de video:" + +#: ../../include/conversation.php:949 +msgid "Please enter an audio link/URL:" +msgstr "Bonvolu entajpi ligilon/adreson de sono:" + +#: ../../include/conversation.php:950 +msgid "Tag term:" +msgstr "Markfrazo:" + +#: ../../include/conversation.php:952 +msgid "Where are you right now?" +msgstr "Kie vi estas nun?" + +#: ../../include/conversation.php:995 +msgid "upload photo" +msgstr "alÅuti bildon" + +#: ../../include/conversation.php:997 +msgid "attach file" +msgstr "kunsendi dosieron" + +#: ../../include/conversation.php:999 +msgid "web link" +msgstr "TTT ligilo" + +#: ../../include/conversation.php:1000 +msgid "Insert video link" +msgstr "Alglui ligilon de video" + +#: ../../include/conversation.php:1001 +msgid "video link" +msgstr "video ligilo" + +#: ../../include/conversation.php:1002 +msgid "Insert audio link" +msgstr "Alglui ligilon de sono" + +#: ../../include/conversation.php:1003 +msgid "audio link" +msgstr "sono ligilo" + +#: ../../include/conversation.php:1005 +msgid "set location" +msgstr "agordi lokon" + +#: ../../include/conversation.php:1007 +msgid "clear location" +msgstr "forviÅi lokon" + +#: ../../include/conversation.php:1014 +msgid "permissions" +msgstr "permesoj" + +#: ../../include/plugin.php:388 ../../include/plugin.php:390 +msgid "Click here to upgrade." +msgstr "Klaku ĉi tie por Äisdatigi." + +#: ../../include/plugin.php:396 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Tia ago preterpasas la limojn de via abono." + +#: ../../include/plugin.php:401 +msgid "This action is not available under your subscription plan." +msgstr "Tia ago ne estas permesita laÅ­ via abono." + +#: ../../boot.php:527 +msgid "Delete this item?" +msgstr "ForviÅi ĉi tiun elementon?" + +#: ../../boot.php:530 +msgid "show fewer" +msgstr "montri malpli" + +#: ../../boot.php:725 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "Malsukcesis Äisdatigi %s. Vidu la protokolojn." + +#: ../../boot.php:727 +#, php-format +msgid "Update Error at %s" +msgstr "Eraro dum Äisdatigo ĉe %s" + +#: ../../boot.php:827 +msgid "Create a New Account" +msgstr "Krei Novan Konton" + +#: ../../boot.php:851 +msgid "Nickname or Email address: " +msgstr "KaÅnomo aÅ­ retpoÅtadreso:" + +#: ../../boot.php:852 +msgid "Password: " +msgstr "Pasvorto:" + +#: ../../boot.php:855 +msgid "Or login using OpenID: " +msgstr "AÅ­ ensaluti per OpenID:" + +#: ../../boot.php:861 +msgid "Forgot your password?" +msgstr "Ĉu vi vorgesis vian pasvorton?" + +#: ../../boot.php:1028 +msgid "Edit profile" +msgstr "Redakti profilon" + +#: ../../boot.php:1088 +msgid "Message" +msgstr "MesaÄo" + +#: ../../boot.php:1204 ../../boot.php:1283 +msgid "g A l F d" +msgstr "\\j\\e \\l\\a G\\a \\h\\o\\r\\o, l F d" + +#: ../../boot.php:1205 ../../boot.php:1284 +msgid "F d" +msgstr "F d" + +#: ../../boot.php:1250 ../../boot.php:1324 +msgid "[today]" +msgstr "[hodiaÅ­]" + +#: ../../boot.php:1262 +msgid "Birthday Reminders" +msgstr "Memorigilo pri naskiÄtagoj" + +#: ../../boot.php:1263 +msgid "Birthdays this week:" +msgstr "NaskiÄtagoj ĉi-semajne:" + +#: ../../boot.php:1317 +msgid "[No description]" +msgstr "[Neniu priskribo]" + +#: ../../boot.php:1335 +msgid "Event Reminders" +msgstr "Memorigilo pri Okazoj" + +#: ../../boot.php:1336 +msgid "Events this week:" +msgstr "Okazoj ĉi-semajne:" + +#: ../../boot.php:1541 +msgid "Status Messages and Posts" +msgstr "ÅœtatmesaÄoj kaj AfiÅoj" + +#: ../../boot.php:1547 +msgid "Profile Details" +msgstr "Profildetaloj" + +#: ../../boot.php:1562 +msgid "Events and Calendar" +msgstr "Okazoj kaj Kalendaro" + +#: ../../boot.php:1568 +msgid "Only You Can See This" +msgstr "Nur Vi Povas Vidi Tiun" diff --git a/sources/view/eo/passchanged_eml.tpl b/sources/view/eo/passchanged_eml.tpl new file mode 100644 index 00000000..0d94be3c --- /dev/null +++ b/sources/view/eo/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Dear {{$username}}, + Your password has been changed as requested. Please retain this +information for your records (or change your password immediately to +something that you will remember). + + +Your login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +Password: {{$new_password}} + +You may change that password from your account settings page after logging in. + + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/eo/register_open_eml.tpl b/sources/view/eo/register_open_eml.tpl new file mode 100644 index 00000000..4b397201 --- /dev/null +++ b/sources/view/eo/register_open_eml.tpl @@ -0,0 +1,19 @@ + +An account has been created at {{$sitename}} for this email address. +The login details are as follows: + +Site Location: {{$siteurl}} +Login: {{$email}} +Password: (the password which was provided during registration) + +If this account was created without your knowledge and is not desired, you may +visit this site and reset the password. This will allow you to remove the +account from the links on the Settings page, and we +apologise for any inconvenience. + +Thank you and welcome to {{$sitename}}. + +Sincerely, + {{$sitename}} Administrator + + diff --git a/sources/view/eo/register_verify_eml.tpl b/sources/view/eo/register_verify_eml.tpl new file mode 100644 index 00000000..85d9a12d --- /dev/null +++ b/sources/view/eo/register_verify_eml.tpl @@ -0,0 +1,25 @@ + +A new user registration request was received at {{$sitename}} which requires +your approval. + + +The login details are as follows: + +Site Location: {{$siteurl}} +Login Name: {{$email}} +IP Address: {{$details}} + +To approve this request please visit the following link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +To deny the request and remove the account, please visit: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Thank you. + diff --git a/sources/view/eo/strings.php b/sources/view/eo/strings.php new file mode 100644 index 00000000..46649fcd --- /dev/null +++ b/sources/view/eo/strings.php @@ -0,0 +1,1771 @@ +strings["Post successful."] = "Sukcese afiÅita."; +$a->strings["[Embedded content - reload page to view]"] = "[Enigita enhavo - reÅargu paÄon por spekti Äin]"; +$a->strings["Contact settings applied."] = "Kontaktagordoj estas konservita."; +$a->strings["Contact update failed."] = "Äœisdatigo de kontakto malsukcesis."; +$a->strings["Permission denied."] = "Malpermesita."; +$a->strings["Contact not found."] = "Kontakto ne trovita."; +$a->strings["Repair Contact Settings"] = "Ripari kontaktagordoj."; +$a->strings["WARNING: This is highly advanced and if you enter incorrect information your communications with this contact may stop working."] = "AVERTO: Tio estas tre altnivela kaj se vi entajpus malÄustan informojn, komunikado kun la kontakto eble ne plu funkcios."; +$a->strings["Please use your browser 'Back' button now if you are uncertain what to do on this page."] = "Bonvolu klaki 'malantaÅ­en' en via retesplorilo nun se vi ne scias kion faru ĉi tie."; +$a->strings["Return to contact editor"] = "Reen al kontakta redaktilo"; +$a->strings["Name"] = "Nomo"; +$a->strings["Account Nickname"] = "KaÅnomo de la konto"; +$a->strings["@Tagname - overrides Name/Nickname"] = "@Marknomo - Transpasas nomon/kaÅnomon"; +$a->strings["Account URL"] = "Adreso de la konto"; +$a->strings["Friend Request URL"] = "Kontaktpeta adreso"; +$a->strings["Friend Confirm URL"] = "Kontaktkonfirma adreso"; +$a->strings["Notification Endpoint URL"] = "Finpunkta adreso por atentigoj"; +$a->strings["Poll/Feed URL"] = "Adreso de fluo"; +$a->strings["New photo from this URL"] = "Nova bildo el tiu adreso"; +$a->strings["Submit"] = "Sendi"; +$a->strings["Help:"] = "Helpo:"; +$a->strings["Help"] = "Helpo"; +$a->strings["Not Found"] = "Ne trovita"; +$a->strings["Page not found."] = "PaÄo ne trovita"; +$a->strings["File exceeds size limit of %d"] = "Dosiero estas pli granda ol la limito de %d"; +$a->strings["File upload failed."] = "AlÅutado malsukcesis."; +$a->strings["Friend suggestion sent."] = "Amikosugesto sendita."; +$a->strings["Suggest Friends"] = "Sugesti amikojn"; +$a->strings["Suggest a friend for %s"] = "Sugesti amikon por %s"; +$a->strings["Event title and start time are required."] = "Titolo kaj starttempo estas bezonataj por la okazo."; +$a->strings["l, F j"] = "l, F j"; +$a->strings["Edit event"] = "Redakti okazon"; +$a->strings["link to source"] = "ligilo al fonto"; +$a->strings["Events"] = "Okazoj"; +$a->strings["Create New Event"] = "Krei novan okazon"; +$a->strings["Previous"] = "antaÅ­a"; +$a->strings["Next"] = "sekva"; +$a->strings["hour:minute"] = "horo:minuto"; +$a->strings["Event details"] = "Detaloj de okazo"; +$a->strings["Format is %s %s. Starting date and Title are required."] = "Format is %s %s. Titolo kaj starttempo estas bezonataj."; +$a->strings["Event Starts:"] = "Okazo startas:"; +$a->strings["Required"] = "Bezonata"; +$a->strings["Finish date/time is not known or not relevant"] = "Fina dato/tempo ne estas konata aÅ­ ne bezonata"; +$a->strings["Event Finishes:"] = "Okazo finas:"; +$a->strings["Adjust for viewer timezone"] = "Agordi al horzono de la leganto"; +$a->strings["Description:"] = "Priskribo"; +$a->strings["Location:"] = "Loko:"; +$a->strings["Title:"] = "Titolo:"; +$a->strings["Share this event"] = "Kunhavigi la okazon"; +$a->strings["Cancel"] = "Nuligi"; +$a->strings["Tag removed"] = "Marko forviÅita"; +$a->strings["Remove Item Tag"] = "ForviÅi markon"; +$a->strings["Select a tag to remove: "] = "Elektu forviÅontan markon:"; +$a->strings["Remove"] = "ForviÅi"; +$a->strings["%s welcomes %s"] = "%s salutas %s"; +$a->strings["Authorize application connection"] = "Rajtigi programkonekton"; +$a->strings["Return to your app and insert this Securty Code:"] = "Reiru al via programo kaj entajpu la securecan kodon:"; +$a->strings["Please login to continue."] = "Bonvolu ensaluti por pluigi."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Ĉu rajtigi ĉi tiun programon por atingi viajn afiÅojn kaj kontaktojn kaj/aÅ­ krei novajn afiÅojn?"; +$a->strings["Yes"] = "Jes"; +$a->strings["No"] = "Ne"; +$a->strings["Photo Albums"] = "Bildalbumoj"; +$a->strings["Contact Photos"] = "Kontaktbildoj"; +$a->strings["Upload New Photos"] = "AlÅuti novajn bildojn"; +$a->strings["everybody"] = "ĉiuj"; +$a->strings["Contact information unavailable"] = "Kontaktoj informoj ne disponeblas"; +$a->strings["Profile Photos"] = "Profilbildoj"; +$a->strings["Album not found."] = "Albumo ne trovita."; +$a->strings["Delete Album"] = "ForviÅi albumon"; +$a->strings["Delete Photo"] = "ForviÅi bildon"; +$a->strings["was tagged in a"] = "estas markita en"; +$a->strings["photo"] = "bildo"; +$a->strings["by"] = "de"; +$a->strings["Image exceeds size limit of "] = "Bildo estas pli granda ol la limito de"; +$a->strings["Image file is empty."] = "Bilddosiero estas malplena."; +$a->strings["Unable to process image."] = "Ne eblas procedi la bildon."; +$a->strings["Image upload failed."] = "AlÅuto de bildo malsukcesis."; +$a->strings["Public access denied."] = "Publika atingo ne permesita."; +$a->strings["No photos selected"] = "Neniu bildoj elektita"; +$a->strings["Access to this item is restricted."] = "Atingo al tio elemento estas limigita."; +$a->strings["You have used %1$.2f Mbytes of %2$.2f Mbytes photo storage."] = "Vi uzas %1$.2f MB de %2$.2f MB bildkonservejo."; +$a->strings["You have used %1$.2f Mbytes of photo storage."] = "Vi uzas %1$.2f MB de bildkonservejo."; +$a->strings["Upload Photos"] = "AlÅuti bildojn"; +$a->strings["New album name: "] = "Nomo por nova albumo:"; +$a->strings["or existing album name: "] = "aÅ­ nomo de estanta albumo:"; +$a->strings["Do not show a status post for this upload"] = "Ne kreu statan afiÅon por tio alÅuto."; +$a->strings["Permissions"] = "Permesoj"; +$a->strings["Edit Album"] = "Redakti albumon"; +$a->strings["View Photo"] = "Vidi bildon"; +$a->strings["Permission denied. Access to this item may be restricted."] = "Malpermesita. Atingo al tio elemento eble estas limigita."; +$a->strings["Photo not available"] = "La bildo ne disponeblas"; +$a->strings["View photo"] = "Vidi bildon"; +$a->strings["Edit photo"] = "Redakti bildon"; +$a->strings["Use as profile photo"] = "Uzi kiel profilbildo"; +$a->strings["Private Message"] = "Privata mesaÄo"; +$a->strings["View Full Size"] = "Vidi plengrande "; +$a->strings["Tags: "] = "Markoj:"; +$a->strings["[Remove any tag]"] = "[ForviÅi iun markon]"; +$a->strings["Rotate CW (right)"] = "Turni horloÄdirekte (dekstren)"; +$a->strings["Rotate CCW (left)"] = "Turni kontraÅ­horloÄdirekte (maldekstren)"; +$a->strings["New album name"] = "Nova nomo de albumo"; +$a->strings["Caption"] = "Apudskribo"; +$a->strings["Add a Tag"] = "Aldoni markon"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"] = "Ekzemple: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"; +$a->strings["I like this (toggle)"] = "Mi Åatas tion (Åalti)"; +$a->strings["I don't like this (toggle)"] = "Mi malÅatas tion(Åalti)"; +$a->strings["Share"] = "Kunhavigi"; +$a->strings["Please wait"] = "Bonvolu atendi"; +$a->strings["This is you"] = "Tiu estas vi"; +$a->strings["Comment"] = "Komenti"; +$a->strings["Preview"] = "AntaÅ­rigardi"; +$a->strings["Delete"] = "ForviÅi"; +$a->strings["View Album"] = "Vidi albumon"; +$a->strings["Recent Photos"] = "Ì‚Ä´usaj bildoj"; +$a->strings["Not available."] = "Ne disponebla."; +$a->strings["Community"] = "Komunumo"; +$a->strings["No results."] = "Nenion trovita."; +$a->strings["This is Friendica, version"] = "Tio estas Friendica en la versio"; +$a->strings["running at web location"] = "instalita ĉe la adreso"; +$a->strings["Please visit Friendica.com to learn more about the Friendica project."] = "Bonvolu iri al Friendica.com por lerni pli pri la projekto Friendica"; +$a->strings["Bug reports and issues: please visit"] = "Cimraportoj kaj atendindaĵo: bonvolu iri al"; +$a->strings["Suggestions, praise, donations, etc. - please email \"Info\" at Friendica - dot com"] = "Sugestoj, laÅ­doj, donacoj ktp - bonvolu sendi mesÄon al \"Info\" ĉe Friendica - punkto com"; +$a->strings["Installed plugins/addons/apps:"] = "Instalitaj kromprogramoj/programoj:"; +$a->strings["No installed plugins/addons/apps"] = "Neniom da instalitaj aldonaĵoj/programoj"; +$a->strings["Item not found"] = "Elemento ne trovita"; +$a->strings["Edit post"] = "Redakti afiÅon"; +$a->strings["Post to Email"] = "Sendi per retpoÅto"; +$a->strings["Edit"] = "Redakti"; +$a->strings["Upload photo"] = "AlÅuti bildon"; +$a->strings["Attach file"] = "Kunligi dosieron"; +$a->strings["Insert web link"] = "Enmeti retan adreson"; +$a->strings["Insert YouTube video"] = "Enmeti videton ĉe YouTube"; +$a->strings["Insert Vorbis [.ogg] video"] = "Enmeti videton en formato Vorbis [.ogg]"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Enmeti sonon en formato Vorbis [.ogg]"; +$a->strings["Set your location"] = "Agordi vian lokon"; +$a->strings["Clear browser location"] = "ForviÅu retesplorilan lokon"; +$a->strings["Permission settings"] = "Permesagordoj"; +$a->strings["CC: email addresses"] = "CC: retpoÅtadresojn"; +$a->strings["Public post"] = "Publika afiÅo"; +$a->strings["Set title"] = "Redakti titolon"; +$a->strings["Categories (comma-separated list)"] = "Kategorioj (disigita per komo)"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Ekzemple: bob@example.com, mary@example.com"; +$a->strings["This introduction has already been accepted."] = "Tia prezento jam estas akceptita"; +$a->strings["Profile location is not valid or does not contain profile information."] = "La adreso de la profilo ne validas aÅ­ ne enhavas profilinformojn."; +$a->strings["Warning: profile location has no identifiable owner name."] = "Averto: La adreso de la profilo ne enhavas identeblan personan nomon."; +$a->strings["Warning: profile location has no profile photo."] = "Averto: La adreso de la profilo ne enhavas bildon."; +$a->strings["%d required parameter was not found at the given location"] = array( + 0 => "%d bezonataj parametroj ne trovita ĉe la donata adreso.", + 1 => "%d bezonataj parametroj ne trovita ĉe la donata adreso.", +); +$a->strings["Introduction complete."] = "Prezento sukcesis."; +$a->strings["Unrecoverable protocol error."] = "NeÄustigebla eraro en protokolo."; +$a->strings["Profile unavailable."] = "Profilo ne estas disponebla."; +$a->strings["%s has received too many connection requests today."] = "%s hodiaÅ­ ricevis tro multe da konektpetoj."; +$a->strings["Spam protection measures have been invoked."] = "KontraÅ­spamilo estas aktivita."; +$a->strings["Friends are advised to please try again in 24 hours."] = "Amikoj, vi bonvolu ripeti post 24 horoj."; +$a->strings["Invalid locator"] = "Nevalida adreso."; +$a->strings["Invalid email address."] = "Nevalida repoÅtadreso."; +$a->strings["This account has not been configured for email. Request failed."] = "La konto ne estas agordita por retpoÅto. La peto malsukcesis."; +$a->strings["Unable to resolve your name at the provided location."] = "Via nomo ne troveblas al la donita adreso."; +$a->strings["You have already introduced yourself here."] = "Vi vin jam prezentis tie."; +$a->strings["Apparently you are already friends with %s."] = "Åœajnas kvazaÅ­ vi jam amikiÄis kun %s."; +$a->strings["Invalid profile URL."] = "Nevalida adreso de profilo."; +$a->strings["Disallowed profile URL."] = "Malpermesita adreso de profilo."; +$a->strings["Failed to update contact record."] = "Äœisdatigo de via kontaktrikordo malsukcesis."; +$a->strings["Your introduction has been sent."] = "Via prezento estas sendita."; +$a->strings["Please login to confirm introduction."] = "Bonvolu ensaluti por jesigi la prezenton."; +$a->strings["Incorrect identity currently logged in. Please login to this profile."] = "MalÄusta identaĵo ensalutata. Bonvolu ensaluti en tiun profilon."; +$a->strings["Hide this contact"] = "KaÅi tiun kontakton"; +$a->strings["Welcome home %s."] = "Bonvenon hejme, %s."; +$a->strings["Please confirm your introduction/connection request to %s."] = "Bonvolu konfirmi vian prezenton / kontaktpeton al %s."; +$a->strings["Confirm"] = "Konfirmi."; +$a->strings["[Name Withheld]"] = "[KaÅita nomo]"; +$a->strings["Please enter your 'Identity Address' from one of the following supported communications networks:"] = "Bonvolu entajpi vian 'Identecan Adreson' de iu de tiuj subtenataj komunikaj retejoj: "; +$a->strings["Connect as an email follower (Coming soon)"] = "Konektu kiel retpoÅta sekvanto (BaldaÅ­ venos)"; +$a->strings["If you are not yet a member of the free social web, follow this link to find a public Friendica site and join us today."] = "Se vi ne estas membro de la libra interkona reto, sekvu ĉi-ligilon por trovi publikan Friendica retejon kaj aliÄi kun ni hodiaÅ­."; +$a->strings["Friend/Connection Request"] = "Prezento / Konektpeto"; +$a->strings["Examples: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca"] = "Ekzemploj: jojo@demo.friendica.com, http://demo.friendica.com/profile/jojo, testuser@identi.ca"; +$a->strings["Please answer the following:"] = "Bonvolu respondi:"; +$a->strings["Does %s know you?"] = "Ĉu %s konas vin?"; +$a->strings["Add a personal note:"] = "Aldoni personan noton:"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["StatusNet/Federated Social Web"] = "StatusNet/Federaciaj interkonaj retejoj"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings[" - please do not use this form. Instead, enter %s into your Diaspora search bar."] = " - bonvolu ne uzi ĉi formo. AnstataÅ­e, entajpu %s en la Diaspora serĉilo."; +$a->strings["Your Identity Address:"] = "Via identeca adreso:"; +$a->strings["Submit Request"] = "Sendi peton"; +$a->strings["Friendica Social Communications Server - Setup"] = "Friendica Interkona Komunikada Servilo - Instalo"; +$a->strings["Could not connect to database."] = "Ne eblas konekti la datumbazon."; +$a->strings["Could not create table."] = "Ne eblas krei tabelon."; +$a->strings["Your Friendica site database has been installed."] = "La datumbazo de vi Friendica retjo estas instalita."; +$a->strings["You may need to import the file \"database.sql\" manually using phpmyadmin or mysql."] = "Vi bezonas mane importi la dosieron \"database.sql\" per phpmyadmin aÅ­ mysql."; +$a->strings["Please see the file \"INSTALL.txt\"."] = "Bonvolu legi la dosieron \"INSTALL.txt\"."; +$a->strings["System check"] = "Sistema kontrolo"; +$a->strings["Check again"] = "Ree kontroli"; +$a->strings["Database connection"] = "Datumbaza konekto"; +$a->strings["In order to install Friendica we need to know how to connect to your database."] = "Por instali Friendica, ni bezonas scii kiel konekti al via datumbazo."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Bonvolu kontakti vian servilprovizanton aÅ­ administranton se vi havas demandoj pri ĉi tiaj agordoj."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "La datumbazo nomata malsupren jam ekzistu. Se Äi ne ekzistas, bonvolu unue krei Äin antaÅ­ progresi."; +$a->strings["Database Server Name"] = "Nomo de datumbaza servilo."; +$a->strings["Database Login Name"] = "Salutnomo ĉe la datumbazo."; +$a->strings["Database Login Password"] = "Pasvorto ĉe la datumbazo."; +$a->strings["Database Name"] = "Nomo de la datumbazo."; +$a->strings["Site administrator email address"] = "RetpoÅtadreso de la reteja administranto"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "La repoÅtadreso de via konto bezonas esti la sama por uzi la TTTa administrilo."; +$a->strings["Please select a default timezone for your website"] = "Bonvolu elekti defaÅ­ltan horzonon por via retejo."; +$a->strings["Site settings"] = "Retejaj agordoj"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Komanda linia versio de PHP ne trovita en $PATH de la retservilo."; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron. See 'Activating scheduled tasks'"] = "Se vi ne havas komandlinian version de PHP sur la servilo, vi ne eblas plenumi fonan planitan enketon per cron. Bonvolu legi 'Activating scheduled tasks'"; +$a->strings["PHP executable path"] = "Vojo de la komanda linia versio de PHP"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Entajpu la plenan vojon al la php komandodosiero. Vi eblas lasi tion malplena por pluigi la instalado."; +$a->strings["Command line PHP"] = "komanda linia versio de PHP"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "En via komanda linia versio de PHP je via sistemo, \"register_argc_argv\" ne estas aktivita."; +$a->strings["This is required for message delivery to work."] = "Tio estas bezonata por la livero de mesaÄoj."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Eraro: La funkcio \"openssl_pkey_new\" je tia sistemo ne eblas generi ĉifroÅlosilojn."; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Se la operaciumo sistemo estas Windows, bonvolu legi: http://www.php.net/manual/en/openssl.installation.php"; +$a->strings["Generate encryption keys"] = "Generi ĉifroÅlosilojn"; +$a->strings["libCurl PHP module"] = "PHP modulo libCurl"; +$a->strings["GD graphics PHP module"] = "PHP modulo GD"; +$a->strings["OpenSSL PHP module"] = "PHP modulo OpenSSL"; +$a->strings["mysqli PHP module"] = "PHP modulo mysqli"; +$a->strings["mb_string PHP module"] = "PHP modulo mb_string"; +$a->strings["Apache mod_rewrite module"] = "Apache mod_rewrite modulo"; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Eraro: La modulo mod_rewrite en la Apache retservilo estas bezonata sed ne instalita."; +$a->strings["Error: libCURL PHP module required but not installed."] = "Eraro: La modulo libCURL en PHP estas bezonata sed ne instalita."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Eraro: La modulo GD en PHP kun subteno por JPEG estas bezonata sed ne instalita."; +$a->strings["Error: openssl PHP module required but not installed."] = "Eraro: La modulo OpenSSL en PHP estas bezonata sed ne instalita."; +$a->strings["Error: mysqli PHP module required but not installed."] = "Eraro: La modulo mysqli en PHP estas bezonata sed ne instalita."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Eraro: La modulo mb_string en PHP estas bezonata sed ne instalita."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\ in the top folder of your web server and it is unable to do so."] = "La reta instalilo bezonas skribi dosieron nomata \".htconfig.php\" en la baza dosierujo de la retservilo, sed ne sukcesis."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Tio ĉi plej ofte estas agordo rilate al permesoj, ĉar la servilo eble ne povas skribi en via dosierujo, eĉ se vi mem povas skribi."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Friendica top folder."] = "Post la fino de tiu proceduro, ni donos al vi tekston por konservi en dosiero .htconfig.php en via baza Friendica dosierujo."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"INSTALL.txt\" for instructions."] = "Vi ankaÅ­ povas preterpasi tiun proceduron kaj fari permanan instaladon. Bonvolu legi la dosieron \"INSTALL.txt\" por trovi instrukciojn."; +$a->strings[".htconfig.php is writable"] = ".htconfig.php estas skribebla."; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration."] = "Url rewrite en .htaccess ne funkcias. Kontrolu la agordojn de la servilo."; +$a->strings["Url rewrite is working"] = "URL rewrite funkcias."; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Ne povis skribi la datumbaza agordoj en la dosiero \".htconfig.php\". Bonvolu uzi la inkluzivan tekston por krei agordan dosieron en la baza dosierujo de la retservilo."; +$a->strings["Errors encountered creating database tables."] = "Okazis eraroj dum la kreado de tabeloj en la datumbazo."; +$a->strings["

    What next

    "] = "

    Kio sekvas nun?

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "GRAVA: Vi bezonas [mane] agordi planitan taskon por la Friendica poller."; +$a->strings["l F d, Y \\@ g:i A"] = "l F d, Y \\@ g:i A"; +$a->strings["Time Conversion"] = "Konverto de tempo"; +$a->strings["Friendika provides this service for sharing events with other networks and friends in unknown timezones."] = "Friendica provizas tiun servon por kunhavigi okazojn kun aliaj retoj kaj amikoj en aliaj horzonoj."; +$a->strings["UTC time: %s"] = "UTC horo: %s"; +$a->strings["Current timezone: %s"] = "Aktuala horzono: %s"; +$a->strings["Converted localtime: %s"] = "Konvertita loka horo: %s"; +$a->strings["Please select your timezone:"] = "Bonvolu elekti vian horzonon:"; +$a->strings["Profile Match"] = "Kongrua profilo"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "Neniom da kategoriaj vortoj kongruas. Bonvolu aldoni kategoriajn vortojn al via defaÅ­lta profilo."; +$a->strings["is interested in:"] = "interesiÄas pri:"; +$a->strings["Connect"] = "Konekti"; +$a->strings["No matches"] = "Nenio estas trovita"; +$a->strings["Remote privacy information not available."] = "Informoj pri fora privateca ne estas disponebla."; +$a->strings["Visible to:"] = "Videbla al:"; +$a->strings["Welcome to %s"] = "Bonvenon ĉe %s"; +$a->strings["Invalid request identifier."] = "Nevalida peta identigilo."; +$a->strings["Discard"] = "ForviÅi"; +$a->strings["Ignore"] = "Ignori"; +$a->strings["System"] = "Sistemo"; +$a->strings["Network"] = "Reto"; +$a->strings["Personal"] = "Propra"; +$a->strings["Home"] = "Hejmo"; +$a->strings["Introductions"] = "Prezentoj"; +$a->strings["Messages"] = "MesaÄoj"; +$a->strings["Show Ignored Requests"] = "Montri ignoritajn petojn"; +$a->strings["Hide Ignored Requests"] = "KaÅi ignoritajn petojn"; +$a->strings["Notification type: "] = "Tipo de atentigo:"; +$a->strings["Friend Suggestion"] = "Amikosugestoj"; +$a->strings["suggested by %s"] = "sugestita de %s"; +$a->strings["Hide this contact from others"] = "KaÅi ĉi tiun kontakton al aliaj"; +$a->strings["Post a new friend activity"] = "AfiÅi novan amikecan aktivecon"; +$a->strings["if applicable"] = "se aplikebla"; +$a->strings["Approve"] = "Aprobi"; +$a->strings["Claims to be known to you: "] = "Pensas ke vi konas ilin:"; +$a->strings["yes"] = "jes"; +$a->strings["no"] = "ne"; +$a->strings["Approve as: "] = "Aprobi kiel:"; +$a->strings["Friend"] = "Amiko"; +$a->strings["Sharer"] = "Kunhaviganto"; +$a->strings["Fan/Admirer"] = "Fanatikulo/Admiranto"; +$a->strings["Friend/Connect Request"] = "Kontaktpeto"; +$a->strings["New Follower"] = "Nova abonanto"; +$a->strings["No introductions."] = "Neniom da prezentoj"; +$a->strings["Notifications"] = "Atentigoj"; +$a->strings["%s liked %s's post"] = "%s Åatis la afiÅon de %s"; +$a->strings["%s disliked %s's post"] = "%s malÅatis la afiÅon de %s"; +$a->strings["%s is now friends with %s"] = "%s amikiÄis kun %s"; +$a->strings["%s created a new post"] = "%s kreis novan afiÅon"; +$a->strings["%s commented on %s's post"] = "%s komentis pri la afiÅo de %s"; +$a->strings["No more network notifications."] = "Ne pli da retaj atentigoj."; +$a->strings["Network Notifications"] = "Retaj Atentigoj"; +$a->strings["No more system notifications."] = "Ne pli da sistemaj atentigoj."; +$a->strings["System Notifications"] = "Sistemaj Atentigoj"; +$a->strings["No more personal notifications."] = "Ne pli da personaj atentigoj"; +$a->strings["Personal Notifications"] = "Personaj Atentigoj"; +$a->strings["No more home notifications."] = "Ne pli da hejmrilataj atentigoj."; +$a->strings["Home Notifications"] = "Hejmrilataj atentigoj"; +$a->strings["Could not access contact record."] = "Ne eblis atingi kontaktrikordo."; +$a->strings["Could not locate selected profile."] = "Ne trovis elektitan profilon."; +$a->strings["Contact updated."] = "Kontakto estas Äisdatigita."; +$a->strings["Contact has been blocked"] = "Kontakto estas blokita."; +$a->strings["Contact has been unblocked"] = "Kontakto estas malblokita."; +$a->strings["Contact has been ignored"] = "Kontakto estas ignorita."; +$a->strings["Contact has been unignored"] = "Kontakto estas malignorita."; +$a->strings["Contact has been archived"] = "Enarkivigis kontakton"; +$a->strings["Contact has been unarchived"] = "Elarkivigis kontakton"; +$a->strings["Contact has been removed."] = "Kontakto estas forigita."; +$a->strings["You are mutual friends with %s"] = "Vi estas reciproka amiko de %s"; +$a->strings["You are sharing with %s"] = "Vi kunhavigas kun %s"; +$a->strings["%s is sharing with you"] = "%s kunhavigas kun vi"; +$a->strings["Private communications are not available for this contact."] = "Privataj komunikadoj ne disponeblas por ĉi tiu kontakto."; +$a->strings["Never"] = "Neniam"; +$a->strings["(Update was successful)"] = "(Äœisdatigo sukcesis.)"; +$a->strings["(Update was not successful)"] = "(Äœisdatigo malsukcesis.)"; +$a->strings["Suggest friends"] = "Sugesti amikojn"; +$a->strings["Network type: %s"] = "Reta tipo: %s"; +$a->strings["%d contact in common"] = array( + 0 => "%d komuna kontakto", + 1 => "%d komunaj kontaktoj", +); +$a->strings["View all contacts"] = "Vidi ĉiujn kontaktojn"; +$a->strings["Unblock"] = "Malbloki"; +$a->strings["Block"] = "Bloki"; +$a->strings["Toggle Blocked status"] = "Åœalti/malÅalti Blokitan staton"; +$a->strings["Unignore"] = "Malignori"; +$a->strings["Toggle Ignored status"] = "Åœalti/malÅalti Ignoritan staton"; +$a->strings["Unarchive"] = "Elarkivigi"; +$a->strings["Archive"] = "Enarkivigi"; +$a->strings["Toggle Archive status"] = "Åœalti/malÅalti Enarkivigitan staton"; +$a->strings["Repair"] = "Ripari"; +$a->strings["Advanced Contact Settings"] = "Specialaj Kontaktagordoj"; +$a->strings["Communications lost with this contact!"] = "Mi perdis la kommunikadon kun tiu kontakto!"; +$a->strings["Contact Editor"] = "Kontakta redaktilo."; +$a->strings["Profile Visibility"] = "Videbleco de profilo"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Bonvolu elekti la profilon kiu vi volas montri al %s aspektinde kiam sekure aspektante vian profilon."; +$a->strings["Contact Information / Notes"] = "Kontaktaj informoj / Notoj"; +$a->strings["Edit contact notes"] = "Redakti kontaktnotojn"; +$a->strings["Visit %s's profile [%s]"] = "Viziti la profilon de %s [%s]"; +$a->strings["Block/Unblock contact"] = "Bloki/Malbloki kontakton"; +$a->strings["Ignore contact"] = "Ignori kontakton"; +$a->strings["Repair URL settings"] = "Ripari URL agordoj"; +$a->strings["View conversations"] = "Vidi konversaciojn"; +$a->strings["Delete contact"] = "ForviÅi kontakton"; +$a->strings["Last update:"] = "Plej ĵusa Äisdatigo:"; +$a->strings["Update public posts"] = "Äœisdatigi publikajn afiÅojn"; +$a->strings["Update now"] = "Äœisdatigi nun"; +$a->strings["Currently blocked"] = "Nuntempe blokata"; +$a->strings["Currently ignored"] = "Nuntempe ignorata"; +$a->strings["Currently archived"] = "Nuntempe enarkivigita"; +$a->strings["Replies/likes to your public posts may still be visible"] = "Rispondoj/Åataĵo al viaj publikaj afiÅoj eble plu estos videbla"; +$a->strings["Suggestions"] = "Sugestoj"; +$a->strings["Suggest potential friends"] = "Sugesti amikojn"; +$a->strings["All Contacts"] = "Ĉiuj Kontaktoj"; +$a->strings["Show all contacts"] = "Montri ĉiujn kontaktojn"; +$a->strings["Unblocked"] = "Malblokita"; +$a->strings["Only show unblocked contacts"] = "Nur montri neblokitajn kontaktojn"; +$a->strings["Blocked"] = "Blokita"; +$a->strings["Only show blocked contacts"] = "Nur montri blokitajn kontaktojn"; +$a->strings["Ignored"] = "Ignorita"; +$a->strings["Only show ignored contacts"] = "Nur montri ignoritajn kontaktojn"; +$a->strings["Archived"] = "Enarkivigita"; +$a->strings["Only show archived contacts"] = "Nur montri enarkivigitajn kontaktojn"; +$a->strings["Hidden"] = "KaÅita"; +$a->strings["Only show hidden contacts"] = "Nur montri kaÅitajn kontaktojn"; +$a->strings["Mutual Friendship"] = "Reciproka amikeco"; +$a->strings["is a fan of yours"] = "estas admiranto de vi"; +$a->strings["you are a fan of"] = "vi estas admiranto de"; +$a->strings["Edit contact"] = "Redakti kontakton"; +$a->strings["Contacts"] = "Kontaktoj"; +$a->strings["Search your contacts"] = "Serĉi viajn kontaktojn"; +$a->strings["Finding: "] = "Trovata:"; +$a->strings["Find"] = "Trovi"; +$a->strings["No valid account found."] = "Ne trovis validan konton."; +$a->strings["Password reset request issued. Check your email."] = "Eldonis riparadon de pasvorto. Legu vian retpoÅton."; +$a->strings["Password reset requested at %s"] = "Pasvorta riparado petita je %s"; +$a->strings["Administrator"] = "Administranto"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "Ne povis konfirmi la peton. (Eble vi sendis Äin antaÅ­.) Pasvorta riparado malsukcesis."; +$a->strings["Password Reset"] = "Pasvorta riparado"; +$a->strings["Your password has been reset as requested."] = "Via pasvorto estis riparita laÅ­ via peto."; +$a->strings["Your new password is"] = "Via nova pasvorto estas"; +$a->strings["Save or copy your new password - and then"] = "Memorigi vian novan pasvorton - kaj poste"; +$a->strings["click here to login"] = "klaku ĉi tie por ensaluti"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Vi povas Åangi vian pasvorton sur la paÄo agordoj kiam vi sukcese ensalutis."; +$a->strings["Forgot your Password?"] = "Ĉu vi forgesis vian pasvorton?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Entajpu vian retpoÅtadreson kaj sendu por pasvorta riparado. Poste, bonvolu legi vian retpoÅton por trovi pliajn instrukciojn."; +$a->strings["Nickname or Email: "] = "Salutnomo aÅ­ retpoÅtadreso: "; +$a->strings["Reset"] = "Repari"; +$a->strings["Account settings"] = "Konto"; +$a->strings["Display settings"] = "Ekrano"; +$a->strings["Connector settings"] = "Konektiloj"; +$a->strings["Plugin settings"] = "Kromprogramoj"; +$a->strings["Connected apps"] = "Konektitaj programoj"; +$a->strings["Export personal data"] = "Eksporto"; +$a->strings["Remove account"] = "Forigi konton"; +$a->strings["Settings"] = "Agordoj"; +$a->strings["Missing some important data!"] = "Mankas importantaj datumoj!"; +$a->strings["Update"] = "Äœisdatigi"; +$a->strings["Failed to connect with email account using the settings provided."] = "Ne sukcesis konekti al retpoÅtkonto kun la provizitaj agordoj."; +$a->strings["Email settings updated."] = "RetpoÅtagordoj Äisdatigita"; +$a->strings["Passwords do not match. Password unchanged."] = "La pasvortoj ne estas egala. Pasvorto ne ÅanÄita."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Malplenaj pasvortoj ne estas permesita. Pasvorto ne ÅanÄita."; +$a->strings["Password changed."] = "Pasvorto ÅanÄita."; +$a->strings["Password update failed. Please try again."] = "Äœisdatigo de pasvorto malsukcesis. Bonvolu provi refoje."; +$a->strings[" Please use a shorter name."] = " Bonvolu uzi pli mallongan nomon."; +$a->strings[" Name too short."] = " Nomo estas tro mallonga."; +$a->strings[" Not valid email."] = " RepoÅtadreso ne validas."; +$a->strings[" Cannot change to that email."] = " Ne povas ÅanÄi al tio retpoÅtadreso."; +$a->strings["Private forum has no privacy permissions. Using default privacy group."] = "Privata forumo ne havas privatecajn agordojn. DefaÅ­lta privateca grupo estas uzata."; +$a->strings["Private forum has no privacy permissions and no default privacy group."] = "Privata forumo havas nek privatecajn agordojn nek defaÅ­ltan privatecan grupon."; +$a->strings["Settings updated."] = "Agordoj Äisdatigita."; +$a->strings["Add application"] = "Aldoni programon"; +$a->strings["Consumer Key"] = "Åœlosilo de kliento"; +$a->strings["Consumer Secret"] = "Sekreto de kliento"; +$a->strings["Redirect"] = "Alidirekto"; +$a->strings["Icon url"] = "Piktograma adreso"; +$a->strings["You can't edit this application."] = "Ĉi tio programo ne estas redaktebla."; +$a->strings["Connected Apps"] = "Konektitaj Programoj"; +$a->strings["Client key starts with"] = "Åœlosilo de kliento komencas kun"; +$a->strings["No name"] = "Neniu nomo"; +$a->strings["Remove authorization"] = "ForviÅi rajtigon"; +$a->strings["No Plugin settings configured"] = "Neniom da kromprogramoagordoj farita"; +$a->strings["Plugin Settings"] = "Kromprogramoagordoj"; +$a->strings["Built-in support for %s connectivity is %s"] = "Integrita subteno por %s koneto estas %s"; +$a->strings["enabled"] = "Åaltita"; +$a->strings["disabled"] = "malÅaltita"; +$a->strings["StatusNet"] = "StatusNet"; +$a->strings["Email access is disabled on this site."] = "RetpoÅta atingo ne disponeblas ĉi tie."; +$a->strings["Connector Settings"] = "Konektiloagordoj"; +$a->strings["Email/Mailbox Setup"] = "Agordoj pri RetpoÅto"; +$a->strings["If you wish to communicate with email contacts using this service (optional), please specify how to connect to your mailbox."] = "Se vi volas uzi ĉi tiun servon por komuniki per retpoÅto (nedeviga), bonvolu specifi kiel konekti al vian retpoÅtkonton."; +$a->strings["Last successful email check:"] = "Plej ĵusa sukcesa kontrolo de poÅto:"; +$a->strings["IMAP server name:"] = "Nomo de IMAP servilo:"; +$a->strings["IMAP port:"] = "Numero de IMAP pordo:"; +$a->strings["Security:"] = "Sekureco:"; +$a->strings["None"] = "Nenio"; +$a->strings["Email login name:"] = "RetpoÅta salutnomo:"; +$a->strings["Email password:"] = "RetpoÅta pasvorto:"; +$a->strings["Reply-to address:"] = "Responda adreso (Reply-to):"; +$a->strings["Send public posts to all email contacts:"] = "Sendu publikajn afiÅojn al ĉiuj retpoÅtkontaktoj:"; +$a->strings["Action after import:"] = "Ago post la importado:"; +$a->strings["Mark as seen"] = "Marki kiel legita"; +$a->strings["Move to folder"] = "Movi al dosierujo"; +$a->strings["Move to folder:"] = "Movi al dosierujo:"; +$a->strings["Display Settings"] = "Ekranagordoj"; +$a->strings["Display Theme:"] = "Vidiga etoso:"; +$a->strings["Update browser every xx seconds"] = "Äœisdatigu retesplorilon ĉiu xxx sekundoj"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Minimume 10 sekundoj, sen maksimumo"; +$a->strings["Number of items to display on the network page:"] = "Kvanto da elementoj kiuj estos montrata ĉe la reto paÄo."; +$a->strings["Maximum of 100 items"] = "Maksimume 100 eroj"; +$a->strings["Don't show emoticons"] = "Ne montru ridetulojn"; +$a->strings["Normal Account Page"] = "Normala KontopaÄo"; +$a->strings["This account is a normal personal profile"] = "Tiu konto estas normala persona profilo"; +$a->strings["Soapbox Page"] = "Soapbox PaÄo"; +$a->strings["Automatically approve all connection/friend requests as read-only fans"] = "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel nurlegaj admirantoj"; +$a->strings["Community Forum/Celebrity Account"] = "Komunuma Forumo/Eminentula Konto"; +$a->strings["Automatically approve all connection/friend requests as read-write fans"] = "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel admirantoj kapable legi kaj skribi"; +$a->strings["Automatic Friend Page"] = "AÅ­tomata Amiko PaÄo"; +$a->strings["Automatically approve all connection/friend requests as friends"] = "AÅ­tomate konfirmi ĉiujn kontaktpetojn kiel amikoj"; +$a->strings["Private Forum [Experimental]"] = "Privata Forumo [eksperimenta]"; +$a->strings["Private forum - approved members only"] = "Privata forumo - nur por aprobitaj membroj"; +$a->strings["OpenID:"] = "OpenID:"; +$a->strings["(Optional) Allow this OpenID to login to this account."] = "(Nedeviga) Permesi atingon al la konton al ĉi tio OpenID."; +$a->strings["Publish your default profile in your local site directory?"] = "Publikigi vian defaÅ­ltan profilon en la loka reteja katalogo?"; +$a->strings["Publish your default profile in the global social directory?"] = "Publikigi vian defaÅ­ltan profilon en la tutmonda interkona katalogo?"; +$a->strings["Hide your contact/friend list from viewers of your default profile?"] = "KaÅi vian liston de kontaktoj/amiko al spektantoj de via defaÅ­lta profilo?"; +$a->strings["Hide your profile details from unknown viewers?"] = "KaÅi viajn profilajn detalojn al nekonataj spektantoj?"; +$a->strings["Allow friends to post to your profile page?"] = "Ĉu amikoj povu afiÅi al via profilo?"; +$a->strings["Allow friends to tag your posts?"] = "Ĉu amikoj povu aldoni markojn al viaj afiÅoj?"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Ĉu ni povu sugesti vin kiel amiko al novaj membroj?"; +$a->strings["Permit unknown people to send you private mail?"] = "Permesigi nekonatulojn sendi retpoÅton al vi?"; +$a->strings["Profile is not published."] = "Profilo ne estas publika."; +$a->strings["or"] = "aÅ­"; +$a->strings["Your Identity Address is"] = "Via identeca adreso estas"; +$a->strings["Automatically expire posts after this many days:"] = "Automatike senvalidigi afiÅojn post tiom da tagoj:"; +$a->strings["If empty, posts will not expire. Expired posts will be deleted"] = "Se malplena, afiÅoj neniam senvalidiÄos. Senvalidigitajn afiÅon estos forviÅata"; +$a->strings["Advanced expiration settings"] = "Detalaj agordoj rilate al senvalidiÄo"; +$a->strings["Advanced Expiration"] = "Detala senvalidiÄo"; +$a->strings["Expire posts:"] = "Senvalidigi afiÅojn:"; +$a->strings["Expire personal notes:"] = "Senvalidigi personajn notojn:"; +$a->strings["Expire starred posts:"] = "Senvalidigi steligitajn afiÅojn:"; +$a->strings["Expire photos:"] = "Senvalidigi bildojn:"; +$a->strings["Only expire posts by others:"] = "Nur senvalidigi afiÅojn de aliaj: "; +$a->strings["Account Settings"] = "Kontoagordoj"; +$a->strings["Password Settings"] = "Agordoj pri Pasvorto"; +$a->strings["New Password:"] = "Nova pasvorto:"; +$a->strings["Confirm:"] = "Konfirmi:"; +$a->strings["Leave password fields blank unless changing"] = "Lasu pasvortkampojn malplenaj se vi ne ÅanÄas la pasvorton."; +$a->strings["Basic Settings"] = "Bazaj Agordoj"; +$a->strings["Full Name:"] = "Plena Nomo:"; +$a->strings["Email Address:"] = "RetpoÅtadreso:"; +$a->strings["Your Timezone:"] = "Via Horzono:"; +$a->strings["Default Post Location:"] = "DefaÅ­lta Loko por AfiÅoj:"; +$a->strings["Use Browser Location:"] = "Uzu Lokon laÅ­ Retesplorilo:"; +$a->strings["Security and Privacy Settings"] = "Agordoj pri Sekureco kaj Privateco"; +$a->strings["Maximum Friend Requests/Day:"] = "Taga maksimumo da kontaktpetoj:"; +$a->strings["(to prevent spam abuse)"] = "(por malhelpi spamaĵojn)"; +$a->strings["Default Post Permissions"] = "DefaÅ­ltaj permesoj por afiÅoj"; +$a->strings["(click to open/close)"] = "(klaku por malfermi/fermi)"; +$a->strings["Maximum private messages per day from unknown people:"] = "Taga maksimumo da privataj mesaÄoj."; +$a->strings["Notification Settings"] = "Agordoj pri Atentigoj"; +$a->strings["By default post a status message when:"] = "DefaÅ­lte afiÅi statmesaÄon okaze de:"; +$a->strings["accepting a friend request"] = "akcepti kontaktpeton"; +$a->strings["joining a forum/community"] = "aliÄi forumon/komunumon"; +$a->strings["making an interesting profile change"] = "fari interesan profilÅanÄon"; +$a->strings["Send a notification email when:"] = "Sendu atentiga repoÅton se:"; +$a->strings["You receive an introduction"] = "Vi ricevas inviton"; +$a->strings["Your introductions are confirmed"] = "Viaj prezentoj estas konfirmata."; +$a->strings["Someone writes on your profile wall"] = "Iu skribas je via profila muro."; +$a->strings["Someone writes a followup comment"] = "Iu skribas sekvan komenton"; +$a->strings["You receive a private message"] = "Vi ricevas privatan mesaÄon."; +$a->strings["You receive a friend suggestion"] = "Vi ricevas amikosugeston"; +$a->strings["You are tagged in a post"] = "Vi estas markita en afiÅon"; +$a->strings["Advanced Account/Page Type Settings"] = "Detalaj Agordoj pri Tipo de Konto/PaÄo."; +$a->strings["Change the behaviour of this account for special situations"] = "Agordi la teniÄon de la konto en specialaj situacioj"; +$a->strings["Manage Identities and/or Pages"] = "Administri identecojn kaj/aÅ­ paÄojn."; +$a->strings["Toggle between different identities or community/group pages which share your account details or which you have been granted \"manage\" permissions"] = "Åœalti inter aliaj identecojn aj komunumaj/grupaj paÄoj kiuj kunhavas viajn kontajn detalojn au por kiuj vi havas \"administranto\" permesojn."; +$a->strings["Select an identity to manage: "] = "Elektu identencon por administrado:"; +$a->strings["Search Results For:"] = "Rezultoj de la serĉado pri:"; +$a->strings["Remove term"] = "ForviÅu terminon"; +$a->strings["Saved Searches"] = "Konservitaj Serĉadoj"; +$a->strings["add"] = "aldoni"; +$a->strings["Commented Order"] = "Komenta Ordo"; +$a->strings["Sort by Comment Date"] = "Ordigi laÅ­ Dato de Komento"; +$a->strings["Posted Order"] = "AfiÅita Ordo"; +$a->strings["Sort by Post Date"] = "Ordigi laÅ­ Dato de AfiÅado"; +$a->strings["Posts that mention or involve you"] = "AfiÅoj menciantaj vin aÅ­ pri vi"; +$a->strings["New"] = "Nova"; +$a->strings["Activity Stream - by date"] = "Fluo de Aktiveco - laÅ­ dato"; +$a->strings["Starred"] = "Steligita"; +$a->strings["Favourite Posts"] = "Favorigitaj AfiÅoj"; +$a->strings["Shared Links"] = "Kunhavigitaj Ligiloj"; +$a->strings["Interesting Links"] = "Interesaj Ligiloj"; +$a->strings["Warning: This group contains %s member from an insecure network."] = array( + 0 => "Averto: La grupo enhavas %s membron el nesekuraj retejoj.", + 1 => "Averto: La grupo enhavas %s membrojn el nesekuraj retejoj.", +); +$a->strings["Private messages to this group are at risk of public disclosure."] = "La privateco de privataj mesaÄoj al ĉi tiu grupo ne ĉiam estas garantita."; +$a->strings["No such group"] = "Grupo ne estas trovita"; +$a->strings["Group is empty"] = "Grupo estas malplena"; +$a->strings["Group: "] = "Grupo:"; +$a->strings["Contact: "] = "Kontakto:"; +$a->strings["Private messages to this person are at risk of public disclosure."] = "La privateco de privataj mesaÄoj al ĉi tiu persono ne ĉiam estas garantita."; +$a->strings["Invalid contact."] = "Nevalida kontakto."; +$a->strings["Personal Notes"] = "Personaj Notoj"; +$a->strings["Save"] = "Konservi"; +$a->strings["Number of daily wall messages for %s exceeded. Message failed."] = "Number of daily wall messages for %s exceeded. MessaÄo malsukcesis."; +$a->strings["No recipient selected."] = "Neniom da ricevontoj."; +$a->strings["Unable to check your home location."] = "Ne eblas kontroli vian hejmlokon."; +$a->strings["Message could not be sent."] = "Ne povas sendi la mesaÄon."; +$a->strings["Message collection failure."] = "Malsukcese provis kolekti mesaÄojn."; +$a->strings["Message sent."] = "MesaÄo estas sendita."; +$a->strings["No recipient."] = "Neniom da ricevontoj."; +$a->strings["Please enter a link URL:"] = "Bonvolu entajpu adreson de ligilo:"; +$a->strings["Send Private Message"] = "Sendi Privatan MesaÄon"; +$a->strings["If you wish for %s to respond, please check that the privacy settings on your site allow private mail from unknown senders."] = "Se vi deziras ke %s respondu, bonvolu kontroli ke la privatecaj agordoj je via retejo permesas privatajn mesaÄojn de nekonataj sendantoj."; +$a->strings["To:"] = "Al:"; +$a->strings["Subject:"] = "Temo:"; +$a->strings["Your message:"] = "Via mesaÄo:"; +$a->strings["Welcome to Friendica"] = "Bonvenon ĉe Friendica"; +$a->strings["New Member Checklist"] = "Kontrololisto por Novaj Membroj"; +$a->strings["We would like to offer some tips and links to help make your experience enjoyable. Click any item to visit the relevant page. A link to this page will be visible from your home page for two weeks after your initial registration and then will quietly disappear."] = "Lasu nin oferi al vi kelkajn konsolojn kaj ligilojn por plifaciligi vian komencon. Klaku iun elementon por viziti la rilatan paÄon. Ligilo al ĉi tiu paÄo videblos en via hejmpaÄo dum du semajnojn post via komenca membriÄo. Post du semajnoj, la ligilo silente malaperos. "; +$a->strings["On your Quick Start page - find a brief introduction to your profile and network tabs, connect to Facebook, make some new connections, and find some groups to join."] = "Je via Rapida Starto paÄo - trovu mallongan enigon pri via profilo kaj la reto folioj, konektu al Facebook, faru novajn konektojn kaj trovu aliÄindajn grupojn."; +$a->strings["On your Settings page - change your initial password. Also make a note of your Identity Address. This looks just like an email address - and will be useful in making friends on the free social web."] = "Bonvolu ÅanÄi vian pasvorton ĉe Agordoj. Krome, memorigu vian identadreson. Äœi aspektas kiel retpoÅtadreso kaj estas bezonata por konekti al novaj amikon en la libera interkona reto."; +$a->strings["Review the other settings, particularly the privacy settings. An unpublished directory listing is like having an unlisted phone number. In general, you should probably publish your listing - unless all of your friends and potential friends know exactly how to find you."] = "Kontrolu la aliajn agordojn, precipe la privatecajn agordojn. Nepublikigita profilo similas al havi telefonnumberon ne registrata en iu telefonlibro. Äœenerale vi eble volas publikigi vian profilon. Alie, viaj amikoj kaj estontaj amikoj bezonas scii kiel rekte trovi vin."; +$a->strings["Upload a profile photo if you have not done so already. Studies have shown that people with real photos of themselves are ten times more likely to make friends than people who do not."] = "EnÅuti profilbildon se vi ankoraÅ­ ne havas Äin. LaÅ­ studoj, homoj kun realaj biloj de si mem trovas novajn amikon duope pli probable ol homoj sen reala bildo."; +$a->strings["Authorise the Facebook Connector if you currently have a Facebook account and we will (optionally) import all your Facebook friends and conversations."] = "Rajtigu la Facebook Konektilon se vi nuntempe havas Facebook konton, kaj ni (nedeviga) enportu viajn Facebook amikojn kaj konversaciojn."; +$a->strings["If this is your own personal server, installing the Facebook addon may ease your transition to the free social web."] = "Se ĉi tiu estas via propra TTT servilo, instali la Facebook kromprogramon eble plifaciligos la transpason al la libera interkona reto."; +$a->strings["Enter your email access information on your Connector Settings page if you wish to import and interact with friends or mailing lists from your email INBOX"] = "Entajpu la akreditaĵojn por via retpoÅtkonto en la konektilagordoj se vi volas importi aÅ­ interagi kun amikoj aÅ­ dissendlistoj pere de via retkesto."; +$a->strings["Edit your default profile to your liking. Review the settings for hiding your list of friends and hiding the profile from unknown visitors."] = "Redakti viajn defaÅ­ltan profilon kiel vi Åatas Äin. Kontrolu la agordojn por kaÅi vian kontaktliston aÅ­ kaÅi vian profilon al nekonataj vizitantoj."; +$a->strings["Set some public keywords for your default profile which describe your interests. We may be able to find other people with similar interests and suggest friendships."] = "Aldonu publikajn Ålosilvortojn al via defaÅ­lta profilo, kiuj priskribas viajn interesojn. Ni eble povas trovi aliajn uzantojn kun similaj interesoj kaj sugesti amikojn."; +$a->strings["Your Contacts page is your gateway to managing friendships and connecting with friends on other networks. Typically you enter their address or site URL in the Add New Contact dialog."] = "Via kontaktpaÄo estas via portalo por administri amikojn kaj konekti kun amikoj en aliaj retoj. Vi kutime entajpas iliajn adreson aÅ­ URL adreso en la Aldonu Novan Kontakton dialogon."; +$a->strings["The Directory page lets you find other people in this network or other federated sites. Look for a Connect or Follow link on their profile page. Provide your own Identity Address if requested."] = "Ĉe la Katalogo vi povas trovi aliajn homojn en ĉi tiu retejo, au en aliaj federaciaj retejoj. Elrigardi al Konekti aÅ­ Sekvi ligiloj ĉe iliaj profilo. Donu vian propran Identecan Adreson se la retejo demandas Äin."; +$a->strings["On the side panel of the Contacts page are several tools to find new friends. We can match people by interest, look up people by name or interest, and provide suggestions based on network relationships. On a brand new site, friend suggestions will usually begin to be populated within 24 hours."] = "En la flanka strio de la Kontaktoj paÄo troviÄas kelkajn helpilojn por trovi novajn amikojn. Ni povas automate trovi amikojn per interesoj, serĉu ilin per nomo aÅ­ intereso kaj faras sugestojn baze de estantaj kontaktoj. Ĉe nova instalita retejo, la unuaj sugestoj kutime aperas post 24 horoj."; +$a->strings["Once you have made some friends, organize them into private conversation groups from the sidebar of your Contacts page and then you can interact with each group privately on your Network page."] = "Kiam vi trovis kelkajn novajn amikojn, ordigi ilin en grupoj por privata komunikado en la flanka strio de via Kontaktoj paÄo, kaj vi povas private komuniki kun ili je via Reto paÄo."; +$a->strings["Our help pages may be consulted for detail on other program features and resources."] = "Niaj Helpo paÄoj enhavas pli da detaloj pri aliaj programaj trajtoj."; +$a->strings["Item not available."] = "Elemento ne disponeblas."; +$a->strings["Item was not found."] = "Elemento ne trovita."; +$a->strings["Group created."] = "Grupo estas kreita."; +$a->strings["Could not create group."] = "Ne povas krei grupon."; +$a->strings["Group not found."] = "Grupo ne estas trovita."; +$a->strings["Group name changed."] = "La nomo de la grupo estas ÅanÄita."; +$a->strings["Permission denied"] = "Malpermesita"; +$a->strings["Create a group of contacts/friends."] = "Krei grupon da kontaktoj/amikoj."; +$a->strings["Group Name: "] = "Nomo de la grupo:"; +$a->strings["Group removed."] = "Grupo estas forviÅita."; +$a->strings["Unable to remove group."] = "Ne eblas forviÅi grupon."; +$a->strings["Group Editor"] = "Grupa redaktilo"; +$a->strings["Members"] = "Anoj"; +$a->strings["Click on a contact to add or remove."] = "Klaku kontakton por aldoni aÅ­ forviÅi."; +$a->strings["Invalid profile identifier."] = "Nevaliada profila identigilo."; +$a->strings["Profile Visibility Editor"] = "Redaktilo por profila videbleco."; +$a->strings["Profile"] = "Profilo"; +$a->strings["Visible To"] = "Videbla Al"; +$a->strings["All Contacts (with secure profile access)"] = "Ĉiuj Kontaktoj (kun sekura atingo al la profilo)"; +$a->strings["No contacts."] = "Neniu kontaktojn."; +$a->strings["View Contacts"] = "Vidi Kontaktojn"; +$a->strings["Registration details for %s"] = "Detaloj de la registrado por %s"; +$a->strings["Registration successful. Please check your email for further instructions."] = "Registrado sukcesis. Bonvolu kontroli vian retpoÅton por pli da instruoj."; +$a->strings["Failed to send email message. Here is the message that failed."] = "Malsukcesis sendi retpoÅton. Jen la malsukcesa mesaÄo."; +$a->strings["Your registration can not be processed."] = "Mi ne povas prilabori vian registradon."; +$a->strings["Registration request at %s"] = "Peto de registrado al %s"; +$a->strings["Your registration is pending approval by the site owner."] = "Via registrado bezonas apropbon de la administranto."; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "La retejo transiras la maksimuman kvanton da ĉiutagaj kontaj registradoj. Bonvolu provi denove morgaÅ­."; +$a->strings["You may (optionally) fill in this form via OpenID by supplying your OpenID and clicking 'Register'."] = "Vi ankaÅ­ (nedeviga) povas plenigi la formularon per OpenID se vi provizas vian OpenID adreson kaj klakas 'Registri'."; +$a->strings["If you are not familiar with OpenID, please leave that field blank and fill in the rest of the items."] = "Se vi ne konas OpenID, bonvolu lasi tiun kampon malplena kaj entajpu la aliajn elementojn."; +$a->strings["Your OpenID (optional): "] = "Via OpenID (nedeviga):"; +$a->strings["Include your profile in member directory?"] = "Aldoni vian profilon al la membrokatalogo?"; +$a->strings["Membership on this site is by invitation only."] = "MembriÄi ĉi tie nur eblas laÅ­ invito."; +$a->strings["Your invitation ID: "] = "Via invita idento: "; +$a->strings["Registration"] = "Registrado"; +$a->strings["Your Full Name (e.g. Joe Smith): "] = "Via Plena Nomo (e.g. Joe Smith): "; +$a->strings["Your Email Address: "] = "Via RetpoÅtadreso: "; +$a->strings["Choose a profile nickname. This must begin with a text character. Your profile address on this site will then be 'nickname@\$sitename'."] = "Elektu kaÅnomon por la profilo. Tiu bezonas komenci kun teksta litero. Poste, via profila adreso ĉi tie estos: 'kaÅnomo@\$sitename'."; +$a->strings["Choose a nickname: "] = "Elektu kaÅnomon: "; +$a->strings["Register"] = "Registri"; +$a->strings["People Search"] = "Serĉi Membrojn"; +$a->strings["status"] = "staton"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s Åatas la %3\$s de %2\$s"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s malÅatas la %3\$s de %2\$s"; +$a->strings["Item not found."] = "Elemento ne estas trovita."; +$a->strings["Access denied."] = "Atingo nepermesita."; +$a->strings["Photos"] = "Bildoj"; +$a->strings["Files"] = "Dosieroj"; +$a->strings["Account approved."] = "Konto aprobita."; +$a->strings["Registration revoked for %s"] = "Registraĵo por %s senvalidigita."; +$a->strings["Please login."] = "Bonvolu ensaluti."; +$a->strings["Unable to locate original post."] = "Ne eblas trovi originalan afiÅon."; +$a->strings["Empty post discarded."] = "ForviÅis malplenan afiÅon."; +$a->strings["Wall Photos"] = "Muraj Bildoj"; +$a->strings["System error. Post not saved."] = "Sistema eraro. AfiÅo ne registrita."; +$a->strings["This message was sent to you by %s, a member of the Friendica social network."] = "Ĉi mesaÄo estas sendita al vi de %s, membro de la Friendica interkona reto."; +$a->strings["You may visit them online at %s"] = "Vi povas viziti ilin rete ĉe %s"; +$a->strings["Please contact the sender by replying to this post if you do not wish to receive these messages."] = "Bonvolu rispondi al ĉi mesaÄo kaj kontaktu la sendinto se vi ne volas ricevi tiujn mesaÄojn."; +$a->strings["%s posted an update."] = "%s publikigis afiÅon."; +$a->strings["Image uploaded but image cropping failed."] = "Bildo estas alÅutita, sed malsukcesis tranĉi la bildon."; +$a->strings["Image size reduction [%s] failed."] = "Malsukcesis malpligrandigi [%s] la bildon."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "ReÅarÄu la paÄon au malplenigu la kaÅmemoro de la retesplorilo se la nova bildo ne tuj aperas."; +$a->strings["Unable to process image"] = "Ne eblas procezi bildon."; +$a->strings["Image exceeds size limit of %d"] = "Bildo estas pli granda ol la limito %d"; +$a->strings["Upload File:"] = "AlÅuti dosieron:"; +$a->strings["Upload Profile Photo"] = "AlÅuti profilbildon"; +$a->strings["Upload"] = "AlÅuti"; +$a->strings["skip this step"] = "Preterpasi tian paÅon"; +$a->strings["select a photo from your photo albums"] = "elekti bildon el viaj albumoj"; +$a->strings["Crop Image"] = "Stuci Bildon"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Bonvolu agordi la stuco de la bildo por optimuma aspekto."; +$a->strings["Done Editing"] = "Finigi Redaktado"; +$a->strings["Image uploaded successfully."] = "Bildo estas sukcese enÅutita."; +$a->strings["No profile"] = "Neniu profilo"; +$a->strings["Remove My Account"] = "Forigi Mian Konton"; +$a->strings["This will completely remove your account. Once this has been done it is not recoverable."] = "Tio tute forigos vian konton. Kiam farita, la konto ne estas restaÅ­rebla."; +$a->strings["Please enter your password for verification:"] = "Bonvolu entajpi vian pasvorton por kontrolado:"; +$a->strings["New Message"] = "Nova MesaÄo"; +$a->strings["Unable to locate contact information."] = "Ne eblas trovi kontaktajn informojn."; +$a->strings["Message deleted."] = "MesaÄo estas forviÅita."; +$a->strings["Conversation removed."] = "Dialogo estas forviÅita."; +$a->strings["No messages."] = "Neniom da mesaÄoj."; +$a->strings["Unknown sender - %s"] = "Nekonata sendanto - %s"; +$a->strings["You and %s"] = "Vi kaj %s"; +$a->strings["%s and You"] = "%s kaj vi"; +$a->strings["Delete conversation"] = "ForviÅi dialogon"; +$a->strings["D, d M Y - g:i A"] = "D, d M Y - g:i A"; +$a->strings["%d message"] = array( + 0 => "%d mesaÄo", + 1 => "%d mesaÄoj", +); +$a->strings["Message not available."] = "MesaÄo nedisponebla."; +$a->strings["Delete message"] = "ForviÅu mesaÄon"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Sekura komunikado ne disponeblas. Vi eble povus respondi sur la profilpaÄo de la sendanto."; +$a->strings["Send Reply"] = "Respondi"; +$a->strings["Friends of %s"] = "Amikoj de %s"; +$a->strings["No friends to display."] = "Neniom da amiko al montri."; +$a->strings["Theme settings updated."] = "Gisdatigis agordojn pri etosoj."; +$a->strings["Site"] = "Retejo"; +$a->strings["Users"] = "Uzantoj"; +$a->strings["Plugins"] = "Kromprogramoj"; +$a->strings["Themes"] = "Etosoj"; +$a->strings["DB updates"] = "DB Äisdatigoj"; +$a->strings["Logs"] = "Protokoloj"; +$a->strings["Admin"] = "Administrado"; +$a->strings["Plugin Features"] = "Kromprogramaj Trajtoj"; +$a->strings["User registrations waiting for confirmation"] = "Uzantaj registradoj atendante konfirmon"; +$a->strings["Normal Account"] = "Normala konto"; +$a->strings["Soapbox Account"] = "Soapbox Konto"; +$a->strings["Community/Celebrity Account"] = "Komunuma/eminentula Konto"; +$a->strings["Automatic Friend Account"] = "AÅ­tomata Amika Konto"; +$a->strings["Message queues"] = "MesaÄvicoj"; +$a->strings["Administration"] = "Administrado"; +$a->strings["Summary"] = "Resumo"; +$a->strings["Registered users"] = "Registrataj uzantoj"; +$a->strings["Pending registrations"] = "Okazontaj registradoj"; +$a->strings["Version"] = "Versio"; +$a->strings["Active plugins"] = "Åœaltitaj kromprogramoj"; +$a->strings["Site settings updated."] = "Äœisdatigis retejaj agordoj."; +$a->strings["Closed"] = "Ferma"; +$a->strings["Requires approval"] = "Bezonas aprobon"; +$a->strings["Open"] = "Malferma"; +$a->strings["No SSL policy, links will track page SSL state"] = "Sen SSL strategio. Ligiloj sekvos la SSL staton de la paÄo."; +$a->strings["Force all links to use SSL"] = "Devigi ke ĉiuj ligiloj uzu SSL."; +$a->strings["Self-signed certificate, use SSL for local links only (discouraged)"] = "Memsubskribita atestilo, nur uzu SSL por lokaj ligiloj (malkuraÄigata)"; +$a->strings["File upload"] = "AlÅuto"; +$a->strings["Policies"] = "Politiko"; +$a->strings["Advanced"] = "Altnivela"; +$a->strings["Site name"] = "Nomo de retejo"; +$a->strings["Banner/Logo"] = "Emblemo"; +$a->strings["System language"] = "Sistema lingvo"; +$a->strings["System theme"] = "Sistema etoso"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "DefaÅ­lta sistema etoso - transpasebla de uzantprofiloj - redakti agordoj pri etosoj"; +$a->strings["SSL link policy"] = "Strategio por SSL ligiloj"; +$a->strings["Determines whether generated links should be forced to use SSL"] = "Difinas ĉu generotaj ligiloj devige uzu SSL."; +$a->strings["Maximum image size"] = "Maksimuma bildgrando"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Maksimuma grando en bajtoj por alÅutotaj bildoj. DefaÅ­lte 0, kio signifas neniu limito."; +$a->strings["Register policy"] = "Interkonsento pri registrado"; +$a->strings["Register text"] = "Interkonsento teksto"; +$a->strings["Will be displayed prominently on the registration page."] = "Tio estos eminente montrata en la registro paÄo."; +$a->strings["Accounts abandoned after x days"] = "Kontoj forlasitaj post x tagoj"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "Mi ne malÅparu energion por enketi aliajn retejojn pri forlasitaj kontoj. Entajpu 0 por ne uzi templimo."; +$a->strings["Allowed friend domains"] = "Permesitaj amikaj domainoj"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "Perkome disigita listo da domajnoj kiuj rajtas konstrui amikecojn kun ĉi tiu retejo. Ä´okeroj eblas. Malplena por rajtigi ĉiujn ajn domajnojn."; +$a->strings["Allowed email domains"] = "Permesitaj retpoÅtaj domajnoj"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "Perkome disigita listo da domajnoj kiuj uzeblas kiel retpoÅtaj adresoj en novaj registradoj. Ä´okeroj eblas. Malplena por rajtigi ĉiujn ajn domajnojn."; +$a->strings["Block public"] = "Bloki publike"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Elektu por bloki publikan atingon al ĉiuj alie publikajn paÄojn en ĉi tiu retejo kiam vi ne estas ensalutita."; +$a->strings["Force publish"] = "Devigi publikigon"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Elektu por devigi la registradon en la loka katalogo al ĉiuj profiloj en ĉi tiu retejo."; +$a->strings["Global directory update URL"] = "Äœenerala adreso por Äisdatigi la katalogon"; +$a->strings["URL to update the global directory. If this is not set, the global directory is completely unavailable to the application."] = "URL adreso por Äisdatigi la tutmondan katalogon. Se ne agordita, la tutmonda katatolge tute ne disponeblas al la programo."; +$a->strings["Block multiple registrations"] = "Bloki pluroblajn registradojn."; +$a->strings["Disallow users to register additional accounts for use as pages."] = "Malpermesi al uzantoj la permeson por registri pluajn kontojn kiel paÄoj."; +$a->strings["OpenID support"] = "Subteno por OpenID"; +$a->strings["OpenID support for registration and logins."] = "Subteni OpenID por registrado kaj ensaluto."; +$a->strings["Fullname check"] = "Kontroli plenan nomon"; +$a->strings["Force users to register with a space between firstname and lastname in Full name, as an antispam measure"] = "Kiel kontraÅ­spamilo, devigi uzantoj al registrado kun spaceto inter la persona nomo kaj la familia nomo."; +$a->strings["UTF-8 Regular expressions"] = "UTF-8 regulaj exprimoj"; +$a->strings["Use PHP UTF8 regular expressions"] = "Uzi PHP UTF8 regulajn esprimojn."; +$a->strings["Show Community Page"] = "Montri Komunuma PaÄo"; +$a->strings["Display a Community page showing all recent public postings on this site."] = "Montri komunuma paÄo kun ĉiuj ĵusaj afiÅoj en ĉi tiu retejo."; +$a->strings["Enable OStatus support"] = "Åœalti subtenon por OStatus"; +$a->strings["Provide built-in OStatus (identi.ca, status.net, etc.) compatibility. All communications in OStatus are public, so privacy warnings will be occasionally displayed."] = "Provizi integritan OStatus (identi.ca, status.net ktp) subtenon. Ĉiuj komunikadoj en OStatus estas publikaj, do privatecaj avertoj aperos de tempo al tempo."; +$a->strings["Enable Diaspora support"] = "Åœalti subtenon por Diaspora"; +$a->strings["Provide built-in Diaspora network compatibility."] = "Provizi integritan Diaspora subtenon."; +$a->strings["Only allow Friendica contacts"] = "Nur permesigi Friendica kontaktojn"; +$a->strings["All contacts must use Friendica protocols. All other built-in communication protocols disabled."] = "Ĉiuj kontaktoj devas uzi Friendica protokolojn. Ĉiuj aliaj komunikaj protokoloj malaktivita."; +$a->strings["Verify SSL"] = "Kontroli SSL"; +$a->strings["If you wish, you can turn on strict certificate checking. This will mean you cannot connect (at all) to self-signed SSL sites."] = "Se vi deziras, vi povas aktivigi severan kontroladon de SSL atestiloj. Pro tio, vie (tute) ne eblos konekti al SSL retejoj kun memsubskribitaj atestiloj."; +$a->strings["Proxy user"] = "Uzantnomo por retperanto"; +$a->strings["Proxy URL"] = "URL adreso de retperanto"; +$a->strings["Network timeout"] = "Reta tempolimo"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "Valoro en sekundoj. Uzu 0 por mallimitigi (ne rekomendata)."; +$a->strings["Delivery interval"] = "Intervalo de liverado"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Malfruigi fonan liveradon dum tiom da sekundoj por malpliigi la Åargon de la sistemo. Rekomendoj: 4-5 por komunaj serviloj, 2-3 por virtualaj privataj serviloj, 0-1 por grandaj dediĉitaj serviloj."; +$a->strings["Poll interval"] = "Enketintervalo"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Malfruigi fonajn enketprocesojn je tiom da sekundoj por malpliigi la Åargon de la sistemo. Se 0, uzas la liverintervalon."; +$a->strings["Maximum Load Average"] = "Maksimuma Meza SistemÅargo"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Maksimuma sistemÅargo post kiu livero- kaj enketprocesoj estos prokrastinataj. - DefaÅ­lte 50."; +$a->strings["Update has been marked successful"] = "Äœisdatigo estas markita sukcesa"; +$a->strings["Executing %s failed. Check system logs."] = "Ne sukcesis plenumi %s. Kontrolu la sistemprotokolojn."; +$a->strings["Update %s was successfully applied."] = "Sukcese aplikis la Äisdatigo %s."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "Äœisdatigo %s ne liveris elirstaton. "; +$a->strings["Update function %s could not be found."] = "Ne troveblas Äisdatigo funkcio %s."; +$a->strings["No failed updates."] = "Neniom da malsukcesaj Äisdatigoj."; +$a->strings["Failed Updates"] = "Malsukcesaj Äœisdatigoj"; +$a->strings["This does not include updates prior to 1139, which did not return a status."] = "Ne inkluzivas Äisdatigojn antaÅ­ 1139, kiuj ne liveris elirstaton."; +$a->strings["Mark success (if update was manually applied)"] = "Marki sukcesa (se la Äisdatigo estas instalita mane)"; +$a->strings["Attempt to execute this update step automatically"] = "Provi automate plenumi ĉi tian paÅon de la Äisdatigo."; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "Blokis/malblokis %s uzanton", + 1 => "Blokis/malblokis %s uzantojn", +); +$a->strings["%s user deleted"] = array( + 0 => "%s uzanto forviÅita", + 1 => "%s uzanto forviÅitaj", +); +$a->strings["User '%s' deleted"] = "Uzanto '%s' forviÅita"; +$a->strings["User '%s' unblocked"] = "Uzanto '%s' malblokita"; +$a->strings["User '%s' blocked"] = "Uzanto '%s' blokita"; +$a->strings["select all"] = "elekti ĉiujn"; +$a->strings["User registrations waiting for confirm"] = "RegistriÄoj atendante aprobon"; +$a->strings["Request date"] = "Dato de peto"; +$a->strings["Email"] = "RetpoÅto"; +$a->strings["No registrations."] = "Neniom da registriÄoj."; +$a->strings["Deny"] = "Negi"; +$a->strings["Register date"] = "Dato de registrado"; +$a->strings["Last login"] = "Plej ĵusa ensaluto"; +$a->strings["Last item"] = "Plej ĵusa elemento"; +$a->strings["Account"] = "Konto"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "La elektitaj uzantkontoj estas forviÅotaj!\\n\\nĈiuj elementoj kiujn ili afiÅis je la retpaÄo estos permanente forviÅitaj.\\n\\nĈu vi certas?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "La uzanto {0} estas forviÅota!\\n\\nĈiuj elementoj kiujn li afiÅis je la retpaÄo estos permanente forviÅitaj.\\n\\nĈu vi certas?"; +$a->strings["Plugin %s disabled."] = "Kromprogramo %s estas malÅaltita."; +$a->strings["Plugin %s enabled."] = "Kromprogramo %s estas Åaltita."; +$a->strings["Disable"] = "MalÅalti"; +$a->strings["Enable"] = "Åœalti"; +$a->strings["Toggle"] = "Åœalti/MalÅalti"; +$a->strings["Author: "] = "AÅ­toro: "; +$a->strings["Maintainer: "] = "Prizorganto: "; +$a->strings["No themes found."] = "Ne trovis etosojn."; +$a->strings["Screenshot"] = "Ekrankopio"; +$a->strings["[Experimental]"] = "[Eksperimenta]"; +$a->strings["[Unsupported]"] = "[Nesubtenata]"; +$a->strings["Log settings updated."] = "Protokolagordoj Äisdatigitaj."; +$a->strings["Clear"] = "ForviÅi"; +$a->strings["Debugging"] = "Sencimigado"; +$a->strings["Log file"] = "Protokolo"; +$a->strings["Must be writable by web server. Relative to your Friendica top-level directory."] = "Devas esti skribebla de la retservilo. Relativa al via plej supra Friendica dosierujo."; +$a->strings["Log level"] = "Protokolnivelo"; +$a->strings["Close"] = "Fermi"; +$a->strings["FTP Host"] = "FTP Servilo"; +$a->strings["FTP Path"] = "FTP Vojo"; +$a->strings["FTP User"] = "FTP Uzanto"; +$a->strings["FTP Password"] = "FTP Pasvorto"; +$a->strings["Requested profile is not available."] = "La petita profilo ne disponeblas."; +$a->strings["Access to this profile has been restricted."] = "Atingo al ĉi tio profilo estas limitigita"; +$a->strings["Tips for New Members"] = "Konsilo por novaj membroj"; +$a->strings["{0} wants to be your friend"] = "{0} volas amikiÄi kun vi"; +$a->strings["{0} sent you a message"] = "{0} sendis mesaÄon al vi"; +$a->strings["{0} requested registration"] = "{0} petis registradon"; +$a->strings["{0} commented %s's post"] = "{0} komentis pri la afiÅo de %s"; +$a->strings["{0} liked %s's post"] = "{0} satis la afiÅon de %s"; +$a->strings["{0} disliked %s's post"] = "{0} malÅatis la afiÅon de %s"; +$a->strings["{0} is now friends with %s"] = "{0} amikiÄis kun %s"; +$a->strings["{0} posted"] = "{0} afiÅis"; +$a->strings["{0} tagged %s's post with #%s"] = "{0} markis la afiÅon de %s kun #%s"; +$a->strings["{0} mentioned you in a post"] = "{0} menciis vin en afiÅo"; +$a->strings["Contacts who are not members of a group"] = "Kontaktoj kiuj ne estas en iu grupo"; +$a->strings["OpenID protocol error. No ID returned."] = "Eraro en OpenID protokolo. Ne resendis identecon."; +$a->strings["Account not found and OpenID registration is not permitted on this site."] = "Ne trovis kontoj, kaj registrado per OpenID estas malpermesita ĉi tie."; +$a->strings["Login failed."] = "Ensalutado malsukcesis."; +$a->strings["Contact added"] = "Aldonis kontakton"; +$a->strings["Common Friends"] = "Komunaj Amikoj"; +$a->strings["No contacts in common."] = "Neniom da komunaj kontaktoj."; +$a->strings["Item has been removed."] = "Elemento estas forviÅita."; +$a->strings["Applications"] = "Programoj"; +$a->strings["No installed applications."] = "Neniom da instalitaj programoj."; +$a->strings["Search"] = "Serĉi"; +$a->strings["Profile not found."] = "Profilo ne trovita."; +$a->strings["Profile Name is required."] = "Nomo de profilo estas bezonata."; +$a->strings["Marital Status"] = "Amrilata Stato"; +$a->strings["Romantic Partner"] = "Kora Partnero"; +$a->strings["Likes"] = "Åœatoj"; +$a->strings["Dislikes"] = "MalÅatoj"; +$a->strings["Work/Employment"] = "Laboro"; +$a->strings["Religion"] = "Religio"; +$a->strings["Political Views"] = "Politikaj Opinioj"; +$a->strings["Gender"] = "Sekso"; +$a->strings["Sexual Preference"] = "Seksa Prefero"; +$a->strings["Homepage"] = "HejmpaÄo"; +$a->strings["Interests"] = "Interesoj"; +$a->strings["Address"] = "Adreso"; +$a->strings["Location"] = "Loko"; +$a->strings["Profile updated."] = "Profilo Äisdatigita."; +$a->strings[" and "] = " kaj "; +$a->strings["public profile"] = "publika profilo"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s ÅanÄis %2\$s al “%3\$s”"; +$a->strings[" - Visit %1\$s's %2\$s"] = " - Vizitu la %2\$s de %1\$s"; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s havas Äisdatigigan %2\$s, ÅanÄas %3\$s."; +$a->strings["Profile deleted."] = "Profilo forviÅita."; +$a->strings["Profile-"] = "Profilo-"; +$a->strings["New profile created."] = "Nova profilo kreita."; +$a->strings["Profile unavailable to clone."] = "Ne eblas kopii profilon."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "KaÅi vian liston de kontaktoj/amikoj al vidantoj de ĉi-tio profilo?"; +$a->strings["Edit Profile Details"] = "Redakti Detalojn de Profilo"; +$a->strings["View this profile"] = "Vidi la profilon."; +$a->strings["Create a new profile using these settings"] = "Krei novan profilon kun tiaj agordoj"; +$a->strings["Clone this profile"] = "Kopii ĉi tiun profilon"; +$a->strings["Delete this profile"] = "ForviÅi ĉi tiun profilon"; +$a->strings["Profile Name:"] = "Nomo de Profilo:"; +$a->strings["Your Full Name:"] = "Via Plena Nomo:"; +$a->strings["Title/Description:"] = "Titolo/Priskribo:"; +$a->strings["Your Gender:"] = "Via Sekso:"; +$a->strings["Birthday (%s):"] = "NaskiÄtago (%s):"; +$a->strings["Street Address:"] = "Adreso:"; +$a->strings["Locality/City:"] = "Urbo:"; +$a->strings["Postal/Zip Code:"] = "PoÅtkodo:"; +$a->strings["Country:"] = "Lando:"; +$a->strings["Region/State:"] = "Åœtato:"; +$a->strings[" Marital Status:"] = " Civita Stato:"; +$a->strings["Who: (if applicable)"] = "Kiu (se aplikeble):"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Ekzemploj: cathy123, Cathy Williams, cathy@example.com"; +$a->strings["Since [date]:"] = "Ekde [dato]:"; +$a->strings["Sexual Preference:"] = "Seksa Prefero:"; +$a->strings["Homepage URL:"] = "Adreso de HejmpaÄo:"; +$a->strings["Hometown:"] = "Hejmurbo:"; +$a->strings["Political Views:"] = "Politikaj Opinioj:"; +$a->strings["Religious Views:"] = "Religiaj Opinioj:"; +$a->strings["Public Keywords:"] = "Publikaj Ålosilvortoj:"; +$a->strings["Private Keywords:"] = "Privataj Ålosilvortoj:"; +$a->strings["Likes:"] = "Åœatoj:"; +$a->strings["Dislikes:"] = "MalÅatoj:"; +$a->strings["Example: fishing photography software"] = "Ekzemple: fiÅkapti fotografio programaro"; +$a->strings["(Used for suggesting potential friends, can be seen by others)"] = "(Por sugesti amikoj. Videbla al aliaj.)"; +$a->strings["(Used for searching profiles, never shown to others)"] = "(Por serĉi profilojn. Neniam videbla al aliaj.)"; +$a->strings["Tell us about yourself..."] = "Diru al ni pri vi..."; +$a->strings["Hobbies/Interests"] = "Åœatokupoj/Interesoj"; +$a->strings["Contact information and Social Networks"] = "Kontaktaj informoj kaj Interkonaj Retejoj"; +$a->strings["Musical interests"] = "Muzikaj interesoj"; +$a->strings["Books, literature"] = "Libroj, literaturo"; +$a->strings["Television"] = "Televido"; +$a->strings["Film/dance/culture/entertainment"] = "Filmoj/dancoj/arto/amuzaĵoj"; +$a->strings["Love/romance"] = "Amo/romanco"; +$a->strings["Work/employment"] = "Laboro"; +$a->strings["School/education"] = "Lernejo/eduko"; +$a->strings["This is your public profile.
    It may be visible to anybody using the internet."] = "Ĉi tio estas via publika profilo. Äœi eble estas videbla al ĉiuj en interreto. "; +$a->strings["Age: "] = "AÄo:"; +$a->strings["Edit/Manage Profiles"] = "Redakti/administri Profilojn"; +$a->strings["Change profile photo"] = "ÅœanÄi profilbildon"; +$a->strings["Create New Profile"] = "Krei novan profilon"; +$a->strings["Profile Image"] = "Profilbildo"; +$a->strings["visible to everybody"] = "videbla al ĉiuj"; +$a->strings["Edit visibility"] = "Redakti videblecon"; +$a->strings["Save to Folder:"] = "Konservi en Dosierujo:"; +$a->strings["- select -"] = "- elekti -"; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s markis la %3\$s de %2\$s kun %4\$s"; +$a->strings["No potential page delegates located."] = "Ne trovis delegiteblajn paÄojn."; +$a->strings["Delegate Page Management"] = "Administrado de Delegitajn PaÄojn"; +$a->strings["Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely."] = "Delegitoj povas administri ĉiujn ecojn de la konto/paÄo, escepte bazaj kontoagordoj. Bonvolu ne delegitigi vian personan konton al iu al kiu vi ne plene fidas."; +$a->strings["Existing Page Managers"] = "Estantaj Administrantoj de la PaÄo"; +$a->strings["Existing Page Delegates"] = "Estantaj Delegitoj de la PaÄo"; +$a->strings["Potential Delegates"] = "Eblaj Delegitoj"; +$a->strings["Add"] = "Aldoni"; +$a->strings["No entries."] = "Neniom da afiÅoj."; +$a->strings["Friend Suggestions"] = "Amikosugestoj"; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Neniu sugestoj disponeblas. Se ĉi tiu estas nova retejo, bonvolu reprovi post 24 horoj."; +$a->strings["Ignore/Hide"] = "Ignori/KaÅi"; +$a->strings["Global Directory"] = "Tutmonda Katalogo"; +$a->strings["Find on this site"] = "Trovi en ĉi retejo"; +$a->strings["Site Directory"] = "Reteja Katalogo"; +$a->strings["Gender: "] = "Sekso:"; +$a->strings["No entries (some entries may be hidden)."] = "Neniom da afiÅoj (kelkaj afiÅoj eble ne estas videbla)."; +$a->strings["%s : Not a valid email address."] = "%s: Ne estas valida retpoÅtadreso."; +$a->strings["Please join us on Friendica"] = "Bonvolu aliÄi kun ni ĉe Friendica"; +$a->strings["%s : Message delivery failed."] = "%s: La livero de la mesaÄo malsukcesis."; +$a->strings["%d message sent."] = array( + 0 => "Sendis %d mesaÄon.", + 1 => "Sendis %d mesaÄojn.", +); +$a->strings["You have no more invitations available"] = "Vi ne plu disponeblas invitaĵojn"; +$a->strings["Visit %s for a list of public sites that you can join. Friendica members on other sites can all connect with each other, as well as with members of many other social networks."] = "Vizitu %s por listo de publikaj retejoj kie vi povas aliÄi. Anoj de Friendica ĉe aliaj retejoj povas konekti unu kun la alian, kaj ankaÅ­ kun membroj de multaj aliaj retejoj."; +$a->strings["To accept this invitation, please visit and register at %s or any other public Friendica website."] = "Por akcepti ĉi tiu invito, bonvolu viziti kaj registriÄi ĉe %s au alia publika Friendica retejo."; +$a->strings["Friendica sites all inter-connect to create a huge privacy-enhanced social web that is owned and controlled by its members. They can also connect with many traditional social networks. See %s for a list of alternate Friendica sites you can join."] = "Ĉiuj Friendica retejoj interkonektiÄas kaj kune faras grandan altprivatecan interkonan reton, kiun posedas kaj kontrolas Äiaj membroj. Ili ankaÅ­ povas konekti kun multe de tradiciaj interkonaj retejoj. Vidu %s por listo de publikaj retejoj kie vi povas aliÄi."; +$a->strings["Our apologies. This system is not currently configured to connect with other public sites or invite members."] = "Senkulpigu nin. La sistemo nuntempe ne estas agordita por konekti al aliaj retejoj au inviti membrojn."; +$a->strings["Send invitations"] = "Sendi invitojn"; +$a->strings["Enter email addresses, one per line:"] = "Entajpu retpoÅtadresojn, po unu por ĉiu linio."; +$a->strings["You are cordially invited to join me and other close friends on Friendica - and help us to create a better social web."] = "Ni bonkore invitas vin aliÄi kun ni kaj aliaj bonaj amikoj ĉe Friendica. Helpu nin krei pli bonan interkonan reton."; +$a->strings["You will need to supply this invitation code: \$invite_code"] = "Vi bezonas ĉi-tiun invitkodon: \$invite_code"; +$a->strings["Once you have registered, please connect with me via my profile page at:"] = "Kiam vi registris, bonvolu konekti al mi pere de mi profilo ĉe: "; +$a->strings["For more information about the Friendica project and why we feel it is important, please visit http://friendica.com"] = "Por pli da informoj pri Friendica, kaj kial ni pensas ke Äi estas grava, bonvolu viziti http://friendica.com"; +$a->strings["This may occasionally happen if contact was requested by both persons and it has already been approved."] = "Tio ĉi okazis de tempo al tempo se ambaÅ­ personoj petas kontakton ka Äi jam estas aprobita."; +$a->strings["Response from remote site was not understood."] = "Ne komprenis la rispondon de la fora retejo."; +$a->strings["Unexpected response from remote site: "] = "Neatendita rispondo de la fora retejo:"; +$a->strings["Confirmation completed successfully."] = "Konfirmo sukcese kompletigita."; +$a->strings["Remote site reported: "] = "La fora retejo raportis:"; +$a->strings["Temporary failure. Please wait and try again."] = "Dumtempa eraro. Bonvolu atendi kaj provi refoje."; +$a->strings["Introduction failed or was revoked."] = "La prezento malsukcesis au estas revokita."; +$a->strings["Unable to set contact photo."] = "Neeblas agordi la kontaktbildo."; +$a->strings["%1\$s is now friends with %2\$s"] = "%1\$s amikiÄis kun %2\$s"; +$a->strings["No user record found for '%s' "] = "Ne trovis uzanton '%s' "; +$a->strings["Our site encryption key is apparently messed up."] = "Åœajnas kvazaÅ­ la ĉifroÅlosilo de nia retejo estas fuÅita."; +$a->strings["Empty site URL was provided or URL could not be decrypted by us."] = "Malplena adreso de retejo provizita, aÅ­ ni ne povis malĉifri la adreson."; +$a->strings["Contact record was not found for you on our site."] = "Kontakto ne trovita por vi en via retejo."; +$a->strings["Site public key not available in contact record for URL %s."] = "Publika Ålosilo de retejo ne disponeblas en la kontaktrikordo por la URL adreso %s."; +$a->strings["The ID provided by your system is a duplicate on our system. It should work if you try again."] = "La identeco provizita de via sistemo estas duoblo ĉe nia sistemo. Äœi eble funkcias se vi provas refoje."; +$a->strings["Unable to set your contact credentials on our system."] = "Ne sukcesis agordi la legitimaĵojn de via kontakto ĉe nia sistemo."; +$a->strings["Unable to update your contact profile details on our system"] = "Neeblas Äisdatigi viajn profildetalojn ĉe nia sistemo."; +$a->strings["Connection accepted at %s"] = "Konekto akceptita je %s"; +$a->strings["%1\$s has joined %2\$s"] = "%1\$s aliÄis al %2\$s"; +$a->strings["Google+ Import Settings"] = "Google+ Importo"; +$a->strings["Enable Google+ Import"] = "Aktivigi Äœoogle+ Importon"; +$a->strings["Google Account ID"] = "Google Konto ID"; +$a->strings["Google+ Import Settings saved."] = "Konservis Agordojn por Google+ Importo."; +$a->strings["Facebook disabled"] = "Facebook malÅaltita"; +$a->strings["Updating contacts"] = "Mi Äisdatigas la kontaktojn."; +$a->strings["Facebook API key is missing."] = "La API Ålosilo de Facebook ne estas konata ĉi tie."; +$a->strings["Facebook Connect"] = "Kontekto al Facebook"; +$a->strings["Install Facebook connector for this account."] = "Instali la Facebook konektilo por ĉi tiu konto."; +$a->strings["Remove Facebook connector"] = "Forigi la Facebook konektilon."; +$a->strings["Re-authenticate [This is necessary whenever your Facebook password is changed.]"] = "ReaÅ­tentiÄi [Tio estas bezonata ĉiam kiam vi ÅanÄis vian pasvorton ĉe Facebook.]"; +$a->strings["Post to Facebook by default"] = "Ĉiam afiÅi al Facebook."; +$a->strings["Facebook friend linking has been disabled on this site. The following settings will have no effect."] = "Ligado kun Facebook amikoj estas malaktivita ĉe tiu retejo. La sekvantaj agordoj do ne havas validecon."; +$a->strings["Facebook friend linking has been disabled on this site. If you disable it, you will be unable to re-enable it."] = "Ligado kun Facebook amikoj estas malaktivita ĉe tiu retejo. Se vi malÅaltas Äin, vi ne eblos ree Åalti Äin."; +$a->strings["Link all your Facebook friends and conversations on this website"] = "Alligu ĉiujn viajn Facebook amikojn kaj konversaciojn je ĉi-tiu retejo."; +$a->strings["Facebook conversations consist of your profile wall and your friend stream."] = "Facebok konversacioj konsistas el via profilmuro kaj la fluo de viaj amikoj."; +$a->strings["On this website, your Facebook friend stream is only visible to you."] = "Je ĉi-tiu retejo, la fluo de viaj amikoj ĉe Facebook nur videblas al vi."; +$a->strings["The following settings determine the privacy of your Facebook profile wall on this website."] = "La sekvontaj agordoj difinas la privatecon de via Facebook profilmuro je ĉi-tiu retejo."; +$a->strings["On this website your Facebook profile wall conversations will only be visible to you"] = "Je ĉi-tiu retejo, la conversacioj sur via Facebook profilmuro nur videblas al vi."; +$a->strings["Do not import your Facebook profile wall conversations"] = "Ne importi konversaciojn de via Facebook profilmuro"; +$a->strings["If you choose to link conversations and leave both of these boxes unchecked, your Facebook profile wall will be merged with your profile wall on this website and your privacy settings on this website will be used to determine who may see the conversations."] = "Se vi elektas alligi conversaciojn kaj ne elektas tiujn butonojn, via Facebook profilmuro estas kunigota kun via profilmuro ĉi tie. Viaj privatecaj agordoj ĉi tie difinos kiu povas vidi la coversaciojn."; +$a->strings["Comma separated applications to ignore"] = "Ignorotaj programoj, disigita per komo"; +$a->strings["Problems with Facebook Real-Time Updates"] = "Problemoj kun Facebook Realtempaj Äœisdatigoj"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Facebook Connector Settings"] = "Agordoj por la Facebook konektilo"; +$a->strings["Facebook API Key"] = "Facebook API Ålosilo"; +$a->strings["Error: it appears that you have specified the App-ID and -Secret in your .htconfig.php file. As long as they are specified there, they cannot be set using this form.

    "] = "Eraro: Åœajnas kvazaÅ­ vi agordis la App-ID kaj la sekreton en via .htconfig.php dosiero. Kiam ili estas agordita tie, vi ne povas agordi Äin en tiu ĉi formo.

    "; +$a->strings["Error: the given API Key seems to be incorrect (the application access token could not be retrieved)."] = "Eraro: La API Ålosilo aspektas malÄusta (ne eblas ricevi la programa atingoĵetono)."; +$a->strings["The given API Key seems to work correctly."] = "La API Ålosilo Åajne Äuste funkcias."; +$a->strings["The correctness of the API Key could not be detected. Somthing strange's going on."] = "Ne povis kontroli la Äustecon de la API Ålosilo. Ia stranga afero okazas. "; +$a->strings["App-ID / API-Key"] = "Programo ID / API Åœlosilo"; +$a->strings["Application secret"] = "Programo sekreto"; +$a->strings["Polling Interval in minutes (minimum %1\$s minutes)"] = "Intervalo de enketo en minutoj (minimume %1\$s minutoj)"; +$a->strings["Synchronize comments (no comments on Facebook are missed, at the cost of increased system load)"] = "Sinkronigi komentojn (vi ricevas ĉiujn komentojn de Facebook, sed la Åargo de la sistemo iom kreskas)"; +$a->strings["Real-Time Updates"] = "Realtempaj Äœisdatigoj"; +$a->strings["Real-Time Updates are activated."] = "Realtempaj Äœisdatigoj estas Åaltita"; +$a->strings["Deactivate Real-Time Updates"] = "MalÅalti Realtempaj Äœisdatigoj"; +$a->strings["Real-Time Updates not activated."] = "Realtempaj Äœisdatigoj estas malÅaltita"; +$a->strings["Activate Real-Time Updates"] = "Åœalti Realtempaj Äœisdatigoj"; +$a->strings["The new values have been saved."] = "Konservis novajn valorojn."; +$a->strings["Post to Facebook"] = "AfiÅi al Facebook"; +$a->strings["Post to Facebook cancelled because of multi-network access permission conflict."] = "AfiÅado al Facebook nuligita ĉar okazis konflikto en la multretpermesoj."; +$a->strings["View on Friendica"] = "Vidi ĉe Friendica"; +$a->strings["Facebook post failed. Queued for retry."] = "Malsukcesis afiÅi ĉe Facebook. Enigita en vico."; +$a->strings["Your Facebook connection became invalid. Please Re-authenticate."] = "Via Facbook konekto iÄis nevalida. Bonvolu reaÅ­tentiÄi."; +$a->strings["Facebook connection became invalid"] = "Facebook konekto iÄis nevalida."; +$a->strings["Hi %1\$s,\n\nThe connection between your accounts on %2\$s and Facebook became invalid. This usually happens after you change your Facebook-password. To enable the connection again, you have to %3\$sre-authenticate the Facebook-connector%4\$s."] = "Saluton %1\$s,\n\nla kontekto inter viaj kontoj ĉe %2\$s kaj Facebook malvalidiÄis. Tio kutime okazas post kiam via Åangas vian pasvorton ĉe Facebook. Por reaktivigi la konekto, vi bezonas %3\$sreaÅ­tentiÄi la Facebook konektilon%4\$s."; +$a->strings["StatusNet AutoFollow settings updated."] = "Äœidatigis StatusNet AutoFollow agordojn."; +$a->strings["StatusNet AutoFollow Settings"] = "StatusNet AutoFollow agordoj"; +$a->strings["Automatically follow any StatusNet followers/mentioners"] = "AÅ­tomate sekvu ĉiujn StatusNet sekvantojn/menciantojn."; +$a->strings["Lifetime of the cache (in hours)"] = "VivodaÅ­ro de kaÅmemoro (horoj)"; +$a->strings["Cache Statistics"] = "Statistikoj pri kaÅmemoro"; +$a->strings["Number of items"] = "Kvanto da eroj"; +$a->strings["Size of the cache"] = "Grando de la kaÅmemoro"; +$a->strings["Delete the whole cache"] = "ForviÅi la kaÅmemoron"; +$a->strings["%d person likes this"] = array( + 0 => "%d homo Åatas tiun", + 1 => "%d homoj Åatas tiun", +); +$a->strings["%d person doesn't like this"] = array( + 0 => "%d homo malÅatas tiun", + 1 => "%d homo malÅatas tiun", +); +$a->strings["Get added to this list!"] = "IÄu membro de ĉi tiu listo!"; +$a->strings["Generate new key"] = "Generi novan ĉifroÅlosilon"; +$a->strings["Widgets key"] = "Åœlosilo por fenestraĵoj"; +$a->strings["Widgets available"] = "Disponeblaj fenestraĵoj"; +$a->strings["Connect on Friendica!"] = "Konekti ĉe Friendica!"; +$a->strings["YourLS Settings"] = "\"YourLS\" Agordoj"; +$a->strings["URL: http://"] = "URL adreso: http://"; +$a->strings["Username:"] = "Salutnomo:"; +$a->strings["Password:"] = "Pasvorto:"; +$a->strings["Use SSL "] = "Uzi SSL "; +$a->strings["yourls Settings saved."] = "Konservis la agordojn de YourLS."; +$a->strings["Post to LiveJournal"] = "AfiÅi ĉe LiveJournal"; +$a->strings["LiveJournal Post Settings"] = "Agordoj pri afiÅoj ĉe LiveJournal"; +$a->strings["Enable LiveJournal Post Plugin"] = "Åœalti la LiveJournal-afiÅo kromprogramon."; +$a->strings["LiveJournal username"] = "LiveJournal Salutnomo"; +$a->strings["LiveJournal password"] = "LiveJournal pasvorto"; +$a->strings["Post to LiveJournal by default"] = "DefaÅ­lte afiÅi al LiveJournal"; +$a->strings["Not Safe For Work (General Purpose Content Filter) settings"] = "Not Safe For Work (Äenerala filtrilo por enhavoj) agordoj"; +$a->strings["This plugin looks in posts for the words/text you specify below, and collapses any content containing those keywords so it is not displayed at inappropriate times, such as sexual innuendo that may be improper in a work setting. It is polite and recommended to tag any content containing nudity with #NSFW. This filter can also match any other word/text you specify, and can thereby be used as a general purpose content filter."] = "Tiu kromprogramo serĉas la malsupre agordatajn vortojn en afiÅoj kaj malvidebligis ilin se ili enhavas iun vorton. Tiel, afiÅoj ne montriÄis kiuj enhavas maladekvatan enhavon, ekzemple seksumaj aferoj, kiuj ne estas adekvata, ekzemple en la laborejo. En la reto, oni kutime markas tiajn afiÅojn #NSFW - Not Safe For Work - ne adekvata por la laborejo. La filtrilo ankaÅ­ serĉas ĉiujn vortojn kiujn vi agordas kaj tial funkcias kiel Äenerala filtrilo."; +$a->strings["Enable Content filter"] = "Åœalti la filtrilo por la enhavo"; +$a->strings["Comma separated list of keywords to hide"] = "Perkome disigita listo da kaÅontaj Ålosilvortoj"; +$a->strings["Use /expression/ to provide regular expressions"] = "Uzu /expr/ por provizi regulajn esprimojn."; +$a->strings["NSFW Settings saved."] = "NSFW agordoj konservitaj."; +$a->strings["%s - Click to open/close"] = "%s - Klaku por malfermi/fermi"; +$a->strings["Forums"] = "Forumoj"; +$a->strings["show more"] = "montri pli"; +$a->strings["Forums:"] = "Forumoj:"; +$a->strings["Page settings updated."] = "PaÄajn agordojn Äisdatigita."; +$a->strings["Page Settings"] = "PaÄaj Agordoj"; +$a->strings["How many forums to display on sidebar without paging"] = "Montri tiom da forumoj en la flanka strio sen paÄigo"; +$a->strings["Randomise Page/Forum list"] = "Hazardigi la liston de PaÄoj/Forumoj"; +$a->strings["Show pages/forums on profile page"] = "Montri paÄojn/forumojn sur la profilpaÄo"; +$a->strings["Planets Settings"] = "Agordo pri Planets"; +$a->strings["Enable Planets Plugin"] = "Åœalti la Planets kromprogamon"; +$a->strings["Login"] = "Ensaluti"; +$a->strings["OpenID"] = "OpenID"; +$a->strings["Latest users"] = "Ä´usaj uzantoj"; +$a->strings["Most active users"] = "Plej aktivaj uzantoj"; +$a->strings["Latest photos"] = "Ä´usaj bildoj"; +$a->strings["Latest likes"] = "Ä´usaj Åatitaĵoj"; +$a->strings["event"] = "okazo"; +$a->strings["U.S. Time Format (mm/dd/YYYY)"] = "Usona datformato (mm/dd/YYYY)"; +$a->strings["German Time Format (dd.mm.YYYY)"] = "Germana datformato (dd.mm.YYYY)"; +$a->strings["Error"] = "Eraro"; +$a->strings["No access"] = "No access"; +$a->strings["New event"] = "Nova okazo"; +$a->strings["Today"] = "HodiaÅ­"; +$a->strings["Day"] = "Tago"; +$a->strings["Week"] = "Semajno"; +$a->strings["Month"] = "Monato"; +$a->strings["Reload"] = "ReÅargi"; +$a->strings["Date"] = "Dato"; +$a->strings["Not found"] = "Ne trovita"; +$a->strings["Go back to the calendar"] = "Iri reen al la kalendaro"; +$a->strings["Starts"] = "Komencas"; +$a->strings["Ends"] = "Finas"; +$a->strings["Description"] = "Priskribo"; +$a->strings["Notification"] = "Atentigo"; +$a->strings["Minutes"] = "Minutoj"; +$a->strings["Hours"] = "Horoj"; +$a->strings["Days"] = "Tagoj"; +$a->strings["before"] = "antaÅ­"; +$a->strings["Calendar Settings"] = "Kalendaraj Agordoj"; +$a->strings["Date format"] = "Datformato"; +$a->strings["Time zone"] = "Horzono"; +$a->strings["Limitations"] = "Limigoj"; +$a->strings["Warning"] = "Averto"; +$a->strings["Synchronization (iPhone, Thunderbird Lightning, Android, ...)"] = "Sinkronigo (iPhone, Thunderbird Lightning, Android, ...)"; +$a->strings["Synchronizing this calendar with the iPhone"] = "Sinkronigi tiun kalendaron kun la iPhone"; +$a->strings["Synchronizing your Friendica-Contacts with the iPhone"] = "Sinkronigi viajn Friendica kontaktojn kun la iPhone"; +$a->strings["Friendica-Contacts"] = "Friendica Kontaktoj"; +$a->strings["Your Friendica-Contacts"] = "Viaj Friendica Kontaktoj"; +$a->strings["Calendar"] = "Kalendaro"; +$a->strings["Extended calendar with CalDAV-support"] = "Etendita kalendaro kun CalDAV subteno"; +$a->strings["The database tables have been installed."] = "La tabeloj estas instalita en la datumbazo"; +$a->strings["An error occurred during the installation."] = "Eraro okazis dum instalado"; +$a->strings["No system-wide settings yet."] = "AnkoraÅ­ ne disponablas tutsistemaj agordoj"; +$a->strings["Database status"] = "Stato de datumbazo"; +$a->strings["Installed"] = "Instalita"; +$a->strings["Upgrade needed"] = "Äœisdatigo bezonata"; +$a->strings["Upgrade"] = "Äœisdatigo"; +$a->strings["Not installed"] = "Ne instalita"; +$a->strings["Install"] = "Instali"; +$a->strings["Troubleshooting"] = "Problemsolvado"; +$a->strings["Manual creation of the database tables:"] = "Mana kreado de tabeloj en la datumbazo:"; +$a->strings["Show SQL-statements"] = "Montru SQL ordonojn"; +$a->strings["Private Calendar"] = "Privata kalendaro"; +$a->strings["Friendica Events: Mine"] = "Friendica Okazoj: Miaj"; +$a->strings["Friendica Events: Contacts"] = "Friendica Okazoj: De Kontaktoj"; +$a->strings["Allow to use your friendica id (%s) to connecto to external unhosted-enabled storage (like ownCloud). See RemoteStorage WebFinger"] = "Permesi vian identecon ĉe Friendica (%s) por konekti al eksteraj konservejoj subtenata de unhosted (ekz. OwnCloud). Vidu RemoteStorage WebFinger"; +$a->strings["Template URL (with {category})"] = "URL adreso de Åablono (kun {category})"; +$a->strings["OAuth end-point"] = "OAuth finpunkto"; +$a->strings["Api"] = "Api"; +$a->strings["Member since:"] = "Membro ekde:"; +$a->strings["Three Dimensional Tic-Tac-Toe"] = "Tri-dimensia Tiktakto"; +$a->strings["3D Tic-Tac-Toe"] = "3D Tiktakto"; +$a->strings["New game"] = "Nova ludo"; +$a->strings["New game with handicap"] = "Nova ludo kun handikapo"; +$a->strings["Three dimensional tic-tac-toe is just like the traditional game except that it is played on multiple levels simultaneously. "] = "Tri-dimensia tiktakto similas la tradician ludon, sed estas ludata sur pluraj ebenoj dum la sama tempo."; +$a->strings["In this case there are three levels. You win by getting three in a row on any level, as well as up, down, and diagonally across the different levels."] = "Ĉi-kaze ekzistas tri ebenoj. Vi venkas vicigante tri signojn en una vico, en la sama ebeno, same kiel supren, malsupren aÅ­ diagonale, trans la ebenoj."; +$a->strings["The handicap game disables the center position on the middle level because the player claiming this square often has an unfair advantage."] = "La ludo kun handikapo malvalidigas la mezan pozicion sur la meza ebeno, ĉar la ludisto kio okupas ĉi tiun pozicion ĉiam havas avantaÄon."; +$a->strings["You go first..."] = "Estas via vico unue."; +$a->strings["I'm going first this time..."] = "Ĉi-tempe, unue estas mia vico."; +$a->strings["You won!"] = "Vi venkis!"; +$a->strings["\"Cat\" game!"] = "Sendecida ludo!"; +$a->strings["I won!"] = "Mi venkis!"; +$a->strings["Randplace Settings"] = "Randplace agordoj."; +$a->strings["Enable Randplace Plugin"] = "Aktivigi la Randplace kromprogramon."; +$a->strings["Post to Dreamwidth"] = "AfiÅi al Dreamwidth"; +$a->strings["Dreamwidth Post Settings"] = "Agordoj por AfiÅoj al Dreamwidth"; +$a->strings["Enable dreamwidth Post Plugin"] = "Åœalti la Dreamwidth Kromprogramon"; +$a->strings["dreamwidth username"] = "Dreamwidth salutnomo"; +$a->strings["dreamwidth password"] = "Dreamwidth pasvorto"; +$a->strings["Post to dreamwidth by default"] = "DefaÅ­lte afiÅi al Dreamwidth"; +$a->strings["Post to Drupal"] = "AfiÅi al Drupal"; +$a->strings["Drupal Post Settings"] = "Agordoj por Drupal AfiÅoj"; +$a->strings["Enable Drupal Post Plugin"] = "Åœalti la Drupal-afiÅo Kromprogramon"; +$a->strings["Drupal username"] = "Drupal salutnomo"; +$a->strings["Drupal password"] = "Drupal pasvorto"; +$a->strings["Post Type - article,page,or blog"] = "Tipo de AfiÅoj - article, page, aÅ­ blog"; +$a->strings["Drupal site URL"] = "URL adreso de Drupal retejo"; +$a->strings["Drupal site uses clean URLS"] = "Drupal retejo uzas purajn URL adresojn"; +$a->strings["Post to Drupal by default"] = "DefaÅ­lte afiÅi ĉe Drupal"; +$a->strings["Post from Friendica"] = "AfiÅo de Friendica"; +$a->strings["Startpage Settings"] = "StartpaÄaj Agordoj"; +$a->strings["Home page to load after login - leave blank for profile wall"] = "HejmpaÄo Åargonta post la ensaluto - Lasu malplena por profilmuro."; +$a->strings["Examples: "network" or "notifications/system""] = "Ekzemple: "network" aÅ­ "notifications/system""; +$a->strings["Geonames settings updated."] = "Äœidatigis la Geonames agordojn."; +$a->strings["Geonames Settings"] = "Geonames Agordoj"; +$a->strings["Enable Geonames Plugin"] = "Åœalti la Geonames Kromprogramon"; +$a->strings["Your account on %s will expire in a few days."] = "Via konto ĉe %s senvalidiÄos post kelkaj tagoj."; +$a->strings["Your Friendica account is about to expire."] = "Via konto ĉe Friendica baldaÅ­ senvalidiÄos."; +$a->strings["Hi %1\$s,\n\nYour account on %2\$s will expire in less than five days. You may keep your account by logging in at least once every 30 days"] = "Saluton %1\$s,\n\nVia konto ĉe %2\$s senvalidiÄos post malpli ol kvin tagoj. Vi povas konservi vian konton se vi ensalutas almenaÅ­ ĉiujn 30 tagojn. "; +$a->strings["Upload a file"] = "AlÅuti dosieron"; +$a->strings["Drop files here to upload"] = "Åœovmeti dosierojn ĉi tie por alÅuti ilin."; +$a->strings["Failed"] = "Malsukcesi"; +$a->strings["No files were uploaded."] = "Neniom da dosieroj alÅutita."; +$a->strings["Uploaded file is empty"] = "AlÅutita dosiero estas malplena."; +$a->strings["File has an invalid extension, it should be one of "] = "Dosiero havas nevalidan sufikson. Äœi estu unu de "; +$a->strings["Upload was cancelled, or server error encountered"] = "AlÅutado estas nuligita aÅ­ okazis eraro sur la servilo"; +$a->strings["OEmbed settings updated"] = "Äœisdatigis OEmbed agordojn"; +$a->strings["Use OEmbed for YouTube videos"] = "Uzi OEmbed por YouTube videtoj"; +$a->strings["URL to embed:"] = "Enigi la URL adreson:"; +$a->strings["Impressum"] = "Kolofono"; +$a->strings["Site Owner"] = "Proprietulo de la paÄo"; +$a->strings["Email Address"] = "RetpoÅta Adreso"; +$a->strings["Postal Address"] = "PoÅta Adreso"; +$a->strings["The impressum addon needs to be configured!
    Please add at least the owner variable to your config file. For other variables please refer to the README file of the addon."] = "La kolofono (impressum) kromprogramo bezonas agordojn!
    Bonvolu aldoni minimume la owner variablon al via agorda dosiero. Por aliaj variabloj, bonvolu legi la README dosieron de la kromprogramo."; +$a->strings["The page operators name."] = "La nomo de la funkciigisto de la retejo."; +$a->strings["Site Owners Profile"] = "Profilo de la Proprietulo de la Retejo"; +$a->strings["Profile address of the operator."] = "La profilo de la funkciigisto de la retejo."; +$a->strings["How to contact the operator via snail mail. You can use BBCode here."] = "Kiel poÅte kontakti la funkciigisto de la retejo. Vi eblas uzi BBCode ĉi tie."; +$a->strings["Notes"] = "Notoj"; +$a->strings["Additional notes that are displayed beneath the contact information. You can use BBCode here."] = "Pli da notoj kiuj aperas sub la kontaktinformoj. Vi eblas uzi BBCode ĉi tie."; +$a->strings["How to contact the operator via email. (will be displayed obfuscated)"] = "Kiel kontakti la funkciigiston de la retejo per retpoÅto. (montriÄos vuale) "; +$a->strings["Footer note"] = "PaÄpiednoto"; +$a->strings["Text for the footer. You can use BBCode here."] = "Teksto por la paÄpiedo. Vie eblas uzi BBCode ĉi tie."; +$a->strings["Report Bug"] = "Skribi cimraporton"; +$a->strings["No Timeline settings updated."] = "No Timeline agordojn Äisdatigita."; +$a->strings["No Timeline Settings"] = "No Timeline Agordoj"; +$a->strings["Disable Archive selector on profile wall"] = "Malaktivigi la Arkivo elektilo sur la profilmuro"; +$a->strings["\"Blockem\" Settings"] = "\"Blockem\" Agordoj"; +$a->strings["Comma separated profile URLS to block"] = "Blokotaj URL adresoj, disigita per komo"; +$a->strings["BLOCKEM Settings saved."] = "Konservis Agordojn de BLOCKEM."; +$a->strings["Blocked %s - Click to open/close"] = "%s blokita - Klaku por malfermi/fermi"; +$a->strings["Unblock Author"] = "Malbloki AÅ­toron"; +$a->strings["Block Author"] = "Bloki AÅ­toron"; +$a->strings["blockem settings updated"] = "Äœisdatigis la blockem agordojn"; +$a->strings[":-)"] = ":-)"; +$a->strings[":-("] = ":-("; +$a->strings["lol"] = "lol"; +$a->strings["Quick Comment Settings"] = "Agordoj pri Rapidaj Komentoj"; +$a->strings["Quick comments are found near comment boxes, sometimes hidden. Click them to provide simple replies."] = "Rapidaj komentoj troviÄas apud komentkampoj, kelkfoje kaÅita. Klaku ilin por provizi simplajn rispondojn."; +$a->strings["Enter quick comments, one per line"] = "Entajpu rapidaj komentoj, po unu je linio."; +$a->strings["Quick Comment settings saved."] = "Konservis agordojn pri rapidaj komentoj."; +$a->strings["Tile Server URL"] = "Adreso de Kahelservilo"; +$a->strings["A list of public tile servers"] = "Listo de publikaj kahelserviloj"; +$a->strings["Default zoom"] = "DefaÅ­lta zoma faktoro"; +$a->strings["The default zoom level. (1:world, 18:highest)"] = "La defaÅ­lta zoma faktoro. (1:tutmonda, 18:plej proksima)"; +$a->strings["Post to libertree"] = "AfiÅi al libertree"; +$a->strings["libertree Post Settings"] = "Agordoj por AfiÅoj ĉe libertree"; +$a->strings["Enable Libertree Post Plugin"] = "Aktivigi Kromprogramon por AfiÅoj ĉe libertree"; +$a->strings["Libertree API token"] = "Libertree API ĵetono"; +$a->strings["Libertree site URL"] = "URL adreso de libertree retejo:"; +$a->strings["Post to Libertree by default"] = "DefaÅ­lte afiÅi ĉe Libertree"; +$a->strings["The MathJax addon renders mathematical formulae written using the LaTeX syntax surrounded by the usual $$ or an eqnarray block in the postings of your wall,network tab and private mail."] = "La Mathjax kromprogramo bildigas matematikajn formulojn skribitajn en la LaTeX sintakso, cirkaÅ­igita de la komuna $$ aÅ­ eqnarray bloko en afiÅoj ĉe via muro, Reto folio kaj privataj mesaÄoj."; +$a->strings["Use the MathJax renderer"] = "Ĉu uzi la Mathjax bildigilo"; +$a->strings["MathJax Base URL"] = "Mathjax Baza URL Adreso"; +$a->strings["The URL for the javascript file that should be included to use MathJax. Can be either the MathJax CDN or another installation of MathJax."] = "La URL adreso por la javascript dosiero kiu estas inkluzivigonta por uzi Mathjaz. Eblas esti aÅ­ la Mathjax CDN aÅ­ alia Mathjax instalo."; +$a->strings["Editplain settings updated."] = "Äœisdatigis la Editplain agordojn."; +$a->strings["Editplain Settings"] = "Agordoj por Editplain"; +$a->strings["Disable richtext status editor"] = "MalÅalti la riĉteksto-redaktilon"; +$a->strings["generic profile image"] = "komuna profilbildo"; +$a->strings["random geometric pattern"] = "loteca geometria skemo"; +$a->strings["monster face"] = "monstrobildo"; +$a->strings["computer generated face"] = "komputita vizaÄo"; +$a->strings["retro arcade style face"] = "retrostila videoludstila vizaÄo"; +$a->strings["Default avatar image"] = "DefaÅ­lta avatarbildo"; +$a->strings["Select default avatar image if none was found at Gravatar. See README"] = "Elektu defaÅ­ltan avatarbildon se neniu troviÄis ĉe Gravatar. Vidu README."; +$a->strings["Rating of images"] = "Pritakso de bildoj"; +$a->strings["Select the appropriate avatar rating for your site. See README"] = "Elektu la Äustan pritakson de via avataro por via retejo. Vidu README."; +$a->strings["Gravatar settings updated."] = "Gravatar agordoj Äisdatigitaj."; +$a->strings["Your Friendica test account is about to expire."] = "Via Friendica provkonto baldaÅ­ malaktiviÄos."; +$a->strings["Hi %1\$s,\n\nYour test account on %2\$s will expire in less than five days. We hope you enjoyed this test drive and use this opportunity to find a permanent Friendica website for your integrated social communications. A list of public sites is available at http://dir.friendica.com/siteinfo - and for more information on setting up your own Friendica server please see the Friendica project website at http://friendica.com."] = "Saluton %1\$s,\n\nVia testkonto ĉe %2\$s senvalidiÄos post malpli ol kvin tagoj. Vi esperas ke vi Äuis la teston kaj baldaÅ­ trovosÄustan Friendica retejon por via integrita sociala komunikado. Listo de publikaj retejoj troviÄas ĉe http://dir.friendica.com/siteinfo - kaj por pli da informoj pri kiel instali vian propran Friendica servilon, bonvolu viziti la retejon de la Friendica projekton ĉe http://friendica.com."; +$a->strings["\"pageheader\" Settings"] = "\"pageheader\" Agordoj"; +$a->strings["pageheader Settings saved."] = "Konservis Agordojn de pageheader."; +$a->strings["Post to Insanejournal"] = "AfiÅi al Insanejournal"; +$a->strings["InsaneJournal Post Settings"] = "Agordoj pri Insaenejournal AfiÅoj"; +$a->strings["Enable InsaneJournal Post Plugin"] = "Åœalti la InsaneJournal afiÅo kromprogramon."; +$a->strings["InsaneJournal username"] = "Salutnomo ĉe InsaneJournal"; +$a->strings["InsaneJournal password"] = "Pasvorto ĉe InsaneJournal"; +$a->strings["Post to InsaneJournal by default"] = "DefaÅ­lte afiÅi ĉe InsaneJournal"; +$a->strings["View Source"] = "Vidi Fonton"; +$a->strings["Post to StatusNet"] = "AfiÅi ĉe StatusNet"; +$a->strings["Please contact your site administrator.
    The provided API URL is not valid."] = "Bonvolu kontaki vian retejan administranton.
    La API URL adreso ne validas."; +$a->strings["We could not contact the StatusNet API with the Path you entered."] = "Ni ne povis trovi la StatusNet API kun la vojo kiun vi entajpis."; +$a->strings["StatusNet settings updated."] = "StatusNet agordoj Äisdatigita."; +$a->strings["StatusNet Posting Settings"] = "Agordoj por StausNet afiÅoj"; +$a->strings["Globally Available StatusNet OAuthKeys"] = "Äœeneralaj disponeblaj StatusNet OAuth Ålosiloj"; +$a->strings["There are preconfigured OAuth key pairs for some StatusNet servers available. If you are useing one of them, please use these credentials. If not feel free to connect to any other StatusNet instance (see below)."] = "Disponeblas antaÅ­agorditaj Ålosilparoj por kelkaj StatusNet serviloj. Se via uzas iun de iu, bonvolu uzi unun de tiuj legitimaĵojn. Se ne, bonvolu konekti al iu alia StatusNet servilo (vidu malsupre)."; +$a->strings["Provide your own OAuth Credentials"] = "Provizi viajn proprajn OAuth legitimaĵojn"; +$a->strings["No consumer key pair for StatusNet found. Register your Friendica Account as an desktop client on your StatusNet account, copy the consumer key pair here and enter the API base root.
    Before you register your own OAuth key pair ask the administrator if there is already a key pair for this Friendica installation at your favorited StatusNet installation."] = "Ne trovis klientajn Ålosilojn por StatusNet. Registru vian Friendica konton kiel klientkomputilo/desktop client en via StausNet konto. Kopiu la klientajn Ålosilojn ĉi tien kaj entajpu la baza API radiko.
    AntaÅ­ vi registros viajn proprajn OAuth Ålosilojn, demandu al la administranto ĉu jam ekzistas Ålosiloj por ĉi-tiu Friendia retejo je via StatusNet retejo."; +$a->strings["OAuth Consumer Key"] = "OAuth Åœlosilo de Kliento"; +$a->strings["OAuth Consumer Secret"] = "OAuth Sekreto de Kliento"; +$a->strings["Base API Path (remember the trailing /)"] = "Baza vojo al la API (ne forgesu la finan /)"; +$a->strings["To connect to your StatusNet account click the button below to get a security code from StatusNet which you have to copy into the input box below and submit the form. Only your public posts will be posted to StatusNet."] = "Por konekti al vian konton ĉe StatusNet, klaku la malsupran butonon por atingi sekurecan kodon de StatusNet, kiun vi devas alglui en la malsupra kampo kaj sendi la formon. Nur viaj publikaj afiÅoj estos afiÅota al StatusNet."; +$a->strings["Log in with StatusNet"] = "Ensaluti kun StatusNet."; +$a->strings["Copy the security code from StatusNet here"] = "Alglui la kodon de StatusNet ĉi tie:"; +$a->strings["Cancel Connection Process"] = "Nuligi Konektadon"; +$a->strings["Current StatusNet API is"] = "La nuna StatusNet API estas"; +$a->strings["Cancel StatusNet Connection"] = "Nuligi Konekton al StatusNet"; +$a->strings["Currently connected to: "] = "Konektita al:"; +$a->strings["If enabled all your public postings can be posted to the associated StatusNet account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry."] = "Kiam Åaltita, ĉiuj publikaj afiÅoj de vi ankaÅ­ eblas esti afiÅota al la asociigita StatusNet konto. Vi povas elekti Äin defaÅ­lte (ĉi tie) au unuope por ĉiuj afiÅoj kiam vi skribos ilin."; +$a->strings["Note: Due your privacy settings (Hide your profile details from unknown viewers?) the link potentially included in public postings relayed to StatusNet will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted."] = "Averto: LaÅ­ viaj privatecaj agordoj (KaÅi viajn profilajn detalojn al nekonataj spektantoj?), la ligilo en publikaj afiÅoj plusendata al StatusNet gvidas vizitontojn al malplena paÄo sciigante ilin ke atingo al via profilo estas lmitigita."; +$a->strings["Allow posting to StatusNet"] = "Permesi afiÅojn al StatusNet"; +$a->strings["Send public postings to StatusNet by default"] = "DefaÅ­lte sendi publikajn afiÅojn al StatusNet"; +$a->strings["Send linked #-tags and @-names to StatusNet"] = "Sendi ligitajn #-etikedojn kaj @-nomon al StatusNet"; +$a->strings["Clear OAuth configuration"] = "ForviÅi OAuth agordojn"; +$a->strings["API URL"] = "API URL adreso"; +$a->strings["Infinite Improbability Drive"] = "Senfina Probableca Pelilo"; +$a->strings["Post to Tumblr"] = "AfiÅi al Tumblr"; +$a->strings["Tumblr Post Settings"] = "Agordoj pri afiÅoj ĉe Tumblr"; +$a->strings["Enable Tumblr Post Plugin"] = "Åœalti la kromprogramon por Tumblr afiÅoj"; +$a->strings["Tumblr login"] = "Salutnomo ĉe Tumblr"; +$a->strings["Tumblr password"] = "Pasvorto ĉe Tumblr"; +$a->strings["Post to Tumblr by default"] = "DefaÅ­lte afiÅi ĉe Tumblr"; +$a->strings["Numfriends settings updated."] = "Äœisdatigis agordojn por Numfriends."; +$a->strings["Numfriends Settings"] = "Agordoj por Numfriends"; +$a->strings["How many contacts to display on profile sidebar"] = "Kiom da kontaktoj mi montru en la flanka strio"; +$a->strings["Gnot settings updated."] = "Äœisdatigis Gnot agordojn."; +$a->strings["Gnot Settings"] = "Agordoj por Gnot"; +$a->strings["Allows threading of email comment notifications on Gmail and anonymising the subject line."] = "Permesas la ĉenadon de retpoÅtaj atentigoj pri komentoj ĉe Gmail kan anonimigado de la temlinio."; +$a->strings["Enable this plugin/addon?"] = "Åœalti tiun kromprogramon?"; +$a->strings["[Friendica:Notify] Comment to conversation #%d"] = "[Friendica:Atentigo] Komento pri konversacio #%d"; +$a->strings["Post to Wordpress"] = "AfiÅi al Wordpress"; +$a->strings["WordPress Post Settings"] = "Agordoj por WordPress afiÅojn"; +$a->strings["Enable WordPress Post Plugin"] = "Åœalti la Wordpress-afiÅo kromprogramon"; +$a->strings["WordPress username"] = "WordPress salutnomo"; +$a->strings["WordPress password"] = "WordPress pasvorto"; +$a->strings["WordPress API URL"] = "Wordpress API URL adreso"; +$a->strings["Post to WordPress by default"] = "DefaÅ­lte afiÅi al WordPress"; +$a->strings["Provide a backlink to the Friendica post"] = "Provizi re-ligilon al la Friendica afiÅo"; +$a->strings["Read the original post and comment stream on Friendica"] = "Legi la originalan afiÅon kaj komentfluo ĉe Friendica"; +$a->strings["\"Show more\" Settings"] = "\"Montri pli\" agordoj"; +$a->strings["Enable Show More"] = "Åœalti \"montri pli\""; +$a->strings["Cutting posts after how much characters"] = "Limitigi afiÅojn al kiom da literoj"; +$a->strings["Show More Settings saved."] = "Konservis \"montri pli\" agordojn."; +$a->strings["This website is tracked using the Piwik analytics tool."] = "Ĉi retejo uzas Piwik kiel retuma analizilo."; +$a->strings["If you do not want that your visits are logged this way you can set a cookie to prevent Piwik from tracking further visits of the site (opt-out)."] = "Se ni ne protokolu viajn vizitojn tiel, vi povas agordi kuketon por malpermesi Piwik al plu protokoli pliajn vizitojn (mem-for-elekti / opt-out)."; +$a->strings["Piwik Base URL"] = "Piwik baza URL adreso"; +$a->strings["Absolute path to your Piwik installation. (without protocol (http/s), with trailing slash)"] = "Absoluta vojo al via Piwik instalo. (sen protokolo (http/s), inkluzive vosta oblikva streketo)"; +$a->strings["Site ID"] = "Reteja idento"; +$a->strings["Show opt-out cookie link?"] = "Montru ligilon al kuketo por mem-for-elekti (opt-out)?"; +$a->strings["Asynchronous tracking"] = "Nesinkrona spurado."; +$a->strings["Post to Twitter"] = "AfiÅi ĉe Twitter"; +$a->strings["Twitter settings updated."] = "Äœisdatigis Twitter agordojn."; +$a->strings["Twitter Posting Settings"] = "Agordoj por afiÅi ĉe Twitter"; +$a->strings["No consumer key pair for Twitter found. Please contact your site administrator."] = "Ne trovis klientajn Ålosilojn por Twitter. Bonvolu kontakti vian retejan administranton."; +$a->strings["At this Friendica instance the Twitter plugin was enabled but you have not yet connected your account to your Twitter account. To do so click the button below to get a PIN from Twitter which you have to copy into the input box below and submit the form. Only your public posts will be posted to Twitter."] = "Je ĉi tiu Friendica retejo, la Twitter kromprogramo jam estas Åaltita, sed via konto anokoraÅ­ ne estas konektita kun via Twitter konto. Por fari tion, klaku la supran butonon por atingi nombrokodon de Twitter, kion vi kopiu en la supran eniga ĉelo, kaj sendu la formularon. Nur viaj publikaj afiÅoj estas plusendota al Twitter. "; +$a->strings["Log in with Twitter"] = "Ensaluti kun Twitter"; +$a->strings["Copy the PIN from Twitter here"] = "Alglui la PIN de Twitter ĉi tie"; +$a->strings["If enabled all your public postings can be posted to the associated Twitter account. You can choose to do so by default (here) or for every posting separately in the posting options when writing the entry."] = "Kiam Åaltita, ĉiuj publikaj afiÅoj de vi ankaÅ­ eblas esti afiÅota al la asociigita Twitter konto. Vi povas elekti Äin defaÅ­lte (ĉi tie) au unuope por ĉiuj afiÅoj kiam vi skribos ilin."; +$a->strings["Note: Due your privacy settings (Hide your profile details from unknown viewers?) the link potentially included in public postings relayed to Twitter will lead the visitor to a blank page informing the visitor that the access to your profile has been restricted."] = "Averto: LaÅ­ viaj privatecaj agordoj (KaÅi viajn profilajn detalojn al nekonataj spektantoj?), la ligilo en publikaj afiÅoj plusendata al Twitter gvidas vizitontojn al malplena paÄo sciigante ilin ke atingo al via profilo estas lmitigita."; +$a->strings["Allow posting to Twitter"] = "Permesi afiÅojn al Twitter"; +$a->strings["Send public postings to Twitter by default"] = "DefaÅ­lte sendi publikajn afiÅojn al Twitter"; +$a->strings["Send linked #-tags and @-names to Twitter"] = "Sendi ligitajn #-etikedojn kaj @-nomon al Twitter"; +$a->strings["Consumer key"] = "Åœlosilo de Kliento"; +$a->strings["Consumer secret"] = "Sekreto de Kliento"; +$a->strings["IRC Settings"] = "IRC Agordoj"; +$a->strings["Channel(s) to auto connect (comma separated)"] = "AÅ­tomate konektiÄi al la kanalo(j) (disigita per komo)"; +$a->strings["Popular Channels (comma separated)"] = "Popularaj kanaloj (disigita per komo)"; +$a->strings["IRC settings saved."] = "IRC agordoj konservitaj."; +$a->strings["IRC Chatroom"] = "IRC babilejo"; +$a->strings["Popular Channels"] = "Popularaj Kanaloj"; +$a->strings["Post to blogger"] = "AfiÅi al blogger"; +$a->strings["Blogger Post Settings"] = "Agordo pri Blogger AfiÅoj"; +$a->strings["Enable Blogger Post Plugin"] = "Åœalti la Blogger afiÅo kromprogramon"; +$a->strings["Blogger username"] = "Blogger uzantonomo"; +$a->strings["Blogger password"] = "Blogger pasvorto"; +$a->strings["Blogger API URL"] = "Blogger API URL"; +$a->strings["Post to Blogger by default"] = "DefaÅ­lte afiÅi al Blogger"; +$a->strings["Post to Posterous"] = "AfiÅi al Posterous"; +$a->strings["Posterous Post Settings"] = "Agordoj pri afiÅoj ĉe Posterous"; +$a->strings["Enable Posterous Post Plugin"] = "Åœalti la Poserous-afiÅo kromprogramon"; +$a->strings["Posterous login"] = "Posterous salutnomo"; +$a->strings["Posterous password"] = "Posterous pasvorto"; +$a->strings["Posterous site ID"] = "Idento de Posterous retejo"; +$a->strings["Posterous API token"] = "API ĵetono de Posterous retejo"; +$a->strings["Post to Posterous by default"] = "DefaÅ­lte afiÅi al Posterous"; +$a->strings["Theme settings"] = "Agordoj pri la etoso"; +$a->strings["Set resize level for images in posts and comments (width and height)"] = "Agordi la regrandignivelo por bildoj en afiÅoj kaj komentoj (larÄo kaj alto)"; +$a->strings["Set font-size for posts and comments"] = "Agordi la tiparan grandon por afiÅoj kaj komentoj"; +$a->strings["Set theme width"] = "Agordi la larÄo por la etoso"; +$a->strings["Color scheme"] = "Kolorskemo"; +$a->strings["Your posts and conversations"] = "Viaj afiÅoj kaj komunikadoj"; +$a->strings["Your profile page"] = "Via profilo"; +$a->strings["Your contacts"] = "Viaj kontaktoj"; +$a->strings["Your photos"] = "Viaj bildoj"; +$a->strings["Your events"] = "Viaj okazoj"; +$a->strings["Personal notes"] = "Personaj notoj"; +$a->strings["Your personal photos"] = "Viaj personaj bildoj"; +$a->strings["Community Pages"] = "Komunumaj paÄoj"; +$a->strings["Community Profiles"] = "Komunumaj Profiloj"; +$a->strings["Last users"] = "Ä´usaj uzantoj"; +$a->strings["Last likes"] = "Ä´usaj Åatitaj elementoj"; +$a->strings["Last photos"] = "Ä´usaj bildoj"; +$a->strings["Find Friends"] = "Trovi Amikojn"; +$a->strings["Local Directory"] = "Loka Katalogo"; +$a->strings["Similar Interests"] = "Similaj Interesoj"; +$a->strings["Invite Friends"] = "Inviti amikojn"; +$a->strings["Earth Layers"] = "Tertavoloj (Earth Layers)"; +$a->strings["Set zoomfactor for Earth Layers"] = "Agordi zoman faktoron por Tertavoloj"; +$a->strings["Set longitude (X) for Earth Layers"] = "Agordi longitudon (X) por Tertavoloj"; +$a->strings["Set latitude (Y) for Earth Layers"] = "Agordi latitudon (Y) por Tertavoloj"; +$a->strings["Help or @NewHere ?"] = "Helpu aÅ­ @NewHere ?"; +$a->strings["Connect Services"] = "Konekti Servojn"; +$a->strings["Last Tweets"] = "Ä´usaj Pepaĵoj"; +$a->strings["Set twitter search term"] = "Agordi Twitter serĉtekston"; +$a->strings["don't show"] = "kaÅi"; +$a->strings["show"] = "montri"; +$a->strings["Show/hide boxes at right-hand column:"] = "KaÅi/montri kestojn ĉe dekstra kolumno:"; +$a->strings["Set line-height for posts and comments"] = "Agordi la linigrandon por afiÅoj kaj komentoj"; +$a->strings["Set resolution for middle column"] = "Agordi la distingivon por la meza kolumno"; +$a->strings["Set color scheme"] = "Agordi Kolorskemon"; +$a->strings["Set zoomfactor for Earth Layer"] = "Agordi zoman faktoron de Tertavolo"; +$a->strings["Last tweets"] = "Ä´usaj pepaĵoj"; +$a->strings["Alignment"] = "Äœisrandigo"; +$a->strings["Left"] = "Maldekstren"; +$a->strings["Center"] = "Centren"; +$a->strings["Set colour scheme"] = "Agordi Kolorskemon"; +$a->strings["Gender:"] = "Sekso:"; +$a->strings["j F, Y"] = "j F, Y"; +$a->strings["j F"] = "j F"; +$a->strings["Birthday:"] = "NaskiÄtago:"; +$a->strings["Age:"] = "AÄo:"; +$a->strings["Status:"] = "Stato:"; +$a->strings["for %1\$d %2\$s"] = "por %1\$d %2\$s"; +$a->strings["Homepage:"] = "HejmpaÄo:"; +$a->strings["Tags:"] = "Markoj:"; +$a->strings["Religion:"] = "Religio:"; +$a->strings["About:"] = "Pri:"; +$a->strings["Hobbies/Interests:"] = "Åœatokupoj/Interesoj:"; +$a->strings["Contact information and Social Networks:"] = "Kontaktinformoj kaj Interkonaj Retejoj:"; +$a->strings["Musical interests:"] = "Muzaikaj interesoj:"; +$a->strings["Books, literature:"] = "Libroj, literaturo:"; +$a->strings["Television:"] = "Televido:"; +$a->strings["Film/dance/culture/entertainment:"] = "Filmoj/dancoj/arto/amuzaĵoj:"; +$a->strings["Love/Romance:"] = "Amo/romanco:"; +$a->strings["Work/employment:"] = "Laboro:"; +$a->strings["School/education:"] = "Lernejo/eduko:"; +$a->strings["Unknown | Not categorised"] = "Nekonata | Nekatorigita"; +$a->strings["Block immediately"] = "Bloki tuj"; +$a->strings["Shady, spammer, self-marketer"] = "Suspekta, spamisto, memmerkatisto"; +$a->strings["Known to me, but no opinion"] = "Konata al mi, sed mi ne havas opinion"; +$a->strings["OK, probably harmless"] = "OK, verÅajne sendanÄera"; +$a->strings["Reputable, has my trust"] = "Fidinda laÅ­ mi"; +$a->strings["Frequently"] = "Ofte"; +$a->strings["Hourly"] = "Ĉiuhore"; +$a->strings["Twice daily"] = "Duope ĉiutage"; +$a->strings["Daily"] = "Ĉiutage"; +$a->strings["Weekly"] = "Ĉiusemajne"; +$a->strings["Monthly"] = "Ĉiumonate"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "LinkedIn"; +$a->strings["XMPP/IM"] = "XMPP/TujmesaÄilo"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["Male"] = "Vira"; +$a->strings["Female"] = "Ina"; +$a->strings["Currently Male"] = "Nuntempe Vira"; +$a->strings["Currently Female"] = "Nuntempe Ina"; +$a->strings["Mostly Male"] = "Ĉefe Vira"; +$a->strings["Mostly Female"] = "Ĉefe Ina"; +$a->strings["Transgender"] = "Transgenra"; +$a->strings["Intersex"] = "Interseksa"; +$a->strings["Transsexual"] = "Transseksa"; +$a->strings["Hermaphrodite"] = "Hermafrodita"; +$a->strings["Neuter"] = "NeÅ­tra"; +$a->strings["Non-specific"] = "Nespecifa"; +$a->strings["Other"] = "Alia"; +$a->strings["Undecided"] = "Nedecida"; +$a->strings["Males"] = "Viroj"; +$a->strings["Females"] = "Inoj"; +$a->strings["Gay"] = "Geja"; +$a->strings["Lesbian"] = "Lesba"; +$a->strings["No Preference"] = "Neniu Prefero"; +$a->strings["Bisexual"] = "AmbaÅ­seksema"; +$a->strings["Autosexual"] = "Memseksema"; +$a->strings["Abstinent"] = "Abstinema"; +$a->strings["Virgin"] = "Virgulino"; +$a->strings["Deviant"] = "Devia"; +$a->strings["Fetish"] = "Fetiĉo"; +$a->strings["Oodles"] = "Amasa"; +$a->strings["Nonsexual"] = "Neseksa"; +$a->strings["Single"] = "Sola"; +$a->strings["Lonely"] = "Soleca"; +$a->strings["Available"] = "Havebla"; +$a->strings["Unavailable"] = "Nehavebla"; +$a->strings["Has crush"] = "Sekrete enamiÄinta"; +$a->strings["Infatuated"] = "Blinda amo"; +$a->strings["Dating"] = "Rendevuanta"; +$a->strings["Unfaithful"] = "Malfidela"; +$a->strings["Sex Addict"] = "Seksmaniulo"; +$a->strings["Friends"] = "Amikoj"; +$a->strings["Friends/Benefits"] = "Amikoj/AvantaÄoj"; +$a->strings["Casual"] = "Neformala"; +$a->strings["Engaged"] = "Fianĉiginta"; +$a->strings["Married"] = "EdziÄinta"; +$a->strings["Imaginarily married"] = "Image edziÄinta"; +$a->strings["Partners"] = "Geparuloj"; +$a->strings["Cohabiting"] = "KunloÄanta"; +$a->strings["Common law"] = "Registrita partnereco "; +$a->strings["Happy"] = "Feliĉa"; +$a->strings["Not looking"] = "Ne interesiÄis"; +$a->strings["Swinger"] = "Swinger"; +$a->strings["Betrayed"] = "Trompita"; +$a->strings["Separated"] = "DisiÄinta"; +$a->strings["Unstable"] = "Malfirma"; +$a->strings["Divorced"] = "EksedziÄinta"; +$a->strings["Imaginarily divorced"] = "Image eksedziÄinta"; +$a->strings["Widowed"] = "Vidva"; +$a->strings["Uncertain"] = "Ne certa"; +$a->strings["It's complicated"] = "Estas komplika"; +$a->strings["Don't care"] = "Egala"; +$a->strings["Ask me"] = "Demandu min"; +$a->strings["Starts:"] = "Ekas:"; +$a->strings["Finishes:"] = "Finas:"; +$a->strings["(no subject)"] = "(neniu temo)"; +$a->strings["noreply"] = "nerespondi"; +$a->strings[" on Last.fm"] = " ĉe Last.fm"; +$a->strings["prev"] = "antaÅ­a"; +$a->strings["first"] = "unua"; +$a->strings["last"] = "lasta"; +$a->strings["next"] = "sekvanta"; +$a->strings["No contacts"] = "Neniu kontaktoj"; +$a->strings["%d Contact"] = array( + 0 => "%d Kontakto", + 1 => "%d Kontaktoj", +); +$a->strings["Monday"] = "Lundo"; +$a->strings["Tuesday"] = "Mardo"; +$a->strings["Wednesday"] = "Merkredo"; +$a->strings["Thursday"] = "Ä´aÅ­do"; +$a->strings["Friday"] = "Vendredo"; +$a->strings["Saturday"] = "Sabato"; +$a->strings["Sunday"] = "Dimanĉo"; +$a->strings["January"] = "Januaro"; +$a->strings["February"] = "Februaro"; +$a->strings["March"] = "Marto"; +$a->strings["April"] = "Aprilo"; +$a->strings["May"] = "Majo"; +$a->strings["June"] = "Junio"; +$a->strings["July"] = "Julio"; +$a->strings["August"] = "AÅ­gusto"; +$a->strings["September"] = "Septembro"; +$a->strings["October"] = "Oktobro"; +$a->strings["November"] = "Novembro"; +$a->strings["December"] = "Decembro"; +$a->strings["bytes"] = "bajtoj"; +$a->strings["remove"] = "forviÅi"; +$a->strings["[remove]"] = "[forviÅi]"; +$a->strings["Categories:"] = "Kategorioj:"; +$a->strings["Filed under:"] = "Enarkivigita kiel:"; +$a->strings["Click to open/close"] = "Klaku por malfermi/fermi"; +$a->strings["default"] = "defaÅ­lta"; +$a->strings["Select an alternate language"] = "Elekti alian lingvon"; +$a->strings["activity"] = "aktiveco"; +$a->strings["comment"] = "komento"; +$a->strings["post"] = "afiÅo"; +$a->strings["Item filed"] = "Enarkivigis elementon "; +$a->strings["Sharing notification from Diaspora network"] = "Antentigo pri kunhavigado de la Diaspora reto"; +$a->strings["Attachments:"] = "Kunsendaĵoj:"; +$a->strings["view full size"] = "vidi plengrande"; +$a->strings["Embedded content"] = "Enigita enhavo"; +$a->strings["Embedding disabled"] = "MalÅaltita enigitado"; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "Revivigis malnovan grupon kun la sama nomo. Permesoj por estantaj elementoj eble estas validaj por la grupo kaj estontaj membroj. Se tiu ne estas kiun vi atendis, bonvolu krei alian grupon kun alia nomo."; +$a->strings["Default privacy group for new contacts"] = "DefaÅ­lta privateca grupo por novaj kontaktoj"; +$a->strings["Everybody"] = "Ĉiuj"; +$a->strings["edit"] = "redakti"; +$a->strings["Groups"] = "Grupoj"; +$a->strings["Edit group"] = "Redakti grupon"; +$a->strings["Create a new group"] = "Krei novan grupon"; +$a->strings["Contacts not in any group"] = "Kontaktoj en neniu grupo"; +$a->strings["Logout"] = "Elsaluti"; +$a->strings["End this session"] = "Fini ĉi-tiun seancon"; +$a->strings["Status"] = "Stato"; +$a->strings["Sign in"] = "Ensaluti"; +$a->strings["Home Page"] = "HejmpaÄo"; +$a->strings["Create an account"] = "Krei konton"; +$a->strings["Help and documentation"] = "Helpo kaj dokumentado"; +$a->strings["Apps"] = "Programoj"; +$a->strings["Addon applications, utilities, games"] = "Kromprogramoj, utilaĵoj, ludiloj"; +$a->strings["Search site content"] = "Serĉu la retejon"; +$a->strings["Conversations on this site"] = "Konversacioj je ĉi-tiu retejo"; +$a->strings["Directory"] = "Katalogo"; +$a->strings["People directory"] = "Katalogo de homoj"; +$a->strings["Conversations from your friends"] = "Konversacioj de viaj amikoj"; +$a->strings["Friend Requests"] = "Kontaktpetoj"; +$a->strings["See all notifications"] = "Vidu ĉiujn atentigojn"; +$a->strings["Mark all system notifications seen"] = "Marki ĉiujn atentigojn legita"; +$a->strings["Private mail"] = "Privata poÅto"; +$a->strings["Inbox"] = "Enirkesto"; +$a->strings["Outbox"] = "Elirkesto"; +$a->strings["Manage"] = "Administri"; +$a->strings["Manage other pages"] = "Administri aliajn paÄojn"; +$a->strings["Profiles"] = "Profiloj"; +$a->strings["Manage/edit profiles"] = "Administri/redakti profilojn"; +$a->strings["Manage/edit friends and contacts"] = "Administri/redakti amikojn kaj kontaktojn"; +$a->strings["Site setup and configuration"] = "Agordoj pri la retejo"; +$a->strings["Nothing new here"] = "Estas neniu nova ĉi tie"; +$a->strings["Add New Contact"] = "Aldonu Novan Kontakton"; +$a->strings["Enter address or web location"] = "Entajpu adreson aÅ­ retlokon"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Ekzemple: bob@example.com, http://example.com/barbara"; +$a->strings["%d invitation available"] = array( + 0 => "Disponeblas %d invito", + 1 => "Disponeblas %d invitoj", +); +$a->strings["Find People"] = "Trovi Homojn"; +$a->strings["Enter name or interest"] = "Entajpu nomon aÅ­ intereson"; +$a->strings["Connect/Follow"] = "Konekti/Aboni"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Ekzemple: Robert Morgenstein, Fishing"; +$a->strings["Random Profile"] = "Hazarda Profilo"; +$a->strings["Networks"] = "Retoj"; +$a->strings["All Networks"] = "Ĉiuj Retoj"; +$a->strings["Saved Folders"] = "Konservitaj Dosierujoj"; +$a->strings["Everything"] = "Ĉio"; +$a->strings["Categories"] = "Kategorioj"; +$a->strings["Logged out."] = "Elsalutita."; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Okazis problemo ensalutinta kun via OpenID. Bonvolu kontroli la ID."; +$a->strings["The error message was:"] = "La erarmesaÄo estis:"; +$a->strings["Miscellaneous"] = "Diversaj"; +$a->strings["year"] = "jaro"; +$a->strings["month"] = "monato"; +$a->strings["day"] = "tago"; +$a->strings["never"] = "neniam"; +$a->strings["less than a second ago"] = "antaÅ­ malpli ol unu sekundo"; +$a->strings["years"] = "jaroj"; +$a->strings["months"] = "monatoj"; +$a->strings["week"] = "semajno"; +$a->strings["weeks"] = "semajnoj"; +$a->strings["days"] = "tagoj"; +$a->strings["hour"] = "horo"; +$a->strings["hours"] = "horoj"; +$a->strings["minute"] = "minuto"; +$a->strings["minutes"] = "minutoj"; +$a->strings["second"] = "sekundo"; +$a->strings["seconds"] = "sekundoj"; +$a->strings["%1\$d %2\$s ago"] = "antaÅ­ %1\$d %2\$s"; +$a->strings["%s's birthday"] = "NaskiÄtago de %s"; +$a->strings["Happy Birthday %s"] = "Feliĉan NaskiÄtagon al %s"; +$a->strings["From: "] = "De: "; +$a->strings["$1 wrote:"] = "$1 skribis:"; +$a->strings["Image/photo"] = "Bildo"; +$a->strings["Cannot locate DNS info for database server '%s'"] = "Ne trovis DNS informojn por datumbaza servilo '%s'."; +$a->strings["[no subject]"] = "[neniu temo]"; +$a->strings["Visible to everybody"] = "Videbla al ĉiuj"; +$a->strings["Friendica Notification"] = "Friendica Atentigo"; +$a->strings["Thank You,"] = "Dankon,"; +$a->strings["%s Administrator"] = "%s Administranto"; +$a->strings["%s "] = "%s "; +$a->strings["[Friendica:Notify] New mail received at %s"] = "[Friendica:Atentigo] Ricevis novan retpoÅton ĉe %s"; +$a->strings["%1\$s sent you a new private message at %2\$s."] = "%1\$s sendis al vi novan privatan mesaÄon ĉe %2\$s."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s sendis al vi %2\$s."; +$a->strings["a private message"] = "privatan mesaÄon"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Bonvolu viziti %s por vidi aÅ­ respondi viajn privatajn mesaÄojn."; +$a->strings["%1\$s commented on [url=%2\$s]a %3\$s[/url]"] = "%1\$s komentis pri [url=%2\$s]%3\$s[/url]"; +$a->strings["%1\$s commented on [url=%2\$s]%3\$s's %4\$s[/url]"] = "%1\$s komentis pri [url=%2\$s]%4\$s de %3\$s[/url]"; +$a->strings["%1\$s commented on [url=%2\$s]your %3\$s[/url]"] = "%1\$s komentis pri [url=%2\$s]via %3\$s[/url]"; +$a->strings["[Friendica:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Friendica:Atentigo] Komento pri konversacio #%1\$d de %2\$s"; +$a->strings["%s commented on an item/conversation you have been following."] = "%s komentis pri elemento/konversacio kiun vi sekvas."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Bonvolu viziti %s por vidi aÅ­ respondi la konversacion."; +$a->strings["[Friendica:Notify] %s posted to your profile wall"] = "[Friendica:Atentigo] %s afiÅis al via profilmuro"; +$a->strings["%1\$s posted to your profile wall at %2\$s"] = "%1\$s skribis al via profilmuro ĉe %2\$s"; +$a->strings["%1\$s posted to [url=%2s]your wall[/url]"] = "%1\$s afiÅis al [url=%2s]via muro[/url]"; +$a->strings["[Friendica:Notify] %s tagged you"] = "[Friendica:Atentigo] %s markis vin"; +$a->strings["%1\$s tagged you at %2\$s"] = "%1\$s markis vin ĉe %2\$s"; +$a->strings["%1\$s [url=%2\$s]tagged you[/url]."] = "%1\$s [url=%2\$s]markis vin[/url]."; +$a->strings["[Friendica:Notify] %s tagged your post"] = "[Friendica:Atentigo] %s markis vian afiÅon"; +$a->strings["%1\$s tagged your post at %2\$s"] = "%1\$s markis vian afiÅon ĉe %2\$s"; +$a->strings["%1\$s tagged [url=%2\$s]your post[/url]"] = "%1\$s markis [url=%2\$s]vian afiÅon[/url]"; +$a->strings["[Friendica:Notify] Introduction received"] = "[Friendica:Atentigo] Ricevis prezenton"; +$a->strings["You've received an introduction from '%1\$s' at %2\$s"] = "Vi ricevis prezenton de '%1\$s' ĉe %2\$s"; +$a->strings["You've received [url=%1\$s]an introduction[/url] from %2\$s."] = "Vi ricevis [url=%1\$s]prezenton[/url] de %2\$s."; +$a->strings["You may visit their profile at %s"] = "Vi povas vidi la profilon de li aÅ­ Åi ĉe %s"; +$a->strings["Please visit %s to approve or reject the introduction."] = "Bonvolu viziti %s por aprobi aÅ­ malaprobi la prezenton."; +$a->strings["[Friendica:Notify] Friend suggestion received"] = "[Friendica:Atentigo] Ricevis amikosugeston"; +$a->strings["You've received a friend suggestion from '%1\$s' at %2\$s"] = "Vi ricevis amikosugeston de '%1\$s' ĉe %2\$s"; +$a->strings["You've received [url=%1\$s]a friend suggestion[/url] for %2\$s from %3\$s."] = "Vi ricevis [url=%1\$s]amikosugeston[/url] pri %2\$s de %3\$s."; +$a->strings["Name:"] = "Nomo:"; +$a->strings["Photo:"] = "Bildo:"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Bonvolu viziti %s por aprobi aÅ­ malaprobi la sugeston."; +$a->strings["Connect URL missing."] = "Ne ekzistas URL adreso por konekti."; +$a->strings["This site is not configured to allow communications with other networks."] = "Tiu retpaÄo ne permesas komunikadon kun aliaj retoj."; +$a->strings["No compatible communication protocols or feeds were discovered."] = "Ne malkovris kongruajn protokolojn por komunikado aÅ­ fluojn."; +$a->strings["The profile address specified does not provide adequate information."] = "La specifita profiladreso ne enhavas sufiĉe da informoj."; +$a->strings["An author or name was not found."] = "Ne trovis aÅ­toron aÅ­ nomon."; +$a->strings["No browser URL could be matched to this address."] = "Neniu retuma URL adreso kongruas al la adreso."; +$a->strings["Unable to match @-style Identity Address with a known protocol or email contact."] = "Ne eblas kongrui @-stilan identecon adreson al iu konata protokolo au retpoÅtadreso."; +$a->strings["Use mailto: in front of address to force email check."] = "Uzu mailto: antaÅ­ la adreso por devigi la testadon per retpoÅto."; +$a->strings["The profile address specified belongs to a network which has been disabled on this site."] = "Tiu profila adreso apartenas al retejo kiu estas maÅaltita je ĉi tiu retejo."; +$a->strings["Limited profile. This person will be unable to receive direct/personal notifications from you."] = "Profilo limigata. Ĉi persono ne eblos ricevi rektajn/personajn atentigojn de vi. "; +$a->strings["Unable to retrieve contact information."] = "Ne eblas ricevi kontaktinformojn."; +$a->strings["following"] = "sekvanta"; +$a->strings["A new person is sharing with you at "] = "Nova persono kunhavigas kun vi ĉe "; +$a->strings["You have a new follower at "] = "Vi havas novan sekvanton ĉe "; +$a->strings["Archives"] = "Arkivoj"; +$a->strings["An invitation is required."] = "Invio bezonata."; +$a->strings["Invitation could not be verified."] = "Ne povis kontroli la inviton."; +$a->strings["Invalid OpenID url"] = "Nevalida OpenID adreso"; +$a->strings["Please enter the required information."] = "Bonvolu entajpi la bezonatajn informojn."; +$a->strings["Please use a shorter name."] = "Bonvolu uzi pli mallongan nomon."; +$a->strings["Name too short."] = "Nomo estas tro mallonga."; +$a->strings["That doesn't appear to be your full (First Last) name."] = "Tio Åajne ne estas via plena (persona, familia) nomo."; +$a->strings["Your email domain is not among those allowed on this site."] = "Via retpoÅtodomajno ne estas permesita ĉi tie."; +$a->strings["Not a valid email address."] = "Nevalida retpoÅtadreso."; +$a->strings["Cannot use that email."] = "Neuzebla retpoÅtadreso."; +$a->strings["Your \"nickname\" can only contain \"a-z\", \"0-9\", \"-\", and \"_\", and must also begin with a letter."] = "Via kaÅnomo nur povas enhavi \"a-z\", \"0-9\", \"-\", kaj \"_\". Äœi ankaÅ­ devas komenci kun litero."; +$a->strings["Nickname is already registered. Please choose another."] = "Tio kaÅnomo jam estas registrita. Bonvolu elekti alian."; +$a->strings["Nickname was once registered here and may not be re-used. Please choose another."] = "Tiu kaÅnomo iam estis registrita ĉi tie kaj ne ree uzeblas. Bonvolu elekti alian."; +$a->strings["SERIOUS ERROR: Generation of security keys failed."] = "GRAVA ERARO: La generacio de sekurecaj ĉifroÅlosiloj malsukcesis."; +$a->strings["An error occurred during registration. Please try again."] = "Eraro okazis dum registrado. Bonvolu provi denove."; +$a->strings["An error occurred creating your default profile. Please try again."] = "Eraro okazi dum kreado de via defaÅ­lta profilo. Bonvolu provi denove."; +$a->strings["Welcome "] = "Bonvenon "; +$a->strings["Please upload a profile photo."] = "Bonvolu alÅuti profilbildon."; +$a->strings["Welcome back "] = "Bonvenon "; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "La sekuriga ĵetono de la formo estis malÄusta. Tio verÅajne okazis ĉar la formo estis malfermita dum tro longa tempo (>3 horoj) antaÅ­ la sendado."; +$a->strings["stopped following"] = "ne plu sekvas"; +$a->strings["View Status"] = "Vidi Staton"; +$a->strings["View Profile"] = "Vidi Profilon"; +$a->strings["View Photos"] = "Vidi Bildojn"; +$a->strings["Network Posts"] = "Enretaj AfiÅoj"; +$a->strings["Edit Contact"] = "Redakti Kontakton"; +$a->strings["Send PM"] = "Sendi PM"; +$a->strings["post/item"] = "afiÅo/elemento"; +$a->strings["%1\$s marked %2\$s's %3\$s as favorite"] = "%1\$s markis la %3\$s de %2\$s kiel preferita."; +$a->strings["Select"] = "Elekti"; +$a->strings["View %s's profile @ %s"] = "Vidi la profilon de %s ĉe %s"; +$a->strings["%s from %s"] = "%s de %s"; +$a->strings["View in context"] = "Vidi kun kunteksto"; +$a->strings["%d comment"] = array( + 0 => "%d komento", + 1 => "%d komentoj", +); +$a->strings["like"] = "Åati"; +$a->strings["dislike"] = "malÅati"; +$a->strings["Share this"] = "Kunhavigi ĉi tiun"; +$a->strings["share"] = "kunhavigi"; +$a->strings["Bold"] = "Grasa"; +$a->strings["Italic"] = "Kursiva"; +$a->strings["Underline"] = "Substreki"; +$a->strings["Quote"] = "Citaĵo"; +$a->strings["Code"] = "Kodo"; +$a->strings["Image"] = "Bildo"; +$a->strings["Link"] = "Ligilo"; +$a->strings["Video"] = "Video"; +$a->strings["add star"] = "aldoni stelon"; +$a->strings["remove star"] = "forpreni stelon"; +$a->strings["toggle star status"] = "Åalti/malÅalti steloÅtato"; +$a->strings["starred"] = "steligita"; +$a->strings["add tag"] = "aldoni markon"; +$a->strings["save to folder"] = "konservi en dosierujo"; +$a->strings["to"] = "al"; +$a->strings["Wall-to-Wall"] = "Muro-al-Muro"; +$a->strings["via Wall-To-Wall:"] = "per Muro-al-Muro:"; +$a->strings["Delete Selected Items"] = "ForviÅi Elektitajn Elementojn"; +$a->strings["%s likes this."] = "%s Åatas tiun."; +$a->strings["%s doesn't like this."] = "%s malÅatas tiun."; +$a->strings["%2\$d people like this."] = "%2\$d homoj Åatas tiun."; +$a->strings["%2\$d people don't like this."] = "%2\$d homojmalÅatas tiun."; +$a->strings["and"] = "kaj"; +$a->strings[", and %d other people"] = ", kaj %d aliaj homoj."; +$a->strings["%s like this."] = "%s Åatas tiun."; +$a->strings["%s don't like this."] = "%s malÅatas tiun."; +$a->strings["Visible to everybody"] = "Videbla al ĉiuj"; +$a->strings["Please enter a video link/URL:"] = "Bonvolu entajpi ligilon/adreson de video:"; +$a->strings["Please enter an audio link/URL:"] = "Bonvolu entajpi ligilon/adreson de sono:"; +$a->strings["Tag term:"] = "Markfrazo:"; +$a->strings["Where are you right now?"] = "Kie vi estas nun?"; +$a->strings["upload photo"] = "alÅuti bildon"; +$a->strings["attach file"] = "kunsendi dosieron"; +$a->strings["web link"] = "TTT ligilo"; +$a->strings["Insert video link"] = "Alglui ligilon de video"; +$a->strings["video link"] = "video ligilo"; +$a->strings["Insert audio link"] = "Alglui ligilon de sono"; +$a->strings["audio link"] = "sono ligilo"; +$a->strings["set location"] = "agordi lokon"; +$a->strings["clear location"] = "forviÅi lokon"; +$a->strings["permissions"] = "permesoj"; +$a->strings["Click here to upgrade."] = "Klaku ĉi tie por Äisdatigi."; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Tia ago preterpasas la limojn de via abono."; +$a->strings["This action is not available under your subscription plan."] = "Tia ago ne estas permesita laÅ­ via abono."; +$a->strings["Delete this item?"] = "ForviÅi ĉi tiun elementon?"; +$a->strings["show fewer"] = "montri malpli"; +$a->strings["Update %s failed. See error logs."] = "Malsukcesis Äisdatigi %s. Vidu la protokolojn."; +$a->strings["Update Error at %s"] = "Eraro dum Äisdatigo ĉe %s"; +$a->strings["Create a New Account"] = "Krei Novan Konton"; +$a->strings["Nickname or Email address: "] = "KaÅnomo aÅ­ retpoÅtadreso:"; +$a->strings["Password: "] = "Pasvorto:"; +$a->strings["Or login using OpenID: "] = "AÅ­ ensaluti per OpenID:"; +$a->strings["Forgot your password?"] = "Ĉu vi vorgesis vian pasvorton?"; +$a->strings["Edit profile"] = "Redakti profilon"; +$a->strings["Message"] = "MesaÄo"; +$a->strings["g A l F d"] = "\\j\\e \\l\\a G\\a \\h\\o\\r\\o, l F d"; +$a->strings["F d"] = "F d"; +$a->strings["[today]"] = "[hodiaÅ­]"; +$a->strings["Birthday Reminders"] = "Memorigilo pri naskiÄtagoj"; +$a->strings["Birthdays this week:"] = "NaskiÄtagoj ĉi-semajne:"; +$a->strings["[No description]"] = "[Neniu priskribo]"; +$a->strings["Event Reminders"] = "Memorigilo pri Okazoj"; +$a->strings["Events this week:"] = "Okazoj ĉi-semajne:"; +$a->strings["Status Messages and Posts"] = "ÅœtatmesaÄoj kaj AfiÅoj"; +$a->strings["Profile Details"] = "Profildetaloj"; +$a->strings["Events and Calendar"] = "Okazoj kaj Kalendaro"; +$a->strings["Only You Can See This"] = "Nur Vi Povas Vidi Tiun"; diff --git a/sources/view/eo/update_fail_eml.tpl b/sources/view/eo/update_fail_eml.tpl new file mode 100644 index 00000000..61f44b1e --- /dev/null +++ b/sources/view/eo/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Hey, +I'm the web server at {{$sitename}}; + +The Hubzilla developers released update {{$update}} recently, +but when I tried to install it, something went terribly wrong. +This needs to be fixed soon and it requires human intervention. +Please contact a Red developer if you can not figure out how to +fix it on your own. My database might be invalid. + +The error message is '{{$error}}'. + +Apologies for the inconvenience, + your web server at {{$siteurl}} \ No newline at end of file diff --git a/sources/view/es/lostpass_eml.tpl b/sources/view/es/lostpass_eml.tpl new file mode 100644 index 00000000..0ae657ac --- /dev/null +++ b/sources/view/es/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Estimado {{$username}}, + Una petición fue recibida recientemente en {{$sitename}} para cambiar la contraseña de su cuenta +contraseña. Para confirmar esta petición, por favor, selecciona el enlace de verificación +de más abajo o corte y pégelo en la barra de su navegador web. + +Si no hizo esta petición de cambio, por favor, NO siga el enlace +que encontrará más abajo e ignore y/o borre este correo electrónico. + +Su contraseña no será cambiada hasta que verifiquemos que es usted +envió esta petición. + +Siga el enlace para verificar su identidad: + +{{$reset_link}} + +Seguidamente recibirá un mensaje con la nueva contraseña. + +Puede cambiar esta contraseña desde tu cuenta después de iniciar sesión. + +Los detalles del inicio de sesión son los siguientes: + +Localización del Sitio: {{$siteurl}} +Nombre de usuario: {{$email}} + + + + +Atentamente, + Administrador de {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/es/messages.po b/sources/view/es/messages.po new file mode 100644 index 00000000..7d133cb3 --- /dev/null +++ b/sources/view/es/messages.po @@ -0,0 +1,9076 @@ +# Red Matrix Project +# Copyright (C) 2012-2014 the Red Matrix Project +# This file is distributed under the same license as the Red package. +# +# Translators: +# boquiabierto , 2013-2014 +# Alfonso , 2015 +# jeroenpraat , 2015 +# Manuel Jiménez Friaza , 2015 +# Rafael, 2015 +# tony baldwin , 2014 +msgid "" +msgstr "" +"Project-Id-Version: Redmatrix\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-08-14 00:04-0700\n" +"PO-Revision-Date: 2015-08-20 11:57+0000\n" +"Last-Translator: Manuel Jiménez Friaza \n" +"Language-Team: Spanish (http://www.transifex.com/Friendica/red-matrix/language/es/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: es\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../../include/dba/dba_driver.php:141 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "No se ha podido localizar información para el servidor de base de datos “%sâ€" + +#: ../../include/photo/photo_driver.php:687 ../../mod/profile_photo.php:143 +#: ../../mod/profile_photo.php:302 ../../mod/profile_photo.php:424 +#: ../../mod/photos.php:92 ../../mod/photos.php:637 +msgid "Profile Photos" +msgstr "Fotos de perfil" + +#: ../../include/menu.php:107 ../../include/page_widgets.php:8 +#: ../../include/page_widgets.php:36 ../../include/RedDAV/RedBrowser.php:266 +#: ../../include/ItemObject.php:100 ../../include/apps.php:254 +#: ../../mod/webpages.php:181 ../../mod/thing.php:227 +#: ../../mod/connections.php:382 ../../mod/connections.php:395 +#: ../../mod/connections.php:414 ../../mod/blocks.php:153 +#: ../../mod/editpost.php:106 ../../mod/editlayout.php:133 +#: ../../mod/editwebpage.php:178 ../../mod/editblock.php:134 +#: ../../mod/menu.php:103 ../../mod/settings.php:650 ../../mod/layouts.php:183 +msgid "Edit" +msgstr "Editar" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Frecuentemente" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Cada hora" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Dos veces al día" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Diariamente" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Semanalmente" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Mensualmente" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:822 +#: ../../mod/admin.php:831 ../../mod/id.php:15 ../../mod/id.php:16 +#: ../../boot.php:1553 +msgid "Email" +msgstr "Correo electrónico" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "LinkedIn" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/IM" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "Crear una nueva entrada" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +msgstr "comentar la entrada de %s" + +#: ../../include/Import/import_diaspora.php:17 +msgid "No username found in import file." +msgstr "No se ha encontrado el nombre de usuario en el archivo importado." + +#: ../../include/Import/import_diaspora.php:42 ../../mod/import.php:156 +msgid "Unable to create a unique channel address. Import failed." +msgstr "No se ha podido crear una dirección de canal única. Ha fallado la importación." + +#: ../../include/Import/import_diaspora.php:140 ../../mod/import.php:530 +msgid "Import completed." +msgstr "Importación completada." + +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "Un grupo suprimido con éste nombre ha sido reestablecido. Es posible que los permisos existentes sean aplicados a éste grupo y sus futuros miembros. Si no quiere esto por favor cree otro grupo con un nombre diferente." + +#: ../../include/group.php:235 +msgid "Default privacy group for new contacts" +msgstr "Grupo de privacidad por defecto para nuevos contactos " + +#: ../../include/group.php:254 ../../mod/admin.php:831 +msgid "All Channels" +msgstr "Todos los canales" + +#: ../../include/group.php:276 +msgid "edit" +msgstr "editar" + +#: ../../include/group.php:298 +msgid "Collections" +msgstr "Colecciones" + +#: ../../include/group.php:299 +msgid "Edit collection" +msgstr "Editar colección" + +#: ../../include/group.php:300 +msgid "Add new collection" +msgstr "Añadir nueva colección" + +#: ../../include/group.php:301 +msgid "Channels not in any collection" +msgstr "El canal no se encuentra en ninguna colección" + +#: ../../include/group.php:303 ../../include/widgets.php:275 +msgid "add" +msgstr "añadir" + +#: ../../include/account.php:27 +msgid "Not a valid email address" +msgstr "Dirección de correo inválida" + +#: ../../include/account.php:29 +msgid "Your email domain is not among those allowed on this site" +msgstr "Su dirección de correo no pertenece a los dominios permitidos en este sitio." + +#: ../../include/account.php:35 +msgid "Your email address is already registered at this site." +msgstr "Su dirección de correo está ya registrada en este sitio." + +#: ../../include/account.php:67 +msgid "An invitation is required." +msgstr "Es obligatorio que le inviten." + +#: ../../include/account.php:71 +msgid "Invitation could not be verified." +msgstr "No se ha podido verificar su invitación." + +#: ../../include/account.php:121 +msgid "Please enter the required information." +msgstr "Por favor introduzca la información requerida." + +#: ../../include/account.php:188 +msgid "Failed to store account information." +msgstr "La información de la cuenta no se ha podido guardar." + +#: ../../include/account.php:246 +#, php-format +msgid "Registration confirmation for %s" +msgstr "Confirmación de registro para %s" + +#: ../../include/account.php:312 +#, php-format +msgid "Registration request at %s" +msgstr "Solicitud de registro en %s" + +#: ../../include/account.php:314 ../../include/account.php:341 +#: ../../include/account.php:401 ../../include/network.php:1632 +msgid "Administrator" +msgstr "Administrador" + +#: ../../include/account.php:336 +msgid "your registration password" +msgstr "su contraseña de registro" + +#: ../../include/account.php:339 ../../include/account.php:399 +#, php-format +msgid "Registration details for %s" +msgstr "Detalles del registro para %s" + +#: ../../include/account.php:408 +msgid "Account approved." +msgstr "Cuenta aprobada." + +#: ../../include/account.php:447 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registro rechazado para %s" + +#: ../../include/account.php:492 +msgid "Account verified. Please login." +msgstr "Cuenta verificada. Por favor, inicia sesión." + +#: ../../include/account.php:705 ../../include/account.php:707 +msgid "Click here to upgrade." +msgstr "Pulse aquí para actualizar" + +#: ../../include/account.php:713 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Ésta acción supera los límites establecidos por su plan de suscripción " + +#: ../../include/account.php:718 +msgid "This action is not available under your subscription plan." +msgstr "Esta acción no está disponible en su plan de suscripción." + +#: ../../include/datetime.php:48 +msgid "Miscellaneous" +msgstr "Varios" + +#: ../../include/datetime.php:132 +msgid "YYYY-MM-DD or MM-DD" +msgstr "YYYY-MM-DD o MM-DD" + +#: ../../include/datetime.php:235 ../../mod/events.php:649 +#: ../../mod/appman.php:91 ../../mod/appman.php:92 +msgid "Required" +msgstr "Obligatorio" + +#: ../../include/datetime.php:262 ../../boot.php:2354 +msgid "never" +msgstr "nunca" + +#: ../../include/datetime.php:268 +msgid "less than a second ago" +msgstr "hace un instante" + +#: ../../include/datetime.php:271 +msgid "year" +msgstr "año" + +#: ../../include/datetime.php:271 +msgid "years" +msgstr "años" + +#: ../../include/datetime.php:272 +msgid "month" +msgstr "mes" + +#: ../../include/datetime.php:272 +msgid "months" +msgstr "meses" + +#: ../../include/datetime.php:273 +msgid "week" +msgstr "semana" + +#: ../../include/datetime.php:273 +msgid "weeks" +msgstr "semanas" + +#: ../../include/datetime.php:274 +msgid "day" +msgstr "día" + +#: ../../include/datetime.php:274 +msgid "days" +msgstr "días" + +#: ../../include/datetime.php:275 +msgid "hour" +msgstr "hora" + +#: ../../include/datetime.php:275 +msgid "hours" +msgstr "horas" + +#: ../../include/datetime.php:276 +msgid "minute" +msgstr "minuto" + +#: ../../include/datetime.php:276 +msgid "minutes" +msgstr "minutos" + +#: ../../include/datetime.php:277 +msgid "second" +msgstr "segundo" + +#: ../../include/datetime.php:277 +msgid "seconds" +msgstr "segundos" + +#: ../../include/datetime.php:285 +#, php-format +msgctxt "e.g. 22 hours ago, 1 minute ago" +msgid "%1$d %2$s ago" +msgstr "Hace %1$d y %2$s" + +#: ../../include/datetime.php:519 +#, php-format +msgid "%1$s's birthday" +msgstr "Cumpleaños de %1$s" + +#: ../../include/datetime.php:520 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "Feliz cumpleaños %1$s" + +#: ../../include/dir_fns.php:126 +msgid "Directory Options" +msgstr "Opciones del directorio" + +#: ../../include/dir_fns.php:128 +msgid "Safe Mode" +msgstr "Modo seguro" + +#: ../../include/dir_fns.php:128 ../../include/dir_fns.php:129 +#: ../../include/dir_fns.php:130 ../../mod/api.php:106 +#: ../../mod/photos.php:568 ../../mod/mitem.php:157 ../../mod/mitem.php:158 +#: ../../mod/mitem.php:229 ../../mod/mitem.php:230 ../../mod/menu.php:91 +#: ../../mod/menu.php:147 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:428 +#: ../../mod/settings.php:579 ../../mod/removeme.php:60 +#: ../../mod/connedit.php:635 ../../mod/connedit.php:663 +#: ../../view/theme/redbasic/php/config.php:104 +#: ../../view/theme/redbasic/php/config.php:129 ../../boot.php:1555 +msgid "No" +msgstr "No" + +#: ../../include/dir_fns.php:128 ../../include/dir_fns.php:129 +#: ../../include/dir_fns.php:130 ../../mod/api.php:105 +#: ../../mod/photos.php:568 ../../mod/mitem.php:157 ../../mod/mitem.php:158 +#: ../../mod/mitem.php:229 ../../mod/mitem.php:230 ../../mod/menu.php:91 +#: ../../mod/menu.php:147 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:430 +#: ../../mod/settings.php:579 ../../mod/removeme.php:60 +#: ../../view/theme/redbasic/php/config.php:104 +#: ../../view/theme/redbasic/php/config.php:129 ../../boot.php:1555 +msgid "Yes" +msgstr "Sí" + +#: ../../include/dir_fns.php:129 +msgid "Public Forums Only" +msgstr "Solamente foros públicos" + +#: ../../include/dir_fns.php:130 +msgid "This Website Only" +msgstr "Solamente este sitio web" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "Nueva página" + +#: ../../include/page_widgets.php:39 ../../mod/webpages.php:187 +#: ../../mod/blocks.php:159 ../../mod/layouts.php:188 +msgid "View" +msgstr "Ver" + +#: ../../include/page_widgets.php:40 ../../include/ItemObject.php:677 +#: ../../include/conversation.php:1155 ../../mod/webpages.php:188 +#: ../../mod/events.php:667 ../../mod/editpost.php:143 +#: ../../mod/photos.php:982 ../../mod/editwebpage.php:214 +#: ../../mod/editblock.php:170 +msgid "Preview" +msgstr "Previsualizar" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:189 +msgid "Actions" +msgstr "Acciones" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:190 +msgid "Page Link" +msgstr "Vínculo de la página" + +#: ../../include/page_widgets.php:43 +msgid "Title" +msgstr "Título" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:192 +#: ../../mod/blocks.php:150 ../../mod/menu.php:105 ../../mod/layouts.php:181 +msgid "Created" +msgstr "Creado" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:193 +#: ../../mod/blocks.php:151 ../../mod/menu.php:106 ../../mod/layouts.php:182 +msgid "Edited" +msgstr "Editado" + +#: ../../include/api.php:1193 +msgid "Public Timeline" +msgstr "Cronología pública" + +#: ../../include/comanche.php:34 ../../mod/admin.php:390 +#: ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "Predeterminado" + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "¿Borrar este elemento?" + +#: ../../include/js_strings.php:6 ../../include/ItemObject.php:667 +#: ../../mod/photos.php:980 ../../mod/photos.php:1098 +msgid "Comment" +msgstr "Comentar" + +#: ../../include/js_strings.php:7 ../../include/ItemObject.php:384 +msgid "[+] show all" +msgstr "[+] mostrar todo" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "[-] mostrar menos" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "[+] expandir" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "[-] contraer" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "Contraseña demasiado corta" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "Las contraseñas no cinciden" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:40 +msgid "everybody" +msgstr "cualquiera" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "Contraseña secreta" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "Pista de contraseña" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "Aviso: los permisos han cambiado pero aún no han sido enviados." + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "cerrar todo" + +#: ../../include/js_strings.php:18 +msgid "Nothing new here" +msgstr "Nada nuevo por aquí" + +#: ../../include/js_strings.php:19 +msgid "Rate This Channel (this is public)" +msgstr "Valorar este canal (esto es público)" + +#: ../../include/js_strings.php:20 ../../mod/rate.php:156 +#: ../../mod/connedit.php:671 +msgid "Rating" +msgstr "Valoración" + +#: ../../include/js_strings.php:21 +msgid "Describe (optional)" +msgstr "Describir (opcional)" + +#: ../../include/js_strings.php:22 ../../include/ItemObject.php:668 +#: ../../mod/xchan.php:11 ../../mod/connect.php:93 ../../mod/thing.php:275 +#: ../../mod/thing.php:318 ../../mod/events.php:494 ../../mod/events.php:670 +#: ../../mod/group.php:81 ../../mod/photos.php:577 ../../mod/photos.php:654 +#: ../../mod/photos.php:941 ../../mod/photos.php:981 ../../mod/photos.php:1099 +#: ../../mod/pdledit.php:58 ../../mod/import.php:560 ../../mod/chat.php:177 +#: ../../mod/chat.php:211 ../../mod/mitem.php:232 ../../mod/rate.php:167 +#: ../../mod/invite.php:142 ../../mod/locs.php:105 ../../mod/sources.php:104 +#: ../../mod/sources.php:138 ../../mod/filestorage.php:156 +#: ../../mod/fsuggest.php:108 ../../mod/poke.php:166 +#: ../../mod/profiles.php:667 ../../mod/setup.php:327 ../../mod/setup.php:367 +#: ../../mod/admin.php:453 ../../mod/admin.php:819 ../../mod/admin.php:986 +#: ../../mod/admin.php:1118 ../../mod/admin.php:1312 ../../mod/admin.php:1397 +#: ../../mod/settings.php:588 ../../mod/settings.php:692 +#: ../../mod/settings.php:718 ../../mod/settings.php:746 +#: ../../mod/settings.php:769 ../../mod/settings.php:854 +#: ../../mod/settings.php:1050 ../../mod/mood.php:134 +#: ../../mod/connedit.php:692 ../../mod/mail.php:355 ../../mod/appman.php:99 +#: ../../mod/pconfig.php:108 ../../mod/poll.php:68 +#: ../../mod/bulksetclose.php:24 ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Submit" +msgstr "Enviar" + +#: ../../include/js_strings.php:23 +msgid "Please enter a link URL" +msgstr "Por favor, introduzca una dirección de enlace" + +#: ../../include/js_strings.php:24 +msgid "Unsaved changes. Are you sure you wish to leave this page?" +msgstr "Cambios no guardados. ¿Está seguro que desea abandonar la página?" + +#: ../../include/js_strings.php:26 +msgid "timeago.prefixAgo" +msgstr "timeago.prefixAgo" + +#: ../../include/js_strings.php:27 +msgid "timeago.prefixFromNow" +msgstr "timeago.prefixFromNow" + +#: ../../include/js_strings.php:28 +msgid "ago" +msgstr "de su publicación" + +#: ../../include/js_strings.php:29 +msgid "from now" +msgstr "desde ahora" + +#: ../../include/js_strings.php:30 +msgid "less than a minute" +msgstr "menos de un minuto" + +#: ../../include/js_strings.php:31 +msgid "about a minute" +msgstr "alrededor de un minuto" + +#: ../../include/js_strings.php:32 +#, php-format +msgid "%d minutes" +msgstr "%d minutos" + +#: ../../include/js_strings.php:33 +msgid "about an hour" +msgstr "alrededor de una hora" + +#: ../../include/js_strings.php:34 +#, php-format +msgid "about %d hours" +msgstr "alrededor de %d horas" + +#: ../../include/js_strings.php:35 +msgid "a day" +msgstr "un día" + +#: ../../include/js_strings.php:36 +#, php-format +msgid "%d days" +msgstr "%d días" + +#: ../../include/js_strings.php:37 +msgid "about a month" +msgstr "alrededor de un mes" + +#: ../../include/js_strings.php:38 +#, php-format +msgid "%d months" +msgstr "%d meses" + +#: ../../include/js_strings.php:39 +msgid "about a year" +msgstr "alrededor de un año" + +#: ../../include/js_strings.php:40 +#, php-format +msgid "%d years" +msgstr "%d años" + +#: ../../include/js_strings.php:41 +msgid " " +msgstr " " + +#: ../../include/js_strings.php:42 +msgid "timeago.numbers" +msgstr "timeago.numbers" + +#: ../../include/text.php:395 +msgid "prev" +msgstr "previa" + +#: ../../include/text.php:397 +msgid "first" +msgstr "Primera" + +#: ../../include/text.php:426 +msgid "last" +msgstr "última" + +#: ../../include/text.php:429 +msgid "next" +msgstr "próxima" + +#: ../../include/text.php:439 +msgid "older" +msgstr "más antiguas" + +#: ../../include/text.php:441 +msgid "newer" +msgstr "más recientes" + +#: ../../include/text.php:834 +msgid "No connections" +msgstr "Sin conexiones" + +#: ../../include/text.php:848 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "%d conexión" +msgstr[1] "%d conexiones" + +#: ../../include/text.php:861 ../../mod/viewconnections.php:104 +msgid "View Connections" +msgstr "Ver conexiones" + +#: ../../include/text.php:918 ../../include/text.php:930 +#: ../../include/nav.php:165 ../../include/apps.php:147 +#: ../../mod/search.php:38 +msgid "Search" +msgstr "Buscar" + +#: ../../include/text.php:919 ../../include/text.php:931 +#: ../../include/widgets.php:192 ../../mod/rbmark.php:28 +#: ../../mod/rbmark.php:98 ../../mod/filer.php:50 ../../mod/admin.php:1457 +#: ../../mod/admin.php:1477 +msgid "Save" +msgstr "Guardar" + +#: ../../include/text.php:994 +msgid "poke" +msgstr "dar un toque" + +#: ../../include/text.php:994 ../../include/conversation.php:243 +msgid "poked" +msgstr "ha recibido un toque" + +#: ../../include/text.php:995 +msgid "ping" +msgstr "avisar" + +#: ../../include/text.php:995 +msgid "pinged" +msgstr " le hicieron un ping" + +#: ../../include/text.php:996 +msgid "prod" +msgstr "incitar" + +#: ../../include/text.php:996 +msgid "prodded" +msgstr "incitaros" + +#: ../../include/text.php:997 +msgid "slap" +msgstr "abofetear" + +#: ../../include/text.php:997 +msgid "slapped" +msgstr "abofeteado" + +#: ../../include/text.php:998 +msgid "finger" +msgstr "señalar" + +#: ../../include/text.php:998 +msgid "fingered" +msgstr "manosear" + +#: ../../include/text.php:999 +msgid "rebuff" +msgstr "desairar" + +#: ../../include/text.php:999 +msgid "rebuffed" +msgstr "desairado" + +#: ../../include/text.php:1009 +msgid "happy" +msgstr "feliz" + +#: ../../include/text.php:1010 +msgid "sad" +msgstr "triste" + +#: ../../include/text.php:1011 +msgid "mellow" +msgstr "amable" + +#: ../../include/text.php:1012 +msgid "tired" +msgstr "cansado/a" + +#: ../../include/text.php:1013 +msgid "perky" +msgstr "fesco/a" + +#: ../../include/text.php:1014 +msgid "angry" +msgstr "enfadado/a" + +#: ../../include/text.php:1015 +msgid "stupified" +msgstr "estupefacto/a" + +#: ../../include/text.php:1016 +msgid "puzzled" +msgstr "perplejo/a" + +#: ../../include/text.php:1017 +msgid "interested" +msgstr "interesado/a" + +#: ../../include/text.php:1018 +msgid "bitter" +msgstr "amargado/a" + +#: ../../include/text.php:1019 +msgid "cheerful" +msgstr "alegre" + +#: ../../include/text.php:1020 +msgid "alive" +msgstr "vivo/a" + +#: ../../include/text.php:1021 +msgid "annoyed" +msgstr "molesto/a" + +#: ../../include/text.php:1022 +msgid "anxious" +msgstr "ansioso/a" + +#: ../../include/text.php:1023 +msgid "cranky" +msgstr "de mal humor" + +#: ../../include/text.php:1024 +msgid "disturbed" +msgstr "perturbado/a" + +#: ../../include/text.php:1025 +msgid "frustrated" +msgstr "frustrado/a" + +#: ../../include/text.php:1026 +msgid "depressed" +msgstr "deprimido" + +#: ../../include/text.php:1027 +msgid "motivated" +msgstr "motivado/a" + +#: ../../include/text.php:1028 +msgid "relaxed" +msgstr "relajado/a" + +#: ../../include/text.php:1029 +msgid "surprised" +msgstr "sorprendido/a" + +#: ../../include/text.php:1201 +msgid "Monday" +msgstr "Lunes" + +#: ../../include/text.php:1201 +msgid "Tuesday" +msgstr "Martes" + +#: ../../include/text.php:1201 +msgid "Wednesday" +msgstr "Miércoles" + +#: ../../include/text.php:1201 +msgid "Thursday" +msgstr "Jueves" + +#: ../../include/text.php:1201 +msgid "Friday" +msgstr "Viernes" + +#: ../../include/text.php:1201 +msgid "Saturday" +msgstr "Sábado" + +#: ../../include/text.php:1201 +msgid "Sunday" +msgstr "Domingo" + +#: ../../include/text.php:1205 +msgid "January" +msgstr "Enero" + +#: ../../include/text.php:1205 +msgid "February" +msgstr "Febrero" + +#: ../../include/text.php:1205 +msgid "March" +msgstr "Marzo" + +#: ../../include/text.php:1205 +msgid "April" +msgstr "Abril" + +#: ../../include/text.php:1205 +msgid "May" +msgstr "Mayo" + +#: ../../include/text.php:1205 +msgid "June" +msgstr "Junio" + +#: ../../include/text.php:1205 +msgid "July" +msgstr "Julio" + +#: ../../include/text.php:1205 +msgid "August" +msgstr "Agosto" + +#: ../../include/text.php:1205 +msgid "September" +msgstr "Septiembre" + +#: ../../include/text.php:1205 +msgid "October" +msgstr "Octubre" + +#: ../../include/text.php:1205 +msgid "November" +msgstr "Noviembre" + +#: ../../include/text.php:1205 +msgid "December" +msgstr "Diciembre" + +#: ../../include/text.php:1310 +msgid "unknown.???" +msgstr "desconocido.???" + +#: ../../include/text.php:1311 +msgid "bytes" +msgstr "bytes" + +#: ../../include/text.php:1347 +msgid "remove category" +msgstr "eliminar categoría" + +#: ../../include/text.php:1422 +msgid "remove from file" +msgstr "eliminar del archivo" + +#: ../../include/text.php:1498 ../../include/text.php:1509 +msgid "Click to open/close" +msgstr "Pulsar para abrir/cerrar" + +#: ../../include/text.php:1665 ../../mod/events.php:457 +msgid "Link to Source" +msgstr "Ir al mensaje original" + +#: ../../include/text.php:1686 ../../include/text.php:1757 +msgid "default" +msgstr "por defecto" + +#: ../../include/text.php:1694 +msgid "Page layout" +msgstr "Disposición de página" + +#: ../../include/text.php:1694 +msgid "You can create your own with the layouts tool" +msgstr "Puede crear la suya propia con la herramienta de disposiciones" + +#: ../../include/text.php:1735 +msgid "Page content type" +msgstr "Tipo de contenido de página" + +#: ../../include/text.php:1769 +msgid "Select an alternate language" +msgstr "Selecciona un idioma alternativo" + +#: ../../include/text.php:1888 ../../include/diaspora.php:2119 +#: ../../include/conversation.php:120 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +#: ../../mod/tagger.php:43 +msgid "photo" +msgstr "foto" + +#: ../../include/text.php:1891 ../../include/conversation.php:123 +#: ../../mod/like.php:348 ../../mod/tagger.php:47 +msgid "event" +msgstr "evento" + +#: ../../include/text.php:1894 ../../include/diaspora.php:2119 +#: ../../include/conversation.php:148 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +msgid "status" +msgstr "estado" + +#: ../../include/text.php:1896 ../../include/conversation.php:150 +#: ../../mod/tagger.php:53 +msgid "comment" +msgstr "comentario" + +#: ../../include/text.php:1901 +msgid "activity" +msgstr "actividad" + +#: ../../include/text.php:2196 +msgid "Design Tools" +msgstr "Herramientas de diseño" + +#: ../../include/text.php:2199 ../../mod/blocks.php:147 +msgid "Blocks" +msgstr "Bloques" + +#: ../../include/text.php:2200 ../../mod/menu.php:98 +msgid "Menus" +msgstr "Menús" + +#: ../../include/text.php:2201 ../../mod/layouts.php:174 +msgid "Layouts" +msgstr "Disposiciones" + +#: ../../include/text.php:2202 +msgid "Pages" +msgstr "Páginas" + +#: ../../include/text.php:2553 ../../include/RedDAV/RedBrowser.php:131 +msgid "Collection" +msgstr "Colección" + +#: ../../include/RedDAV/RedBrowser.php:107 +#: ../../include/RedDAV/RedBrowser.php:265 +msgid "parent" +msgstr "padre" + +#: ../../include/RedDAV/RedBrowser.php:134 +msgid "Principal" +msgstr "Principal" + +#: ../../include/RedDAV/RedBrowser.php:137 +msgid "Addressbook" +msgstr "Libreta de direcciones" + +#: ../../include/RedDAV/RedBrowser.php:140 +msgid "Calendar" +msgstr "Calendario" + +#: ../../include/RedDAV/RedBrowser.php:143 +msgid "Schedule Inbox" +msgstr "Programar bandeja de entrada" + +#: ../../include/RedDAV/RedBrowser.php:146 +msgid "Schedule Outbox" +msgstr "Programar bandeja de salida" + +#: ../../include/RedDAV/RedBrowser.php:164 ../../include/conversation.php:1019 +#: ../../include/apps.php:336 ../../include/apps.php:387 +#: ../../mod/photos.php:693 ../../mod/photos.php:1131 +msgid "Unknown" +msgstr "Desconocido" + +#: ../../include/RedDAV/RedBrowser.php:227 +#, php-format +msgid "%1$s used" +msgstr "%1$s usado" + +#: ../../include/RedDAV/RedBrowser.php:232 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "%1$s usado de %2$s (%3$s%)" + +#: ../../include/RedDAV/RedBrowser.php:251 ../../include/nav.php:98 +#: ../../include/conversation.php:1609 ../../include/apps.php:135 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "Ficheros" + +#: ../../include/RedDAV/RedBrowser.php:253 +msgid "Total" +msgstr "Total" + +#: ../../include/RedDAV/RedBrowser.php:255 +msgid "Shared" +msgstr "Compartido" + +#: ../../include/RedDAV/RedBrowser.php:256 +#: ../../include/RedDAV/RedBrowser.php:303 ../../mod/webpages.php:180 +#: ../../mod/blocks.php:152 ../../mod/menu.php:109 +#: ../../mod/new_channel.php:121 ../../mod/layouts.php:175 +msgid "Create" +msgstr "Crear" + +#: ../../include/RedDAV/RedBrowser.php:257 +#: ../../include/RedDAV/RedBrowser.php:305 ../../mod/profile_photo.php:362 +#: ../../mod/photos.php:718 ../../mod/photos.php:1248 +msgid "Upload" +msgstr "Subir" + +#: ../../include/RedDAV/RedBrowser.php:261 ../../mod/admin.php:994 +#: ../../mod/settings.php:590 ../../mod/settings.php:616 +#: ../../mod/sharedwithme.php:95 +msgid "Name" +msgstr "Nombre" + +#: ../../include/RedDAV/RedBrowser.php:262 +msgid "Type" +msgstr "Tipo" + +#: ../../include/RedDAV/RedBrowser.php:263 ../../mod/sharedwithme.php:97 +msgid "Size" +msgstr "Tamaño" + +#: ../../include/RedDAV/RedBrowser.php:264 ../../mod/sharedwithme.php:98 +msgid "Last Modified" +msgstr "Última modificación" + +#: ../../include/RedDAV/RedBrowser.php:267 ../../include/ItemObject.php:120 +#: ../../include/conversation.php:660 ../../include/apps.php:255 +#: ../../mod/webpages.php:183 ../../mod/thing.php:228 ../../mod/group.php:176 +#: ../../mod/blocks.php:155 ../../mod/photos.php:1062 +#: ../../mod/editlayout.php:178 ../../mod/editwebpage.php:225 +#: ../../mod/editblock.php:180 ../../mod/admin.php:826 ../../mod/admin.php:988 +#: ../../mod/settings.php:651 ../../mod/connedit.php:551 +msgid "Delete" +msgstr "Borrar" + +#: ../../include/RedDAV/RedBrowser.php:302 +msgid "Create new folder" +msgstr "Crear nueva carpeta" + +#: ../../include/RedDAV/RedBrowser.php:304 +msgid "Upload file" +msgstr "Subir archivo" + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "Marcadores de %1$s" + +#: ../../include/network.php:635 +msgid "view full size" +msgstr "Ver a pantalla completa" + +#: ../../include/network.php:1585 ../../include/enotify.php:58 +msgid "$Projectname Notification" +msgstr "Notificación de $Projectname" + +#: ../../include/network.php:1586 ../../include/enotify.php:59 +#: ../../include/diaspora.php:2522 ../../include/diaspora.php:2533 +#: ../../mod/p.php:46 +msgid "$projectname" +msgstr "$projectname" + +#: ../../include/network.php:1588 ../../include/enotify.php:61 +msgid "Thank You," +msgstr "Gracias," + +#: ../../include/network.php:1590 ../../include/enotify.php:63 +#, php-format +msgid "%s Administrator" +msgstr "%s Administrador" + +#: ../../include/network.php:1646 +msgid "No Subject" +msgstr "Sin asunto" + +#: ../../include/features.php:38 +msgid "General Features" +msgstr "Características generales" + +#: ../../include/features.php:40 +msgid "Content Expiration" +msgstr "Expiración del contenido" + +#: ../../include/features.php:40 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "Eliminar publicaciones/comentarios y/o mensajes privados más adelante" + +#: ../../include/features.php:41 +msgid "Multiple Profiles" +msgstr "Múltiples perfiles" + +#: ../../include/features.php:41 +msgid "Ability to create multiple profiles" +msgstr "Capacidad de crear múltiples perfiles" + +#: ../../include/features.php:42 +msgid "Advanced Profiles" +msgstr "Perfiles avanzados" + +#: ../../include/features.php:42 +msgid "Additional profile sections and selections" +msgstr "Secciones y selecciones de perfil adicionales" + +#: ../../include/features.php:43 +msgid "Profile Import/Export" +msgstr "Importar/Exportar perfil" + +#: ../../include/features.php:43 +msgid "Save and load profile details across sites/channels" +msgstr "Guardar y cargar detalles del perfil a través de sitios/canales" + +#: ../../include/features.php:44 +msgid "Web Pages" +msgstr "Páginas web" + +#: ../../include/features.php:44 +msgid "Provide managed web pages on your channel" +msgstr "Proveer páginas web gestionadas en su canal" + +#: ../../include/features.php:45 +msgid "Private Notes" +msgstr "Notas privadas" + +#: ../../include/features.php:45 +msgid "Enables a tool to store notes and reminders" +msgstr "Activa una herramienta para almacenar notas y recordatorios" + +#: ../../include/features.php:46 +msgid "Navigation Channel Select" +msgstr "Selección de navegación de canal" + +#: ../../include/features.php:46 +msgid "Change channels directly from within the navigation dropdown menu" +msgstr "Cambiar canales directamente desde el menú de navegación desplegable" + +#: ../../include/features.php:47 +msgid "Photo Location" +msgstr "Ubicación de las fotos" + +#: ../../include/features.php:47 +msgid "If location data is available on uploaded photos, link this to a map." +msgstr "Si los datos de ubicación están disponibles en las fotos subidas, enlaza esto a un mapa." + +#: ../../include/features.php:49 +msgid "Expert Mode" +msgstr "Modo de experto" + +#: ../../include/features.php:49 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "Habilitar el modo de experto para acceder a opciones avanzadas de configuración" + +#: ../../include/features.php:50 +msgid "Premium Channel" +msgstr "Canal premium" + +#: ../../include/features.php:50 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "Les permite configurar restricciones y normas de uso a aquellos que conectan con su canal" + +#: ../../include/features.php:55 +msgid "Post Composition Features" +msgstr "Características de composición de entradas" + +#: ../../include/features.php:57 +msgid "Use Markdown" +msgstr "Usar Markdown" + +#: ../../include/features.php:57 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "Permitir el uso de \"Markdown\" para formatear publicaciones" + +#: ../../include/features.php:58 +msgid "Large Photos" +msgstr "Fotos de gran tamaño" + +#: ../../include/features.php:58 +msgid "" +"Include large (640px) photo thumbnails in posts. If not enabled, use small " +"(320px) photo thumbnails" +msgstr "Incluir miniaturas de foto grandes (640px) en publicaciones. Si no está habilitado, usar miniaturas pequeñas (320px)" + +#: ../../include/features.php:59 ../../include/widgets.php:548 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "Fuentes del canal" + +#: ../../include/features.php:59 +msgid "Automatically import channel content from other channels or feeds" +msgstr "Importar automáticamente contenido de otros canales o fuentes" + +#: ../../include/features.php:60 +msgid "Even More Encryption" +msgstr "Más cifrado todavía" + +#: ../../include/features.php:60 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "Permitir cifrado adicional de contenido punto-a-punto con una clave secreta compartida." + +#: ../../include/features.php:61 +msgid "Enable voting tools" +msgstr "Activar herramientas de votación" + +#: ../../include/features.php:61 +msgid "Provide a class of post which others can vote on" +msgstr "Proveer una clase de publicación en la que otros puedan votar" + +#: ../../include/features.php:67 +msgid "Network and Stream Filtering" +msgstr "Filtrado de red y flujo" + +#: ../../include/features.php:68 +msgid "Search by Date" +msgstr "Buscar por fecha" + +#: ../../include/features.php:68 +msgid "Ability to select posts by date ranges" +msgstr "Capacidad de seleccionar entradas por rango de fechas" + +#: ../../include/features.php:69 +msgid "Collections Filter" +msgstr "Filtrado de colecciones" + +#: ../../include/features.php:69 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "Habilitar la muestra de entradas de red eligiendo colecciones" + +#: ../../include/features.php:70 ../../include/widgets.php:274 +msgid "Saved Searches" +msgstr "Búsquedas Guardadas" + +#: ../../include/features.php:70 +msgid "Save search terms for re-use" +msgstr "Guardar términos de búsqueda para su reutilización" + +#: ../../include/features.php:71 +msgid "Network Personal Tab" +msgstr "Pestaña de red personal" + +#: ../../include/features.php:71 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "Habilitar una pestaña en la cual se muestran solo entradas de red en las que ha participado." + +#: ../../include/features.php:72 +msgid "Network New Tab" +msgstr "Nueva pestaña de red" + +#: ../../include/features.php:72 +msgid "Enable tab to display all new Network activity" +msgstr "Habilitar una pestaña en la cual se muestra toda la actividad de la red" + +#: ../../include/features.php:73 +msgid "Affinity Tool" +msgstr "Herramienta de afinidad" + +#: ../../include/features.php:73 +msgid "Filter stream activity by depth of relationships" +msgstr "Filtrar la actividad del flujo por profundidad de relaciones" + +#: ../../include/features.php:74 +msgid "Connection Filtering" +msgstr "Filtrado de conexiones" + +#: ../../include/features.php:74 +msgid "Filter incoming posts from connections based on keywords/content" +msgstr "Filtrar publicaciones entrantes de conexiones basadas en palabras clave / contenido" + +#: ../../include/features.php:75 +msgid "Suggest Channels" +msgstr "Sugerir canales" + +#: ../../include/features.php:75 +msgid "Show channel suggestions" +msgstr "Mostrar sugerencias de canales" + +#: ../../include/features.php:80 +msgid "Post/Comment Tools" +msgstr "Herramientas de entradas/comentarios" + +#: ../../include/features.php:81 +msgid "Tagging" +msgstr "Etiquetado" + +#: ../../include/features.php:81 +msgid "Ability to tag existing posts" +msgstr "Capacidad de etiquetar entradas existentes" + +#: ../../include/features.php:82 +msgid "Post Categories" +msgstr "Categorías de entradas" + +#: ../../include/features.php:82 +msgid "Add categories to your posts" +msgstr "Añadir categorías a sus publicaciones" + +#: ../../include/features.php:83 ../../include/widgets.php:304 +#: ../../include/contact_widgets.php:57 +msgid "Saved Folders" +msgstr "Carpetas guardadas" + +#: ../../include/features.php:83 +msgid "Ability to file posts under folders" +msgstr "Capacidad de archivar entradas en carpetas" + +#: ../../include/features.php:84 +msgid "Dislike Posts" +msgstr "No me gusta:" + +#: ../../include/features.php:84 +msgid "Ability to dislike posts/comments" +msgstr "Capacidad de mostrar desacuerdo con el contenido de entradas/comentarios" + +#: ../../include/features.php:85 +msgid "Star Posts" +msgstr "Entrada destacada" + +#: ../../include/features.php:85 +msgid "Ability to mark special posts with a star indicator" +msgstr "Capacidad de marcar entradas destacadas con un indicador de estrella" + +#: ../../include/features.php:86 +msgid "Tag Cloud" +msgstr "Nube de etiquetas" + +#: ../../include/features.php:86 +msgid "Provide a personal tag cloud on your channel page" +msgstr "Proveer nube de etiquetas personal en su página de canal" + +#: ../../include/widgets.php:35 ../../include/taxonomy.php:264 +#: ../../include/contact_widgets.php:92 +msgid "Categories" +msgstr "Categorías" + +#: ../../include/widgets.php:91 ../../include/nav.php:163 +#: ../../mod/apps.php:36 +msgid "Apps" +msgstr "Aplicaciones" + +#: ../../include/widgets.php:92 +msgid "System" +msgstr "Sistema" + +#: ../../include/widgets.php:94 ../../include/conversation.php:1504 +msgid "Personal" +msgstr "Personales" + +#: ../../include/widgets.php:95 +msgid "Create Personal App" +msgstr "Crear una aplicación personal" + +#: ../../include/widgets.php:96 +msgid "Edit Personal App" +msgstr "Editar una aplicación personal" + +#: ../../include/widgets.php:136 ../../include/widgets.php:175 +#: ../../include/Contact.php:107 ../../include/conversation.php:945 +#: ../../include/identity.php:857 ../../mod/directory.php:316 +#: ../../mod/match.php:64 ../../mod/suggest.php:52 +msgid "Connect" +msgstr "Conectar" + +#: ../../include/widgets.php:138 ../../mod/suggest.php:54 +msgid "Ignore/Hide" +msgstr "Ignorar/Ocultar" + +#: ../../include/widgets.php:143 ../../mod/connections.php:268 +msgid "Suggestions" +msgstr "Sugerencias" + +#: ../../include/widgets.php:144 +msgid "See more..." +msgstr "Ver más..." + +#: ../../include/widgets.php:166 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "Tiene %1$.0f de %2$.0f conexiones permitidas." + +#: ../../include/widgets.php:172 +msgid "Add New Connection" +msgstr "Añadir nueva conección" + +#: ../../include/widgets.php:173 +msgid "Enter the channel address" +msgstr "Introduzca la dirección del canal" + +#: ../../include/widgets.php:174 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Ejemplo: paco@ejemplo.com, http://ejemplo.com/paco" + +#: ../../include/widgets.php:190 +msgid "Notes" +msgstr "Notas" + +#: ../../include/widgets.php:266 +msgid "Remove term" +msgstr "Eliminar término" + +#: ../../include/widgets.php:307 ../../include/contact_widgets.php:60 +#: ../../include/contact_widgets.php:95 +msgid "Everything" +msgstr "Todo" + +#: ../../include/widgets.php:349 +msgid "Archives" +msgstr "Hemeroteca" + +#: ../../include/widgets.php:429 ../../mod/connedit.php:571 +msgid "Me" +msgstr "Yo" + +#: ../../include/widgets.php:430 ../../mod/connedit.php:572 +msgid "Family" +msgstr "Familia" + +#: ../../include/widgets.php:431 ../../include/identity.php:394 +#: ../../include/identity.php:395 ../../include/identity.php:402 +#: ../../include/profile_selectors.php:80 ../../mod/settings.php:345 +#: ../../mod/settings.php:349 ../../mod/settings.php:350 +#: ../../mod/settings.php:353 ../../mod/settings.php:364 +#: ../../mod/connedit.php:573 +msgid "Friends" +msgstr "Amigos" + +#: ../../include/widgets.php:432 ../../mod/connedit.php:574 +msgid "Acquaintances" +msgstr "Conocidos/as" + +#: ../../include/widgets.php:433 ../../mod/connections.php:231 +#: ../../mod/connections.php:246 ../../mod/connedit.php:575 +msgid "All" +msgstr "Todos" + +#: ../../include/widgets.php:452 +msgid "Refresh" +msgstr "Refrescar" + +#: ../../include/widgets.php:487 +msgid "Account settings" +msgstr "Configuración de la cuenta" + +#: ../../include/widgets.php:493 +msgid "Channel settings" +msgstr "Configuración del canal" + +#: ../../include/widgets.php:499 +msgid "Additional features" +msgstr "Características adicionales" + +#: ../../include/widgets.php:505 +msgid "Feature/Addon settings" +msgstr "Configuración de característica/complemento" + +#: ../../include/widgets.php:511 +msgid "Display settings" +msgstr "Configuración de visualización" + +#: ../../include/widgets.php:517 +msgid "Connected apps" +msgstr "Aplicaciones conectadas" + +#: ../../include/widgets.php:523 +msgid "Export channel" +msgstr "Exportar canal" + +#: ../../include/widgets.php:532 ../../mod/connedit.php:662 +msgid "Connection Default Permissions" +msgstr "Permisos predeterminados de conexión" + +#: ../../include/widgets.php:540 +msgid "Premium Channel Settings" +msgstr "Configuración del canal premium" + +#: ../../include/widgets.php:556 ../../include/nav.php:208 +#: ../../include/apps.php:134 ../../mod/admin.php:1079 +#: ../../mod/admin.php:1279 +msgid "Settings" +msgstr "Ajustes" + +#: ../../include/widgets.php:569 ../../mod/message.php:31 +#: ../../mod/mail.php:128 +msgid "Messages" +msgstr "Mensajes" + +#: ../../include/widgets.php:572 +msgid "Check Mail" +msgstr "Comprobar correo" + +#: ../../include/widgets.php:577 ../../include/nav.php:199 +msgid "New Message" +msgstr "Nuevo mensaje" + +#: ../../include/widgets.php:652 +msgid "Chat Rooms" +msgstr "Salas de chat" + +#: ../../include/widgets.php:672 +msgid "Bookmarked Chatrooms" +msgstr "Salas de chat favoritas" + +#: ../../include/widgets.php:692 +msgid "Suggested Chatrooms" +msgstr "Salas de chat sugeridas" + +#: ../../include/widgets.php:819 ../../include/widgets.php:877 +msgid "photo/image" +msgstr "foto/imagen" + +#: ../../include/widgets.php:972 ../../include/widgets.php:974 +msgid "Rate Me" +msgstr "Valorar este canal" + +#: ../../include/widgets.php:978 +msgid "View Ratings" +msgstr "Ver valoraciones" + +#: ../../include/widgets.php:989 +msgid "Public Hubs" +msgstr "Servidores públicos" + +#: ../../include/event.php:22 ../../include/bb2diaspora.php:459 +msgid "l F d, Y \\@ g:i A" +msgstr "l d de F, Y \\@ G:i" + +#: ../../include/event.php:30 ../../include/bb2diaspora.php:465 +msgid "Starts:" +msgstr "Comienza:" + +#: ../../include/event.php:40 ../../include/bb2diaspora.php:473 +msgid "Finishes:" +msgstr "Finaliza:" + +#: ../../include/event.php:50 ../../include/bb2diaspora.php:481 +#: ../../include/identity.php:908 ../../mod/directory.php:302 +#: ../../mod/events.php:661 +msgid "Location:" +msgstr "Ubicación:" + +#: ../../include/event.php:535 +msgid "This event has been added to your calendar." +msgstr "Este evento ha sido añadido a su calendario." + +#: ../../include/enotify.php:96 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:100 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "[Red notifica] Nuevo correo recibido en %s" + +#: ../../include/enotify.php:102 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "%1$s, %2$s te ha enviado un nuevo mensaje privado en %3$s." + +#: ../../include/enotify.php:103 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s te envió %2$s." + +#: ../../include/enotify.php:103 +msgid "a private message" +msgstr "un mensaje privado" + +#: ../../include/enotify.php:104 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Por favor visite %s para ver y/o responder a su mensaje privado." + +#: ../../include/enotify.php:158 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "%1$s, %2$s comentó sobre [zrl=%3$s]a %4$s[/zrl]" + +#: ../../include/enotify.php:166 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "%1$s, %2$s comentó sobre [zrl=%3$s]%4$s's %5$s[/zrl]" + +#: ../../include/enotify.php:175 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "%1$s, %2$s comentó sobre [zrl=%3$s]your %4$s[/zrl]" + +#: ../../include/enotify.php:186 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Red notifica] Comentario en la conversación #%1$d por %2$s" + +#: ../../include/enotify.php:187 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "%1$s, %2$s comentó sobre un elemento/conversación que ha estado siguiendo." + +#: ../../include/enotify.php:190 ../../include/enotify.php:205 +#: ../../include/enotify.php:231 ../../include/enotify.php:249 +#: ../../include/enotify.php:263 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Para ver o comentar la conversación, visita %s" + +#: ../../include/enotify.php:196 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "[Red:Notify] %s escribió en su muro" + +#: ../../include/enotify.php:198 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "%1$s, %2$s publicó en su muro de perfil en %3$s" + +#: ../../include/enotify.php:200 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "%1$s, %2$s publicó en [zrl=%3$s]su muro[/zrl]" + +#: ../../include/enotify.php:224 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "[Red notifica] %s le etiquetó" + +#: ../../include/enotify.php:225 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "%1$s, %2$s le etiquetó en %3$s" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "%1$s, %2$s [zrl=%3$s]le etiquetó[/zrl]." + +#: ../../include/enotify.php:238 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "[Red aviso] %1$s ha recibido un toque" + +#: ../../include/enotify.php:239 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "%1$s, %2$s recibió un toque en %3$s" + +#: ../../include/enotify.php:240 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "%1$s, %2$s [zrl=%2$s]recibió un toque[/zrl]." + +#: ../../include/enotify.php:256 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "[Red notifica] %s etiquetó su entrada" + +#: ../../include/enotify.php:257 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "%1$s, %2$s etiquetó su publicación en %3$s" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "%1$s, %2$s etiquetó [zrl=%3$s]su publicación[/zrl]" + +#: ../../include/enotify.php:270 +msgid "[Red:Notify] Introduction received" +msgstr "[Red notifica] S\nDemanda de amistad recibida" + +#: ../../include/enotify.php:271 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "%1$s, ha recibido una nueva solicitud de conexión de '%2$s' en %3$s" + +#: ../../include/enotify.php:272 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "%1$s, ha recibido [zrl=%2$s]una nueva solicitud de conexión[/zrl] de %3$s." + +#: ../../include/enotify.php:276 ../../include/enotify.php:295 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Puede visitar su perfil en %s" + +#: ../../include/enotify.php:278 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "Por favor, visita %s para permitir o rechazar la solicitd de conexión." + +#: ../../include/enotify.php:285 +msgid "[Red:Notify] Friend suggestion received" +msgstr "[Red notifica] recibió una sugerencia de amistad" + +#: ../../include/enotify.php:286 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "%1$s, ha recibido una sugerencia de un amigo de '%2$s' en %3$s" + +#: ../../include/enotify.php:287 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from " +"%4$s." +msgstr "%1$s, ha recibido [zrl=%2$s]una sugerencia de amistad[/zrl] para %3$s de %4$s." + +#: ../../include/enotify.php:293 +msgid "Name:" +msgstr "Nombre:" + +#: ../../include/enotify.php:294 +msgid "Photo:" +msgstr "Foto:" + +#: ../../include/enotify.php:297 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Por favor, visite %s para aprobar o rechazar la sugerencia." + +#: ../../include/enotify.php:508 +msgid "[Red:Notify]" +msgstr "[Red:Notify]" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "No se ha especificado ningún destinatario." + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "[sin asunto]" + +#: ../../include/message.php:45 +msgid "Unable to determine sender." +msgstr "No ha sido posible de determinar el remitente. " + +#: ../../include/message.php:200 +msgid "Stored post could not be verified." +msgstr "No se ha podido verificar las entradas guardadas." + +#: ../../include/diaspora.php:2148 ../../include/conversation.php:164 +#: ../../mod/like.php:394 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "a %1$s le gusta el %3$s de %2$s" + +#: ../../include/diaspora.php:2494 +msgid "Please choose" +msgstr "Por favor selecciona" + +#: ../../include/diaspora.php:2496 +msgid "Agree" +msgstr "De acuerdo" + +#: ../../include/diaspora.php:2498 +msgid "Disagree" +msgstr "En desacuerdo" + +#: ../../include/diaspora.php:2500 +msgid "Abstain" +msgstr "Abstención" + +#: ../../include/follow.php:28 +msgid "Channel is blocked on this site." +msgstr "El canal está bloqueado en éste sitio." + +#: ../../include/follow.php:33 +msgid "Channel location missing." +msgstr "Falta la dirección del canal " + +#: ../../include/follow.php:83 +msgid "Response from remote channel was incomplete." +msgstr "Respuesta del canal remoto incompleta." + +#: ../../include/follow.php:100 +msgid "Channel was deleted and no longer exists." +msgstr "El canal ha sido eliminado y ya no existe." + +#: ../../include/follow.php:135 ../../include/follow.php:206 +msgid "Protocol disabled." +msgstr "Protocolo deshabilitado." + +#: ../../include/follow.php:144 +msgid "Protocol blocked for this channel." +msgstr "Protocolo bloqueado para este canal." + +#: ../../include/follow.php:179 +msgid "Channel discovery failed." +msgstr "Búsqueda de canales ha fallado." + +#: ../../include/follow.php:195 +msgid "local account not found." +msgstr "No se ha encontrado la cuenta local." + +#: ../../include/follow.php:224 +msgid "Cannot connect to yourself." +msgstr "No puede conectarse consigo mismo." + +#: ../../include/ItemObject.php:89 ../../include/conversation.php:667 +msgid "Private Message" +msgstr "Mensaje Privado" + +#: ../../include/ItemObject.php:126 ../../include/conversation.php:659 +msgid "Select" +msgstr "Seleccionar" + +#: ../../include/ItemObject.php:130 +msgid "Save to Folder" +msgstr "Guardar en carpeta" + +#: ../../include/ItemObject.php:151 +msgid "I will attend" +msgstr "Participaré" + +#: ../../include/ItemObject.php:151 +msgid "I will not attend" +msgstr "No participaré" + +#: ../../include/ItemObject.php:151 +msgid "I might attend" +msgstr "Quizá asista" + +#: ../../include/ItemObject.php:161 +msgid "I agree" +msgstr "Estoy de acuerdo" + +#: ../../include/ItemObject.php:161 +msgid "I disagree" +msgstr "No estoy de acuerdo" + +#: ../../include/ItemObject.php:161 +msgid "I abstain" +msgstr "Me abstengo" + +#: ../../include/ItemObject.php:175 ../../include/ItemObject.php:187 +#: ../../include/conversation.php:1677 ../../mod/photos.php:1015 +#: ../../mod/photos.php:1027 +msgid "View all" +msgstr "Ver todo" + +#: ../../include/ItemObject.php:179 ../../include/taxonomy.php:396 +#: ../../include/conversation.php:1701 ../../include/identity.php:1167 +#: ../../mod/photos.php:1019 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "Me gusta" +msgstr[1] "Me gusta" + +#: ../../include/ItemObject.php:184 ../../include/conversation.php:1704 +#: ../../mod/photos.php:1024 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "No me gusta" +msgstr[1] "No me gusta" + +#: ../../include/ItemObject.php:212 +msgid "Add Star" +msgstr "Añadir estrella" + +#: ../../include/ItemObject.php:213 +msgid "Remove Star" +msgstr "Eliminar estrella" + +#: ../../include/ItemObject.php:214 +msgid "Toggle Star Status" +msgstr "Activa o desactiva el estado de preferido" + +#: ../../include/ItemObject.php:218 +msgid "starred" +msgstr "preferidos" + +#: ../../include/ItemObject.php:227 ../../include/conversation.php:674 +msgid "Message signature validated" +msgstr "Firma de mensaje validada" + +#: ../../include/ItemObject.php:228 ../../include/conversation.php:675 +msgid "Message signature incorrect" +msgstr "Firma de mensaje incorrecta" + +#: ../../include/ItemObject.php:236 +msgid "Add Tag" +msgstr "Añadir etiqueta" + +#: ../../include/ItemObject.php:254 ../../mod/photos.php:959 +msgid "I like this (toggle)" +msgstr "me gusta (cambiar)" + +#: ../../include/ItemObject.php:254 ../../include/taxonomy.php:310 +msgid "like" +msgstr "Me gusta" + +#: ../../include/ItemObject.php:255 ../../mod/photos.php:960 +msgid "I don't like this (toggle)" +msgstr "No me gusta (cambiar)" + +#: ../../include/ItemObject.php:255 ../../include/taxonomy.php:311 +msgid "dislike" +msgstr "No me gusta" + +#: ../../include/ItemObject.php:259 +msgid "Share This" +msgstr "Compartir esto" + +#: ../../include/ItemObject.php:259 +msgid "share" +msgstr "Compartir" + +#: ../../include/ItemObject.php:276 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d comentario" +msgstr[1] "%d comentarios" + +#: ../../include/ItemObject.php:294 ../../include/ItemObject.php:295 +#, php-format +msgid "View %s's profile - %s" +msgstr "Ver perfil de %s - %s" + +#: ../../include/ItemObject.php:298 +msgid "to" +msgstr "a" + +#: ../../include/ItemObject.php:299 +msgid "via" +msgstr "mediante" + +#: ../../include/ItemObject.php:300 +msgid "Wall-to-Wall" +msgstr "Muro-a-Muro" + +#: ../../include/ItemObject.php:301 +msgid "via Wall-To-Wall:" +msgstr "mediante Muro-a-Muro" + +#: ../../include/ItemObject.php:312 ../../include/conversation.php:716 +#, php-format +msgid "from %s" +msgstr "desde %s" + +#: ../../include/ItemObject.php:315 ../../include/conversation.php:719 +#, php-format +msgid "last edited: %s" +msgstr "último cambio: %s" + +#: ../../include/ItemObject.php:316 ../../include/conversation.php:720 +#, php-format +msgid "Expires: %s" +msgstr "Caduca: %s" + +#: ../../include/ItemObject.php:337 +msgid "Save Bookmarks" +msgstr "Guardar marcadores" + +#: ../../include/ItemObject.php:338 +msgid "Add to Calendar" +msgstr "Añadir al calendario" + +#: ../../include/ItemObject.php:347 +msgid "Mark all seen" +msgstr "Marcar todos como vistos" + +#: ../../include/ItemObject.php:353 ../../mod/photos.php:1145 +msgctxt "noun" +msgid "Likes" +msgstr "Me gusta" + +#: ../../include/ItemObject.php:354 ../../mod/photos.php:1146 +msgctxt "noun" +msgid "Dislikes" +msgstr "No me gusta" + +#: ../../include/ItemObject.php:359 ../../include/acl_selectors.php:249 +#: ../../mod/photos.php:1151 +msgid "Close" +msgstr "Cerrar" + +#: ../../include/ItemObject.php:364 ../../include/conversation.php:737 +#: ../../include/conversation.php:1209 ../../mod/editpost.php:123 +#: ../../mod/photos.php:962 ../../mod/editlayout.php:147 +#: ../../mod/editwebpage.php:192 ../../mod/editblock.php:149 +#: ../../mod/mail.php:241 ../../mod/mail.php:356 +msgid "Please wait" +msgstr "Espera por favor" + +#: ../../include/ItemObject.php:665 ../../mod/photos.php:978 +#: ../../mod/photos.php:1096 +msgid "This is you" +msgstr "Este es usted" + +#: ../../include/ItemObject.php:669 ../../include/conversation.php:1181 +#: ../../mod/editpost.php:107 ../../mod/editlayout.php:134 +#: ../../mod/editwebpage.php:179 ../../mod/editblock.php:135 +msgid "Bold" +msgstr "Negrita" + +#: ../../include/ItemObject.php:670 ../../include/conversation.php:1182 +#: ../../mod/editpost.php:108 ../../mod/editlayout.php:135 +#: ../../mod/editwebpage.php:180 ../../mod/editblock.php:136 +msgid "Italic" +msgstr "Itálico " + +#: ../../include/ItemObject.php:671 ../../include/conversation.php:1183 +#: ../../mod/editpost.php:109 ../../mod/editlayout.php:136 +#: ../../mod/editwebpage.php:181 ../../mod/editblock.php:137 +msgid "Underline" +msgstr "Subrayar" + +#: ../../include/ItemObject.php:672 ../../include/conversation.php:1184 +#: ../../mod/editpost.php:110 ../../mod/editlayout.php:137 +#: ../../mod/editwebpage.php:182 ../../mod/editblock.php:138 +msgid "Quote" +msgstr "Citar" + +#: ../../include/ItemObject.php:673 ../../include/conversation.php:1185 +#: ../../mod/editpost.php:111 ../../mod/editlayout.php:138 +#: ../../mod/editwebpage.php:183 ../../mod/editblock.php:139 +msgid "Code" +msgstr "Código" + +#: ../../include/ItemObject.php:674 +msgid "Image" +msgstr "Imagen" + +#: ../../include/ItemObject.php:675 +msgid "Insert Link" +msgstr "Insertar enlace" + +#: ../../include/ItemObject.php:676 +msgid "Video" +msgstr "Vídeo" + +#: ../../include/ItemObject.php:680 ../../include/conversation.php:1236 +#: ../../mod/editpost.php:151 ../../mod/mail.php:247 ../../mod/mail.php:361 +msgid "Encrypt text" +msgstr "Cifrar texto" + +#: ../../include/Contact.php:124 +msgid "New window" +msgstr "Nueva ventana" + +#: ../../include/Contact.php:125 +msgid "Open the selected location in a different window or browser tab" +msgstr "Abrir la ubicación seleccionada en una ventana o pestaña aparte" + +#: ../../include/Contact.php:215 ../../mod/admin.php:739 +#, php-format +msgid "User '%s' deleted" +msgstr "Usuario '%s' eliminado" + +#: ../../include/bb2diaspora.php:373 +msgid "Attachments:" +msgstr "Ficheros adjuntos:" + +#: ../../include/bb2diaspora.php:461 +msgid "$Projectname event notification:" +msgstr "Notificación de eventos de $Projectname:" + +#: ../../include/nav.php:87 ../../include/nav.php:120 ../../boot.php:1550 +msgid "Logout" +msgstr "Cerrar sesión" + +#: ../../include/nav.php:87 ../../include/nav.php:120 +msgid "End this session" +msgstr "Cerrar ésta sesión" + +#: ../../include/nav.php:90 ../../include/nav.php:151 +msgid "Home" +msgstr "Inicio" + +#: ../../include/nav.php:90 +msgid "Your posts and conversations" +msgstr "Sus entradas y conversaciones" + +#: ../../include/nav.php:91 ../../include/conversation.php:942 +#: ../../mod/connedit.php:498 +msgid "View Profile" +msgstr "Ver perfil" + +#: ../../include/nav.php:91 +msgid "Your profile page" +msgstr "Su página de perfil" + +#: ../../include/nav.php:93 +msgid "Edit Profiles" +msgstr "Editar perfiles" + +#: ../../include/nav.php:93 +msgid "Manage/Edit profiles" +msgstr "Administrar/editar perfiles" + +#: ../../include/nav.php:95 ../../include/identity.php:880 +msgid "Edit Profile" +msgstr "Editar perfil" + +#: ../../include/nav.php:95 +msgid "Edit your profile" +msgstr "Editar su perfil" + +#: ../../include/nav.php:97 ../../include/conversation.php:1600 +#: ../../include/apps.php:139 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "Fotos" + +#: ../../include/nav.php:97 +msgid "Your photos" +msgstr "Sus fotos" + +#: ../../include/nav.php:98 +msgid "Your files" +msgstr "Sus ficheros" + +#: ../../include/nav.php:103 ../../include/apps.php:146 +msgid "Chat" +msgstr "Chat" + +#: ../../include/nav.php:103 +msgid "Your chatrooms" +msgstr "Sus salas de chat" + +#: ../../include/nav.php:109 ../../include/conversation.php:1635 +#: ../../include/apps.php:129 +msgid "Bookmarks" +msgstr "Marcadores" + +#: ../../include/nav.php:109 +msgid "Your bookmarks" +msgstr "Sus marcadores" + +#: ../../include/nav.php:113 ../../include/conversation.php:1645 +#: ../../include/apps.php:136 ../../mod/webpages.php:178 +msgid "Webpages" +msgstr "Páginas web" + +#: ../../include/nav.php:113 +msgid "Your webpages" +msgstr "Sus páginas web" + +#: ../../include/nav.php:117 ../../include/apps.php:131 ../../boot.php:1551 +msgid "Login" +msgstr "Iniciar sesión" + +#: ../../include/nav.php:117 +msgid "Sign in" +msgstr "Acceder" + +#: ../../include/nav.php:134 +#, php-format +msgid "%s - click to logout" +msgstr "%s - pulsar para cerrar sesión" + +#: ../../include/nav.php:137 +msgid "Remote authentication" +msgstr "Acceder desde su servidor" + +#: ../../include/nav.php:137 +msgid "Click to authenticate to your home hub" +msgstr "Pulsar para identificarse en su servidor" + +#: ../../include/nav.php:151 +msgid "Home Page" +msgstr "Página de inicio" + +#: ../../include/nav.php:155 ../../mod/register.php:224 ../../boot.php:1527 +msgid "Register" +msgstr "Registrarse" + +#: ../../include/nav.php:155 +msgid "Create an account" +msgstr "Crear una cuenta" + +#: ../../include/nav.php:160 ../../include/apps.php:142 ../../mod/help.php:67 +#: ../../mod/help.php:72 ../../mod/layouts.php:176 +msgid "Help" +msgstr "Ayuda" + +#: ../../include/nav.php:160 +msgid "Help and documentation" +msgstr "Ayuda y documentación" + +#: ../../include/nav.php:163 +msgid "Applications, utilities, links, games" +msgstr "Aplicaciones, utilidades, enlaces, juegos" + +#: ../../include/nav.php:165 +msgid "Search site content" +msgstr "Buscar contenido del sitio" + +#: ../../include/nav.php:168 ../../include/apps.php:141 +msgid "Directory" +msgstr "Directorio" + +#: ../../include/nav.php:168 +msgid "Channel Directory" +msgstr "Directorio de canales" + +#: ../../include/nav.php:180 ../../include/apps.php:133 +msgid "Matrix" +msgstr "Matríz" + +#: ../../include/nav.php:180 +msgid "Your matrix" +msgstr "Su red" + +#: ../../include/nav.php:181 +msgid "Mark all matrix notifications seen" +msgstr "Marcar todas las notificaciones de la red como leídas" + +#: ../../include/nav.php:183 ../../include/apps.php:137 +msgid "Channel Home" +msgstr "Mi canal" + +#: ../../include/nav.php:183 +msgid "Channel home" +msgstr "Mi canal" + +#: ../../include/nav.php:184 +msgid "Mark all channel notifications seen" +msgstr "Marcar todas las notificaciones de canales como leídas" + +#: ../../include/nav.php:187 ../../mod/connections.php:407 +msgid "Connections" +msgstr "Conexiones" + +#: ../../include/nav.php:190 +msgid "Notices" +msgstr "Avisos" + +#: ../../include/nav.php:190 +msgid "Notifications" +msgstr "Notificaciones" + +#: ../../include/nav.php:191 +msgid "See all notifications" +msgstr "Ver todas las notificaciones" + +#: ../../include/nav.php:192 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "Marcar todas las notificaciones de sistema como leídas" + +#: ../../include/nav.php:194 ../../include/apps.php:143 +msgid "Mail" +msgstr "Correo" + +#: ../../include/nav.php:194 +msgid "Private mail" +msgstr "Correo privado" + +#: ../../include/nav.php:195 +msgid "See all private messages" +msgstr "Ver todas los mensajes privados" + +#: ../../include/nav.php:196 +msgid "Mark all private messages seen" +msgstr "Marcar todos los mensajes privados como leídos" + +#: ../../include/nav.php:197 +msgid "Inbox" +msgstr "Bandeja de entrada" + +#: ../../include/nav.php:198 +msgid "Outbox" +msgstr "Bandeja de salida" + +#: ../../include/nav.php:202 ../../include/apps.php:140 +#: ../../mod/events.php:486 +msgid "Events" +msgstr "Eventos" + +#: ../../include/nav.php:202 +msgid "Event Calendar" +msgstr "Calendario de eventos" + +#: ../../include/nav.php:203 +msgid "See all events" +msgstr "Ver todos los eventos" + +#: ../../include/nav.php:204 +msgid "Mark all events seen" +msgstr "Marcar todos los eventos como leidos" + +#: ../../include/nav.php:206 ../../include/apps.php:132 +#: ../../mod/manage.php:166 +msgid "Channel Manager" +msgstr "Administración del canal" + +#: ../../include/nav.php:206 +msgid "Manage Your Channels" +msgstr "Gestione sus canales" + +#: ../../include/nav.php:208 +msgid "Account/Channel Settings" +msgstr "Ajustes de cuenta/canales" + +#: ../../include/nav.php:216 ../../mod/admin.php:120 +msgid "Admin" +msgstr "Administrador" + +#: ../../include/nav.php:216 +msgid "Site Setup and Configuration" +msgstr "Configuración del sitio" + +#: ../../include/nav.php:247 ../../include/conversation.php:850 +msgid "Loading..." +msgstr "Cargando..." + +#: ../../include/nav.php:252 +msgid "@name, #tag, content" +msgstr "@nombre, #etiqueta, contenido" + +#: ../../include/nav.php:253 +msgid "Please wait..." +msgstr "Espere por favor…" + +#: ../../include/taxonomy.php:222 ../../include/taxonomy.php:243 +msgid "Tags" +msgstr "Etiquetas" + +#: ../../include/taxonomy.php:287 +msgid "Keywords" +msgstr "Palabras clave" + +#: ../../include/taxonomy.php:308 +msgid "have" +msgstr "tener" + +#: ../../include/taxonomy.php:308 +msgid "has" +msgstr "tiene" + +#: ../../include/taxonomy.php:309 +msgid "want" +msgstr "quiere" + +#: ../../include/taxonomy.php:309 +msgid "wants" +msgstr "quiere" + +#: ../../include/taxonomy.php:310 +msgid "likes" +msgstr "le gusta" + +#: ../../include/taxonomy.php:311 +msgid "dislikes" +msgstr "no le gusta" + +#: ../../include/activities.php:39 +msgid " and " +msgstr "y" + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "perfil público" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s cambió %2$s a “%3$s”" + +#: ../../include/activities.php:57 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "Visita %2$s de %1$s" + +#: ../../include/activities.php:60 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s actualizó %2$s, %3$s cambió." + +#: ../../include/security.php:349 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "El token de seguridad del formulario no es correcto. Esto ha ocurrido probablemente porque el formulario ha estado abierto demasiado tiempo (>3 horas) antes de ser enviado" + +#: ../../include/permissions.php:26 +msgid "Can view my normal stream and posts" +msgstr "Puede ver mi flujo y publicaciones normales" + +#: ../../include/permissions.php:27 +msgid "Can view my default channel profile" +msgstr "Puede ver mi perfil de canal predeterminado." + +#: ../../include/permissions.php:28 +msgid "Can view my photo albums" +msgstr "Puede ver mis álbumes de fotos" + +#: ../../include/permissions.php:29 +msgid "Can view my connections" +msgstr "Puede ver mis conexiones" + +#: ../../include/permissions.php:30 +msgid "Can view my file storage" +msgstr "Puede ver mis ficheros almacenados" + +#: ../../include/permissions.php:31 +msgid "Can view my webpages" +msgstr "Puede ver mis páginas web" + +#: ../../include/permissions.php:34 +msgid "Can send me their channel stream and posts" +msgstr "Te pueden enviar sus canales de flujos y entradas" + +#: ../../include/permissions.php:35 +msgid "Can post on my channel page (\"wall\")" +msgstr "Pueden crear entradas en su página del canal (“muroâ€)" + +#: ../../include/permissions.php:36 +msgid "Can comment on or like my posts" +msgstr "Puede comentar en mis publicaciones o marcar como 'me gusta'." + +#: ../../include/permissions.php:37 +msgid "Can send me private mail messages" +msgstr "Puede enviarme mensajes privados" + +#: ../../include/permissions.php:38 +msgid "Can post photos to my photo albums" +msgstr "Puede publicar fotos en mis galerias" + +#: ../../include/permissions.php:39 +msgid "Can like/dislike stuff" +msgstr "Puede marcar contenido como me gustar/no me gusta." + +#: ../../include/permissions.php:39 +msgid "Profiles and things other than posts/comments" +msgstr "Perfiles y cosas aparte de publicaciones/comentarios" + +#: ../../include/permissions.php:41 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "Puede reenviar a todos mis contactos de canalmediante post @mentions" + +#: ../../include/permissions.php:41 +msgid "Advanced - useful for creating group forum channels" +msgstr "Avanzado - útil para crear canales de foro o grupos" + +#: ../../include/permissions.php:42 +msgid "Can chat with me (when available)" +msgstr "Puede charlar conmigo" + +#: ../../include/permissions.php:43 +msgid "Can write to my file storage" +msgstr "Puede escribir en mi almacenamiento de ficheros" + +#: ../../include/permissions.php:44 +msgid "Can edit my webpages" +msgstr "Puede editar mis páginas web" + +#: ../../include/permissions.php:46 +msgid "Can source my public posts in derived channels" +msgstr "Puede utilizar como fuente mis publicaciones públicas en canales derivados" + +#: ../../include/permissions.php:46 +msgid "Somewhat advanced - very useful in open communities" +msgstr "Algo avanzado - muy útil en comunidades abiertas" + +#: ../../include/permissions.php:48 +msgid "Can administer my channel resources" +msgstr "Puede administrar mis recursos de canal" + +#: ../../include/permissions.php:48 +msgid "" +"Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "Muy avanzado. Déjelo a no ser que sepa bien lo que está haciendo." + +#: ../../include/permissions.php:893 +msgid "Social Networking" +msgstr "Creación de redes sociales" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Mostly Public" +msgstr "Público en su mayor parte" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +#: ../../include/permissions.php:895 +msgid "Restricted" +msgstr "Restringido" + +#: ../../include/permissions.php:893 ../../include/permissions.php:894 +msgid "Private" +msgstr "Privado" + +#: ../../include/permissions.php:894 +msgid "Community Forum" +msgstr "Foro de la comunidad" + +#: ../../include/permissions.php:895 +msgid "Feed Republish" +msgstr "Republicar feed" + +#: ../../include/permissions.php:896 +msgid "Special Purpose" +msgstr "Propósito especial" + +#: ../../include/permissions.php:896 +msgid "Celebrity/Soapbox" +msgstr "Celebridad / Plataforma improvisada" + +#: ../../include/permissions.php:896 +msgid "Group Repository" +msgstr "Repositorio de grupo" + +#: ../../include/permissions.php:897 ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 +msgid "Other" +msgstr "Otro" + +#: ../../include/permissions.php:897 +msgid "Custom/Expert Mode" +msgstr "Modo personalizado/experto" + +#: ../../include/conversation.php:126 ../../mod/like.php:113 +msgid "channel" +msgstr "canal" + +#: ../../include/conversation.php:167 ../../mod/like.php:396 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "a %1$s no le gusta el %3$s de %2$s" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "%1$s ahora está conectado con %2$s" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "%1$s dio un toque a %2$s" + +#: ../../include/conversation.php:260 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "%1$s está %2$s" + +#: ../../include/conversation.php:572 ../../mod/photos.php:996 +msgctxt "title" +msgid "Likes" +msgstr "Me gusta" + +#: ../../include/conversation.php:572 ../../mod/photos.php:996 +msgctxt "title" +msgid "Dislikes" +msgstr "No me gusta" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Agree" +msgstr "De acuerdo" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Disagree" +msgstr "En desacuerdo" + +#: ../../include/conversation.php:573 ../../mod/photos.php:997 +msgctxt "title" +msgid "Abstain" +msgstr "Abstenerse" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Attending" +msgstr "Participar" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Not attending" +msgstr "No participar" + +#: ../../include/conversation.php:574 ../../mod/photos.php:998 +msgctxt "title" +msgid "Might attend" +msgstr "Quizá participe" + +#: ../../include/conversation.php:692 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Ver perfil @ %s de %s" + +#: ../../include/conversation.php:707 +msgid "Categories:" +msgstr "Categorías:" + +#: ../../include/conversation.php:708 +msgid "Filed under:" +msgstr "Archivado bajo:" + +#: ../../include/conversation.php:735 +msgid "View in context" +msgstr "Mostrar en su contexto" + +#: ../../include/conversation.php:846 +msgid "remove" +msgstr "eliminar" + +#: ../../include/conversation.php:851 +msgid "Delete Selected Items" +msgstr "Eliminar elementos seleccionados" + +#: ../../include/conversation.php:939 +msgid "View Source" +msgstr "Ver fuente" + +#: ../../include/conversation.php:940 +msgid "Follow Thread" +msgstr "Seguir el hilo" + +#: ../../include/conversation.php:941 +msgid "View Status" +msgstr "Ver estado" + +#: ../../include/conversation.php:943 +msgid "View Photos" +msgstr "Ver fotos" + +#: ../../include/conversation.php:944 +msgid "Matrix Activity" +msgstr "Actividad en la red" + +#: ../../include/conversation.php:946 +msgid "Edit Contact" +msgstr "Editar contacto" + +#: ../../include/conversation.php:947 +msgid "Send PM" +msgstr "Enviar Mensaje Privado" + +#: ../../include/conversation.php:948 ../../include/apps.php:145 +msgid "Poke" +msgstr "Dar un toque" + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s likes this." +msgstr "a %s le gusta esto." + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s doesn't like this." +msgstr "a %s no le gusta esto." + +#: ../../include/conversation.php:1066 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "a %2$d persona le gusta esto." +msgstr[1] "a %2$d personas les gusta esto." + +#: ../../include/conversation.php:1068 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "a %2$d persona no le gusta esto." +msgstr[1] "a %2$d personas no les gusta esto." + +#: ../../include/conversation.php:1074 +msgid "and" +msgstr "y" + +#: ../../include/conversation.php:1077 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] ", y %d persona más" +msgstr[1] ", y %d personas más" + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s like this." +msgstr "a %s le gusta esto." + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s don't like this." +msgstr "a %s no le gusta esto." + +#: ../../include/conversation.php:1140 +msgid "Visible to everybody" +msgstr "Visible para cualquiera" + +#: ../../include/conversation.php:1141 ../../mod/mail.php:174 +#: ../../mod/mail.php:289 +msgid "Please enter a link URL:" +msgstr "Por favor, introduzca una URL de enlace:" + +#: ../../include/conversation.php:1142 +msgid "Please enter a video link/URL:" +msgstr "Por favor, introduzca un enlace/URL de vídeo:" + +#: ../../include/conversation.php:1143 +msgid "Please enter an audio link/URL:" +msgstr "Por favor, introduzca un enlace/URL de audio:" + +#: ../../include/conversation.php:1144 +msgid "Tag term:" +msgstr "Término de etiqueta:" + +#: ../../include/conversation.php:1145 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "Guardar en carpeta:" + +#: ../../include/conversation.php:1146 +msgid "Where are you right now?" +msgstr "¿Donde está ahora?" + +#: ../../include/conversation.php:1147 ../../mod/editpost.php:47 +#: ../../mod/mail.php:175 ../../mod/mail.php:290 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "Caduca YYYY-MM-DD HH:MM" + +#: ../../include/conversation.php:1174 ../../mod/webpages.php:182 +#: ../../mod/blocks.php:154 ../../mod/photos.php:961 ../../mod/layouts.php:184 +msgid "Share" +msgstr "Compartir" + +#: ../../include/conversation.php:1176 +msgid "Page link name" +msgstr "Nombre de enlace de página" + +#: ../../include/conversation.php:1179 +msgid "Post as" +msgstr "Publicar como" + +#: ../../include/conversation.php:1186 ../../mod/editpost.php:112 +#: ../../mod/editlayout.php:139 ../../mod/editwebpage.php:184 +#: ../../mod/editblock.php:141 ../../mod/mail.php:238 ../../mod/mail.php:352 +msgid "Upload photo" +msgstr "Subir foto" + +#: ../../include/conversation.php:1187 +msgid "upload photo" +msgstr "subir foto" + +#: ../../include/conversation.php:1188 ../../mod/editpost.php:113 +#: ../../mod/editlayout.php:140 ../../mod/editwebpage.php:185 +#: ../../mod/editblock.php:142 ../../mod/mail.php:239 ../../mod/mail.php:353 +msgid "Attach file" +msgstr "Adjuntar archivo" + +#: ../../include/conversation.php:1189 +msgid "attach file" +msgstr "adjuntar archivo" + +#: ../../include/conversation.php:1190 ../../mod/editpost.php:114 +#: ../../mod/editlayout.php:141 ../../mod/editwebpage.php:186 +#: ../../mod/editblock.php:143 ../../mod/mail.php:240 ../../mod/mail.php:354 +msgid "Insert web link" +msgstr "Insertar enlace web" + +#: ../../include/conversation.php:1191 +msgid "web link" +msgstr "enlace web" + +#: ../../include/conversation.php:1192 +msgid "Insert video link" +msgstr "Insertar enlace de vídeo" + +#: ../../include/conversation.php:1193 +msgid "video link" +msgstr "enlace de vídeo" + +#: ../../include/conversation.php:1194 +msgid "Insert audio link" +msgstr "Insertar enlace de audio" + +#: ../../include/conversation.php:1195 +msgid "audio link" +msgstr "enlace de audio" + +#: ../../include/conversation.php:1196 ../../mod/editpost.php:118 +#: ../../mod/editlayout.php:145 ../../mod/editwebpage.php:190 +#: ../../mod/editblock.php:147 +msgid "Set your location" +msgstr "Configure su localización" + +#: ../../include/conversation.php:1197 +msgid "set location" +msgstr "configura localización" + +#: ../../include/conversation.php:1198 ../../mod/editpost.php:120 +msgid "Toggle voting" +msgstr "Invertir votación" + +#: ../../include/conversation.php:1201 ../../mod/editpost.php:119 +#: ../../mod/editlayout.php:146 ../../mod/editwebpage.php:191 +#: ../../mod/editblock.php:148 +msgid "Clear browser location" +msgstr "Eliminar localización del navegador" + +#: ../../include/conversation.php:1202 +msgid "clear location" +msgstr "eliminar localización" + +#: ../../include/conversation.php:1204 ../../mod/editpost.php:135 +#: ../../mod/editwebpage.php:207 ../../mod/editblock.php:161 +msgid "Title (optional)" +msgstr "Título (opcional)" + +#: ../../include/conversation.php:1208 ../../mod/editpost.php:137 +#: ../../mod/editlayout.php:162 ../../mod/editwebpage.php:209 +#: ../../mod/editblock.php:164 +msgid "Categories (optional, comma-separated list)" +msgstr "Categorías (opcional, lista separada por comas)" + +#: ../../include/conversation.php:1210 ../../mod/editpost.php:124 +#: ../../mod/editlayout.php:148 ../../mod/editwebpage.php:193 +#: ../../mod/editblock.php:150 +msgid "Permission settings" +msgstr "Configuración de permisos" + +#: ../../include/conversation.php:1211 +msgid "permissions" +msgstr "permisos" + +#: ../../include/conversation.php:1219 ../../mod/editpost.php:132 +#: ../../mod/editlayout.php:155 ../../mod/editwebpage.php:202 +#: ../../mod/editblock.php:158 +msgid "Public post" +msgstr "Publicación pública" + +#: ../../include/conversation.php:1221 ../../mod/editpost.php:138 +#: ../../mod/editlayout.php:163 ../../mod/editwebpage.php:210 +#: ../../mod/editblock.php:165 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Ejemplo: bob@example.com, mary@example.com" + +#: ../../include/conversation.php:1234 ../../mod/editpost.php:149 +#: ../../mod/editlayout.php:172 ../../mod/editwebpage.php:219 +#: ../../mod/editblock.php:175 ../../mod/mail.php:245 ../../mod/mail.php:359 +msgid "Set expiration date" +msgstr "Configurar fecha de expiración" + +#: ../../include/conversation.php:1238 ../../mod/events.php:651 +#: ../../mod/editpost.php:153 +msgid "OK" +msgstr "OK" + +#: ../../include/conversation.php:1239 ../../mod/tagrm.php:11 +#: ../../mod/tagrm.php:134 ../../mod/events.php:650 ../../mod/fbrowser.php:82 +#: ../../mod/fbrowser.php:117 ../../mod/editpost.php:154 +#: ../../mod/settings.php:589 ../../mod/settings.php:615 +msgid "Cancel" +msgstr "Cancelar" + +#: ../../include/conversation.php:1481 +msgid "Discover" +msgstr "Descubrir" + +#: ../../include/conversation.php:1484 +msgid "Imported public streams" +msgstr "Flujos públicos importados" + +#: ../../include/conversation.php:1489 +msgid "Commented Order" +msgstr "Comentarios recientes" + +#: ../../include/conversation.php:1492 +msgid "Sort by Comment Date" +msgstr "Ordenar por fecha de comentario" + +#: ../../include/conversation.php:1496 +msgid "Posted Order" +msgstr "Publicaciones recientes" + +#: ../../include/conversation.php:1499 +msgid "Sort by Post Date" +msgstr "Ordenar por fecha de publicación" + +#: ../../include/conversation.php:1507 +msgid "Posts that mention or involve you" +msgstr "Publicaciones que le mencionan o involucran" + +#: ../../include/conversation.php:1513 ../../mod/connections.php:212 +#: ../../mod/connections.php:225 ../../mod/menu.php:107 +msgid "New" +msgstr "Novedades" + +#: ../../include/conversation.php:1516 +msgid "Activity Stream - by date" +msgstr "Flujo de actividad - por fecha" + +#: ../../include/conversation.php:1522 +msgid "Starred" +msgstr "Preferidos" + +#: ../../include/conversation.php:1525 +msgid "Favourite Posts" +msgstr "Publicaciones favoritas" + +#: ../../include/conversation.php:1532 +msgid "Spam" +msgstr "Correo basura" + +#: ../../include/conversation.php:1535 +msgid "Posts flagged as SPAM" +msgstr "Publicaciones marcadas como basura" + +#: ../../include/conversation.php:1579 ../../mod/admin.php:993 +msgid "Channel" +msgstr "Canal" + +#: ../../include/conversation.php:1582 +msgid "Status Messages and Posts" +msgstr "Mensajes de estado y publicaciones" + +#: ../../include/conversation.php:1591 +msgid "About" +msgstr "Perfil" + +#: ../../include/conversation.php:1594 +msgid "Profile Details" +msgstr "Detalles de perfil" + +#: ../../include/conversation.php:1603 ../../include/photos.php:359 +msgid "Photo Albums" +msgstr "Ãlbumes de fotos" + +#: ../../include/conversation.php:1612 +msgid "Files and Storage" +msgstr "Ficheros y almacenamiento" + +#: ../../include/conversation.php:1622 ../../include/conversation.php:1625 +msgid "Chatrooms" +msgstr "Salas de chat" + +#: ../../include/conversation.php:1638 +msgid "Saved Bookmarks" +msgstr "Marcadores guardados" + +#: ../../include/conversation.php:1648 +msgid "Manage Webpages" +msgstr "Administrar páginas web" + +#: ../../include/conversation.php:1707 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "Asistir" +msgstr[1] "Participar" + +#: ../../include/conversation.php:1710 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "No asistir" +msgstr[1] "No participar" + +#: ../../include/conversation.php:1713 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] "Indeciso/a" +msgstr[1] "Indecisos/as" + +#: ../../include/conversation.php:1716 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "Está de acuerdo" +msgstr[1] "Están de acuerdo" + +#: ../../include/conversation.php:1719 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "No está de acuerdo" +msgstr[1] "No están de acuerdo" + +#: ../../include/conversation.php:1722 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "se abstiene" +msgstr[1] "Abstenerse" + +#: ../../include/items.php:413 ../../mod/like.php:270 +#: ../../mod/subthread.php:49 ../../mod/group.php:68 ../../mod/profperm.php:23 +#: ../../mod/bulksetclose.php:11 ../../index.php:392 +msgid "Permission denied" +msgstr "Permiso denegado" + +#: ../../include/items.php:1038 ../../include/items.php:1084 +msgid "(Unknown)" +msgstr "(Desconocido)" + +#: ../../include/items.php:1310 +msgid "Visible to anybody on the internet." +msgstr "Visible para todo el mundo en internet." + +#: ../../include/items.php:1312 +msgid "Visible to you only." +msgstr "Visible sólo para usted." + +#: ../../include/items.php:1314 +msgid "Visible to anybody in this network." +msgstr "Visible para cualquiera en esta red." + +#: ../../include/items.php:1316 +msgid "Visible to anybody authenticated." +msgstr "Visible para cualquiera autenticado." + +#: ../../include/items.php:1318 +#, php-format +msgid "Visible to anybody on %s." +msgstr "Visible para cualquiera en %s." + +#: ../../include/items.php:1320 +msgid "Visible to all connections." +msgstr "Visible para todas las conexiones." + +#: ../../include/items.php:1322 +msgid "Visible to approved connections." +msgstr "Visible para conexiones permitidas." + +#: ../../include/items.php:1324 +msgid "Visible to specific connections." +msgstr "Visible para conexiones específicas." + +#: ../../include/items.php:4218 ../../mod/thing.php:74 +#: ../../mod/filestorage.php:27 ../../mod/viewsrc.php:20 +#: ../../mod/admin.php:167 ../../mod/admin.php:1025 ../../mod/admin.php:1225 +#: ../../mod/display.php:36 +msgid "Item not found." +msgstr "Elemento no encontrado." + +#: ../../include/items.php:4291 ../../include/attach.php:137 +#: ../../include/attach.php:184 ../../include/attach.php:247 +#: ../../include/attach.php:261 ../../include/attach.php:305 +#: ../../include/attach.php:319 ../../include/attach.php:350 +#: ../../include/attach.php:546 ../../include/attach.php:618 +#: ../../include/chat.php:131 ../../include/photos.php:26 +#: ../../mod/profile.php:64 ../../mod/profile.php:72 +#: ../../mod/achievements.php:30 ../../mod/manage.php:6 ../../mod/api.php:26 +#: ../../mod/api.php:31 ../../mod/webpages.php:69 ../../mod/thing.php:241 +#: ../../mod/thing.php:256 ../../mod/thing.php:290 +#: ../../mod/profile_photo.php:264 ../../mod/profile_photo.php:277 +#: ../../mod/block.php:22 ../../mod/block.php:72 ../../mod/like.php:178 +#: ../../mod/events.php:232 ../../mod/group.php:9 ../../mod/item.php:206 +#: ../../mod/item.php:214 ../../mod/item.php:978 ../../mod/network.php:12 +#: ../../mod/common.php:35 ../../mod/connections.php:169 +#: ../../mod/blocks.php:69 ../../mod/blocks.php:76 ../../mod/editpost.php:13 +#: ../../mod/photos.php:69 ../../mod/pdledit.php:21 ../../mod/authtest.php:13 +#: ../../mod/editlayout.php:63 ../../mod/editlayout.php:87 +#: ../../mod/chat.php:90 ../../mod/chat.php:95 ../../mod/mitem.php:109 +#: ../../mod/editwebpage.php:64 ../../mod/editwebpage.php:86 +#: ../../mod/editwebpage.php:101 ../../mod/editwebpage.php:125 +#: ../../mod/rate.php:110 ../../mod/editblock.php:65 ../../mod/invite.php:13 +#: ../../mod/invite.php:104 ../../mod/locs.php:77 ../../mod/sources.php:66 +#: ../../mod/menu.php:69 ../../mod/filestorage.php:18 +#: ../../mod/filestorage.php:73 ../../mod/filestorage.php:88 +#: ../../mod/filestorage.php:115 ../../mod/fsuggest.php:78 +#: ../../mod/poke.php:128 ../../mod/profiles.php:188 +#: ../../mod/profiles.php:576 ../../mod/viewsrc.php:14 ../../mod/setup.php:223 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +#: ../../mod/register.php:72 ../../mod/settings.php:570 ../../mod/id.php:71 +#: ../../mod/message.php:16 ../../mod/mood.php:111 ../../mod/connedit.php:336 +#: ../../mod/mail.php:114 ../../mod/notifications.php:66 +#: ../../mod/regmod.php:17 ../../mod/new_channel.php:68 +#: ../../mod/new_channel.php:99 ../../mod/appman.php:66 +#: ../../mod/layouts.php:69 ../../mod/layouts.php:76 ../../mod/layouts.php:87 +#: ../../mod/page.php:31 ../../mod/page.php:86 ../../mod/bookmarks.php:46 +#: ../../mod/channel.php:100 ../../mod/channel.php:219 +#: ../../mod/channel.php:262 ../../mod/suggest.php:26 +#: ../../mod/service_limits.php:7 ../../mod/sharedwithme.php:7 +#: ../../index.php:182 ../../index.php:393 +msgid "Permission denied." +msgstr "Acceso denegado." + +#: ../../include/items.php:4693 ../../mod/group.php:38 ../../mod/group.php:140 +#: ../../mod/bulksetclose.php:51 +msgid "Collection not found." +msgstr "Colección no encontrada." + +#: ../../include/items.php:4709 +msgid "Collection is empty." +msgstr "La colección está vacía." + +#: ../../include/items.php:4716 +#, php-format +msgid "Collection: %s" +msgstr "Colección: %s" + +#: ../../include/items.php:4726 ../../mod/connedit.php:662 +#, php-format +msgid "Connection: %s" +msgstr "Conexión: %s" + +#: ../../include/items.php:4728 +msgid "Connection not found." +msgstr "Conexión no encontrada" + +#: ../../include/zot.php:666 +msgid "Invalid data packet" +msgstr "Paquete de datos inválido" + +#: ../../include/zot.php:682 +msgid "Unable to verify channel signature" +msgstr "No ha sido posible de verificar la signatura del canal" + +#: ../../include/zot.php:2144 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "No ha sido posible de verificar la signatura del sitio para %s" + +#: ../../include/oembed.php:183 +msgid "Embedded content" +msgstr "Contenido incrustado" + +#: ../../include/oembed.php:192 +msgid "Embedding disabled" +msgstr "Incrustación deshabilitada" + +#: ../../include/auth.php:131 +msgid "Logged out." +msgstr "Desconectado." + +#: ../../include/auth.php:272 +msgid "Failed authentication" +msgstr "Autenticación fallida." + +#: ../../include/auth.php:286 ../../mod/openid.php:190 +msgid "Login failed." +msgstr "Login ha fallado." + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "%d invitación pendiente" +msgstr[1] "%d invitaciones pendientes" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:457 +msgid "Advanced" +msgstr "Avanzado" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "Encontrar canales" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "Introducir nombre o interés" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "Conectar/Seguir" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Ejemplos: José Fernández, Pesca" + +#: ../../include/contact_widgets.php:26 ../../mod/directory.php:379 +#: ../../mod/directory.php:384 ../../mod/connections.php:413 +msgid "Find" +msgstr "Encontrar" + +#: ../../include/contact_widgets.php:27 ../../mod/directory.php:383 +#: ../../mod/suggest.php:60 +msgid "Channel Suggestions" +msgstr "Sugerencias de canales" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "Perfil aleatorio" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "Invitar amigos" + +#: ../../include/contact_widgets.php:32 +msgid "Advanced example: name=fred and country=iceland" +msgstr "Ejemplo avanzado: nombre=fred y pais=islandia" + +#: ../../include/contact_widgets.php:125 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "%d conexión en común" +msgstr[1] "%d conexiones en común" + +#: ../../include/contact_widgets.php:130 +msgid "show more" +msgstr "mostrar más" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "Visible para su público predeterminado." + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "Mostrar" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "No mostrar" + +#: ../../include/acl_selectors.php:248 ../../mod/events.php:668 +#: ../../mod/photos.php:571 ../../mod/photos.php:934 ../../mod/chat.php:209 +#: ../../mod/filestorage.php:147 +msgid "Permissions" +msgstr "Permisos" + +#: ../../include/attach.php:242 ../../include/attach.php:300 +msgid "Item was not found." +msgstr "Elemento no encontrado." + +#: ../../include/attach.php:363 +msgid "No source file." +msgstr "Ningún archivo de fuente" + +#: ../../include/attach.php:381 +msgid "Cannot locate file to replace" +msgstr "No se puede localizar el archivo a ser sustituido." + +#: ../../include/attach.php:399 +msgid "Cannot locate file to revise/update" +msgstr "No se puede localizar el archivo para revisar/actualizar" + +#: ../../include/attach.php:410 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Archivo supera el limite de tamaño de %d" + +#: ../../include/attach.php:422 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "Ha alcanzado su límite de %1$.0f Mbytes de almacenamiento de adjuntos." + +#: ../../include/attach.php:505 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "Error de carga, posiblemente por limite de sistema o terminación de acción" + +#: ../../include/attach.php:517 +msgid "Stored file could not be verified. Upload failed." +msgstr "El archivo almacenado no ha podido ser verificado. El envío ha fallado." + +#: ../../include/attach.php:561 ../../include/attach.php:578 +msgid "Path not available." +msgstr "Ruta no disponible." + +#: ../../include/attach.php:623 +msgid "Empty pathname" +msgstr "Ruta vacía" + +#: ../../include/attach.php:639 +msgid "duplicate filename or path" +msgstr "Nombre de ruta o archivo duplicado" + +#: ../../include/attach.php:663 +msgid "Path not found." +msgstr "Ruta no encontrada" + +#: ../../include/attach.php:714 +msgid "mkdir failed." +msgstr "mkdir ha fallado." + +#: ../../include/attach.php:718 +msgid "database storage failed." +msgstr "almacenamiento en base de datos ha fallado." + +#: ../../include/identity.php:33 +msgid "Unable to obtain identity information from database" +msgstr "No ha sido posible de obtener la información de identidad de la base de datos" + +#: ../../include/identity.php:67 +msgid "Empty name" +msgstr "Nombre vacío" + +#: ../../include/identity.php:70 +msgid "Name too long" +msgstr "Nombre demasiado largo" + +#: ../../include/identity.php:186 +msgid "No account identifier" +msgstr "Ningún identificador de la cuenta" + +#: ../../include/identity.php:198 +msgid "Nickname is required." +msgstr "Se requiere un sobrenombre (alias)." + +#: ../../include/identity.php:212 +msgid "Reserved nickname. Please choose another." +msgstr "Sobrenombre en uso. Por favor, elija otro." + +#: ../../include/identity.php:217 ../../include/dimport.php:34 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "El apodo contiene caracteres no admitidos o está ya en uso por otros usuarios de éste sitio." + +#: ../../include/identity.php:292 +msgid "Unable to retrieve created identity" +msgstr "No ha sido posible de conseguir la identidad creada" + +#: ../../include/identity.php:350 +msgid "Default Profile" +msgstr "Perfil principal" + +#: ../../include/identity.php:660 +msgid "Requested channel is not available." +msgstr "El canal solicitado no está disponible." + +#: ../../include/identity.php:707 ../../mod/profile.php:16 +#: ../../mod/achievements.php:11 ../../mod/webpages.php:29 +#: ../../mod/connect.php:13 ../../mod/hcard.php:8 ../../mod/blocks.php:29 +#: ../../mod/editlayout.php:27 ../../mod/editwebpage.php:28 +#: ../../mod/editblock.php:29 ../../mod/filestorage.php:54 +#: ../../mod/layouts.php:29 +msgid "Requested profile is not available." +msgstr "El perfil solicitado no está disponible." + +#: ../../include/identity.php:870 ../../mod/profiles.php:774 +msgid "Change profile photo" +msgstr "Cambiar foto de perfil" + +#: ../../include/identity.php:876 +msgid "Profiles" +msgstr "Perfiles" + +#: ../../include/identity.php:876 +msgid "Manage/edit profiles" +msgstr "Administrar/editar perfiles" + +#: ../../include/identity.php:877 ../../mod/profiles.php:775 +msgid "Create New Profile" +msgstr "Crear nuevo perfil" + +#: ../../include/identity.php:892 ../../mod/profiles.php:786 +msgid "Profile Image" +msgstr "Imagen de perfil" + +#: ../../include/identity.php:895 +msgid "visible to everybody" +msgstr "visible para todos" + +#: ../../include/identity.php:896 ../../mod/profiles.php:669 +#: ../../mod/profiles.php:790 +msgid "Edit visibility" +msgstr "Editar visibilidad" + +#: ../../include/identity.php:912 ../../include/identity.php:1151 +msgid "Gender:" +msgstr "Género:" + +#: ../../include/identity.php:913 ../../include/identity.php:1195 +msgid "Status:" +msgstr "Estado:" + +#: ../../include/identity.php:914 ../../include/identity.php:1206 +msgid "Homepage:" +msgstr "Página web:" + +#: ../../include/identity.php:915 +msgid "Online Now" +msgstr "Ahora en línea" + +#: ../../include/identity.php:998 ../../include/identity.php:1076 +#: ../../mod/ping.php:324 +msgid "g A l F d" +msgstr "g A l F d" + +#: ../../include/identity.php:999 ../../include/identity.php:1077 +msgid "F d" +msgstr "F d" + +#: ../../include/identity.php:1044 ../../include/identity.php:1116 +#: ../../mod/ping.php:346 +msgid "[today]" +msgstr "[hoy]" + +#: ../../include/identity.php:1055 +msgid "Birthday Reminders" +msgstr "Recordatorios de cumpleaños" + +#: ../../include/identity.php:1056 +msgid "Birthdays this week:" +msgstr "Cumpleaños esta semana:" + +#: ../../include/identity.php:1109 +msgid "[No description]" +msgstr "[Sin descripción]" + +#: ../../include/identity.php:1127 +msgid "Event Reminders" +msgstr "Recordatorios de eventos" + +#: ../../include/identity.php:1128 +msgid "Events this week:" +msgstr "Eventos de esta semana:" + +#: ../../include/identity.php:1141 ../../include/identity.php:1258 +#: ../../include/apps.php:138 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "Perfil" + +#: ../../include/identity.php:1149 ../../mod/settings.php:1056 +msgid "Full Name:" +msgstr "Nombre completo:" + +#: ../../include/identity.php:1156 +msgid "Like this channel" +msgstr "Me gusta este canal" + +#: ../../include/identity.php:1180 +msgid "j F, Y" +msgstr "j F, Y" + +#: ../../include/identity.php:1181 +msgid "j F" +msgstr "j F" + +#: ../../include/identity.php:1188 +msgid "Birthday:" +msgstr "Cumpleaños:" + +#: ../../include/identity.php:1192 ../../mod/directory.php:297 +msgid "Age:" +msgstr "Edad:" + +#: ../../include/identity.php:1201 +#, php-format +msgid "for %1$d %2$s" +msgstr "por %1$d %2$s" + +#: ../../include/identity.php:1204 ../../mod/profiles.php:691 +msgid "Sexual Preference:" +msgstr "Orientación sexual:" + +#: ../../include/identity.php:1208 ../../mod/directory.php:313 +#: ../../mod/profiles.php:693 +msgid "Hometown:" +msgstr "Ciudad de origen:" + +#: ../../include/identity.php:1210 +msgid "Tags:" +msgstr "Etiquetas:" + +#: ../../include/identity.php:1212 ../../mod/profiles.php:694 +msgid "Political Views:" +msgstr "Posición política:" + +#: ../../include/identity.php:1214 +msgid "Religion:" +msgstr "Religión:" + +#: ../../include/identity.php:1216 ../../mod/directory.php:315 +msgid "About:" +msgstr "Sobre mí:" + +#: ../../include/identity.php:1218 +msgid "Hobbies/Interests:" +msgstr "Aficciones/Intereses:" + +#: ../../include/identity.php:1220 ../../mod/profiles.php:697 +msgid "Likes:" +msgstr "Me gusta:" + +#: ../../include/identity.php:1222 ../../mod/profiles.php:698 +msgid "Dislikes:" +msgstr "No me gusta:" + +#: ../../include/identity.php:1224 +msgid "Contact information and Social Networks:" +msgstr "Información de contacto y redes sociales:" + +#: ../../include/identity.php:1226 +msgid "My other channels:" +msgstr "Mis otros canales:" + +#: ../../include/identity.php:1228 +msgid "Musical interests:" +msgstr "Intereses musicales:" + +#: ../../include/identity.php:1230 +msgid "Books, literature:" +msgstr "Libros, literatura:" + +#: ../../include/identity.php:1232 +msgid "Television:" +msgstr "Televisión:" + +#: ../../include/identity.php:1234 +msgid "Film/dance/culture/entertainment:" +msgstr "Cine/baile/cultura/entretenimiento:" + +#: ../../include/identity.php:1236 +msgid "Love/Romance:" +msgstr "Amor/romance:" + +#: ../../include/identity.php:1238 +msgid "Work/employment:" +msgstr "Trabajo/empleo:" + +#: ../../include/identity.php:1240 +msgid "School/education:" +msgstr "Estudios:" + +#: ../../include/identity.php:1260 +msgid "Like this thing" +msgstr "Me gusta esto" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:103 +msgid "Male" +msgstr "Hombre" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:105 +msgid "Female" +msgstr "Mujer" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Actualmente hombre" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Actualmente mujer" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Generalmente hombre" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Generalmente mujer" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transgénero" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Intersexual" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transexual" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Hermafrodita" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Neutral" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "No-especificada" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Indecidido" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "Hombres" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "Mujeres" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "Gay" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "Lesbiana" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "Sin preferencias" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "Bisexual" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "Autosexual" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "Abstemio" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "Virgen" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "Fuera de lo común" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "Fetiche" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "Montones" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "No sexual" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "Soltero/a" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "Solo/a" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "Disponible" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "No disponible" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "Enamorado/a" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "Infatuado" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "Citando" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "Infiel" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "Con adicción al sexo" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "Amistad beneficiosa" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "Casual" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "Prometido/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "Casado/a" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "Casado/a imaginario/a" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "Pareja" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "Cohabitando" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "Derecho común" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "Felíz" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "No estoy buscando" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "Swinger" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "Engañado/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "Separado/a" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "Inestable" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "Divorciado/a" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "Divorciado/a imaginario/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "Viudo/a" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "Indeterminado" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "Es complicado" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "No me importa" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "Pregúnteme" + +#: ../../include/apps.php:128 +msgid "Site Admin" +msgstr "Adminstrador del sitio" + +#: ../../include/apps.php:130 +msgid "Address Book" +msgstr "Libreta de direcciones" + +#: ../../include/apps.php:144 ../../mod/mood.php:130 +msgid "Mood" +msgstr "Estado de ánimo" + +#: ../../include/apps.php:148 +msgid "Probe" +msgstr "Probar" + +#: ../../include/apps.php:149 +msgid "Suggest" +msgstr "Sugerir" + +#: ../../include/apps.php:150 +msgid "Random Channel" +msgstr "Canal aleatorio" + +#: ../../include/apps.php:151 +msgid "Invite" +msgstr "Invitar" + +#: ../../include/apps.php:152 +msgid "Features" +msgstr "Características" + +#: ../../include/apps.php:153 ../../mod/id.php:28 +msgid "Language" +msgstr "Idioma" + +#: ../../include/apps.php:154 +msgid "Post" +msgstr "Publicación" + +#: ../../include/apps.php:155 ../../mod/id.php:17 ../../mod/id.php:18 +#: ../../mod/id.php:19 +msgid "Profile Photo" +msgstr "Foto de perfil" + +#: ../../include/apps.php:247 ../../mod/settings.php:84 +#: ../../mod/settings.php:614 +msgid "Update" +msgstr "Actualizar" + +#: ../../include/apps.php:247 +msgid "Install" +msgstr "Instalar" + +#: ../../include/apps.php:252 +msgid "Purchase" +msgstr "Comprar" + +#: ../../include/bbcode.php:122 ../../include/bbcode.php:768 +#: ../../include/bbcode.php:771 ../../include/bbcode.php:776 +#: ../../include/bbcode.php:779 ../../include/bbcode.php:782 +#: ../../include/bbcode.php:785 ../../include/bbcode.php:790 +#: ../../include/bbcode.php:793 ../../include/bbcode.php:798 +#: ../../include/bbcode.php:801 ../../include/bbcode.php:804 +#: ../../include/bbcode.php:807 +msgid "Image/photo" +msgstr "Imagen/foto" + +#: ../../include/bbcode.php:161 ../../include/bbcode.php:818 +msgid "Encrypted content" +msgstr "Contenido encriptado" + +#: ../../include/bbcode.php:178 +#, php-format +msgid "Install %s element: " +msgstr "Instalar %s elemento:" + +#: ../../include/bbcode.php:182 +#, php-format +msgid "" +"This post contains an installable %s element, however you lack permissions " +"to install it on this site." +msgstr "Esta entrada contiene un elemento instalable %s, sin embargo le faltan permisos para instalarlo en este sitio." + +#: ../../include/bbcode.php:192 ../../mod/impel.php:37 +msgid "webpage" +msgstr "página web" + +#: ../../include/bbcode.php:195 ../../mod/impel.php:47 +msgid "layout" +msgstr "disposición" + +#: ../../include/bbcode.php:198 ../../mod/impel.php:42 +msgid "block" +msgstr "bloquear" + +#: ../../include/bbcode.php:201 ../../mod/impel.php:54 +msgid "menu" +msgstr "menú" + +#: ../../include/bbcode.php:215 +msgid "QR code" +msgstr "Código QR" + +#: ../../include/bbcode.php:266 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "%1$s escribió la siguiente %2$s %3$s" + +#: ../../include/bbcode.php:268 ../../mod/tagger.php:51 +msgid "post" +msgstr "entrada" + +#: ../../include/bbcode.php:518 +msgid "Different viewers will see this text differently" +msgstr "Visitantes diferentes verán este texto de forma diferente" + +#: ../../include/bbcode.php:729 +msgid "$1 spoiler" +msgstr "alerón $1" + +#: ../../include/bbcode.php:756 +msgid "$1 wrote:" +msgstr "$1 escribió" + +#: ../../include/chat.php:23 +msgid "Missing room name" +msgstr "Nombre de sala desaparecido." + +#: ../../include/chat.php:32 +msgid "Duplicate room name" +msgstr "Nombre de sala duplicado." + +#: ../../include/chat.php:82 ../../include/chat.php:90 +msgid "Invalid room specifier." +msgstr "Especificador de sala inválido." + +#: ../../include/chat.php:120 +msgid "Room not found." +msgstr "Sala no encontrada." + +#: ../../include/chat.php:141 +msgid "Room is full" +msgstr "La sala está llena." + +#: ../../include/photos.php:94 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "La imagen es demasiado grande (%lu demás)" + +#: ../../include/photos.php:101 +msgid "Image file is empty." +msgstr "El fichero de imagen ésta vacío. " + +#: ../../include/photos.php:128 ../../mod/profile_photo.php:217 +msgid "Unable to process image" +msgstr "No ha sido posible de procesar la imagen" + +#: ../../include/photos.php:199 +msgid "Photo storage failed." +msgstr "La foto no ha podido ser guardada." + +#: ../../include/photos.php:363 +msgid "Upload New Photos" +msgstr "Subir nuevas fotos" + +#: ../../mod/achievements.php:34 +msgid "Some blurb about what to do when you're new here" +msgstr "Algunas palabras sobre qué hacer cuando eres nuevo aquí" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "Ha creado %1$.0f de %2$.0f canales permitidos." + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "Crear un nuevo canal" + +#: ../../mod/manage.php:167 +msgid "Current Channel" +msgstr "Canal actual" + +#: ../../mod/manage.php:169 +msgid "Switch to one of your channels by selecting it." +msgstr "Cambiar a uno de sus canales seleccionándolo." + +#: ../../mod/manage.php:170 +msgid "Default Channel" +msgstr "Canal predeterminado" + +#: ../../mod/manage.php:171 +msgid "Make Default" +msgstr "Convertir en predeterminado" + +#: ../../mod/manage.php:174 +#, php-format +msgid "%d new messages" +msgstr "%d nuevos mensajes" + +#: ../../mod/manage.php:175 +#, php-format +msgid "%d new introductions" +msgstr "%d nuevas introducciones" + +#: ../../mod/manage.php:177 +msgid "Delegated Channels" +msgstr "Canales delegados" + +#: ../../mod/directory.php:59 ../../mod/photos.php:441 ../../mod/search.php:13 +#: ../../mod/ratings.php:82 ../../mod/viewconnections.php:17 +#: ../../mod/display.php:13 +msgid "Public access denied." +msgstr "Acceso público denegado." + +#: ../../mod/directory.php:234 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "%d valoración" +msgstr[1] "%d valoraciones" + +#: ../../mod/directory.php:245 +msgid "Gender: " +msgstr "Género:" + +#: ../../mod/directory.php:247 +msgid "Status: " +msgstr "Estado:" + +#: ../../mod/directory.php:249 +msgid "Homepage: " +msgstr "Página de inicio:" + +#: ../../mod/directory.php:308 ../../mod/events.php:659 +msgid "Description:" +msgstr "Descripción:" + +#: ../../mod/directory.php:317 +msgid "Public Forum:" +msgstr "Foro público:" + +#: ../../mod/directory.php:320 +msgid "Keywords: " +msgstr "Palabras clave:" + +#: ../../mod/directory.php:323 +msgid "Don't suggest" +msgstr "No sugerir:" + +#: ../../mod/directory.php:325 +msgid "Common connections:" +msgstr "Conexiones comunes:" + +#: ../../mod/directory.php:374 +msgid "Global Directory" +msgstr "Directorio global:" + +#: ../../mod/directory.php:374 +msgid "Local Directory" +msgstr "Directorio local:" + +#: ../../mod/directory.php:380 +msgid "Finding:" +msgstr "Encontrar:" + +#: ../../mod/directory.php:385 +msgid "next page" +msgstr "siguiente página" + +#: ../../mod/directory.php:385 +msgid "previous page" +msgstr "página anterior" + +#: ../../mod/directory.php:386 +msgid "Sort options" +msgstr "Ordenar opciones" + +#: ../../mod/directory.php:387 +msgid "Alphabetic" +msgstr "Alfabético" + +#: ../../mod/directory.php:388 +msgid "Reverse Alphabetic" +msgstr "Alfabético inverso" + +#: ../../mod/directory.php:389 +msgid "Newest to Oldest" +msgstr "Más nuevo a más antiguo" + +#: ../../mod/directory.php:390 +msgid "Oldest to Newest" +msgstr "Más antiguo a más nuevo" + +#: ../../mod/directory.php:407 +msgid "No entries (some entries may be hidden)." +msgstr "Sin entradas (algunas entradas pueden estar ocultas)." + +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +msgstr "Búsqueda Xchan" + +#: ../../mod/xchan.php:9 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "Buscar xchan que comience por (o webbie):" + +#: ../../mod/xchan.php:37 ../../mod/mitem.php:114 ../../mod/menu.php:156 +msgid "Not found." +msgstr "No encontrado." + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Autorizar conexión de aplicación" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Volver a su aplicación e introducir este código de seguridad:" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Por favor inicia sesión para continuar." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "¿Desea autorizar a esta aplicación a acceder a sus publicaciones y contactos, y/o crear nuevas publicaciones por usted?" + +#: ../../mod/webpages.php:191 +msgid "Page Title" +msgstr "Título de página" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "Canal añadido." + +#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94 +msgid "Tag removed" +msgstr "Etiqueta eliminada." + +#: ../../mod/tagrm.php:119 +msgid "Remove Item Tag" +msgstr "Eliminar etiqueta de elemento." + +#: ../../mod/tagrm.php:121 +msgid "Select a tag to remove: " +msgstr "Selecciona una etiqueta a eliminar:" + +#: ../../mod/tagrm.php:133 ../../mod/photos.php:887 +msgid "Remove" +msgstr "Eliminar" + +#: ../../mod/connect.php:56 ../../mod/connect.php:104 +msgid "Continue" +msgstr "Continuar" + +#: ../../mod/connect.php:85 +msgid "Premium Channel Setup" +msgstr "Configuración del canal premium" + +#: ../../mod/connect.php:87 +msgid "Enable premium channel connection restrictions" +msgstr "Habilitar restricciones de conexión de canal premium" + +#: ../../mod/connect.php:88 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "Por favor introduzca sus restricciones o condiciones, como recibo paypal, normas de uso, etc." + +#: ../../mod/connect.php:90 ../../mod/connect.php:110 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "Este canal puede requerir antes de conectar pasos adicionales o conocimiento de las siguientes condiciones:" + +#: ../../mod/connect.php:91 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "Las posibles conexiones verán por tanto el siguiente texto antes de proceder:" + +#: ../../mod/connect.php:92 ../../mod/connect.php:113 +msgid "" +"By continuing, I certify that I have complied with any instructions provided" +" on this page." +msgstr "Al continuar, certifico que he cumplido con todas las intrucciones proporcionadas en esta página." + +#: ../../mod/connect.php:101 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "(No ha sido proporcionada ninguna instrucción específica por el propietario del canal.)" + +#: ../../mod/connect.php:109 +msgid "Restricted or Premium Channel" +msgstr "Canal premium o restringido" + +#: ../../mod/thing.php:94 +msgid "Thing updated" +msgstr "Elemento actualizado." + +#: ../../mod/thing.php:153 +msgid "Object store: failed" +msgstr "Guardar objeto: ha fallado" + +#: ../../mod/thing.php:157 +msgid "Thing added" +msgstr "Elemento añadido" + +#: ../../mod/thing.php:175 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "OBJ: %1$s %2$s %3$s" + +#: ../../mod/thing.php:226 +msgid "Show Thing" +msgstr "Mostrar elemento" + +#: ../../mod/thing.php:233 +msgid "item not found." +msgstr "elemento no encontrado." + +#: ../../mod/thing.php:261 +msgid "Edit Thing" +msgstr "Editar elemento" + +#: ../../mod/thing.php:263 ../../mod/thing.php:310 +msgid "Select a profile" +msgstr "Seleccionar un perfil" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Post an activity" +msgstr "Publicar una actividad" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Only sends to viewers of the applicable profile" +msgstr "Sólo envíos a espectadores del perfil pertinente." + +#: ../../mod/thing.php:269 ../../mod/thing.php:315 +msgid "Name of thing e.g. something" +msgstr "Nombre del elemento e.g. algo" + +#: ../../mod/thing.php:271 ../../mod/thing.php:316 +msgid "URL of thing (optional)" +msgstr "URL del elemento (opcional)" + +#: ../../mod/thing.php:273 ../../mod/thing.php:317 +msgid "URL for photo of thing (optional)" +msgstr "URL para foto o elemento (opcional)" + +#: ../../mod/thing.php:308 +msgid "Add Thing to your Profile" +msgstr "Añadir elemento a su perfil" + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "Elemento no disponible" + +#: ../../mod/probe.php:24 ../../mod/probe.php:30 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "Obtener URL retorna error: %1$s" + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "Imagen actualizada pero recorte de imagen ha fallado. " + +#: ../../mod/profile_photo.php:162 +msgid "Image resize failed." +msgstr "Ajustar tamaño de imagen ha fallado." + +#: ../../mod/profile_photo.php:206 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Recargue la página o limpie caché del navegador si la nueva foto no se muestra inmediatamente." + +#: ../../mod/profile_photo.php:233 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "La imagen supera el límite de %d" + +#: ../../mod/profile_photo.php:242 +msgid "Unable to process image." +msgstr "No ha sido posible procesar la imagen." + +#: ../../mod/profile_photo.php:291 ../../mod/profile_photo.php:340 +msgid "Photo not available." +msgstr "Foto no disponible." + +#: ../../mod/profile_photo.php:359 +msgid "Upload File:" +msgstr "Subir archivo:" + +#: ../../mod/profile_photo.php:360 +msgid "Select a profile:" +msgstr "Seleccionar un perfil:" + +#: ../../mod/profile_photo.php:361 +msgid "Upload Profile Photo" +msgstr "Subir foto de perfil" + +#: ../../mod/profile_photo.php:366 ../../mod/settings.php:995 +msgid "or" +msgstr "o" + +#: ../../mod/profile_photo.php:366 +msgid "skip this step" +msgstr "Omitir este paso" + +#: ../../mod/profile_photo.php:366 +msgid "select a photo from your photo albums" +msgstr "Seleccione una foto de sus álbums de fotos" + +#: ../../mod/profile_photo.php:382 +msgid "Crop Image" +msgstr "Recortar imagen" + +#: ../../mod/profile_photo.php:383 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Por favor ajuta el recorte de la imagen para una visión óptima." + +#: ../../mod/profile_photo.php:385 +msgid "Done Editing" +msgstr "Edición completada" + +#: ../../mod/profile_photo.php:428 +msgid "Image uploaded successfully." +msgstr "Imagen subida correctamente." + +#: ../../mod/profile_photo.php:430 +msgid "Image upload failed." +msgstr "Subida de imagen fallida." + +#: ../../mod/profile_photo.php:439 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "Reducción de la imagen [%s] fallida." + +#: ../../mod/block.php:27 ../../mod/page.php:36 +msgid "Invalid item." +msgstr "Elemento no válido." + +#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:52 +msgid "Channel not found." +msgstr "Canal no encontrado." + +#: ../../mod/block.php:75 ../../mod/display.php:110 ../../mod/help.php:79 +#: ../../mod/page.php:89 ../../index.php:241 +msgid "Page not found." +msgstr "Página no encontrada." + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "Me gusta/No me gusta" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "Esta acción está restringida solo para miembros." + +#: ../../mod/like.php:21 +msgid "" +"Please login with your $Projectname ID or register as a new $Projectname member to continue." +msgstr "Por favor, identifíquese con su $Projectname ID o rregístrese como un nuevo $Projectname member para continuar." + +#: ../../mod/like.php:101 ../../mod/like.php:128 ../../mod/like.php:166 +msgid "Invalid request." +msgstr "Solicitud incorrecta." + +#: ../../mod/like.php:143 +msgid "thing" +msgstr "elemento" + +#: ../../mod/like.php:189 +msgid "Channel unavailable." +msgstr "Canal no disponible." + +#: ../../mod/like.php:228 +msgid "Previous action reversed." +msgstr "Acción anterior revocada." + +#: ../../mod/like.php:398 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" +msgstr "%1$s está de acuerdo con %3$s de %2$s" + +#: ../../mod/like.php:400 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" +msgstr "%1$s no está de acuerdo con %3$s de %2$s" + +#: ../../mod/like.php:402 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" +msgstr "%1$s se abstiene en %3$s de %2$s" + +#: ../../mod/like.php:404 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "%1$s participará en el %3$s de %2$s" + +#: ../../mod/like.php:406 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "%1$s no participará en el %3$s de %2$s" + +#: ../../mod/like.php:408 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "%1$s tal vez participe en el %3$s de %2$s" + +#: ../../mod/like.php:492 +msgid "Action completed." +msgstr "Acción completada." + +#: ../../mod/like.php:493 +msgid "Thank you." +msgstr "Gracias." + +#: ../../mod/events.php:21 +msgid "Calendar entries imported." +msgstr "Entradas de calendario importadas." + +#: ../../mod/events.php:23 +msgid "No calendar entries found." +msgstr "No encontradas entradas de calendario." + +#: ../../mod/events.php:101 +msgid "Event can not end before it has started." +msgstr "Un evento no puede terminar antes de que haya comenzado." + +#: ../../mod/events.php:103 ../../mod/events.php:112 ../../mod/events.php:130 +msgid "Unable to generate preview." +msgstr "No se puede crear la vista previa." + +#: ../../mod/events.php:110 +msgid "Event title and start time are required." +msgstr "Se requieren el título del evento y su hora de inicio." + +#: ../../mod/events.php:128 +msgid "Event not found." +msgstr "Evento no encontrado." + +#: ../../mod/events.php:409 +msgid "l, F j" +msgstr "l j F" + +#: ../../mod/events.php:431 +msgid "Edit event" +msgstr "Editar evento" + +#: ../../mod/events.php:432 +msgid "Delete event" +msgstr "Borrar evento" + +#: ../../mod/events.php:466 +msgid "calendar" +msgstr "calendario" + +#: ../../mod/events.php:487 +msgid "Create New Event" +msgstr "Crear Nuevo Evento" + +#: ../../mod/events.php:488 ../../mod/photos.php:839 +msgid "Previous" +msgstr "Anterior" + +#: ../../mod/events.php:489 ../../mod/photos.php:848 ../../mod/setup.php:281 +msgid "Next" +msgstr "Siguiente" + +#: ../../mod/events.php:490 +msgid "Export" +msgstr "Exportar" + +#: ../../mod/events.php:493 +msgid "Import" +msgstr "Importar" + +#: ../../mod/events.php:518 +msgid "Event removed" +msgstr "Evento borrado" + +#: ../../mod/events.php:521 +msgid "Failed to remove event" +msgstr "Error al borrar evento" + +#: ../../mod/events.php:641 +msgid "Event details" +msgstr "Detalles del evento" + +#: ../../mod/events.php:642 +msgid "Starting date and Title are required." +msgstr "Se requieren fecha y Título." + +#: ../../mod/events.php:644 +msgid "Categories (comma-separated list)" +msgstr "Categorías (lista separada por comas)" + +#: ../../mod/events.php:646 +msgid "Event Starts:" +msgstr "Inicios de acontecimientos:" + +#: ../../mod/events.php:653 +msgid "Finish date/time is not known or not relevant" +msgstr "La fecha / hora de finalización no se conocen o no son relevantes" + +#: ../../mod/events.php:655 +msgid "Event Finishes:" +msgstr "Eventos Terminados:" + +#: ../../mod/events.php:657 ../../mod/events.php:658 +msgid "Adjust for viewer timezone" +msgstr "Ajustar para obtener el visor de zona horaria" + +#: ../../mod/events.php:657 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." +msgstr "Importante para los eventos que suceden en un lugar determinado. No práctico para las vacaciones globales." + +#: ../../mod/events.php:663 +msgid "Title:" +msgstr "Título:" + +#: ../../mod/events.php:665 +msgid "Share this event" +msgstr "Compartir este evento" + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "%1$s está siguiendo %2$s de %3$s" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "Sitios públicos" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration for the $Projectname network. All" +" sites in the network are interlinked so membership on any of them conveys " +"membership in the network as a whole. Some sites may require subscription or" +" provide tiered service plans. The provider links may " +"provide additional details." +msgstr "Los sitios listados permiten el registro público de la red $Projectname. Todos los sitios de la red están vinculados entre sí por lo que sus miembros, en ninguna de ellas, indican la pertenencia a la red en su conjunto. Algunos sitios pueden requerir suscripción o proporcionar planes de servicio por niveles. Los enlaces de los proveedores de pueden proporcionar detalles adicionales." + +#: ../../mod/pubsites.php:25 +msgid "Rate this hub" +msgstr "Valorar este sitio" + +#: ../../mod/pubsites.php:26 +msgid "Site URL" +msgstr "URL del sitio" + +#: ../../mod/pubsites.php:26 +msgid "Access Type" +msgstr "Tipo de Acceso" + +#: ../../mod/pubsites.php:26 +msgid "Registration Policy" +msgstr "Normas de Registro" + +#: ../../mod/pubsites.php:26 ../../mod/profiles.php:454 +msgid "Location" +msgstr "Localización" + +#: ../../mod/pubsites.php:26 +msgid "View hub ratings" +msgstr "Ver las valoraciones del sitio" + +#: ../../mod/pubsites.php:30 +msgid "Rate" +msgstr "Valoración" + +#: ../../mod/pubsites.php:31 +msgid "View ratings" +msgstr "Ver valoraciones" + +#: ../../mod/rpost.php:131 ../../mod/editpost.php:158 +msgid "Edit post" +msgstr "Editar entrada" + +#: ../../mod/dav.php:121 +msgid "$Projectname channel" +msgstr "canal $Projectname" + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "Colección creada." + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "No se puede crear colección." + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "Colección actualizada." + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "Crear una colección de canales." + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "Nombre de la Colección:" + +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "Los miembros son visibles para otros canales" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "Colección eliminada." + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "No ha sido posible de eliminar la colección." + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "Editor de Colecciones" + +#: ../../mod/group.php:196 ../../mod/bulksetclose.php:89 +msgid "Members" +msgstr "Miembros" + +#: ../../mod/group.php:198 ../../mod/bulksetclose.php:91 +msgid "All Connected Channels" +msgstr "Todos los canales conectados" + +#: ../../mod/group.php:233 ../../mod/bulksetclose.php:126 +msgid "Click on a channel to add or remove." +msgstr "Haga clic en un canal para agregar o quitar." + +#: ../../mod/siteinfo.php:112 +#, php-format +msgid "Version %s" +msgstr "Versión %s" + +#: ../../mod/siteinfo.php:133 +msgid "Installed plugins/addons/apps:" +msgstr "Extensiones/Aplicaciones instaladas:" + +#: ../../mod/siteinfo.php:146 +msgid "No installed plugins/addons/apps" +msgstr "Extensiones/Aplicaciones no instaladas:" + +#: ../../mod/siteinfo.php:155 ../../mod/home.php:58 ../../mod/home.php:64 +msgid "$Projectname" +msgstr "$Projectname" + +#: ../../mod/siteinfo.php:156 +msgid "" +"This is a hub of $Projectname - a global cooperative network of " +"decentralized privacy enhanced websites." +msgstr "Este es un sitio integrado en $Projectname - una red cooperativa mundial de sitios web descentralizados de privacidad mejorada." + +#: ../../mod/siteinfo.php:158 +msgid "Tag: " +msgstr "Etiqueta:" + +#: ../../mod/siteinfo.php:160 +msgid "Last background fetch: " +msgstr "Última actualización en segundo plano:" + +#: ../../mod/siteinfo.php:163 +msgid "Running at web location" +msgstr "Corriendo en el sitio web" + +#: ../../mod/siteinfo.php:164 +msgid "" +"Please visit redmatrix.me to learn more" +" about $Projectname." +msgstr "Por favor, visite redmatrix.me para aprender más sobre $Projectname." + +#: ../../mod/siteinfo.php:165 +msgid "Bug reports and issues: please visit" +msgstr "Informes de errores e incidencias: por, favor visite" + +#: ../../mod/siteinfo.php:167 +msgid "$projectname issues" +msgstr "Problemas en $projectname" + +#: ../../mod/siteinfo.php:168 +msgid "" +"Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot " +"com" +msgstr "Sugerencias, elogios, etc - por favor, un correo electrónico a \"redmatrix\" en librelist - punto com" + +#: ../../mod/siteinfo.php:170 +msgid "Site Administrators" +msgstr "Administradores del sitio" + +#: ../../mod/item.php:174 +msgid "Unable to locate original post." +msgstr "No ha sido posible encontrar la entrada original." + +#: ../../mod/item.php:440 +msgid "Empty post discarded." +msgstr "Desechada entrada vacía." + +#: ../../mod/item.php:480 +msgid "Executable content type not permitted to this channel." +msgstr "Contenido de tipo ejecutable no permitido en este canal." + +#: ../../mod/item.php:901 +msgid "System error. Post not saved." +msgstr "Error del sistema. Entrada no salvada." + +#: ../../mod/item.php:1119 +msgid "Unable to obtain post information from database." +msgstr "No ha sido posible obtener información de la entrada en la base de datos." + +#: ../../mod/item.php:1126 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "Ha alcanzado su límite de %1$.0f tope máximo de entradas" + +#: ../../mod/item.php:1133 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "Ha alcanzado su límite de %1$.0f páginas web." + +#: ../../mod/network.php:91 +msgid "No such group" +msgstr "No se encuentra el grupo" + +#: ../../mod/network.php:129 +msgid "No such channel" +msgstr "No se encuentra el canal" + +#: ../../mod/network.php:143 +msgid "Search Results For:" +msgstr "Buscar resultados para:" + +#: ../../mod/network.php:198 +msgid "Collection is empty" +msgstr "La colección está vacía" + +#: ../../mod/network.php:207 +msgid "Collection: " +msgstr "Colección:" + +#: ../../mod/network.php:226 +msgid "Connection: " +msgstr "Conexión:" + +#: ../../mod/network.php:233 +msgid "Invalid connection." +msgstr "Conexión no válida." + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "Ningún canal." + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "Conexiones comunes" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "Ninguna conexión en común." + +#: ../../mod/regdir.php:45 ../../mod/dirsearch.php:21 +msgid "This site is not a directory server" +msgstr "Este sitio no es un servidor de directorio" + +#: ../../mod/connections.php:37 ../../mod/connedit.php:75 +msgid "Could not access contact record." +msgstr "No se ha podido acceder al registro de contacto." + +#: ../../mod/connections.php:51 ../../mod/connedit.php:99 +msgid "Could not locate selected profile." +msgstr "No se ha podido localizar el perfil seleccionado." + +#: ../../mod/connections.php:94 ../../mod/connedit.php:219 +msgid "Connection updated." +msgstr "Conexión actualizada." + +#: ../../mod/connections.php:96 ../../mod/connedit.php:221 +msgid "Failed to update connection record." +msgstr "Error al actualizar el registro de la conexión." + +#: ../../mod/connections.php:192 ../../mod/connections.php:293 +msgid "Blocked" +msgstr "Bloqueados" + +#: ../../mod/connections.php:197 ../../mod/connections.php:300 +msgid "Ignored" +msgstr "Ignorados" + +#: ../../mod/connections.php:202 ../../mod/connections.php:314 +msgid "Hidden" +msgstr "Ocultos" + +#: ../../mod/connections.php:207 ../../mod/connections.php:307 +msgid "Archived" +msgstr "Archivados" + +#: ../../mod/connections.php:271 +msgid "Suggest new connections" +msgstr "Sugerir nuevas conexiones" + +#: ../../mod/connections.php:274 +msgid "New Connections" +msgstr "Nuevas conexiones" + +#: ../../mod/connections.php:277 +msgid "Show pending (new) connections" +msgstr "Mostrar conexiones (nuevas) pendientes" + +#: ../../mod/connections.php:280 ../../mod/profperm.php:139 +msgid "All Connections" +msgstr "Todas las conexiones" + +#: ../../mod/connections.php:283 +msgid "Show all connections" +msgstr "Mostrar todas las conexiones" + +#: ../../mod/connections.php:286 +msgid "Unblocked" +msgstr "Desbloqueados" + +#: ../../mod/connections.php:289 +msgid "Only show unblocked connections" +msgstr "Mostrar solo las conexiones desbloqueadas" + +#: ../../mod/connections.php:296 +msgid "Only show blocked connections" +msgstr "Mostrar solo las conexiones bloqueadas" + +#: ../../mod/connections.php:303 +msgid "Only show ignored connections" +msgstr "Mostrar solo conexiones ignoradas" + +#: ../../mod/connections.php:310 +msgid "Only show archived connections" +msgstr "Mostrar solo las conexiones archivadas" + +#: ../../mod/connections.php:317 +msgid "Only show hidden connections" +msgstr "Mostrar solo las conexiones ocultas" + +#: ../../mod/connections.php:372 +#, php-format +msgid "%1$s [%2$s]" +msgstr "%1$s [%2$s]" + +#: ../../mod/connections.php:373 +msgid "Edit connection" +msgstr "Editar conexión" + +#: ../../mod/connections.php:411 +msgid "Search your connections" +msgstr "Buscar sus conexiones" + +#: ../../mod/connections.php:412 +msgid "Finding: " +msgstr "Encontrado:" + +#: ../../mod/blocks.php:95 ../../mod/blocks.php:148 +msgid "Block Name" +msgstr "Nombre del bloque" + +#: ../../mod/blocks.php:149 +msgid "Block Title" +msgstr "Título del bloque" + +#: ../../mod/editpost.php:20 ../../mod/editlayout.php:76 +#: ../../mod/editwebpage.php:77 ../../mod/editblock.php:78 +#: ../../mod/editblock.php:94 +msgid "Item not found" +msgstr "Elemento no encontrado" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "El elemento no es editable" + +#: ../../mod/editpost.php:48 +msgid "Delete item?" +msgstr "¿Borrar el elemento?" + +#: ../../mod/editpost.php:115 ../../mod/editlayout.php:142 +#: ../../mod/editwebpage.php:187 ../../mod/editblock.php:144 +msgid "Insert YouTube video" +msgstr "Insertar vídeo de YouTube" + +#: ../../mod/editpost.php:116 ../../mod/editlayout.php:143 +#: ../../mod/editwebpage.php:188 ../../mod/editblock.php:145 +msgid "Insert Vorbis [.ogg] video" +msgstr "Insertar vídeo Vorbis [.ogg]" + +#: ../../mod/editpost.php:117 ../../mod/editlayout.php:144 +#: ../../mod/editwebpage.php:189 ../../mod/editblock.php:146 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Insertar audio Vorbis [.ogg]" + +#: ../../mod/cloud.php:120 +msgid "$Projectname - Guests: Username: {your email address}, Password: +++" +msgstr "$Projectname - Invitados: Nombre de usuario: {su dirección de correo electrónico}, Contraseña: +++" + +#: ../../mod/photos.php:78 +msgid "Page owner information could not be retrieved." +msgstr "La información del propietario de la página no pudo ser recuperada." + +#: ../../mod/photos.php:98 +msgid "Album not found." +msgstr "Ãlbum no encontrado." + +#: ../../mod/photos.php:120 ../../mod/photos.php:655 +msgid "Delete Album" +msgstr "Borrar álbum" + +#: ../../mod/photos.php:160 ../../mod/photos.php:942 +msgid "Delete Photo" +msgstr "Borrar foto" + +#: ../../mod/photos.php:452 +msgid "No photos selected" +msgstr "No hay fotos seleccionadas" + +#: ../../mod/photos.php:496 +msgid "Access to this item is restricted." +msgstr "El acceso a este elemento está restringido." + +#: ../../mod/photos.php:535 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgstr "%1$.2f MB de %2$.2f MB de almacenamiento de fotos utilizado." + +#: ../../mod/photos.php:538 +#, php-format +msgid "%1$.2f MB photo storage used." +msgstr "%1$.2f MB de almacenamiento de fotos utilizado." + +#: ../../mod/photos.php:562 +msgid "Upload Photos" +msgstr "Subir fotos" + +#: ../../mod/photos.php:566 ../../mod/photos.php:648 ../../mod/photos.php:927 +msgid "Enter a new album name" +msgstr "Introducir un nuevo nombre de álbum" + +#: ../../mod/photos.php:567 ../../mod/photos.php:649 ../../mod/photos.php:928 +msgid "or select an existing one (doubleclick)" +msgstr "o seleccionar uno (Double click) existente" + +#: ../../mod/photos.php:568 +msgid "Create a status post for this upload" +msgstr "Crear una entrada de estado para esta subida" + +#: ../../mod/photos.php:596 +msgid "Album name could not be decoded" +msgstr "El nombre del álbum no ha podido ser descifrado" + +#: ../../mod/photos.php:637 ../../mod/photos.php:1169 +#: ../../mod/photos.php:1185 +msgid "Contact Photos" +msgstr "Fotos de contacto" + +#: ../../mod/photos.php:661 +msgid "Show Newest First" +msgstr "Mostrar lo más reciente primero" + +#: ../../mod/photos.php:663 +msgid "Show Oldest First" +msgstr "Mostrar lo más antiguo primero" + +#: ../../mod/photos.php:687 ../../mod/photos.php:1217 +msgid "View Photo" +msgstr "Ver foto" + +#: ../../mod/photos.php:716 +msgid "Edit Album" +msgstr "Editar álbum" + +#: ../../mod/photos.php:761 +msgid "Permission denied. Access to this item may be restricted." +msgstr "Permiso denegado. El acceso a este elemento puede estar restringido." + +#: ../../mod/photos.php:763 +msgid "Photo not available" +msgstr "Foto no disponible" + +#: ../../mod/photos.php:821 +msgid "Use as profile photo" +msgstr "Usar como foto de perfil" + +#: ../../mod/photos.php:828 +msgid "Private Photo" +msgstr "Foto privada" + +#: ../../mod/photos.php:843 +msgid "View Full Size" +msgstr "Ver tamaño completo" + +#: ../../mod/photos.php:921 +msgid "Edit photo" +msgstr "Editar foto" + +#: ../../mod/photos.php:923 +msgid "Rotate CW (right)" +msgstr "Girar CW (a la derecha)" + +#: ../../mod/photos.php:924 +msgid "Rotate CCW (left)" +msgstr "Girar CCW (a la izquierda)" + +#: ../../mod/photos.php:931 +msgid "Caption" +msgstr "Título" + +#: ../../mod/photos.php:933 +msgid "Add a Tag" +msgstr "Añadir una etiqueta" + +#: ../../mod/photos.php:937 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +msgstr "Ejemplo: @bob, @Barbara_Jensen, @jim@example.com" + +#: ../../mod/photos.php:940 +msgid "Flag as adult in album view" +msgstr "Marcar como \"solo para adultos\" en el álbum" + +#: ../../mod/photos.php:1132 +msgid "In This Photo:" +msgstr "En esta foto:" + +#: ../../mod/photos.php:1137 +msgid "Map" +msgstr "Mapa" + +#: ../../mod/photos.php:1223 +msgid "View Album" +msgstr "Ver álbum" + +#: ../../mod/photos.php:1246 +msgid "Recent Photos" +msgstr "Fotos recientes" + +#: ../../mod/search.php:206 +#, php-format +msgid "Items tagged with: %s" +msgstr "elementos etiquetados con: %s" + +#: ../../mod/search.php:208 +#, php-format +msgid "Search results for: %s" +msgstr "Resultados de la búsqueda para: %s" + +#: ../../mod/match.php:22 +msgid "Profile Match" +msgstr "Perfil compatible" + +#: ../../mod/match.php:31 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "No hay palabras clave en el perfil principal para poder encontrar perfiles compatibles. Por favor, añada palabras clave a su perfil principal." + +#: ../../mod/match.php:63 +msgid "is interested in:" +msgstr "está interesado en:" + +#: ../../mod/match.php:70 +msgid "No matches" +msgstr "No se han encontrado perfiles compatibles" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "Ausente" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "Conectado" + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "Seleccionar una carpeta de marcadores" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "Guardar marcador" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "URL del marcador" + +#: ../../mod/rbmark.php:95 ../../mod/appman.php:93 +msgid "Description" +msgstr "Descripción" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "O introduzca un nuevo nombre para la carpeta de marcadores" + +#: ../../mod/notify.php:53 ../../mod/notifications.php:94 +msgid "No more system notifications." +msgstr "No hay más notificaciones del sistema" + +#: ../../mod/notify.php:57 ../../mod/notifications.php:98 +msgid "System Notifications" +msgstr "Notificaciones de sistema" + +#: ../../mod/acl.php:231 +msgid "network" +msgstr "red" + +#: ../../mod/acl.php:241 +msgid "RSS" +msgstr "RSS" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "Diseño actualizado" + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "Editor del Sistema de Descripción de Páginas" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "Diseño no encontrado" + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "Nombre del módulo:" + +#: ../../mod/pdledit.php:55 +msgid "Layout Help" +msgstr "Ayuda para el diseño de la página" + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "-seleccionar-" + +#: ../../mod/import.php:25 +#, php-format +msgid "Your service plan only allows %d channels." +msgstr "Su paquete de servicios solo permite %d canales." + +#: ../../mod/import.php:60 +msgid "Nothing to import." +msgstr "No hay nada para importar." + +#: ../../mod/import.php:84 +msgid "Unable to download data from old server" +msgstr "No se han podido descargar datos de su antiguo servidor" + +#: ../../mod/import.php:90 +msgid "Imported file is empty." +msgstr "El fichero importado está vacío." + +#: ../../mod/import.php:110 +msgid "The data provided is not compatible with this project." +msgstr "Los datos proporcionados no son compatibles con este proyecto." + +#: ../../mod/import.php:115 +#, php-format +msgid "Warning: Database versions differ by %1$d updates." +msgstr "Atención: Las versiones de la base de datos difieren en %1$d actualizaciones." + +#: ../../mod/import.php:135 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "No se ha podido crear el canal porque el identificador del canal no se ha podido duplicar en este servidor." + +#: ../../mod/import.php:176 +msgid "Channel clone failed. Import failed." +msgstr "No se ha podido importar el canal porque el canal no se ha podido clonar." + +#: ../../mod/import.php:186 +msgid "Cloned channel not found. Import failed." +msgstr "No se ha podido importar el canal porque el canal clonado no se ha encontrado." + +#: ../../mod/import.php:542 +msgid "You must be logged in to use this feature." +msgstr "Debe estar registrado para poder usar esta funcionalidad." + +#: ../../mod/import.php:547 +msgid "Import Channel" +msgstr "Importar canal" + +#: ../../mod/import.php:548 +msgid "" +"Use this form to import an existing channel from a different server/hub. You" +" may retrieve the channel identity from the old server/hub via the network " +"or provide an export file." +msgstr "Emplee este formulario para importar un canal desde un servidor/hub diferente. Puede recuperar el canal desde el antiguo servidor/hub a través de la red o proporcionando un fichero de exportación." + +#: ../../mod/import.php:549 +msgid "File to Upload" +msgstr "Fichero para subir" + +#: ../../mod/import.php:550 +msgid "Or provide the old server/hub details" +msgstr "O proporcione los detalles de su antiguo servidor/hub" + +#: ../../mod/import.php:551 +msgid "Your old identity address (xyz@example.com)" +msgstr "Su identidad en el antiguo servidor (canal@ejemplo.com)" + +#: ../../mod/import.php:552 +msgid "Your old login email address" +msgstr "Su antigua dirección de correo electrónico" + +#: ../../mod/import.php:553 +msgid "Your old login password" +msgstr "Su antigua contraseña" + +#: ../../mod/import.php:554 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be" +" able to post from either location, but only one can be marked as the " +"primary location for files, photos, and media." +msgstr "Para cualquiera de las opciones, elija si hacer de este servidor su nueva dirección primaria, o si su antigua ubicación debe continuar con este papel. Usted podrá publicar desde cualquier ubicación, pero sólo una puede estar marcada como la ubicación principal para los ficheros, fotos y otras imágenes o vídeos." + +#: ../../mod/import.php:555 +msgid "Make this hub my primary location" +msgstr "Convertir este servidor en mi ubicación primaria" + +#: ../../mod/import.php:556 +msgid "" +"Import existing posts if possible (experimental - limited by available " +"memory" +msgstr "Importar el contenido publicado si es posible (experimental - limitado por la memoria disponible" + +#: ../../mod/import.php:557 +msgid "" +"This process may take several minutes to complete. Please submit the form " +"only once and leave this page open until finished." +msgstr "Este proceso puede tardar varios minutos en completarse. Por favor envíe el formulario una sola vez y mantenga esta página abierta hasta que termine." + +#: ../../mod/editlayout.php:111 +msgid "Delete layout?" +msgstr "¿Borrar formato?" + +#: ../../mod/editlayout.php:158 ../../mod/layouts.php:124 +msgid "Layout Description (Optional)" +msgstr "Descripción del diseño (opcional)" + +#: ../../mod/editlayout.php:160 ../../mod/layouts.php:121 +#: ../../mod/layouts.php:179 +msgid "Layout Name" +msgstr "Nombre del diseño" + +#: ../../mod/editlayout.php:177 +msgid "Edit Layout" +msgstr "Editar diseño" + +#: ../../mod/chat.php:19 ../../mod/channel.php:25 +msgid "You must be logged in to see this page." +msgstr "Debe estar registrado para poder ver esta página." + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "Sala no encontrada" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "Abandonar sala" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "Eliminar esta sala" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "Estoy ausente momentáneamente" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "Estoy conectado" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "Añadir esta sala a Marcadores" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "Nueva sala de chat" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "Nombre de sala de chat" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "Sala de chat de %1$s" + +#: ../../mod/mitem.php:24 ../../mod/menu.php:134 +msgid "Menu not found." +msgstr "Menú no encontrado" + +#: ../../mod/mitem.php:48 +msgid "Unable to create element." +msgstr "Imposible crear el elemento." + +#: ../../mod/mitem.php:71 +msgid "Unable to update menu element." +msgstr "No es posible actualizar el elemento del menú." + +#: ../../mod/mitem.php:86 +msgid "Unable to add menu element." +msgstr "No es posible añadir el elemento al menú" + +#: ../../mod/mitem.php:152 ../../mod/mitem.php:223 +msgid "Menu Item Permissions" +msgstr "Permisos del elemento del menú" + +#: ../../mod/mitem.php:153 ../../mod/mitem.php:224 ../../mod/settings.php:1083 +msgid "(click to open/close)" +msgstr "(pulsa para abrir/cerrar)" + +#: ../../mod/mitem.php:155 ../../mod/mitem.php:171 +msgid "Link Name" +msgstr "Nombre del enlace" + +#: ../../mod/mitem.php:156 ../../mod/mitem.php:228 +msgid "Link or Submenu Target" +msgstr "Destino del enlace o submenú" + +#: ../../mod/mitem.php:156 +msgid "Enter URL of the link or select a menu name to create a submenu" +msgstr "Introduzca la dirección del enlace o seleccione el nombre de un submenú" + +#: ../../mod/mitem.php:157 ../../mod/mitem.php:229 +msgid "Use magic-auth if available" +msgstr "Use la autenticación mágica si está disponible" + +#: ../../mod/mitem.php:158 ../../mod/mitem.php:230 +msgid "Open link in new window" +msgstr "Abrir el enlace en una nueva ventana" + +#: ../../mod/mitem.php:159 ../../mod/mitem.php:231 +msgid "Order in list" +msgstr "Orden en la lista" + +#: ../../mod/mitem.php:159 ../../mod/mitem.php:231 +msgid "Higher numbers will sink to bottom of listing" +msgstr "Los números más altos irán al final de la lista" + +#: ../../mod/mitem.php:160 +msgid "Submit and finish" +msgstr "Enviar y terminar" + +#: ../../mod/mitem.php:161 +msgid "Submit and continue" +msgstr "Enviar y continuar" + +#: ../../mod/mitem.php:169 +msgid "Menu:" +msgstr "Menú:" + +#: ../../mod/mitem.php:172 +msgid "Link Target" +msgstr "Destino del enlace" + +#: ../../mod/mitem.php:175 +msgid "Edit menu" +msgstr "Editar menú" + +#: ../../mod/mitem.php:178 +msgid "Edit element" +msgstr "Editar elemento" + +#: ../../mod/mitem.php:179 +msgid "Drop element" +msgstr "Eliminar el elemento" + +#: ../../mod/mitem.php:180 +msgid "New element" +msgstr "Nuevo elemento" + +#: ../../mod/mitem.php:181 +msgid "Edit this menu container" +msgstr "Modificar el contenedor del menú" + +#: ../../mod/mitem.php:182 +msgid "Add menu element" +msgstr "Añadir un elemento al menú" + +#: ../../mod/mitem.php:183 +msgid "Delete this menu item" +msgstr "Eliminar este elemento del menú" + +#: ../../mod/mitem.php:184 +msgid "Edit this menu item" +msgstr "Modificar este elemento del menú" + +#: ../../mod/mitem.php:201 +msgid "Menu item not found." +msgstr "Este elemento del menú no se ha encontrado" + +#: ../../mod/mitem.php:212 +msgid "Menu item deleted." +msgstr "Este elemento del menú ha sido borrado" + +#: ../../mod/mitem.php:214 +msgid "Menu item could not be deleted." +msgstr "Este elemento del menú no puede ser borrada." + +#: ../../mod/mitem.php:221 +msgid "Edit Menu Element" +msgstr "Editar elemento del menú" + +#: ../../mod/mitem.php:227 +msgid "Link text" +msgstr "Texto del enlace" + +#: ../../mod/editwebpage.php:152 +msgid "Delete webpage?" +msgstr "¿Eliminar página web?" + +#: ../../mod/editwebpage.php:173 +msgid "Page link title" +msgstr "Título del enlace de la página" + +#: ../../mod/editwebpage.php:224 +msgid "Edit Webpage" +msgstr "Editar página web" + +#: ../../mod/dirsearch.php:29 +msgid "This directory server requires an access token" +msgstr "El servidor de este directorio necesita un \"token\" de acceso" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "No se ha encontrado una cuenta válida." + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "Se ha recibido una solicitud de restablecimiento de contraseña. Consulte su correo electrónico." + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "Usuario del sitio (%s)" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "Se ha solicitado restablecer la contraseña en %s" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "La solicitud no ha podido ser verificada. (Puede que la haya enviado con anterioridad) El restablecimiento de la contraseña ha fallado." + +#: ../../mod/lostpass.php:85 ../../boot.php:1559 +msgid "Password Reset" +msgstr "Restablecer la contraseña" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "Su contraseña ha sido restablecida según lo solicitó." + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "Su nueva contraseña es" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "Guarde o copie su nueva contraseña - y después" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "Pulse aquí para conectarse" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Puede cambiar la contraseña en la página Configuraciones una vez iniciada la sesión." + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "Su contraseña en %s ha sido cambiada" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "¿Ha olvidado su contraseña?" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Introduzca y envíe su dirección de correo electrónico para que el restablecimiento de su contraseña. Luego revise su correo para obtener más instrucciones." + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "Dirección de correo electrónico" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "Reiniciar" + +#: ../../mod/rate.php:157 +msgid "Website:" +msgstr "Sitio web:" + +#: ../../mod/rate.php:160 +#, php-format +msgid "Remote Channel [%s] (not yet known on this site)" +msgstr "Canal remoto [%s] (aún no es conocido en este sitio)" + +#: ../../mod/rate.php:161 +msgid "Rating (this information is public)" +msgstr "Valoración (esta información es pública)" + +#: ../../mod/rate.php:162 +msgid "Optionally explain your rating (this information is public)" +msgstr "Opcionalmente puede explicar su valoración (esta información es pública)" + +#: ../../mod/editblock.php:117 +msgid "Delete block?" +msgstr "¿Borrar este bloque?" + +#: ../../mod/editblock.php:179 +msgid "Edit Block" +msgstr "Modificar este bloque" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "Se ha superado el límite máximo de invitaciones." + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s : No es una dirección de correo electrónico válida. " + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "Únase a nosotros en RedMatrix" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Excedido el límite de invitaciones. Por favor, contacte con el Administrador de su sitio." + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : Falló la entrega del mensaje." + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d mensajes enviados." +msgstr[1] "%d mensajes enviados." + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "No tiene más invitaciones disponibles" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "Enviar invitaciones" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "Introduzca las direcciones de correo electrónica, una por línea:" + +#: ../../mod/invite.php:131 ../../mod/mail.php:235 ../../mod/mail.php:348 +msgid "Your message:" +msgstr "Su mensaje:" + +#: ../../mod/invite.php:132 +msgid "Please join my community on $Projectname." +msgstr "Por favor, únase a mi comunidad en $Projectname." + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "Debe proporcionar este código de invitación:" + +#: ../../mod/invite.php:135 +msgid "" +"1. Register at any $Projectname location (they are all inter-connected)" +msgstr "1. Regístrese en cualquier lugar del $Projectname (están todos interconectados)" + +#: ../../mod/invite.php:137 +msgid "2. Enter my $Projectname network address into the site searchbar." +msgstr "2. Introduzca mi dirección $Projectname en la caja de búsqueda del sitio." + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "o visite" + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "3. Pulse [conectar]" + +#: ../../mod/locs.php:21 ../../mod/locs.php:52 +msgid "Location not found." +msgstr "Localización no encontrada." + +#: ../../mod/locs.php:56 +msgid "Primary location cannot be removed." +msgstr "La localización primaria no puede ser eliminada." + +#: ../../mod/locs.php:88 +msgid "No locations found." +msgstr "Ninguna localización encontrada." + +#: ../../mod/locs.php:101 +msgid "Manage Channel Locations" +msgstr "Gestionar localizaciones del canal" + +#: ../../mod/locs.php:102 +msgid "Location (address)" +msgstr "Localización (dirección)" + +#: ../../mod/locs.php:103 +msgid "Primary Location" +msgstr "Localización primaria" + +#: ../../mod/locs.php:104 +msgid "Drop location" +msgstr "Eliminar localización" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "Imposible crear la fuente. Ningún canal ha sido seleccionado." + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "Fuente creada." + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "Fuente actualizada." + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "*" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "Gestionar contenido de origen remoto para su canal." + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "Nueva fuente" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "Importar todo el contenido o una selección de los siguientes canales en este canal, y distribuirlo de acuerdo con los ajustes de su canal." + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "Importar solo contenido que contenga estas palabras (una por línea)" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "Dejar en blanco para importar todo el contenido público" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:112 +msgid "Channel Name" +msgstr "Nombre del canal" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "Fuente no encontrada" + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "Editar fuente" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "Eliminar fuente" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "Fuente eliminada" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "Imposible eliminar la fuente." + +#: ../../mod/menu.php:44 +msgid "Unable to update menu." +msgstr "No se puede actualizar el menú." + +#: ../../mod/menu.php:53 +msgid "Unable to create menu." +msgstr "No se puede crear el menú." + +#: ../../mod/menu.php:89 ../../mod/menu.php:101 +msgid "Menu Name" +msgstr "Nombre del menú" + +#: ../../mod/menu.php:89 +msgid "Unique name (not visible on webpage) - required" +msgstr "Nombre único (no será visible en la página web) - requerido" + +#: ../../mod/menu.php:90 ../../mod/menu.php:102 +msgid "Menu Title" +msgstr "Título del menú" + +#: ../../mod/menu.php:90 +msgid "Visible on webpage - leave empty for no title" +msgstr "Visible en la página web - no ponga nada si no desea un título" + +#: ../../mod/menu.php:91 +msgid "Allow Bookmarks" +msgstr "Permitir marcadores" + +#: ../../mod/menu.php:91 ../../mod/menu.php:147 +msgid "Menu may be used to store saved bookmarks" +msgstr "El menú se puede usar para guardar marcadores" + +#: ../../mod/menu.php:92 ../../mod/menu.php:149 +msgid "Submit and proceed" +msgstr "Enviar y proceder" + +#: ../../mod/menu.php:104 +msgid "Drop" +msgstr "Eliminar" + +#: ../../mod/menu.php:108 +msgid "Bookmarks allowed" +msgstr "Marcadores permitidos" + +#: ../../mod/menu.php:110 +msgid "Delete this menu" +msgstr "Borrar este menú" + +#: ../../mod/menu.php:111 ../../mod/menu.php:144 +msgid "Edit menu contents" +msgstr "Editar los contenidos del menú" + +#: ../../mod/menu.php:112 +msgid "Edit this menu" +msgstr "Modificar este menú" + +#: ../../mod/menu.php:126 +msgid "Menu could not be deleted." +msgstr "El menú no puede ser eliminado." + +#: ../../mod/menu.php:139 +msgid "Edit Menu" +msgstr "Modificar el menú" + +#: ../../mod/menu.php:143 +msgid "Add or remove entries to this menu" +msgstr "Añadir o quitar entradas en este menú" + +#: ../../mod/menu.php:145 +msgid "Menu name" +msgstr "Nombre del menú" + +#: ../../mod/menu.php:145 +msgid "Must be unique, only seen by you" +msgstr "Debe ser único, solo será visible para usted" + +#: ../../mod/menu.php:146 +msgid "Menu title" +msgstr "Título del menú" + +#: ../../mod/menu.php:146 +msgid "Menu title as seen by others" +msgstr "El título del menú tal como será visto por los demás" + +#: ../../mod/menu.php:147 +msgid "Allow bookmarks" +msgstr "Permitir marcadores" + +#: ../../mod/filestorage.php:82 +msgid "Permission Denied." +msgstr "Permiso denegado" + +#: ../../mod/filestorage.php:98 +msgid "File not found." +msgstr "Fichero no encontrado." + +#: ../../mod/filestorage.php:141 +msgid "Edit file permissions" +msgstr "Modificar los permisos del fichero" + +#: ../../mod/filestorage.php:150 +msgid "Set/edit permissions" +msgstr "Establecer/editar los permisos" + +#: ../../mod/filestorage.php:151 +msgid "Include all files and sub folders" +msgstr "Incluir todos los ficheros y subcarpetas" + +#: ../../mod/filestorage.php:152 +msgid "Return to file list" +msgstr "Volver a la lista de ficheros" + +#: ../../mod/filestorage.php:154 +msgid "Copy/paste this code to attach file to a post" +msgstr "Copiar/pegar este código para adjuntar el fichero al envío" + +#: ../../mod/filestorage.php:155 +msgid "Copy/paste this URL to link file from a web page" +msgstr "Copiar/pegar esta dirección para enlazar el fichero desde una página web" + +#: ../../mod/filestorage.php:157 +msgid "Share this file" +msgstr "Compartir este fichero" + +#: ../../mod/filestorage.php:158 +msgid "Show URL to this file" +msgstr "Mostrar la dirección de este fichero" + +#: ../../mod/filestorage.php:159 +msgid "Notify your contacts about this file" +msgstr "Avisar a sus contactos de este fichero" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "Contacto no encontrado" + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Enviar sugerencia a un amigo." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Sugerir amigos" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Sugerir un amigo a %s" + +#: ../../mod/magic.php:69 +msgid "Hub not found." +msgstr "Servidor no encontrado" + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "Dar un toque/Incitar" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "dar un toque, incitar u otras cosas a alguien" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "Destinatario" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "Elegir qué desea enviar al destinatario" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "Convertir en privado este envío" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "Identificador de perfil no válido" + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "Editor de visibilidad el perfil" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "Pulsar en un contacto para añadir o eliminar." + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "Visible para" + +#: ../../mod/impel.php:191 +#, php-format +msgid "%s element installed" +msgstr "%s elemento instalado" + +#: ../../mod/impel.php:194 +#, php-format +msgid "%s element installation failed" +msgstr "Elemento con instalación fallida: %s" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:174 +#: ../../mod/profiles.php:231 ../../mod/profiles.php:600 +msgid "Profile not found." +msgstr "Perfil no encontrado." + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "Perfil eliminado." + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "Perfil-" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "Creado el nuevo perfil." + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "Perfil no disponible para clonar." + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "Perfil no disponible para exportar." + +#: ../../mod/profiles.php:241 +msgid "Profile Name is required." +msgstr "Se necesita el nombre del perfil." + +#: ../../mod/profiles.php:404 +msgid "Marital Status" +msgstr "Estado sentimental" + +#: ../../mod/profiles.php:408 +msgid "Romantic Partner" +msgstr "Pareja sentimental" + +#: ../../mod/profiles.php:412 +msgid "Likes" +msgstr "Me gusta" + +#: ../../mod/profiles.php:416 +msgid "Dislikes" +msgstr "No me gusta" + +#: ../../mod/profiles.php:420 +msgid "Work/Employment" +msgstr "Trabajo:" + +#: ../../mod/profiles.php:423 +msgid "Religion" +msgstr "Religión" + +#: ../../mod/profiles.php:427 +msgid "Political Views" +msgstr "Ideas políticas" + +#: ../../mod/profiles.php:431 ../../mod/id.php:33 +msgid "Gender" +msgstr "Género" + +#: ../../mod/profiles.php:435 +msgid "Sexual Preference" +msgstr "Preferencia sexual" + +#: ../../mod/profiles.php:439 +msgid "Homepage" +msgstr "Página personal" + +#: ../../mod/profiles.php:443 +msgid "Interests" +msgstr "Intereses" + +#: ../../mod/profiles.php:447 ../../mod/admin.php:994 +msgid "Address" +msgstr "Dirección" + +#: ../../mod/profiles.php:537 +msgid "Profile updated." +msgstr "Perfil actualizado." + +#: ../../mod/profiles.php:626 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "¿Ocultar su lista de contactos a los visitantes de este perfil?" + +#: ../../mod/profiles.php:666 +msgid "Edit Profile Details" +msgstr "Modificar los detalles de este perfil" + +#: ../../mod/profiles.php:668 +msgid "View this profile" +msgstr "Ver este perfil" + +#: ../../mod/profiles.php:670 +msgid "Change Profile Photo" +msgstr "Cambiar la foto del perfil" + +#: ../../mod/profiles.php:671 +msgid "Create a new profile using these settings" +msgstr "Crear un nuevo perfil usando estos ajustes" + +#: ../../mod/profiles.php:672 +msgid "Clone this profile" +msgstr "Clonar este perfil" + +#: ../../mod/profiles.php:673 +msgid "Delete this profile" +msgstr "Eliminar este perfil" + +#: ../../mod/profiles.php:675 +msgid "Import profile from file" +msgstr "Importar perfil desde un fichero" + +#: ../../mod/profiles.php:676 +msgid "Export profile to file" +msgstr "Exportar perfil a un fichero" + +#: ../../mod/profiles.php:677 +msgid "Profile Name:" +msgstr "Nombre del perfil:" + +#: ../../mod/profiles.php:678 +msgid "Your Full Name:" +msgstr "Su nombre completo:" + +#: ../../mod/profiles.php:679 +msgid "Title/Description:" +msgstr "Título/Descripción:" + +#: ../../mod/profiles.php:680 +msgid "Your Gender:" +msgstr "Su género:" + +#: ../../mod/profiles.php:681 +msgid "Birthday :" +msgstr "Cumpleaños:" + +#: ../../mod/profiles.php:682 +msgid "Street Address:" +msgstr "Calle:" + +#: ../../mod/profiles.php:683 +msgid "Locality/City:" +msgstr "Ciudad:" + +#: ../../mod/profiles.php:684 +msgid "Postal/Zip Code:" +msgstr "Código postal:" + +#: ../../mod/profiles.php:685 +msgid "Country:" +msgstr "País:" + +#: ../../mod/profiles.php:686 +msgid "Region/State:" +msgstr "Región/Estado:" + +#: ../../mod/profiles.php:687 +msgid " Marital Status:" +msgstr " Estado sentimental:" + +#: ../../mod/profiles.php:688 +msgid "Who: (if applicable)" +msgstr "Quién: (si es aplicable)" + +#: ../../mod/profiles.php:689 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Por ejemplo: cathy123, Cathy Williams, cathy@example.com" + +#: ../../mod/profiles.php:690 +msgid "Since [date]:" +msgstr "Desde [fecha]:" + +#: ../../mod/profiles.php:692 +msgid "Homepage URL:" +msgstr "Dirección de la página personal:" + +#: ../../mod/profiles.php:695 +msgid "Religious Views:" +msgstr "Creencias religiosas:" + +#: ../../mod/profiles.php:696 +msgid "Keywords:" +msgstr "Palabras clave:" + +#: ../../mod/profiles.php:699 +msgid "Example: fishing photography software" +msgstr "Por ejemplo: software de fotografía submarina" + +#: ../../mod/profiles.php:700 +msgid "Used in directory listings" +msgstr "Visible en el directorio público del canal" + +#: ../../mod/profiles.php:701 +msgid "Tell us about yourself..." +msgstr "Háblenos de usted..." + +#: ../../mod/profiles.php:702 +msgid "Hobbies/Interests" +msgstr "Aficiones/Intereses" + +#: ../../mod/profiles.php:703 +msgid "Contact information and Social Networks" +msgstr "Información de contacto y redes sociales" + +#: ../../mod/profiles.php:704 +msgid "My other channels" +msgstr "Mis otros canales" + +#: ../../mod/profiles.php:705 +msgid "Musical interests" +msgstr "Preferencias musicales" + +#: ../../mod/profiles.php:706 +msgid "Books, literature" +msgstr "Libros, literatura" + +#: ../../mod/profiles.php:707 +msgid "Television" +msgstr "Televisión" + +#: ../../mod/profiles.php:708 +msgid "Film/dance/culture/entertainment" +msgstr "Cine/danza/cultura/entretenimiento" + +#: ../../mod/profiles.php:709 +msgid "Love/romance" +msgstr "Vida sentimental/amorosa" + +#: ../../mod/profiles.php:710 +msgid "Work/employment" +msgstr "Trabajo" + +#: ../../mod/profiles.php:711 +msgid "School/education" +msgstr "Estudios" + +#: ../../mod/profiles.php:717 +msgid "This is your default profile." +msgstr "Este es su perfil principal." + +#: ../../mod/profiles.php:728 +msgid "Age: " +msgstr "Edad:" + +#: ../../mod/profiles.php:771 +msgid "Edit/Manage Profiles" +msgstr "Modificar/gestionar perfiles" + +#: ../../mod/profiles.php:772 +msgid "Add profile things" +msgstr "Añadir cosas al perfil" + +#: ../../mod/profiles.php:773 +msgid "Include desirable objects in your profile" +msgstr "Añadir objetos interesantes en su perfil" + +#: ../../mod/ratings.php:69 +msgid "No ratings" +msgstr "Ninguna valoración" + +#: ../../mod/ratings.php:99 +msgid "Ratings" +msgstr "Valoraciones" + +#: ../../mod/ratings.php:100 +msgid "Rating: " +msgstr "Valoración:" + +#: ../../mod/ratings.php:101 +msgid "Website: " +msgstr "Sitio web:" + +#: ../../mod/ratings.php:103 +msgid "Description: " +msgstr "Descripción:" + +#: ../../mod/viewsrc.php:38 +msgid "Source of Item" +msgstr "Origen del elemento" + +#: ../../mod/setup.php:187 +msgid "$Projectname Server - Setup" +msgstr "Servidor $Projectname - Instalación" + +#: ../../mod/setup.php:191 +msgid "Could not connect to database." +msgstr "No se ha podido conectar a la base de datos." + +#: ../../mod/setup.php:195 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "No se puede conectar con la dirección del sitio indicada. Podría tratarse de un problema de SSL o DNS." + +#: ../../mod/setup.php:202 +msgid "Could not create table." +msgstr "No se puede crear la tabla." + +#: ../../mod/setup.php:207 +msgid "Your site database has been installed." +msgstr "La base de datos del sitio ha sido instalada." + +#: ../../mod/setup.php:211 +msgid "" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." +msgstr "Podría tener que importar manualmente el fichero \"install/schema_xxx.sql\" usando un cliente de base de datos." + +#: ../../mod/setup.php:212 ../../mod/setup.php:280 ../../mod/setup.php:730 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "Por favor, lea el fichero \"install/INSTALL.txt\"." + +#: ../../mod/setup.php:277 +msgid "System check" +msgstr "Verificación del sistema" + +#: ../../mod/setup.php:282 +msgid "Check again" +msgstr "Verificar de nuevo" + +#: ../../mod/setup.php:304 +msgid "Database connection" +msgstr "Conexión a la base de datos" + +#: ../../mod/setup.php:305 +msgid "" +"In order to install $Projectname we need to know how to connect to your " +"database." +msgstr "Para instalar $Projectname es necesario saber cómo conectar con su base de datos." + +#: ../../mod/setup.php:306 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Por favor, contacte con el proveedor de servicios o el administrador del sitio si tiene dudas sobre estos ajustes." + +#: ../../mod/setup.php:307 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "La base de datos que especifique a continuación debe existir ya. Si no es así, por favor, créela antes de seguir." + +#: ../../mod/setup.php:311 +msgid "Database Server Name" +msgstr "Nombre del servidor de base de datos" + +#: ../../mod/setup.php:311 +msgid "Default is localhost" +msgstr "Por defecto es localhost" + +#: ../../mod/setup.php:312 +msgid "Database Port" +msgstr "Puerto de la base de datos" + +#: ../../mod/setup.php:312 +msgid "Communication port number - use 0 for default" +msgstr "Número del puerto de comunicaciones - use 0 como valor por defecto" + +#: ../../mod/setup.php:313 +msgid "Database Login Name" +msgstr "Nombre de acceso a la base de datos" + +#: ../../mod/setup.php:314 +msgid "Database Login Password" +msgstr "Contraseña de acceso a la base de datos" + +#: ../../mod/setup.php:315 +msgid "Database Name" +msgstr "Nombre de la base de datos" + +#: ../../mod/setup.php:316 +msgid "Database Type" +msgstr "Tipo de base de datos" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "Site administrator email address" +msgstr "Dirección de correo electrónico del administrador del sitio" + +#: ../../mod/setup.php:318 ../../mod/setup.php:359 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "Su cuenta deberá usar la misma dirección de correo electrónico para poder utilizar el panel de administración web." + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Website URL" +msgstr "Dirección del sitio web" + +#: ../../mod/setup.php:319 ../../mod/setup.php:361 +msgid "Please use SSL (https) URL if available." +msgstr "Por favor, use SSL (https) si está disponible." + +#: ../../mod/setup.php:321 ../../mod/setup.php:363 +msgid "Please select a default timezone for your website" +msgstr "Por favor, selecciones la zona horaria por defecto de su sitio web" + +#: ../../mod/setup.php:348 +msgid "Site settings" +msgstr "Ajustes del sitio" + +#: ../../mod/setup.php:413 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "No se puede encontrar una versión en línea de comandos de PHP en la ruta del servidor web." + +#: ../../mod/setup.php:414 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "Si no tiene instalada la versión de línea de comandos de PHP en su servidor, no podrá ejecutar votaciones en segundo plano vía cron." + +#: ../../mod/setup.php:418 +msgid "PHP executable path" +msgstr "ruta del ejecutable PHP" + +#: ../../mod/setup.php:418 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Introducir la ruta completa del ejecutable PHP. Puede dejar la línea en blanco para continuar la instalación." + +#: ../../mod/setup.php:423 +msgid "Command line PHP" +msgstr "PHP en línea de comandos" + +#: ../../mod/setup.php:432 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "La línea de comandos PHP de su sistema no tiene activado \"register_argc_argv\"." + +#: ../../mod/setup.php:433 +msgid "This is required for message delivery to work." +msgstr "Esto es necesario para que funcione la entrega de mensajes." + +#: ../../mod/setup.php:436 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/setup.php:454 +#, php-format +msgid "" +"Your max allowed total upload size is set to %s. Maximum size of one file to" +" upload is set to %s. You are allowed to upload up to %d files at once." +msgstr "La carga máxima que se le permite subir está establecida en %s. El tamaño máxima de un archivo está establecido en %s. Está permitido subir hasta un máximo de %d ficheros de una sola vez." + +#: ../../mod/setup.php:459 +msgid "You can adjust these settings in the servers php.ini." +msgstr "Puede ajustar estos valores en el fichero php.ini de su servidor." + +#: ../../mod/setup.php:461 +msgid "PHP upload limits" +msgstr "Límites PHP de subida" + +#: ../../mod/setup.php:484 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Error: La función \"openssl_pkey_new\" en este sistema no es capaz de general claves de cifrado." + +#: ../../mod/setup.php:485 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "si está en un servidor Windows, por favor, lea \"http://www.php.net/manual/en/openssl.installation.php\"." + +#: ../../mod/setup.php:488 +msgid "Generate encryption keys" +msgstr "Generar claves de cifrado" + +#: ../../mod/setup.php:500 +msgid "libCurl PHP module" +msgstr "módulo libCurl PHP" + +#: ../../mod/setup.php:501 +msgid "GD graphics PHP module" +msgstr "módulo PHP GD graphics" + +#: ../../mod/setup.php:502 +msgid "OpenSSL PHP module" +msgstr "módulo PHP OpenSSL" + +#: ../../mod/setup.php:503 +msgid "mysqli or postgres PHP module" +msgstr "módulo PHP mysqli o postgres" + +#: ../../mod/setup.php:504 +msgid "mb_string PHP module" +msgstr "módulo PHP mb_string" + +#: ../../mod/setup.php:505 +msgid "mcrypt PHP module" +msgstr "módulo PHP mcrypt " + +#: ../../mod/setup.php:506 +msgid "xml PHP module" +msgstr "módulo PHP xml" + +#: ../../mod/setup.php:510 ../../mod/setup.php:512 +msgid "Apache mod_rewrite module" +msgstr "módulo Apache mod_rewrite " + +#: ../../mod/setup.php:510 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Error: se necesita el módulo del servidor web Apache mod-rewrite pero no está instalado." + +#: ../../mod/setup.php:516 ../../mod/setup.php:519 +msgid "proc_open" +msgstr "proc_open" + +#: ../../mod/setup.php:516 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "Error: se necesita proc_open pero o no está instalado o ha sido desactivado en el fichero php.ini" + +#: ../../mod/setup.php:524 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Error: se necesita el módulo PHP libCURL pero no está instalado." + +#: ../../mod/setup.php:528 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Error: el módulo PHP GD graphics es necesario, pero no está instalado." + +#: ../../mod/setup.php:532 +msgid "Error: openssl PHP module required but not installed." +msgstr "Error: el módulo PHP openssl es necesario, pero no está instalado." + +#: ../../mod/setup.php:536 +msgid "" +"Error: mysqli or postgres PHP module required but neither are installed." +msgstr "Error: el módulo PHP mysqli o postgres es necesario pero no ninguno de los dos está instalado." + +#: ../../mod/setup.php:540 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Error: el módulo PHP mb_string es necesario, pero no está instalado." + +#: ../../mod/setup.php:544 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "Error: el módulo PHP mcrypt es necesario, pero no está instalado." + +#: ../../mod/setup.php:548 +msgid "Error: xml PHP module required for DAV but not installed." +msgstr "Error: el módulo PHP xml es necesario para DAV, pero no está instalado." + +#: ../../mod/setup.php:566 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "El instalador web no ha podido crear un fichero llamado “.htconfig.php†en la carpeta base de su servidor." + +#: ../../mod/setup.php:567 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Esto está generalmente ligado a un problema de permisos, a causa del cual el servidor web tiene prohibido modificar ficheros en su carpeta - incluso si usted mismo tiene esos permisos." + +#: ../../mod/setup.php:568 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "Al término de este procedimiento, podemos crear un fichero de texto para guardar con el nombre .htconfig.php en el directorio raíz de su instalación de Red." + +#: ../../mod/setup.php:569 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "Como alternativa, puede dejar este procedimiento e intentar realizar una instalación manual. Lea, por favor, el fichero\"install/INSTALL.txt\" para las instrucciones." + +#: ../../mod/setup.php:572 +msgid ".htconfig.php is writable" +msgstr ".htconfig.php tiene permisos de escritura" + +#: ../../mod/setup.php:586 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "Red hace uso del motor de plantillas Smarty3 para diseñar sus plantillas gráficas. Smarty3 es más rápido porque compila las plantillas de páginas directamente en PHP." + +#: ../../mod/setup.php:587 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "Para poder guardar las plantillas compiladas, el servidor web necesita permisos para acceder al subdirectorio %s en el directorio de instalación de Red." + +#: ../../mod/setup.php:588 ../../mod/setup.php:609 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "Por favor, asegúrese de que el servidor web está siendo ejecutado por un usuario que tenga permisos de escritura sobre esta carpeta (por ejemplo, www-data)." + +#: ../../mod/setup.php:589 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "Nota: como medida de seguridad, debe dar al servidor web permisos de escritura solo sobre %s -no al fichero de plantilla (.tpl) que contiene." + +#: ../../mod/setup.php:592 +#, php-format +msgid "%s is writable" +msgstr "%s tiene permisos de escritura" + +#: ../../mod/setup.php:608 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to" +" have write access to the store directory under the Red top level folder" +msgstr "Red guarda los ficheros descargados en la carpeta \"store\". El servidor web necesita tener permisos de escritura sobre esa carpeta, en el directorio de instalación." + +#: ../../mod/setup.php:612 +msgid "store is writable" +msgstr "\"store\" tiene permisos de escritura" + +#: ../../mod/setup.php:645 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access" +" to this site." +msgstr "El certificado SSL no ha podido ser validado. Corrija este problema o desactive el acceso https a este sitio." + +#: ../../mod/setup.php:646 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "Si su servidor soporta conexiones cifradas SSL o si permite conexiones al puerto TCP 443 (el puerto usado por el protocolo https), debe utilizar un certificado válido. No debe usar un certificado firmado por usted mismo." + +#: ../../mod/setup.php:647 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "Se ha incorporado esta restricción para evitar que sus publicaciones públicas hagan referencia a imágenes en su propio servidor." + +#: ../../mod/setup.php:648 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "Si su certificado no ha sido reconocido, los miembros de otros sitios (con certificados válidos) recibirán mensajes de aviso en sus propios sitios web." + +#: ../../mod/setup.php:649 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "Por razones de compatibilidad (sobre el conjunto de la red, no solo sobre su propio sitio), debemos insistir en estos requisitos." + +#: ../../mod/setup.php:650 +msgid "" +"Providers are available that issue free certificates which are browser-" +"valid." +msgstr "Existen varias Autoridades de Certificación que le pueden proporcionar certificados válidos." + +#: ../../mod/setup.php:652 +msgid "SSL certificate validation" +msgstr "validación del certificado SSL" + +#: ../../mod/setup.php:658 +msgid "" +"Url rewrite in .htaccess is not working. Check your server " +"configuration.Test: " +msgstr "No se pueden reescribir las direcciones web en .htaccess. Compruebe la configuración de su servidor:" + +#: ../../mod/setup.php:661 +msgid "Url rewrite is working" +msgstr "Se puede reescribir la dirección en .htaccess" + +#: ../../mod/setup.php:670 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "El fichero de configuración de la base de datos .htconfig.php no se ha podido modificar. Por favor, copie el texto generado en un fichero con ese nombre en el directorio raíz de su servidor." + +#: ../../mod/setup.php:694 +msgid "Errors encountered creating database tables." +msgstr "Se han encontrado errores al crear las tablas de la base de datos." + +#: ../../mod/setup.php:728 +msgid "

    What next

    " +msgstr "

    Siguiente paso

    " + +#: ../../mod/setup.php:729 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "IMPORTANTE: Debe crear [manualmente] una tarea programada para las actualizaciones." + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "Error del protocolo OpenID. Ningún ID recibido como respuesta." + +#: ../../mod/openid.php:72 ../../mod/openid.php:180 ../../mod/post.php:286 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "Bienvenido %s. La identificación desde su servidor se ha llevado a cabo correctamente." + +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s ha etiquetado el %3$s de %2$s con %4$s" + +#: ../../mod/uexport.php:41 ../../mod/uexport.php:42 +msgid "Export Channel" +msgstr "Exportar el canal" + +#: ../../mod/uexport.php:43 +msgid "" +"Export your basic channel information to a small file. This acts as a " +"backup of your connections, permissions, profile and basic data, which can " +"be used to import your data to a new hub, but\tdoes not contain your " +"content." +msgstr "Exportar la base de datos de su canal a un pequeño fichero. Este podrá servir como una copia de seguridad de sus conexiones, permisos, perfil y datos básicos, que podrá importar a un nuevo canal, pero sin sus contenidos." + +#: ../../mod/uexport.php:44 +msgid "Export Content" +msgstr "Exportar contenidos" + +#: ../../mod/uexport.php:45 +msgid "" +"Export your channel information and all the content to a JSON backup. This " +"backs up all of your connections, permissions, profile data and all of your " +"content, but is generally not suitable for importing a channel to a new hub " +"as this file may be VERY large. Please be patient - it may take several " +"minutes for this download to begin." +msgstr "Exportar toda la información del canal y todo su contenido a un fichero JSON. Este contendrá todas sus conexiones, permisos, información del perfil y todo su contenido, Sin embargo, a menudo, no será una buena solución para importarlo en una nueva instancia, pues el fichero será MUY voluminoso. Por favor, tenga paciencia - pueden pasar muchos minutos antes de comience la carga." + +#: ../../mod/viewconnections.php:62 +msgid "No connections." +msgstr "No hay conexiones." + +#: ../../mod/viewconnections.php:75 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Visitar el perfil de %s [%s]" + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "La firma recibida no es válida" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "Ajustes del tema actualizados." + +#: ../../mod/admin.php:93 ../../mod/admin.php:452 +msgid "Site" +msgstr "Sitio" + +#: ../../mod/admin.php:94 +msgid "Accounts" +msgstr "Cuentas" + +#: ../../mod/admin.php:95 ../../mod/admin.php:985 +msgid "Channels" +msgstr "Canales" + +#: ../../mod/admin.php:96 ../../mod/admin.php:1077 ../../mod/admin.php:1117 +msgid "Plugins" +msgstr "Plugins" + +#: ../../mod/admin.php:97 ../../mod/admin.php:1277 ../../mod/admin.php:1311 +msgid "Themes" +msgstr "Temas" + +#: ../../mod/admin.php:98 +msgid "Inspect queue" +msgstr "Examinar la cola" + +#: ../../mod/admin.php:100 +msgid "Profile Config" +msgstr "Ajustes del perfil" + +#: ../../mod/admin.php:101 +msgid "DB updates" +msgstr "Actualizaciones de la base de datos" + +#: ../../mod/admin.php:115 ../../mod/admin.php:122 ../../mod/admin.php:1396 +msgid "Logs" +msgstr "Informes" + +#: ../../mod/admin.php:121 +msgid "Plugin Features" +msgstr "Ajustes del plugin" + +#: ../../mod/admin.php:123 +msgid "User registrations waiting for confirmation" +msgstr "Registro de usuarios pendientes de confirmación" + +#: ../../mod/admin.php:200 +msgid "# Accounts" +msgstr "# Cuentas" + +#: ../../mod/admin.php:201 +msgid "# blocked accounts" +msgstr "# cuentas bloqueadas" + +#: ../../mod/admin.php:202 +msgid "# expired accounts" +msgstr "# cuentas expiradas" + +#: ../../mod/admin.php:203 +msgid "# expiring accounts" +msgstr "# cuentas expiradas" + +#: ../../mod/admin.php:216 +msgid "# Channels" +msgstr "# Canales" + +#: ../../mod/admin.php:217 +msgid "# primary" +msgstr "# primario" + +#: ../../mod/admin.php:218 +msgid "# clones" +msgstr "# clones" + +#: ../../mod/admin.php:224 +msgid "Message queues" +msgstr "Mensajes en cola" + +#: ../../mod/admin.php:240 ../../mod/admin.php:451 ../../mod/admin.php:548 +#: ../../mod/admin.php:817 ../../mod/admin.php:984 ../../mod/admin.php:1076 +#: ../../mod/admin.php:1116 ../../mod/admin.php:1276 ../../mod/admin.php:1310 +#: ../../mod/admin.php:1395 +msgid "Administration" +msgstr "Administración" + +#: ../../mod/admin.php:241 +msgid "Summary" +msgstr "Sumario" + +#: ../../mod/admin.php:244 +msgid "Registered accounts" +msgstr "Cuentas registradas" + +#: ../../mod/admin.php:245 ../../mod/admin.php:552 +msgid "Pending registrations" +msgstr "Registros pendientes" + +#: ../../mod/admin.php:246 +msgid "Registered channels" +msgstr "Canales registrados" + +#: ../../mod/admin.php:247 ../../mod/admin.php:553 +msgid "Active plugins" +msgstr "Plugins activos" + +#: ../../mod/admin.php:248 +msgid "Version" +msgstr "Versión" + +#: ../../mod/admin.php:363 +msgid "Site settings updated." +msgstr "Ajustes del sitio actualizados." + +#: ../../mod/admin.php:400 ../../mod/settings.php:813 +msgid "mobile" +msgstr "móvil" + +#: ../../mod/admin.php:402 +msgid "experimental" +msgstr "experimental" + +#: ../../mod/admin.php:404 +msgid "unsupported" +msgstr "no soportado" + +#: ../../mod/admin.php:429 +msgid "Yes - with approval" +msgstr "Sí - con aprobación" + +#: ../../mod/admin.php:435 +msgid "My site is not a public server" +msgstr "Mi sitio no es un servidor público" + +#: ../../mod/admin.php:436 +msgid "My site has paid access only" +msgstr "Mi sitio es un servicio de pago" + +#: ../../mod/admin.php:437 +msgid "My site has free access only" +msgstr "Mi sitio es un servicio gratuito" + +#: ../../mod/admin.php:438 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "Mi sitio ofrece cuentas gratuitas con opciones extra de pago" + +#: ../../mod/admin.php:454 ../../mod/register.php:207 +msgid "Registration" +msgstr "Registro" + +#: ../../mod/admin.php:455 +msgid "File upload" +msgstr "Fichero subido" + +#: ../../mod/admin.php:456 +msgid "Policies" +msgstr "Políticas" + +#: ../../mod/admin.php:461 +msgid "Site name" +msgstr "Nombre del sitio" + +#: ../../mod/admin.php:462 +msgid "Banner/Logo" +msgstr "Banner/Logo" + +#: ../../mod/admin.php:463 +msgid "Administrator Information" +msgstr "Información del Administrador" + +#: ../../mod/admin.php:463 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "Información de contacto de los administradores del sitio. Visible en la página \"siteinfo\". Se puede usar BBCode" + +#: ../../mod/admin.php:464 +msgid "System language" +msgstr "Lengua del sistema" + +#: ../../mod/admin.php:465 +msgid "System theme" +msgstr "Tema del sistema" + +#: ../../mod/admin.php:465 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "Tema del sistema por defecto - se puede cambiar por cada perfil de usuario - modificar ajustes del tema" + +#: ../../mod/admin.php:466 +msgid "Mobile system theme" +msgstr "Tema del sistema para móviles" + +#: ../../mod/admin.php:466 +msgid "Theme for mobile devices" +msgstr "Tema para aparatos móviles" + +#: ../../mod/admin.php:468 +msgid "Enable Diaspora Protocol" +msgstr "Activar protocolo de la red social Diaspora" + +#: ../../mod/admin.php:468 +msgid "Communicate with Diaspora and Friendica - experimental" +msgstr "Comunicar con Diaspora y Friendica - experimental" + +#: ../../mod/admin.php:469 +msgid "Allow Feeds as Connections" +msgstr "Permitir flujos RSS como conexiones" + +#: ../../mod/admin.php:469 +msgid "(Heavy system resource usage)" +msgstr "(Uso intenso de los recursos del sistema)" + +#: ../../mod/admin.php:470 +msgid "Maximum image size" +msgstr "Tamaño máximo de imagen" + +#: ../../mod/admin.php:470 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Tamaño máximo en bytes de la imagen subida. Por defecto, es 0, lo que significa que no hay límites." + +#: ../../mod/admin.php:471 +msgid "Does this site allow new member registration?" +msgstr "¿Debe este sitio permitir el registro de nuevos miembros?" + +#: ../../mod/admin.php:472 +msgid "Which best describes the types of account offered by this hub?" +msgstr "¿Cómo describiría el tipo de servicio ofrecido por este servidor?" + +#: ../../mod/admin.php:473 +msgid "Register text" +msgstr "Texto del registro" + +#: ../../mod/admin.php:473 +msgid "Will be displayed prominently on the registration page." +msgstr "Se mostrará de forma destacada en la página de registro." + +#: ../../mod/admin.php:474 +msgid "Site homepage to show visitors (default: login box)" +msgstr "Página de inicio que se mostrará a los visitantes (por defecto: la página de identificación)" + +#: ../../mod/admin.php:474 +msgid "" +"example: 'public' to show public stream, 'page/sys/home' to show a system " +"webpage called 'home' or 'include:home.html' to include a file." +msgstr "ejemplo: 'public' para mostrar contenido público de los usuarios, 'page/sys/home' para mostrar la página web definida como \"home\" o 'include:home.html' para mostrar el contenido de un fichero." + +#: ../../mod/admin.php:475 +msgid "Preserve site homepage URL" +msgstr "Preservar la dirección de la página web" + +#: ../../mod/admin.php:475 +msgid "" +"Present the site homepage in a frame at the original location instead of " +"redirecting" +msgstr "Presenta la página web del sitio en un marco en la ubicación original, en vez de redirigirla." + +#: ../../mod/admin.php:476 +msgid "Accounts abandoned after x days" +msgstr "Cuentas abandonados después de x días" + +#: ../../mod/admin.php:476 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "Para evitar consumir recursos del sistema intentando poner al día las cuentas abandonadas. Introduzca 0 para no tener límite de tiempo." + +#: ../../mod/admin.php:477 +msgid "Allowed friend domains" +msgstr "Dominios amigos permitidos" + +#: ../../mod/admin.php:477 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "Lista separada por comas de dominios a los que está permitido establecer relaciones de amistad con este sitio. Se permiten comodines. Dejar en claro para aceptar cualquier dominio." + +#: ../../mod/admin.php:478 +msgid "Allowed email domains" +msgstr "Se aceptan dominios de correo electrónico" + +#: ../../mod/admin.php:478 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "Lista separada por comas de los dominios de los que se acepta una dirección de correo electrónico para registros en este sitio. Se permiten comodines. Dejar en claro para aceptar cualquier dominio. " + +#: ../../mod/admin.php:479 +msgid "Not allowed email domains" +msgstr "No se permiten dominios de correo electrónico" + +#: ../../mod/admin.php:479 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for" +" registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "Lista separada por comas de los dominios de los que no se acepta una dirección de correo electrónico para registros en este sitio. Se permiten comodines. Dejar en claro para no aceptar cualquier dominio, excepto los que se hayan autorizado." + +#: ../../mod/admin.php:480 +msgid "Block public" +msgstr "Bloque público" + +#: ../../mod/admin.php:480 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Activar para bloquear el acceso público a todas las páginas públicas personales en este sitio salvo que estén identificadas en el sistema." + +#: ../../mod/admin.php:481 +msgid "Verify Email Addresses" +msgstr "Verificar direcciones de correo electrónico" + +#: ../../mod/admin.php:481 +msgid "" +"Check to verify email addresses used in account registration (recommended)." +msgstr "Activar para la verificación de la dirección de correo electrónico en el registro de una cuenta (recomendado)." + +#: ../../mod/admin.php:482 +msgid "Force publish" +msgstr "Forzar la publicación" + +#: ../../mod/admin.php:482 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Intentar forzar todos los perfiles para que sean listados en el directorio de este sitio." + +#: ../../mod/admin.php:483 +msgid "Disable discovery tab" +msgstr "Desactivar la pestaña \"Descubrir\"" + +#: ../../mod/admin.php:483 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "Quitar la pestaña para ver contenido público extraído de las fuentes elegidas por este sitio." + +#: ../../mod/admin.php:484 +msgid "login on Homepage" +msgstr "Acceso a la página de inicio" + +#: ../../mod/admin.php:484 +msgid "" +"Present a login box to visitors on the home page if no other content has " +"been configured." +msgstr "Presentar a los visitantes una casilla de identificación en la página de inicio, si no se ha configurado otro tipo de contenido." + +#: ../../mod/admin.php:486 +msgid "Proxy user" +msgstr "Usuario del proxy" + +#: ../../mod/admin.php:487 +msgid "Proxy URL" +msgstr "Dirección del proxy" + +#: ../../mod/admin.php:488 +msgid "Network timeout" +msgstr "Tiempo de espera de la red" + +#: ../../mod/admin.php:488 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "Valor en segundos. Poner a 0 para que no haya tiempo límite (no recomendado)" + +#: ../../mod/admin.php:489 +msgid "Delivery interval" +msgstr "Intervalo de entrega" + +#: ../../mod/admin.php:489 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Retrasar los procesos de entrega en segundo plano por esta cantidad de segundos para reducir la carga del sistema. Recomendado: 4-5 para hosts compartidos, 2-3 para servidores virtuales privados, 0-1 para grandes servidores dedicados." + +#: ../../mod/admin.php:490 +msgid "Poll interval" +msgstr "Intervalo de sondeo" + +#: ../../mod/admin.php:490 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Retrasar el sondeo en segundo plano en esta cantidad de segundo para reducir la carga del sistema. Si es 0, use el intervalo de entrega." + +#: ../../mod/admin.php:491 +msgid "Maximum Load Average" +msgstr "Carga media máxima" + +#: ../../mod/admin.php:491 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Carga máxima del sistema antes de que los procesos de entrega y sondeo se hayan retardado - por defecto, 50." + +#: ../../mod/admin.php:492 +msgid "Expiration period in days for imported (matrix/network) content" +msgstr "Periodo de caducidad en días para el contenido importado (matrix/red)" + +#: ../../mod/admin.php:492 +msgid "0 for no expiration of imported content" +msgstr "0 para que no caduque el contenido importado" + +#: ../../mod/admin.php:540 +msgid "No server found" +msgstr "Servidor no encontrado" + +#: ../../mod/admin.php:547 ../../mod/admin.php:831 +msgid "ID" +msgstr "ID" + +#: ../../mod/admin.php:547 +msgid "for channel" +msgstr "por canal" + +#: ../../mod/admin.php:547 +msgid "on server" +msgstr "sobre el servidor" + +#: ../../mod/admin.php:547 +msgid "Status" +msgstr "Estado" + +#: ../../mod/admin.php:549 +msgid "Server" +msgstr "Servidor" + +#: ../../mod/admin.php:566 +msgid "Update has been marked successful" +msgstr "La actualización ha sido marcada como exitosa" + +#: ../../mod/admin.php:576 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "La ejecución de %s ha fallado. Mire en los registros del sistema." + +#: ../../mod/admin.php:579 +#, php-format +msgid "Update %s was successfully applied." +msgstr "La actualización de %s se ha realizado exitosamente." + +#: ../../mod/admin.php:583 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "La actualización de %s no ha devuelto ningún estado. No se sabe si ha tenido éxito." + +#: ../../mod/admin.php:586 +#, php-format +msgid "Update function %s could not be found." +msgstr "No se encuentra la función de actualización de %s." + +#: ../../mod/admin.php:602 +msgid "No failed updates." +msgstr "No ha fallado ninguna actualización." + +#: ../../mod/admin.php:606 +msgid "Failed Updates" +msgstr "Han fallado las actualizaciones" + +#: ../../mod/admin.php:608 +msgid "Mark success (if update was manually applied)" +msgstr "Marcar como exitosa (si la actualización se ha hecho manualmente)" + +#: ../../mod/admin.php:609 +msgid "Attempt to execute this update step automatically" +msgstr "Intentar ejecutar este paso de actualización automáticamente" + +#: ../../mod/admin.php:641 +msgid "Queue Statistics" +msgstr "Estadísticas de la cola" + +#: ../../mod/admin.php:642 +msgid "Total Entries" +msgstr "Total de entradas" + +#: ../../mod/admin.php:643 +msgid "Priority" +msgstr "Prioridad" + +#: ../../mod/admin.php:644 +msgid "Destination URL" +msgstr "Dirección de destino" + +#: ../../mod/admin.php:645 +msgid "Mark hub permanently offline" +msgstr "Marcar el servidor como permanentemente fuera de línea" + +#: ../../mod/admin.php:646 +msgid "Empty queue for this hub" +msgstr "Vaciar la cola para este servidor" + +#: ../../mod/admin.php:647 +msgid "Last known contact" +msgstr "Último contacto conocido" + +#: ../../mod/admin.php:683 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s usuarios bloqueados/desbloqueados" +msgstr[1] "%s de usuarios bloqueados/desbloqueados" + +#: ../../mod/admin.php:691 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s usuarios eliminados" +msgstr[1] "%s usuarios eliminados" + +#: ../../mod/admin.php:727 +msgid "Account not found" +msgstr "Cuenta no encontrada" + +#: ../../mod/admin.php:747 +#, php-format +msgid "User '%s' blocked" +msgstr "Usuario %s bloqueado" + +#: ../../mod/admin.php:755 +#, php-format +msgid "User '%s' unblocked" +msgstr "Usuario %s desbloqueado" + +#: ../../mod/admin.php:818 ../../mod/admin.php:830 +msgid "Users" +msgstr "Usuarios" + +#: ../../mod/admin.php:820 ../../mod/admin.php:987 +msgid "select all" +msgstr "seleccionar todo" + +#: ../../mod/admin.php:821 +msgid "User registrations waiting for confirm" +msgstr "Registros de usuario en espera de aprobación" + +#: ../../mod/admin.php:822 +msgid "Request date" +msgstr "Fecha de solicitud" + +#: ../../mod/admin.php:823 +msgid "No registrations." +msgstr "Sin registros." + +#: ../../mod/admin.php:824 ../../mod/connedit.php:687 +msgid "Approve" +msgstr "Aprobar" + +#: ../../mod/admin.php:825 +msgid "Deny" +msgstr "Rechazar" + +#: ../../mod/admin.php:827 ../../mod/connedit.php:519 +msgid "Block" +msgstr "Bloquear" + +#: ../../mod/admin.php:828 ../../mod/connedit.php:519 +msgid "Unblock" +msgstr "Desbloquear" + +#: ../../mod/admin.php:831 +msgid "Register date" +msgstr "Fecha de registro" + +#: ../../mod/admin.php:831 +msgid "Last login" +msgstr "Último acceso" + +#: ../../mod/admin.php:831 +msgid "Expires" +msgstr "Expira" + +#: ../../mod/admin.php:831 +msgid "Service Class" +msgstr "Clase de servicio" + +#: ../../mod/admin.php:833 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Los usuarios seleccionados serám eliminados!\\n\\nTodo lo que estos usuarios han publicado en este sitio se borrará de manera definitiva!\\n\\n¿Está seguro de querer hacerlo?" + +#: ../../mod/admin.php:834 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "El usuario {0} va a ser eliminado!\\n\\nTodo lo que este usuario ha publicado en este sitio será borrado de forma permanente!\\n\\n¿Está seguro de querer hacerlo?" + +#: ../../mod/admin.php:870 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channels censored/uncensored" +msgstr[0] "%s canales censurados/no censurados" +msgstr[1] "%s canales censurados/no censurados" + +#: ../../mod/admin.php:879 +#, php-format +msgid "%s channel code allowed/disallowed" +msgid_plural "%s channels code allowed/disallowed" +msgstr[0] "%s código permitido/no permitido al canal" +msgstr[1] "%s código permitido/no permitido al canal" + +#: ../../mod/admin.php:886 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "%s canales eliminados" +msgstr[1] "%s canales eliminados" + +#: ../../mod/admin.php:906 +msgid "Channel not found" +msgstr "Canal no encontrado" + +#: ../../mod/admin.php:917 +#, php-format +msgid "Channel '%s' deleted" +msgstr "Canal '%s' eliminado" + +#: ../../mod/admin.php:929 +#, php-format +msgid "Channel '%s' censored" +msgstr "Canal '%s' censurado" + +#: ../../mod/admin.php:929 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "Canal '%s' no censurado" + +#: ../../mod/admin.php:940 +#, php-format +msgid "Channel '%s' code allowed" +msgstr "Código permitido al canal '%s'" + +#: ../../mod/admin.php:940 +#, php-format +msgid "Channel '%s' code disallowed" +msgstr "Código no permitido al canal '%s'" + +#: ../../mod/admin.php:989 +msgid "Censor" +msgstr "Censurar" + +#: ../../mod/admin.php:990 +msgid "Uncensor" +msgstr "No censurar" + +#: ../../mod/admin.php:991 +msgid "Allow Code" +msgstr "Permitir código" + +#: ../../mod/admin.php:992 +msgid "Disallow Code" +msgstr "No permitir código" + +#: ../../mod/admin.php:994 +msgid "UID" +msgstr "UID" + +#: ../../mod/admin.php:996 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Los canales seleccionados se eliminarán!\\n\\nTodo lo publicado por estos canales en este sitio se borrarán definitivamente!\\n\\n¿Está seguro de querer hacerlo?" + +#: ../../mod/admin.php:997 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "El canal {0} va a ser eliminado!\\n\\nTodo lo publicado por el canal en este sitio se borrará definitivamente!\\n\\n¿Está seguro de querer hacerlo?" + +#: ../../mod/admin.php:1037 +#, php-format +msgid "Plugin %s disabled." +msgstr "Plugin %s desactivado." + +#: ../../mod/admin.php:1041 +#, php-format +msgid "Plugin %s enabled." +msgstr "Plugin %s activado." + +#: ../../mod/admin.php:1051 ../../mod/admin.php:1249 +msgid "Disable" +msgstr "Desactivar" + +#: ../../mod/admin.php:1054 ../../mod/admin.php:1251 +msgid "Enable" +msgstr "Activar" + +#: ../../mod/admin.php:1078 ../../mod/admin.php:1278 +msgid "Toggle" +msgstr "Cambiar" + +#: ../../mod/admin.php:1086 ../../mod/admin.php:1288 +msgid "Author: " +msgstr "Autor:" + +#: ../../mod/admin.php:1087 ../../mod/admin.php:1289 +msgid "Maintainer: " +msgstr "Mantenedor:" + +#: ../../mod/admin.php:1214 +msgid "No themes found." +msgstr "No se han encontrado temas." + +#: ../../mod/admin.php:1270 +msgid "Screenshot" +msgstr "Instantánea de pantalla" + +#: ../../mod/admin.php:1316 +msgid "[Experimental]" +msgstr "[Experimental]" + +#: ../../mod/admin.php:1317 +msgid "[Unsupported]" +msgstr "[No soportado]" + +#: ../../mod/admin.php:1341 +msgid "Log settings updated." +msgstr "Actualizado el informe de configuraciones." + +#: ../../mod/admin.php:1398 +msgid "Clear" +msgstr "Vaciar" + +#: ../../mod/admin.php:1404 +msgid "Debugging" +msgstr "Depurando" + +#: ../../mod/admin.php:1405 +msgid "Log file" +msgstr "Fichero de informe" + +#: ../../mod/admin.php:1405 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "Debe tener permisos de escritura para el servidor web. Ruta relativa al directorio raíz de Red." + +#: ../../mod/admin.php:1406 +msgid "Log level" +msgstr "Nivel de depuración" + +#: ../../mod/admin.php:1452 +msgid "New Profile Field" +msgstr "Nuevo campo en el perfil" + +#: ../../mod/admin.php:1453 ../../mod/admin.php:1473 +msgid "Field nickname" +msgstr "Alias del campo" + +#: ../../mod/admin.php:1453 ../../mod/admin.php:1473 +msgid "System name of field" +msgstr "Nombre del campo en el sistema" + +#: ../../mod/admin.php:1454 ../../mod/admin.php:1474 +msgid "Input type" +msgstr "Tipo de entrada" + +#: ../../mod/admin.php:1455 ../../mod/admin.php:1475 +msgid "Field Name" +msgstr "Nombre del campo" + +#: ../../mod/admin.php:1455 ../../mod/admin.php:1475 +msgid "Label on profile pages" +msgstr "Etiqueta a mostrar en las páginas del perfil" + +#: ../../mod/admin.php:1456 ../../mod/admin.php:1476 +msgid "Help text" +msgstr "Texto de ayuda" + +#: ../../mod/admin.php:1456 ../../mod/admin.php:1476 +msgid "Additional info (optional)" +msgstr "Información adicional (opcional)" + +#: ../../mod/admin.php:1466 +msgid "Field definition not found" +msgstr "Definición del campo no encontrada" + +#: ../../mod/admin.php:1472 +msgid "Edit Profile Field" +msgstr "Modificar el campo del perfil" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "No se puede encontrar su servidor." + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "Enviado con éxito." + +#: ../../mod/register.php:44 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "Se ha superado el límite máximo de inscripciones diarias de este sitio. Por favor, pruebe de nuevo mañana." + +#: ../../mod/register.php:50 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "Por favor, confirme que acepta los Términos del servicio. El registro ha fallado." + +#: ../../mod/register.php:84 +msgid "Passwords do not match." +msgstr "Las contraseñas no coinciden." + +#: ../../mod/register.php:117 +msgid "" +"Registration successful. Please check your email for validation " +"instructions." +msgstr "Registro realizado con éxito. Por favor, compruebe su correo electrónico para ver las instrucciones para validarlo." + +#: ../../mod/register.php:123 +msgid "Your registration is pending approval by the site owner." +msgstr "Su registro está pendiente de aprobación por el propietario del sitio." + +#: ../../mod/register.php:126 +msgid "Your registration can not be processed." +msgstr "Su registro no puede ser procesado." + +#: ../../mod/register.php:163 +msgid "Registration on this site/hub is by approval only." +msgstr "El registro en este servidor/hub está sometido a aprobación previa." + +#: ../../mod/register.php:164 +msgid "Register at another affiliated site/hub" +msgstr "Inscribirse en un servidor/hub afiliado" + +#: ../../mod/register.php:174 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "Este sitio ha excedido el límite de inscripción diaria de cuentas. Por favor, inténtelo de nuevo mañana." + +#: ../../mod/register.php:185 +msgid "Terms of Service" +msgstr "Términos del servicio" + +#: ../../mod/register.php:191 +#, php-format +msgid "I accept the %s for this website" +msgstr "Acepto los %s de este sitio" + +#: ../../mod/register.php:193 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "Tengo más de 13 años de edad y acepto los %s de este sitio" + +#: ../../mod/register.php:212 +msgid "Membership on this site is by invitation only." +msgstr "Para registrarse en este sitio es necesaria una invitación." + +#: ../../mod/register.php:213 +msgid "Please enter your invitation code" +msgstr "Por favor, introduzca el código de su invitación" + +#: ../../mod/register.php:216 +msgid "Your email address" +msgstr "Su dirección de correo electrónico" + +#: ../../mod/register.php:217 +msgid "Choose a password" +msgstr "Elija una contraseña" + +#: ../../mod/register.php:218 +msgid "Please re-enter your password" +msgstr "Por favor, vuelva a escribir su contraseña" + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "La eliminación de cuentas no está permitida hasta después de que hayan transcurrido 48 horas desde el último cambio de contraseña." + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "Eliminar esta cuenta" + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "WARNING: " +msgstr "ATENCIÓN:" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This account and all its channels will be completely removed from the " +"network. " +msgstr "Esta cuenta y todos sus canales van a ser eliminados de la red." + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "This action is permanent and can not be undone!" +msgstr "¡Esta acción tiene carácter definitivo y no se puede deshacer!" + +#: ../../mod/removeaccount.php:59 ../../mod/removeme.php:59 +msgid "Please enter your password for verification:" +msgstr "Por favor, introduzca su contraseña para su verificación:" + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "Remover esta cuenta, todos sus canales y clones de la red" + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "Por defecto, solo las instancias de los canales ubicados en este servidor serán eliminados de la red" + +#: ../../mod/removeaccount.php:61 ../../mod/settings.php:720 +msgid "Remove Account" +msgstr "Eliminar cuenta" + +#: ../../mod/help.php:49 ../../mod/help.php:55 ../../mod/help.php:61 +msgid "Help:" +msgstr "Ayuda:" + +#: ../../mod/help.php:76 ../../index.php:238 +msgid "Not Found" +msgstr "No encontrado" + +#: ../../mod/help.php:100 +msgid "$Projectname Documentation" +msgstr "Documentación de $Projectname" + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +#: ../../mod/update_home.php:21 ../../mod/update_public.php:21 +msgid "[Embedded content - reload page to view]" +msgstr "[Contenido incorporado - recargue la página para poder verlo]" + +#: ../../mod/lockview.php:37 +msgid "Remote privacy information not available." +msgstr "La información privada remota no está disponible." + +#: ../../mod/lockview.php:58 +msgid "Visible to:" +msgstr "Visible para:" + +#: ../../mod/settings.php:76 +msgid "Name is required" +msgstr "El nombre es obligatorio" + +#: ../../mod/settings.php:80 +msgid "Key and Secret are required" +msgstr "Clave y Secreto son obligatorios" + +#: ../../mod/settings.php:130 +msgid "Diaspora Policy Settings updated." +msgstr "Configuración de directivas de Diaspora actualizada." + +#: ../../mod/settings.php:238 +msgid "Passwords do not match. Password unchanged." +msgstr "Las contraseñas no coinciden. La contraseña no se ha cambiado." + +#: ../../mod/settings.php:242 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "No se permiten contraseñas vacías. La contraseña no se ha cambiado." + +#: ../../mod/settings.php:256 +msgid "Password changed." +msgstr "Constraseña cambiada." + +#: ../../mod/settings.php:258 +msgid "Password update failed. Please try again." +msgstr "La actualización de la contraseña ha fallado. Por favor, inténtalo de nuevo." + +#: ../../mod/settings.php:272 +msgid "Not valid email." +msgstr "Correo electrónico no válido." + +#: ../../mod/settings.php:275 +msgid "Protected email address. Cannot change to that email." +msgstr "Dirección de correo electrónico protegida. No se puede cambiar a ella." + +#: ../../mod/settings.php:284 +msgid "System failure storing new email. Please try again." +msgstr "Fallo de sistema al guardar el nuevo correo electrónico. Por favor, inténtelo de nuevo." + +#: ../../mod/settings.php:523 +msgid "Settings updated." +msgstr "Configuración actualizada." + +#: ../../mod/settings.php:587 ../../mod/settings.php:613 +#: ../../mod/settings.php:649 +msgid "Add application" +msgstr "Añadir aplicación" + +#: ../../mod/settings.php:590 +msgid "Name of application" +msgstr "Nombre de la aplicación" + +#: ../../mod/settings.php:591 ../../mod/settings.php:617 +msgid "Consumer Key" +msgstr "Clave de consumidor" + +#: ../../mod/settings.php:591 ../../mod/settings.php:592 +msgid "Automatically generated - change if desired. Max length 20" +msgstr "Generado automáticamente - si lo desea, cámbielo. Longitud máxima: 20" + +#: ../../mod/settings.php:592 ../../mod/settings.php:618 +msgid "Consumer Secret" +msgstr "Secreto de consumidor" + +#: ../../mod/settings.php:593 ../../mod/settings.php:619 +msgid "Redirect" +msgstr "Redirigir" + +#: ../../mod/settings.php:593 +msgid "" +"Redirect URI - leave blank unless your application specifically requires " +"this" +msgstr "URI de redirección - dejar en blanco a menos que su aplicación específicamente lo requiera" + +#: ../../mod/settings.php:594 ../../mod/settings.php:620 +msgid "Icon url" +msgstr "url de icono" + +#: ../../mod/settings.php:594 +msgid "Optional" +msgstr "Opcional" + +#: ../../mod/settings.php:605 +msgid "You can't edit this application." +msgstr "No puede modificar esta aplicación." + +#: ../../mod/settings.php:648 +msgid "Connected Apps" +msgstr "Aplicaciones conectadas" + +#: ../../mod/settings.php:652 +msgid "Client key starts with" +msgstr "La clave de cliente empieza por" + +#: ../../mod/settings.php:653 +msgid "No name" +msgstr "Sin nombre" + +#: ../../mod/settings.php:654 +msgid "Remove authorization" +msgstr "Eliminar autorización" + +#: ../../mod/settings.php:668 +msgid "No feature settings configured" +msgstr "No se ha establecido la configuración de características" + +#: ../../mod/settings.php:685 +msgid "Feature/Addon Settings" +msgstr "Configuración de característica/complemento" + +#: ../../mod/settings.php:687 +msgid "Settings for the built-in Diaspora emulator" +msgstr "Configuración para el emulador de Diaspora incorporado" + +#: ../../mod/settings.php:688 +msgid "Allow any Diaspora member to comment on your public posts" +msgstr "Permitir a cualquier miembro de Diaspora comentar en sus publicaciones públicas" + +#: ../../mod/settings.php:689 +msgid "Enable the Diaspora protocol for this channel" +msgstr "Activar el protocolo de Diaspora para este canal" + +#: ../../mod/settings.php:690 +msgid "Diaspora Policy Settings" +msgstr "Configuración de directivas de Diaspora" + +#: ../../mod/settings.php:691 +msgid "Prevent your hashtags from being redirected to other sites" +msgstr "Impedir que sus \"hashtags\" sean redirigidos a otros sitios " + +#: ../../mod/settings.php:715 +msgid "Account Settings" +msgstr "Configuración de la cuenta" + +#: ../../mod/settings.php:716 +msgid "Enter New Password:" +msgstr "Introduzca la nueva contraseña:" + +#: ../../mod/settings.php:717 +msgid "Confirm New Password:" +msgstr "Confirma la nueva contraseña:" + +#: ../../mod/settings.php:717 +msgid "Leave password fields blank unless changing" +msgstr "Dejar en blanco los campos de contraseña a menos que cambie" + +#: ../../mod/settings.php:719 ../../mod/settings.php:1057 +msgid "Email Address:" +msgstr "Dirección de correo electrónico:" + +#: ../../mod/settings.php:721 +msgid "Remove this account including all its channels" +msgstr "Eliminar esta cuenta incuyendo todos sus canales" + +#: ../../mod/settings.php:737 +msgid "Off" +msgstr "Desactivado" + +#: ../../mod/settings.php:737 +msgid "On" +msgstr "Activado" + +#: ../../mod/settings.php:744 +msgid "Additional Features" +msgstr "Características adicionales" + +#: ../../mod/settings.php:768 +msgid "Connector Settings" +msgstr "Configuración de conector" + +#: ../../mod/settings.php:807 +msgid "No special theme for mobile devices" +msgstr "Sin tema especial para dispositivos móviles" + +#: ../../mod/settings.php:810 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s - (Experimental)" + +#: ../../mod/settings.php:849 +msgid "Display Settings" +msgstr "Configuración de visualización" + +#: ../../mod/settings.php:850 +msgid "Theme Settings" +msgstr "Ajustes del tema" + +#: ../../mod/settings.php:851 +msgid "Custom Theme Settings" +msgstr "Ajustes personalizados del tema" + +#: ../../mod/settings.php:852 +msgid "Content Settings" +msgstr "Ajustes del contenido" + +#: ../../mod/settings.php:858 +msgid "Display Theme:" +msgstr "Tema de visualización:" + +#: ../../mod/settings.php:859 +msgid "Mobile Theme:" +msgstr "Tema móvil:" + +#: ../../mod/settings.php:860 +msgid "Enable user zoom on mobile devices" +msgstr "Habilitar zoom de usuario en dispositivos móviles" + +#: ../../mod/settings.php:861 +msgid "Update browser every xx seconds" +msgstr "Actualizar navegador cada xx segundos" + +#: ../../mod/settings.php:861 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Mínimo de 10 segundos, sin máximo" + +#: ../../mod/settings.php:862 +msgid "Maximum number of conversations to load at any time:" +msgstr "Máximo número de conversaciones a cargar en cualquier momento:" + +#: ../../mod/settings.php:862 +msgid "Maximum of 100 items" +msgstr "Máximo de 100 elementos" + +#: ../../mod/settings.php:863 +msgid "Show emoticons (smilies) as images" +msgstr "Mostrar emoticonos (smilies) como imágenes" + +#: ../../mod/settings.php:864 +msgid "Link post titles to source" +msgstr "Enlazar título de la publicación a la fuente" + +#: ../../mod/settings.php:865 +msgid "System Page Layout Editor - (advanced)" +msgstr "Editor de sistema de distribución de página - (avanzado)" + +#: ../../mod/settings.php:868 +msgid "Use blog/list mode on channel page" +msgstr "Usar modo blog/lista en página del canal" + +#: ../../mod/settings.php:868 ../../mod/settings.php:869 +msgid "(comments displayed separately)" +msgstr "(comentarios mostrados de forma separada)" + +#: ../../mod/settings.php:869 +msgid "Use blog/list mode on matrix page" +msgstr "Mostrar su red en modo blog/lista" + +#: ../../mod/settings.php:870 +msgid "Channel page max height of content (in pixels)" +msgstr "Altura máxima del contenido de la página del canal (en píxeles)" + +#: ../../mod/settings.php:870 ../../mod/settings.php:871 +msgid "click to expand content exceeding this height" +msgstr "Pulsa para expandir el contenido que excede esta altura" + +#: ../../mod/settings.php:871 +msgid "Matrix page max height of content (in pixels)" +msgstr "Altura máxima del contenido de la página de matrix (en píxeles)" + +#: ../../mod/settings.php:905 +msgid "Nobody except yourself" +msgstr "Nadie excepto tú" + +#: ../../mod/settings.php:906 +msgid "Only those you specifically allow" +msgstr "Solamente aquellos a los que tú permitas específicamente" + +#: ../../mod/settings.php:907 +msgid "Approved connections" +msgstr "Conexiones aprobadas" + +#: ../../mod/settings.php:908 +msgid "Any connections" +msgstr "Cualquier conexión" + +#: ../../mod/settings.php:909 +msgid "Anybody on this website" +msgstr "Cualquiera en este website" + +#: ../../mod/settings.php:910 +msgid "Anybody in this network" +msgstr "Cualquiera en esta red" + +#: ../../mod/settings.php:911 +msgid "Anybody authenticated" +msgstr "Cualquiera autenticado" + +#: ../../mod/settings.php:912 +msgid "Anybody on the internet" +msgstr "Cualquiera en internet" + +#: ../../mod/settings.php:986 +msgid "Publish your default profile in the network directory" +msgstr "Publicar tu perfil predeterminado en el directorio de la red" + +#: ../../mod/settings.php:991 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "¿Nos permite sugerirle como amigo potencial a los nuevos miembros?" + +#: ../../mod/settings.php:1000 +msgid "Your channel address is" +msgstr "Su dirección de canal es" + +#: ../../mod/settings.php:1048 +msgid "Channel Settings" +msgstr "Configuración del canal" + +#: ../../mod/settings.php:1055 +msgid "Basic Settings" +msgstr "Configuración básica" + +#: ../../mod/settings.php:1058 +msgid "Your Timezone:" +msgstr "Su zona horaria:" + +#: ../../mod/settings.php:1059 +msgid "Default Post Location:" +msgstr "Ubicación de publicación predeterminada:" + +#: ../../mod/settings.php:1059 +msgid "Geographical location to display on your posts" +msgstr "Localización geográfica a mostrar en sus publicaciones" + +#: ../../mod/settings.php:1060 +msgid "Use Browser Location:" +msgstr "Usar localización de navegador:" + +#: ../../mod/settings.php:1062 +msgid "Adult Content" +msgstr "Contenido solo para adultos" + +#: ../../mod/settings.php:1062 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "Este canal publica contenido solo para adultos con frecuencia o regularmente. (Por favor etiquete cualquier material para adultos con la etiqueta #NSFW)" + +#: ../../mod/settings.php:1064 +msgid "Security and Privacy Settings" +msgstr "Configuración de seguridad y privacidad" + +#: ../../mod/settings.php:1066 +msgid "Your permissions are already configured. Click to view/adjust" +msgstr "Sus permisos ya están configurados. Pulse para ver/ajustar" + +#: ../../mod/settings.php:1068 +msgid "Hide my online presence" +msgstr "Oculta mi presencia online" + +#: ../../mod/settings.php:1068 +msgid "Prevents displaying in your profile that you are online" +msgstr "Evita mostrar en su perfil que está en línea" + +#: ../../mod/settings.php:1070 +msgid "Simple Privacy Settings:" +msgstr "Configuración de privacidad sencilla:" + +#: ../../mod/settings.php:1071 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "Muy Público - extremadamente permisivo (debería ser usado con precaución)" + +#: ../../mod/settings.php:1072 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "Típico - por defecto público, privado cuando se desee (similar a los permisos de red social pero con privacidad mejorada)" + +#: ../../mod/settings.php:1073 +msgid "Private - default private, never open or public" +msgstr "Privado - por defecto privado, nunca abierto o público" + +#: ../../mod/settings.php:1074 +msgid "Blocked - default blocked to/from everybody" +msgstr "Bloqueado - por defecto bloqueado bloqueado a/para cualquiera" + +#: ../../mod/settings.php:1076 +msgid "Allow others to tag your posts" +msgstr "Permitir a otros etiquetar sus publicaciones" + +#: ../../mod/settings.php:1076 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "A menudo usado por la comunidad para marcar contenido inapropiado de forma retroactiva." + +#: ../../mod/settings.php:1078 +msgid "Advanced Privacy Settings" +msgstr "Configuración de privacidad avanzada" + +#: ../../mod/settings.php:1080 +msgid "Expire other channel content after this many days" +msgstr "Caducar contenido de otro canal después de este número de días" + +#: ../../mod/settings.php:1080 +msgid "0 or blank prevents expiration" +msgstr "0 o vacío evita la expiración" + +#: ../../mod/settings.php:1081 +msgid "Maximum Friend Requests/Day:" +msgstr "Máximo de solicitudes de amistad por día:" + +#: ../../mod/settings.php:1081 +msgid "May reduce spam activity" +msgstr "Podría reducir la actividad de spam" + +#: ../../mod/settings.php:1082 +msgid "Default Post Permissions" +msgstr "Permidos de publicación predeterminados" + +#: ../../mod/settings.php:1087 +msgid "Channel permissions category:" +msgstr "Categoría de permisos del canal:" + +#: ../../mod/settings.php:1093 +msgid "Maximum private messages per day from unknown people:" +msgstr "Máximo de mensajes privados por día de gente desconocida:" + +#: ../../mod/settings.php:1093 +msgid "Useful to reduce spamming" +msgstr "Útil para reducir el envío de correo no deseado" + +#: ../../mod/settings.php:1096 +msgid "Notification Settings" +msgstr "Configuración de notificaciones" + +#: ../../mod/settings.php:1097 +msgid "By default post a status message when:" +msgstr "Por defecto, enviar un mensaje de estado cuando:" + +#: ../../mod/settings.php:1098 +msgid "accepting a friend request" +msgstr "acepte una solicitud de amistad" + +#: ../../mod/settings.php:1099 +msgid "joining a forum/community" +msgstr "unirse a un foro o comunidad" + +#: ../../mod/settings.php:1100 +msgid "making an interesting profile change" +msgstr "realice un cambio interesante en su perfil" + +#: ../../mod/settings.php:1101 +msgid "Send a notification email when:" +msgstr "Enviar una notificación por correo electrónico cuando:" + +#: ../../mod/settings.php:1102 +msgid "You receive a connection request" +msgstr "Reciba una solicitud de conexión" + +#: ../../mod/settings.php:1103 +msgid "Your connections are confirmed" +msgstr "Su conexión haya sido confirmada" + +#: ../../mod/settings.php:1104 +msgid "Someone writes on your profile wall" +msgstr "Alguien escriba en el muro de su perfil" + +#: ../../mod/settings.php:1105 +msgid "Someone writes a followup comment" +msgstr "Alguien escriba un comentario sobre sus publicaciones" + +#: ../../mod/settings.php:1106 +msgid "You receive a private message" +msgstr "Reciba un mensaje privado" + +#: ../../mod/settings.php:1107 +msgid "You receive a friend suggestion" +msgstr "Reciba una sugerencia de amistad" + +#: ../../mod/settings.php:1108 +msgid "You are tagged in a post" +msgstr "Usted es etiquetado en una publicación" + +#: ../../mod/settings.php:1109 +msgid "You are poked/prodded/etc. in a post" +msgstr "Ha recibido un toque o ha sido incitado, etc. en una publicación" + +#: ../../mod/settings.php:1112 +msgid "Show visual notifications including:" +msgstr "Mostrar notificaciones visuales que incluyan:" + +#: ../../mod/settings.php:1114 +msgid "Unseen matrix activity" +msgstr "Actividad no vista en la red" + +#: ../../mod/settings.php:1115 +msgid "Unseen channel activity" +msgstr "Actividad no vista en el canal" + +#: ../../mod/settings.php:1116 +msgid "Unseen private messages" +msgstr "Mensajes privados no leídos" + +#: ../../mod/settings.php:1116 ../../mod/settings.php:1121 +#: ../../mod/settings.php:1122 ../../mod/settings.php:1123 +msgid "Recommended" +msgstr "Recomendado" + +#: ../../mod/settings.php:1117 +msgid "Upcoming events" +msgstr "Próximos eventos" + +#: ../../mod/settings.php:1118 +msgid "Events today" +msgstr "Eventos de hoy" + +#: ../../mod/settings.php:1119 +msgid "Upcoming birthdays" +msgstr "Próximos cumpleaños" + +#: ../../mod/settings.php:1119 +msgid "Not available in all themes" +msgstr "No disponible en todos los temas" + +#: ../../mod/settings.php:1120 +msgid "System (personal) notifications" +msgstr "Notificaciones del sistema (personales)" + +#: ../../mod/settings.php:1121 +msgid "System info messages" +msgstr "Mensajes de información del sistema" + +#: ../../mod/settings.php:1122 +msgid "System critical alerts" +msgstr "Alertas críticas del sistema" + +#: ../../mod/settings.php:1123 +msgid "New connections" +msgstr "Nuevas conexiones" + +#: ../../mod/settings.php:1124 +msgid "System Registrations" +msgstr "Registros del sistema" + +#: ../../mod/settings.php:1125 +msgid "" +"Also show new wall posts, private messages and connections under Notices" +msgstr "Mostrar también en Avisos las nuevas publicaciones, los mensajes privados y las conexiones" + +#: ../../mod/settings.php:1127 +msgid "Notify me of events this many days in advance" +msgstr "Avisarme de los eventos con algunos días de antelación" + +#: ../../mod/settings.php:1127 +msgid "Must be greater than 0" +msgstr "Debe ser mayor que 0" + +#: ../../mod/settings.php:1129 +msgid "Advanced Account/Page Type Settings" +msgstr "Ajustes avanzados de la cuenta y de los tipos de página" + +#: ../../mod/settings.php:1130 +msgid "Change the behaviour of this account for special situations" +msgstr "Cambiar el comportamiento de esta cuenta en situaciones especiales" + +#: ../../mod/settings.php:1133 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "Activar modo experto (en Ajustes > Características Adicionales) para ajustar." + +#: ../../mod/settings.php:1134 +msgid "Miscellaneous Settings" +msgstr "Ajustes diversos" + +#: ../../mod/settings.php:1136 +msgid "Personal menu to display in your channel pages" +msgstr "Menú personal que debe mostrarse en las páginas de su canal" + +#: ../../mod/settings.php:1137 ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "Eliminar canal" + +#: ../../mod/settings.php:1138 +msgid "Remove this channel." +msgstr "Eliminar este canal." + +#: ../../mod/id.php:11 +msgid "First Name" +msgstr "Nombre" + +#: ../../mod/id.php:12 +msgid "Last Name" +msgstr "Apellido" + +#: ../../mod/id.php:13 +msgid "Nickname" +msgstr "Alias" + +#: ../../mod/id.php:14 +msgid "Full Name" +msgstr "Nombre completo" + +#: ../../mod/id.php:20 +msgid "Profile Photo 16px" +msgstr "Foto de perfil 16px" + +#: ../../mod/id.php:21 +msgid "Profile Photo 32px" +msgstr "Foto de perfil 32px" + +#: ../../mod/id.php:22 +msgid "Profile Photo 48px" +msgstr "Foto de perfil 48px" + +#: ../../mod/id.php:23 +msgid "Profile Photo 64px" +msgstr "Foto de perfil 64px" + +#: ../../mod/id.php:24 +msgid "Profile Photo 80px" +msgstr "Foto de perfil 80px" + +#: ../../mod/id.php:25 +msgid "Profile Photo 128px" +msgstr "Foto de perfil 128px" + +#: ../../mod/id.php:26 +msgid "Timezone" +msgstr "Zona horaria" + +#: ../../mod/id.php:27 +msgid "Homepage URL" +msgstr "Dirección de la página personal" + +#: ../../mod/id.php:29 +msgid "Birth Year" +msgstr "Año de nacimiento" + +#: ../../mod/id.php:30 +msgid "Birth Month" +msgstr "Mes de nacimiento" + +#: ../../mod/id.php:31 +msgid "Birth Day" +msgstr "Día de nacimiento" + +#: ../../mod/id.php:32 +msgid "Birthdate" +msgstr "Fecha de nacimiento" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "Conversación eliminada." + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "Sin mensajes." + +#: ../../mod/message.php:72 ../../mod/mail.php:336 +msgid "Delete conversation" +msgstr "Eliminar conversación" + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "D d M Y - G:i" + +#: ../../mod/mood.php:131 +msgid "Set your current mood and tell your friends" +msgstr "Describir su estado de ánimo para comunicárselo a sus amigos" + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "Total de votos" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "Valoración media" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "La eliminación de canales no está permitida hasta pasadas 48 horas desde el último cambio de contraseña." + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "Eliminar este canal" + +#: ../../mod/removeme.php:58 +msgid "This channel will be completely removed from the network. " +msgstr "Este canal va a ser completamente eliminado de la red." + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "Eliminar este canal y todos sus clones de la red" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "Por defecto, solo la instancia del canal alojado en este servidor será eliminado de la red" + +#: ../../mod/connedit.php:267 +msgid "is now connected to" +msgstr "ahora está conectado a" + +#: ../../mod/connedit.php:380 +msgid "Could not access address book record." +msgstr "No se pudo acceder a la entrada en su libreta de direcciones." + +#: ../../mod/connedit.php:394 +msgid "Refresh failed - channel is currently unavailable." +msgstr "Recarga fallida - no se puede encontrar actualmente el canal" + +#: ../../mod/connedit.php:406 ../../mod/connedit.php:418 +#: ../../mod/connedit.php:430 ../../mod/connedit.php:442 +#: ../../mod/connedit.php:458 +msgid "Unable to set address book parameters." +msgstr "No ha sido posible establecer los parámetros de la libreta de direcciones." + +#: ../../mod/connedit.php:482 +msgid "Connection has been removed." +msgstr "La conexión ha sido eliminada." + +#: ../../mod/connedit.php:501 +#, php-format +msgid "View %s's profile" +msgstr "Ver el perfil de %s" + +#: ../../mod/connedit.php:505 +msgid "Refresh Permissions" +msgstr "Recargar los permisos" + +#: ../../mod/connedit.php:508 +msgid "Fetch updated permissions" +msgstr "Obtener los permisos actualizados" + +#: ../../mod/connedit.php:512 +msgid "Recent Activity" +msgstr "Actividad reciente" + +#: ../../mod/connedit.php:515 +msgid "View recent posts and comments" +msgstr "Ver publicaciones y comentarios recientes" + +#: ../../mod/connedit.php:522 +msgid "Block (or Unblock) all communications with this connection" +msgstr "Bloquear (o desbloquear) todas las comunicaciones con esta conexión" + +#: ../../mod/connedit.php:523 +msgid "This connection is blocked!" +msgstr "¡Esta conexión está bloqueada!" + +#: ../../mod/connedit.php:527 +msgid "Unignore" +msgstr "Dejar de ignorar" + +#: ../../mod/connedit.php:527 ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "Ignorar" + +#: ../../mod/connedit.php:530 +msgid "Ignore (or Unignore) all inbound communications from this connection" +msgstr "Ignorar (o dejar de ignorar) todas las comunicaciones entrantes de esta conexión" + +#: ../../mod/connedit.php:531 +msgid "This connection is ignored!" +msgstr "¡Esta conexión es ignorada!" + +#: ../../mod/connedit.php:535 +msgid "Unarchive" +msgstr "Desarchivar" + +#: ../../mod/connedit.php:535 +msgid "Archive" +msgstr "Archivar" + +#: ../../mod/connedit.php:538 +msgid "" +"Archive (or Unarchive) this connection - mark channel dead but keep content" +msgstr "Archiva (o desarchiva) esta conexión - marca el canal como muerto aunque mantiene sus contenidos" + +#: ../../mod/connedit.php:539 +msgid "This connection is archived!" +msgstr "¡Esta conexión esta archivada!" + +#: ../../mod/connedit.php:543 +msgid "Unhide" +msgstr "Mostrar" + +#: ../../mod/connedit.php:543 +msgid "Hide" +msgstr "Ocultar" + +#: ../../mod/connedit.php:546 +msgid "Hide or Unhide this connection from your other connections" +msgstr "Ocultar o mostrar esta conexión a sus otras conexiones" + +#: ../../mod/connedit.php:547 +msgid "This connection is hidden!" +msgstr "¡Esta conexión está oculta!" + +#: ../../mod/connedit.php:554 +msgid "Delete this connection" +msgstr "Eliminar esta conexión" + +#: ../../mod/connedit.php:635 +msgid "Approve this connection" +msgstr "Aprobar esta conexión" + +#: ../../mod/connedit.php:635 +msgid "Accept connection to allow communication" +msgstr "Aceptar la conexión para permitir la comunicación" + +#: ../../mod/connedit.php:640 +msgid "Set Affinity" +msgstr "Ajustar Afinidad" + +#: ../../mod/connedit.php:643 +msgid "Set Profile" +msgstr "Ajustar Perfil" + +#: ../../mod/connedit.php:646 +msgid "Set Affinity & Profile" +msgstr "Ajustar Afinidad y Perfil" + +#: ../../mod/connedit.php:663 +msgid "Apply these permissions automatically" +msgstr "Aplicar estos permisos automaticamente" + +#: ../../mod/connedit.php:665 +msgid "This connection's address is" +msgstr "Esta dirección de conexión es" + +#: ../../mod/connedit.php:668 +msgid "" +"The permissions indicated on this page will be applied to all new " +"connections." +msgstr "Los permisos indicados en esta página serán aplicados en todas las nuevas conexiones." + +#: ../../mod/connedit.php:670 +msgid "Slide to adjust your degree of friendship" +msgstr "Deslizar para ajustar el grado de amistad" + +#: ../../mod/connedit.php:672 +msgid "Slide to adjust your rating" +msgstr "Deslizar para ajustar su valoración" + +#: ../../mod/connedit.php:673 ../../mod/connedit.php:678 +msgid "Optionally explain your rating" +msgstr "Opcionalmente, puede explicar su valoración" + +#: ../../mod/connedit.php:675 +msgid "Custom Filter" +msgstr "Filtro Personalizado" + +#: ../../mod/connedit.php:676 +msgid "Only import posts with this text" +msgstr "Importar solo entradas que contengan este texto" + +#: ../../mod/connedit.php:676 ../../mod/connedit.php:677 +msgid "" +"words one per line or #tags or /patterns/, leave blank to import all posts" +msgstr "Palabras, una por línea o #etiquetas o /patrones/, dejar en blanco para importar todas las entradas" + +#: ../../mod/connedit.php:677 +msgid "Do not import posts with this text" +msgstr "No importes entradas conteniendo este texto" + +#: ../../mod/connedit.php:679 +msgid "This information is public!" +msgstr "Esta información es pública!" + +#: ../../mod/connedit.php:684 +msgid "Connection Pending Approval" +msgstr "Conexión Pendiente de Aprobación" + +#: ../../mod/connedit.php:685 +msgid "Connection Request" +msgstr "Petición de Conexión" + +#: ../../mod/connedit.php:686 +#, php-format +msgid "" +"(%s) would like to connect with you. Please approve this connection to allow" +" communication." +msgstr "(%s) desearía conectar contigo. por favor, aprueba esta conexión para permitir la comunicación." + +#: ../../mod/connedit.php:688 +msgid "Approve Later" +msgstr "Aprobar Más Tarde" + +#: ../../mod/connedit.php:691 +msgid "inherited" +msgstr "heredado" + +#: ../../mod/connedit.php:693 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Por favor, escoja el perfil que quiere mostrar a %s cuando esté viendo su perfil de forma segura." + +#: ../../mod/connedit.php:695 +msgid "Their Settings" +msgstr "Sus Ajustes" + +#: ../../mod/connedit.php:696 +msgid "My Settings" +msgstr "Mis Ajustes" + +#: ../../mod/connedit.php:698 +msgid "Individual Permissions" +msgstr "Permisos Individuales" + +#: ../../mod/connedit.php:699 +msgid "" +"Some permissions may be inherited from your channel's privacy settings, which have higher " +"priority than individual settings. You can not change those" +" settings here." +msgstr "Algunos permisos pueden ser heredados de los ajustes de privacidad de sus canales, los cuales tienen una prioridad más alta que los ajustes individuales. No puede cambiar estos ajustes aquí." + +#: ../../mod/connedit.php:700 +msgid "" +"Some permissions may be inherited from your channel's privacy settings, which have higher " +"priority than individual settings. You can change those settings here but " +"they wont have any impact unless the inherited setting changes." +msgstr "Algunos permisos pueden ser heredados de los ajustes de privacidad de sus canales, los cuales tienen una prioridad más alta que los ajustes individuales. Puede cambiar estos ajustes aquí pero no tendrán ningún impacto hasta que cambie los ajustes heredados." + +#: ../../mod/connedit.php:701 +msgid "Last update:" +msgstr "Última actualización:" + +#: ../../mod/rmagic.php:40 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Encontramos un problema durante el inicio de sesión con la OpenID que proporcionaste. por favor, comprueba la escritura correcta de la ID." + +#: ../../mod/rmagic.php:40 +msgid "The error message was:" +msgstr "El mensaje de error fue:" + +#: ../../mod/rmagic.php:44 +msgid "Authentication failed." +msgstr "Falló la autenticación." + +#: ../../mod/rmagic.php:84 +msgid "Remote Authentication" +msgstr "Acceso desde su servidor" + +#: ../../mod/rmagic.php:85 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "Introduzca la dirección del canal (p.e. channel@example.com)" + +#: ../../mod/rmagic.php:86 +msgid "Authenticate" +msgstr "Identifíquese" + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "No ha sido posible de " + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "Incapaz de comunicar con el canal solicitado." + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "No puedo verificar el canal solicitado." + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "El canal seleccionado tiene restricciones sobre los mensajes privados. El envió falló." + +#: ../../mod/mail.php:139 +msgid "Message deleted." +msgstr "Mensaje eliminado." + +#: ../../mod/mail.php:156 +msgid "Message recalled." +msgstr "Mensaje recuperado." + +#: ../../mod/mail.php:225 +msgid "Send Private Message" +msgstr "Envía un Mensaje Privado" + +#: ../../mod/mail.php:226 ../../mod/mail.php:343 +msgid "To:" +msgstr "Para:" + +#: ../../mod/mail.php:231 ../../mod/mail.php:345 +msgid "Subject:" +msgstr "Asunto:" + +#: ../../mod/mail.php:242 +msgid "Send" +msgstr "Envia" + +#: ../../mod/mail.php:269 +msgid "Message not found." +msgstr "No se encuentra el mensaje." + +#: ../../mod/mail.php:312 +msgid "Delete message" +msgstr "Mensaje eliminado" + +#: ../../mod/mail.php:313 +msgid "Recall message" +msgstr "Mensaje recuperado" + +#: ../../mod/mail.php:315 +msgid "Message has been recalled." +msgstr "El mensaje ha sido recuperado." + +#: ../../mod/mail.php:332 +msgid "Private Conversation" +msgstr "Conversación Privada" + +#: ../../mod/mail.php:338 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Comunicación segura no disponible. Pero puede responder desde la página de perfil del remitente." + +#: ../../mod/mail.php:342 +msgid "Send Reply" +msgstr "Envía Respuesta" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Petición inválida del identificador." + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "Descarta" + +#: ../../mod/regmod.php:11 +msgid "Please login." +msgstr "Por favor, inicia sesión." + +#: ../../mod/post.php:235 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please" +" logout and retry." +msgstr "La autenticación desde su servidor está bloqueada. Ha iniciado sesión localmente. Por favor, salga de la sesión y vuelva a intentarlo." + +#: ../../mod/new_channel.php:109 +msgid "Add a Channel" +msgstr "Añade un Canal" + +#: ../../mod/new_channel.php:110 +msgid "" +"A channel is your own collection of related web pages. A channel can be used" +" to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "Un canal es su propia colección de páginas web relacionadas. Un canal se puede utilizar para almacenar los perfiles sociales de la red, blogs, grupos de conversación y foros, páginas de famosos y mucho más. Puede crear tantos canales como su proveedor de servicio permita." + +#: ../../mod/new_channel.php:113 +msgid "Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " +msgstr "Ejemplos: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " + +#: ../../mod/new_channel.php:114 +msgid "Choose a short nickname" +msgstr "Elija un alias corto" + +#: ../../mod/new_channel.php:115 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "Su alias podrá usarse para crear una dirección de canal fácilmente memorizable (como una dirección de correo electrónico) el cual puede ser compartido con otros." + +#: ../../mod/new_channel.php:116 +msgid "Or import an existing channel from another location" +msgstr "O importar un canal existente de otro lugar" + +#: ../../mod/new_channel.php:118 +msgid "" +"Please choose a channel type (such as social networking or community forum) " +"and privacy requirements so we can select the best permissions for you" +msgstr "elija el tipo de canal (como red social o foro de comunidad) y la privacidad que requiera, así podemos seleccionar el mejor conjunto de permisos para usted" + +#: ../../mod/new_channel.php:119 +msgid "Channel Type" +msgstr "Tipo de Canal" + +#: ../../mod/new_channel.php:119 +msgid "Read more about roles" +msgstr "Lea más sobre los roles" + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "Aplicación instalada." + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "Aplicación malformada" + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "codigo embebido" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "Modificar la aplicación" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "Crear una aplicación" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "Nombre de la aplicación" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "Ubicación (URL) de la aplicación" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "Foto del icono URL" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "80 x 80 pixels - opcional" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "Versión ID" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "Precio de la aplicación" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "Ubicación (URL) para conseguir la aplicación" + +#: ../../mod/ping.php:263 +msgid "sent you a private message" +msgstr "envia un mensaje privado" + +#: ../../mod/ping.php:314 +msgid "added your channel" +msgstr "se añadió su canal" + +#: ../../mod/ping.php:355 +msgid "posted an event" +msgstr "publicó un evento" + +#: ../../mod/layouts.php:176 +msgid "Comanche page description language help" +msgstr "Página de ayuda de la descripción del lenguaje Comanche" + +#: ../../mod/layouts.php:180 +msgid "Layout Description" +msgstr "Descripción del Formato Gráfico" + +#: ../../mod/layouts.php:185 +msgid "Download PDL file" +msgstr "Descarga el fichero PDL" + +#: ../../mod/home.php:73 +#, php-format +msgid "Welcome to %s" +msgstr "Bienvenido a %s" + +#: ../../mod/page.php:126 +msgid "Lorem Ipsum" +msgstr "Lorem Ipsum" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "Marcador añadido" + +#: ../../mod/bookmarks.php:60 +msgid "My Bookmarks" +msgstr "Mis Marcadores" + +#: ../../mod/bookmarks.php:71 +msgid "My Connections Bookmarks" +msgstr "Mis Marcadores de Conexiones" + +#: ../../mod/channel.php:97 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "Permisos insuficientes. Petición redirigida a la página de perfil." + +#: ../../mod/pconfig.php:27 ../../mod/pconfig.php:60 +msgid "This setting requires special processing and editing has been blocked." +msgstr "Este ajuste necesita de un proceso especial y la edición ha sido bloqueada." + +#: ../../mod/pconfig.php:49 +msgid "Configuration Editor" +msgstr "Editor de Configuración" + +#: ../../mod/pconfig.php:50 +msgid "" +"Warning: Changing some settings could render your channel inoperable. Please" +" leave this page unless you are comfortable with and knowledgeable about how" +" to correctly use this feature." +msgstr "Atención: El cambio de algunos ajustes puede convertir su canal en inoperable. Por favor, abandone la página excepto que esté seguro y sepa cómo usar correctamente esta característica." + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "No hay sugerencias disponibles. Si es un sitio nuevo, espere 24 horas y pruebe de nuevo." + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "Sondea" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "Mostrar Resultados" + +#: ../../mod/service_limits.php:19 +msgid "No service class restrictions found." +msgstr "No se han encontrado clases de restricción de servicio." + +#: ../../mod/sharedwithme.php:94 +msgid "Files: shared with me" +msgstr "Ficheros: compartidos conmigo" + +#: ../../mod/sharedwithme.php:96 +msgid "NEW" +msgstr "NUEVO" + +#: ../../mod/sharedwithme.php:99 +msgid "Remove all files" +msgstr "Borrar todos los ficheros" + +#: ../../mod/sharedwithme.php:100 +msgid "Remove this file" +msgstr "Borra este archivo" + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "Esquema Predeterminado" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "Sans-Serif" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "Monospace" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Theme settings" +msgstr "Ajustes de tema" + +#: ../../view/theme/apw/php/config.php:260 +msgid "Set scheme" +msgstr "Ajustar esquema" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set font-size for posts and comments" +msgstr "Ajustar el tamaño del tipo de letra para entradas y comentarios" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "Ajustar el tipo de letra" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "Ajustar el conjunto de iconos" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "Ajustar el sombreado grande, por defecto 15px 15px 15px" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "Ajustar el sombreado pequeño, por defecto 5px 5px 5px" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "Ajustar el color del sombreado, predeterminado a #000" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "Ajusta el tamaño del radio, predeterminado a 5px" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "Ajustar la altura de linea para entradas y comentarios" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "Ajusta la imagen de fondo" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "Ajustar el fondo adjuntado" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "Ajustar el color de fondo" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "Ajustar la imagen de la sección del fondo" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "Ajustar el color de la sección del fondo" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "Ajustar el color de los elementos - utilizar código hexadecimal" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "Ajusta el color de los enlaces - utilizar código hexadecimal" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "Ajustar la anchura máxima para los elementos. Predeterminado a 400px" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "Ajustar la anchura mínima para los elementos. Predeterminado a 240px" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "Ajustar el ancho de la envoltura del contenido genérico. Predeterminado 48%" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "Ajustar el color del tipo de letra - utiliza código hexadecimal" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "Ajustar el tamaño de fondo del elemento" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "Opacidad del elemento" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "Muestra solo las previsualizaciones de las entradas" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "Muestra la barra lateral en la página del canal" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "Color de la barra de navegación" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "Elemento flotante" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "Desplazamiento izquierdo del elemento de la sección" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "Desplazamiento derecho del elemento de la sección" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "Ancho de la sección" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "Desplazamiento izquierdo del lateral" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "Desplazamiento derecho del elemento lateral" + +#: ../../view/theme/redbasic/php/config.php:82 +msgid "Light (Red Matrix default)" +msgstr "Ligero (Red Matrix predeterminado)" + +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Select scheme" +msgstr "Elija un esquema" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Narrow navbar" +msgstr "Estrechar la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar background color" +msgstr "Color de fondo de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation bar gradient top color" +msgstr "Color superior del gradiente de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation bar gradient bottom color" +msgstr "Color inferior del gradiente de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation active button gradient top color" +msgstr "Color superior del gradiente del botón activo de navegación" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation active button gradient bottom color" +msgstr "Color inferior del gradiente del botón activo de navegación" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar border color " +msgstr "Color del borde de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "Navigation bar icon color " +msgstr "Color del icono de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Navigation bar active icon color " +msgstr "Color del icono activo de la barra de navegación" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "link color" +msgstr "Color del enlace" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set font-color for banner" +msgstr "Ajustar el color del tipo de letra para la pancarta" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color" +msgstr "Ajustar el color de fondo" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background image" +msgstr "Ajustar la imagen de fondo" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the background color of items" +msgstr "Ajustar el color de los elementos de fondo" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the background color of comments" +msgstr "Ajustar el color de fondo de los comentarios" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the border color of comments" +msgstr "Ajustar el color del borde de los comentarios" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the indent for comments" +msgstr "Ajusta la indentación de los comentarios" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set the basic color for item icons" +msgstr "Ajustar el color básico para los iconos de los elementos" + +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set the hover color for item icons" +msgstr "Ajustar el color flotante para los iconos de los elementos" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-size for the entire application" +msgstr "Ajustar el tamaño del tipo de letra para toda la aplicación" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Example: 14px" +msgstr "Ejemplo: 14px" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set font-color for posts and comments" +msgstr "Establecer el color de la fuente para publicaciones y comentarios" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set radius of corners" +msgstr "Establecer el radio de curvatura de las esquinas" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Set shadow depth of photos" +msgstr "Ajustar la profundidad de sombras de las fotos" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set maximum width of content region in pixel" +msgstr "Ajustar la anchura máxima de la región de contenido, en pixels" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Leave empty for default width" +msgstr "Dejar en blanco para la anchura predeterminada" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Center page content" +msgstr "Contenido del centro de la página" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "Ajustar la opacidad mínima de la barra de navegación - para ocultarla" + +#: ../../view/theme/redbasic/php/config.php:131 +msgid "Set size of conversation author photo" +msgstr "Ajustar el tamaño de la foto del autor de la conversación" + +#: ../../view/theme/redbasic/php/config.php:132 +msgid "Set size of followup author photos" +msgstr "Ajustar el tamaño de foto de los seguidores del autor" + +#: ../../boot.php:1356 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "La actualización %s ha fallado. Mire el informe de errores." + +#: ../../boot.php:1359 +#, php-format +msgid "Update Error at %s" +msgstr "Error de Actualización en %s" + +#: ../../boot.php:1526 +msgid "" +"Create an account to access services and applications within the Red Matrix" +msgstr "Crear una cuenta para acceder a los servicios y aplicaciones dentro de la red" + +#: ../../boot.php:1554 +msgid "Password" +msgstr "Contraseña" + +#: ../../boot.php:1555 +msgid "Remember me" +msgstr "Recuérdeme" + +#: ../../boot.php:1558 +msgid "Forgot your password?" +msgstr "¿Olvidó su contraseña?" + +#: ../../boot.php:2178 +msgid "toggle mobile" +msgstr "cambiar a móvil" + +#: ../../boot.php:2313 +msgid "Website SSL certificate is not valid. Please correct." +msgstr "El certificado SSL del sitio web no es válido. Por favor, corríjalo." + +#: ../../boot.php:2316 +#, php-format +msgid "[red] Website SSL error for %s" +msgstr "[red] SSL error de Sitio Web en %s" + +#: ../../boot.php:2353 +msgid "Cron/Scheduled tasks not running." +msgstr "Las tareas de Cron/Planificador no funcionan." + +#: ../../boot.php:2357 +#, php-format +msgid "[red] Cron tasks not running on %s" +msgstr "[red] Las tareas de Cron no están funcionando en %s" diff --git a/sources/view/es/passchanged_eml.tpl b/sources/view/es/passchanged_eml.tpl new file mode 100644 index 00000000..be6ad74d --- /dev/null +++ b/sources/view/es/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Estimado {{$username}}, + Su contraseña ha sido cambiada, tal como pidió. Por favor, guarde esta +información en sus registros ( o cambie la contraseña inmediatamente +a alguna que pueda recordar). + + +Los detalles del inicio de sesión son los siguientes: + +Localización del Sitio: {{$siteurl}} +Nombre de usuario: {{$email}} +Contraseña: {{$new_password}} + +Puede cambiar esta contraseña desde su cuenta después de iniciar sesión. + + +Atentamente, + Administrador de {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/es/register_open_eml.tpl b/sources/view/es/register_open_eml.tpl new file mode 100644 index 00000000..74e5ba46 --- /dev/null +++ b/sources/view/es/register_open_eml.tpl @@ -0,0 +1,19 @@ + +Una cuenta ha sido creada en {{$sitename}} con esta dirección de correo electrónico. +Los detalles del inicio de sesión son los siguientes: + +Localización del Sitio: {{$siteurl}} +Nombre de usuario: {{$email}} +Contraseña: (la contraseña que proporcionó durante el proceso de registro) + +Si esta cuenta se creó sin su consentimiento y no es deseada, puedes +visitar el sitio y cambiar la contraseña. Esto le permitirá eliminar la +cuenta de los enlaces en la página de Ajustes, le +pedimos disculpas por cualquier inconveniente que hayamos podido causar. + +gracias y bienvenido a {{$sitename}}. + +Atentamente, + Administrador de {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/es/register_verify_eml.tpl b/sources/view/es/register_verify_eml.tpl new file mode 100644 index 00000000..4eabaacc --- /dev/null +++ b/sources/view/es/register_verify_eml.tpl @@ -0,0 +1,24 @@ + +Una nueva petición de registro de usuario se ha recibido en {{$sitename}}, que requiere +su aprobación. + + +Los detalles del inicio de sesión son los siguientes: + +Localización del Sitio: {{$siteurl}} +Nombre de usuario: {{$email}} +Dirección IP: {{$details}} + +Para aprobar la petición siga el enlace: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +Para denegar la petición y eliminar la cuenta , siga: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Gracias. diff --git a/sources/view/es/register_verify_member.tpl b/sources/view/es/register_verify_member.tpl new file mode 100644 index 00000000..202c4111 --- /dev/null +++ b/sources/view/es/register_verify_member.tpl @@ -0,0 +1,24 @@ + +Gracias por registrarse en {{$sitename}}. + +Los detalles del inicio de sesión son los siguientes: + +Localización del Sitio: {{$siteurl}} +Nombre de usuario: {{$email}} + +inicie la sesión con la contraseña que elegió durante el registro. + +Necesitamos verificar su correo electrónico para poder darle pleno acceso. + +Si registró esta cuenta, por favor, siga el enlace: + +{{$siteurl}}/regver/allow/{{$hash}} + + +Para denegar la petición y eliminar la cuenta , siga: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Gracias. diff --git a/sources/view/es/strings.php b/sources/view/es/strings.php new file mode 100644 index 00000000..02a9047a --- /dev/null +++ b/sources/view/es/strings.php @@ -0,0 +1,2148 @@ +strings["Cannot locate DNS info for database server '%s'"] = "No se ha podido localizar información para el servidor de base de datos “%sâ€"; +$a->strings["Profile Photos"] = "Fotos de perfil"; +$a->strings["Edit"] = "Editar"; +$a->strings["Frequently"] = "Frecuentemente"; +$a->strings["Hourly"] = "Cada hora"; +$a->strings["Twice daily"] = "Dos veces al día"; +$a->strings["Daily"] = "Diariamente"; +$a->strings["Weekly"] = "Semanalmente"; +$a->strings["Monthly"] = "Mensualmente"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Email"] = "Correo electrónico"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "LinkedIn"; +$a->strings["XMPP/IM"] = "XMPP/IM"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["created a new post"] = "Crear una nueva entrada"; +$a->strings["commented on %s's post"] = "comentar la entrada de %s"; +$a->strings["No username found in import file."] = "No se ha encontrado el nombre de usuario en el archivo importado."; +$a->strings["Unable to create a unique channel address. Import failed."] = "No se ha podido crear una dirección de canal única. Ha fallado la importación."; +$a->strings["Import completed."] = "Importación completada."; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "Un grupo suprimido con éste nombre ha sido reestablecido. Es posible que los permisos existentes sean aplicados a éste grupo y sus futuros miembros. Si no quiere esto por favor cree otro grupo con un nombre diferente."; +$a->strings["Default privacy group for new contacts"] = "Grupo de privacidad por defecto para nuevos contactos "; +$a->strings["All Channels"] = "Todos los canales"; +$a->strings["edit"] = "editar"; +$a->strings["Collections"] = "Colecciones"; +$a->strings["Edit collection"] = "Editar colección"; +$a->strings["Add new collection"] = "Añadir nueva colección"; +$a->strings["Channels not in any collection"] = "El canal no se encuentra en ninguna colección"; +$a->strings["add"] = "añadir"; +$a->strings["Not a valid email address"] = "Dirección de correo inválida"; +$a->strings["Your email domain is not among those allowed on this site"] = "Su dirección de correo no pertenece a los dominios permitidos en este sitio."; +$a->strings["Your email address is already registered at this site."] = "Su dirección de correo está ya registrada en este sitio."; +$a->strings["An invitation is required."] = "Es obligatorio que le inviten."; +$a->strings["Invitation could not be verified."] = "No se ha podido verificar su invitación."; +$a->strings["Please enter the required information."] = "Por favor introduzca la información requerida."; +$a->strings["Failed to store account information."] = "La información de la cuenta no se ha podido guardar."; +$a->strings["Registration confirmation for %s"] = "Confirmación de registro para %s"; +$a->strings["Registration request at %s"] = "Solicitud de registro en %s"; +$a->strings["Administrator"] = "Administrador"; +$a->strings["your registration password"] = "su contraseña de registro"; +$a->strings["Registration details for %s"] = "Detalles del registro para %s"; +$a->strings["Account approved."] = "Cuenta aprobada."; +$a->strings["Registration revoked for %s"] = "Registro rechazado para %s"; +$a->strings["Account verified. Please login."] = "Cuenta verificada. Por favor, inicia sesión."; +$a->strings["Click here to upgrade."] = "Pulse aquí para actualizar"; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Ésta acción supera los límites establecidos por su plan de suscripción "; +$a->strings["This action is not available under your subscription plan."] = "Esta acción no está disponible en su plan de suscripción."; +$a->strings["Miscellaneous"] = "Varios"; +$a->strings["YYYY-MM-DD or MM-DD"] = "YYYY-MM-DD o MM-DD"; +$a->strings["Required"] = "Obligatorio"; +$a->strings["never"] = "nunca"; +$a->strings["less than a second ago"] = "hace un instante"; +$a->strings["year"] = "año"; +$a->strings["years"] = "años"; +$a->strings["month"] = "mes"; +$a->strings["months"] = "meses"; +$a->strings["week"] = "semana"; +$a->strings["weeks"] = "semanas"; +$a->strings["day"] = "día"; +$a->strings["days"] = "días"; +$a->strings["hour"] = "hora"; +$a->strings["hours"] = "horas"; +$a->strings["minute"] = "minuto"; +$a->strings["minutes"] = "minutos"; +$a->strings["second"] = "segundo"; +$a->strings["seconds"] = "segundos"; +$a->strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = "Hace %1\$d y %2\$s"; +$a->strings["%1\$s's birthday"] = "Cumpleaños de %1\$s"; +$a->strings["Happy Birthday %1\$s"] = "Feliz cumpleaños %1\$s"; +$a->strings["Directory Options"] = "Opciones del directorio"; +$a->strings["Safe Mode"] = "Modo seguro"; +$a->strings["No"] = "No"; +$a->strings["Yes"] = "Sí"; +$a->strings["Public Forums Only"] = "Solamente foros públicos"; +$a->strings["This Website Only"] = "Solamente este sitio web"; +$a->strings["New Page"] = "Nueva página"; +$a->strings["View"] = "Ver"; +$a->strings["Preview"] = "Previsualizar"; +$a->strings["Actions"] = "Acciones"; +$a->strings["Page Link"] = "Vínculo de la página"; +$a->strings["Title"] = "Título"; +$a->strings["Created"] = "Creado"; +$a->strings["Edited"] = "Editado"; +$a->strings["Public Timeline"] = "Cronología pública"; +$a->strings["Default"] = "Predeterminado"; +$a->strings["Delete this item?"] = "¿Borrar este elemento?"; +$a->strings["Comment"] = "Comentar"; +$a->strings["[+] show all"] = "[+] mostrar todo"; +$a->strings["[-] show less"] = "[-] mostrar menos"; +$a->strings["[+] expand"] = "[+] expandir"; +$a->strings["[-] collapse"] = "[-] contraer"; +$a->strings["Password too short"] = "Contraseña demasiado corta"; +$a->strings["Passwords do not match"] = "Las contraseñas no cinciden"; +$a->strings["everybody"] = "cualquiera"; +$a->strings["Secret Passphrase"] = "Contraseña secreta"; +$a->strings["Passphrase hint"] = "Pista de contraseña"; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = "Aviso: los permisos han cambiado pero aún no han sido enviados."; +$a->strings["close all"] = "cerrar todo"; +$a->strings["Nothing new here"] = "Nada nuevo por aquí"; +$a->strings["Rate This Channel (this is public)"] = "Valorar este canal (esto es público)"; +$a->strings["Rating"] = "Valoración"; +$a->strings["Describe (optional)"] = "Describir (opcional)"; +$a->strings["Submit"] = "Enviar"; +$a->strings["Please enter a link URL"] = "Por favor, introduzca una dirección de enlace"; +$a->strings["Unsaved changes. Are you sure you wish to leave this page?"] = "Cambios no guardados. ¿Está seguro que desea abandonar la página?"; +$a->strings["timeago.prefixAgo"] = "timeago.prefixAgo"; +$a->strings["timeago.prefixFromNow"] = "timeago.prefixFromNow"; +$a->strings["ago"] = "de su publicación"; +$a->strings["from now"] = "desde ahora"; +$a->strings["less than a minute"] = "menos de un minuto"; +$a->strings["about a minute"] = "alrededor de un minuto"; +$a->strings["%d minutes"] = "%d minutos"; +$a->strings["about an hour"] = "alrededor de una hora"; +$a->strings["about %d hours"] = "alrededor de %d horas"; +$a->strings["a day"] = "un día"; +$a->strings["%d days"] = "%d días"; +$a->strings["about a month"] = "alrededor de un mes"; +$a->strings["%d months"] = "%d meses"; +$a->strings["about a year"] = "alrededor de un año"; +$a->strings["%d years"] = "%d años"; +$a->strings[" "] = " "; +$a->strings["timeago.numbers"] = "timeago.numbers"; +$a->strings["prev"] = "previa"; +$a->strings["first"] = "Primera"; +$a->strings["last"] = "última"; +$a->strings["next"] = "próxima"; +$a->strings["older"] = "más antiguas"; +$a->strings["newer"] = "más recientes"; +$a->strings["No connections"] = "Sin conexiones"; +$a->strings["%d Connection"] = array( + 0 => "%d conexión", + 1 => "%d conexiones", +); +$a->strings["View Connections"] = "Ver conexiones"; +$a->strings["Search"] = "Buscar"; +$a->strings["Save"] = "Guardar"; +$a->strings["poke"] = "dar un toque"; +$a->strings["poked"] = "ha recibido un toque"; +$a->strings["ping"] = "avisar"; +$a->strings["pinged"] = " le hicieron un ping"; +$a->strings["prod"] = "incitar"; +$a->strings["prodded"] = "incitaros"; +$a->strings["slap"] = "abofetear"; +$a->strings["slapped"] = "abofeteado"; +$a->strings["finger"] = "señalar"; +$a->strings["fingered"] = "manosear"; +$a->strings["rebuff"] = "desairar"; +$a->strings["rebuffed"] = "desairado"; +$a->strings["happy"] = "feliz"; +$a->strings["sad"] = "triste"; +$a->strings["mellow"] = "amable"; +$a->strings["tired"] = "cansado/a"; +$a->strings["perky"] = "fesco/a"; +$a->strings["angry"] = "enfadado/a"; +$a->strings["stupified"] = "estupefacto/a"; +$a->strings["puzzled"] = "perplejo/a"; +$a->strings["interested"] = "interesado/a"; +$a->strings["bitter"] = "amargado/a"; +$a->strings["cheerful"] = "alegre"; +$a->strings["alive"] = "vivo/a"; +$a->strings["annoyed"] = "molesto/a"; +$a->strings["anxious"] = "ansioso/a"; +$a->strings["cranky"] = "de mal humor"; +$a->strings["disturbed"] = "perturbado/a"; +$a->strings["frustrated"] = "frustrado/a"; +$a->strings["depressed"] = "deprimido"; +$a->strings["motivated"] = "motivado/a"; +$a->strings["relaxed"] = "relajado/a"; +$a->strings["surprised"] = "sorprendido/a"; +$a->strings["Monday"] = "Lunes"; +$a->strings["Tuesday"] = "Martes"; +$a->strings["Wednesday"] = "Miércoles"; +$a->strings["Thursday"] = "Jueves"; +$a->strings["Friday"] = "Viernes"; +$a->strings["Saturday"] = "Sábado"; +$a->strings["Sunday"] = "Domingo"; +$a->strings["January"] = "Enero"; +$a->strings["February"] = "Febrero"; +$a->strings["March"] = "Marzo"; +$a->strings["April"] = "Abril"; +$a->strings["May"] = "Mayo"; +$a->strings["June"] = "Junio"; +$a->strings["July"] = "Julio"; +$a->strings["August"] = "Agosto"; +$a->strings["September"] = "Septiembre"; +$a->strings["October"] = "Octubre"; +$a->strings["November"] = "Noviembre"; +$a->strings["December"] = "Diciembre"; +$a->strings["unknown.???"] = "desconocido.???"; +$a->strings["bytes"] = "bytes"; +$a->strings["remove category"] = "eliminar categoría"; +$a->strings["remove from file"] = "eliminar del archivo"; +$a->strings["Click to open/close"] = "Pulsar para abrir/cerrar"; +$a->strings["Link to Source"] = "Ir al mensaje original"; +$a->strings["default"] = "por defecto"; +$a->strings["Page layout"] = "Disposición de página"; +$a->strings["You can create your own with the layouts tool"] = "Puede crear la suya propia con la herramienta de disposiciones"; +$a->strings["Page content type"] = "Tipo de contenido de página"; +$a->strings["Select an alternate language"] = "Selecciona un idioma alternativo"; +$a->strings["photo"] = "foto"; +$a->strings["event"] = "evento"; +$a->strings["status"] = "estado"; +$a->strings["comment"] = "comentario"; +$a->strings["activity"] = "actividad"; +$a->strings["Design Tools"] = "Herramientas de diseño"; +$a->strings["Blocks"] = "Bloques"; +$a->strings["Menus"] = "Menús"; +$a->strings["Layouts"] = "Disposiciones"; +$a->strings["Pages"] = "Páginas"; +$a->strings["Collection"] = "Colección"; +$a->strings["parent"] = "padre"; +$a->strings["Principal"] = "Principal"; +$a->strings["Addressbook"] = "Libreta de direcciones"; +$a->strings["Calendar"] = "Calendario"; +$a->strings["Schedule Inbox"] = "Programar bandeja de entrada"; +$a->strings["Schedule Outbox"] = "Programar bandeja de salida"; +$a->strings["Unknown"] = "Desconocido"; +$a->strings["%1\$s used"] = "%1\$s usado"; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = "%1\$s usado de %2\$s (%3\$s%)"; +$a->strings["Files"] = "Ficheros"; +$a->strings["Total"] = "Total"; +$a->strings["Shared"] = "Compartido"; +$a->strings["Create"] = "Crear"; +$a->strings["Upload"] = "Subir"; +$a->strings["Name"] = "Nombre"; +$a->strings["Type"] = "Tipo"; +$a->strings["Size"] = "Tamaño"; +$a->strings["Last Modified"] = "Última modificación"; +$a->strings["Delete"] = "Borrar"; +$a->strings["Create new folder"] = "Crear nueva carpeta"; +$a->strings["Upload file"] = "Subir archivo"; +$a->strings["%1\$s's bookmarks"] = "Marcadores de %1\$s"; +$a->strings["view full size"] = "Ver a pantalla completa"; +$a->strings["\$Projectname Notification"] = "Notificación de \$Projectname"; +$a->strings["\$projectname"] = "\$projectname"; +$a->strings["Thank You,"] = "Gracias,"; +$a->strings["%s Administrator"] = "%s Administrador"; +$a->strings["No Subject"] = "Sin asunto"; +$a->strings["General Features"] = "Características generales"; +$a->strings["Content Expiration"] = "Expiración del contenido"; +$a->strings["Remove posts/comments and/or private messages at a future time"] = "Eliminar publicaciones/comentarios y/o mensajes privados más adelante"; +$a->strings["Multiple Profiles"] = "Múltiples perfiles"; +$a->strings["Ability to create multiple profiles"] = "Capacidad de crear múltiples perfiles"; +$a->strings["Advanced Profiles"] = "Perfiles avanzados"; +$a->strings["Additional profile sections and selections"] = "Secciones y selecciones de perfil adicionales"; +$a->strings["Profile Import/Export"] = "Importar/Exportar perfil"; +$a->strings["Save and load profile details across sites/channels"] = "Guardar y cargar detalles del perfil a través de sitios/canales"; +$a->strings["Web Pages"] = "Páginas web"; +$a->strings["Provide managed web pages on your channel"] = "Proveer páginas web gestionadas en su canal"; +$a->strings["Private Notes"] = "Notas privadas"; +$a->strings["Enables a tool to store notes and reminders"] = "Activa una herramienta para almacenar notas y recordatorios"; +$a->strings["Navigation Channel Select"] = "Selección de navegación de canal"; +$a->strings["Change channels directly from within the navigation dropdown menu"] = "Cambiar canales directamente desde el menú de navegación desplegable"; +$a->strings["Photo Location"] = "Ubicación de las fotos"; +$a->strings["If location data is available on uploaded photos, link this to a map."] = "Si los datos de ubicación están disponibles en las fotos subidas, enlaza esto a un mapa."; +$a->strings["Expert Mode"] = "Modo de experto"; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = "Habilitar el modo de experto para acceder a opciones avanzadas de configuración"; +$a->strings["Premium Channel"] = "Canal premium"; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = "Les permite configurar restricciones y normas de uso a aquellos que conectan con su canal"; +$a->strings["Post Composition Features"] = "Características de composición de entradas"; +$a->strings["Use Markdown"] = "Usar Markdown"; +$a->strings["Allow use of \"Markdown\" to format posts"] = "Permitir el uso de \"Markdown\" para formatear publicaciones"; +$a->strings["Large Photos"] = "Fotos de gran tamaño"; +$a->strings["Include large (640px) photo thumbnails in posts. If not enabled, use small (320px) photo thumbnails"] = "Incluir miniaturas de foto grandes (640px) en publicaciones. Si no está habilitado, usar miniaturas pequeñas (320px)"; +$a->strings["Channel Sources"] = "Fuentes del canal"; +$a->strings["Automatically import channel content from other channels or feeds"] = "Importar automáticamente contenido de otros canales o fuentes"; +$a->strings["Even More Encryption"] = "Más cifrado todavía"; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = "Permitir cifrado adicional de contenido punto-a-punto con una clave secreta compartida."; +$a->strings["Enable voting tools"] = "Activar herramientas de votación"; +$a->strings["Provide a class of post which others can vote on"] = "Proveer una clase de publicación en la que otros puedan votar"; +$a->strings["Network and Stream Filtering"] = "Filtrado de red y flujo"; +$a->strings["Search by Date"] = "Buscar por fecha"; +$a->strings["Ability to select posts by date ranges"] = "Capacidad de seleccionar entradas por rango de fechas"; +$a->strings["Collections Filter"] = "Filtrado de colecciones"; +$a->strings["Enable widget to display Network posts only from selected collections"] = "Habilitar la muestra de entradas de red eligiendo colecciones"; +$a->strings["Saved Searches"] = "Búsquedas Guardadas"; +$a->strings["Save search terms for re-use"] = "Guardar términos de búsqueda para su reutilización"; +$a->strings["Network Personal Tab"] = "Pestaña de red personal"; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = "Habilitar una pestaña en la cual se muestran solo entradas de red en las que ha participado."; +$a->strings["Network New Tab"] = "Nueva pestaña de red"; +$a->strings["Enable tab to display all new Network activity"] = "Habilitar una pestaña en la cual se muestra toda la actividad de la red"; +$a->strings["Affinity Tool"] = "Herramienta de afinidad"; +$a->strings["Filter stream activity by depth of relationships"] = "Filtrar la actividad del flujo por profundidad de relaciones"; +$a->strings["Connection Filtering"] = "Filtrado de conexiones"; +$a->strings["Filter incoming posts from connections based on keywords/content"] = "Filtrar publicaciones entrantes de conexiones basadas en palabras clave / contenido"; +$a->strings["Suggest Channels"] = "Sugerir canales"; +$a->strings["Show channel suggestions"] = "Mostrar sugerencias de canales"; +$a->strings["Post/Comment Tools"] = "Herramientas de entradas/comentarios"; +$a->strings["Tagging"] = "Etiquetado"; +$a->strings["Ability to tag existing posts"] = "Capacidad de etiquetar entradas existentes"; +$a->strings["Post Categories"] = "Categorías de entradas"; +$a->strings["Add categories to your posts"] = "Añadir categorías a sus publicaciones"; +$a->strings["Saved Folders"] = "Carpetas guardadas"; +$a->strings["Ability to file posts under folders"] = "Capacidad de archivar entradas en carpetas"; +$a->strings["Dislike Posts"] = "No me gusta:"; +$a->strings["Ability to dislike posts/comments"] = "Capacidad de mostrar desacuerdo con el contenido de entradas/comentarios"; +$a->strings["Star Posts"] = "Entrada destacada"; +$a->strings["Ability to mark special posts with a star indicator"] = "Capacidad de marcar entradas destacadas con un indicador de estrella"; +$a->strings["Tag Cloud"] = "Nube de etiquetas"; +$a->strings["Provide a personal tag cloud on your channel page"] = "Proveer nube de etiquetas personal en su página de canal"; +$a->strings["Categories"] = "Categorías"; +$a->strings["Apps"] = "Aplicaciones"; +$a->strings["System"] = "Sistema"; +$a->strings["Personal"] = "Personales"; +$a->strings["Create Personal App"] = "Crear una aplicación personal"; +$a->strings["Edit Personal App"] = "Editar una aplicación personal"; +$a->strings["Connect"] = "Conectar"; +$a->strings["Ignore/Hide"] = "Ignorar/Ocultar"; +$a->strings["Suggestions"] = "Sugerencias"; +$a->strings["See more..."] = "Ver más..."; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = "Tiene %1$.0f de %2$.0f conexiones permitidas."; +$a->strings["Add New Connection"] = "Añadir nueva conección"; +$a->strings["Enter the channel address"] = "Introduzca la dirección del canal"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Ejemplo: paco@ejemplo.com, http://ejemplo.com/paco"; +$a->strings["Notes"] = "Notas"; +$a->strings["Remove term"] = "Eliminar término"; +$a->strings["Everything"] = "Todo"; +$a->strings["Archives"] = "Hemeroteca"; +$a->strings["Me"] = "Yo"; +$a->strings["Family"] = "Familia"; +$a->strings["Friends"] = "Amigos"; +$a->strings["Acquaintances"] = "Conocidos/as"; +$a->strings["All"] = "Todos"; +$a->strings["Refresh"] = "Refrescar"; +$a->strings["Account settings"] = "Configuración de la cuenta"; +$a->strings["Channel settings"] = "Configuración del canal"; +$a->strings["Additional features"] = "Características adicionales"; +$a->strings["Feature/Addon settings"] = "Configuración de característica/complemento"; +$a->strings["Display settings"] = "Configuración de visualización"; +$a->strings["Connected apps"] = "Aplicaciones conectadas"; +$a->strings["Export channel"] = "Exportar canal"; +$a->strings["Connection Default Permissions"] = "Permisos predeterminados de conexión"; +$a->strings["Premium Channel Settings"] = "Configuración del canal premium"; +$a->strings["Settings"] = "Ajustes"; +$a->strings["Messages"] = "Mensajes"; +$a->strings["Check Mail"] = "Comprobar correo"; +$a->strings["New Message"] = "Nuevo mensaje"; +$a->strings["Chat Rooms"] = "Salas de chat"; +$a->strings["Bookmarked Chatrooms"] = "Salas de chat favoritas"; +$a->strings["Suggested Chatrooms"] = "Salas de chat sugeridas"; +$a->strings["photo/image"] = "foto/imagen"; +$a->strings["Rate Me"] = "Valorar este canal"; +$a->strings["View Ratings"] = "Ver valoraciones"; +$a->strings["Public Hubs"] = "Servidores públicos"; +$a->strings["l F d, Y \\@ g:i A"] = "l d de F, Y \\@ G:i"; +$a->strings["Starts:"] = "Comienza:"; +$a->strings["Finishes:"] = "Finaliza:"; +$a->strings["Location:"] = "Ubicación:"; +$a->strings["This event has been added to your calendar."] = "Este evento ha sido añadido a su calendario."; +$a->strings["%s "] = "%s "; +$a->strings["[Red:Notify] New mail received at %s"] = "[Red notifica] Nuevo correo recibido en %s"; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s te ha enviado un nuevo mensaje privado en %3\$s."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s te envió %2\$s."; +$a->strings["a private message"] = "un mensaje privado"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Por favor visite %s para ver y/o responder a su mensaje privado."; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s comentó sobre [zrl=%3\$s]a %4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s comentó sobre [zrl=%3\$s]%4\$s's %5\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s comentó sobre [zrl=%3\$s]your %4\$s[/zrl]"; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red notifica] Comentario en la conversación #%1\$d por %2\$s"; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s comentó sobre un elemento/conversación que ha estado siguiendo."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Para ver o comentar la conversación, visita %s"; +$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Notify] %s escribió en su muro"; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s publicó en su muro de perfil en %3\$s"; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s publicó en [zrl=%3\$s]su muro[/zrl]"; +$a->strings["[Red:Notify] %s tagged you"] = "[Red notifica] %s le etiquetó"; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s le etiquetó en %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]le etiquetó[/zrl]."; +$a->strings["[Red:Notify] %1\$s poked you"] = "[Red aviso] %1\$s ha recibido un toque"; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s recibió un toque en %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]recibió un toque[/zrl]."; +$a->strings["[Red:Notify] %s tagged your post"] = "[Red notifica] %s etiquetó su entrada"; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s etiquetó su publicación en %3\$s"; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s etiquetó [zrl=%3\$s]su publicación[/zrl]"; +$a->strings["[Red:Notify] Introduction received"] = "[Red notifica] S\nDemanda de amistad recibida"; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, ha recibido una nueva solicitud de conexión de '%2\$s' en %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, ha recibido [zrl=%2\$s]una nueva solicitud de conexión[/zrl] de %3\$s."; +$a->strings["You may visit their profile at %s"] = "Puede visitar su perfil en %s"; +$a->strings["Please visit %s to approve or reject the connection request."] = "Por favor, visita %s para permitir o rechazar la solicitd de conexión."; +$a->strings["[Red:Notify] Friend suggestion received"] = "[Red notifica] recibió una sugerencia de amistad"; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, ha recibido una sugerencia de un amigo de '%2\$s' en %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, ha recibido [zrl=%2\$s]una sugerencia de amistad[/zrl] para %3\$s de %4\$s."; +$a->strings["Name:"] = "Nombre:"; +$a->strings["Photo:"] = "Foto:"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Por favor, visite %s para aprobar o rechazar la sugerencia."; +$a->strings["[Red:Notify]"] = "[Red:Notify]"; +$a->strings["No recipient provided."] = "No se ha especificado ningún destinatario."; +$a->strings["[no subject]"] = "[sin asunto]"; +$a->strings["Unable to determine sender."] = "No ha sido posible de determinar el remitente. "; +$a->strings["Stored post could not be verified."] = "No se ha podido verificar las entradas guardadas."; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "a %1\$s le gusta el %3\$s de %2\$s"; +$a->strings["Please choose"] = "Por favor selecciona"; +$a->strings["Agree"] = "De acuerdo"; +$a->strings["Disagree"] = "En desacuerdo"; +$a->strings["Abstain"] = "Abstención"; +$a->strings["Channel is blocked on this site."] = "El canal está bloqueado en éste sitio."; +$a->strings["Channel location missing."] = "Falta la dirección del canal "; +$a->strings["Response from remote channel was incomplete."] = "Respuesta del canal remoto incompleta."; +$a->strings["Channel was deleted and no longer exists."] = "El canal ha sido eliminado y ya no existe."; +$a->strings["Protocol disabled."] = "Protocolo deshabilitado."; +$a->strings["Protocol blocked for this channel."] = "Protocolo bloqueado para este canal."; +$a->strings["Channel discovery failed."] = "Búsqueda de canales ha fallado."; +$a->strings["local account not found."] = "No se ha encontrado la cuenta local."; +$a->strings["Cannot connect to yourself."] = "No puede conectarse consigo mismo."; +$a->strings["Private Message"] = "Mensaje Privado"; +$a->strings["Select"] = "Seleccionar"; +$a->strings["Save to Folder"] = "Guardar en carpeta"; +$a->strings["I will attend"] = "Participaré"; +$a->strings["I will not attend"] = "No participaré"; +$a->strings["I might attend"] = "Quizá asista"; +$a->strings["I agree"] = "Estoy de acuerdo"; +$a->strings["I disagree"] = "No estoy de acuerdo"; +$a->strings["I abstain"] = "Me abstengo"; +$a->strings["View all"] = "Ver todo"; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "Me gusta", + 1 => "Me gusta", +); +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "No me gusta", + 1 => "No me gusta", +); +$a->strings["Add Star"] = "Añadir estrella"; +$a->strings["Remove Star"] = "Eliminar estrella"; +$a->strings["Toggle Star Status"] = "Activa o desactiva el estado de preferido"; +$a->strings["starred"] = "preferidos"; +$a->strings["Message signature validated"] = "Firma de mensaje validada"; +$a->strings["Message signature incorrect"] = "Firma de mensaje incorrecta"; +$a->strings["Add Tag"] = "Añadir etiqueta"; +$a->strings["I like this (toggle)"] = "me gusta (cambiar)"; +$a->strings["like"] = "Me gusta"; +$a->strings["I don't like this (toggle)"] = "No me gusta (cambiar)"; +$a->strings["dislike"] = "No me gusta"; +$a->strings["Share This"] = "Compartir esto"; +$a->strings["share"] = "Compartir"; +$a->strings["%d comment"] = array( + 0 => "%d comentario", + 1 => "%d comentarios", +); +$a->strings["View %s's profile - %s"] = "Ver perfil de %s - %s"; +$a->strings["to"] = "a"; +$a->strings["via"] = "mediante"; +$a->strings["Wall-to-Wall"] = "Muro-a-Muro"; +$a->strings["via Wall-To-Wall:"] = "mediante Muro-a-Muro"; +$a->strings["from %s"] = "desde %s"; +$a->strings["last edited: %s"] = "último cambio: %s"; +$a->strings["Expires: %s"] = "Caduca: %s"; +$a->strings["Save Bookmarks"] = "Guardar marcadores"; +$a->strings["Add to Calendar"] = "Añadir al calendario"; +$a->strings["Mark all seen"] = "Marcar todos como vistos"; +$a->strings["__ctx:noun__ Likes"] = "Me gusta"; +$a->strings["__ctx:noun__ Dislikes"] = "No me gusta"; +$a->strings["Close"] = "Cerrar"; +$a->strings["Please wait"] = "Espera por favor"; +$a->strings["This is you"] = "Este es usted"; +$a->strings["Bold"] = "Negrita"; +$a->strings["Italic"] = "Itálico "; +$a->strings["Underline"] = "Subrayar"; +$a->strings["Quote"] = "Citar"; +$a->strings["Code"] = "Código"; +$a->strings["Image"] = "Imagen"; +$a->strings["Insert Link"] = "Insertar enlace"; +$a->strings["Video"] = "Vídeo"; +$a->strings["Encrypt text"] = "Cifrar texto"; +$a->strings["New window"] = "Nueva ventana"; +$a->strings["Open the selected location in a different window or browser tab"] = "Abrir la ubicación seleccionada en una ventana o pestaña aparte"; +$a->strings["User '%s' deleted"] = "Usuario '%s' eliminado"; +$a->strings["Attachments:"] = "Ficheros adjuntos:"; +$a->strings["\$Projectname event notification:"] = "Notificación de eventos de \$Projectname:"; +$a->strings["Logout"] = "Cerrar sesión"; +$a->strings["End this session"] = "Cerrar ésta sesión"; +$a->strings["Home"] = "Inicio"; +$a->strings["Your posts and conversations"] = "Sus entradas y conversaciones"; +$a->strings["View Profile"] = "Ver perfil"; +$a->strings["Your profile page"] = "Su página de perfil"; +$a->strings["Edit Profiles"] = "Editar perfiles"; +$a->strings["Manage/Edit profiles"] = "Administrar/editar perfiles"; +$a->strings["Edit Profile"] = "Editar perfil"; +$a->strings["Edit your profile"] = "Editar su perfil"; +$a->strings["Photos"] = "Fotos"; +$a->strings["Your photos"] = "Sus fotos"; +$a->strings["Your files"] = "Sus ficheros"; +$a->strings["Chat"] = "Chat"; +$a->strings["Your chatrooms"] = "Sus salas de chat"; +$a->strings["Bookmarks"] = "Marcadores"; +$a->strings["Your bookmarks"] = "Sus marcadores"; +$a->strings["Webpages"] = "Páginas web"; +$a->strings["Your webpages"] = "Sus páginas web"; +$a->strings["Login"] = "Iniciar sesión"; +$a->strings["Sign in"] = "Acceder"; +$a->strings["%s - click to logout"] = "%s - pulsar para cerrar sesión"; +$a->strings["Remote authentication"] = "Acceder desde su servidor"; +$a->strings["Click to authenticate to your home hub"] = "Pulsar para identificarse en su servidor"; +$a->strings["Home Page"] = "Página de inicio"; +$a->strings["Register"] = "Registrarse"; +$a->strings["Create an account"] = "Crear una cuenta"; +$a->strings["Help"] = "Ayuda"; +$a->strings["Help and documentation"] = "Ayuda y documentación"; +$a->strings["Applications, utilities, links, games"] = "Aplicaciones, utilidades, enlaces, juegos"; +$a->strings["Search site content"] = "Buscar contenido del sitio"; +$a->strings["Directory"] = "Directorio"; +$a->strings["Channel Directory"] = "Directorio de canales"; +$a->strings["Matrix"] = "Matríz"; +$a->strings["Your matrix"] = "Su red"; +$a->strings["Mark all matrix notifications seen"] = "Marcar todas las notificaciones de la red como leídas"; +$a->strings["Channel Home"] = "Mi canal"; +$a->strings["Channel home"] = "Mi canal"; +$a->strings["Mark all channel notifications seen"] = "Marcar todas las notificaciones de canales como leídas"; +$a->strings["Connections"] = "Conexiones"; +$a->strings["Notices"] = "Avisos"; +$a->strings["Notifications"] = "Notificaciones"; +$a->strings["See all notifications"] = "Ver todas las notificaciones"; +$a->strings["Mark all system notifications seen"] = "Marcar todas las notificaciones de sistema como leídas"; +$a->strings["Mail"] = "Correo"; +$a->strings["Private mail"] = "Correo privado"; +$a->strings["See all private messages"] = "Ver todas los mensajes privados"; +$a->strings["Mark all private messages seen"] = "Marcar todos los mensajes privados como leídos"; +$a->strings["Inbox"] = "Bandeja de entrada"; +$a->strings["Outbox"] = "Bandeja de salida"; +$a->strings["Events"] = "Eventos"; +$a->strings["Event Calendar"] = "Calendario de eventos"; +$a->strings["See all events"] = "Ver todos los eventos"; +$a->strings["Mark all events seen"] = "Marcar todos los eventos como leidos"; +$a->strings["Channel Manager"] = "Administración del canal"; +$a->strings["Manage Your Channels"] = "Gestione sus canales"; +$a->strings["Account/Channel Settings"] = "Ajustes de cuenta/canales"; +$a->strings["Admin"] = "Administrador"; +$a->strings["Site Setup and Configuration"] = "Configuración del sitio"; +$a->strings["Loading..."] = "Cargando..."; +$a->strings["@name, #tag, content"] = "@nombre, #etiqueta, contenido"; +$a->strings["Please wait..."] = "Espere por favor…"; +$a->strings["Tags"] = "Etiquetas"; +$a->strings["Keywords"] = "Palabras clave"; +$a->strings["have"] = "tener"; +$a->strings["has"] = "tiene"; +$a->strings["want"] = "quiere"; +$a->strings["wants"] = "quiere"; +$a->strings["likes"] = "le gusta"; +$a->strings["dislikes"] = "no le gusta"; +$a->strings[" and "] = "y"; +$a->strings["public profile"] = "perfil público"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s cambió %2\$s a “%3\$s”"; +$a->strings["Visit %1\$s's %2\$s"] = "Visita %2\$s de %1\$s"; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s actualizó %2\$s, %3\$s cambió."; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "El token de seguridad del formulario no es correcto. Esto ha ocurrido probablemente porque el formulario ha estado abierto demasiado tiempo (>3 horas) antes de ser enviado"; +$a->strings["Can view my normal stream and posts"] = "Puede ver mi flujo y publicaciones normales"; +$a->strings["Can view my default channel profile"] = "Puede ver mi perfil de canal predeterminado."; +$a->strings["Can view my photo albums"] = "Puede ver mis álbumes de fotos"; +$a->strings["Can view my connections"] = "Puede ver mis conexiones"; +$a->strings["Can view my file storage"] = "Puede ver mis ficheros almacenados"; +$a->strings["Can view my webpages"] = "Puede ver mis páginas web"; +$a->strings["Can send me their channel stream and posts"] = "Te pueden enviar sus canales de flujos y entradas"; +$a->strings["Can post on my channel page (\"wall\")"] = "Pueden crear entradas en su página del canal (“muroâ€)"; +$a->strings["Can comment on or like my posts"] = "Puede comentar en mis publicaciones o marcar como 'me gusta'."; +$a->strings["Can send me private mail messages"] = "Puede enviarme mensajes privados"; +$a->strings["Can post photos to my photo albums"] = "Puede publicar fotos en mis galerias"; +$a->strings["Can like/dislike stuff"] = "Puede marcar contenido como me gustar/no me gusta."; +$a->strings["Profiles and things other than posts/comments"] = "Perfiles y cosas aparte de publicaciones/comentarios"; +$a->strings["Can forward to all my channel contacts via post @mentions"] = "Puede reenviar a todos mis contactos de canalmediante post @mentions"; +$a->strings["Advanced - useful for creating group forum channels"] = "Avanzado - útil para crear canales de foro o grupos"; +$a->strings["Can chat with me (when available)"] = "Puede charlar conmigo"; +$a->strings["Can write to my file storage"] = "Puede escribir en mi almacenamiento de ficheros"; +$a->strings["Can edit my webpages"] = "Puede editar mis páginas web"; +$a->strings["Can source my public posts in derived channels"] = "Puede utilizar como fuente mis publicaciones públicas en canales derivados"; +$a->strings["Somewhat advanced - very useful in open communities"] = "Algo avanzado - muy útil en comunidades abiertas"; +$a->strings["Can administer my channel resources"] = "Puede administrar mis recursos de canal"; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Muy avanzado. Déjelo a no ser que sepa bien lo que está haciendo."; +$a->strings["Social Networking"] = "Creación de redes sociales"; +$a->strings["Mostly Public"] = "Público en su mayor parte"; +$a->strings["Restricted"] = "Restringido"; +$a->strings["Private"] = "Privado"; +$a->strings["Community Forum"] = "Foro de la comunidad"; +$a->strings["Feed Republish"] = "Republicar feed"; +$a->strings["Special Purpose"] = "Propósito especial"; +$a->strings["Celebrity/Soapbox"] = "Celebridad / Plataforma improvisada"; +$a->strings["Group Repository"] = "Repositorio de grupo"; +$a->strings["Other"] = "Otro"; +$a->strings["Custom/Expert Mode"] = "Modo personalizado/experto"; +$a->strings["channel"] = "canal"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "a %1\$s no le gusta el %3\$s de %2\$s"; +$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s ahora está conectado con %2\$s"; +$a->strings["%1\$s poked %2\$s"] = "%1\$s dio un toque a %2\$s"; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s está %2\$s"; +$a->strings["__ctx:title__ Likes"] = "Me gusta"; +$a->strings["__ctx:title__ Dislikes"] = "No me gusta"; +$a->strings["__ctx:title__ Agree"] = "De acuerdo"; +$a->strings["__ctx:title__ Disagree"] = "En desacuerdo"; +$a->strings["__ctx:title__ Abstain"] = "Abstenerse"; +$a->strings["__ctx:title__ Attending"] = "Participar"; +$a->strings["__ctx:title__ Not attending"] = "No participar"; +$a->strings["__ctx:title__ Might attend"] = "Quizá participe"; +$a->strings["View %s's profile @ %s"] = "Ver perfil @ %s de %s"; +$a->strings["Categories:"] = "Categorías:"; +$a->strings["Filed under:"] = "Archivado bajo:"; +$a->strings["View in context"] = "Mostrar en su contexto"; +$a->strings["remove"] = "eliminar"; +$a->strings["Delete Selected Items"] = "Eliminar elementos seleccionados"; +$a->strings["View Source"] = "Ver fuente"; +$a->strings["Follow Thread"] = "Seguir el hilo"; +$a->strings["View Status"] = "Ver estado"; +$a->strings["View Photos"] = "Ver fotos"; +$a->strings["Matrix Activity"] = "Actividad en la red"; +$a->strings["Edit Contact"] = "Editar contacto"; +$a->strings["Send PM"] = "Enviar Mensaje Privado"; +$a->strings["Poke"] = "Dar un toque"; +$a->strings["%s likes this."] = "a %s le gusta esto."; +$a->strings["%s doesn't like this."] = "a %s no le gusta esto."; +$a->strings["%2\$d people like this."] = array( + 0 => "a %2\$d persona le gusta esto.", + 1 => "a %2\$d personas les gusta esto.", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "a %2\$d persona no le gusta esto.", + 1 => "a %2\$d personas no les gusta esto.", +); +$a->strings["and"] = "y"; +$a->strings[", and %d other people"] = array( + 0 => ", y %d persona más", + 1 => ", y %d personas más", +); +$a->strings["%s like this."] = "a %s le gusta esto."; +$a->strings["%s don't like this."] = "a %s no le gusta esto."; +$a->strings["Visible to everybody"] = "Visible para cualquiera"; +$a->strings["Please enter a link URL:"] = "Por favor, introduzca una URL de enlace:"; +$a->strings["Please enter a video link/URL:"] = "Por favor, introduzca un enlace/URL de vídeo:"; +$a->strings["Please enter an audio link/URL:"] = "Por favor, introduzca un enlace/URL de audio:"; +$a->strings["Tag term:"] = "Término de etiqueta:"; +$a->strings["Save to Folder:"] = "Guardar en carpeta:"; +$a->strings["Where are you right now?"] = "¿Donde está ahora?"; +$a->strings["Expires YYYY-MM-DD HH:MM"] = "Caduca YYYY-MM-DD HH:MM"; +$a->strings["Share"] = "Compartir"; +$a->strings["Page link name"] = "Nombre de enlace de página"; +$a->strings["Post as"] = "Publicar como"; +$a->strings["Upload photo"] = "Subir foto"; +$a->strings["upload photo"] = "subir foto"; +$a->strings["Attach file"] = "Adjuntar archivo"; +$a->strings["attach file"] = "adjuntar archivo"; +$a->strings["Insert web link"] = "Insertar enlace web"; +$a->strings["web link"] = "enlace web"; +$a->strings["Insert video link"] = "Insertar enlace de vídeo"; +$a->strings["video link"] = "enlace de vídeo"; +$a->strings["Insert audio link"] = "Insertar enlace de audio"; +$a->strings["audio link"] = "enlace de audio"; +$a->strings["Set your location"] = "Configure su localización"; +$a->strings["set location"] = "configura localización"; +$a->strings["Toggle voting"] = "Invertir votación"; +$a->strings["Clear browser location"] = "Eliminar localización del navegador"; +$a->strings["clear location"] = "eliminar localización"; +$a->strings["Title (optional)"] = "Título (opcional)"; +$a->strings["Categories (optional, comma-separated list)"] = "Categorías (opcional, lista separada por comas)"; +$a->strings["Permission settings"] = "Configuración de permisos"; +$a->strings["permissions"] = "permisos"; +$a->strings["Public post"] = "Publicación pública"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Ejemplo: bob@example.com, mary@example.com"; +$a->strings["Set expiration date"] = "Configurar fecha de expiración"; +$a->strings["OK"] = "OK"; +$a->strings["Cancel"] = "Cancelar"; +$a->strings["Discover"] = "Descubrir"; +$a->strings["Imported public streams"] = "Flujos públicos importados"; +$a->strings["Commented Order"] = "Comentarios recientes"; +$a->strings["Sort by Comment Date"] = "Ordenar por fecha de comentario"; +$a->strings["Posted Order"] = "Publicaciones recientes"; +$a->strings["Sort by Post Date"] = "Ordenar por fecha de publicación"; +$a->strings["Posts that mention or involve you"] = "Publicaciones que le mencionan o involucran"; +$a->strings["New"] = "Novedades"; +$a->strings["Activity Stream - by date"] = "Flujo de actividad - por fecha"; +$a->strings["Starred"] = "Preferidos"; +$a->strings["Favourite Posts"] = "Publicaciones favoritas"; +$a->strings["Spam"] = "Correo basura"; +$a->strings["Posts flagged as SPAM"] = "Publicaciones marcadas como basura"; +$a->strings["Channel"] = "Canal"; +$a->strings["Status Messages and Posts"] = "Mensajes de estado y publicaciones"; +$a->strings["About"] = "Perfil"; +$a->strings["Profile Details"] = "Detalles de perfil"; +$a->strings["Photo Albums"] = "Ãlbumes de fotos"; +$a->strings["Files and Storage"] = "Ficheros y almacenamiento"; +$a->strings["Chatrooms"] = "Salas de chat"; +$a->strings["Saved Bookmarks"] = "Marcadores guardados"; +$a->strings["Manage Webpages"] = "Administrar páginas web"; +$a->strings["__ctx:noun__ Attending"] = array( + 0 => "Asistir", + 1 => "Participar", +); +$a->strings["__ctx:noun__ Not Attending"] = array( + 0 => "No asistir", + 1 => "No participar", +); +$a->strings["__ctx:noun__ Undecided"] = array( + 0 => "Indeciso/a", + 1 => "Indecisos/as", +); +$a->strings["__ctx:noun__ Agree"] = array( + 0 => "Está de acuerdo", + 1 => "Están de acuerdo", +); +$a->strings["__ctx:noun__ Disagree"] = array( + 0 => "No está de acuerdo", + 1 => "No están de acuerdo", +); +$a->strings["__ctx:noun__ Abstain"] = array( + 0 => "se abstiene", + 1 => "Abstenerse", +); +$a->strings["Permission denied"] = "Permiso denegado"; +$a->strings["(Unknown)"] = "(Desconocido)"; +$a->strings["Visible to anybody on the internet."] = "Visible para todo el mundo en internet."; +$a->strings["Visible to you only."] = "Visible sólo para usted."; +$a->strings["Visible to anybody in this network."] = "Visible para cualquiera en esta red."; +$a->strings["Visible to anybody authenticated."] = "Visible para cualquiera autenticado."; +$a->strings["Visible to anybody on %s."] = "Visible para cualquiera en %s."; +$a->strings["Visible to all connections."] = "Visible para todas las conexiones."; +$a->strings["Visible to approved connections."] = "Visible para conexiones permitidas."; +$a->strings["Visible to specific connections."] = "Visible para conexiones específicas."; +$a->strings["Item not found."] = "Elemento no encontrado."; +$a->strings["Permission denied."] = "Acceso denegado."; +$a->strings["Collection not found."] = "Colección no encontrada."; +$a->strings["Collection is empty."] = "La colección está vacía."; +$a->strings["Collection: %s"] = "Colección: %s"; +$a->strings["Connection: %s"] = "Conexión: %s"; +$a->strings["Connection not found."] = "Conexión no encontrada"; +$a->strings["Invalid data packet"] = "Paquete de datos inválido"; +$a->strings["Unable to verify channel signature"] = "No ha sido posible de verificar la signatura del canal"; +$a->strings["Unable to verify site signature for %s"] = "No ha sido posible de verificar la signatura del sitio para %s"; +$a->strings["Embedded content"] = "Contenido incrustado"; +$a->strings["Embedding disabled"] = "Incrustación deshabilitada"; +$a->strings["Logged out."] = "Desconectado."; +$a->strings["Failed authentication"] = "Autenticación fallida."; +$a->strings["Login failed."] = "Login ha fallado."; +$a->strings["%d invitation available"] = array( + 0 => "%d invitación pendiente", + 1 => "%d invitaciones pendientes", +); +$a->strings["Advanced"] = "Avanzado"; +$a->strings["Find Channels"] = "Encontrar canales"; +$a->strings["Enter name or interest"] = "Introducir nombre o interés"; +$a->strings["Connect/Follow"] = "Conectar/Seguir"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Ejemplos: José Fernández, Pesca"; +$a->strings["Find"] = "Encontrar"; +$a->strings["Channel Suggestions"] = "Sugerencias de canales"; +$a->strings["Random Profile"] = "Perfil aleatorio"; +$a->strings["Invite Friends"] = "Invitar amigos"; +$a->strings["Advanced example: name=fred and country=iceland"] = "Ejemplo avanzado: nombre=fred y pais=islandia"; +$a->strings["%d connection in common"] = array( + 0 => "%d conexión en común", + 1 => "%d conexiones en común", +); +$a->strings["show more"] = "mostrar más"; +$a->strings["Visible to your default audience"] = "Visible para su público predeterminado."; +$a->strings["Show"] = "Mostrar"; +$a->strings["Don't show"] = "No mostrar"; +$a->strings["Permissions"] = "Permisos"; +$a->strings["Item was not found."] = "Elemento no encontrado."; +$a->strings["No source file."] = "Ningún archivo de fuente"; +$a->strings["Cannot locate file to replace"] = "No se puede localizar el archivo a ser sustituido."; +$a->strings["Cannot locate file to revise/update"] = "No se puede localizar el archivo para revisar/actualizar"; +$a->strings["File exceeds size limit of %d"] = "Archivo supera el limite de tamaño de %d"; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Ha alcanzado su límite de %1$.0f Mbytes de almacenamiento de adjuntos."; +$a->strings["File upload failed. Possible system limit or action terminated."] = "Error de carga, posiblemente por limite de sistema o terminación de acción"; +$a->strings["Stored file could not be verified. Upload failed."] = "El archivo almacenado no ha podido ser verificado. El envío ha fallado."; +$a->strings["Path not available."] = "Ruta no disponible."; +$a->strings["Empty pathname"] = "Ruta vacía"; +$a->strings["duplicate filename or path"] = "Nombre de ruta o archivo duplicado"; +$a->strings["Path not found."] = "Ruta no encontrada"; +$a->strings["mkdir failed."] = "mkdir ha fallado."; +$a->strings["database storage failed."] = "almacenamiento en base de datos ha fallado."; +$a->strings["Unable to obtain identity information from database"] = "No ha sido posible de obtener la información de identidad de la base de datos"; +$a->strings["Empty name"] = "Nombre vacío"; +$a->strings["Name too long"] = "Nombre demasiado largo"; +$a->strings["No account identifier"] = "Ningún identificador de la cuenta"; +$a->strings["Nickname is required."] = "Se requiere un sobrenombre (alias)."; +$a->strings["Reserved nickname. Please choose another."] = "Sobrenombre en uso. Por favor, elija otro."; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = "El apodo contiene caracteres no admitidos o está ya en uso por otros usuarios de éste sitio."; +$a->strings["Unable to retrieve created identity"] = "No ha sido posible de conseguir la identidad creada"; +$a->strings["Default Profile"] = "Perfil principal"; +$a->strings["Requested channel is not available."] = "El canal solicitado no está disponible."; +$a->strings["Requested profile is not available."] = "El perfil solicitado no está disponible."; +$a->strings["Change profile photo"] = "Cambiar foto de perfil"; +$a->strings["Profiles"] = "Perfiles"; +$a->strings["Manage/edit profiles"] = "Administrar/editar perfiles"; +$a->strings["Create New Profile"] = "Crear nuevo perfil"; +$a->strings["Profile Image"] = "Imagen de perfil"; +$a->strings["visible to everybody"] = "visible para todos"; +$a->strings["Edit visibility"] = "Editar visibilidad"; +$a->strings["Gender:"] = "Género:"; +$a->strings["Status:"] = "Estado:"; +$a->strings["Homepage:"] = "Página web:"; +$a->strings["Online Now"] = "Ahora en línea"; +$a->strings["g A l F d"] = "g A l F d"; +$a->strings["F d"] = "F d"; +$a->strings["[today]"] = "[hoy]"; +$a->strings["Birthday Reminders"] = "Recordatorios de cumpleaños"; +$a->strings["Birthdays this week:"] = "Cumpleaños esta semana:"; +$a->strings["[No description]"] = "[Sin descripción]"; +$a->strings["Event Reminders"] = "Recordatorios de eventos"; +$a->strings["Events this week:"] = "Eventos de esta semana:"; +$a->strings["Profile"] = "Perfil"; +$a->strings["Full Name:"] = "Nombre completo:"; +$a->strings["Like this channel"] = "Me gusta este canal"; +$a->strings["j F, Y"] = "j F, Y"; +$a->strings["j F"] = "j F"; +$a->strings["Birthday:"] = "Cumpleaños:"; +$a->strings["Age:"] = "Edad:"; +$a->strings["for %1\$d %2\$s"] = "por %1\$d %2\$s"; +$a->strings["Sexual Preference:"] = "Orientación sexual:"; +$a->strings["Hometown:"] = "Ciudad de origen:"; +$a->strings["Tags:"] = "Etiquetas:"; +$a->strings["Political Views:"] = "Posición política:"; +$a->strings["Religion:"] = "Religión:"; +$a->strings["About:"] = "Sobre mí:"; +$a->strings["Hobbies/Interests:"] = "Aficciones/Intereses:"; +$a->strings["Likes:"] = "Me gusta:"; +$a->strings["Dislikes:"] = "No me gusta:"; +$a->strings["Contact information and Social Networks:"] = "Información de contacto y redes sociales:"; +$a->strings["My other channels:"] = "Mis otros canales:"; +$a->strings["Musical interests:"] = "Intereses musicales:"; +$a->strings["Books, literature:"] = "Libros, literatura:"; +$a->strings["Television:"] = "Televisión:"; +$a->strings["Film/dance/culture/entertainment:"] = "Cine/baile/cultura/entretenimiento:"; +$a->strings["Love/Romance:"] = "Amor/romance:"; +$a->strings["Work/employment:"] = "Trabajo/empleo:"; +$a->strings["School/education:"] = "Estudios:"; +$a->strings["Like this thing"] = "Me gusta esto"; +$a->strings["Male"] = "Hombre"; +$a->strings["Female"] = "Mujer"; +$a->strings["Currently Male"] = "Actualmente hombre"; +$a->strings["Currently Female"] = "Actualmente mujer"; +$a->strings["Mostly Male"] = "Generalmente hombre"; +$a->strings["Mostly Female"] = "Generalmente mujer"; +$a->strings["Transgender"] = "Transgénero"; +$a->strings["Intersex"] = "Intersexual"; +$a->strings["Transsexual"] = "Transexual"; +$a->strings["Hermaphrodite"] = "Hermafrodita"; +$a->strings["Neuter"] = "Neutral"; +$a->strings["Non-specific"] = "No-especificada"; +$a->strings["Undecided"] = "Indecidido"; +$a->strings["Males"] = "Hombres"; +$a->strings["Females"] = "Mujeres"; +$a->strings["Gay"] = "Gay"; +$a->strings["Lesbian"] = "Lesbiana"; +$a->strings["No Preference"] = "Sin preferencias"; +$a->strings["Bisexual"] = "Bisexual"; +$a->strings["Autosexual"] = "Autosexual"; +$a->strings["Abstinent"] = "Abstemio"; +$a->strings["Virgin"] = "Virgen"; +$a->strings["Deviant"] = "Fuera de lo común"; +$a->strings["Fetish"] = "Fetiche"; +$a->strings["Oodles"] = "Montones"; +$a->strings["Nonsexual"] = "No sexual"; +$a->strings["Single"] = "Soltero/a"; +$a->strings["Lonely"] = "Solo/a"; +$a->strings["Available"] = "Disponible"; +$a->strings["Unavailable"] = "No disponible"; +$a->strings["Has crush"] = "Enamorado/a"; +$a->strings["Infatuated"] = "Infatuado"; +$a->strings["Dating"] = "Citando"; +$a->strings["Unfaithful"] = "Infiel"; +$a->strings["Sex Addict"] = "Con adicción al sexo"; +$a->strings["Friends/Benefits"] = "Amistad beneficiosa"; +$a->strings["Casual"] = "Casual"; +$a->strings["Engaged"] = "Prometido/a"; +$a->strings["Married"] = "Casado/a"; +$a->strings["Imaginarily married"] = "Casado/a imaginario/a"; +$a->strings["Partners"] = "Pareja"; +$a->strings["Cohabiting"] = "Cohabitando"; +$a->strings["Common law"] = "Derecho común"; +$a->strings["Happy"] = "Felíz"; +$a->strings["Not looking"] = "No estoy buscando"; +$a->strings["Swinger"] = "Swinger"; +$a->strings["Betrayed"] = "Engañado/a"; +$a->strings["Separated"] = "Separado/a"; +$a->strings["Unstable"] = "Inestable"; +$a->strings["Divorced"] = "Divorciado/a"; +$a->strings["Imaginarily divorced"] = "Divorciado/a imaginario/a"; +$a->strings["Widowed"] = "Viudo/a"; +$a->strings["Uncertain"] = "Indeterminado"; +$a->strings["It's complicated"] = "Es complicado"; +$a->strings["Don't care"] = "No me importa"; +$a->strings["Ask me"] = "Pregúnteme"; +$a->strings["Site Admin"] = "Adminstrador del sitio"; +$a->strings["Address Book"] = "Libreta de direcciones"; +$a->strings["Mood"] = "Estado de ánimo"; +$a->strings["Probe"] = "Probar"; +$a->strings["Suggest"] = "Sugerir"; +$a->strings["Random Channel"] = "Canal aleatorio"; +$a->strings["Invite"] = "Invitar"; +$a->strings["Features"] = "Características"; +$a->strings["Language"] = "Idioma"; +$a->strings["Post"] = "Publicación"; +$a->strings["Profile Photo"] = "Foto de perfil"; +$a->strings["Update"] = "Actualizar"; +$a->strings["Install"] = "Instalar"; +$a->strings["Purchase"] = "Comprar"; +$a->strings["Image/photo"] = "Imagen/foto"; +$a->strings["Encrypted content"] = "Contenido encriptado"; +$a->strings["Install %s element: "] = "Instalar %s elemento:"; +$a->strings["This post contains an installable %s element, however you lack permissions to install it on this site."] = "Esta entrada contiene un elemento instalable %s, sin embargo le faltan permisos para instalarlo en este sitio."; +$a->strings["webpage"] = "página web"; +$a->strings["layout"] = "disposición"; +$a->strings["block"] = "bloquear"; +$a->strings["menu"] = "menú"; +$a->strings["QR code"] = "Código QR"; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s escribió la siguiente %2\$s %3\$s"; +$a->strings["post"] = "entrada"; +$a->strings["Different viewers will see this text differently"] = "Visitantes diferentes verán este texto de forma diferente"; +$a->strings["$1 spoiler"] = "alerón $1"; +$a->strings["$1 wrote:"] = "$1 escribió"; +$a->strings["Missing room name"] = "Nombre de sala desaparecido."; +$a->strings["Duplicate room name"] = "Nombre de sala duplicado."; +$a->strings["Invalid room specifier."] = "Especificador de sala inválido."; +$a->strings["Room not found."] = "Sala no encontrada."; +$a->strings["Room is full"] = "La sala está llena."; +$a->strings["Image exceeds website size limit of %lu bytes"] = "La imagen es demasiado grande (%lu demás)"; +$a->strings["Image file is empty."] = "El fichero de imagen ésta vacío. "; +$a->strings["Unable to process image"] = "No ha sido posible de procesar la imagen"; +$a->strings["Photo storage failed."] = "La foto no ha podido ser guardada."; +$a->strings["Upload New Photos"] = "Subir nuevas fotos"; +$a->strings["Some blurb about what to do when you're new here"] = "Algunas palabras sobre qué hacer cuando eres nuevo aquí"; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Ha creado %1$.0f de %2$.0f canales permitidos."; +$a->strings["Create a new channel"] = "Crear un nuevo canal"; +$a->strings["Current Channel"] = "Canal actual"; +$a->strings["Switch to one of your channels by selecting it."] = "Cambiar a uno de sus canales seleccionándolo."; +$a->strings["Default Channel"] = "Canal predeterminado"; +$a->strings["Make Default"] = "Convertir en predeterminado"; +$a->strings["%d new messages"] = "%d nuevos mensajes"; +$a->strings["%d new introductions"] = "%d nuevas introducciones"; +$a->strings["Delegated Channels"] = "Canales delegados"; +$a->strings["Public access denied."] = "Acceso público denegado."; +$a->strings["%d rating"] = array( + 0 => "%d valoración", + 1 => "%d valoraciones", +); +$a->strings["Gender: "] = "Género:"; +$a->strings["Status: "] = "Estado:"; +$a->strings["Homepage: "] = "Página de inicio:"; +$a->strings["Description:"] = "Descripción:"; +$a->strings["Public Forum:"] = "Foro público:"; +$a->strings["Keywords: "] = "Palabras clave:"; +$a->strings["Don't suggest"] = "No sugerir:"; +$a->strings["Common connections:"] = "Conexiones comunes:"; +$a->strings["Global Directory"] = "Directorio global:"; +$a->strings["Local Directory"] = "Directorio local:"; +$a->strings["Finding:"] = "Encontrar:"; +$a->strings["next page"] = "siguiente página"; +$a->strings["previous page"] = "página anterior"; +$a->strings["Sort options"] = "Ordenar opciones"; +$a->strings["Alphabetic"] = "Alfabético"; +$a->strings["Reverse Alphabetic"] = "Alfabético inverso"; +$a->strings["Newest to Oldest"] = "Más nuevo a más antiguo"; +$a->strings["Oldest to Newest"] = "Más antiguo a más nuevo"; +$a->strings["No entries (some entries may be hidden)."] = "Sin entradas (algunas entradas pueden estar ocultas)."; +$a->strings["Xchan Lookup"] = "Búsqueda Xchan"; +$a->strings["Lookup xchan beginning with (or webbie): "] = "Buscar xchan que comience por (o webbie):"; +$a->strings["Not found."] = "No encontrado."; +$a->strings["Authorize application connection"] = "Autorizar conexión de aplicación"; +$a->strings["Return to your app and insert this Securty Code:"] = "Volver a su aplicación e introducir este código de seguridad:"; +$a->strings["Please login to continue."] = "Por favor inicia sesión para continuar."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "¿Desea autorizar a esta aplicación a acceder a sus publicaciones y contactos, y/o crear nuevas publicaciones por usted?"; +$a->strings["Page Title"] = "Título de página"; +$a->strings["Channel added."] = "Canal añadido."; +$a->strings["Tag removed"] = "Etiqueta eliminada."; +$a->strings["Remove Item Tag"] = "Eliminar etiqueta de elemento."; +$a->strings["Select a tag to remove: "] = "Selecciona una etiqueta a eliminar:"; +$a->strings["Remove"] = "Eliminar"; +$a->strings["Continue"] = "Continuar"; +$a->strings["Premium Channel Setup"] = "Configuración del canal premium"; +$a->strings["Enable premium channel connection restrictions"] = "Habilitar restricciones de conexión de canal premium"; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Por favor introduzca sus restricciones o condiciones, como recibo paypal, normas de uso, etc."; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Este canal puede requerir antes de conectar pasos adicionales o conocimiento de las siguientes condiciones:"; +$a->strings["Potential connections will then see the following text before proceeding:"] = "Las posibles conexiones verán por tanto el siguiente texto antes de proceder:"; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "Al continuar, certifico que he cumplido con todas las intrucciones proporcionadas en esta página."; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(No ha sido proporcionada ninguna instrucción específica por el propietario del canal.)"; +$a->strings["Restricted or Premium Channel"] = "Canal premium o restringido"; +$a->strings["Thing updated"] = "Elemento actualizado."; +$a->strings["Object store: failed"] = "Guardar objeto: ha fallado"; +$a->strings["Thing added"] = "Elemento añadido"; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = "OBJ: %1\$s %2\$s %3\$s"; +$a->strings["Show Thing"] = "Mostrar elemento"; +$a->strings["item not found."] = "elemento no encontrado."; +$a->strings["Edit Thing"] = "Editar elemento"; +$a->strings["Select a profile"] = "Seleccionar un perfil"; +$a->strings["Post an activity"] = "Publicar una actividad"; +$a->strings["Only sends to viewers of the applicable profile"] = "Sólo envíos a espectadores del perfil pertinente."; +$a->strings["Name of thing e.g. something"] = "Nombre del elemento e.g. algo"; +$a->strings["URL of thing (optional)"] = "URL del elemento (opcional)"; +$a->strings["URL for photo of thing (optional)"] = "URL para foto o elemento (opcional)"; +$a->strings["Add Thing to your Profile"] = "Añadir elemento a su perfil"; +$a->strings["Item not available."] = "Elemento no disponible"; +$a->strings["Fetching URL returns error: %1\$s"] = "Obtener URL retorna error: %1\$s"; +$a->strings["Image uploaded but image cropping failed."] = "Imagen actualizada pero recorte de imagen ha fallado. "; +$a->strings["Image resize failed."] = "Ajustar tamaño de imagen ha fallado."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Recargue la página o limpie caché del navegador si la nueva foto no se muestra inmediatamente."; +$a->strings["Image exceeds size limit of %d"] = "La imagen supera el límite de %d"; +$a->strings["Unable to process image."] = "No ha sido posible procesar la imagen."; +$a->strings["Photo not available."] = "Foto no disponible."; +$a->strings["Upload File:"] = "Subir archivo:"; +$a->strings["Select a profile:"] = "Seleccionar un perfil:"; +$a->strings["Upload Profile Photo"] = "Subir foto de perfil"; +$a->strings["or"] = "o"; +$a->strings["skip this step"] = "Omitir este paso"; +$a->strings["select a photo from your photo albums"] = "Seleccione una foto de sus álbums de fotos"; +$a->strings["Crop Image"] = "Recortar imagen"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Por favor ajuta el recorte de la imagen para una visión óptima."; +$a->strings["Done Editing"] = "Edición completada"; +$a->strings["Image uploaded successfully."] = "Imagen subida correctamente."; +$a->strings["Image upload failed."] = "Subida de imagen fallida."; +$a->strings["Image size reduction [%s] failed."] = "Reducción de la imagen [%s] fallida."; +$a->strings["Invalid item."] = "Elemento no válido."; +$a->strings["Channel not found."] = "Canal no encontrado."; +$a->strings["Page not found."] = "Página no encontrada."; +$a->strings["Like/Dislike"] = "Me gusta/No me gusta"; +$a->strings["This action is restricted to members."] = "Esta acción está restringida solo para miembros."; +$a->strings["Please login with your \$Projectname ID or register as a new \$Projectname member to continue."] = "Por favor, identifíquese con su \$Projectname ID o rregístrese como un nuevo \$Projectname member para continuar."; +$a->strings["Invalid request."] = "Solicitud incorrecta."; +$a->strings["thing"] = "elemento"; +$a->strings["Channel unavailable."] = "Canal no disponible."; +$a->strings["Previous action reversed."] = "Acción anterior revocada."; +$a->strings["%1\$s agrees with %2\$s's %3\$s"] = "%1\$s está de acuerdo con %3\$s de %2\$s"; +$a->strings["%1\$s doesn't agree with %2\$s's %3\$s"] = "%1\$s no está de acuerdo con %3\$s de %2\$s"; +$a->strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = "%1\$s se abstiene en %3\$s de %2\$s"; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%1\$s participará en el %3\$s de %2\$s"; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%1\$s no participará en el %3\$s de %2\$s"; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%1\$s tal vez participe en el %3\$s de %2\$s"; +$a->strings["Action completed."] = "Acción completada."; +$a->strings["Thank you."] = "Gracias."; +$a->strings["Calendar entries imported."] = "Entradas de calendario importadas."; +$a->strings["No calendar entries found."] = "No encontradas entradas de calendario."; +$a->strings["Event can not end before it has started."] = "Un evento no puede terminar antes de que haya comenzado."; +$a->strings["Unable to generate preview."] = "No se puede crear la vista previa."; +$a->strings["Event title and start time are required."] = "Se requieren el título del evento y su hora de inicio."; +$a->strings["Event not found."] = "Evento no encontrado."; +$a->strings["l, F j"] = "l j F"; +$a->strings["Edit event"] = "Editar evento"; +$a->strings["Delete event"] = "Borrar evento"; +$a->strings["calendar"] = "calendario"; +$a->strings["Create New Event"] = "Crear Nuevo Evento"; +$a->strings["Previous"] = "Anterior"; +$a->strings["Next"] = "Siguiente"; +$a->strings["Export"] = "Exportar"; +$a->strings["Import"] = "Importar"; +$a->strings["Event removed"] = "Evento borrado"; +$a->strings["Failed to remove event"] = "Error al borrar evento"; +$a->strings["Event details"] = "Detalles del evento"; +$a->strings["Starting date and Title are required."] = "Se requieren fecha y Título."; +$a->strings["Categories (comma-separated list)"] = "Categorías (lista separada por comas)"; +$a->strings["Event Starts:"] = "Inicios de acontecimientos:"; +$a->strings["Finish date/time is not known or not relevant"] = "La fecha / hora de finalización no se conocen o no son relevantes"; +$a->strings["Event Finishes:"] = "Eventos Terminados:"; +$a->strings["Adjust for viewer timezone"] = "Ajustar para obtener el visor de zona horaria"; +$a->strings["Important for events that happen in a particular place. Not practical for global holidays."] = "Importante para los eventos que suceden en un lugar determinado. No práctico para las vacaciones globales."; +$a->strings["Title:"] = "Título:"; +$a->strings["Share this event"] = "Compartir este evento"; +$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s está siguiendo %2\$s de %3\$s"; +$a->strings["Public Sites"] = "Sitios públicos"; +$a->strings["The listed sites allow public registration for the \$Projectname network. All sites in the network are interlinked so membership on any of them conveys membership in the network as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = "Los sitios listados permiten el registro público de la red \$Projectname. Todos los sitios de la red están vinculados entre sí por lo que sus miembros, en ninguna de ellas, indican la pertenencia a la red en su conjunto. Algunos sitios pueden requerir suscripción o proporcionar planes de servicio por niveles. Los enlaces de los proveedores de pueden proporcionar detalles adicionales."; +$a->strings["Rate this hub"] = "Valorar este sitio"; +$a->strings["Site URL"] = "URL del sitio"; +$a->strings["Access Type"] = "Tipo de Acceso"; +$a->strings["Registration Policy"] = "Normas de Registro"; +$a->strings["Location"] = "Localización"; +$a->strings["View hub ratings"] = "Ver las valoraciones del sitio"; +$a->strings["Rate"] = "Valoración"; +$a->strings["View ratings"] = "Ver valoraciones"; +$a->strings["Edit post"] = "Editar entrada"; +$a->strings["\$Projectname channel"] = "canal \$Projectname"; +$a->strings["Collection created."] = "Colección creada."; +$a->strings["Could not create collection."] = "No se puede crear colección."; +$a->strings["Collection updated."] = "Colección actualizada."; +$a->strings["Create a collection of channels."] = "Crear una colección de canales."; +$a->strings["Collection Name: "] = "Nombre de la Colección:"; +$a->strings["Members are visible to other channels"] = "Los miembros son visibles para otros canales"; +$a->strings["Collection removed."] = "Colección eliminada."; +$a->strings["Unable to remove collection."] = "No ha sido posible de eliminar la colección."; +$a->strings["Collection Editor"] = "Editor de Colecciones"; +$a->strings["Members"] = "Miembros"; +$a->strings["All Connected Channels"] = "Todos los canales conectados"; +$a->strings["Click on a channel to add or remove."] = "Haga clic en un canal para agregar o quitar."; +$a->strings["Version %s"] = "Versión %s"; +$a->strings["Installed plugins/addons/apps:"] = "Extensiones/Aplicaciones instaladas:"; +$a->strings["No installed plugins/addons/apps"] = "Extensiones/Aplicaciones no instaladas:"; +$a->strings["\$Projectname"] = "\$Projectname"; +$a->strings["This is a hub of \$Projectname - a global cooperative network of decentralized privacy enhanced websites."] = "Este es un sitio integrado en \$Projectname - una red cooperativa mundial de sitios web descentralizados de privacidad mejorada."; +$a->strings["Tag: "] = "Etiqueta:"; +$a->strings["Last background fetch: "] = "Última actualización en segundo plano:"; +$a->strings["Running at web location"] = "Corriendo en el sitio web"; +$a->strings["Please visit redmatrix.me to learn more about \$Projectname."] = "Por favor, visite redmatrix.me para aprender más sobre \$Projectname."; +$a->strings["Bug reports and issues: please visit"] = "Informes de errores e incidencias: por, favor visite"; +$a->strings["\$projectname issues"] = "Problemas en \$projectname"; +$a->strings["Suggestions, praise, etc. - please email \"redmatrix\" at librelist - dot com"] = "Sugerencias, elogios, etc - por favor, un correo electrónico a \"redmatrix\" en librelist - punto com"; +$a->strings["Site Administrators"] = "Administradores del sitio"; +$a->strings["Unable to locate original post."] = "No ha sido posible encontrar la entrada original."; +$a->strings["Empty post discarded."] = "Desechada entrada vacía."; +$a->strings["Executable content type not permitted to this channel."] = "Contenido de tipo ejecutable no permitido en este canal."; +$a->strings["System error. Post not saved."] = "Error del sistema. Entrada no salvada."; +$a->strings["Unable to obtain post information from database."] = "No ha sido posible obtener información de la entrada en la base de datos."; +$a->strings["You have reached your limit of %1$.0f top level posts."] = "Ha alcanzado su límite de %1$.0f tope máximo de entradas"; +$a->strings["You have reached your limit of %1$.0f webpages."] = "Ha alcanzado su límite de %1$.0f páginas web."; +$a->strings["No such group"] = "No se encuentra el grupo"; +$a->strings["No such channel"] = "No se encuentra el canal"; +$a->strings["Search Results For:"] = "Buscar resultados para:"; +$a->strings["Collection is empty"] = "La colección está vacía"; +$a->strings["Collection: "] = "Colección:"; +$a->strings["Connection: "] = "Conexión:"; +$a->strings["Invalid connection."] = "Conexión no válida."; +$a->strings["No channel."] = "Ningún canal."; +$a->strings["Common connections"] = "Conexiones comunes"; +$a->strings["No connections in common."] = "Ninguna conexión en común."; +$a->strings["This site is not a directory server"] = "Este sitio no es un servidor de directorio"; +$a->strings["Could not access contact record."] = "No se ha podido acceder al registro de contacto."; +$a->strings["Could not locate selected profile."] = "No se ha podido localizar el perfil seleccionado."; +$a->strings["Connection updated."] = "Conexión actualizada."; +$a->strings["Failed to update connection record."] = "Error al actualizar el registro de la conexión."; +$a->strings["Blocked"] = "Bloqueados"; +$a->strings["Ignored"] = "Ignorados"; +$a->strings["Hidden"] = "Ocultos"; +$a->strings["Archived"] = "Archivados"; +$a->strings["Suggest new connections"] = "Sugerir nuevas conexiones"; +$a->strings["New Connections"] = "Nuevas conexiones"; +$a->strings["Show pending (new) connections"] = "Mostrar conexiones (nuevas) pendientes"; +$a->strings["All Connections"] = "Todas las conexiones"; +$a->strings["Show all connections"] = "Mostrar todas las conexiones"; +$a->strings["Unblocked"] = "Desbloqueados"; +$a->strings["Only show unblocked connections"] = "Mostrar solo las conexiones desbloqueadas"; +$a->strings["Only show blocked connections"] = "Mostrar solo las conexiones bloqueadas"; +$a->strings["Only show ignored connections"] = "Mostrar solo conexiones ignoradas"; +$a->strings["Only show archived connections"] = "Mostrar solo las conexiones archivadas"; +$a->strings["Only show hidden connections"] = "Mostrar solo las conexiones ocultas"; +$a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]"; +$a->strings["Edit connection"] = "Editar conexión"; +$a->strings["Search your connections"] = "Buscar sus conexiones"; +$a->strings["Finding: "] = "Encontrado:"; +$a->strings["Block Name"] = "Nombre del bloque"; +$a->strings["Block Title"] = "Título del bloque"; +$a->strings["Item not found"] = "Elemento no encontrado"; +$a->strings["Item is not editable"] = "El elemento no es editable"; +$a->strings["Delete item?"] = "¿Borrar el elemento?"; +$a->strings["Insert YouTube video"] = "Insertar vídeo de YouTube"; +$a->strings["Insert Vorbis [.ogg] video"] = "Insertar vídeo Vorbis [.ogg]"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Insertar audio Vorbis [.ogg]"; +$a->strings["\$Projectname - Guests: Username: {your email address}, Password: +++"] = "\$Projectname - Invitados: Nombre de usuario: {su dirección de correo electrónico}, Contraseña: +++"; +$a->strings["Page owner information could not be retrieved."] = "La información del propietario de la página no pudo ser recuperada."; +$a->strings["Album not found."] = "Ãlbum no encontrado."; +$a->strings["Delete Album"] = "Borrar álbum"; +$a->strings["Delete Photo"] = "Borrar foto"; +$a->strings["No photos selected"] = "No hay fotos seleccionadas"; +$a->strings["Access to this item is restricted."] = "El acceso a este elemento está restringido."; +$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "%1$.2f MB de %2$.2f MB de almacenamiento de fotos utilizado."; +$a->strings["%1$.2f MB photo storage used."] = "%1$.2f MB de almacenamiento de fotos utilizado."; +$a->strings["Upload Photos"] = "Subir fotos"; +$a->strings["Enter a new album name"] = "Introducir un nuevo nombre de álbum"; +$a->strings["or select an existing one (doubleclick)"] = "o seleccionar uno (Double click) existente"; +$a->strings["Create a status post for this upload"] = "Crear una entrada de estado para esta subida"; +$a->strings["Album name could not be decoded"] = "El nombre del álbum no ha podido ser descifrado"; +$a->strings["Contact Photos"] = "Fotos de contacto"; +$a->strings["Show Newest First"] = "Mostrar lo más reciente primero"; +$a->strings["Show Oldest First"] = "Mostrar lo más antiguo primero"; +$a->strings["View Photo"] = "Ver foto"; +$a->strings["Edit Album"] = "Editar álbum"; +$a->strings["Permission denied. Access to this item may be restricted."] = "Permiso denegado. El acceso a este elemento puede estar restringido."; +$a->strings["Photo not available"] = "Foto no disponible"; +$a->strings["Use as profile photo"] = "Usar como foto de perfil"; +$a->strings["Private Photo"] = "Foto privada"; +$a->strings["View Full Size"] = "Ver tamaño completo"; +$a->strings["Edit photo"] = "Editar foto"; +$a->strings["Rotate CW (right)"] = "Girar CW (a la derecha)"; +$a->strings["Rotate CCW (left)"] = "Girar CCW (a la izquierda)"; +$a->strings["Caption"] = "Título"; +$a->strings["Add a Tag"] = "Añadir una etiqueta"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Ejemplo: @bob, @Barbara_Jensen, @jim@example.com"; +$a->strings["Flag as adult in album view"] = "Marcar como \"solo para adultos\" en el álbum"; +$a->strings["In This Photo:"] = "En esta foto:"; +$a->strings["Map"] = "Mapa"; +$a->strings["View Album"] = "Ver álbum"; +$a->strings["Recent Photos"] = "Fotos recientes"; +$a->strings["Items tagged with: %s"] = "elementos etiquetados con: %s"; +$a->strings["Search results for: %s"] = "Resultados de la búsqueda para: %s"; +$a->strings["Profile Match"] = "Perfil compatible"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "No hay palabras clave en el perfil principal para poder encontrar perfiles compatibles. Por favor, añada palabras clave a su perfil principal."; +$a->strings["is interested in:"] = "está interesado en:"; +$a->strings["No matches"] = "No se han encontrado perfiles compatibles"; +$a->strings["Away"] = "Ausente"; +$a->strings["Online"] = "Conectado"; +$a->strings["Select a bookmark folder"] = "Seleccionar una carpeta de marcadores"; +$a->strings["Save Bookmark"] = "Guardar marcador"; +$a->strings["URL of bookmark"] = "URL del marcador"; +$a->strings["Description"] = "Descripción"; +$a->strings["Or enter new bookmark folder name"] = "O introduzca un nuevo nombre para la carpeta de marcadores"; +$a->strings["No more system notifications."] = "No hay más notificaciones del sistema"; +$a->strings["System Notifications"] = "Notificaciones de sistema"; +$a->strings["network"] = "red"; +$a->strings["RSS"] = "RSS"; +$a->strings["Layout updated."] = "Diseño actualizado"; +$a->strings["Edit System Page Description"] = "Editor del Sistema de Descripción de Páginas"; +$a->strings["Layout not found."] = "Diseño no encontrado"; +$a->strings["Module Name:"] = "Nombre del módulo:"; +$a->strings["Layout Help"] = "Ayuda para el diseño de la página"; +$a->strings["- select -"] = "-seleccionar-"; +$a->strings["Your service plan only allows %d channels."] = "Su paquete de servicios solo permite %d canales."; +$a->strings["Nothing to import."] = "No hay nada para importar."; +$a->strings["Unable to download data from old server"] = "No se han podido descargar datos de su antiguo servidor"; +$a->strings["Imported file is empty."] = "El fichero importado está vacío."; +$a->strings["The data provided is not compatible with this project."] = "Los datos proporcionados no son compatibles con este proyecto."; +$a->strings["Warning: Database versions differ by %1\$d updates."] = "Atención: Las versiones de la base de datos difieren en %1\$d actualizaciones."; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "No se ha podido crear el canal porque el identificador del canal no se ha podido duplicar en este servidor."; +$a->strings["Channel clone failed. Import failed."] = "No se ha podido importar el canal porque el canal no se ha podido clonar."; +$a->strings["Cloned channel not found. Import failed."] = "No se ha podido importar el canal porque el canal clonado no se ha encontrado."; +$a->strings["You must be logged in to use this feature."] = "Debe estar registrado para poder usar esta funcionalidad."; +$a->strings["Import Channel"] = "Importar canal"; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file."] = "Emplee este formulario para importar un canal desde un servidor/hub diferente. Puede recuperar el canal desde el antiguo servidor/hub a través de la red o proporcionando un fichero de exportación."; +$a->strings["File to Upload"] = "Fichero para subir"; +$a->strings["Or provide the old server/hub details"] = "O proporcione los detalles de su antiguo servidor/hub"; +$a->strings["Your old identity address (xyz@example.com)"] = "Su identidad en el antiguo servidor (canal@ejemplo.com)"; +$a->strings["Your old login email address"] = "Su antigua dirección de correo electrónico"; +$a->strings["Your old login password"] = "Su antigua contraseña"; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Para cualquiera de las opciones, elija si hacer de este servidor su nueva dirección primaria, o si su antigua ubicación debe continuar con este papel. Usted podrá publicar desde cualquier ubicación, pero sólo una puede estar marcada como la ubicación principal para los ficheros, fotos y otras imágenes o vídeos."; +$a->strings["Make this hub my primary location"] = "Convertir este servidor en mi ubicación primaria"; +$a->strings["Import existing posts if possible (experimental - limited by available memory"] = "Importar el contenido publicado si es posible (experimental - limitado por la memoria disponible"; +$a->strings["This process may take several minutes to complete. Please submit the form only once and leave this page open until finished."] = "Este proceso puede tardar varios minutos en completarse. Por favor envíe el formulario una sola vez y mantenga esta página abierta hasta que termine."; +$a->strings["Delete layout?"] = "¿Borrar formato?"; +$a->strings["Layout Description (Optional)"] = "Descripción del diseño (opcional)"; +$a->strings["Layout Name"] = "Nombre del diseño"; +$a->strings["Edit Layout"] = "Editar diseño"; +$a->strings["You must be logged in to see this page."] = "Debe estar registrado para poder ver esta página."; +$a->strings["Room not found"] = "Sala no encontrada"; +$a->strings["Leave Room"] = "Abandonar sala"; +$a->strings["Delete This Room"] = "Eliminar esta sala"; +$a->strings["I am away right now"] = "Estoy ausente momentáneamente"; +$a->strings["I am online"] = "Estoy conectado"; +$a->strings["Bookmark this room"] = "Añadir esta sala a Marcadores"; +$a->strings["New Chatroom"] = "Nueva sala de chat"; +$a->strings["Chatroom Name"] = "Nombre de sala de chat"; +$a->strings["%1\$s's Chatrooms"] = "Sala de chat de %1\$s"; +$a->strings["Menu not found."] = "Menú no encontrado"; +$a->strings["Unable to create element."] = "Imposible crear el elemento."; +$a->strings["Unable to update menu element."] = "No es posible actualizar el elemento del menú."; +$a->strings["Unable to add menu element."] = "No es posible añadir el elemento al menú"; +$a->strings["Menu Item Permissions"] = "Permisos del elemento del menú"; +$a->strings["(click to open/close)"] = "(pulsa para abrir/cerrar)"; +$a->strings["Link Name"] = "Nombre del enlace"; +$a->strings["Link or Submenu Target"] = "Destino del enlace o submenú"; +$a->strings["Enter URL of the link or select a menu name to create a submenu"] = "Introduzca la dirección del enlace o seleccione el nombre de un submenú"; +$a->strings["Use magic-auth if available"] = "Use la autenticación mágica si está disponible"; +$a->strings["Open link in new window"] = "Abrir el enlace en una nueva ventana"; +$a->strings["Order in list"] = "Orden en la lista"; +$a->strings["Higher numbers will sink to bottom of listing"] = "Los números más altos irán al final de la lista"; +$a->strings["Submit and finish"] = "Enviar y terminar"; +$a->strings["Submit and continue"] = "Enviar y continuar"; +$a->strings["Menu:"] = "Menú:"; +$a->strings["Link Target"] = "Destino del enlace"; +$a->strings["Edit menu"] = "Editar menú"; +$a->strings["Edit element"] = "Editar elemento"; +$a->strings["Drop element"] = "Eliminar el elemento"; +$a->strings["New element"] = "Nuevo elemento"; +$a->strings["Edit this menu container"] = "Modificar el contenedor del menú"; +$a->strings["Add menu element"] = "Añadir un elemento al menú"; +$a->strings["Delete this menu item"] = "Eliminar este elemento del menú"; +$a->strings["Edit this menu item"] = "Modificar este elemento del menú"; +$a->strings["Menu item not found."] = "Este elemento del menú no se ha encontrado"; +$a->strings["Menu item deleted."] = "Este elemento del menú ha sido borrado"; +$a->strings["Menu item could not be deleted."] = "Este elemento del menú no puede ser borrada."; +$a->strings["Edit Menu Element"] = "Editar elemento del menú"; +$a->strings["Link text"] = "Texto del enlace"; +$a->strings["Delete webpage?"] = "¿Eliminar página web?"; +$a->strings["Page link title"] = "Título del enlace de la página"; +$a->strings["Edit Webpage"] = "Editar página web"; +$a->strings["This directory server requires an access token"] = "El servidor de este directorio necesita un \"token\" de acceso"; +$a->strings["No valid account found."] = "No se ha encontrado una cuenta válida."; +$a->strings["Password reset request issued. Check your email."] = "Se ha recibido una solicitud de restablecimiento de contraseña. Consulte su correo electrónico."; +$a->strings["Site Member (%s)"] = "Usuario del sitio (%s)"; +$a->strings["Password reset requested at %s"] = "Se ha solicitado restablecer la contraseña en %s"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "La solicitud no ha podido ser verificada. (Puede que la haya enviado con anterioridad) El restablecimiento de la contraseña ha fallado."; +$a->strings["Password Reset"] = "Restablecer la contraseña"; +$a->strings["Your password has been reset as requested."] = "Su contraseña ha sido restablecida según lo solicitó."; +$a->strings["Your new password is"] = "Su nueva contraseña es"; +$a->strings["Save or copy your new password - and then"] = "Guarde o copie su nueva contraseña - y después"; +$a->strings["click here to login"] = "Pulse aquí para conectarse"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Puede cambiar la contraseña en la página Configuraciones una vez iniciada la sesión."; +$a->strings["Your password has changed at %s"] = "Su contraseña en %s ha sido cambiada"; +$a->strings["Forgot your Password?"] = "¿Ha olvidado su contraseña?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Introduzca y envíe su dirección de correo electrónico para que el restablecimiento de su contraseña. Luego revise su correo para obtener más instrucciones."; +$a->strings["Email Address"] = "Dirección de correo electrónico"; +$a->strings["Reset"] = "Reiniciar"; +$a->strings["Website:"] = "Sitio web:"; +$a->strings["Remote Channel [%s] (not yet known on this site)"] = "Canal remoto [%s] (aún no es conocido en este sitio)"; +$a->strings["Rating (this information is public)"] = "Valoración (esta información es pública)"; +$a->strings["Optionally explain your rating (this information is public)"] = "Opcionalmente puede explicar su valoración (esta información es pública)"; +$a->strings["Delete block?"] = "¿Borrar este bloque?"; +$a->strings["Edit Block"] = "Modificar este bloque"; +$a->strings["Total invitation limit exceeded."] = "Se ha superado el límite máximo de invitaciones."; +$a->strings["%s : Not a valid email address."] = "%s : No es una dirección de correo electrónico válida. "; +$a->strings["Please join us on Red"] = "Únase a nosotros en RedMatrix"; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = "Excedido el límite de invitaciones. Por favor, contacte con el Administrador de su sitio."; +$a->strings["%s : Message delivery failed."] = "%s : Falló la entrega del mensaje."; +$a->strings["%d message sent."] = array( + 0 => "%d mensajes enviados.", + 1 => "%d mensajes enviados.", +); +$a->strings["You have no more invitations available"] = "No tiene más invitaciones disponibles"; +$a->strings["Send invitations"] = "Enviar invitaciones"; +$a->strings["Enter email addresses, one per line:"] = "Introduzca las direcciones de correo electrónica, una por línea:"; +$a->strings["Your message:"] = "Su mensaje:"; +$a->strings["Please join my community on \$Projectname."] = "Por favor, únase a mi comunidad en \$Projectname."; +$a->strings["You will need to supply this invitation code: "] = "Debe proporcionar este código de invitación:"; +$a->strings["1. Register at any \$Projectname location (they are all inter-connected)"] = "1. Regístrese en cualquier lugar del \$Projectname (están todos interconectados)"; +$a->strings["2. Enter my \$Projectname network address into the site searchbar."] = "2. Introduzca mi dirección \$Projectname en la caja de búsqueda del sitio."; +$a->strings["or visit "] = "o visite"; +$a->strings["3. Click [Connect]"] = "3. Pulse [conectar]"; +$a->strings["Location not found."] = "Localización no encontrada."; +$a->strings["Primary location cannot be removed."] = "La localización primaria no puede ser eliminada."; +$a->strings["No locations found."] = "Ninguna localización encontrada."; +$a->strings["Manage Channel Locations"] = "Gestionar localizaciones del canal"; +$a->strings["Location (address)"] = "Localización (dirección)"; +$a->strings["Primary Location"] = "Localización primaria"; +$a->strings["Drop location"] = "Eliminar localización"; +$a->strings["Failed to create source. No channel selected."] = "Imposible crear la fuente. Ningún canal ha sido seleccionado."; +$a->strings["Source created."] = "Fuente creada."; +$a->strings["Source updated."] = "Fuente actualizada."; +$a->strings["*"] = "*"; +$a->strings["Manage remote sources of content for your channel."] = "Gestionar contenido de origen remoto para su canal."; +$a->strings["New Source"] = "Nueva fuente"; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importar todo el contenido o una selección de los siguientes canales en este canal, y distribuirlo de acuerdo con los ajustes de su canal."; +$a->strings["Only import content with these words (one per line)"] = "Importar solo contenido que contenga estas palabras (una por línea)"; +$a->strings["Leave blank to import all public content"] = "Dejar en blanco para importar todo el contenido público"; +$a->strings["Channel Name"] = "Nombre del canal"; +$a->strings["Source not found."] = "Fuente no encontrada"; +$a->strings["Edit Source"] = "Editar fuente"; +$a->strings["Delete Source"] = "Eliminar fuente"; +$a->strings["Source removed"] = "Fuente eliminada"; +$a->strings["Unable to remove source."] = "Imposible eliminar la fuente."; +$a->strings["Unable to update menu."] = "No se puede actualizar el menú."; +$a->strings["Unable to create menu."] = "No se puede crear el menú."; +$a->strings["Menu Name"] = "Nombre del menú"; +$a->strings["Unique name (not visible on webpage) - required"] = "Nombre único (no será visible en la página web) - requerido"; +$a->strings["Menu Title"] = "Título del menú"; +$a->strings["Visible on webpage - leave empty for no title"] = "Visible en la página web - no ponga nada si no desea un título"; +$a->strings["Allow Bookmarks"] = "Permitir marcadores"; +$a->strings["Menu may be used to store saved bookmarks"] = "El menú se puede usar para guardar marcadores"; +$a->strings["Submit and proceed"] = "Enviar y proceder"; +$a->strings["Drop"] = "Eliminar"; +$a->strings["Bookmarks allowed"] = "Marcadores permitidos"; +$a->strings["Delete this menu"] = "Borrar este menú"; +$a->strings["Edit menu contents"] = "Editar los contenidos del menú"; +$a->strings["Edit this menu"] = "Modificar este menú"; +$a->strings["Menu could not be deleted."] = "El menú no puede ser eliminado."; +$a->strings["Edit Menu"] = "Modificar el menú"; +$a->strings["Add or remove entries to this menu"] = "Añadir o quitar entradas en este menú"; +$a->strings["Menu name"] = "Nombre del menú"; +$a->strings["Must be unique, only seen by you"] = "Debe ser único, solo será visible para usted"; +$a->strings["Menu title"] = "Título del menú"; +$a->strings["Menu title as seen by others"] = "El título del menú tal como será visto por los demás"; +$a->strings["Allow bookmarks"] = "Permitir marcadores"; +$a->strings["Permission Denied."] = "Permiso denegado"; +$a->strings["File not found."] = "Fichero no encontrado."; +$a->strings["Edit file permissions"] = "Modificar los permisos del fichero"; +$a->strings["Set/edit permissions"] = "Establecer/editar los permisos"; +$a->strings["Include all files and sub folders"] = "Incluir todos los ficheros y subcarpetas"; +$a->strings["Return to file list"] = "Volver a la lista de ficheros"; +$a->strings["Copy/paste this code to attach file to a post"] = "Copiar/pegar este código para adjuntar el fichero al envío"; +$a->strings["Copy/paste this URL to link file from a web page"] = "Copiar/pegar esta dirección para enlazar el fichero desde una página web"; +$a->strings["Share this file"] = "Compartir este fichero"; +$a->strings["Show URL to this file"] = "Mostrar la dirección de este fichero"; +$a->strings["Notify your contacts about this file"] = "Avisar a sus contactos de este fichero"; +$a->strings["Contact not found."] = "Contacto no encontrado"; +$a->strings["Friend suggestion sent."] = "Enviar sugerencia a un amigo."; +$a->strings["Suggest Friends"] = "Sugerir amigos"; +$a->strings["Suggest a friend for %s"] = "Sugerir un amigo a %s"; +$a->strings["Hub not found."] = "Servidor no encontrado"; +$a->strings["Poke/Prod"] = "Dar un toque/Incitar"; +$a->strings["poke, prod or do other things to somebody"] = "dar un toque, incitar u otras cosas a alguien"; +$a->strings["Recipient"] = "Destinatario"; +$a->strings["Choose what you wish to do to recipient"] = "Elegir qué desea enviar al destinatario"; +$a->strings["Make this post private"] = "Convertir en privado este envío"; +$a->strings["Invalid profile identifier."] = "Identificador de perfil no válido"; +$a->strings["Profile Visibility Editor"] = "Editor de visibilidad el perfil"; +$a->strings["Click on a contact to add or remove."] = "Pulsar en un contacto para añadir o eliminar."; +$a->strings["Visible To"] = "Visible para"; +$a->strings["%s element installed"] = "%s elemento instalado"; +$a->strings["%s element installation failed"] = "Elemento con instalación fallida: %s"; +$a->strings["Profile not found."] = "Perfil no encontrado."; +$a->strings["Profile deleted."] = "Perfil eliminado."; +$a->strings["Profile-"] = "Perfil-"; +$a->strings["New profile created."] = "Creado el nuevo perfil."; +$a->strings["Profile unavailable to clone."] = "Perfil no disponible para clonar."; +$a->strings["Profile unavailable to export."] = "Perfil no disponible para exportar."; +$a->strings["Profile Name is required."] = "Se necesita el nombre del perfil."; +$a->strings["Marital Status"] = "Estado sentimental"; +$a->strings["Romantic Partner"] = "Pareja sentimental"; +$a->strings["Likes"] = "Me gusta"; +$a->strings["Dislikes"] = "No me gusta"; +$a->strings["Work/Employment"] = "Trabajo:"; +$a->strings["Religion"] = "Religión"; +$a->strings["Political Views"] = "Ideas políticas"; +$a->strings["Gender"] = "Género"; +$a->strings["Sexual Preference"] = "Preferencia sexual"; +$a->strings["Homepage"] = "Página personal"; +$a->strings["Interests"] = "Intereses"; +$a->strings["Address"] = "Dirección"; +$a->strings["Profile updated."] = "Perfil actualizado."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "¿Ocultar su lista de contactos a los visitantes de este perfil?"; +$a->strings["Edit Profile Details"] = "Modificar los detalles de este perfil"; +$a->strings["View this profile"] = "Ver este perfil"; +$a->strings["Change Profile Photo"] = "Cambiar la foto del perfil"; +$a->strings["Create a new profile using these settings"] = "Crear un nuevo perfil usando estos ajustes"; +$a->strings["Clone this profile"] = "Clonar este perfil"; +$a->strings["Delete this profile"] = "Eliminar este perfil"; +$a->strings["Import profile from file"] = "Importar perfil desde un fichero"; +$a->strings["Export profile to file"] = "Exportar perfil a un fichero"; +$a->strings["Profile Name:"] = "Nombre del perfil:"; +$a->strings["Your Full Name:"] = "Su nombre completo:"; +$a->strings["Title/Description:"] = "Título/Descripción:"; +$a->strings["Your Gender:"] = "Su género:"; +$a->strings["Birthday :"] = "Cumpleaños:"; +$a->strings["Street Address:"] = "Calle:"; +$a->strings["Locality/City:"] = "Ciudad:"; +$a->strings["Postal/Zip Code:"] = "Código postal:"; +$a->strings["Country:"] = "País:"; +$a->strings["Region/State:"] = "Región/Estado:"; +$a->strings[" Marital Status:"] = " Estado sentimental:"; +$a->strings["Who: (if applicable)"] = "Quién: (si es aplicable)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Por ejemplo: cathy123, Cathy Williams, cathy@example.com"; +$a->strings["Since [date]:"] = "Desde [fecha]:"; +$a->strings["Homepage URL:"] = "Dirección de la página personal:"; +$a->strings["Religious Views:"] = "Creencias religiosas:"; +$a->strings["Keywords:"] = "Palabras clave:"; +$a->strings["Example: fishing photography software"] = "Por ejemplo: software de fotografía submarina"; +$a->strings["Used in directory listings"] = "Visible en el directorio público del canal"; +$a->strings["Tell us about yourself..."] = "Háblenos de usted..."; +$a->strings["Hobbies/Interests"] = "Aficiones/Intereses"; +$a->strings["Contact information and Social Networks"] = "Información de contacto y redes sociales"; +$a->strings["My other channels"] = "Mis otros canales"; +$a->strings["Musical interests"] = "Preferencias musicales"; +$a->strings["Books, literature"] = "Libros, literatura"; +$a->strings["Television"] = "Televisión"; +$a->strings["Film/dance/culture/entertainment"] = "Cine/danza/cultura/entretenimiento"; +$a->strings["Love/romance"] = "Vida sentimental/amorosa"; +$a->strings["Work/employment"] = "Trabajo"; +$a->strings["School/education"] = "Estudios"; +$a->strings["This is your default profile."] = "Este es su perfil principal."; +$a->strings["Age: "] = "Edad:"; +$a->strings["Edit/Manage Profiles"] = "Modificar/gestionar perfiles"; +$a->strings["Add profile things"] = "Añadir cosas al perfil"; +$a->strings["Include desirable objects in your profile"] = "Añadir objetos interesantes en su perfil"; +$a->strings["No ratings"] = "Ninguna valoración"; +$a->strings["Ratings"] = "Valoraciones"; +$a->strings["Rating: "] = "Valoración:"; +$a->strings["Website: "] = "Sitio web:"; +$a->strings["Description: "] = "Descripción:"; +$a->strings["Source of Item"] = "Origen del elemento"; +$a->strings["\$Projectname Server - Setup"] = "Servidor \$Projectname - Instalación"; +$a->strings["Could not connect to database."] = "No se ha podido conectar a la base de datos."; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "No se puede conectar con la dirección del sitio indicada. Podría tratarse de un problema de SSL o DNS."; +$a->strings["Could not create table."] = "No se puede crear la tabla."; +$a->strings["Your site database has been installed."] = "La base de datos del sitio ha sido instalada."; +$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Podría tener que importar manualmente el fichero \"install/schema_xxx.sql\" usando un cliente de base de datos."; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Por favor, lea el fichero \"install/INSTALL.txt\"."; +$a->strings["System check"] = "Verificación del sistema"; +$a->strings["Check again"] = "Verificar de nuevo"; +$a->strings["Database connection"] = "Conexión a la base de datos"; +$a->strings["In order to install \$Projectname we need to know how to connect to your database."] = "Para instalar \$Projectname es necesario saber cómo conectar con su base de datos."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Por favor, contacte con el proveedor de servicios o el administrador del sitio si tiene dudas sobre estos ajustes."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "La base de datos que especifique a continuación debe existir ya. Si no es así, por favor, créela antes de seguir."; +$a->strings["Database Server Name"] = "Nombre del servidor de base de datos"; +$a->strings["Default is localhost"] = "Por defecto es localhost"; +$a->strings["Database Port"] = "Puerto de la base de datos"; +$a->strings["Communication port number - use 0 for default"] = "Número del puerto de comunicaciones - use 0 como valor por defecto"; +$a->strings["Database Login Name"] = "Nombre de acceso a la base de datos"; +$a->strings["Database Login Password"] = "Contraseña de acceso a la base de datos"; +$a->strings["Database Name"] = "Nombre de la base de datos"; +$a->strings["Database Type"] = "Tipo de base de datos"; +$a->strings["Site administrator email address"] = "Dirección de correo electrónico del administrador del sitio"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "Su cuenta deberá usar la misma dirección de correo electrónico para poder utilizar el panel de administración web."; +$a->strings["Website URL"] = "Dirección del sitio web"; +$a->strings["Please use SSL (https) URL if available."] = "Por favor, use SSL (https) si está disponible."; +$a->strings["Please select a default timezone for your website"] = "Por favor, selecciones la zona horaria por defecto de su sitio web"; +$a->strings["Site settings"] = "Ajustes del sitio"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "No se puede encontrar una versión en línea de comandos de PHP en la ruta del servidor web."; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Si no tiene instalada la versión de línea de comandos de PHP en su servidor, no podrá ejecutar votaciones en segundo plano vía cron."; +$a->strings["PHP executable path"] = "ruta del ejecutable PHP"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Introducir la ruta completa del ejecutable PHP. Puede dejar la línea en blanco para continuar la instalación."; +$a->strings["Command line PHP"] = "PHP en línea de comandos"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "La línea de comandos PHP de su sistema no tiene activado \"register_argc_argv\"."; +$a->strings["This is required for message delivery to work."] = "Esto es necesario para que funcione la entrega de mensajes."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Your max allowed total upload size is set to %s. Maximum size of one file to upload is set to %s. You are allowed to upload up to %d files at once."] = "La carga máxima que se le permite subir está establecida en %s. El tamaño máxima de un archivo está establecido en %s. Está permitido subir hasta un máximo de %d ficheros de una sola vez."; +$a->strings["You can adjust these settings in the servers php.ini."] = "Puede ajustar estos valores en el fichero php.ini de su servidor."; +$a->strings["PHP upload limits"] = "Límites PHP de subida"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Error: La función \"openssl_pkey_new\" en este sistema no es capaz de general claves de cifrado."; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "si está en un servidor Windows, por favor, lea \"http://www.php.net/manual/en/openssl.installation.php\"."; +$a->strings["Generate encryption keys"] = "Generar claves de cifrado"; +$a->strings["libCurl PHP module"] = "módulo libCurl PHP"; +$a->strings["GD graphics PHP module"] = "módulo PHP GD graphics"; +$a->strings["OpenSSL PHP module"] = "módulo PHP OpenSSL"; +$a->strings["mysqli or postgres PHP module"] = "módulo PHP mysqli o postgres"; +$a->strings["mb_string PHP module"] = "módulo PHP mb_string"; +$a->strings["mcrypt PHP module"] = "módulo PHP mcrypt "; +$a->strings["xml PHP module"] = "módulo PHP xml"; +$a->strings["Apache mod_rewrite module"] = "módulo Apache mod_rewrite "; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Error: se necesita el módulo del servidor web Apache mod-rewrite pero no está instalado."; +$a->strings["proc_open"] = "proc_open"; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Error: se necesita proc_open pero o no está instalado o ha sido desactivado en el fichero php.ini"; +$a->strings["Error: libCURL PHP module required but not installed."] = "Error: se necesita el módulo PHP libCURL pero no está instalado."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Error: el módulo PHP GD graphics es necesario, pero no está instalado."; +$a->strings["Error: openssl PHP module required but not installed."] = "Error: el módulo PHP openssl es necesario, pero no está instalado."; +$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Error: el módulo PHP mysqli o postgres es necesario pero no ninguno de los dos está instalado."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Error: el módulo PHP mb_string es necesario, pero no está instalado."; +$a->strings["Error: mcrypt PHP module required but not installed."] = "Error: el módulo PHP mcrypt es necesario, pero no está instalado."; +$a->strings["Error: xml PHP module required for DAV but not installed."] = "Error: el módulo PHP xml es necesario para DAV, pero no está instalado."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = "El instalador web no ha podido crear un fichero llamado “.htconfig.php†en la carpeta base de su servidor."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Esto está generalmente ligado a un problema de permisos, a causa del cual el servidor web tiene prohibido modificar ficheros en su carpeta - incluso si usted mismo tiene esos permisos."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Al término de este procedimiento, podemos crear un fichero de texto para guardar con el nombre .htconfig.php en el directorio raíz de su instalación de Red."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Como alternativa, puede dejar este procedimiento e intentar realizar una instalación manual. Lea, por favor, el fichero\"install/INSTALL.txt\" para las instrucciones."; +$a->strings[".htconfig.php is writable"] = ".htconfig.php tiene permisos de escritura"; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red hace uso del motor de plantillas Smarty3 para diseñar sus plantillas gráficas. Smarty3 es más rápido porque compila las plantillas de páginas directamente en PHP."; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "Para poder guardar las plantillas compiladas, el servidor web necesita permisos para acceder al subdirectorio %s en el directorio de instalación de Red."; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Por favor, asegúrese de que el servidor web está siendo ejecutado por un usuario que tenga permisos de escritura sobre esta carpeta (por ejemplo, www-data)."; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Nota: como medida de seguridad, debe dar al servidor web permisos de escritura solo sobre %s -no al fichero de plantilla (.tpl) que contiene."; +$a->strings["%s is writable"] = "%s tiene permisos de escritura"; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red guarda los ficheros descargados en la carpeta \"store\". El servidor web necesita tener permisos de escritura sobre esa carpeta, en el directorio de instalación."; +$a->strings["store is writable"] = "\"store\" tiene permisos de escritura"; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "El certificado SSL no ha podido ser validado. Corrija este problema o desactive el acceso https a este sitio."; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Si su servidor soporta conexiones cifradas SSL o si permite conexiones al puerto TCP 443 (el puerto usado por el protocolo https), debe utilizar un certificado válido. No debe usar un certificado firmado por usted mismo."; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Se ha incorporado esta restricción para evitar que sus publicaciones públicas hagan referencia a imágenes en su propio servidor."; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Si su certificado no ha sido reconocido, los miembros de otros sitios (con certificados válidos) recibirán mensajes de aviso en sus propios sitios web."; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Por razones de compatibilidad (sobre el conjunto de la red, no solo sobre su propio sitio), debemos insistir en estos requisitos."; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Existen varias Autoridades de Certificación que le pueden proporcionar certificados válidos."; +$a->strings["SSL certificate validation"] = "validación del certificado SSL"; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "No se pueden reescribir las direcciones web en .htaccess. Compruebe la configuración de su servidor:"; +$a->strings["Url rewrite is working"] = "Se puede reescribir la dirección en .htaccess"; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "El fichero de configuración de la base de datos .htconfig.php no se ha podido modificar. Por favor, copie el texto generado en un fichero con ese nombre en el directorio raíz de su servidor."; +$a->strings["Errors encountered creating database tables."] = "Se han encontrado errores al crear las tablas de la base de datos."; +$a->strings["

    What next

    "] = "

    Siguiente paso

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "IMPORTANTE: Debe crear [manualmente] una tarea programada para las actualizaciones."; +$a->strings["OpenID protocol error. No ID returned."] = "Error del protocolo OpenID. Ningún ID recibido como respuesta."; +$a->strings["Welcome %s. Remote authentication successful."] = "Bienvenido %s. La identificación desde su servidor se ha llevado a cabo correctamente."; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s ha etiquetado el %3\$s de %2\$s con %4\$s"; +$a->strings["Export Channel"] = "Exportar el canal"; +$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = "Exportar la base de datos de su canal a un pequeño fichero. Este podrá servir como una copia de seguridad de sus conexiones, permisos, perfil y datos básicos, que podrá importar a un nuevo canal, pero sin sus contenidos."; +$a->strings["Export Content"] = "Exportar contenidos"; +$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = "Exportar toda la información del canal y todo su contenido a un fichero JSON. Este contendrá todas sus conexiones, permisos, información del perfil y todo su contenido, Sin embargo, a menudo, no será una buena solución para importarlo en una nueva instancia, pues el fichero será MUY voluminoso. Por favor, tenga paciencia - pueden pasar muchos minutos antes de comience la carga."; +$a->strings["No connections."] = "No hay conexiones."; +$a->strings["Visit %s's profile [%s]"] = "Visitar el perfil de %s [%s]"; +$a->strings["invalid target signature"] = "La firma recibida no es válida"; +$a->strings["Theme settings updated."] = "Ajustes del tema actualizados."; +$a->strings["Site"] = "Sitio"; +$a->strings["Accounts"] = "Cuentas"; +$a->strings["Channels"] = "Canales"; +$a->strings["Plugins"] = "Plugins"; +$a->strings["Themes"] = "Temas"; +$a->strings["Inspect queue"] = "Examinar la cola"; +$a->strings["Profile Config"] = "Ajustes del perfil"; +$a->strings["DB updates"] = "Actualizaciones de la base de datos"; +$a->strings["Logs"] = "Informes"; +$a->strings["Plugin Features"] = "Ajustes del plugin"; +$a->strings["User registrations waiting for confirmation"] = "Registro de usuarios pendientes de confirmación"; +$a->strings["# Accounts"] = "# Cuentas"; +$a->strings["# blocked accounts"] = "# cuentas bloqueadas"; +$a->strings["# expired accounts"] = "# cuentas expiradas"; +$a->strings["# expiring accounts"] = "# cuentas expiradas"; +$a->strings["# Channels"] = "# Canales"; +$a->strings["# primary"] = "# primario"; +$a->strings["# clones"] = "# clones"; +$a->strings["Message queues"] = "Mensajes en cola"; +$a->strings["Administration"] = "Administración"; +$a->strings["Summary"] = "Sumario"; +$a->strings["Registered accounts"] = "Cuentas registradas"; +$a->strings["Pending registrations"] = "Registros pendientes"; +$a->strings["Registered channels"] = "Canales registrados"; +$a->strings["Active plugins"] = "Plugins activos"; +$a->strings["Version"] = "Versión"; +$a->strings["Site settings updated."] = "Ajustes del sitio actualizados."; +$a->strings["mobile"] = "móvil"; +$a->strings["experimental"] = "experimental"; +$a->strings["unsupported"] = "no soportado"; +$a->strings["Yes - with approval"] = "Sí - con aprobación"; +$a->strings["My site is not a public server"] = "Mi sitio no es un servidor público"; +$a->strings["My site has paid access only"] = "Mi sitio es un servicio de pago"; +$a->strings["My site has free access only"] = "Mi sitio es un servicio gratuito"; +$a->strings["My site offers free accounts with optional paid upgrades"] = "Mi sitio ofrece cuentas gratuitas con opciones extra de pago"; +$a->strings["Registration"] = "Registro"; +$a->strings["File upload"] = "Fichero subido"; +$a->strings["Policies"] = "Políticas"; +$a->strings["Site name"] = "Nombre del sitio"; +$a->strings["Banner/Logo"] = "Banner/Logo"; +$a->strings["Administrator Information"] = "Información del Administrador"; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = "Información de contacto de los administradores del sitio. Visible en la página \"siteinfo\". Se puede usar BBCode"; +$a->strings["System language"] = "Lengua del sistema"; +$a->strings["System theme"] = "Tema del sistema"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "Tema del sistema por defecto - se puede cambiar por cada perfil de usuario - modificar ajustes del tema"; +$a->strings["Mobile system theme"] = "Tema del sistema para móviles"; +$a->strings["Theme for mobile devices"] = "Tema para aparatos móviles"; +$a->strings["Enable Diaspora Protocol"] = "Activar protocolo de la red social Diaspora"; +$a->strings["Communicate with Diaspora and Friendica - experimental"] = "Comunicar con Diaspora y Friendica - experimental"; +$a->strings["Allow Feeds as Connections"] = "Permitir flujos RSS como conexiones"; +$a->strings["(Heavy system resource usage)"] = "(Uso intenso de los recursos del sistema)"; +$a->strings["Maximum image size"] = "Tamaño máximo de imagen"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Tamaño máximo en bytes de la imagen subida. Por defecto, es 0, lo que significa que no hay límites."; +$a->strings["Does this site allow new member registration?"] = "¿Debe este sitio permitir el registro de nuevos miembros?"; +$a->strings["Which best describes the types of account offered by this hub?"] = "¿Cómo describiría el tipo de servicio ofrecido por este servidor?"; +$a->strings["Register text"] = "Texto del registro"; +$a->strings["Will be displayed prominently on the registration page."] = "Se mostrará de forma destacada en la página de registro."; +$a->strings["Site homepage to show visitors (default: login box)"] = "Página de inicio que se mostrará a los visitantes (por defecto: la página de identificación)"; +$a->strings["example: 'public' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file."] = "ejemplo: 'public' para mostrar contenido público de los usuarios, 'page/sys/home' para mostrar la página web definida como \"home\" o 'include:home.html' para mostrar el contenido de un fichero."; +$a->strings["Preserve site homepage URL"] = "Preservar la dirección de la página web"; +$a->strings["Present the site homepage in a frame at the original location instead of redirecting"] = "Presenta la página web del sitio en un marco en la ubicación original, en vez de redirigirla."; +$a->strings["Accounts abandoned after x days"] = "Cuentas abandonados después de x días"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "Para evitar consumir recursos del sistema intentando poner al día las cuentas abandonadas. Introduzca 0 para no tener límite de tiempo."; +$a->strings["Allowed friend domains"] = "Dominios amigos permitidos"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "Lista separada por comas de dominios a los que está permitido establecer relaciones de amistad con este sitio. Se permiten comodines. Dejar en claro para aceptar cualquier dominio."; +$a->strings["Allowed email domains"] = "Se aceptan dominios de correo electrónico"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "Lista separada por comas de los dominios de los que se acepta una dirección de correo electrónico para registros en este sitio. Se permiten comodines. Dejar en claro para aceptar cualquier dominio. "; +$a->strings["Not allowed email domains"] = "No se permiten dominios de correo electrónico"; +$a->strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = "Lista separada por comas de los dominios de los que no se acepta una dirección de correo electrónico para registros en este sitio. Se permiten comodines. Dejar en claro para no aceptar cualquier dominio, excepto los que se hayan autorizado."; +$a->strings["Block public"] = "Bloque público"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Activar para bloquear el acceso público a todas las páginas públicas personales en este sitio salvo que estén identificadas en el sistema."; +$a->strings["Verify Email Addresses"] = "Verificar direcciones de correo electrónico"; +$a->strings["Check to verify email addresses used in account registration (recommended)."] = "Activar para la verificación de la dirección de correo electrónico en el registro de una cuenta (recomendado)."; +$a->strings["Force publish"] = "Forzar la publicación"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Intentar forzar todos los perfiles para que sean listados en el directorio de este sitio."; +$a->strings["Disable discovery tab"] = "Desactivar la pestaña \"Descubrir\""; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = "Quitar la pestaña para ver contenido público extraído de las fuentes elegidas por este sitio."; +$a->strings["login on Homepage"] = "Acceso a la página de inicio"; +$a->strings["Present a login box to visitors on the home page if no other content has been configured."] = "Presentar a los visitantes una casilla de identificación en la página de inicio, si no se ha configurado otro tipo de contenido."; +$a->strings["Proxy user"] = "Usuario del proxy"; +$a->strings["Proxy URL"] = "Dirección del proxy"; +$a->strings["Network timeout"] = "Tiempo de espera de la red"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "Valor en segundos. Poner a 0 para que no haya tiempo límite (no recomendado)"; +$a->strings["Delivery interval"] = "Intervalo de entrega"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Retrasar los procesos de entrega en segundo plano por esta cantidad de segundos para reducir la carga del sistema. Recomendado: 4-5 para hosts compartidos, 2-3 para servidores virtuales privados, 0-1 para grandes servidores dedicados."; +$a->strings["Poll interval"] = "Intervalo de sondeo"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Retrasar el sondeo en segundo plano en esta cantidad de segundo para reducir la carga del sistema. Si es 0, use el intervalo de entrega."; +$a->strings["Maximum Load Average"] = "Carga media máxima"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Carga máxima del sistema antes de que los procesos de entrega y sondeo se hayan retardado - por defecto, 50."; +$a->strings["Expiration period in days for imported (matrix/network) content"] = "Periodo de caducidad en días para el contenido importado (matrix/red)"; +$a->strings["0 for no expiration of imported content"] = "0 para que no caduque el contenido importado"; +$a->strings["No server found"] = "Servidor no encontrado"; +$a->strings["ID"] = "ID"; +$a->strings["for channel"] = "por canal"; +$a->strings["on server"] = "sobre el servidor"; +$a->strings["Status"] = "Estado"; +$a->strings["Server"] = "Servidor"; +$a->strings["Update has been marked successful"] = "La actualización ha sido marcada como exitosa"; +$a->strings["Executing %s failed. Check system logs."] = "La ejecución de %s ha fallado. Mire en los registros del sistema."; +$a->strings["Update %s was successfully applied."] = "La actualización de %s se ha realizado exitosamente."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "La actualización de %s no ha devuelto ningún estado. No se sabe si ha tenido éxito."; +$a->strings["Update function %s could not be found."] = "No se encuentra la función de actualización de %s."; +$a->strings["No failed updates."] = "No ha fallado ninguna actualización."; +$a->strings["Failed Updates"] = "Han fallado las actualizaciones"; +$a->strings["Mark success (if update was manually applied)"] = "Marcar como exitosa (si la actualización se ha hecho manualmente)"; +$a->strings["Attempt to execute this update step automatically"] = "Intentar ejecutar este paso de actualización automáticamente"; +$a->strings["Queue Statistics"] = "Estadísticas de la cola"; +$a->strings["Total Entries"] = "Total de entradas"; +$a->strings["Priority"] = "Prioridad"; +$a->strings["Destination URL"] = "Dirección de destino"; +$a->strings["Mark hub permanently offline"] = "Marcar el servidor como permanentemente fuera de línea"; +$a->strings["Empty queue for this hub"] = "Vaciar la cola para este servidor"; +$a->strings["Last known contact"] = "Último contacto conocido"; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "%s usuarios bloqueados/desbloqueados", + 1 => "%s de usuarios bloqueados/desbloqueados", +); +$a->strings["%s user deleted"] = array( + 0 => "%s usuarios eliminados", + 1 => "%s usuarios eliminados", +); +$a->strings["Account not found"] = "Cuenta no encontrada"; +$a->strings["User '%s' blocked"] = "Usuario %s bloqueado"; +$a->strings["User '%s' unblocked"] = "Usuario %s desbloqueado"; +$a->strings["Users"] = "Usuarios"; +$a->strings["select all"] = "seleccionar todo"; +$a->strings["User registrations waiting for confirm"] = "Registros de usuario en espera de aprobación"; +$a->strings["Request date"] = "Fecha de solicitud"; +$a->strings["No registrations."] = "Sin registros."; +$a->strings["Approve"] = "Aprobar"; +$a->strings["Deny"] = "Rechazar"; +$a->strings["Block"] = "Bloquear"; +$a->strings["Unblock"] = "Desbloquear"; +$a->strings["Register date"] = "Fecha de registro"; +$a->strings["Last login"] = "Último acceso"; +$a->strings["Expires"] = "Expira"; +$a->strings["Service Class"] = "Clase de servicio"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Los usuarios seleccionados serám eliminados!\\n\\nTodo lo que estos usuarios han publicado en este sitio se borrará de manera definitiva!\\n\\n¿Está seguro de querer hacerlo?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "El usuario {0} va a ser eliminado!\\n\\nTodo lo que este usuario ha publicado en este sitio será borrado de forma permanente!\\n\\n¿Está seguro de querer hacerlo?"; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "%s canales censurados/no censurados", + 1 => "%s canales censurados/no censurados", +); +$a->strings["%s channel code allowed/disallowed"] = array( + 0 => "%s código permitido/no permitido al canal", + 1 => "%s código permitido/no permitido al canal", +); +$a->strings["%s channel deleted"] = array( + 0 => "%s canales eliminados", + 1 => "%s canales eliminados", +); +$a->strings["Channel not found"] = "Canal no encontrado"; +$a->strings["Channel '%s' deleted"] = "Canal '%s' eliminado"; +$a->strings["Channel '%s' censored"] = "Canal '%s' censurado"; +$a->strings["Channel '%s' uncensored"] = "Canal '%s' no censurado"; +$a->strings["Channel '%s' code allowed"] = "Código permitido al canal '%s'"; +$a->strings["Channel '%s' code disallowed"] = "Código no permitido al canal '%s'"; +$a->strings["Censor"] = "Censurar"; +$a->strings["Uncensor"] = "No censurar"; +$a->strings["Allow Code"] = "Permitir código"; +$a->strings["Disallow Code"] = "No permitir código"; +$a->strings["UID"] = "UID"; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = "Los canales seleccionados se eliminarán!\\n\\nTodo lo publicado por estos canales en este sitio se borrarán definitivamente!\\n\\n¿Está seguro de querer hacerlo?"; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = "El canal {0} va a ser eliminado!\\n\\nTodo lo publicado por el canal en este sitio se borrará definitivamente!\\n\\n¿Está seguro de querer hacerlo?"; +$a->strings["Plugin %s disabled."] = "Plugin %s desactivado."; +$a->strings["Plugin %s enabled."] = "Plugin %s activado."; +$a->strings["Disable"] = "Desactivar"; +$a->strings["Enable"] = "Activar"; +$a->strings["Toggle"] = "Cambiar"; +$a->strings["Author: "] = "Autor:"; +$a->strings["Maintainer: "] = "Mantenedor:"; +$a->strings["No themes found."] = "No se han encontrado temas."; +$a->strings["Screenshot"] = "Instantánea de pantalla"; +$a->strings["[Experimental]"] = "[Experimental]"; +$a->strings["[Unsupported]"] = "[No soportado]"; +$a->strings["Log settings updated."] = "Actualizado el informe de configuraciones."; +$a->strings["Clear"] = "Vaciar"; +$a->strings["Debugging"] = "Depurando"; +$a->strings["Log file"] = "Fichero de informe"; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = "Debe tener permisos de escritura para el servidor web. Ruta relativa al directorio raíz de Red."; +$a->strings["Log level"] = "Nivel de depuración"; +$a->strings["New Profile Field"] = "Nuevo campo en el perfil"; +$a->strings["Field nickname"] = "Alias del campo"; +$a->strings["System name of field"] = "Nombre del campo en el sistema"; +$a->strings["Input type"] = "Tipo de entrada"; +$a->strings["Field Name"] = "Nombre del campo"; +$a->strings["Label on profile pages"] = "Etiqueta a mostrar en las páginas del perfil"; +$a->strings["Help text"] = "Texto de ayuda"; +$a->strings["Additional info (optional)"] = "Información adicional (opcional)"; +$a->strings["Field definition not found"] = "Definición del campo no encontrada"; +$a->strings["Edit Profile Field"] = "Modificar el campo del perfil"; +$a->strings["Unable to find your hub."] = "No se puede encontrar su servidor."; +$a->strings["Post successful."] = "Enviado con éxito."; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Se ha superado el límite máximo de inscripciones diarias de este sitio. Por favor, pruebe de nuevo mañana."; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Por favor, confirme que acepta los Términos del servicio. El registro ha fallado."; +$a->strings["Passwords do not match."] = "Las contraseñas no coinciden."; +$a->strings["Registration successful. Please check your email for validation instructions."] = "Registro realizado con éxito. Por favor, compruebe su correo electrónico para ver las instrucciones para validarlo."; +$a->strings["Your registration is pending approval by the site owner."] = "Su registro está pendiente de aprobación por el propietario del sitio."; +$a->strings["Your registration can not be processed."] = "Su registro no puede ser procesado."; +$a->strings["Registration on this site/hub is by approval only."] = "El registro en este servidor/hub está sometido a aprobación previa."; +$a->strings["Register at another affiliated site/hub"] = "Inscribirse en un servidor/hub afiliado"; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Este sitio ha excedido el límite de inscripción diaria de cuentas. Por favor, inténtelo de nuevo mañana."; +$a->strings["Terms of Service"] = "Términos del servicio"; +$a->strings["I accept the %s for this website"] = "Acepto los %s de este sitio"; +$a->strings["I am over 13 years of age and accept the %s for this website"] = "Tengo más de 13 años de edad y acepto los %s de este sitio"; +$a->strings["Membership on this site is by invitation only."] = "Para registrarse en este sitio es necesaria una invitación."; +$a->strings["Please enter your invitation code"] = "Por favor, introduzca el código de su invitación"; +$a->strings["Your email address"] = "Su dirección de correo electrónico"; +$a->strings["Choose a password"] = "Elija una contraseña"; +$a->strings["Please re-enter your password"] = "Por favor, vuelva a escribir su contraseña"; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = "La eliminación de cuentas no está permitida hasta después de que hayan transcurrido 48 horas desde el último cambio de contraseña."; +$a->strings["Remove This Account"] = "Eliminar esta cuenta"; +$a->strings["WARNING: "] = "ATENCIÓN:"; +$a->strings["This account and all its channels will be completely removed from the network. "] = "Esta cuenta y todos sus canales van a ser eliminados de la red."; +$a->strings["This action is permanent and can not be undone!"] = "¡Esta acción tiene carácter definitivo y no se puede deshacer!"; +$a->strings["Please enter your password for verification:"] = "Por favor, introduzca su contraseña para su verificación:"; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = "Remover esta cuenta, todos sus canales y clones de la red"; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = "Por defecto, solo las instancias de los canales ubicados en este servidor serán eliminados de la red"; +$a->strings["Remove Account"] = "Eliminar cuenta"; +$a->strings["Help:"] = "Ayuda:"; +$a->strings["Not Found"] = "No encontrado"; +$a->strings["\$Projectname Documentation"] = "Documentación de \$Projectname"; +$a->strings["[Embedded content - reload page to view]"] = "[Contenido incorporado - recargue la página para poder verlo]"; +$a->strings["Remote privacy information not available."] = "La información privada remota no está disponible."; +$a->strings["Visible to:"] = "Visible para:"; +$a->strings["Name is required"] = "El nombre es obligatorio"; +$a->strings["Key and Secret are required"] = "Clave y Secreto son obligatorios"; +$a->strings["Diaspora Policy Settings updated."] = "Configuración de directivas de Diaspora actualizada."; +$a->strings["Passwords do not match. Password unchanged."] = "Las contraseñas no coinciden. La contraseña no se ha cambiado."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "No se permiten contraseñas vacías. La contraseña no se ha cambiado."; +$a->strings["Password changed."] = "Constraseña cambiada."; +$a->strings["Password update failed. Please try again."] = "La actualización de la contraseña ha fallado. Por favor, inténtalo de nuevo."; +$a->strings["Not valid email."] = "Correo electrónico no válido."; +$a->strings["Protected email address. Cannot change to that email."] = "Dirección de correo electrónico protegida. No se puede cambiar a ella."; +$a->strings["System failure storing new email. Please try again."] = "Fallo de sistema al guardar el nuevo correo electrónico. Por favor, inténtelo de nuevo."; +$a->strings["Settings updated."] = "Configuración actualizada."; +$a->strings["Add application"] = "Añadir aplicación"; +$a->strings["Name of application"] = "Nombre de la aplicación"; +$a->strings["Consumer Key"] = "Clave de consumidor"; +$a->strings["Automatically generated - change if desired. Max length 20"] = "Generado automáticamente - si lo desea, cámbielo. Longitud máxima: 20"; +$a->strings["Consumer Secret"] = "Secreto de consumidor"; +$a->strings["Redirect"] = "Redirigir"; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = "URI de redirección - dejar en blanco a menos que su aplicación específicamente lo requiera"; +$a->strings["Icon url"] = "url de icono"; +$a->strings["Optional"] = "Opcional"; +$a->strings["You can't edit this application."] = "No puede modificar esta aplicación."; +$a->strings["Connected Apps"] = "Aplicaciones conectadas"; +$a->strings["Client key starts with"] = "La clave de cliente empieza por"; +$a->strings["No name"] = "Sin nombre"; +$a->strings["Remove authorization"] = "Eliminar autorización"; +$a->strings["No feature settings configured"] = "No se ha establecido la configuración de características"; +$a->strings["Feature/Addon Settings"] = "Configuración de característica/complemento"; +$a->strings["Settings for the built-in Diaspora emulator"] = "Configuración para el emulador de Diaspora incorporado"; +$a->strings["Allow any Diaspora member to comment on your public posts"] = "Permitir a cualquier miembro de Diaspora comentar en sus publicaciones públicas"; +$a->strings["Enable the Diaspora protocol for this channel"] = "Activar el protocolo de Diaspora para este canal"; +$a->strings["Diaspora Policy Settings"] = "Configuración de directivas de Diaspora"; +$a->strings["Prevent your hashtags from being redirected to other sites"] = "Impedir que sus \"hashtags\" sean redirigidos a otros sitios "; +$a->strings["Account Settings"] = "Configuración de la cuenta"; +$a->strings["Enter New Password:"] = "Introduzca la nueva contraseña:"; +$a->strings["Confirm New Password:"] = "Confirma la nueva contraseña:"; +$a->strings["Leave password fields blank unless changing"] = "Dejar en blanco los campos de contraseña a menos que cambie"; +$a->strings["Email Address:"] = "Dirección de correo electrónico:"; +$a->strings["Remove this account including all its channels"] = "Eliminar esta cuenta incuyendo todos sus canales"; +$a->strings["Off"] = "Desactivado"; +$a->strings["On"] = "Activado"; +$a->strings["Additional Features"] = "Características adicionales"; +$a->strings["Connector Settings"] = "Configuración de conector"; +$a->strings["No special theme for mobile devices"] = "Sin tema especial para dispositivos móviles"; +$a->strings["%s - (Experimental)"] = "%s - (Experimental)"; +$a->strings["Display Settings"] = "Configuración de visualización"; +$a->strings["Theme Settings"] = "Ajustes del tema"; +$a->strings["Custom Theme Settings"] = "Ajustes personalizados del tema"; +$a->strings["Content Settings"] = "Ajustes del contenido"; +$a->strings["Display Theme:"] = "Tema de visualización:"; +$a->strings["Mobile Theme:"] = "Tema móvil:"; +$a->strings["Enable user zoom on mobile devices"] = "Habilitar zoom de usuario en dispositivos móviles"; +$a->strings["Update browser every xx seconds"] = "Actualizar navegador cada xx segundos"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Mínimo de 10 segundos, sin máximo"; +$a->strings["Maximum number of conversations to load at any time:"] = "Máximo número de conversaciones a cargar en cualquier momento:"; +$a->strings["Maximum of 100 items"] = "Máximo de 100 elementos"; +$a->strings["Show emoticons (smilies) as images"] = "Mostrar emoticonos (smilies) como imágenes"; +$a->strings["Link post titles to source"] = "Enlazar título de la publicación a la fuente"; +$a->strings["System Page Layout Editor - (advanced)"] = "Editor de sistema de distribución de página - (avanzado)"; +$a->strings["Use blog/list mode on channel page"] = "Usar modo blog/lista en página del canal"; +$a->strings["(comments displayed separately)"] = "(comentarios mostrados de forma separada)"; +$a->strings["Use blog/list mode on matrix page"] = "Mostrar su red en modo blog/lista"; +$a->strings["Channel page max height of content (in pixels)"] = "Altura máxima del contenido de la página del canal (en píxeles)"; +$a->strings["click to expand content exceeding this height"] = "Pulsa para expandir el contenido que excede esta altura"; +$a->strings["Matrix page max height of content (in pixels)"] = "Altura máxima del contenido de la página de matrix (en píxeles)"; +$a->strings["Nobody except yourself"] = "Nadie excepto tú"; +$a->strings["Only those you specifically allow"] = "Solamente aquellos a los que tú permitas específicamente"; +$a->strings["Approved connections"] = "Conexiones aprobadas"; +$a->strings["Any connections"] = "Cualquier conexión"; +$a->strings["Anybody on this website"] = "Cualquiera en este website"; +$a->strings["Anybody in this network"] = "Cualquiera en esta red"; +$a->strings["Anybody authenticated"] = "Cualquiera autenticado"; +$a->strings["Anybody on the internet"] = "Cualquiera en internet"; +$a->strings["Publish your default profile in the network directory"] = "Publicar tu perfil predeterminado en el directorio de la red"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "¿Nos permite sugerirle como amigo potencial a los nuevos miembros?"; +$a->strings["Your channel address is"] = "Su dirección de canal es"; +$a->strings["Channel Settings"] = "Configuración del canal"; +$a->strings["Basic Settings"] = "Configuración básica"; +$a->strings["Your Timezone:"] = "Su zona horaria:"; +$a->strings["Default Post Location:"] = "Ubicación de publicación predeterminada:"; +$a->strings["Geographical location to display on your posts"] = "Localización geográfica a mostrar en sus publicaciones"; +$a->strings["Use Browser Location:"] = "Usar localización de navegador:"; +$a->strings["Adult Content"] = "Contenido solo para adultos"; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = "Este canal publica contenido solo para adultos con frecuencia o regularmente. (Por favor etiquete cualquier material para adultos con la etiqueta #NSFW)"; +$a->strings["Security and Privacy Settings"] = "Configuración de seguridad y privacidad"; +$a->strings["Your permissions are already configured. Click to view/adjust"] = "Sus permisos ya están configurados. Pulse para ver/ajustar"; +$a->strings["Hide my online presence"] = "Oculta mi presencia online"; +$a->strings["Prevents displaying in your profile that you are online"] = "Evita mostrar en su perfil que está en línea"; +$a->strings["Simple Privacy Settings:"] = "Configuración de privacidad sencilla:"; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = "Muy Público - extremadamente permisivo (debería ser usado con precaución)"; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = "Típico - por defecto público, privado cuando se desee (similar a los permisos de red social pero con privacidad mejorada)"; +$a->strings["Private - default private, never open or public"] = "Privado - por defecto privado, nunca abierto o público"; +$a->strings["Blocked - default blocked to/from everybody"] = "Bloqueado - por defecto bloqueado bloqueado a/para cualquiera"; +$a->strings["Allow others to tag your posts"] = "Permitir a otros etiquetar sus publicaciones"; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = "A menudo usado por la comunidad para marcar contenido inapropiado de forma retroactiva."; +$a->strings["Advanced Privacy Settings"] = "Configuración de privacidad avanzada"; +$a->strings["Expire other channel content after this many days"] = "Caducar contenido de otro canal después de este número de días"; +$a->strings["0 or blank prevents expiration"] = "0 o vacío evita la expiración"; +$a->strings["Maximum Friend Requests/Day:"] = "Máximo de solicitudes de amistad por día:"; +$a->strings["May reduce spam activity"] = "Podría reducir la actividad de spam"; +$a->strings["Default Post Permissions"] = "Permidos de publicación predeterminados"; +$a->strings["Channel permissions category:"] = "Categoría de permisos del canal:"; +$a->strings["Maximum private messages per day from unknown people:"] = "Máximo de mensajes privados por día de gente desconocida:"; +$a->strings["Useful to reduce spamming"] = "Útil para reducir el envío de correo no deseado"; +$a->strings["Notification Settings"] = "Configuración de notificaciones"; +$a->strings["By default post a status message when:"] = "Por defecto, enviar un mensaje de estado cuando:"; +$a->strings["accepting a friend request"] = "acepte una solicitud de amistad"; +$a->strings["joining a forum/community"] = "unirse a un foro o comunidad"; +$a->strings["making an interesting profile change"] = "realice un cambio interesante en su perfil"; +$a->strings["Send a notification email when:"] = "Enviar una notificación por correo electrónico cuando:"; +$a->strings["You receive a connection request"] = "Reciba una solicitud de conexión"; +$a->strings["Your connections are confirmed"] = "Su conexión haya sido confirmada"; +$a->strings["Someone writes on your profile wall"] = "Alguien escriba en el muro de su perfil"; +$a->strings["Someone writes a followup comment"] = "Alguien escriba un comentario sobre sus publicaciones"; +$a->strings["You receive a private message"] = "Reciba un mensaje privado"; +$a->strings["You receive a friend suggestion"] = "Reciba una sugerencia de amistad"; +$a->strings["You are tagged in a post"] = "Usted es etiquetado en una publicación"; +$a->strings["You are poked/prodded/etc. in a post"] = "Ha recibido un toque o ha sido incitado, etc. en una publicación"; +$a->strings["Show visual notifications including:"] = "Mostrar notificaciones visuales que incluyan:"; +$a->strings["Unseen matrix activity"] = "Actividad no vista en la red"; +$a->strings["Unseen channel activity"] = "Actividad no vista en el canal"; +$a->strings["Unseen private messages"] = "Mensajes privados no leídos"; +$a->strings["Recommended"] = "Recomendado"; +$a->strings["Upcoming events"] = "Próximos eventos"; +$a->strings["Events today"] = "Eventos de hoy"; +$a->strings["Upcoming birthdays"] = "Próximos cumpleaños"; +$a->strings["Not available in all themes"] = "No disponible en todos los temas"; +$a->strings["System (personal) notifications"] = "Notificaciones del sistema (personales)"; +$a->strings["System info messages"] = "Mensajes de información del sistema"; +$a->strings["System critical alerts"] = "Alertas críticas del sistema"; +$a->strings["New connections"] = "Nuevas conexiones"; +$a->strings["System Registrations"] = "Registros del sistema"; +$a->strings["Also show new wall posts, private messages and connections under Notices"] = "Mostrar también en Avisos las nuevas publicaciones, los mensajes privados y las conexiones"; +$a->strings["Notify me of events this many days in advance"] = "Avisarme de los eventos con algunos días de antelación"; +$a->strings["Must be greater than 0"] = "Debe ser mayor que 0"; +$a->strings["Advanced Account/Page Type Settings"] = "Ajustes avanzados de la cuenta y de los tipos de página"; +$a->strings["Change the behaviour of this account for special situations"] = "Cambiar el comportamiento de esta cuenta en situaciones especiales"; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = "Activar modo experto (en Ajustes > Características Adicionales) para ajustar."; +$a->strings["Miscellaneous Settings"] = "Ajustes diversos"; +$a->strings["Personal menu to display in your channel pages"] = "Menú personal que debe mostrarse en las páginas de su canal"; +$a->strings["Remove Channel"] = "Eliminar canal"; +$a->strings["Remove this channel."] = "Eliminar este canal."; +$a->strings["First Name"] = "Nombre"; +$a->strings["Last Name"] = "Apellido"; +$a->strings["Nickname"] = "Alias"; +$a->strings["Full Name"] = "Nombre completo"; +$a->strings["Profile Photo 16px"] = "Foto de perfil 16px"; +$a->strings["Profile Photo 32px"] = "Foto de perfil 32px"; +$a->strings["Profile Photo 48px"] = "Foto de perfil 48px"; +$a->strings["Profile Photo 64px"] = "Foto de perfil 64px"; +$a->strings["Profile Photo 80px"] = "Foto de perfil 80px"; +$a->strings["Profile Photo 128px"] = "Foto de perfil 128px"; +$a->strings["Timezone"] = "Zona horaria"; +$a->strings["Homepage URL"] = "Dirección de la página personal"; +$a->strings["Birth Year"] = "Año de nacimiento"; +$a->strings["Birth Month"] = "Mes de nacimiento"; +$a->strings["Birth Day"] = "Día de nacimiento"; +$a->strings["Birthdate"] = "Fecha de nacimiento"; +$a->strings["Conversation removed."] = "Conversación eliminada."; +$a->strings["No messages."] = "Sin mensajes."; +$a->strings["Delete conversation"] = "Eliminar conversación"; +$a->strings["D, d M Y - g:i A"] = "D d M Y - G:i"; +$a->strings["Set your current mood and tell your friends"] = "Describir su estado de ánimo para comunicárselo a sus amigos"; +$a->strings["Total votes"] = "Total de votos"; +$a->strings["Average Rating"] = "Valoración media"; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "La eliminación de canales no está permitida hasta pasadas 48 horas desde el último cambio de contraseña."; +$a->strings["Remove This Channel"] = "Eliminar este canal"; +$a->strings["This channel will be completely removed from the network. "] = "Este canal va a ser completamente eliminado de la red."; +$a->strings["Remove this channel and all its clones from the network"] = "Eliminar este canal y todos sus clones de la red"; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = "Por defecto, solo la instancia del canal alojado en este servidor será eliminado de la red"; +$a->strings["is now connected to"] = "ahora está conectado a"; +$a->strings["Could not access address book record."] = "No se pudo acceder a la entrada en su libreta de direcciones."; +$a->strings["Refresh failed - channel is currently unavailable."] = "Recarga fallida - no se puede encontrar actualmente el canal"; +$a->strings["Unable to set address book parameters."] = "No ha sido posible establecer los parámetros de la libreta de direcciones."; +$a->strings["Connection has been removed."] = "La conexión ha sido eliminada."; +$a->strings["View %s's profile"] = "Ver el perfil de %s"; +$a->strings["Refresh Permissions"] = "Recargar los permisos"; +$a->strings["Fetch updated permissions"] = "Obtener los permisos actualizados"; +$a->strings["Recent Activity"] = "Actividad reciente"; +$a->strings["View recent posts and comments"] = "Ver publicaciones y comentarios recientes"; +$a->strings["Block (or Unblock) all communications with this connection"] = "Bloquear (o desbloquear) todas las comunicaciones con esta conexión"; +$a->strings["This connection is blocked!"] = "¡Esta conexión está bloqueada!"; +$a->strings["Unignore"] = "Dejar de ignorar"; +$a->strings["Ignore"] = "Ignorar"; +$a->strings["Ignore (or Unignore) all inbound communications from this connection"] = "Ignorar (o dejar de ignorar) todas las comunicaciones entrantes de esta conexión"; +$a->strings["This connection is ignored!"] = "¡Esta conexión es ignorada!"; +$a->strings["Unarchive"] = "Desarchivar"; +$a->strings["Archive"] = "Archivar"; +$a->strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = "Archiva (o desarchiva) esta conexión - marca el canal como muerto aunque mantiene sus contenidos"; +$a->strings["This connection is archived!"] = "¡Esta conexión esta archivada!"; +$a->strings["Unhide"] = "Mostrar"; +$a->strings["Hide"] = "Ocultar"; +$a->strings["Hide or Unhide this connection from your other connections"] = "Ocultar o mostrar esta conexión a sus otras conexiones"; +$a->strings["This connection is hidden!"] = "¡Esta conexión está oculta!"; +$a->strings["Delete this connection"] = "Eliminar esta conexión"; +$a->strings["Approve this connection"] = "Aprobar esta conexión"; +$a->strings["Accept connection to allow communication"] = "Aceptar la conexión para permitir la comunicación"; +$a->strings["Set Affinity"] = "Ajustar Afinidad"; +$a->strings["Set Profile"] = "Ajustar Perfil"; +$a->strings["Set Affinity & Profile"] = "Ajustar Afinidad y Perfil"; +$a->strings["Apply these permissions automatically"] = "Aplicar estos permisos automaticamente"; +$a->strings["This connection's address is"] = "Esta dirección de conexión es"; +$a->strings["The permissions indicated on this page will be applied to all new connections."] = "Los permisos indicados en esta página serán aplicados en todas las nuevas conexiones."; +$a->strings["Slide to adjust your degree of friendship"] = "Deslizar para ajustar el grado de amistad"; +$a->strings["Slide to adjust your rating"] = "Deslizar para ajustar su valoración"; +$a->strings["Optionally explain your rating"] = "Opcionalmente, puede explicar su valoración"; +$a->strings["Custom Filter"] = "Filtro Personalizado"; +$a->strings["Only import posts with this text"] = "Importar solo entradas que contengan este texto"; +$a->strings["words one per line or #tags or /patterns/, leave blank to import all posts"] = "Palabras, una por línea o #etiquetas o /patrones/, dejar en blanco para importar todas las entradas"; +$a->strings["Do not import posts with this text"] = "No importes entradas conteniendo este texto"; +$a->strings["This information is public!"] = "Esta información es pública!"; +$a->strings["Connection Pending Approval"] = "Conexión Pendiente de Aprobación"; +$a->strings["Connection Request"] = "Petición de Conexión"; +$a->strings["(%s) would like to connect with you. Please approve this connection to allow communication."] = "(%s) desearía conectar contigo. por favor, aprueba esta conexión para permitir la comunicación."; +$a->strings["Approve Later"] = "Aprobar Más Tarde"; +$a->strings["inherited"] = "heredado"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Por favor, escoja el perfil que quiere mostrar a %s cuando esté viendo su perfil de forma segura."; +$a->strings["Their Settings"] = "Sus Ajustes"; +$a->strings["My Settings"] = "Mis Ajustes"; +$a->strings["Individual Permissions"] = "Permisos Individuales"; +$a->strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can not change those settings here."] = "Algunos permisos pueden ser heredados de los ajustes de privacidad de sus canales, los cuales tienen una prioridad más alta que los ajustes individuales. No puede cambiar estos ajustes aquí."; +$a->strings["Some permissions may be inherited from your channel's privacy settings, which have higher priority than individual settings. You can change those settings here but they wont have any impact unless the inherited setting changes."] = "Algunos permisos pueden ser heredados de los ajustes de privacidad de sus canales, los cuales tienen una prioridad más alta que los ajustes individuales. Puede cambiar estos ajustes aquí pero no tendrán ningún impacto hasta que cambie los ajustes heredados."; +$a->strings["Last update:"] = "Última actualización:"; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Encontramos un problema durante el inicio de sesión con la OpenID que proporcionaste. por favor, comprueba la escritura correcta de la ID."; +$a->strings["The error message was:"] = "El mensaje de error fue:"; +$a->strings["Authentication failed."] = "Falló la autenticación."; +$a->strings["Remote Authentication"] = "Acceso desde su servidor"; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Introduzca la dirección del canal (p.e. channel@example.com)"; +$a->strings["Authenticate"] = "Identifíquese"; +$a->strings["Unable to lookup recipient."] = "No ha sido posible de "; +$a->strings["Unable to communicate with requested channel."] = "Incapaz de comunicar con el canal solicitado."; +$a->strings["Cannot verify requested channel."] = "No puedo verificar el canal solicitado."; +$a->strings["Selected channel has private message restrictions. Send failed."] = "El canal seleccionado tiene restricciones sobre los mensajes privados. El envió falló."; +$a->strings["Message deleted."] = "Mensaje eliminado."; +$a->strings["Message recalled."] = "Mensaje recuperado."; +$a->strings["Send Private Message"] = "Envía un Mensaje Privado"; +$a->strings["To:"] = "Para:"; +$a->strings["Subject:"] = "Asunto:"; +$a->strings["Send"] = "Envia"; +$a->strings["Message not found."] = "No se encuentra el mensaje."; +$a->strings["Delete message"] = "Mensaje eliminado"; +$a->strings["Recall message"] = "Mensaje recuperado"; +$a->strings["Message has been recalled."] = "El mensaje ha sido recuperado."; +$a->strings["Private Conversation"] = "Conversación Privada"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Comunicación segura no disponible. Pero puede responder desde la página de perfil del remitente."; +$a->strings["Send Reply"] = "Envía Respuesta"; +$a->strings["Invalid request identifier."] = "Petición inválida del identificador."; +$a->strings["Discard"] = "Descarta"; +$a->strings["Please login."] = "Por favor, inicia sesión."; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "La autenticación desde su servidor está bloqueada. Ha iniciado sesión localmente. Por favor, salga de la sesión y vuelva a intentarlo."; +$a->strings["Add a Channel"] = "Añade un Canal"; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = "Un canal es su propia colección de páginas web relacionadas. Un canal se puede utilizar para almacenar los perfiles sociales de la red, blogs, grupos de conversación y foros, páginas de famosos y mucho más. Puede crear tantos canales como su proveedor de servicio permita."; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = "Ejemplos: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "; +$a->strings["Choose a short nickname"] = "Elija un alias corto"; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "Su alias podrá usarse para crear una dirección de canal fácilmente memorizable (como una dirección de correo electrónico) el cual puede ser compartido con otros."; +$a->strings["Or import an existing channel from another location"] = "O importar un canal existente de otro lugar"; +$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = "elija el tipo de canal (como red social o foro de comunidad) y la privacidad que requiera, así podemos seleccionar el mejor conjunto de permisos para usted"; +$a->strings["Channel Type"] = "Tipo de Canal"; +$a->strings["Read more about roles"] = "Lea más sobre los roles"; +$a->strings["App installed."] = "Aplicación instalada."; +$a->strings["Malformed app."] = "Aplicación malformada"; +$a->strings["Embed code"] = "codigo embebido"; +$a->strings["Edit App"] = "Modificar la aplicación"; +$a->strings["Create App"] = "Crear una aplicación"; +$a->strings["Name of app"] = "Nombre de la aplicación"; +$a->strings["Location (URL) of app"] = "Ubicación (URL) de la aplicación"; +$a->strings["Photo icon URL"] = "Foto del icono URL"; +$a->strings["80 x 80 pixels - optional"] = "80 x 80 pixels - opcional"; +$a->strings["Version ID"] = "Versión ID"; +$a->strings["Price of app"] = "Precio de la aplicación"; +$a->strings["Location (URL) to purchase app"] = "Ubicación (URL) para conseguir la aplicación"; +$a->strings["sent you a private message"] = "envia un mensaje privado"; +$a->strings["added your channel"] = "se añadió su canal"; +$a->strings["posted an event"] = "publicó un evento"; +$a->strings["Comanche page description language help"] = "Página de ayuda de la descripción del lenguaje Comanche"; +$a->strings["Layout Description"] = "Descripción del Formato Gráfico"; +$a->strings["Download PDL file"] = "Descarga el fichero PDL"; +$a->strings["Welcome to %s"] = "Bienvenido a %s"; +$a->strings["Lorem Ipsum"] = "Lorem Ipsum"; +$a->strings["Bookmark added"] = "Marcador añadido"; +$a->strings["My Bookmarks"] = "Mis Marcadores"; +$a->strings["My Connections Bookmarks"] = "Mis Marcadores de Conexiones"; +$a->strings["Insufficient permissions. Request redirected to profile page."] = "Permisos insuficientes. Petición redirigida a la página de perfil."; +$a->strings["This setting requires special processing and editing has been blocked."] = "Este ajuste necesita de un proceso especial y la edición ha sido bloqueada."; +$a->strings["Configuration Editor"] = "Editor de Configuración"; +$a->strings["Warning: Changing some settings could render your channel inoperable. Please leave this page unless you are comfortable with and knowledgeable about how to correctly use this feature."] = "Atención: El cambio de algunos ajustes puede convertir su canal en inoperable. Por favor, abandone la página excepto que esté seguro y sepa cómo usar correctamente esta característica."; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "No hay sugerencias disponibles. Si es un sitio nuevo, espere 24 horas y pruebe de nuevo."; +$a->strings["Poll"] = "Sondea"; +$a->strings["View Results"] = "Mostrar Resultados"; +$a->strings["No service class restrictions found."] = "No se han encontrado clases de restricción de servicio."; +$a->strings["Files: shared with me"] = "Ficheros: compartidos conmigo"; +$a->strings["NEW"] = "NUEVO"; +$a->strings["Remove all files"] = "Borrar todos los ficheros"; +$a->strings["Remove this file"] = "Borra este archivo"; +$a->strings["Schema Default"] = "Esquema Predeterminado"; +$a->strings["Sans-Serif"] = "Sans-Serif"; +$a->strings["Monospace"] = "Monospace"; +$a->strings["Theme settings"] = "Ajustes de tema"; +$a->strings["Set scheme"] = "Ajustar esquema"; +$a->strings["Set font-size for posts and comments"] = "Ajustar el tamaño del tipo de letra para entradas y comentarios"; +$a->strings["Set font face"] = "Ajustar el tipo de letra"; +$a->strings["Set iconset"] = "Ajustar el conjunto de iconos"; +$a->strings["Set big shadow size, default 15px 15px 15px"] = "Ajustar el sombreado grande, por defecto 15px 15px 15px"; +$a->strings["Set small shadow size, default 5px 5px 5px"] = "Ajustar el sombreado pequeño, por defecto 5px 5px 5px"; +$a->strings["Set shadow color, default #000"] = "Ajustar el color del sombreado, predeterminado a #000"; +$a->strings["Set radius size, default 5px"] = "Ajusta el tamaño del radio, predeterminado a 5px"; +$a->strings["Set line-height for posts and comments"] = "Ajustar la altura de linea para entradas y comentarios"; +$a->strings["Set background image"] = "Ajusta la imagen de fondo"; +$a->strings["Set background attachment"] = "Ajustar el fondo adjuntado"; +$a->strings["Set background color"] = "Ajustar el color de fondo"; +$a->strings["Set section background image"] = "Ajustar la imagen de la sección del fondo"; +$a->strings["Set section background color"] = "Ajustar el color de la sección del fondo"; +$a->strings["Set color of items - use hex"] = "Ajustar el color de los elementos - utilizar código hexadecimal"; +$a->strings["Set color of links - use hex"] = "Ajusta el color de los enlaces - utilizar código hexadecimal"; +$a->strings["Set max-width for items. Default 400px"] = "Ajustar la anchura máxima para los elementos. Predeterminado a 400px"; +$a->strings["Set min-width for items. Default 240px"] = "Ajustar la anchura mínima para los elementos. Predeterminado a 240px"; +$a->strings["Set the generic content wrapper width. Default 48%"] = "Ajustar el ancho de la envoltura del contenido genérico. Predeterminado 48%"; +$a->strings["Set color of fonts - use hex"] = "Ajustar el color del tipo de letra - utiliza código hexadecimal"; +$a->strings["Set background-size element"] = "Ajustar el tamaño de fondo del elemento"; +$a->strings["Item opacity"] = "Opacidad del elemento"; +$a->strings["Display post previews only"] = "Muestra solo las previsualizaciones de las entradas"; +$a->strings["Display side bar on channel page"] = "Muestra la barra lateral en la página del canal"; +$a->strings["Colour of the navigation bar"] = "Color de la barra de navegación"; +$a->strings["Item float"] = "Elemento flotante"; +$a->strings["Left offset of the section element"] = "Desplazamiento izquierdo del elemento de la sección"; +$a->strings["Right offset of the section element"] = "Desplazamiento derecho del elemento de la sección"; +$a->strings["Section width"] = "Ancho de la sección"; +$a->strings["Left offset of the aside"] = "Desplazamiento izquierdo del lateral"; +$a->strings["Right offset of the aside element"] = "Desplazamiento derecho del elemento lateral"; +$a->strings["Light (Red Matrix default)"] = "Ligero (Red Matrix predeterminado)"; +$a->strings["Select scheme"] = "Elija un esquema"; +$a->strings["Narrow navbar"] = "Estrechar la barra de navegación"; +$a->strings["Navigation bar background color"] = "Color de fondo de la barra de navegación"; +$a->strings["Navigation bar gradient top color"] = "Color superior del gradiente de la barra de navegación"; +$a->strings["Navigation bar gradient bottom color"] = "Color inferior del gradiente de la barra de navegación"; +$a->strings["Navigation active button gradient top color"] = "Color superior del gradiente del botón activo de navegación"; +$a->strings["Navigation active button gradient bottom color"] = "Color inferior del gradiente del botón activo de navegación"; +$a->strings["Navigation bar border color "] = "Color del borde de la barra de navegación"; +$a->strings["Navigation bar icon color "] = "Color del icono de la barra de navegación"; +$a->strings["Navigation bar active icon color "] = "Color del icono activo de la barra de navegación"; +$a->strings["link color"] = "Color del enlace"; +$a->strings["Set font-color for banner"] = "Ajustar el color del tipo de letra para la pancarta"; +$a->strings["Set the background color"] = "Ajustar el color de fondo"; +$a->strings["Set the background image"] = "Ajustar la imagen de fondo"; +$a->strings["Set the background color of items"] = "Ajustar el color de los elementos de fondo"; +$a->strings["Set the background color of comments"] = "Ajustar el color de fondo de los comentarios"; +$a->strings["Set the border color of comments"] = "Ajustar el color del borde de los comentarios"; +$a->strings["Set the indent for comments"] = "Ajusta la indentación de los comentarios"; +$a->strings["Set the basic color for item icons"] = "Ajustar el color básico para los iconos de los elementos"; +$a->strings["Set the hover color for item icons"] = "Ajustar el color flotante para los iconos de los elementos"; +$a->strings["Set font-size for the entire application"] = "Ajustar el tamaño del tipo de letra para toda la aplicación"; +$a->strings["Example: 14px"] = "Ejemplo: 14px"; +$a->strings["Set font-color for posts and comments"] = "Establecer el color de la fuente para publicaciones y comentarios"; +$a->strings["Set radius of corners"] = "Establecer el radio de curvatura de las esquinas"; +$a->strings["Set shadow depth of photos"] = "Ajustar la profundidad de sombras de las fotos"; +$a->strings["Set maximum width of content region in pixel"] = "Ajustar la anchura máxima de la región de contenido, en pixels"; +$a->strings["Leave empty for default width"] = "Dejar en blanco para la anchura predeterminada"; +$a->strings["Center page content"] = "Contenido del centro de la página"; +$a->strings["Set minimum opacity of nav bar - to hide it"] = "Ajustar la opacidad mínima de la barra de navegación - para ocultarla"; +$a->strings["Set size of conversation author photo"] = "Ajustar el tamaño de la foto del autor de la conversación"; +$a->strings["Set size of followup author photos"] = "Ajustar el tamaño de foto de los seguidores del autor"; +$a->strings["Update %s failed. See error logs."] = "La actualización %s ha fallado. Mire el informe de errores."; +$a->strings["Update Error at %s"] = "Error de Actualización en %s"; +$a->strings["Create an account to access services and applications within the Red Matrix"] = "Crear una cuenta para acceder a los servicios y aplicaciones dentro de la red"; +$a->strings["Password"] = "Contraseña"; +$a->strings["Remember me"] = "Recuérdeme"; +$a->strings["Forgot your password?"] = "¿Olvidó su contraseña?"; +$a->strings["toggle mobile"] = "cambiar a móvil"; +$a->strings["Website SSL certificate is not valid. Please correct."] = "El certificado SSL del sitio web no es válido. Por favor, corríjalo."; +$a->strings["[red] Website SSL error for %s"] = "[red] SSL error de Sitio Web en %s"; +$a->strings["Cron/Scheduled tasks not running."] = "Las tareas de Cron/Planificador no funcionan."; +$a->strings["[red] Cron tasks not running on %s"] = "[red] Las tareas de Cron no están funcionando en %s"; diff --git a/sources/view/es/update_fail_eml.tpl b/sources/view/es/update_fail_eml.tpl new file mode 100644 index 00000000..6643947b --- /dev/null +++ b/sources/view/es/update_fail_eml.tpl @@ -0,0 +1,14 @@ +Hey, +Soy el servidor web en {{$sitename}}; + +Los desarrolladores de RedMatrix/Hubzilla han lanzado la actualización {{$update}} recientemente, +pero cuando se intentaba instalar, alguna cosa ha ido terriblemente mal. +Esto requiere intervención humana tan pronto como sea posible. +Por favor, contacte con algún desarrollador de Red si no puede arreglarlo +por sí mismo. Mi base se datos puede quedar inservible. + + +El mensaje de error ha sido el siguiente: '{{$error}}'. + +Disculpe por cualquier inconveniente causado, + su servidor web en {{$siteurl}} diff --git a/sources/view/fr/htconfig.tpl b/sources/view/fr/htconfig.tpl new file mode 100644 index 00000000..a3b4c064 --- /dev/null +++ b/sources/view/fr/htconfig.tpl @@ -0,0 +1,71 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Matrice Rouge"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + +// Vos choix sont REGISTER_OPEN, REGISTER_APPROVE, ou REGISTER_CLOSED. +// Soyez certains de créer votre compte personnel avant de déclarer +// votre site REGISTER_CLOSED. 'register_text' (si vous décider de l'utiliser) +// renvois son contenu systématiquement sur la page d'enregistrement des nouveaux membres. +// REGISTER_APPROVE requiert la configuration de 'admin_email' avec l'adresse de courriel +// d'un membre déjà inscrit qui pourra autoriser et/ou approuver/supprimer la demande. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// taille maximale pour l'importation d'un message, 0 est illimité + +$a->config['system']['max_import_size'] = 200000; + +// taille maximale pour le téléversement de photos + +$a->config['system']['maximagesize'] = 8000000; + +// Lien absolu vers le compilateur PHP + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// configurez la façon dont votre site communique avec les autres serveurs. [Répertoire des membres inscrits à la Matrice] +// DIRECTORY_MODE_NORMAL = client du répertoire de membres, nous vous trouverons un répertoire accessible autre serveur. +// DIRECTORY_MODE_SECONDARY = copie mirroir du répertoire des membres. +// DIRECTORY_MODE_PRIMARY = répertoire des membres principal. +// DIRECTORY_MODE_STANDALONE = "autonome/déconnecté" ou répertoire de membres privés + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// Thème par défaut + +$a->config['system']['theme'] = 'redbasic'; + diff --git a/sources/view/fr/lostpass_eml.tpl b/sources/view/fr/lostpass_eml.tpl new file mode 100644 index 00000000..0421d41a --- /dev/null +++ b/sources/view/fr/lostpass_eml.tpl @@ -0,0 +1,30 @@ + +Cher {{$username}}, + Une demande pour réinitialiser votre mot de passe a récemment été reçue par {{$sitename}} +Pour confirmer cette requête, veuillez suivre le lien de vérification +ci-dessous ou en faire un copier-coller dans la barre d'adresse de votre navigateur. + +Si vous N'AVEZ PAS demandé ce changement, NE SUIVEZ PAS ce lien, ignorez-le simplement et/ou supprimez ce courriel. + +Votre mot de passe ne sera pas changé à moins que nous puissions vérifier vos intentions. + +Suivez ce lien pour confirmer votre identité: + +{{$reset_link}} + +Vous recevrez ensuite un second courriel avec votre nouveau mot de passe. + +Vous pouvez changer ce mot de passe à partir des réglages du profil après vous être connecté. + +Voici les détails de connexion: + +Emplacement du site:⇥{{$siteurl}} +Utilisateur:⇥{{$email}} + + + + +Sincèrement, + L'administrateur {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/fr/messages.po b/sources/view/fr/messages.po new file mode 100644 index 00000000..c54cd5f2 --- /dev/null +++ b/sources/view/fr/messages.po @@ -0,0 +1,8034 @@ +# Hubzilla Project +# Copyright (C) 2012-2014 the Hubzilla Project +# This file is distributed under the same license as the Red package. +# +# Translators: +# Olivier , 2013-2014 +# Webmaster_Hubzilla.ca , 2014 +# Webmaster_Hubzilla.ca , 2014 +msgid "" +msgstr "" +"Project-Id-Version: Hubzilla\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-08-15 00:03-0700\n" +"PO-Revision-Date: 2014-08-17 00:08+0000\n" +"Last-Translator: Webmaster_Hubzilla.ca \n" +"Language-Team: French (http://www.transifex.com/projects/p/red-matrix/language/fr/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: fr\n" +"Plural-Forms: nplurals=2; plural=(n > 1);\n" + +#: ../../include/dba/dba_driver.php:50 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "Impossible de trouver les infos DNS du serveur de base de données '%s'" + +#: ../../include/photo/photo_driver.php:653 ../../include/photos.php:51 +#: ../../mod/profile_photo.php:142 ../../mod/profile_photo.php:301 +#: ../../mod/profile_photo.php:421 ../../mod/photos.php:91 +#: ../../mod/photos.php:659 ../../mod/photos.php:681 +msgid "Profile Photos" +msgstr "Photos du profil" + +#: ../../include/diaspora.php:610 +#, php-format +msgid "%1$s is now friends with %2$s" +msgstr "%1$s et %2$s sont maintenant amis." + +#: ../../include/diaspora.php:693 +msgid "Sharing notification from Diaspora network" +msgstr "Partage de vos notifications du réseau Diaspora" + +#: ../../include/diaspora.php:1910 ../../include/text.php:1732 +#: ../../include/conversation.php:120 ../../mod/subthread.php:72 +#: ../../mod/subthread.php:174 ../../mod/tagger.php:45 ../../mod/like.php:294 +msgid "photo" +msgstr "photo" + +#: ../../include/diaspora.php:1910 ../../include/text.php:1738 +#: ../../include/conversation.php:148 ../../mod/subthread.php:72 +#: ../../mod/subthread.php:174 ../../mod/tagger.php:53 ../../mod/like.php:294 +msgid "status" +msgstr "le statut" + +#: ../../include/diaspora.php:1926 ../../include/conversation.php:164 +#: ../../mod/like.php:331 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "%1$s aime %3$s de %2$s" + +#: ../../include/diaspora.php:2303 +msgid "Attachments:" +msgstr "Pièces jointes:" + +#: ../../include/oembed.php:163 +msgid "Embedded content" +msgstr "Contenu imbriqué" + +#: ../../include/oembed.php:172 +msgid "Embedding disabled" +msgstr "Imbrication désactivée" + +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "a publié" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +msgstr "a commenté la publication de %s" + +#: ../../include/apps.php:123 +msgid "Site Admin" +msgstr "Administrateur" + +#: ../../include/apps.php:124 ../../include/nav.php:100 +#: ../../include/conversation.php:1543 +msgid "Bookmarks" +msgstr "Favoris" + +#: ../../include/apps.php:125 +msgid "Address Book" +msgstr "Carnet d'adresses" + +#: ../../include/apps.php:126 ../../include/nav.php:106 ../../boot.php:1498 +msgid "Login" +msgstr "Connexion" + +#: ../../include/apps.php:127 ../../include/nav.php:196 +msgid "Channel Select" +msgstr "Changer de canal" + +#: ../../include/apps.php:128 ../../include/nav.php:170 +msgid "Matrix" +msgstr "Matrice" + +#: ../../include/apps.php:129 ../../include/nav.php:198 +#: ../../include/widgets.php:514 ../../mod/admin.php:987 +#: ../../mod/admin.php:1192 +msgid "Settings" +msgstr "Réglages" + +#: ../../include/apps.php:130 ../../include/nav.php:92 +#: ../../include/reddav.php:1280 ../../include/conversation.php:1521 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "Fichiers" + +#: ../../include/apps.php:131 ../../include/nav.php:102 +#: ../../include/conversation.php:1554 ../../mod/webpages.php:79 +msgid "Webpages" +msgstr "Pages web" + +#: ../../include/apps.php:132 ../../include/nav.php:173 +msgid "Channel Home" +msgstr "Mon canal" + +#: ../../include/apps.php:133 ../../include/identity.php:973 +#: ../../include/identity.php:1091 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "Profil" + +#: ../../include/apps.php:134 ../../include/nav.php:91 +#: ../../include/conversation.php:1512 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "Photos" + +#: ../../include/apps.php:135 ../../include/nav.php:192 +#: ../../mod/events.php:396 +msgid "Events" +msgstr "Événements" + +#: ../../include/apps.php:136 ../../include/nav.php:159 +#: ../../mod/directory.php:226 +msgid "Directory" +msgstr "Annuaire" + +#: ../../include/apps.php:137 ../../include/nav.php:151 ../../mod/help.php:60 +#: ../../mod/help.php:65 +msgid "Help" +msgstr "Aide" + +#: ../../include/apps.php:138 ../../include/nav.php:184 +msgid "Mail" +msgstr "Messages" + +#: ../../include/apps.php:139 ../../mod/mood.php:131 +msgid "Mood" +msgstr "Humeur" + +#: ../../include/apps.php:140 ../../include/conversation.php:945 +msgid "Poke" +msgstr "Cogner" + +#: ../../include/apps.php:141 ../../include/nav.php:97 +msgid "Chat" +msgstr "Clavardage" + +#: ../../include/apps.php:142 ../../include/text.php:815 +#: ../../include/text.php:829 ../../include/nav.php:156 +#: ../../mod/search.php:30 +msgid "Search" +msgstr "Recherche" + +#: ../../include/apps.php:143 +msgid "Probe" +msgstr "Sonder" + +#: ../../include/apps.php:144 +msgid "Suggest" +msgstr "Suggérer" + +#: ../../include/apps.php:145 +msgid "Random Channel" +msgstr "Un canal au hasard" + +#: ../../include/apps.php:146 +msgid "Invite" +msgstr "Invitation" + +#: ../../include/apps.php:147 +msgid "Features" +msgstr "Fonctionalités" + +#: ../../include/apps.php:148 +msgid "Language" +msgstr "Langue" + +#: ../../include/apps.php:149 +msgid "Post" +msgstr "Envoyer" + +#: ../../include/apps.php:150 +msgid "Profile Photo" +msgstr "Photo du profil" + +#: ../../include/apps.php:239 ../../mod/settings.php:79 +#: ../../mod/settings.php:543 +msgid "Update" +msgstr "Mise à jour" + +#: ../../include/apps.php:239 +msgid "Install" +msgstr "Installer" + +#: ../../include/apps.php:244 +msgid "Purchase" +msgstr "Acheter" + +#: ../../include/apps.php:246 ../../include/page_widgets.php:8 +#: ../../include/page_widgets.php:36 ../../include/reddav.php:1289 +#: ../../include/menu.php:42 ../../include/ItemObject.php:96 +#: ../../mod/settings.php:579 ../../mod/blocks.php:94 +#: ../../mod/connections.php:393 ../../mod/editblock.php:111 +#: ../../mod/editlayout.php:106 ../../mod/editpost.php:112 +#: ../../mod/editwebpage.php:143 ../../mod/thing.php:235 +#: ../../mod/layouts.php:112 ../../mod/menu.php:59 ../../mod/webpages.php:120 +msgid "Edit" +msgstr "Éditer" + +#: ../../include/apps.php:247 ../../include/reddav.php:1290 +#: ../../include/conversation.php:635 ../../include/ItemObject.php:108 +#: ../../mod/settings.php:580 ../../mod/connedit.php:440 +#: ../../mod/photos.php:1052 ../../mod/group.php:176 ../../mod/admin.php:767 +#: ../../mod/admin.php:897 ../../mod/thing.php:236 +msgid "Delete" +msgstr "Supprimer" + +#: ../../include/apps.php:328 ../../include/apps.php:379 +#: ../../include/reddav.php:1202 ../../mod/connedit.php:476 +msgid "Unknown" +msgstr "Inconnu" + +#: ../../include/text.php:321 +msgid "prev" +msgstr "préc." + +#: ../../include/text.php:323 +msgid "first" +msgstr "premier" + +#: ../../include/text.php:352 +msgid "last" +msgstr "dernier" + +#: ../../include/text.php:355 +msgid "next" +msgstr "suiv." + +#: ../../include/text.php:367 +msgid "older" +msgstr "plus ancien" + +#: ../../include/text.php:369 +msgid "newer" +msgstr "plus récent" + +#: ../../include/text.php:730 +msgid "No connections" +msgstr "Sans relations" + +#: ../../include/text.php:743 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "%d relation" +msgstr[1] "%d relations" + +#: ../../include/text.php:756 +msgid "View Connections" +msgstr "Voir les relations" + +#: ../../include/text.php:817 ../../include/text.php:831 +#: ../../include/widgets.php:186 ../../mod/rbmark.php:28 +#: ../../mod/rbmark.php:98 ../../mod/filer.php:50 +msgid "Save" +msgstr "Sauver" + +#: ../../include/text.php:897 +msgid "poke" +msgstr "cogner" + +#: ../../include/text.php:897 ../../include/conversation.php:243 +msgid "poked" +msgstr "a cogné" + +#: ../../include/text.php:898 +msgid "ping" +msgstr "solliciter" + +#: ../../include/text.php:898 +msgid "pinged" +msgstr "a sollicité" + +#: ../../include/text.php:899 +msgid "prod" +msgstr "encourager" + +#: ../../include/text.php:899 +msgid "prodded" +msgstr "a encouragé" + +#: ../../include/text.php:900 +msgid "slap" +msgstr "gifler" + +#: ../../include/text.php:900 +msgid "slapped" +msgstr "a giflé" + +#: ../../include/text.php:901 +msgid "finger" +msgstr "pointer" + +#: ../../include/text.php:901 +msgid "fingered" +msgstr "a pointé" + +#: ../../include/text.php:902 +msgid "rebuff" +msgstr "rejeter" + +#: ../../include/text.php:902 +msgid "rebuffed" +msgstr "a rejeté" + +#: ../../include/text.php:911 +msgid "happy" +msgstr "heureux" + +#: ../../include/text.php:912 +msgid "sad" +msgstr "triste" + +#: ../../include/text.php:913 +msgid "mellow" +msgstr "mélancolique" + +#: ../../include/text.php:914 +msgid "tired" +msgstr "fatigué" + +#: ../../include/text.php:915 +msgid "perky" +msgstr "impertinent" + +#: ../../include/text.php:916 +msgid "angry" +msgstr "colérique" + +#: ../../include/text.php:917 +msgid "stupified" +msgstr "stupéfié" + +#: ../../include/text.php:918 +msgid "puzzled" +msgstr "perplexe" + +#: ../../include/text.php:919 +msgid "interested" +msgstr "intéressé" + +#: ../../include/text.php:920 +msgid "bitter" +msgstr "amer" + +#: ../../include/text.php:921 +msgid "cheerful" +msgstr "joyeux" + +#: ../../include/text.php:922 +msgid "alive" +msgstr "énergique" + +#: ../../include/text.php:923 +msgid "annoyed" +msgstr "agacé" + +#: ../../include/text.php:924 +msgid "anxious" +msgstr "anxieux" + +#: ../../include/text.php:925 +msgid "cranky" +msgstr "énervé" + +#: ../../include/text.php:926 +msgid "disturbed" +msgstr "perturbé" + +#: ../../include/text.php:927 +msgid "frustrated" +msgstr "frustré" + +#: ../../include/text.php:928 +msgid "depressed" +msgstr "déprimé" + +#: ../../include/text.php:929 +msgid "motivated" +msgstr "motivé" + +#: ../../include/text.php:930 +msgid "relaxed" +msgstr "détendu" + +#: ../../include/text.php:931 +msgid "surprised" +msgstr "surpris" + +#: ../../include/text.php:1092 +msgid "Monday" +msgstr "Lundi" + +#: ../../include/text.php:1092 +msgid "Tuesday" +msgstr "Mardi" + +#: ../../include/text.php:1092 +msgid "Wednesday" +msgstr "Mercredi" + +#: ../../include/text.php:1092 +msgid "Thursday" +msgstr "Jeudi" + +#: ../../include/text.php:1092 +msgid "Friday" +msgstr "Vendredi" + +#: ../../include/text.php:1092 +msgid "Saturday" +msgstr "Samedi" + +#: ../../include/text.php:1092 +msgid "Sunday" +msgstr "Dimanche" + +#: ../../include/text.php:1096 +msgid "January" +msgstr "Janvier" + +#: ../../include/text.php:1096 +msgid "February" +msgstr "Février" + +#: ../../include/text.php:1096 +msgid "March" +msgstr "Mars" + +#: ../../include/text.php:1096 +msgid "April" +msgstr "Avril" + +#: ../../include/text.php:1096 +msgid "May" +msgstr "Mai" + +#: ../../include/text.php:1096 +msgid "June" +msgstr "Juin" + +#: ../../include/text.php:1096 +msgid "July" +msgstr "Juillet" + +#: ../../include/text.php:1096 +msgid "August" +msgstr "Août" + +#: ../../include/text.php:1096 +msgid "September" +msgstr "Septembre" + +#: ../../include/text.php:1096 +msgid "October" +msgstr "Octobre" + +#: ../../include/text.php:1096 +msgid "November" +msgstr "Novembre" + +#: ../../include/text.php:1096 +msgid "December" +msgstr "Décembre" + +#: ../../include/text.php:1174 +msgid "unknown.???" +msgstr "inconnu.???" + +#: ../../include/text.php:1175 +msgid "bytes" +msgstr "octets" + +#: ../../include/text.php:1210 +msgid "remove category" +msgstr "supprimer la catégorie" + +#: ../../include/text.php:1280 +msgid "remove from file" +msgstr "retirer du fichier" + +#: ../../include/text.php:1345 ../../include/text.php:1357 +msgid "Click to open/close" +msgstr "Cliquer pour ouvrir/fermer" + +#: ../../include/text.php:1512 ../../mod/events.php:374 +msgid "Link to Source" +msgstr "Lien vers la source" + +#: ../../include/text.php:1531 +msgid "Select a page layout: " +msgstr "Choisir une mise en page :" + +#: ../../include/text.php:1534 ../../include/text.php:1599 +msgid "default" +msgstr "défaut" + +#: ../../include/text.php:1570 +msgid "Page content type: " +msgstr "Type de contenu :" + +#: ../../include/text.php:1611 +msgid "Select an alternate language" +msgstr "Choisir une langue alternative" + +#: ../../include/text.php:1735 ../../include/conversation.php:123 +#: ../../mod/tagger.php:49 +msgid "event" +msgstr "événement" + +#: ../../include/text.php:1740 ../../include/conversation.php:150 +#: ../../mod/tagger.php:55 +msgid "comment" +msgstr "commentaire" + +#: ../../include/text.php:1745 +msgid "activity" +msgstr "activité" + +#: ../../include/text.php:2004 +msgid "Design" +msgstr "Conception" + +#: ../../include/text.php:2006 +msgid "Blocks" +msgstr "Blocs" + +#: ../../include/text.php:2007 +msgid "Menus" +msgstr "Menus" + +#: ../../include/text.php:2008 +msgid "Layouts" +msgstr "Mises en page" + +#: ../../include/text.php:2009 +msgid "Pages" +msgstr "Pages" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "Nouvelle page" + +#: ../../include/page_widgets.php:39 ../../mod/blocks.php:97 +#: ../../mod/layouts.php:116 ../../mod/webpages.php:123 +msgid "View" +msgstr "Voir" + +#: ../../include/page_widgets.php:40 ../../include/conversation.php:1091 +#: ../../include/ItemObject.php:592 ../../mod/editblock.php:141 +#: ../../mod/editlayout.php:135 ../../mod/editpost.php:140 +#: ../../mod/editwebpage.php:174 ../../mod/photos.php:1003 +#: ../../mod/webpages.php:124 +msgid "Preview" +msgstr "Aperçu" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:125 +msgid "Actions" +msgstr "Actions" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:126 +msgid "Page Link" +msgstr "Lien vers la page" + +#: ../../include/page_widgets.php:43 ../../mod/webpages.php:127 +msgid "Title" +msgstr "Titre" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:128 +msgid "Created" +msgstr "Créé" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:129 +msgid "Edited" +msgstr "Édité" + +#: ../../include/security.php:301 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "Le formulaire n'est plus sécurisé, probablement parce qu'il est ouvert depuis trop longtemps (plus de 3 heures)." + +#: ../../include/account.php:23 +msgid "Not a valid email address" +msgstr "Ce n'est pas une adresse de courriel valide" + +#: ../../include/account.php:25 +msgid "Your email domain is not among those allowed on this site" +msgstr "Votre domaine de courriel ne fait pas partie de ceux autorisés par ce site" + +#: ../../include/account.php:31 +msgid "Your email address is already registered at this site." +msgstr "Votre adresse de courriel est déjà inscrite sur ce site." + +#: ../../include/account.php:64 +msgid "An invitation is required." +msgstr "Une invitation est requise." + +#: ../../include/account.php:68 +msgid "Invitation could not be verified." +msgstr "Votre invitation n'a pas pu être vérifiée." + +#: ../../include/account.php:119 +msgid "Please enter the required information." +msgstr "Merci d'entrer les informations requises." + +#: ../../include/account.php:187 +msgid "Failed to store account information." +msgstr "Impossible de stocker les informations liées au compte." + +#: ../../include/account.php:245 +#, php-format +msgid "Registration confirmation for %s" +msgstr "Confirmation de l'enregistrement pour %s" + +#: ../../include/account.php:313 +#, php-format +msgid "Registration request at %s" +msgstr "Demande d'inscription sur %s" + +#: ../../include/account.php:315 ../../include/account.php:342 +#: ../../include/account.php:399 +msgid "Administrator" +msgstr "Administrateur" + +#: ../../include/account.php:337 +msgid "your registration password" +msgstr "votre mot de passe d'inscription" + +#: ../../include/account.php:340 ../../include/account.php:397 +#, php-format +msgid "Registration details for %s" +msgstr "Détails de l'inscription à %s" + +#: ../../include/account.php:406 +msgid "Account approved." +msgstr "Compte approuvé." + +#: ../../include/account.php:440 +#, php-format +msgid "Registration revoked for %s" +msgstr "Inscription révoquée pour %s" + +#: ../../include/account.php:486 +msgid "Account verified. Please login." +msgstr "Compte vérifié. Veuillez vous connecter." + +#: ../../include/photos.php:15 ../../include/attach.php:119 +#: ../../include/attach.php:166 ../../include/attach.php:229 +#: ../../include/attach.php:243 ../../include/attach.php:283 +#: ../../include/attach.php:297 ../../include/attach.php:322 +#: ../../include/attach.php:513 ../../include/attach.php:585 +#: ../../include/chat.php:116 ../../include/items.php:3711 +#: ../../mod/mood.php:112 ../../mod/mitem.php:73 ../../mod/achievements.php:27 +#: ../../mod/settings.php:494 ../../mod/poke.php:128 ../../mod/api.php:26 +#: ../../mod/api.php:31 ../../mod/authtest.php:13 ../../mod/profile.php:64 +#: ../../mod/profile.php:72 ../../mod/block.php:22 ../../mod/block.php:72 +#: ../../mod/profile_photo.php:263 ../../mod/profile_photo.php:276 +#: ../../mod/blocks.php:29 ../../mod/blocks.php:44 ../../mod/profiles.php:179 +#: ../../mod/profiles.php:524 ../../mod/bookmarks.php:46 +#: ../../mod/channel.php:89 ../../mod/channel.php:193 +#: ../../mod/channel.php:236 ../../mod/chat.php:90 ../../mod/chat.php:95 +#: ../../mod/register.php:71 ../../mod/regmod.php:18 ../../mod/common.php:35 +#: ../../mod/network.php:12 ../../mod/connections.php:169 +#: ../../mod/connedit.php:254 ../../mod/delegate.php:6 ../../mod/page.php:30 +#: ../../mod/page.php:80 ../../mod/setup.php:203 ../../mod/editblock.php:34 +#: ../../mod/pdledit.php:21 ../../mod/editlayout.php:48 +#: ../../mod/editpost.php:13 ../../mod/editwebpage.php:44 +#: ../../mod/editwebpage.php:83 ../../mod/photos.php:68 +#: ../../mod/photos.php:526 ../../mod/sources.php:66 ../../mod/events.php:160 +#: ../../mod/filestorage.php:10 ../../mod/filestorage.php:59 +#: ../../mod/filestorage.php:75 ../../mod/filestorage.php:98 +#: ../../mod/fsuggest.php:78 ../../mod/suggest.php:26 ../../mod/group.php:9 +#: ../../mod/thing.php:249 ../../mod/thing.php:266 ../../mod/thing.php:301 +#: ../../mod/invite.php:13 ../../mod/invite.php:104 ../../mod/item.php:178 +#: ../../mod/item.php:186 ../../mod/item.php:916 ../../mod/layouts.php:27 +#: ../../mod/layouts.php:39 ../../mod/like.php:154 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +#: ../../mod/viewsrc.php:12 ../../mod/mail.php:108 ../../mod/manage.php:6 +#: ../../mod/menu.php:44 ../../mod/webpages.php:40 ../../mod/message.php:16 +#: ../../mod/new_channel.php:66 ../../mod/new_channel.php:97 +#: ../../mod/notifications.php:66 ../../mod/appman.php:66 ../../index.php:186 +#: ../../index.php:361 +msgid "Permission denied." +msgstr "Permission refusée." + +#: ../../include/photos.php:104 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "L'image dépasse la taille limite de %lu octets" + +#: ../../include/photos.php:111 +msgid "Image file is empty." +msgstr "L'image est vide." + +#: ../../include/photos.php:140 ../../mod/profile_photo.php:216 +msgid "Unable to process image" +msgstr "Impossible de traiter l'image" + +#: ../../include/photos.php:212 +msgid "Photo storage failed." +msgstr "Le stockage de l'image a échoué." + +#: ../../include/photos.php:339 ../../include/conversation.php:1515 +msgid "Photo Albums" +msgstr "Albums photo" + +#: ../../include/photos.php:343 ../../mod/photos.php:697 +#: ../../mod/photos.php:1199 +msgid "Upload New Photos" +msgstr "Ajouter des photos" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "Visible pour vos contacts seulement." + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "Voir plus" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "Cacher" + +#: ../../include/acl_selectors.php:248 ../../mod/chat.php:209 +#: ../../mod/photos.php:604 ../../mod/photos.php:958 +#: ../../mod/filestorage.php:128 +msgid "Permissions" +msgstr "Permissions" + +#: ../../include/acl_selectors.php:249 ../../include/ItemObject.php:289 +msgid "Close" +msgstr "Fermer" + +#: ../../include/activities.php:39 +msgid " and " +msgstr " et " + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "profil public" + +#: ../../include/activities.php:52 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s a changé %2$s en “%3$s”" + +#: ../../include/activities.php:53 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "Visiter %1$s sur %2$s" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s a mis à jour %2$s, modifiant %3$s." + +#: ../../include/api.php:1036 +msgid "Public Timeline" +msgstr "Fil public" + +#: ../../include/attach.php:224 ../../include/attach.php:278 +msgid "Item was not found." +msgstr "Élément introuvable." + +#: ../../include/attach.php:335 +msgid "No source file." +msgstr "Pas de fichier source." + +#: ../../include/attach.php:352 +msgid "Cannot locate file to replace" +msgstr "Impossible de trouver le fichier à remplacer." + +#: ../../include/attach.php:370 +msgid "Cannot locate file to revise/update" +msgstr "Impossible de trouver le fichier à corriger/mettre à jour" + +#: ../../include/attach.php:381 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Le fichier dépasse la taille limite de %d" + +#: ../../include/attach.php:393 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "Vous avez atteint votre limite de %1$.0f méga-octets autorisés pour le stockage des pièces-jointes" + +#: ../../include/attach.php:475 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "Envoi du fichier impossible. Limite système ou action avortée." + +#: ../../include/attach.php:487 +msgid "Stored file could not be verified. Upload failed." +msgstr "Le fichier stocké n'a pu être vérifié. Envoi impossible." + +#: ../../include/attach.php:528 ../../include/attach.php:545 +msgid "Path not available." +msgstr "Chemin non disponible." + +#: ../../include/attach.php:590 +msgid "Empty pathname" +msgstr "Chemin vide" + +#: ../../include/attach.php:606 +msgid "duplicate filename or path" +msgstr "doublon de chemin ou de fichier" + +#: ../../include/attach.php:630 +msgid "Path not found." +msgstr "Chemin introuvable." + +#: ../../include/attach.php:681 +msgid "mkdir failed." +msgstr "mkdir a échoué." + +#: ../../include/attach.php:685 +msgid "database storage failed." +msgstr "l'écriture dans la BD a échoué" + +#: ../../include/plugin.php:504 ../../include/plugin.php:506 +msgid "Click here to upgrade." +msgstr "Cliquez ici pour mettre à jour." + +#: ../../include/plugin.php:512 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Cette action outrepasserait les limites prévues par votre forfait." + +#: ../../include/plugin.php:517 +msgid "This action is not available under your subscription plan." +msgstr "Cette action n'est pas possible avec la formule choisie." + +#: ../../include/bb2diaspora.php:463 ../../include/event.php:11 +msgid "l F d, Y \\@ g:i A" +msgstr "l d F Y \\à G\\hi" + +#: ../../include/bb2diaspora.php:469 ../../include/event.php:20 +msgid "Starts:" +msgstr "Début :" + +#: ../../include/bb2diaspora.php:477 ../../include/event.php:30 +msgid "Finishes:" +msgstr "Fin :" + +#: ../../include/bb2diaspora.php:485 ../../include/event.php:40 +#: ../../include/identity.php:757 ../../mod/directory.php:156 +#: ../../mod/dirprofile.php:105 ../../mod/events.php:504 +msgid "Location:" +msgstr "Emplacement :" + +#: ../../include/nav.php:81 ../../include/nav.php:108 ../../boot.php:1497 +msgid "Logout" +msgstr "Déconnexion" + +#: ../../include/nav.php:81 ../../include/nav.php:108 +msgid "End this session" +msgstr "Mettre fin à la session" + +#: ../../include/nav.php:84 ../../include/nav.php:142 +msgid "Home" +msgstr "Canal" + +#: ../../include/nav.php:84 +msgid "Your posts and conversations" +msgstr "Vos publications et conversations" + +#: ../../include/nav.php:85 ../../include/conversation.php:940 +#: ../../mod/connedit.php:393 ../../mod/connedit.php:507 +msgid "View Profile" +msgstr "Voir profil" + +#: ../../include/nav.php:85 +msgid "Your profile page" +msgstr "Votre profil" + +#: ../../include/nav.php:87 +msgid "Edit Profiles" +msgstr "Éditer les profils" + +#: ../../include/nav.php:87 +msgid "Manage/Edit profiles" +msgstr "Gérer/éditer les profils" + +#: ../../include/nav.php:89 ../../include/identity.php:730 +msgid "Edit Profile" +msgstr "Éditer le profil" + +#: ../../include/nav.php:89 +msgid "Edit your profile" +msgstr "Éditer votre profil" + +#: ../../include/nav.php:91 +msgid "Your photos" +msgstr "Vos photos" + +#: ../../include/nav.php:92 +msgid "Your files" +msgstr "Vos fichiers" + +#: ../../include/nav.php:97 +msgid "Your chatrooms" +msgstr "Vos salons" + +#: ../../include/nav.php:100 +msgid "Your bookmarks" +msgstr "Vos favoris" + +#: ../../include/nav.php:102 +msgid "Your webpages" +msgstr "Vos pages web" + +#: ../../include/nav.php:106 +msgid "Sign in" +msgstr "Connexion" + +#: ../../include/nav.php:123 +#, php-format +msgid "%s - click to logout" +msgstr "%s - cliquer ici pour déconnecter" + +#: ../../include/nav.php:128 +msgid "Click to authenticate to your home hub" +msgstr "S'authentifier auprès de votre hub" + +#: ../../include/nav.php:142 +msgid "Home Page" +msgstr "Page d'accueil" + +#: ../../include/nav.php:146 ../../mod/register.php:221 ../../boot.php:1474 +msgid "Register" +msgstr "S'inscrire" + +#: ../../include/nav.php:146 +msgid "Create an account" +msgstr "Créer un compte" + +#: ../../include/nav.php:151 +msgid "Help and documentation" +msgstr "Aide et documentation" + +#: ../../include/nav.php:154 ../../include/widgets.php:79 +#: ../../mod/apps.php:33 +msgid "Apps" +msgstr "Applications" + +#: ../../include/nav.php:154 +msgid "Applications, utilities, links, games" +msgstr "Applications, utilitaires, liens, jeux" + +#: ../../include/nav.php:156 +msgid "Search site content" +msgstr "Rechercher parmi le contenu du site" + +#: ../../include/nav.php:159 +msgid "Channel Locator" +msgstr "Localisation de canaux" + +#: ../../include/nav.php:170 +msgid "Your matrix" +msgstr "Votre matrice" + +#: ../../include/nav.php:171 +msgid "Mark all matrix notifications seen" +msgstr "Marquer toutes les notifications de la matrice comme vues" + +#: ../../include/nav.php:173 +msgid "Channel home" +msgstr "Mon canal" + +#: ../../include/nav.php:174 +msgid "Mark all channel notifications seen" +msgstr "Marquer toutes les notifications du canal comme vues" + +#: ../../include/nav.php:177 ../../mod/connections.php:386 +msgid "Connections" +msgstr "Relations" + +#: ../../include/nav.php:180 +msgid "Notices" +msgstr "Notifications" + +#: ../../include/nav.php:180 +msgid "Notifications" +msgstr "Notifications" + +#: ../../include/nav.php:181 +msgid "See all notifications" +msgstr "Voir toutes les notifications" + +#: ../../include/nav.php:182 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "Marquer toutes les notifications système comme vues" + +#: ../../include/nav.php:184 +msgid "Private mail" +msgstr "Messages privés" + +#: ../../include/nav.php:185 +msgid "See all private messages" +msgstr "Voir tous les messages privés" + +#: ../../include/nav.php:186 +msgid "Mark all private messages seen" +msgstr "Marquer tous les messages privés comme vus" + +#: ../../include/nav.php:187 +msgid "Inbox" +msgstr "Boîte de réception" + +#: ../../include/nav.php:188 +msgid "Outbox" +msgstr "Boîte d'envoi" + +#: ../../include/nav.php:189 ../../include/widgets.php:536 +msgid "New Message" +msgstr "Nouveau message" + +#: ../../include/nav.php:192 +msgid "Event Calendar" +msgstr "Calendrier des événements" + +#: ../../include/nav.php:193 +msgid "See all events" +msgstr "Voir tous les événements" + +#: ../../include/nav.php:194 +msgid "Mark all events seen" +msgstr "Marquer tous les événements comme vus" + +#: ../../include/nav.php:196 +msgid "Manage Your Channels" +msgstr "Gérer vos canaux" + +#: ../../include/nav.php:198 +msgid "Account/Channel Settings" +msgstr "Réglages du Compte/Canal" + +#: ../../include/nav.php:206 ../../mod/admin.php:123 +msgid "Admin" +msgstr "Administrateur" + +#: ../../include/nav.php:206 +msgid "Site Setup and Configuration" +msgstr "Configuration du site" + +#: ../../include/nav.php:231 +msgid "Nothing new here" +msgstr "Aucun nouveau contenu trouvé" + +#: ../../include/nav.php:235 +msgid "Please wait..." +msgstr "Merci de patienter..." + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "Favoris de %1$s" + +#: ../../include/taxonomy.php:210 +msgid "Tags" +msgstr "Étiquettes" + +#: ../../include/taxonomy.php:227 +msgid "Keywords" +msgstr "Mots-clefs" + +#: ../../include/taxonomy.php:252 +msgid "have" +msgstr "ont" + +#: ../../include/taxonomy.php:252 +msgid "has" +msgstr "a" + +#: ../../include/taxonomy.php:253 +msgid "want" +msgstr "veulent" + +#: ../../include/taxonomy.php:253 +msgid "wants" +msgstr "veut" + +#: ../../include/taxonomy.php:254 ../../include/ItemObject.php:208 +msgid "like" +msgstr "aime" + +#: ../../include/taxonomy.php:254 +msgid "likes" +msgstr "aiment" + +#: ../../include/taxonomy.php:255 ../../include/ItemObject.php:209 +msgid "dislike" +msgstr "déteste" + +#: ../../include/taxonomy.php:255 +msgid "dislikes" +msgstr "détestent" + +#: ../../include/taxonomy.php:338 ../../include/identity.php:999 +#: ../../include/ItemObject.php:134 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "J'aime" +msgstr[1] "J'aime" + +#: ../../include/comanche.php:35 ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "Défaut" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Constamment" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Chaque heure" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Deux fois par jour" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Chaque jour" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Chaque semaine" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Chaque mois" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:763 +#: ../../mod/admin.php:772 ../../boot.php:1500 +msgid "Email" +msgstr "Courriel" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "Linkedin" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/IM" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "%d invitation disponible" +msgstr[1] "%d invitations disponibles" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:455 +msgid "Advanced" +msgstr "Avancé" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "Trouver des canaux" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "Saisir nom ou centre d'intérêt" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "Ajouter/Suivre" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Exemples: Robert Morgenstein, Course à pieds" + +#: ../../include/contact_widgets.php:26 ../../mod/connections.php:392 +#: ../../mod/directory.php:222 ../../mod/directory.php:227 +msgid "Find" +msgstr "Trouver" + +#: ../../include/contact_widgets.php:27 ../../mod/suggest.php:59 +msgid "Channel Suggestions" +msgstr "Canaux suggérés" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "Un profil au hasard" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "Inviter des amis" + +#: ../../include/contact_widgets.php:32 +msgid "Exammple: name=fred and country=iceland" +msgstr "Exemple: name=fred and country=iceland" + +#: ../../include/contact_widgets.php:33 +msgid "Advanced Find" +msgstr "Recherche avancée" + +#: ../../include/contact_widgets.php:58 ../../include/features.php:69 +#: ../../include/widgets.php:296 +msgid "Saved Folders" +msgstr "Dossiers sauvegardés" + +#: ../../include/contact_widgets.php:61 ../../include/contact_widgets.php:96 +#: ../../include/widgets.php:299 +msgid "Everything" +msgstr "Tout" + +#: ../../include/contact_widgets.php:93 ../../include/widgets.php:29 +msgid "Categories" +msgstr "Catégories" + +#: ../../include/contact_widgets.php:126 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "%d relation en commun" +msgstr[1] "%d relations en commun" + +#: ../../include/contact_widgets.php:131 +msgid "show more" +msgstr "montrer plus" + +#: ../../include/event.php:326 +msgid "This event has been added to your calendar." +msgstr "Cet événement a été ajouté à votre calendrier." + +#: ../../include/zot.php:624 +msgid "Invalid data packet" +msgstr "Paquet de données invalide" + +#: ../../include/zot.php:638 +msgid "Unable to verify channel signature" +msgstr "Impossible de vérifier la signature du canal" + +#: ../../include/zot.php:835 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "Impossible de vérifier la signature de site pour %s" + +#: ../../include/datetime.php:43 ../../include/datetime.php:45 +msgid "Miscellaneous" +msgstr "Divers" + +#: ../../include/datetime.php:152 ../../include/datetime.php:284 +msgid "year" +msgstr "année" + +#: ../../include/datetime.php:157 ../../include/datetime.php:285 +msgid "month" +msgstr "mois" + +#: ../../include/datetime.php:162 ../../include/datetime.php:287 +msgid "day" +msgstr "jour" + +#: ../../include/datetime.php:275 +msgid "never" +msgstr "jamais" + +#: ../../include/datetime.php:281 +msgid "less than a second ago" +msgstr "à l'instant" + +#: ../../include/datetime.php:284 +msgid "years" +msgstr "années" + +#: ../../include/datetime.php:285 +msgid "months" +msgstr "mois" + +#: ../../include/datetime.php:286 +msgid "week" +msgstr "semaine" + +#: ../../include/datetime.php:286 +msgid "weeks" +msgstr "semaines" + +#: ../../include/datetime.php:287 +msgid "days" +msgstr "jours" + +#: ../../include/datetime.php:288 +msgid "hour" +msgstr "heure" + +#: ../../include/datetime.php:288 +msgid "hours" +msgstr "heures" + +#: ../../include/datetime.php:289 +msgid "minute" +msgstr "minute" + +#: ../../include/datetime.php:289 +msgid "minutes" +msgstr "minutes" + +#: ../../include/datetime.php:290 +msgid "second" +msgstr "seconde" + +#: ../../include/datetime.php:290 +msgid "seconds" +msgstr "secondes" + +#: ../../include/datetime.php:299 +#, php-format +msgid "%1$d %2$s ago" +msgstr "il y a %1$d %2$s" + +#: ../../include/datetime.php:504 +#, php-format +msgid "%1$s's birthday" +msgstr "Anniversaire de %1$s" + +#: ../../include/datetime.php:505 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "Joyeux Anniversaire %1$s" + +#: ../../include/dir_fns.php:36 +msgid "Sort Options" +msgstr "Options de tri" + +#: ../../include/dir_fns.php:37 +msgid "Alphabetic" +msgstr "Alphabétique" + +#: ../../include/dir_fns.php:38 +msgid "Reverse Alphabetic" +msgstr "Alphabétique inversé" + +#: ../../include/dir_fns.php:39 +msgid "Newest to Oldest" +msgstr "Anté-chronologique" + +#: ../../include/dir_fns.php:51 +msgid "Enable Safe Search" +msgstr "Activer la recherche sûre" + +#: ../../include/dir_fns.php:53 +msgid "Disable Safe Search" +msgstr "Désactiver la recherche sûre" + +#: ../../include/dir_fns.php:55 +msgid "Safe Mode" +msgstr "Mode sûr" + +#: ../../include/enotify.php:41 +msgid "Hubzilla Notification" +msgstr "Notification Matrice Rouge" + +#: ../../include/enotify.php:42 +msgid "hubzilla" +msgstr "Matrice Rouge" + +#: ../../include/enotify.php:44 +msgid "Thank You," +msgstr "Merci," + +#: ../../include/enotify.php:46 +#, php-format +msgid "%s Administrator" +msgstr "l'administrateur de %s" + +#: ../../include/enotify.php:81 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:85 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "[Red:Notification] Nouveau message reçu sur %s" + +#: ../../include/enotify.php:87 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "%1$s, vous avez reçu un message privé sur %3$s, de la part de %2$s." + +#: ../../include/enotify.php:88 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s vous a envoyé %2$s." + +#: ../../include/enotify.php:88 +msgid "a private message" +msgstr "un message privé" + +#: ../../include/enotify.php:89 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Merci de visiter %s pour voir et/ou répondre à vos messages privés." + +#: ../../include/enotify.php:144 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "%1$s, %2$s a commenté sur [zrl=%3$s]%4$s[/zrl]" + +#: ../../include/enotify.php:152 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "%1$s, %2$s a commenté sur [zrl=%3$s]%5$s de %4$s[/zrl]" + +#: ../../include/enotify.php:161 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "%1$s, %2$s a commenté [zrl=%3$s]votre %4$s[/zrl]" + +#: ../../include/enotify.php:172 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Red:Notification] Commentaire de %2$s sur conversation #%1$d" + +#: ../../include/enotify.php:173 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "%1$s, %2$s a commenté un élément de conversation que vous suivez." + +#: ../../include/enotify.php:176 ../../include/enotify.php:191 +#: ../../include/enotify.php:217 ../../include/enotify.php:236 +#: ../../include/enotify.php:250 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Merci de visiter %s pour voir et/ou répondre sur cette conversation." + +#: ../../include/enotify.php:182 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "[Red:Notification] %s a publié sur votre profil" + +#: ../../include/enotify.php:184 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "%1$s, %2$s a publié sur votre profil à %3$s" + +#: ../../include/enotify.php:186 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "%1$s, %2$s a publié sur [zrl=%3$s]votre profil[/zrl]" + +#: ../../include/enotify.php:210 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "[Red:Notification] %s vous a étiqueté" + +#: ../../include/enotify.php:211 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "%1$s, vous avez été étiqueté sur %3$s par %2$s" + +#: ../../include/enotify.php:212 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "%1$s, %2$s [zrl=%3$s]vous a étiqueté[/zrl]." + +#: ../../include/enotify.php:225 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "[Red:Notification] %1$s vous a cogné" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "%1$s, %2$s vous a cogné sur %3$s + +#: ../../include/enotify.php:227 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "%1$s, %2$s [zrl=%2$s]vous a cogné[/zrl]." + +#: ../../include/enotify.php:243 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "[Red:Notification] %s a étiqueté votre publication" + +#: ../../include/enotify.php:244 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "%1$s, %2$s a étiqueté votre publication sur %3$s" + +#: ../../include/enotify.php:245 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "%1$s, %2$s a étiqueté [zrl=%3$s]votre publication[/zrl]" + +#: ../../include/enotify.php:257 +msgid "[Red:Notify] Introduction received" +msgstr "[Red:Notification] Nouvelle introduction" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "%1$s, vous avez reçu une demande de mise en relation de '%2$s' sur %3$s" + +#: ../../include/enotify.php:259 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "%1$s, vous avez reçu [zrl=%2$s]une demande de mise en relation[/zrl] de %3$s." + +#: ../../include/enotify.php:263 ../../include/enotify.php:282 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Vous pouvez visiter leur profil sur %s" + +#: ../../include/enotify.php:265 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "Merci de visiter %s avant d'approuver (ou non) cette demande de relation." + +#: ../../include/enotify.php:272 +msgid "[Red:Notify] Friend suggestion received" +msgstr "[Red:Notification] Nouvelle suggestion d'amitié" + +#: ../../include/enotify.php:273 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "%1$s, vous avez reçu une suggestion de relation de '%2$s' à %3$s" + +#: ../../include/enotify.php:274 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from " +"%4$s." +msgstr "%1$s, avez reçu %3$s comme [zrl=%2$s]une suggestion de relation[/zrl] de %4$s." + +#: ../../include/enotify.php:280 +msgid "Name:" +msgstr "Nom :" + +#: ../../include/enotify.php:281 +msgid "Photo:" +msgstr "Photo :" + +#: ../../include/enotify.php:284 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Merci de visiter %s pour donner suite (ou non) à cette suggestion." + +#: ../../include/enotify.php:474 +msgid "[Red:Notify]" +msgstr "[Red:Notification]" + +#: ../../include/reddav.php:1145 ../../include/reddav.php:1288 +msgid "parent" +msgstr "retour" + +#: ../../include/reddav.php:1169 +msgid "Collection" +msgstr "Collection" + +#: ../../include/reddav.php:1172 +msgid "Principal" +msgstr "Principal" + +#: ../../include/reddav.php:1175 +msgid "Addressbook" +msgstr "Carnet d'adresse" + +#: ../../include/reddav.php:1178 +msgid "Calendar" +msgstr "Calendrier" + +#: ../../include/reddav.php:1181 +msgid "Schedule Inbox" +msgstr "Calendrier - Message entrants" + +#: ../../include/reddav.php:1184 +msgid "Schedule Outbox" +msgstr "Calendrier - Message sortants" + +#: ../../include/reddav.php:1262 +#, php-format +msgid "%1$s used" +msgstr "%1$s utilisé" + +#: ../../include/reddav.php:1267 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "%1$s utilisé de %2$s (%3$s%)" + +#: ../../include/reddav.php:1284 ../../mod/settings.php:519 +#: ../../mod/settings.php:545 ../../mod/admin.php:902 +msgid "Name" +msgstr "Nom" + +#: ../../include/reddav.php:1285 +msgid "Type" +msgstr "Type" + +#: ../../include/reddav.php:1286 +msgid "Size" +msgstr "Taille" + +#: ../../include/reddav.php:1287 +msgid "Last Modified" +msgstr "Modifié le" + +#: ../../include/reddav.php:1291 +msgid "Total" +msgstr "Total" + +#: ../../include/reddav.php:1344 +msgid "Create new folder" +msgstr "Nouveau dossier" + +#: ../../include/reddav.php:1345 ../../mod/mitem.php:142 ../../mod/menu.php:84 +#: ../../mod/new_channel.php:117 +msgid "Create" +msgstr "Créer" + +#: ../../include/reddav.php:1346 +msgid "Upload file" +msgstr "Téléverser un fichier" + +#: ../../include/reddav.php:1347 ../../mod/profile_photo.php:361 +msgid "Upload" +msgstr "Envoyer" + +#: ../../include/conversation.php:126 ../../mod/like.php:89 +msgid "channel" +msgstr "canal" + +#: ../../include/conversation.php:167 ../../mod/like.php:333 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "%1$s déteste %3$s de %2$s" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "%1$s ajoute %2$s à ses relations" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "%1$s a cogné %2$s" + +#: ../../include/conversation.php:261 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "%1$s est %2$s" + +#: ../../include/conversation.php:634 ../../include/ItemObject.php:114 +msgid "Select" +msgstr "Sélectionner" + +#: ../../include/conversation.php:642 ../../include/ItemObject.php:89 +#: ../../mod/photos.php:850 +msgid "Private Message" +msgstr "Message Privé" + +#: ../../include/conversation.php:649 ../../include/ItemObject.php:182 +msgid "Message is verified" +msgstr "Message vérifié" + +#: ../../include/conversation.php:669 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Voir le profil de %s @ %s" + +#: ../../include/conversation.php:683 +msgid "Categories:" +msgstr "Catégories :" + +#: ../../include/conversation.php:684 +msgid "Filed under:" +msgstr "Classé sous :" + +#: ../../include/conversation.php:693 ../../include/ItemObject.php:250 +#, php-format +msgid " from %s" +msgstr "de %s" + +#: ../../include/conversation.php:696 ../../include/ItemObject.php:253 +#, php-format +msgid "last edited: %s" +msgstr "dernière édition : %s" + +#: ../../include/conversation.php:697 ../../include/ItemObject.php:254 +#, php-format +msgid "Expires: %s" +msgstr "Expire : %s" + +#: ../../include/conversation.php:712 +msgid "View in context" +msgstr "Voir en contexte" + +#: ../../include/conversation.php:714 ../../include/conversation.php:1130 +#: ../../include/ItemObject.php:294 ../../mod/editblock.php:120 +#: ../../mod/editlayout.php:115 ../../mod/editpost.php:121 +#: ../../mod/editwebpage.php:152 ../../mod/photos.php:983 +#: ../../mod/mail.php:231 ../../mod/mail.php:346 +msgid "Please wait" +msgstr "Merci de patienter" + +#: ../../include/conversation.php:841 +msgid "remove" +msgstr "supprimer" + +#: ../../include/conversation.php:845 +msgid "Loading..." +msgstr "Chargement..." + +#: ../../include/conversation.php:846 +msgid "Delete Selected Items" +msgstr "Supprimer les éléments selectionnés" + +#: ../../include/conversation.php:937 +msgid "View Source" +msgstr "Voir source" + +#: ../../include/conversation.php:938 +msgid "Follow Thread" +msgstr "Suivre discussion" + +#: ../../include/conversation.php:939 +msgid "View Status" +msgstr "Voir état" + +#: ../../include/conversation.php:941 +msgid "View Photos" +msgstr "Voir photos" + +#: ../../include/conversation.php:942 +msgid "Matrix Activity" +msgstr "Activité sur la matrice" + +#: ../../include/conversation.php:943 +msgid "Edit Contact" +msgstr "Éditer contact" + +#: ../../include/conversation.php:944 +msgid "Send PM" +msgstr "Envoyer un Message Privé" + +#: ../../include/conversation.php:1001 +#, php-format +msgid "%s likes this." +msgstr "%s aime ça." + +#: ../../include/conversation.php:1001 +#, php-format +msgid "%s doesn't like this." +msgstr "%s déteste ça." + +#: ../../include/conversation.php:1005 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "" +msgstr[1] "%2$d personne(s) aime(nt) ça." + +#: ../../include/conversation.php:1007 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "" +msgstr[1] "%2$d personne(s) déteste(nt) ça." + +#: ../../include/conversation.php:1013 +msgid "and" +msgstr "et" + +#: ../../include/conversation.php:1016 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] "" +msgstr[1] ", et %d autre(s) personne(s)" + +#: ../../include/conversation.php:1017 +#, php-format +msgid "%s like this." +msgstr "%s aime ça." + +#: ../../include/conversation.php:1017 +#, php-format +msgid "%s don't like this." +msgstr "%s déteste ça." + +#: ../../include/conversation.php:1074 +msgid "Visible to everybody" +msgstr "Visible par tout le monde" + +#: ../../include/conversation.php:1075 ../../mod/mail.php:167 +#: ../../mod/mail.php:279 +msgid "Please enter a link URL:" +msgstr "Merci d'entrer l'URL d'un lien :" + +#: ../../include/conversation.php:1076 +msgid "Please enter a video link/URL:" +msgstr "Merci d'entrer l'URL d'une video :" + +#: ../../include/conversation.php:1077 +msgid "Please enter an audio link/URL:" +msgstr "Merci d'entrer l'URL d'un contenu audio :" + +#: ../../include/conversation.php:1078 +msgid "Tag term:" +msgstr "Étiquette :" + +#: ../../include/conversation.php:1079 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "Classer dans le dossier :" + +#: ../../include/conversation.php:1080 +msgid "Where are you right now?" +msgstr "Où êtes-vous présentement?" + +#: ../../include/conversation.php:1081 ../../mod/editpost.php:52 +#: ../../mod/mail.php:168 ../../mod/mail.php:280 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "Expire YYYY-MM-DD HH:MM" + +#: ../../include/conversation.php:1105 ../../mod/photos.php:982 +#: ../../mod/layouts.php:113 +msgid "Share" +msgstr "Partager" + +#: ../../include/conversation.php:1107 ../../mod/editwebpage.php:139 +msgid "Page link title" +msgstr "Titre du lien vers la page" + +#: ../../include/conversation.php:1110 +msgid "Post as" +msgstr "Publier en tant que" + +#: ../../include/conversation.php:1111 ../../mod/editblock.php:112 +#: ../../mod/editlayout.php:107 ../../mod/editpost.php:113 +#: ../../mod/editwebpage.php:144 ../../mod/mail.php:228 ../../mod/mail.php:342 +msgid "Upload photo" +msgstr "Téléverser une photo" + +#: ../../include/conversation.php:1112 +msgid "upload photo" +msgstr "téléverser une photo" + +#: ../../include/conversation.php:1113 ../../mod/editblock.php:113 +#: ../../mod/editlayout.php:108 ../../mod/editpost.php:114 +#: ../../mod/editwebpage.php:145 ../../mod/mail.php:229 ../../mod/mail.php:343 +msgid "Attach file" +msgstr "Attacher un fichier" + +#: ../../include/conversation.php:1114 +msgid "attach file" +msgstr "attacher un fichier" + +#: ../../include/conversation.php:1115 ../../mod/editblock.php:114 +#: ../../mod/editlayout.php:109 ../../mod/editpost.php:115 +#: ../../mod/editwebpage.php:146 ../../mod/mail.php:230 ../../mod/mail.php:344 +msgid "Insert web link" +msgstr "Insérer lien web" + +#: ../../include/conversation.php:1116 +msgid "web link" +msgstr "lien web" + +#: ../../include/conversation.php:1117 +msgid "Insert video link" +msgstr "Insérer lien vidéo" + +#: ../../include/conversation.php:1118 +msgid "video link" +msgstr "lien vidéo" + +#: ../../include/conversation.php:1119 +msgid "Insert audio link" +msgstr "Insérer un lien audio" + +#: ../../include/conversation.php:1120 +msgid "audio link" +msgstr "lien audio" + +#: ../../include/conversation.php:1121 ../../mod/editblock.php:118 +#: ../../mod/editlayout.php:113 ../../mod/editpost.php:119 +#: ../../mod/editwebpage.php:150 +msgid "Set your location" +msgstr "Spécifier votre emplacement géographique" + +#: ../../include/conversation.php:1122 +msgid "set location" +msgstr "spécifier l'emplacement géographique" + +#: ../../include/conversation.php:1123 ../../mod/editblock.php:119 +#: ../../mod/editlayout.php:114 ../../mod/editpost.php:120 +#: ../../mod/editwebpage.php:151 +msgid "Clear browser location" +msgstr "Nettoyer l'emplacement géographique du navigateur" + +#: ../../include/conversation.php:1124 +msgid "clear location" +msgstr "nettoyer l'emplacement géographique" + +#: ../../include/conversation.php:1126 ../../mod/editblock.php:132 +#: ../../mod/editlayout.php:126 ../../mod/editpost.php:132 +#: ../../mod/editwebpage.php:167 +msgid "Set title" +msgstr "Spécifier le titre" + +#: ../../include/conversation.php:1129 ../../mod/editblock.php:135 +#: ../../mod/editlayout.php:129 ../../mod/editpost.php:134 +#: ../../mod/editwebpage.php:169 +msgid "Categories (comma-separated list)" +msgstr "Catégories (séparées par des virgules)" + +#: ../../include/conversation.php:1131 ../../mod/editblock.php:121 +#: ../../mod/editlayout.php:116 ../../mod/editpost.php:122 +#: ../../mod/editwebpage.php:153 +msgid "Permission settings" +msgstr "Permissions" + +#: ../../include/conversation.php:1132 +msgid "permissions" +msgstr "permissions" + +#: ../../include/conversation.php:1139 ../../mod/editblock.php:129 +#: ../../mod/editlayout.php:123 ../../mod/editpost.php:129 +#: ../../mod/editwebpage.php:162 +msgid "Public post" +msgstr "Contenu public" + +#: ../../include/conversation.php:1141 ../../mod/editblock.php:136 +#: ../../mod/editlayout.php:130 ../../mod/editpost.php:135 +#: ../../mod/editwebpage.php:170 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Exemple: robert@exemple.com, marie@exemple.com" + +#: ../../include/conversation.php:1154 ../../mod/editblock.php:146 +#: ../../mod/editlayout.php:140 ../../mod/editpost.php:146 +#: ../../mod/editwebpage.php:179 ../../mod/mail.php:235 ../../mod/mail.php:349 +msgid "Set expiration date" +msgstr "Définir la date d'expiration" + +#: ../../include/conversation.php:1156 ../../include/ItemObject.php:595 +#: ../../mod/editpost.php:148 ../../mod/mail.php:237 ../../mod/mail.php:351 +msgid "Encrypt text" +msgstr "Chiffrer le texte" + +#: ../../include/conversation.php:1158 ../../mod/editpost.php:150 +msgid "OK" +msgstr "Ok" + +#: ../../include/conversation.php:1159 ../../mod/settings.php:518 +#: ../../mod/settings.php:544 ../../mod/editpost.php:151 +#: ../../mod/fbrowser.php:82 ../../mod/fbrowser.php:117 ../../mod/tagrm.php:11 +#: ../../mod/tagrm.php:94 +msgid "Cancel" +msgstr "Annuler" + +#: ../../include/conversation.php:1401 +msgid "Discover" +msgstr "À découvrir" + +#: ../../include/conversation.php:1404 +msgid "Imported public streams" +msgstr "Flux publics importés" + +#: ../../include/conversation.php:1409 +msgid "Commented Order" +msgstr "Commentaires Récents" + +#: ../../include/conversation.php:1412 +msgid "Sort by Comment Date" +msgstr "Trier par date de dernier commentaire" + +#: ../../include/conversation.php:1416 +msgid "Posted Order" +msgstr "Publications Récentes" + +#: ../../include/conversation.php:1419 +msgid "Sort by Post Date" +msgstr "Trier par date de publication" + +#: ../../include/conversation.php:1424 ../../include/widgets.php:82 +msgid "Personal" +msgstr "Personnel" + +#: ../../include/conversation.php:1427 +msgid "Posts that mention or involve you" +msgstr "Publications qui vous mentionnent ou vous concernent d'une manière ou d'une autre" + +#: ../../include/conversation.php:1433 ../../mod/connections.php:211 +#: ../../mod/connections.php:224 ../../mod/menu.php:61 +msgid "New" +msgstr "Nouveautés" + +#: ../../include/conversation.php:1436 +msgid "Activity Stream - by date" +msgstr "Flux d'activité - par date" + +#: ../../include/conversation.php:1442 +msgid "Starred" +msgstr "Mis en avant" + +#: ../../include/conversation.php:1445 +msgid "Favourite Posts" +msgstr "Publications préférées" + +#: ../../include/conversation.php:1452 +msgid "Spam" +msgstr "Indésirable" + +#: ../../include/conversation.php:1455 +msgid "Posts flagged as SPAM" +msgstr "Publications marquées comme indésirables" + +#: ../../include/conversation.php:1491 ../../mod/admin.php:901 +msgid "Channel" +msgstr "Canal" + +#: ../../include/conversation.php:1494 +msgid "Status Messages and Posts" +msgstr "Messages d'état et contributions" + +#: ../../include/conversation.php:1503 +msgid "About" +msgstr "À propos" + +#: ../../include/conversation.php:1506 +msgid "Profile Details" +msgstr "Détails du profil" + +#: ../../include/conversation.php:1524 +msgid "Files and Storage" +msgstr "Fichiers et Stockage" + +#: ../../include/conversation.php:1533 ../../include/conversation.php:1536 +msgid "Chatrooms" +msgstr "Salons de clavardage" + +#: ../../include/conversation.php:1546 +msgid "Saved Bookmarks" +msgstr "Favoris sauvegardés" + +#: ../../include/conversation.php:1557 +msgid "Manage Webpages" +msgstr "Gérer les pages web" + +#: ../../include/features.php:23 +msgid "General Features" +msgstr "Fonctionnalités générales" + +#: ../../include/features.php:25 +msgid "Content Expiration" +msgstr "Expiration de contenu" + +#: ../../include/features.php:25 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "Supprimer les contributions/commentaires et/ou messages privés plus tard" + +#: ../../include/features.php:26 +msgid "Multiple Profiles" +msgstr "Profils multiples" + +#: ../../include/features.php:26 +msgid "Ability to create multiple profiles" +msgstr "Possibilité de créer plusieurs profils" + +#: ../../include/features.php:27 +msgid "Advanced Profiles" +msgstr "Profils Avancés" + +#: ../../include/features.php:27 +msgid "Additional profile sections and selections" +msgstr "Sections additionnelles du profil" + +#: ../../include/features.php:28 +msgid "Profile Import/Export" +msgstr "Importer/Exporter le profil" + +#: ../../include/features.php:28 +msgid "Save and load profile details across sites/channels" +msgstr "Distribuer les détails du profil sur la matrice." + +#: ../../include/features.php:29 +msgid "Web Pages" +msgstr "Pages web" + +#: ../../include/features.php:29 +msgid "Provide managed web pages on your channel" +msgstr "Fournir des pages web, sous votre contrôle, sur votre canal" + +#: ../../include/features.php:30 +msgid "Private Notes" +msgstr "Notes privées" + +#: ../../include/features.php:30 +msgid "Enables a tool to store notes and reminders" +msgstr "Active un outil pour stocker notes et mémos" + +#: ../../include/features.php:35 +msgid "Extended Identity Sharing" +msgstr "Partage d'identité étendue" + +#: ../../include/features.php:35 +msgid "" +"Share your identity with all websites on the internet. When disabled, " +"identity is only shared with sites in the matrix." +msgstr "Partage votre identité avec tous les sites web du Monde. Si décoché, l'identité sera seulement partagée avec les sites de la matrice." + +#: ../../include/features.php:36 +msgid "Expert Mode" +msgstr "Mode expert" + +#: ../../include/features.php:36 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "Activer le mode expert pour accéder aux options avancées" + +#: ../../include/features.php:37 +msgid "Premium Channel" +msgstr "Canal VIP" + +#: ../../include/features.php:37 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "Vous permet d'appliquer des règles et restrictions aux relations de votre canal" + +#: ../../include/features.php:42 +msgid "Post Composition Features" +msgstr "Fonctionnalités de composition" + +#: ../../include/features.php:44 +msgid "Use Markdown" +msgstr "Utiliser Markdown" + +#: ../../include/features.php:44 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "Authoriser l'usage de \"Markdown\" pour le format des partages" + +#: ../../include/features.php:45 +msgid "Post Preview" +msgstr "Aperçu avant publication" + +#: ../../include/features.php:45 +msgid "Allow previewing posts and comments before publishing them" +msgstr "Permettre de prévisualiser les publications/commentaires" + +#: ../../include/features.php:46 ../../include/widgets.php:503 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "Canaux sources" + +#: ../../include/features.php:46 +msgid "Automatically import channel content from other channels or feeds" +msgstr "Importe automatiquement le contenus d'autres canaux ou flux dans le canal en cours" + +#: ../../include/features.php:47 +msgid "Even More Encryption" +msgstr "Encore plus de chiffrement" + +#: ../../include/features.php:47 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "Permettre le chiffrement - optionnel - du contenu de bout-en-bout au moyen d'un secret partagé" + +#: ../../include/features.php:52 +msgid "Network and Stream Filtering" +msgstr "Filtrage du réseau et des flux" + +#: ../../include/features.php:53 +msgid "Search by Date" +msgstr "Chercher par date" + +#: ../../include/features.php:53 +msgid "Ability to select posts by date ranges" +msgstr "Pouvoir choisir des publications par date" + +#: ../../include/features.php:54 +msgid "Collections Filter" +msgstr "Filtre des collections" + +#: ../../include/features.php:54 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "Activer une boîte qui permet de filtrer les publications du réseau parmi les collections selectionnées" + +#: ../../include/features.php:55 ../../include/widgets.php:265 +msgid "Saved Searches" +msgstr "Recherches sauvées" + +#: ../../include/features.php:55 +msgid "Save search terms for re-use" +msgstr "Sauver des termes de recherche pour utilisation ultérieure" + +#: ../../include/features.php:56 +msgid "Network Personal Tab" +msgstr "Onglet \"réseau personnel\"" + +#: ../../include/features.php:56 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "Activer un onglet affichant seulement les publications du réseau sur lesquelles vous êtes intervenu" + +#: ../../include/features.php:57 +msgid "Network New Tab" +msgstr "Onglet \"nouveautés réseau\"" + +#: ../../include/features.php:57 +msgid "Enable tab to display all new Network activity" +msgstr "Activer un onglet avec toute activité récente sur le réseau" + +#: ../../include/features.php:58 +msgid "Affinity Tool" +msgstr "Gérer l'affinité" + +#: ../../include/features.php:58 +msgid "Filter stream activity by depth of relationships" +msgstr "Filtrer le flux d'activité en fonction de la profondeur des relations" + +#: ../../include/features.php:59 +msgid "Suggest Channels" +msgstr "Suggérer des canaux" + +#: ../../include/features.php:59 +msgid "Show channel suggestions" +msgstr "Montrer les suggestions de canaux" + +#: ../../include/features.php:64 +msgid "Post/Comment Tools" +msgstr "Gérer les publications/commentaires" + +#: ../../include/features.php:66 +msgid "Edit Sent Posts" +msgstr "Éditer les publications envoyées" + +#: ../../include/features.php:66 +msgid "Edit and correct posts and comments after sending" +msgstr "Permettre d'éditer/corriger les publications/commentaires après envoi" + +#: ../../include/features.php:67 +msgid "Tagging" +msgstr "Étiquettes" + +#: ../../include/features.php:67 +msgid "Ability to tag existing posts" +msgstr "Permettre de marquer les publications existantes" + +#: ../../include/features.php:68 +msgid "Post Categories" +msgstr "Catégoriser les publications" + +#: ../../include/features.php:68 +msgid "Add categories to your posts" +msgstr "Ajouter des catégories à vos publications" + +#: ../../include/features.php:69 +msgid "Ability to file posts under folders" +msgstr "Permettre de classer les publications dans des dossiers" + +#: ../../include/features.php:70 +msgid "Dislike Posts" +msgstr "Détester les publications" + +#: ../../include/features.php:70 +msgid "Ability to dislike posts/comments" +msgstr "Pouvoir détester les publications/commentaires" + +#: ../../include/features.php:71 +msgid "Star Posts" +msgstr "Mettre en avant les publications" + +#: ../../include/features.php:71 +msgid "Ability to mark special posts with a star indicator" +msgstr "Pouvoir marquer certaines publications d'une étoile" + +#: ../../include/features.php:72 +msgid "Tag Cloud" +msgstr "Nuage de tags" + +#: ../../include/features.php:72 +msgid "Provide a personal tag cloud on your channel page" +msgstr "Afficher un nuage de vos tags sur votre canal" + +#: ../../include/follow.php:23 +msgid "Channel is blocked on this site." +msgstr "Ce canal est bloqué sur ce site." + +#: ../../include/follow.php:28 +msgid "Channel location missing." +msgstr "Emplacement du canal introuvable." + +#: ../../include/follow.php:54 +msgid "Response from remote channel was incomplete." +msgstr "La réponse du canal distant était incomplète." + +#: ../../include/follow.php:85 +msgid "Channel was deleted and no longer exists." +msgstr "Le canal a été supprimé et n'existe plus." + +#: ../../include/follow.php:132 +msgid "Channel discovery failed." +msgstr "La tentative d'accéder au canal a échouée." + +#: ../../include/follow.php:149 +msgid "local account not found." +msgstr "compte local introuvable." + +#: ../../include/follow.php:158 +msgid "Cannot connect to yourself." +msgstr "Ne peut pas se connecter à vous." + +#: ../../include/chat.php:10 +msgid "Missing room name" +msgstr "Il manque le nom du salon" + +#: ../../include/chat.php:19 +msgid "Duplicate room name" +msgstr "Un salon de ce nom existe déjà" + +#: ../../include/chat.php:68 ../../include/chat.php:76 +msgid "Invalid room specifier." +msgstr "Identifiant de salon invalide." + +#: ../../include/chat.php:105 +msgid "Room not found." +msgstr "Salon introuvable." + +#: ../../include/chat.php:126 +msgid "Room is full" +msgstr "Le salon est plein" + +#: ../../include/items.php:295 ../../mod/profperm.php:23 +#: ../../mod/subthread.php:49 ../../mod/group.php:68 ../../mod/like.php:242 +#: ../../mod/frphotos.php:69 ../../index.php:360 +msgid "Permission denied" +msgstr "Accès refusé" + +#: ../../include/items.php:830 +msgid "(Unknown)" +msgstr "(Inconnu)" + +#: ../../include/items.php:959 +msgid "Visible to anybody on the internet." +msgstr "Visible à tout le monde sur internet." + +#: ../../include/items.php:961 +msgid "Visible to you only." +msgstr "Visible pour vous seulement." + +#: ../../include/items.php:963 +msgid "Visible to anybody in this network." +msgstr "Visible sur toute la Matrice." + +#: ../../include/items.php:965 +msgid "Visible to anybody authenticated." +msgstr "Visible aux utilisateurs authentifiés." + +#: ../../include/items.php:967 +#, php-format +msgid "Visible to anybody on %s." +msgstr "Visible pour tous sur %s." + +#: ../../include/items.php:969 +msgid "Visible to all connections." +msgstr "Visible pour tous les contacts." + +#: ../../include/items.php:971 +msgid "Visible to approved connections." +msgstr "Visible aux contacts approuvés." + +#: ../../include/items.php:3649 ../../mod/home.php:67 ../../mod/display.php:32 +#: ../../mod/filestorage.php:18 ../../mod/admin.php:168 +#: ../../mod/admin.php:932 ../../mod/admin.php:1135 ../../mod/thing.php:78 +#: ../../mod/viewsrc.php:18 +msgid "Item not found." +msgstr "Élément introuvable." + +#: ../../include/items.php:4082 ../../mod/group.php:38 ../../mod/group.php:140 +msgid "Collection not found." +msgstr "Collection introuvable." + +#: ../../include/items.php:4097 +msgid "Collection is empty." +msgstr "Collection vide." + +#: ../../include/items.php:4104 +#, php-format +msgid "Collection: %s" +msgstr "Collection : %s" + +#: ../../include/items.php:4115 +#, php-format +msgid "Connection: %s" +msgstr "Relation : %s" + +#: ../../include/items.php:4118 +msgid "Connection not found." +msgstr "Relation introuvable." + +#: ../../include/group.php:25 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "Un groupe supprimé portant ce nom a été ressuscité. Les permissions liées aux éléments existants peuvent s'appliquer au groupe et aux membres futurs. Si ce n'est pas ce que vous attendiez, merci de recréer un nouveau groupe avec un nom différent." + +#: ../../include/group.php:234 +msgid "Default privacy group for new contacts" +msgstr "Groupe de confidentialité par défaut pour les nouveaux contacts" + +#: ../../include/group.php:253 ../../mod/admin.php:772 +msgid "All Channels" +msgstr "Tous canaux" + +#: ../../include/group.php:275 +msgid "edit" +msgstr "éditer" + +#: ../../include/group.php:296 +msgid "Collections" +msgstr "Collections" + +#: ../../include/group.php:297 +msgid "Edit collection" +msgstr "Éditer collection" + +#: ../../include/group.php:298 +msgid "Create a new collection" +msgstr "Créer une nouvelle collection" + +#: ../../include/group.php:299 +msgid "Channels not in any collection" +msgstr "Ces canaux ne sont dans aucune collection" + +#: ../../include/group.php:301 ../../include/widgets.php:266 +msgid "add" +msgstr "ajouter" + +#: ../../include/identity.php:30 ../../mod/item.php:1297 +msgid "Unable to obtain identity information from database" +msgstr "Impossible d'obtenir les données d'identité depuis la base de données" + +#: ../../include/identity.php:63 +msgid "Empty name" +msgstr "Nom vide" + +#: ../../include/identity.php:65 +msgid "Name too long" +msgstr "Nom trop long" + +#: ../../include/identity.php:166 +msgid "No account identifier" +msgstr "Pas d'identifiant de compte" + +#: ../../include/identity.php:176 +msgid "Nickname is required." +msgstr "Un surnom est requis." + +#: ../../include/identity.php:190 +msgid "Reserved nickname. Please choose another." +msgstr "Pseudonyme réservé. Merci d'en choisir un autre." + +#: ../../include/identity.php:195 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "Le surnom contient des caractères interdits, ou est déjà pris sur ce site." + +#: ../../include/identity.php:258 +msgid "Unable to retrieve created identity" +msgstr "Impossible de récupérer l'identité créée" + +#: ../../include/identity.php:317 +msgid "Default Profile" +msgstr "Profil par défaut" + +#: ../../include/identity.php:342 ../../include/widgets.php:400 +#: ../../include/profile_selectors.php:80 ../../mod/connedit.php:473 +msgid "Friends" +msgstr "Amis" + +#: ../../include/identity.php:509 +msgid "Requested channel is not available." +msgstr "Canal demandé non-disponible." + +#: ../../include/identity.php:557 ../../mod/achievements.php:8 +#: ../../mod/profile.php:16 ../../mod/blocks.php:10 ../../mod/connect.php:13 +#: ../../mod/filestorage.php:40 ../../mod/layouts.php:8 +#: ../../mod/webpages.php:8 ../../mod/hcard.php:8 +msgid "Requested profile is not available." +msgstr "Profil demandé inaccessible." + +#: ../../include/identity.php:706 ../../include/widgets.php:128 +#: ../../include/widgets.php:168 ../../include/Contact.php:107 +#: ../../mod/directory.php:183 ../../mod/dirprofile.php:164 +#: ../../mod/suggest.php:51 ../../mod/match.php:62 +msgid "Connect" +msgstr "Ajouter" + +#: ../../include/identity.php:720 ../../mod/profiles.php:695 +msgid "Change profile photo" +msgstr "Changer la photo du profil" + +#: ../../include/identity.php:726 +msgid "Profiles" +msgstr "Profils" + +#: ../../include/identity.php:726 +msgid "Manage/edit profiles" +msgstr "Gérer/éditer les profils" + +#: ../../include/identity.php:727 ../../mod/profiles.php:696 +msgid "Create New Profile" +msgstr "Créer un nouveau profil" + +#: ../../include/identity.php:741 ../../mod/profiles.php:707 +msgid "Profile Image" +msgstr "Image du profil" + +#: ../../include/identity.php:744 +msgid "visible to everybody" +msgstr "visible pour tous" + +#: ../../include/identity.php:745 ../../mod/profiles.php:591 +#: ../../mod/profiles.php:711 +msgid "Edit visibility" +msgstr "Éditer la visibilité" + +#: ../../include/identity.php:759 ../../include/identity.php:983 +#: ../../mod/directory.php:158 +msgid "Gender:" +msgstr "Sexe :" + +#: ../../include/identity.php:760 ../../include/identity.php:1027 +#: ../../mod/directory.php:160 +msgid "Status:" +msgstr "État :" + +#: ../../include/identity.php:761 ../../include/identity.php:1038 +#: ../../mod/directory.php:162 +msgid "Homepage:" +msgstr "Site web :" + +#: ../../include/identity.php:762 ../../mod/dirprofile.php:151 +msgid "Online Now" +msgstr "Connecté" + +#: ../../include/identity.php:827 ../../include/identity.php:907 +#: ../../mod/ping.php:298 +msgid "g A l F d" +msgstr "H:i l d F" + +#: ../../include/identity.php:828 ../../include/identity.php:908 +msgid "F d" +msgstr "d F" + +#: ../../include/identity.php:873 ../../include/identity.php:948 +#: ../../mod/ping.php:320 +msgid "[today]" +msgstr "[aujourd'hui]" + +#: ../../include/identity.php:885 +msgid "Birthday Reminders" +msgstr "Rappels d'anniversaires" + +#: ../../include/identity.php:886 +msgid "Birthdays this week:" +msgstr "Anniversaires cette semaine :" + +#: ../../include/identity.php:941 +msgid "[No description]" +msgstr "[Pas de description]" + +#: ../../include/identity.php:959 +msgid "Event Reminders" +msgstr "Rappels d'événements" + +#: ../../include/identity.php:960 +msgid "Events this week:" +msgstr "Événements cette semaine :" + +#: ../../include/identity.php:981 ../../mod/settings.php:942 +msgid "Full Name:" +msgstr "Nom complet :" + +#: ../../include/identity.php:988 +msgid "Like this channel" +msgstr "J'aime ce canal" + +#: ../../include/identity.php:1012 +msgid "j F, Y" +msgstr "j F Y" + +#: ../../include/identity.php:1013 +msgid "j F" +msgstr "j F" + +#: ../../include/identity.php:1020 +msgid "Birthday:" +msgstr "Date de naissance :" + +#: ../../include/identity.php:1024 +msgid "Age:" +msgstr "Age :" + +#: ../../include/identity.php:1033 +#, php-format +msgid "for %1$d %2$s" +msgstr "depuis %1$d %2$s" + +#: ../../include/identity.php:1036 ../../mod/profiles.php:613 +msgid "Sexual Preference:" +msgstr "Orientation sexuelle :" + +#: ../../include/identity.php:1040 ../../mod/profiles.php:615 +msgid "Hometown:" +msgstr "Ville natale :" + +#: ../../include/identity.php:1042 +msgid "Tags:" +msgstr "Étiquettes :" + +#: ../../include/identity.php:1044 ../../mod/profiles.php:616 +msgid "Political Views:" +msgstr "Opinions politiques :" + +#: ../../include/identity.php:1046 +msgid "Religion:" +msgstr "Religion :" + +#: ../../include/identity.php:1048 ../../mod/directory.php:164 +msgid "About:" +msgstr "À propos :" + +#: ../../include/identity.php:1050 +msgid "Hobbies/Interests:" +msgstr "Occupations/Centres d'intérêt :" + +#: ../../include/identity.php:1052 ../../mod/profiles.php:619 +msgid "Likes:" +msgstr "Aime :" + +#: ../../include/identity.php:1054 ../../mod/profiles.php:620 +msgid "Dislikes:" +msgstr "N'aime pas :" + +#: ../../include/identity.php:1057 +msgid "Contact information and Social Networks:" +msgstr "Coordonnées et réseaux sociaux :" + +#: ../../include/identity.php:1059 +msgid "My other channels:" +msgstr "Mes autres canaux :" + +#: ../../include/identity.php:1061 +msgid "Musical interests:" +msgstr "Goûts musicaux :" + +#: ../../include/identity.php:1063 +msgid "Books, literature:" +msgstr "Lectures, goûts littéraires :" + +#: ../../include/identity.php:1065 +msgid "Television:" +msgstr "Télévision :" + +#: ../../include/identity.php:1067 +msgid "Film/dance/culture/entertainment:" +msgstr "Cinéma/danse/culture/divertissement :" + +#: ../../include/identity.php:1069 +msgid "Love/Romance:" +msgstr "Vie sentimentale/amoureuse :" + +#: ../../include/identity.php:1071 +msgid "Work/employment:" +msgstr "Travail :" + +#: ../../include/identity.php:1073 +msgid "School/education:" +msgstr "Cursus :" + +#: ../../include/identity.php:1093 +msgid "Like this thing" +msgstr "J'aime ceci" + +#: ../../include/network.php:652 +msgid "view full size" +msgstr "pleine taille" + +#: ../../include/bbcode.php:112 ../../include/bbcode.php:645 +#: ../../include/bbcode.php:648 ../../include/bbcode.php:653 +#: ../../include/bbcode.php:656 ../../include/bbcode.php:659 +#: ../../include/bbcode.php:662 ../../include/bbcode.php:667 +#: ../../include/bbcode.php:670 ../../include/bbcode.php:675 +#: ../../include/bbcode.php:678 ../../include/bbcode.php:681 +#: ../../include/bbcode.php:684 +msgid "Image/photo" +msgstr "Image/photo" + +#: ../../include/bbcode.php:147 ../../include/bbcode.php:695 +msgid "Encrypted content" +msgstr "Contenu chiffré" + +#: ../../include/bbcode.php:163 +msgid "QR code" +msgstr "code QR" + +#: ../../include/bbcode.php:212 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "%1$s a écrit %2$s qui suit %3$s" + +#: ../../include/bbcode.php:214 +msgid "post" +msgstr "l'article" + +#: ../../include/bbcode.php:613 ../../include/bbcode.php:633 +msgid "$1 wrote:" +msgstr "$1 a écrit :" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "Pas de destinataire." + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "[sans objet]" + +#: ../../include/message.php:42 +msgid "Unable to determine sender." +msgstr "Impossible de déterminer l'émetteur." + +#: ../../include/message.php:143 +msgid "Stored post could not be verified." +msgstr "Le message stocké n'a pas pu être vérifié." + +#: ../../include/widgets.php:80 +msgid "System" +msgstr "Système" + +#: ../../include/widgets.php:83 +msgid "Create Personal App" +msgstr "Créer Votre Application" + +#: ../../include/widgets.php:84 +msgid "Edit Personal App" +msgstr "Éditer Votre Application" + +#: ../../include/widgets.php:130 ../../mod/suggest.php:53 +msgid "Ignore/Hide" +msgstr "Ignorer/Cacher" + +#: ../../include/widgets.php:136 ../../mod/connections.php:267 +msgid "Suggestions" +msgstr "Suggestion" + +#: ../../include/widgets.php:137 +msgid "See more..." +msgstr "Voir plus..." + +#: ../../include/widgets.php:159 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "Vous avez %1$.0f des %2$.0f relations autorisées." + +#: ../../include/widgets.php:165 +msgid "Add New Connection" +msgstr "Ajouter une nouvelle relation" + +#: ../../include/widgets.php:166 +msgid "Enter the channel address" +msgstr "Adresse du canal" + +#: ../../include/widgets.php:167 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Exemple : bob@exemple.com, http://exemple.com/barbara" + +#: ../../include/widgets.php:184 +msgid "Notes" +msgstr "Notes" + +#: ../../include/widgets.php:256 +msgid "Remove term" +msgstr "Retirer le terme" + +#: ../../include/widgets.php:335 +msgid "Archives" +msgstr "Archives" + +#: ../../include/widgets.php:397 +msgid "Refresh" +msgstr "Actualiser" + +#: ../../include/widgets.php:398 ../../mod/connedit.php:470 +msgid "Me" +msgstr "Moi" + +#: ../../include/widgets.php:399 ../../mod/connedit.php:472 +msgid "Best Friends" +msgstr "Mes meilleurs amis" + +#: ../../include/widgets.php:401 +msgid "Co-workers" +msgstr "Mes collègues" + +#: ../../include/widgets.php:402 ../../mod/connedit.php:474 +msgid "Former Friends" +msgstr "Mes anciens amis" + +#: ../../include/widgets.php:403 ../../mod/connedit.php:475 +msgid "Acquaintances" +msgstr "Mes connaissances" + +#: ../../include/widgets.php:404 +msgid "Everybody" +msgstr "Tout le monde" + +#: ../../include/widgets.php:436 +msgid "Account settings" +msgstr "Réglages du Compte" + +#: ../../include/widgets.php:442 +msgid "Channel settings" +msgstr "Réglages du Canal" + +#: ../../include/widgets.php:448 +msgid "Additional features" +msgstr "Fonctions supplémentaires" + +#: ../../include/widgets.php:454 +msgid "Feature settings" +msgstr "Extensions" + +#: ../../include/widgets.php:460 +msgid "Display settings" +msgstr "Réglages d'affichage" + +#: ../../include/widgets.php:466 +msgid "Connected apps" +msgstr "Applications connectées" + +#: ../../include/widgets.php:472 +msgid "Export channel" +msgstr "Exporter le canal" + +#: ../../include/widgets.php:484 +msgid "Automatic Permissions (Advanced)" +msgstr "Permissions automatiques (avancé)" + +#: ../../include/widgets.php:494 +msgid "Premium Channel Settings" +msgstr "Canal VIP" + +#: ../../include/widgets.php:531 +msgid "Check Mail" +msgstr "Vérifier le courrier" + +#: ../../include/widgets.php:612 +msgid "Chat Rooms" +msgstr "Salons de clavardage" + +#: ../../include/widgets.php:630 +msgid "Bookmarked Chatrooms" +msgstr "Salons favoris" + +#: ../../include/widgets.php:648 +msgid "Suggested Chatrooms" +msgstr "Salons suggérés" + +#: ../../include/ItemObject.php:118 +msgid "Save to Folder" +msgstr "Sauvegarder dans le dossier" + +#: ../../include/ItemObject.php:130 ../../include/ItemObject.php:142 +msgid "View all" +msgstr "Voir tout" + +#: ../../include/ItemObject.php:139 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "Je déteste" +msgstr[1] "Je déteste" + +#: ../../include/ItemObject.php:167 +msgid "Add Star" +msgstr "Ajouter Étoile" + +#: ../../include/ItemObject.php:168 +msgid "Remove Star" +msgstr "Supprimer Étoile" + +#: ../../include/ItemObject.php:169 +msgid "Toggle Star Status" +msgstr "Changer le Statut des Étoiles" + +#: ../../include/ItemObject.php:173 +msgid "starred" +msgstr "mis en avant" + +#: ../../include/ItemObject.php:190 +msgid "Add Tag" +msgstr "Ajouter une balise" + +#: ../../include/ItemObject.php:208 ../../mod/photos.php:980 +msgid "I like this (toggle)" +msgstr "J'aime (oui/non)" + +#: ../../include/ItemObject.php:209 ../../mod/photos.php:981 +msgid "I don't like this (toggle)" +msgstr "Je déteste (oui/non)" + +#: ../../include/ItemObject.php:211 +msgid "Share This" +msgstr "Partager" + +#: ../../include/ItemObject.php:211 +msgid "share" +msgstr "partager" + +#: ../../include/ItemObject.php:235 ../../include/ItemObject.php:236 +#, php-format +msgid "View %s's profile - %s" +msgstr "Voir le profil de %s - %s" + +#: ../../include/ItemObject.php:237 +msgid "to" +msgstr "à" + +#: ../../include/ItemObject.php:238 +msgid "via" +msgstr "via" + +#: ../../include/ItemObject.php:239 +msgid "Wall-to-Wall" +msgstr "Mur-mur" + +#: ../../include/ItemObject.php:240 +msgid "via Wall-To-Wall:" +msgstr "par Mur-mur :" + +#: ../../include/ItemObject.php:274 +msgid "Save Bookmarks" +msgstr "Enregistrer les favoris" + +#: ../../include/ItemObject.php:275 +msgid "Add to Calendar" +msgstr "Ajouter au Calendrier" + +#: ../../include/ItemObject.php:283 +msgctxt "noun" +msgid "Likes" +msgstr "Aimes" + +#: ../../include/ItemObject.php:284 +msgctxt "noun" +msgid "Dislikes" +msgstr "Détestes" + +#: ../../include/ItemObject.php:315 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d commentaire" +msgstr[1] "%d commentaires" + +#: ../../include/ItemObject.php:316 ../../include/js_strings.php:7 +msgid "[+] show all" +msgstr "[+] voir plus" + +#: ../../include/ItemObject.php:580 ../../mod/photos.php:999 +#: ../../mod/photos.php:1086 +msgid "This is you" +msgstr "C'est vous" + +#: ../../include/ItemObject.php:582 ../../include/js_strings.php:6 +#: ../../mod/photos.php:1001 ../../mod/photos.php:1088 +msgid "Comment" +msgstr "Commenter" + +#: ../../include/ItemObject.php:583 ../../mod/mood.php:135 +#: ../../mod/settings.php:517 ../../mod/settings.php:629 +#: ../../mod/settings.php:657 ../../mod/settings.php:681 +#: ../../mod/settings.php:754 ../../mod/settings.php:934 +#: ../../mod/poke.php:166 ../../mod/profiles.php:589 ../../mod/chat.php:177 +#: ../../mod/chat.php:211 ../../mod/connect.php:92 ../../mod/connedit.php:518 +#: ../../mod/setup.php:307 ../../mod/setup.php:350 ../../mod/pdledit.php:58 +#: ../../mod/photos.php:563 ../../mod/photos.php:674 ../../mod/photos.php:962 +#: ../../mod/photos.php:1002 ../../mod/photos.php:1089 +#: ../../mod/sources.php:104 ../../mod/sources.php:138 +#: ../../mod/events.php:511 ../../mod/filestorage.php:137 +#: ../../mod/fsuggest.php:108 ../../mod/group.php:81 ../../mod/admin.php:451 +#: ../../mod/admin.php:760 ../../mod/admin.php:895 ../../mod/admin.php:1028 +#: ../../mod/admin.php:1227 ../../mod/admin.php:1314 ../../mod/thing.php:286 +#: ../../mod/thing.php:329 ../../mod/import.php:393 ../../mod/invite.php:142 +#: ../../mod/mail.php:345 ../../mod/appman.php:99 ../../mod/poll.php:68 +#: ../../mod/frphotos.php:84 ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/blogga/php/config.php:67 +#: ../../view/theme/blogga/view/theme/blog/config.php:67 +#: ../../view/theme/redbasic/php/config.php:99 +msgid "Submit" +msgstr "Envoyer" + +#: ../../include/ItemObject.php:584 +msgid "Bold" +msgstr "Gras" + +#: ../../include/ItemObject.php:585 +msgid "Italic" +msgstr "Italique" + +#: ../../include/ItemObject.php:586 +msgid "Underline" +msgstr "Souligné" + +#: ../../include/ItemObject.php:587 +msgid "Quote" +msgstr "Citation" + +#: ../../include/ItemObject.php:588 +msgid "Code" +msgstr "Code" + +#: ../../include/ItemObject.php:589 +msgid "Image" +msgstr "Image" + +#: ../../include/ItemObject.php:590 +msgid "Link" +msgstr "Lien/URL" + +#: ../../include/ItemObject.php:591 +msgid "Video" +msgstr "Vidéo" + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "Supprimer cet élément?" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "[-] montrer moins" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "[+] déplier" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "[-] replier" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "Mot de passe trop court" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "Les mots de passe ne correspondent pas" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:39 +msgid "everybody" +msgstr "tout le monde" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "Phrase de passe secrète" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "Indice pour la phrase de passe" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "Note : Les permissions ont changé, mais n'ont pas encore été soumises." + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "fermer tout" + +#: ../../include/js_strings.php:19 +msgid "timeago.prefixAgo" +msgstr "Il y a" + +#: ../../include/js_strings.php:20 +msgid "timeago.prefixFromNow" +msgstr "timeago.prefixFromNow" + +#: ../../include/js_strings.php:21 +msgid "ago" +msgstr " " + +#: ../../include/js_strings.php:22 +msgid "from now" +msgstr "de maintenant" + +#: ../../include/js_strings.php:23 +msgid "less than a minute" +msgstr "moins d'une minute" + +#: ../../include/js_strings.php:24 +msgid "about a minute" +msgstr "environ une minute" + +#: ../../include/js_strings.php:25 +#, php-format +msgid "%d minutes" +msgstr "%d minutes" + +#: ../../include/js_strings.php:26 +msgid "about an hour" +msgstr "environ une heure" + +#: ../../include/js_strings.php:27 +#, php-format +msgid "about %d hours" +msgstr "environ %d heures" + +#: ../../include/js_strings.php:28 +msgid "a day" +msgstr "un jour" + +#: ../../include/js_strings.php:29 +#, php-format +msgid "%d days" +msgstr "%d jours" + +#: ../../include/js_strings.php:30 +msgid "about a month" +msgstr "environ un mois" + +#: ../../include/js_strings.php:31 +#, php-format +msgid "%d months" +msgstr "%d mois" + +#: ../../include/js_strings.php:32 +msgid "about a year" +msgstr "environ un an" + +#: ../../include/js_strings.php:33 +#, php-format +msgid "%d years" +msgstr "%d années" + +#: ../../include/js_strings.php:34 +msgid " " +msgstr " " + +#: ../../include/js_strings.php:35 +msgid "timeago.numbers" +msgstr "timeago.numbers" + +#: ../../include/Contact.php:123 +msgid "New window" +msgstr "Nouvelle fenêtre" + +#: ../../include/Contact.php:124 +msgid "Open the selected location in a different window or browser tab" +msgstr "Ouvrir l'emplacement dans une fenêtre (ou un onglet) différent" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +msgid "Male" +msgstr "Masculin" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +msgid "Female" +msgstr "Féminin" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Actuellement masculin" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Actuellement féminin" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Surtout masculin" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Surtout féminin" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transgenre" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Intersexuel" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transsexuel" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Hermaphrodite" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Neutre" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "Rien de spécifique" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 +msgid "Other" +msgstr "Autre" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Indécis" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "Hommes" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "Femmes" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "Gay" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "Lesbienne" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "Sans préférence" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "Bisexuel" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "Autosexuel" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "Abstinent" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "Vierge" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "Déviant" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "Fétichiste" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "Une floppée" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "Nonsexuel" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "Célibataire" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "Solitaire" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "Disponible" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "Indisponible" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "A un béguin" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "Amoureux transi" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "Sort avec quelqu'un" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "Infidèle" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "Accro au sexe" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "Amis avec bénéfices" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "Sans engagement" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "Fiancé(e)" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "Marié(e)" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "Marié(e) dans ses rêves" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "Partenaires" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "En cohabitation" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "Conjoints de fait" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "Heureux" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "Pas en recherche" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "Infidèle" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "Trahi(e)" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "Séparé(e)" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "Instable" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "Divorcé(e)" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "Divorcé(e) dans ses rêves" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "Veuf/veuve" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "Incertain" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "C'est compliqué" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "S'en fiche" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "Me demander" + +#: ../../include/auth.php:90 +msgid "Logged out." +msgstr "Deconnecté." + +#: ../../include/auth.php:236 +msgid "Failed authentication" +msgstr "Échec de l'authentification" + +#: ../../include/auth.php:251 ../../mod/openid.php:188 +msgid "Login failed." +msgstr "Échec de la connexion." + +#: ../../include/permissions.php:13 +msgid "Can view my normal stream and posts" +msgstr "Peut voir les publications sur mon canal et ses partages." + +#: ../../include/permissions.php:14 +msgid "Can view my default channel profile" +msgstr "Peut voir le profil du canal par défaut." + +#: ../../include/permissions.php:15 +msgid "Can view my photo albums" +msgstr "Peut voir mon album photos" + +#: ../../include/permissions.php:16 +msgid "Can view my connections" +msgstr "Peut voir mes connections" + +#: ../../include/permissions.php:17 +msgid "Can view my file storage" +msgstr "Peut voir mes fichiers en partage" + +#: ../../include/permissions.php:18 +msgid "Can view my webpages" +msgstr "Peut voir mes sites-web" + +#: ../../include/permissions.php:21 +msgid "Can send me their channel stream and posts" +msgstr "Peut m'envoyer le flux et les publications de leur canal" + +#: ../../include/permissions.php:22 +msgid "Can post on my channel page (\"wall\")" +msgstr "Peut poster sur la page de mon canal (\"mur\")" + +#: ../../include/permissions.php:23 +msgid "Can comment on or like my posts" +msgstr "Peuvent commenter et/ou aimer mes publications" + +#: ../../include/permissions.php:24 +msgid "Can send me private mail messages" +msgstr "Peut m'envoyer des messages privés" + +#: ../../include/permissions.php:25 +msgid "Can post photos to my photo albums" +msgstr "Peut ajouter des photos à mes albums" + +#: ../../include/permissions.php:26 +msgid "Can like/dislike stuff" +msgstr "Peuvent aimer/détester" + +#: ../../include/permissions.php:26 +msgid "Profiles and things other than posts/comments" +msgstr "Profils et autres excluant les publications/commentaires." + +#: ../../include/permissions.php:28 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "Peut faire suivre à tous les contacts du mon canal via @truc" + +#: ../../include/permissions.php:28 +msgid "Advanced - useful for creating group forum channels" +msgstr "Avancé - utile seulement pour les canaux de type \"forum/groupe\"" + +#: ../../include/permissions.php:29 +msgid "Can chat with me (when available)" +msgstr "Peut discuter avec moi (sous réserve de disponibilité)" + +#: ../../include/permissions.php:30 +msgid "Can write to my file storage" +msgstr "Peut écrire dans mon partage de fichiers" + +#: ../../include/permissions.php:31 +msgid "Can edit my webpages" +msgstr "Peut modifier mes sites-web" + +#: ../../include/permissions.php:33 +msgid "Can source my public posts in derived channels" +msgstr "Peut rediriger mes publications publiques dans des canaux dérivés" + +#: ../../include/permissions.php:33 +msgid "Somewhat advanced - very useful in open communities" +msgstr "Plutôt avancé - très utile dans les communautés ouvertes" + +#: ../../include/permissions.php:35 +msgid "Can administer my channel resources" +msgstr "Peut administrer les ressources de mon canal" + +#: ../../include/permissions.php:35 +msgid "" +"Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "Très avancé. Ne pas toucher, sauf si vous savez VRAIMENT ce que vous faites" + +#: ../../mod/mood.php:132 +msgid "Set your current mood and tell your friends" +msgstr "Indiquez votre humeur du moment à vos amis" + +#: ../../mod/mitem.php:14 ../../mod/menu.php:92 +msgid "Menu not found." +msgstr "Menu introuvable." + +#: ../../mod/mitem.php:47 +msgid "Menu element updated." +msgstr "Entrée de menu mis à jour." + +#: ../../mod/mitem.php:51 +msgid "Unable to update menu element." +msgstr "Impossible de mettre l'entrée de menu à jour." + +#: ../../mod/mitem.php:57 +msgid "Menu element added." +msgstr "Entrée de menu ajouté." + +#: ../../mod/mitem.php:61 +msgid "Unable to add menu element." +msgstr "Impossible d'ajouter l'entrée de menu." + +#: ../../mod/mitem.php:78 ../../mod/dirprofile.php:175 ../../mod/menu.php:120 +#: ../../mod/xchan.php:27 +msgid "Not found." +msgstr "Introuvable." + +#: ../../mod/mitem.php:96 +msgid "Manage Menu Elements" +msgstr "Gérer les entrées de menu" + +#: ../../mod/mitem.php:99 +msgid "Edit menu" +msgstr "Éditer le menu" + +#: ../../mod/mitem.php:102 +msgid "Edit element" +msgstr "Éditer l'entrée" + +#: ../../mod/mitem.php:103 +msgid "Drop element" +msgstr "Supprimer l'entrée" + +#: ../../mod/mitem.php:104 +msgid "New element" +msgstr "Nouvelle entrée" + +#: ../../mod/mitem.php:105 +msgid "Edit this menu container" +msgstr "Éditer ce bloc de menu" + +#: ../../mod/mitem.php:106 +msgid "Add menu element" +msgstr "Ajouter une entrée au menu" + +#: ../../mod/mitem.php:107 +msgid "Delete this menu item" +msgstr "Supprimer cet entrée du menu" + +#: ../../mod/mitem.php:108 +msgid "Edit this menu item" +msgstr "Éditer cette entrée du menu" + +#: ../../mod/mitem.php:131 +msgid "New Menu Element" +msgstr "Nouvelle entrée de menu" + +#: ../../mod/mitem.php:133 ../../mod/mitem.php:176 +msgid "Menu Item Permissions" +msgstr "Permissions de l'entrée de menu" + +#: ../../mod/mitem.php:134 ../../mod/mitem.php:177 ../../mod/settings.php:967 +msgid "(click to open/close)" +msgstr "(cliquer pour ouvrir/fermer)" + +#: ../../mod/mitem.php:136 ../../mod/mitem.php:180 +msgid "Link text" +msgstr "Texte du lien" + +#: ../../mod/mitem.php:137 ../../mod/mitem.php:181 +msgid "URL of link" +msgstr "URL du lien" + +#: ../../mod/mitem.php:138 ../../mod/mitem.php:182 +msgid "Use Red magic-auth if available" +msgstr "Utiliser l'authentification magique, lorsque disponible" + +#: ../../mod/mitem.php:139 ../../mod/mitem.php:183 +msgid "Open link in new window" +msgstr "Ouvrir le lien dans une nouvelle fenêtre" + +#: ../../mod/mitem.php:141 ../../mod/mitem.php:185 +msgid "Order in list" +msgstr "Ordre dans la liste" + +#: ../../mod/mitem.php:141 ../../mod/mitem.php:185 +msgid "Higher numbers will sink to bottom of listing" +msgstr "Les nombres les plus élevés seront descendus au bas de la liste" + +#: ../../mod/mitem.php:154 +msgid "Menu item not found." +msgstr "Entrée de menu introuvable." + +#: ../../mod/mitem.php:163 +msgid "Menu item deleted." +msgstr "Entrée de menu supprimée." + +#: ../../mod/mitem.php:165 +msgid "Menu item could not be deleted." +msgstr "Impossible de supprimer l'entrée de menu." + +#: ../../mod/mitem.php:174 +msgid "Edit Menu Element" +msgstr "Éditer l'entrée de menu" + +#: ../../mod/mitem.php:186 ../../mod/menu.php:114 +msgid "Modify" +msgstr "Modifier" + +#: ../../mod/ping.php:237 +msgid "sent you a private message" +msgstr "vous a envoyé un message privé" + +#: ../../mod/ping.php:288 +msgid "added your channel" +msgstr "a ajouté votre canal" + +#: ../../mod/ping.php:329 +msgid "posted an event" +msgstr "a publié un événement" + +#: ../../mod/acl.php:239 +msgid "network" +msgstr "réseau" + +#: ../../mod/settings.php:71 +msgid "Name is required" +msgstr "Le nom est requis" + +#: ../../mod/settings.php:75 +msgid "Key and Secret are required" +msgstr "Clef et secret sont requis" + +#: ../../mod/settings.php:196 +msgid "Passwords do not match. Password unchanged." +msgstr "Les deux saisies du mot de passe ne correspondent pas. Il n'a donc pas été changé." + +#: ../../mod/settings.php:200 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Le mot de passe ne peut pas être vide. Il n'a donc pas été changé." + +#: ../../mod/settings.php:214 +msgid "Password changed." +msgstr "Le mot de passe a été changé." + +#: ../../mod/settings.php:216 +msgid "Password update failed. Please try again." +msgstr "La mise à jour du mot de passe a échoué. Merci de recommencer." + +#: ../../mod/settings.php:230 +msgid "Not valid email." +msgstr "Adresse de courriel non-valide." + +#: ../../mod/settings.php:233 +msgid "Protected email address. Cannot change to that email." +msgstr "Adresse de courriel protégée. Impossible de l'utiliser." + +#: ../../mod/settings.php:242 +msgid "System failure storing new email. Please try again." +msgstr "Défaillance système lors du stockage de la nouvelle adresse de courriel. Merci de ré-essayer." + +#: ../../mod/settings.php:445 +msgid "Settings updated." +msgstr "Réglages sauvegardés." + +#: ../../mod/settings.php:516 ../../mod/settings.php:542 +#: ../../mod/settings.php:578 +msgid "Add application" +msgstr "Ajouter une application" + +#: ../../mod/settings.php:519 +msgid "Name of application" +msgstr "Nom de l'application" + +#: ../../mod/settings.php:520 ../../mod/settings.php:546 +msgid "Consumer Key" +msgstr "Clef de consommateur" + +#: ../../mod/settings.php:520 ../../mod/settings.php:521 +msgid "Automatically generated - change if desired. Max length 20" +msgstr "Généré automatiquement - à changer si besoin. Longueur maximale 20 caractères." + +#: ../../mod/settings.php:521 ../../mod/settings.php:547 +msgid "Consumer Secret" +msgstr "Secret de consommateur" + +#: ../../mod/settings.php:522 ../../mod/settings.php:548 +msgid "Redirect" +msgstr "Redirection" + +#: ../../mod/settings.php:522 +msgid "" +"Redirect URI - leave blank unless your application specifically requires " +"this" +msgstr "URI de redirection - laissez blanc, sauf si l'application a demandé autrement" + +#: ../../mod/settings.php:523 ../../mod/settings.php:549 +msgid "Icon url" +msgstr "URL de l'icône" + +#: ../../mod/settings.php:523 +msgid "Optional" +msgstr "Facultatif" + +#: ../../mod/settings.php:534 +msgid "You can't edit this application." +msgstr "Vous ne pouvez pas éditer cette application." + +#: ../../mod/settings.php:577 +msgid "Connected Apps" +msgstr "Applications connectées" + +#: ../../mod/settings.php:581 +msgid "Client key starts with" +msgstr "La clef partagée commence par" + +#: ../../mod/settings.php:582 +msgid "No name" +msgstr "Sans nom" + +#: ../../mod/settings.php:583 +msgid "Remove authorization" +msgstr "Révoquer l'autorisation" + +#: ../../mod/settings.php:594 +msgid "No feature settings configured" +msgstr "Pas de fonctionnalité à configurer" + +#: ../../mod/settings.php:602 +msgid "Feature Settings" +msgstr "Extensions" + +#: ../../mod/settings.php:625 +msgid "Account Settings" +msgstr "Compte" + +#: ../../mod/settings.php:626 +msgid "Password Settings" +msgstr "Mot de passe" + +#: ../../mod/settings.php:627 +msgid "New Password:" +msgstr "Nouveau mot de passe :" + +#: ../../mod/settings.php:628 +msgid "Confirm:" +msgstr "Confirmation :" + +#: ../../mod/settings.php:628 +msgid "Leave password fields blank unless changing" +msgstr "Laissez les mots de passe vides si vous ne voulez pas les modifier" + +#: ../../mod/settings.php:630 ../../mod/settings.php:943 +msgid "Email Address:" +msgstr "Adresse de courriel :" + +#: ../../mod/settings.php:631 ../../mod/removeaccount.php:61 +msgid "Remove Account" +msgstr "Supprimer le compte" + +#: ../../mod/settings.php:632 ../../mod/settings.php:1006 +msgid "Warning: This action is permanent and cannot be reversed." +msgstr "Attention : cette action est permanente et irréversible." + +#: ../../mod/settings.php:648 +msgid "Off" +msgstr "Inactif" + +#: ../../mod/settings.php:648 +msgid "On" +msgstr "Actif" + +#: ../../mod/settings.php:655 +msgid "Additional Features" +msgstr "Fonctionnalités additionnelles" + +#: ../../mod/settings.php:680 +msgid "Connector Settings" +msgstr "Connecteurs" + +#: ../../mod/settings.php:710 ../../mod/admin.php:399 +msgid "No special theme for mobile devices" +msgstr "Pas de thème spécifique aux périphériques mobiles" + +#: ../../mod/settings.php:719 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s - (Expérimental)" + +#: ../../mod/settings.php:752 +msgid "Display Settings" +msgstr "Affichage" + +#: ../../mod/settings.php:758 +msgid "Display Theme:" +msgstr "Thème :" + +#: ../../mod/settings.php:759 +msgid "Mobile Theme:" +msgstr "Thème mobile :" + +#: ../../mod/settings.php:760 +msgid "Enable user zoom on mobile devices" +msgstr "Permettre à l'utilisateur d'un mobile d'agrandir le contenu" + +#: ../../mod/settings.php:761 +msgid "Update browser every xx seconds" +msgstr "Rafraîchir le navigateur toutes les xx secondes" + +#: ../../mod/settings.php:761 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Minimum 10 secondes, pas de maximum" + +#: ../../mod/settings.php:762 +msgid "Maximum number of conversations to load at any time:" +msgstr "Nombre maximal de conversations pouvant être chargées en même temps :" + +#: ../../mod/settings.php:762 +msgid "Maximum of 100 items" +msgstr "100 éléments au maximum" + +#: ../../mod/settings.php:763 +msgid "Don't show emoticons" +msgstr "Ne pas montrer les frimousses/émoticones" + +#: ../../mod/settings.php:764 +msgid "System Page Layout Editor - (advanced)" +msgstr "Agencements des pages système - (avancé)" + +#: ../../mod/settings.php:800 +msgid "Nobody except yourself" +msgstr "Personne sauf vous" + +#: ../../mod/settings.php:801 +msgid "Only those you specifically allow" +msgstr "Seulement ceux que vous autorisez spécifiquement" + +#: ../../mod/settings.php:802 +msgid "Approved connections" +msgstr "Contacts Approuvés" + +#: ../../mod/settings.php:803 +msgid "Any connections" +msgstr "Tous les contacts" + +#: ../../mod/settings.php:804 +msgid "Anybody on this website" +msgstr "Tous les utilisateurs du hub" + +#: ../../mod/settings.php:805 +msgid "Anybody in this network" +msgstr "Tous les utilisateurs sur ce réseau" + +#: ../../mod/settings.php:806 +msgid "Anybody authenticated" +msgstr "Tous les utilisateurs authentifiés" + +#: ../../mod/settings.php:807 +msgid "Anybody on the internet" +msgstr "Tous les utilisateurs d'Internet" + +#: ../../mod/settings.php:884 +msgid "Publish your default profile in the network directory" +msgstr "Publier votre profil par défaut dans l'annuaire du réseau" + +#: ../../mod/settings.php:884 ../../mod/settings.php:889 +#: ../../mod/settings.php:960 ../../mod/api.php:106 ../../mod/profiles.php:566 +#: ../../mod/admin.php:429 +msgid "No" +msgstr "Non" + +#: ../../mod/settings.php:884 ../../mod/settings.php:889 +#: ../../mod/settings.php:960 ../../mod/api.php:105 ../../mod/profiles.php:565 +#: ../../mod/admin.php:431 +msgid "Yes" +msgstr "Oui" + +#: ../../mod/settings.php:889 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "Nous autoriser à vous suggérer comme relation potentielle aux nouveaux membres?" + +#: ../../mod/settings.php:893 ../../mod/profile_photo.php:365 +msgid "or" +msgstr "ou" + +#: ../../mod/settings.php:898 +msgid "Your channel address is" +msgstr "Voici l'adresse de votre canal" + +#: ../../mod/settings.php:932 +msgid "Channel Settings" +msgstr "Canal" + +#: ../../mod/settings.php:941 +msgid "Basic Settings" +msgstr "Basique" + +#: ../../mod/settings.php:944 +msgid "Your Timezone:" +msgstr "Fureau Horaire :" + +#: ../../mod/settings.php:945 +msgid "Default Post Location:" +msgstr "Emplacement géographique par défaut :" + +#: ../../mod/settings.php:945 +msgid "Geographical location to display on your posts" +msgstr "Emplacement géographique à afficher sur vos publications" + +#: ../../mod/settings.php:946 +msgid "Use Browser Location:" +msgstr "Utiliser la géolocalisation fournie par le navigateur :" + +#: ../../mod/settings.php:948 +msgid "Adult Content" +msgstr "Contenu \"adulte\"" + +#: ../../mod/settings.php:948 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "Ce canal publie plus ou moins fréquemment du contenu pour adultes. (Merci d'indiquer tout contenu pour adulte ou potentiellement choquant avec l'étiquette #NSFW - Not Safe For Work)" + +#: ../../mod/settings.php:950 +msgid "Security and Privacy Settings" +msgstr "Réglages de Sécurité et vie privée" + +#: ../../mod/settings.php:952 +msgid "Hide my online presence" +msgstr "Cacher ma présence en ligne" + +#: ../../mod/settings.php:952 +msgid "Prevents displaying in your profile that you are online" +msgstr "Cacher votre statut (en ligne/hors ligne) sur votre profil" + +#: ../../mod/settings.php:954 +msgid "Simple Privacy Settings:" +msgstr "Réglages simples :" + +#: ../../mod/settings.php:955 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "Très public - extrèmement permissif (à n'utiliser qu'en connaissance de cause)" + +#: ../../mod/settings.php:956 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "Classique - public par défaut, privé en cas de besoin (comparable dans le principe aux réseaux sociaux centralisés, avec un mode privé plus efficace)" + +#: ../../mod/settings.php:957 +msgid "Private - default private, never open or public" +msgstr "Privé - privé par défaut, jamais ouvert ni public" + +#: ../../mod/settings.php:958 +msgid "Blocked - default blocked to/from everybody" +msgstr "Bloqué - par défaut, bloqué de/vers tout le monde" + +#: ../../mod/settings.php:960 +msgid "Allow others to tag your posts" +msgstr "Autoriser les autres à \"étiqueté\" vos publications" + +#: ../../mod/settings.php:960 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "Souvent utilisé par la communauté pour distinguer le contenu innaproprié" + +#: ../../mod/settings.php:962 +msgid "Advanced Privacy Settings" +msgstr "Réglages avancés" + +#: ../../mod/settings.php:964 +msgid "Expire other channel content after this many days" +msgstr "Faire expirer le contenu des autres canaux après n jours" + +#: ../../mod/settings.php:964 +msgid "0 or blank prevents expiration" +msgstr "0, ou vide, pour ne pas faire expirer" + +#: ../../mod/settings.php:965 +msgid "Maximum Friend Requests/Day:" +msgstr "Nombre maximum de mises en relation par jour :" + +#: ../../mod/settings.php:965 +msgid "May reduce spam activity" +msgstr "Contribue à réduire l'impact des indésirables" + +#: ../../mod/settings.php:966 +msgid "Default Post Permissions" +msgstr "Permissions par défaut des publications" + +#: ../../mod/settings.php:978 +msgid "Maximum private messages per day from unknown people:" +msgstr "Nombre maximum de messages privés émanant d'inconnus, par jour :" + +#: ../../mod/settings.php:978 +msgid "Useful to reduce spamming" +msgstr "Utile pour réduire les indésirables" + +#: ../../mod/settings.php:981 +msgid "Notification Settings" +msgstr "Notifications" + +#: ../../mod/settings.php:982 +msgid "By default post a status message when:" +msgstr "Par défaut, publier un statut quand:" + +#: ../../mod/settings.php:983 +msgid "accepting a friend request" +msgstr "vous acceptez une mise en relation" + +#: ../../mod/settings.php:984 +msgid "joining a forum/community" +msgstr "vous joignez un forum ou à une communauté" + +#: ../../mod/settings.php:985 +msgid "making an interesting profile change" +msgstr "vous faites une modification intéressante de votre profil" + +#: ../../mod/settings.php:986 +msgid "Send a notification email when:" +msgstr "Envoyer un courriel de notification quand :" + +#: ../../mod/settings.php:987 +msgid "You receive a connection request" +msgstr "Vous recevez une demande de mise en relation" + +#: ../../mod/settings.php:988 +msgid "Your connections are confirmed" +msgstr "Vous relations sont confirmées" + +#: ../../mod/settings.php:989 +msgid "Someone writes on your profile wall" +msgstr "Quelqu'un a écrit sur votre mur" + +#: ../../mod/settings.php:990 +msgid "Someone writes a followup comment" +msgstr "Quelqu'un a commenté sur vos publications" + +#: ../../mod/settings.php:991 +msgid "You receive a private message" +msgstr "Vous recevez un message privé" + +#: ../../mod/settings.php:992 +msgid "You receive a friend suggestion" +msgstr "Vous recevez une suggestion d'amitié/relation" + +#: ../../mod/settings.php:993 +msgid "You are tagged in a post" +msgstr "Vous êtes étiqueté dans une publication" + +#: ../../mod/settings.php:994 +msgid "You are poked/prodded/etc. in a post" +msgstr "Vous êtes cogné/encouragé/etc. dans une publication" + +#: ../../mod/settings.php:997 +msgid "Advanced Account/Page Type Settings" +msgstr "Type de page/Compte (avancé)" + +#: ../../mod/settings.php:998 +msgid "Change the behaviour of this account for special situations" +msgstr "Modifie le comportement de ce compte pour certains cas particuliers" + +#: ../../mod/settings.php:1001 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "Mode expert requis (Réglages > Fonctions supplémentaires) svp ajuster!" + +#: ../../mod/settings.php:1002 +msgid "Miscellaneous Settings" +msgstr "Divers" + +#: ../../mod/settings.php:1004 +msgid "Personal menu to display in your channel pages" +msgstr "Menu personnel tel qu'il apparaîtra sur les pages de votre canal" + +#: ../../mod/settings.php:1005 +msgid "Remove this channel" +msgstr "Supprimer ce canal" + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "Cogner/Encourager" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "Cogner, encourager, et autres choses à faire à quelqu'un" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "Destinataire" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "Choisir quoi lui faire" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "Rendre cette contribution privée" + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Autoriser l'application à se connecter" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Merci de retourner vers votre application, et d'y insérer ce Code de Sécurité :" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Merci de vous connecter pour continuer." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Voulez-vous autoriser cette application à accéder à vos publications et contacts, et/ou à publier en votre nom?" + +#: ../../mod/post.php:229 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please" +" logout and retry." +msgstr "Authentification magique bloquée. Vous êtes connecté sur ce site localement. Merci de vous en déconnecter et réessayer." + +#: ../../mod/post.php:261 ../../mod/openid.php:72 ../../mod/openid.php:178 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "Bienvenue %s. L'authentification magique a fonctionné." + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "Élément indisponible." + +#: ../../mod/probe.php:23 ../../mod/probe.php:29 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "Récupération d'URL échouée : %1$s" + +#: ../../mod/block.php:27 ../../mod/page.php:35 +msgid "Invalid item." +msgstr "Élément invalide." + +#: ../../mod/block.php:39 ../../mod/chanview.php:77 ../../mod/page.php:47 +#: ../../mod/home.php:54 ../../mod/wall_upload.php:28 +msgid "Channel not found." +msgstr "Canal introuvable." + +#: ../../mod/block.php:75 ../../mod/page.php:83 ../../mod/display.php:100 +#: ../../mod/help.php:72 ../../index.php:236 +msgid "Page not found." +msgstr "Page introuvable." + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "L'image a été téléversée, mais le recadrage a échoué." + +#: ../../mod/profile_photo.php:161 +msgid "Image resize failed." +msgstr "Le redimensionnement de l'image a échoué." + +#: ../../mod/profile_photo.php:205 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Shirt-rechargez votre page, ou videz le cache du navigateur si la photo ne s'affiche pas immédiatement." + +#: ../../mod/profile_photo.php:232 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "L'image dépasse la taille limite de %d" + +#: ../../mod/profile_photo.php:241 +msgid "Unable to process image." +msgstr "Impossible de traîter l'image." + +#: ../../mod/profile_photo.php:290 ../../mod/profile_photo.php:339 +msgid "Photo not available." +msgstr "Photo inaccessible." + +#: ../../mod/profile_photo.php:358 +msgid "Upload File:" +msgstr "Fichier :" + +#: ../../mod/profile_photo.php:359 +msgid "Select a profile:" +msgstr "Choisir un profil :" + +#: ../../mod/profile_photo.php:360 +msgid "Upload Profile Photo" +msgstr "Téléverser une photo de profil" + +#: ../../mod/profile_photo.php:365 +msgid "skip this step" +msgstr "passer cette étape" + +#: ../../mod/profile_photo.php:365 +msgid "select a photo from your photo albums" +msgstr "choisir une photo dans vos albums" + +#: ../../mod/profile_photo.php:379 +msgid "Crop Image" +msgstr "Recadrer l'image" + +#: ../../mod/profile_photo.php:380 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Merci d'ajuster le cadre pour une visualisation optimale." + +#: ../../mod/profile_photo.php:382 +msgid "Done Editing" +msgstr "J'ai terminé" + +#: ../../mod/profile_photo.php:425 +msgid "Image uploaded successfully." +msgstr "Image téléversée avec succès." + +#: ../../mod/profile_photo.php:427 +msgid "Image upload failed." +msgstr "Le téléversement a échoué." + +#: ../../mod/profile_photo.php:436 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "La réduction de taille [%s] a échoué." + +#: ../../mod/blocks.php:66 +msgid "Block Name" +msgstr "Nom du Bloc" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:165 +#: ../../mod/profiles.php:222 ../../mod/profiles.php:539 +msgid "Profile not found." +msgstr "Profil introuvable." + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "Profil supprimé." + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "Profil-" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "Nouveau profil créé." + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "Profil impossible à cloner." + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "Impossible d'exporter le profil." + +#: ../../mod/profiles.php:232 +msgid "Profile Name is required." +msgstr "Le nom du profil est requis." + +#: ../../mod/profiles.php:354 +msgid "Marital Status" +msgstr "Statut marital" + +#: ../../mod/profiles.php:358 +msgid "Romantic Partner" +msgstr "Partenaire" + +#: ../../mod/profiles.php:362 +msgid "Likes" +msgstr "Aime" + +#: ../../mod/profiles.php:366 +msgid "Dislikes" +msgstr "Déteste" + +#: ../../mod/profiles.php:370 +msgid "Work/Employment" +msgstr "Travail/Occupation" + +#: ../../mod/profiles.php:373 +msgid "Religion" +msgstr "Religion/Croyance" + +#: ../../mod/profiles.php:377 +msgid "Political Views" +msgstr "Opinions politiques" + +#: ../../mod/profiles.php:381 +msgid "Gender" +msgstr "Sexe/Genre" + +#: ../../mod/profiles.php:385 +msgid "Sexual Preference" +msgstr "Préférence sexuelle" + +#: ../../mod/profiles.php:389 +msgid "Homepage" +msgstr "Site Internet" + +#: ../../mod/profiles.php:393 +msgid "Interests" +msgstr "Centres d'intérêt" + +#: ../../mod/profiles.php:397 ../../mod/admin.php:902 +msgid "Address" +msgstr "Adresse" + +#: ../../mod/profiles.php:404 ../../mod/pubsites.php:25 +msgid "Location" +msgstr "Emplacement" + +#: ../../mod/profiles.php:487 +msgid "Profile updated." +msgstr "Profil mis à jour." + +#: ../../mod/profiles.php:564 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "Cacher vos contacts/relations aux visiteurs de ce profil?" + +#: ../../mod/profiles.php:588 +msgid "Edit Profile Details" +msgstr "Éditer les détails du profil" + +#: ../../mod/profiles.php:590 +msgid "View this profile" +msgstr "Voir le profil" + +#: ../../mod/profiles.php:592 +msgid "Change Profile Photo" +msgstr "Changer la photo du profil" + +#: ../../mod/profiles.php:593 +msgid "Create a new profile using these settings" +msgstr "Créer un nouveau profil avec ces réglages" + +#: ../../mod/profiles.php:594 +msgid "Clone this profile" +msgstr "Cloner le profil" + +#: ../../mod/profiles.php:595 +msgid "Delete this profile" +msgstr "Supprimer le profil" + +#: ../../mod/profiles.php:597 +msgid "Import profile from file" +msgstr "Importer le profil à partir d'un fichier" + +#: ../../mod/profiles.php:598 +msgid "Export profile to file" +msgstr "Exporter le profil vers un fichier." + +#: ../../mod/profiles.php:599 +msgid "Profile Name:" +msgstr "Nom du profil :" + +#: ../../mod/profiles.php:600 +msgid "Your Full Name:" +msgstr "Votre nom complet :" + +#: ../../mod/profiles.php:601 +msgid "Title/Description:" +msgstr "Titre/description :" + +#: ../../mod/profiles.php:602 +msgid "Your Gender:" +msgstr "Sexe/Genre :" + +#: ../../mod/profiles.php:603 +#, php-format +msgid "Birthday (%s):" +msgstr "Date de naissance (%s) :" + +#: ../../mod/profiles.php:604 +msgid "Street Address:" +msgstr "Adresse postale :" + +#: ../../mod/profiles.php:605 +msgid "Locality/City:" +msgstr "Ville/Localité :" + +#: ../../mod/profiles.php:606 +msgid "Postal/Zip Code:" +msgstr "Code postal :" + +#: ../../mod/profiles.php:607 +msgid "Country:" +msgstr "Pays :" + +#: ../../mod/profiles.php:608 +msgid "Region/State:" +msgstr "Région/Province/État :" + +#: ../../mod/profiles.php:609 +msgid " Marital Status:" +msgstr "Statut marital :" + +#: ../../mod/profiles.php:610 +msgid "Who: (if applicable)" +msgstr "Avec : (si pertinent)" + +#: ../../mod/profiles.php:611 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Exemples : cathy123, Cathy Williams, cathy@exemple.com" + +#: ../../mod/profiles.php:612 +msgid "Since [date]:" +msgstr "Depuis [date] :" + +#: ../../mod/profiles.php:614 +msgid "Homepage URL:" +msgstr "URL de mon site Internet :" + +#: ../../mod/profiles.php:617 +msgid "Religious Views:" +msgstr "Opinions religieuses :" + +#: ../../mod/profiles.php:618 +msgid "Keywords:" +msgstr "Mots-clefs :" + +#: ../../mod/profiles.php:621 +msgid "Example: fishing photography software" +msgstr "Exemple : escrime photographie modélisme" + +#: ../../mod/profiles.php:622 +msgid "Used in directory listings" +msgstr "Utilisé pour le référencement dans l'annuaire" + +#: ../../mod/profiles.php:623 +msgid "Tell us about yourself..." +msgstr "Parlez nous de vous..." + +#: ../../mod/profiles.php:624 +msgid "Hobbies/Interests" +msgstr "Loisirs/Centres d'intêret" + +#: ../../mod/profiles.php:625 +msgid "Contact information and Social Networks" +msgstr "Coordonnées et réseaux sociaux" + +#: ../../mod/profiles.php:626 +msgid "My other channels" +msgstr "Mes autres canaux" + +#: ../../mod/profiles.php:627 +msgid "Musical interests" +msgstr "Goûts musicaux" + +#: ../../mod/profiles.php:628 +msgid "Books, literature" +msgstr "Littérature" + +#: ../../mod/profiles.php:629 +msgid "Television" +msgstr "Télévision" + +#: ../../mod/profiles.php:630 +msgid "Film/dance/culture/entertainment" +msgstr "Cinéma/Danse/Culture/Divertissement" + +#: ../../mod/profiles.php:631 +msgid "Love/romance" +msgstr "Amour/Romance" + +#: ../../mod/profiles.php:632 +msgid "Work/employment" +msgstr "Travail/Occupation" + +#: ../../mod/profiles.php:633 +msgid "School/education" +msgstr "Études" + +#: ../../mod/profiles.php:639 +msgid "This is your default profile." +msgstr "Voilà votre profil par défault." + +#: ../../mod/profiles.php:650 ../../mod/directory.php:143 +#: ../../mod/dirprofile.php:92 +msgid "Age: " +msgstr "Age :" + +#: ../../mod/profiles.php:692 +msgid "Edit/Manage Profiles" +msgstr "Éditer/gérer les profils" + +#: ../../mod/profiles.php:693 +msgid "Add profile things" +msgstr "Ajouter des choses de profil" + +#: ../../mod/profiles.php:694 +msgid "Include desirable objects in your profile" +msgstr "Incluez des objets souhaitables dans votre profil" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "Favoris ajouté" + +#: ../../mod/bookmarks.php:58 +msgid "My Bookmarks" +msgstr "Mes Favoris" + +#: ../../mod/bookmarks.php:69 +msgid "My Connections Bookmarks" +msgstr "Favoris de mes relations" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "Identifiant de profil invalide." + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "Éditeur de visibilité de profil" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "Cliquez sur un contact pour l'ajouter ou le retirer." + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "Visible par" + +#: ../../mod/profperm.php:139 ../../mod/connections.php:279 +msgid "All Connections" +msgstr "Toutes les relations" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "Sites publics" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration into the Hubzilla. All sites in" +" the matrix are interlinked so membership on any of them conveys membership " +"in the matrix as a whole. Some sites may require subscription or provide " +"tiered service plans. The provider links may provide " +"additional details." +msgstr "Les sites listés autorisent l'inscription pour tous. Tous sont liés entre eux, de manière à ce qu'un compte sur un seul d'entre eux soit valable sur l'ensemble de la matrice. Certains sites peuvent demander des frais de souscriptions, ou fournir des forfaits ajustés. Le lien \"fournisseur\" peut vous donner des détails supplémentaires." + +#: ../../mod/pubsites.php:25 +msgid "Site URL" +msgstr "URL du site" + +#: ../../mod/pubsites.php:25 +msgid "Access Type" +msgstr "Type d'accès" + +#: ../../mod/pubsites.php:25 +msgid "Registration Policy" +msgstr "Politique d'inscription" + +#: ../../mod/channel.php:25 ../../mod/chat.php:19 +msgid "You must be logged in to see this page." +msgstr "Vous devez vous connecter pour voir cette page." + +#: ../../mod/channel.php:86 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "Permissions insuffisantes. Demande redirigée à la page du profil." + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "Choisir un dossier de favoris" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "Sauver le favoris" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "URL du favoris" + +#: ../../mod/rbmark.php:95 ../../mod/appman.php:93 +msgid "Description" +msgstr "Description" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "Ou entrez le nom d'un nouveau dossier" + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "Salon introuvable" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "Quitter le salon" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "Supprimer le salon" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "Je suis momentanément absent" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "Je suis en ligne" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "Marquer ce salon" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "Nouveau salon" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "Nom du salon" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "Salons de %1$s" + +#: ../../mod/register.php:43 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "Nombre d'inscriptions quotidiennes dépassé. Merci de recommencer demain." + +#: ../../mod/register.php:49 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "Merci d'indiquer votre adhésion aux Règles du Service. L'inscription a échoué." + +#: ../../mod/register.php:83 +msgid "Passwords do not match." +msgstr "Les mots de passe ne concordent pas." + +#: ../../mod/register.php:116 +msgid "" +"Registration successful. Please check your email for validation " +"instructions." +msgstr "Inscription réussie. Merci de vérifier vos courriels pour valider votre compte." + +#: ../../mod/register.php:122 +msgid "Your registration is pending approval by the site owner." +msgstr "Votre inscription est en attente de l'approbation d'un administrateur." + +#: ../../mod/register.php:125 +msgid "Your registration can not be processed." +msgstr "Votre inscription ne peut être traîtée." + +#: ../../mod/register.php:162 +msgid "Registration on this site/hub is by approval only." +msgstr "L'inscription sur cette instance/ce site est soumis à une modération." + +#: ../../mod/register.php:163 +msgid "Register at another affiliated site/hub" +msgstr "S'inscrire sur un site/hub affilié" + +#: ../../mod/register.php:171 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "Ce site a dépassé le nombre de création de compte autorisé par jour. Merci de recommencer demain." + +#: ../../mod/register.php:182 +msgid "Terms of Service" +msgstr "Règles du Service" + +#: ../../mod/register.php:188 +#, php-format +msgid "I accept the %s for this website" +msgstr "J'accepte %s de ce site" + +#: ../../mod/register.php:190 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "J'ai plus de 13 ans et j'accepte les %s de ce site" + +#: ../../mod/register.php:204 ../../mod/admin.php:452 +msgid "Registration" +msgstr "Inscription" + +#: ../../mod/register.php:209 +msgid "Membership on this site is by invitation only." +msgstr "L'inscription à ce site se fait uniquement sur invitation." + +#: ../../mod/register.php:210 +msgid "Please enter your invitation code" +msgstr "Merci de saisir votre code d'invitation" + +#: ../../mod/register.php:213 +msgid "Your email address" +msgstr "Votre adresse de courriel" + +#: ../../mod/register.php:214 +msgid "Choose a password" +msgstr "Choisissez un mot de passe" + +#: ../../mod/register.php:215 +msgid "Please re-enter your password" +msgstr "Confirmez-le" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "Absent" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "En ligne" + +#: ../../mod/regmod.php:12 +msgid "Please login." +msgstr "Merci de vous connecter." + +#: ../../mod/cloud.php:126 +msgid "Hubzilla - Guests: Username: {your email address}, Password: +++" +msgstr "Matrice Rouge - Pour les invités: Nom d'utilisateur = {votre courriel}, Mot de passe = +++" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Il est impossible de supprimer un canal à l'intérieur de 48 heures après avoir changé le mot de passe d'un compte." + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "Supprimer ce Canal" + +#: ../../mod/removeme.php:58 +msgid "" +"This will completely remove this channel from the network. Once this has " +"been done it is not recoverable." +msgstr "Ceci effacera complètement le canal du réseau. Une fois effacé, un canal ne PEUT PAS être récupéré." + +#: ../../mod/removeme.php:59 ../../mod/removeaccount.php:59 +msgid "Please enter your password for verification:" +msgstr "Merci de re-saisir votre mot de passe pour vérification :" + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "Supprimer ce canal ainsi que tous ses clones sur la matrice" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "Par défaut, seule l'instance du canal présente sur ce hub sera supprimée du réseau" + +#: ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "Enlever le canal" + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "Pas de canal." + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "Relations communes" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "Pas de relation en commun." + +#: ../../mod/rmagic.php:38 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Nous avons rencontré un problème avec l'OpenID que vous nous avez fourni. Merci de vérifier que l'ID est bien saisi." + +#: ../../mod/rmagic.php:38 +msgid "The error message was:" +msgstr "Le message d'erreur était :" + +#: ../../mod/rmagic.php:42 +msgid "Authentication failed." +msgstr "Échec de l'authentification." + +#: ../../mod/rmagic.php:82 +msgid "Remote Authentication" +msgstr "Authentification distante" + +#: ../../mod/rmagic.php:83 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "Entrez l'adresse de votre canal (p.ex. moncanal@monsite.com)" + +#: ../../mod/rmagic.php:84 +msgid "Authenticate" +msgstr "Authentifier" + +#: ../../mod/connect.php:55 ../../mod/connect.php:103 +msgid "Continue" +msgstr "Continuer" + +#: ../../mod/connect.php:84 +msgid "Premium Channel Setup" +msgstr "Configuration du canal VIP" + +#: ../../mod/connect.php:86 +msgid "Enable premium channel connection restrictions" +msgstr "Activer les restrictions liées au canal VIP" + +#: ../../mod/connect.php:87 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "Merci de saisir les restrictions et/ou conditions - reçu Paypal, transaction Bitcoin, ligne de conduite, ..." + +#: ../../mod/connect.php:89 ../../mod/connect.php:109 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "Avant d'autoriser la mise en relation, ce canal attire votre attention sur les conditions suivantes :" + +#: ../../mod/connect.php:90 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "Les relations potentielles verront ce qui suit avant de pouvoir continuer :" + +#: ../../mod/connect.php:91 ../../mod/connect.php:112 +msgid "" +"By continuing, I certify that I have complied with any instructions provided" +" on this page." +msgstr "En continuant, je certifie que je me suis acquitté de toutes les instructions indiquées" + +#: ../../mod/connect.php:100 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "(Aucune instruction spécifique n'a été établie par le propriétaire du canal.)" + +#: ../../mod/connect.php:108 +msgid "Restricted or Premium Channel" +msgstr "Canal VIP ou restreint" + +#: ../../mod/network.php:79 +msgid "No such group" +msgstr "Groupe introuvable" + +#: ../../mod/network.php:118 +msgid "Search Results For:" +msgstr "Résultats de recherche pour :" + +#: ../../mod/network.php:172 +msgid "Collection is empty" +msgstr "Collection vide" + +#: ../../mod/network.php:180 +msgid "Collection: " +msgstr "Collection :" + +#: ../../mod/network.php:193 +msgid "Connection: " +msgstr "Relation :" + +#: ../../mod/network.php:196 +msgid "Invalid connection." +msgstr "Relation invalide." + +#: ../../mod/connections.php:37 ../../mod/connedit.php:64 +msgid "Could not access contact record." +msgstr "Impossible d'accéder aux détails du contact." + +#: ../../mod/connections.php:51 ../../mod/connedit.php:78 +msgid "Could not locate selected profile." +msgstr "Impossible de localiser le profil sélectionné." + +#: ../../mod/connections.php:94 ../../mod/connedit.php:132 +msgid "Connection updated." +msgstr "Connexion mise à jour." + +#: ../../mod/connections.php:96 ../../mod/connedit.php:134 +msgid "Failed to update connection record." +msgstr "Impossible de mettre à jour les détails de la relation." + +#: ../../mod/connections.php:191 ../../mod/connections.php:292 +msgid "Blocked" +msgstr "Bloqué" + +#: ../../mod/connections.php:196 ../../mod/connections.php:299 +msgid "Ignored" +msgstr "Ignoré" + +#: ../../mod/connections.php:201 ../../mod/connections.php:313 +msgid "Hidden" +msgstr "Caché" + +#: ../../mod/connections.php:206 ../../mod/connections.php:306 +msgid "Archived" +msgstr "Archivé" + +#: ../../mod/connections.php:230 ../../mod/connections.php:245 +msgid "All" +msgstr "Tout" + +#: ../../mod/connections.php:270 +msgid "Suggest new connections" +msgstr "Suggérer de nouvelles relations" + +#: ../../mod/connections.php:273 +msgid "New Connections" +msgstr "Nouvelles relations" + +#: ../../mod/connections.php:276 +msgid "Show pending (new) connections" +msgstr "Voir les (nouvelles) relations en attente" + +#: ../../mod/connections.php:282 +msgid "Show all connections" +msgstr "Voir toutes les relations" + +#: ../../mod/connections.php:285 +msgid "Unblocked" +msgstr "Non bloquées" + +#: ../../mod/connections.php:288 +msgid "Only show unblocked connections" +msgstr "Ne montrer que les relations non-bloquées" + +#: ../../mod/connections.php:295 +msgid "Only show blocked connections" +msgstr "Ne montrer que les relations bloquées" + +#: ../../mod/connections.php:302 +msgid "Only show ignored connections" +msgstr "Ne montrer que les relations ignorées" + +#: ../../mod/connections.php:309 +msgid "Only show archived connections" +msgstr "Ne montrer que les relations archivées" + +#: ../../mod/connections.php:316 +msgid "Only show hidden connections" +msgstr "Ne montrer que les relations cachées" + +#: ../../mod/connections.php:368 +#, php-format +msgid "%1$s [%2$s]" +msgstr "%1$s [%2$s]" + +#: ../../mod/connections.php:369 +msgid "Edit contact" +msgstr "Éditer contact" + +#: ../../mod/connections.php:390 +msgid "Search your connections" +msgstr "Chercher parmi vos relations" + +#: ../../mod/connections.php:391 +msgid "Finding: " +msgstr "Recherche :" + +#: ../../mod/rpost.php:97 ../../mod/editpost.php:42 +msgid "Edit post" +msgstr "Éditer la contribution" + +#: ../../mod/connedit.php:181 +msgid "is now connected to" +msgstr "est maintenant connecté avec" + +#: ../../mod/connedit.php:274 +msgid "Could not access address book record." +msgstr "Impossible d'accéder aux détails du carnet d'adresses." + +#: ../../mod/connedit.php:288 +msgid "Refresh failed - channel is currently unavailable." +msgstr "Actualisation impossible - le canal est momentanément indisponible." + +#: ../../mod/connedit.php:295 +msgid "Channel has been unblocked" +msgstr "Le canal n'est plus bloqué" + +#: ../../mod/connedit.php:296 +msgid "Channel has been blocked" +msgstr "Le canal est bloqué" + +#: ../../mod/connedit.php:300 ../../mod/connedit.php:312 +#: ../../mod/connedit.php:324 ../../mod/connedit.php:336 +#: ../../mod/connedit.php:352 +msgid "Unable to set address book parameters." +msgstr "Impossible de régler les paramètres du carnet d'adresses." + +#: ../../mod/connedit.php:307 +msgid "Channel has been unignored" +msgstr "Le canal n'est plus ignoré" + +#: ../../mod/connedit.php:308 +msgid "Channel has been ignored" +msgstr "Le canal est ignoré" + +#: ../../mod/connedit.php:319 +msgid "Channel has been unarchived" +msgstr "Le canal n'est plus archivé" + +#: ../../mod/connedit.php:320 +msgid "Channel has been archived" +msgstr "Le canal est archivé" + +#: ../../mod/connedit.php:331 +msgid "Channel has been unhidden" +msgstr "Le canal n'est plus caché" + +#: ../../mod/connedit.php:332 +msgid "Channel has been hidden" +msgstr "Le canal est caché" + +#: ../../mod/connedit.php:347 +msgid "Channel has been approved" +msgstr "Le canal est approuvé" + +#: ../../mod/connedit.php:348 +msgid "Channel has been unapproved" +msgstr "Le canal n'est plus approuvé" + +#: ../../mod/connedit.php:376 +msgid "Connection has been removed." +msgstr "La relation a été supprimée" + +#: ../../mod/connedit.php:396 +#, php-format +msgid "View %s's profile" +msgstr "Voir le profil de %s" + +#: ../../mod/connedit.php:400 +msgid "Refresh Permissions" +msgstr "Actualiser les permissions" + +#: ../../mod/connedit.php:403 +msgid "Fetch updated permissions" +msgstr "Récupérer les permissions les plus récentes" + +#: ../../mod/connedit.php:407 +msgid "Recent Activity" +msgstr "Activité récente" + +#: ../../mod/connedit.php:410 +msgid "View recent posts and comments" +msgstr "Voir les contributions et commentaires récentes" + +#: ../../mod/connedit.php:414 ../../mod/connedit.php:557 +#: ../../mod/admin.php:769 +msgid "Unblock" +msgstr "Débloquer" + +#: ../../mod/connedit.php:414 ../../mod/connedit.php:557 +#: ../../mod/admin.php:768 +msgid "Block" +msgstr "Bloquer" + +#: ../../mod/connedit.php:417 +msgid "Block or Unblock this connection" +msgstr "Bloquer ou Débloquer cette relation" + +#: ../../mod/connedit.php:421 ../../mod/connedit.php:558 +msgid "Unignore" +msgstr "Ne plus ignorer" + +#: ../../mod/connedit.php:421 ../../mod/connedit.php:558 +#: ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "Ignorer" + +#: ../../mod/connedit.php:424 +msgid "Ignore or Unignore this connection" +msgstr "Ignorer ou ne plus ignorer cette relation" + +#: ../../mod/connedit.php:427 +msgid "Unarchive" +msgstr "Ne plus archiver" + +#: ../../mod/connedit.php:427 +msgid "Archive" +msgstr "Archiver" + +#: ../../mod/connedit.php:430 +msgid "Archive or Unarchive this connection" +msgstr "Archiver ou ne plus archiver cette relation" + +#: ../../mod/connedit.php:433 +msgid "Unhide" +msgstr "Ne plus cacher" + +#: ../../mod/connedit.php:433 +msgid "Hide" +msgstr "Cacher" + +#: ../../mod/connedit.php:436 +msgid "Hide or Unhide this connection" +msgstr "Cacher ou ne plus cacher cette relation" + +#: ../../mod/connedit.php:443 +msgid "Delete this connection" +msgstr "Supprimer cette relation" + +#: ../../mod/connedit.php:486 ../../mod/connedit.php:515 +msgid "Approve this connection" +msgstr "Approuver cette relation" + +#: ../../mod/connedit.php:486 +msgid "Accept connection to allow communication" +msgstr "Accepter la relation pour permettre la communication" + +#: ../../mod/connedit.php:502 +msgid "Automatic Permissions Settings" +msgstr "Permissions automatiques" + +#: ../../mod/connedit.php:502 +#, php-format +msgid "Connections: settings for %s" +msgstr "Relations : réglages pour %s" + +#: ../../mod/connedit.php:506 +msgid "" +"When receiving a channel introduction, any permissions provided here will be" +" applied to the new connection automatically and the introduction approved. " +"Leave this page if you do not wish to use this feature." +msgstr "Pour chaque introduction reçue, toutes les permissions définies ici seront appliquées aux nouvelles relations automatiquement, et l'introduction sera approuvée. Laissez cette page telle quelle si vous ne souhaitez pas utiliser ce mécanisme." + +#: ../../mod/connedit.php:508 +msgid "Slide to adjust your degree of friendship" +msgstr "Faites glisser pour ajuster le niveau de la relation" + +#: ../../mod/connedit.php:514 +msgid "inherited" +msgstr "héritée" + +#: ../../mod/connedit.php:516 +msgid "Connection has no individual permissions!" +msgstr "Cette relation n'a aucune permission spécifique!" + +#: ../../mod/connedit.php:517 +msgid "" +"This may be appropriate based on your privacy " +"settings, though you may wish to review the \"Advanced Permissions\"." +msgstr "Ceci devrait correspondre à vos réglages de vie privée, mais vous pouvez toujours contrôler les \"Permissions avancées\"." + +#: ../../mod/connedit.php:519 +msgid "Profile Visibility" +msgstr "Visibilité du profil" + +#: ../../mod/connedit.php:520 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Merci de choisir le profil que vous souhaitez montrer quand %s visite votre profil de manière authentifiée." + +#: ../../mod/connedit.php:521 +msgid "Contact Information / Notes" +msgstr "Notes / Information de contact" + +#: ../../mod/connedit.php:522 +msgid "Edit contact notes" +msgstr "Éditer les notes du contact" + +#: ../../mod/connedit.php:524 +msgid "Their Settings" +msgstr "Ses réglages" + +#: ../../mod/connedit.php:525 +msgid "My Settings" +msgstr "Mes réglages" + +#: ../../mod/connedit.php:527 +msgid "Clear/Disable Automatic Permissions" +msgstr "Effacer/Désactiver les Permissions Automatiques" + +#: ../../mod/connedit.php:528 +msgid "Forum Members" +msgstr "Membres du forum" + +#: ../../mod/connedit.php:529 +msgid "Soapbox" +msgstr "Blogue" + +#: ../../mod/connedit.php:530 +msgid "Full Sharing (typical social network permissions)" +msgstr "Partage Complet (fonctionnement habituel des réseaux sociaux)" + +#: ../../mod/connedit.php:531 +msgid "Cautious Sharing " +msgstr "Partage modéré" + +#: ../../mod/connedit.php:532 +msgid "Follow Only" +msgstr "Suivre uniquement" + +#: ../../mod/connedit.php:533 +msgid "Individual Permissions" +msgstr "Permissions spécifiques" + +#: ../../mod/connedit.php:534 +msgid "" +"Some permissions may be inherited from your channel privacy settings, which have higher priority than " +"individual settings. Changing those inherited settings on this page will " +"have no effect." +msgstr "Certaines permissions peuvent être héritées de vos réglages de vie privée, lesquels sont prioritaires sur les réglages spécifiques. Changer ces permissions héritées sur la présente page n'aura aucun effet." + +#: ../../mod/connedit.php:535 +msgid "Advanced Permissions" +msgstr "Permissions avancées" + +#: ../../mod/connedit.php:536 +msgid "Simple Permissions (select one and submit)" +msgstr "Permissions simples (en choisir une, puis valider)" + +#: ../../mod/connedit.php:540 +#, php-format +msgid "Visit %s's profile - %s" +msgstr "Visiter le profil de %s - %s" + +#: ../../mod/connedit.php:541 +msgid "Block/Unblock contact" +msgstr "Bloquer/Débloquer le contact" + +#: ../../mod/connedit.php:542 +msgid "Ignore contact" +msgstr "Ignorer le contact" + +#: ../../mod/connedit.php:543 +msgid "Repair URL settings" +msgstr "Réparer les réglages d'URL" + +#: ../../mod/connedit.php:544 +msgid "View conversations" +msgstr "Voir les conversations" + +#: ../../mod/connedit.php:546 +msgid "Delete contact" +msgstr "Supprimer le contact" + +#: ../../mod/connedit.php:549 +msgid "Last update:" +msgstr "Dernière mise à jour :" + +#: ../../mod/connedit.php:551 +msgid "Update public posts" +msgstr "Mettre à jour les publications" + +#: ../../mod/connedit.php:553 +msgid "Update now" +msgstr "Mettre à jour maintenant" + +#: ../../mod/connedit.php:559 +msgid "Currently blocked" +msgstr "Actuellement bloqué" + +#: ../../mod/connedit.php:560 +msgid "Currently ignored" +msgstr "Actuellement ignoré" + +#: ../../mod/connedit.php:561 +msgid "Currently archived" +msgstr "Actuellement archivé" + +#: ../../mod/connedit.php:562 +msgid "Currently pending" +msgstr "Actuellement en attente" + +#: ../../mod/connedit.php:563 +msgid "Hide this contact from others" +msgstr "Dissimuler ce contact aux autres" + +#: ../../mod/connedit.php:563 +msgid "" +"Replies/likes to your public posts may still be visible" +msgstr "Les réponses et autres réactions à vos contributions publiques pourraient être toujours visibles" + +#: ../../mod/delegate.php:95 +msgid "No potential page delegates located." +msgstr "Aucun délégué potentiel n'a été trouvé pour cette page." + +#: ../../mod/delegate.php:121 +msgid "Delegate Page Management" +msgstr "Gestion des délégués de la page" + +#: ../../mod/delegate.php:123 +msgid "" +"Delegates are able to manage all aspects of this account/page except for " +"basic account settings. Please do not delegate your personal account to " +"anybody that you do not trust completely." +msgstr "Les délégués sont capables de gérer tous les aspects de ce compte ou de cette page, à l'exception des réglages basiques du compte. Merci de ne déléguer votre compte personnel qu'à quelqu'un en qui vous avez une confiance aveugle." + +#: ../../mod/delegate.php:124 +msgid "Existing Page Managers" +msgstr "Actuels gestionnaires de pages" + +#: ../../mod/delegate.php:126 +msgid "Existing Page Delegates" +msgstr "Actuels délégués" + +#: ../../mod/delegate.php:128 +msgid "Potential Delegates" +msgstr "Délégués potentiels" + +#: ../../mod/delegate.php:130 ../../mod/photos.php:912 ../../mod/tagrm.php:93 +msgid "Remove" +msgstr "Retirer" + +#: ../../mod/delegate.php:131 +msgid "Add" +msgstr "Ajouter" + +#: ../../mod/delegate.php:132 +msgid "No entries." +msgstr "Aucune entrée." + +#: ../../mod/search.php:13 ../../mod/directory.php:15 +#: ../../mod/dirprofile.php:9 ../../mod/display.php:9 ../../mod/photos.php:443 +#: ../../mod/viewconnections.php:17 +msgid "Public access denied." +msgstr "Accès public refusé." + +#: ../../mod/directory.php:146 ../../mod/dirprofile.php:95 +msgid "Gender: " +msgstr "Sexe/genre :" + +#: ../../mod/directory.php:223 +msgid "Finding:" +msgstr "Recherche :" + +#: ../../mod/directory.php:239 +msgid "No entries (some entries may be hidden)." +msgstr "Pas d'entrées (certaines peuvent être cachées)." + +#: ../../mod/dirprofile.php:108 +msgid "Status: " +msgstr "État :" + +#: ../../mod/dirprofile.php:109 +msgid "Sexual Preference: " +msgstr "Orientation sexuelle :" + +#: ../../mod/dirprofile.php:111 +msgid "Homepage: " +msgstr "Site web :" + +#: ../../mod/dirprofile.php:112 +msgid "Hometown: " +msgstr "Ville natale :" + +#: ../../mod/dirprofile.php:114 +msgid "About: " +msgstr "À propos :" + +#: ../../mod/dirprofile.php:162 +msgid "Keywords: " +msgstr "Mots-clefs :" + +#: ../../mod/dirsearch.php:21 +msgid "This site is not a directory server" +msgstr "Ce site n'est pas un serveur d'annuaire" + +#: ../../mod/home.php:81 +msgid "Hubzilla - "The Network"" +msgstr "La Matrice Rouge - "LE Réseau"" + +#: ../../mod/home.php:94 +#, php-format +msgid "Welcome to %s" +msgstr "Bienvenue sur %s" + +#: ../../mod/setup.php:162 +msgid "Hubzilla Server - Setup" +msgstr "Serveur de la Matrice Rouge - Configuration" + +#: ../../mod/setup.php:168 +msgid "Could not connect to database." +msgstr "Impossible de se connecter à la base de données." + +#: ../../mod/setup.php:172 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "Impossible de se connecter au site par l'URL indiquée. Problème potentiel de certificat SSL/TLS ou de DNS." + +#: ../../mod/setup.php:179 +msgid "Could not create table." +msgstr "Impossible de créer la table." + +#: ../../mod/setup.php:185 +msgid "Your site database has been installed." +msgstr "La base de données de votre site a été installée." + +#: ../../mod/setup.php:190 +msgid "" +"You may need to import the file \"install/database.sql\" manually using " +"phpmyadmin or mysql." +msgstr "Vous pourriez avoir besoin d'importer le fichier \"install/database.sql\" manuellement via phpmyadmin ou mysql." + +#: ../../mod/setup.php:191 ../../mod/setup.php:260 ../../mod/setup.php:655 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "Merci de consulter le fichier \"install/INSTALL.txt\"." + +#: ../../mod/setup.php:257 +msgid "System check" +msgstr "Vérification du système" + +#: ../../mod/setup.php:261 ../../mod/events.php:399 +msgid "Next" +msgstr "Suivant" + +#: ../../mod/setup.php:262 +msgid "Check again" +msgstr "Re-vérifier" + +#: ../../mod/setup.php:284 +msgid "Database connection" +msgstr "Connexion à la base de données" + +#: ../../mod/setup.php:285 +msgid "" +"In order to install Hubzilla we need to know how to connect to your " +"database." +msgstr "Pour installer la Matrice Rouge, nous avons besoin de savoir comment contacter votre base de données." + +#: ../../mod/setup.php:286 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Merci de contacter votre prestataire d'hébergement ou votre administrateur système si vous avez des doutes à propos de ces paramètres." + +#: ../../mod/setup.php:287 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "La base de données que vous allez spécifier doit exister. Si ce n'est pas déjà le cas, merci de la créer avant de continuer." + +#: ../../mod/setup.php:291 +msgid "Database Server Name" +msgstr "Nom du serveur de la base de données" + +#: ../../mod/setup.php:291 +msgid "Default is localhost" +msgstr "Par défaut, localhost" + +#: ../../mod/setup.php:292 +msgid "Database Port" +msgstr "Port du serveur" + +#: ../../mod/setup.php:292 +msgid "Communication port number - use 0 for default" +msgstr "Numéro TCP du port - utilisez 0 pour la valeur par défaut" + +#: ../../mod/setup.php:293 +msgid "Database Login Name" +msgstr "Identifiant de connexion à la Base de Données" + +#: ../../mod/setup.php:294 +msgid "Database Login Password" +msgstr "Mot de passe de connexion à la Base de Données" + +#: ../../mod/setup.php:295 +msgid "Database Name" +msgstr "Nom de la Base de Données" + +#: ../../mod/setup.php:297 ../../mod/setup.php:339 +msgid "Site administrator email address" +msgstr "Adresse de courriel de l'administrateur du site" + +#: ../../mod/setup.php:297 ../../mod/setup.php:339 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "Votre compte devra utiliser la même adresse de courriel pour pouvoir utiliser l'administration web." + +#: ../../mod/setup.php:298 ../../mod/setup.php:341 +msgid "Website URL" +msgstr "URL du site" + +#: ../../mod/setup.php:298 ../../mod/setup.php:341 +msgid "Please use SSL (https) URL if available." +msgstr "Merci d'utiliser SSL/TLS (https) autant que possible." + +#: ../../mod/setup.php:301 ../../mod/setup.php:344 +msgid "Please select a default timezone for your website" +msgstr "Merci de choisir une zone de temps (fuseau horaire) pour votre site" + +#: ../../mod/setup.php:328 +msgid "Site settings" +msgstr "Réglages du site" + +#: ../../mod/setup.php:387 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Impossible de trouver une version CLI de PHP dans le PATH du serveur web." + +#: ../../mod/setup.php:388 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "En l'absence de version CLI de PHP sur votre serveur, vous ne pourrez pas utiliser la mise à jour en arrière-plan via cron." + +#: ../../mod/setup.php:392 +msgid "PHP executable path" +msgstr "Chemin vers l'éxecutable PHP" + +#: ../../mod/setup.php:392 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Entrez le chemin complet vers l'exécutable php. Vous pouvez continuer l'installation sans." + +#: ../../mod/setup.php:397 +msgid "Command line PHP" +msgstr "PHP en ligne de commande (CLI)" + +#: ../../mod/setup.php:406 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "La version CLI de PHP sur votre système n'a pas l'option \"register_argc_argv\" activée." + +#: ../../mod/setup.php:407 +msgid "This is required for message delivery to work." +msgstr "Elle est nécessaire pour la livraison de messages." + +#: ../../mod/setup.php:409 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/setup.php:430 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Erreur : la fonction \"openssl_pkey_new\" de ce système n'est pas capable de générer des clefs de chiffrement" + +#: ../../mod/setup.php:431 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Si vous êtes sur un serveur Windows, merci de consulter \"http://www.php.net/manual/fr/openssl.installation.php\"." + +#: ../../mod/setup.php:433 +msgid "Generate encryption keys" +msgstr "Générer les clefs de chiffrement" + +#: ../../mod/setup.php:440 +msgid "libCurl PHP module" +msgstr "module PHP libCurl" + +#: ../../mod/setup.php:441 +msgid "GD graphics PHP module" +msgstr "module PHP GD graphics" + +#: ../../mod/setup.php:442 +msgid "OpenSSL PHP module" +msgstr "module PHP OpenSSL" + +#: ../../mod/setup.php:443 +msgid "mysqli PHP module" +msgstr "module PHP mysqli" + +#: ../../mod/setup.php:444 +msgid "mb_string PHP module" +msgstr "module PHP mb_string" + +#: ../../mod/setup.php:445 +msgid "mcrypt PHP module" +msgstr "module PHP mcrypt" + +#: ../../mod/setup.php:450 ../../mod/setup.php:452 +msgid "Apache mod_rewrite module" +msgstr "module Apache mod_rewrite" + +#: ../../mod/setup.php:450 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Erreur : le module mod-rewrite du serveur web Apache est requis, mais pas installé." + +#: ../../mod/setup.php:456 ../../mod/setup.php:459 +msgid "proc_open" +msgstr "proc_open" + +#: ../../mod/setup.php:456 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "Erreur : proc_open est requis, mais soit n'est pas installé, soit est désactivé dans le php.ini" + +#: ../../mod/setup.php:464 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Erreur : le module libCURL de PHP est requis, mais pas installé." + +#: ../../mod/setup.php:468 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Erreur : le module GD de PHP (avec support JPEG) est requis, mais pas installé." + +#: ../../mod/setup.php:472 +msgid "Error: openssl PHP module required but not installed." +msgstr "Erreur : le module openssl de PHP est requis, mais pas installé." + +#: ../../mod/setup.php:476 +msgid "Error: mysqli PHP module required but not installed." +msgstr "Erreur : le module mysqli de PHP est requis, mais pas installé." + +#: ../../mod/setup.php:480 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Erreur : le module mb_string de PHP est requis, mais pas installé." + +#: ../../mod/setup.php:484 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "Erreur : le module mcrypt de PHP est requis, mais pas installé." + +#: ../../mod/setup.php:500 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "L'installeur web a besoin de créer un fichier \".htconfig.php\" à la racine de votre serveur web, mais en est incapable." + +#: ../../mod/setup.php:501 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "C'est généralement lié à un problème de droits, à cause duquel le serveur web est interdit d'écriture dans le répertoire concerné - alors que votre propre utilisateur a le droit." + +#: ../../mod/setup.php:502 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "Au terme de cette procédure, nous vous transmettrons un texte à sauvegarder dans un fichier nommé .htconfig.php, à la racine de votre installation de La Matrice Rouge." + +#: ../../mod/setup.php:503 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "Autrement, vous pouvez contourner toute cette procédure et réaliser l'installation manuellement. Merci de consulter le fichier \"install/INSTALL.txt\" pour les instructions détaillées." + +#: ../../mod/setup.php:506 +msgid ".htconfig.php is writable" +msgstr "Le fichier .htconfig.php est accessible en écriture" + +#: ../../mod/setup.php:516 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "La Matrice Rouge utilise le moteur de template Smarty3 pour mettre son contenu en forme. Smarty3 compile ses modèles vers du PHP natif pour accélérer le rendu." + +#: ../../mod/setup.php:517 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "Pour utiliser ces modèles, le serveur doit avoir le droits d'écrire dans le dossier %s." + +#: ../../mod/setup.php:518 ../../mod/setup.php:536 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "Merci de vous assurer que l'utilisateur sous lequel le serveur web tourne (le plus souvent, www-data) a bien l'autorisation d'écrire dans ce répertoire." + +#: ../../mod/setup.php:519 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "Note: Comme mesure de sécurité, assurez vous de donner les droits d'écriture sur %s au serveur web uniquement. Éviter de définir les permissions sur les fichiers individuels (.tpl)." + +#: ../../mod/setup.php:522 +#, php-format +msgid "%s is writable" +msgstr "Permission d'écriture sur %s activée" + +#: ../../mod/setup.php:535 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to" +" have write access to the store directory under the Red top level folder" +msgstr "Red utilise le répertoire 'store' - situé à la racine de votre installation de la Matrice Rouge - pour sauvegarder les fichiers envoyés. Le serveur web aura donc besoin de pouvoir y écrire." + +#: ../../mod/setup.php:539 +msgid "store is writable" +msgstr "'store' est accessible en écriture" + +#: ../../mod/setup.php:569 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access" +" to this site." +msgstr "Le certificat SSL/TLS n'a pas pu être validé. Merci de le corriger, ou de désactiver l'accès https à ce site." + +#: ../../mod/setup.php:570 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "Si votre serveur supporte les connections encryptées SSL ou s'il permet les connections sur le port TCP 443 (le port utilisé par le protocole https), vous DEVEZ utiliser un certificat valide. Vous ne DEVEZ PAS utiliser un certificat que vous avez vous-mêmes signé!" + +#: ../../mod/setup.php:571 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "Nous avons ajouté cette contrainte pour éviter que vos publications publiques ne fassent référence à des images sur votre propre hub." + +#: ../../mod/setup.php:572 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "Si votre certificat n'est pas reconnu, les membres des autres sites (avec certificats valides) recevront des messages d'avertissement sur leur propre sites." + +#: ../../mod/setup.php:573 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "Pour des raisons de compatibilité (sur l'ensemble de la matrice) nous nous devons d'insister sur ce prérequis." + +#: ../../mod/setup.php:574 +msgid "" +"Providers are available that issue free certificates which are browser-" +"valid." +msgstr "Il existe une plusieurs autorités de certification qui vous fourniront gratuitement un certificat valide." + +#: ../../mod/setup.php:576 +msgid "SSL certificate validation" +msgstr "Validation du certificat SSL/TLS" + +#: ../../mod/setup.php:582 +msgid "" +"Url rewrite in .htaccess is not working. Check your server configuration." +msgstr "La réécriture d'URL définie dans le .htaccess ne fonctionne pas. Merci de vérifier la configuration de votre serveur web." + +#: ../../mod/setup.php:584 +msgid "Url rewrite is working" +msgstr "La réécriture d'URL fonctionne" + +#: ../../mod/setup.php:594 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "Le fichier de configuration de la base de données - \".htconfig.php\" - ne peut être écrit. Merci de copier le texte généré dans un fichier à ce nom, à la racine de votre serveur web." + +#: ../../mod/setup.php:618 +msgid "Errors encountered creating database tables." +msgstr "Erreurs rencontrées pendant la création de tables de BD." + +#: ../../mod/setup.php:653 +msgid "

    What next

    " +msgstr "

    Et maintenant

    " + +#: ../../mod/setup.php:654 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "IMPORTANT : Vous devez créer [manuellement] une tâche planifiée pour les mises à jour." + +#: ../../mod/editblock.php:8 ../../mod/editblock.php:27 +#: ../../mod/editblock.php:53 ../../mod/editlayout.php:36 +#: ../../mod/editpost.php:20 ../../mod/editwebpage.php:32 +msgid "Item not found" +msgstr "Élément introuvable" + +#: ../../mod/editblock.php:77 +msgid "Edit Block" +msgstr "Éditer bloc" + +#: ../../mod/editblock.php:87 +msgid "Delete block?" +msgstr "Supprimer le bloc?" + +#: ../../mod/editblock.php:115 ../../mod/editlayout.php:110 +#: ../../mod/editpost.php:116 ../../mod/editwebpage.php:147 +msgid "Insert YouTube video" +msgstr "Insérer une vidéo YouTube" + +#: ../../mod/editblock.php:116 ../../mod/editlayout.php:111 +#: ../../mod/editpost.php:117 ../../mod/editwebpage.php:148 +msgid "Insert Vorbis [.ogg] video" +msgstr "Insérer une vidéo Vorbis [.ogg]" + +#: ../../mod/editblock.php:117 ../../mod/editlayout.php:112 +#: ../../mod/editpost.php:118 ../../mod/editwebpage.php:149 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Insérer un son Vorbis [.ogg]" + +#: ../../mod/editblock.php:153 +msgid "Delete Block" +msgstr "Supprimer le bloc" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "Agencement pris-en-compte." + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "Éditer la description" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "Agencement introuvable." + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "Nom du module :" + +#: ../../mod/pdledit.php:55 ../../mod/layouts.php:59 +msgid "Layout Help" +msgstr "Aide à la mise en page" + +#: ../../mod/editlayout.php:72 +msgid "Edit Layout" +msgstr "Éditer mise-en-page" + +#: ../../mod/editlayout.php:82 +msgid "Delete layout?" +msgstr "Supprimer la mise-en-page?" + +#: ../../mod/editlayout.php:146 +msgid "Delete Layout" +msgstr "Supprimer mise-en-page" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "Élément non-éditable" + +#: ../../mod/editpost.php:53 +msgid "Delete item?" +msgstr "Supprimer l'élément?" + +#: ../../mod/editwebpage.php:106 +msgid "Edit Webpage" +msgstr "Éditer page web" + +#: ../../mod/editwebpage.php:116 +msgid "Delete webpage?" +msgstr "Supprimer la page web?" + +#: ../../mod/editwebpage.php:186 +msgid "Delete Webpage" +msgstr "Supprimer page web" + +#: ../../mod/siteinfo.php:57 +#, php-format +msgid "Version %s" +msgstr "Version %s" + +#: ../../mod/siteinfo.php:76 +msgid "Installed plugins/addons/apps:" +msgstr "Extensions/applications installées :" + +#: ../../mod/siteinfo.php:89 +msgid "No installed plugins/addons/apps" +msgstr "Aucune extension/application installée" + +#: ../../mod/siteinfo.php:97 +msgid "Red" +msgstr "Rouge" + +#: ../../mod/siteinfo.php:98 +msgid "" +"This is a hub of the Hubzilla - a global cooperative network of " +"decentralized privacy enhanced websites." +msgstr "Ceci est un serveur de la Matrice Rouge - un réseau collaboratif de plusieurs serveurs qui assurent la protection de votre vie privée notamment par la décentralisation de votre identité." + +#: ../../mod/siteinfo.php:101 +msgid "Running at web location" +msgstr "Installée sur" + +#: ../../mod/siteinfo.php:102 +msgid "" +"Please visit GetZot.com to learn more " +"about the Hubzilla." +msgstr "Merci de visiter GetZot.com pour en apprendre davantage sur la Matrice Rouge." + +#: ../../mod/siteinfo.php:103 +msgid "Bug reports and issues: please visit" +msgstr "Pour remonter bogues et problèmes, merci de visiter" + +#: ../../mod/siteinfo.php:106 +msgid "" +"Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot " +"com" +msgstr "Suggestions, demandes, etc. - merci de vous adresser à \"hubzilla\" à librelist - point com" + +#: ../../mod/siteinfo.php:108 +msgid "Site Administrators" +msgstr "Administrateurs du site" + +#: ../../mod/photos.php:77 +msgid "Page owner information could not be retrieved." +msgstr "Impossible d'obtenir des informations sur le propriétaire de la page." + +#: ../../mod/photos.php:97 +msgid "Album not found." +msgstr "Album introuvable." + +#: ../../mod/photos.php:119 ../../mod/photos.php:675 +msgid "Delete Album" +msgstr "Supprimer album" + +#: ../../mod/photos.php:159 ../../mod/photos.php:963 +msgid "Delete Photo" +msgstr "Supprimer photo" + +#: ../../mod/photos.php:453 +msgid "No photos selected" +msgstr "Aucune photo selectionnée" + +#: ../../mod/photos.php:500 +msgid "Access to this item is restricted." +msgstr "L'accès à l'élément est restreint." + +#: ../../mod/photos.php:574 +#, php-format +msgid "You have used %1$.2f Mbytes of %2$.2f Mbytes photo storage." +msgstr "Vous avez utilisé %1$.2f mégaoctets sur les %2$.2f autorisés pour le stockage des photos." + +#: ../../mod/photos.php:577 +#, php-format +msgid "You have used %1$.2f Mbytes of photo storage." +msgstr "Vous avez utilisé %1$.2f mégaoctets pour le stockage des photos." + +#: ../../mod/photos.php:596 +msgid "Upload Photos" +msgstr "Téléverser des photos" + +#: ../../mod/photos.php:600 ../../mod/photos.php:670 +msgid "New album name: " +msgstr "Créer un album :" + +#: ../../mod/photos.php:601 +msgid "or existing album name: " +msgstr "ou choisir un album existant :" + +#: ../../mod/photos.php:602 +msgid "Do not show a status post for this upload" +msgstr "Ne pas publier de statut pour cet envoi" + +#: ../../mod/photos.php:622 +msgid "Album name could not be decoded" +msgstr "Le nom de l'Album n'a pu être décodé" + +#: ../../mod/photos.php:659 ../../mod/photos.php:681 ../../mod/photos.php:1135 +#: ../../mod/photos.php:1150 +msgid "Contact Photos" +msgstr "Photos de contact" + +#: ../../mod/photos.php:685 +msgid "Edit Album" +msgstr "Éditer l'album" + +#: ../../mod/photos.php:691 +msgid "Show Newest First" +msgstr "Ordre anté-chronologique" + +#: ../../mod/photos.php:693 +msgid "Show Oldest First" +msgstr "Ordre chronologique" + +#: ../../mod/photos.php:736 ../../mod/photos.php:1182 +msgid "View Photo" +msgstr "Voir la photo" + +#: ../../mod/photos.php:782 +msgid "Permission denied. Access to this item may be restricted." +msgstr "Permission refusée. L'accès à cet élément peut avoir été restreint." + +#: ../../mod/photos.php:784 +msgid "Photo not available" +msgstr "Photo indisponible" + +#: ../../mod/photos.php:844 +msgid "Use as profile photo" +msgstr "Utiliser comme photo du profil" + +#: ../../mod/photos.php:868 +msgid "View Full Size" +msgstr "Voir en taille réelle" + +#: ../../mod/photos.php:946 +msgid "Edit photo" +msgstr "Éditer la photo" + +#: ../../mod/photos.php:948 +msgid "Rotate CW (right)" +msgstr "Rotation horaire (droite)" + +#: ../../mod/photos.php:949 +msgid "Rotate CCW (left)" +msgstr "Rotation anti-horaire (gauche)" + +#: ../../mod/photos.php:952 +msgid "New album name" +msgstr "Nouveau nom d'album :" + +#: ../../mod/photos.php:955 +msgid "Caption" +msgstr "Titre/légende" + +#: ../../mod/photos.php:957 +msgid "Add a Tag" +msgstr "Ajouter une étiquette" + +#: ../../mod/photos.php:960 +msgid "" +"Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping" +msgstr "Exemple : @bob, @Barbara_Jensen, @jim@exemple.com, #Ile_de_France, #marathon" + +#: ../../mod/photos.php:1113 +msgid "In This Photo:" +msgstr "Dans cette photo :" + +#: ../../mod/photos.php:1188 +msgid "View Album" +msgstr "Voir l'album" + +#: ../../mod/photos.php:1197 +msgid "Recent Photos" +msgstr "Photos récentes" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "Impossible de créer la source. Aucun canal selectionné." + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "Source créée." + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "Source mise à jour." + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "*" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "Gérer les sources distantes du contenu de votre canal." + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "Nouvelle Source" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "Importer tout ou partie du contenu du canal suivant dans le canal en cours, et le distribuer en concordance avec les réglages de votre canal." + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "N'importer le contenu que s'ils contient ces mots (un par ligne)" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "Laissez en blanc pour importer tout le contenu public" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:110 +msgid "Channel Name" +msgstr "Nom du Canal" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "Source introuvable." + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "Éditer la source" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "Supprimer la source" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "Source supprimée" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "Impossible de supprimer la source." + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "- choisir -" + +#: ../../mod/events.php:72 +msgid "Event title and start time are required." +msgstr "Un titre et une date de début sont requises pour l'événement." + +#: ../../mod/events.php:86 +msgid "Event not found." +msgstr "Événement introuvable." + +#: ../../mod/events.php:329 +msgid "l, F j" +msgstr "l j F" + +#: ../../mod/events.php:351 +msgid "Edit event" +msgstr "Éditer l'événement" + +#: ../../mod/events.php:397 +msgid "Create New Event" +msgstr "Créer événement" + +#: ../../mod/events.php:398 +msgid "Previous" +msgstr "Précédent" + +#: ../../mod/events.php:469 +msgid "hour:minute" +msgstr "heure:minute" + +#: ../../mod/events.php:489 +msgid "Event details" +msgstr "Détails de l'événement" + +#: ../../mod/events.php:490 +#, php-format +msgid "Format is %s %s. Starting date and Title are required." +msgstr "Le format est %s %s. Date de début et titre obligatoires." + +#: ../../mod/events.php:492 +msgid "Event Starts:" +msgstr "L'événement débute :" + +#: ../../mod/events.php:492 ../../mod/events.php:506 ../../mod/appman.php:91 +#: ../../mod/appman.php:92 +msgid "Required" +msgstr "Requis" + +#: ../../mod/events.php:495 +msgid "Finish date/time is not known or not relevant" +msgstr "Date/heure de fin inconnue ou sans objet" + +#: ../../mod/events.php:497 +msgid "Event Finishes:" +msgstr "L'événement termine :" + +#: ../../mod/events.php:500 +msgid "Adjust for viewer timezone" +msgstr "Ajuster au fuseau horaire du visiteur" + +#: ../../mod/events.php:502 +msgid "Description:" +msgstr "Description:" + +#: ../../mod/events.php:506 +msgid "Title:" +msgstr "Titre:" + +#: ../../mod/events.php:508 +msgid "Share this event" +msgstr "Partager cet événement" + +#: ../../mod/filestorage.php:68 +msgid "Permission Denied." +msgstr "Permission refusée." + +#: ../../mod/filestorage.php:85 +msgid "File not found." +msgstr "Fichier introuvable." + +#: ../../mod/filestorage.php:122 +msgid "Edit file permissions" +msgstr "Éditer les permissions du fichier" + +#: ../../mod/filestorage.php:131 +msgid "Set/edit permissions" +msgstr "Définir/Édition des authorisations" + +#: ../../mod/filestorage.php:132 +msgid "Include all files and sub folders" +msgstr "Inclure tous fichiers et sous-répertoires" + +#: ../../mod/filestorage.php:133 +msgid "Return to file list" +msgstr "Retourner à la liste des fichiers" + +#: ../../mod/filestorage.php:135 +msgid "Copy/paste this code to attach file to a post" +msgstr "Copiez/collez ce code pour joindre le fichier à une publication" + +#: ../../mod/filestorage.php:136 +msgid "Copy/paste this URL to link file from a web page" +msgstr "Copiez/collez cette URL pour lier le fichier depuis une page web" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "Canal ajouté." + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "%1$s suit %3$s de %2$s" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "Contact introuvable." + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Suggestion d'amitié/relation envoyée." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Suggérer une relation" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Suggérer une relation à %s" + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "Pas de suggestions pour l'instant. Si le site est récent, merci de re-tenter dans 24 heures." + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "Collection créée." + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "Impossible de créer la collection." + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "Collection mise à jour." + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "Créez une collection de canaux." + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "Nom de la collection :" + +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "Les membres sont visibles par les autres canaux" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "Collection supprimée." + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "Impossible de supprimer la collection." + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "Éditeur de collection" + +#: ../../mod/group.php:196 +msgid "Members" +msgstr "Membres" + +#: ../../mod/group.php:198 +msgid "All Connected Channels" +msgstr "Tous canaux connectés" + +#: ../../mod/group.php:233 +msgid "Click on a channel to add or remove." +msgstr "Cliquer sur un canal pour l'ajouter ou le supprimer" + +#: ../../mod/tagger.php:98 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s a étiqueté le %3$s de %2$s par %4$s" + +#: ../../mod/help.php:43 ../../mod/help.php:49 ../../mod/help.php:55 +msgid "Help:" +msgstr "Aide :" + +#: ../../mod/help.php:69 ../../index.php:233 +msgid "Not Found" +msgstr "Introuvable" + +#: ../../mod/tagrm.php:41 +msgid "Tag removed" +msgstr "Étiquette retirée" + +#: ../../mod/tagrm.php:79 +msgid "Remove Item Tag" +msgstr "Retirer une étiquette à l'élément" + +#: ../../mod/tagrm.php:81 +msgid "Select a tag to remove: " +msgstr "Étiquette à retirer :" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "Réglages du thème sauvegardés." + +#: ../../mod/admin.php:97 ../../mod/admin.php:450 +msgid "Site" +msgstr "Site" + +#: ../../mod/admin.php:98 +msgid "Accounts" +msgstr "Comptes" + +#: ../../mod/admin.php:99 ../../mod/admin.php:894 +msgid "Channels" +msgstr "Canaux" + +#: ../../mod/admin.php:100 ../../mod/admin.php:985 ../../mod/admin.php:1027 +msgid "Plugins" +msgstr "Extensions" + +#: ../../mod/admin.php:101 ../../mod/admin.php:1190 ../../mod/admin.php:1226 +msgid "Themes" +msgstr "Thèmes" + +#: ../../mod/admin.php:102 ../../mod/admin.php:550 +msgid "Server" +msgstr "Serveur" + +#: ../../mod/admin.php:103 +msgid "Profile Config" +msgstr "Configurations du profil" + +#: ../../mod/admin.php:104 +msgid "DB updates" +msgstr "MàJ BD" + +#: ../../mod/admin.php:118 ../../mod/admin.php:125 ../../mod/admin.php:1313 +msgid "Logs" +msgstr "Journaux" + +#: ../../mod/admin.php:124 +msgid "Plugin Features" +msgstr "Fonctionnalités liées aux extensions" + +#: ../../mod/admin.php:126 +msgid "User registrations waiting for confirmation" +msgstr "Inscriptions en attente" + +#: ../../mod/admin.php:206 +msgid "Message queues" +msgstr "File des messages" + +#: ../../mod/admin.php:211 ../../mod/admin.php:449 ../../mod/admin.php:549 +#: ../../mod/admin.php:758 ../../mod/admin.php:893 ../../mod/admin.php:984 +#: ../../mod/admin.php:1026 ../../mod/admin.php:1189 ../../mod/admin.php:1225 +#: ../../mod/admin.php:1312 +msgid "Administration" +msgstr "Administration" + +#: ../../mod/admin.php:212 +msgid "Summary" +msgstr "Résumé" + +#: ../../mod/admin.php:214 +msgid "Registered users" +msgstr "Utilisateurs inscrits" + +#: ../../mod/admin.php:216 ../../mod/admin.php:553 +msgid "Pending registrations" +msgstr "Inscriptions en attente" + +#: ../../mod/admin.php:217 +msgid "Version" +msgstr "Version" + +#: ../../mod/admin.php:219 ../../mod/admin.php:554 +msgid "Active plugins" +msgstr "Extensions actives" + +#: ../../mod/admin.php:370 +msgid "Site settings updated." +msgstr "Réglages du site sauvegardés." + +#: ../../mod/admin.php:401 +msgid "No special theme for accessibility" +msgstr "Pas de thème spécifique pour l'accessibilité" + +#: ../../mod/admin.php:430 +msgid "Yes - with approval" +msgstr "Oui - avec approbation" + +#: ../../mod/admin.php:436 +msgid "My site is not a public server" +msgstr "Mon site n'est pas un serveur publique" + +#: ../../mod/admin.php:437 +msgid "My site has paid access only" +msgstr "Mon site est payant" + +#: ../../mod/admin.php:438 +msgid "My site has free access only" +msgstr "Mon site est gratuit" + +#: ../../mod/admin.php:439 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "Mon site offre des comptes gratuits avec des ajouts payants" + +#: ../../mod/admin.php:453 +msgid "File upload" +msgstr "Envoi de fichier" + +#: ../../mod/admin.php:454 +msgid "Policies" +msgstr "Stratégies" + +#: ../../mod/admin.php:459 +msgid "Site name" +msgstr "Nom du site" + +#: ../../mod/admin.php:460 +msgid "Banner/Logo" +msgstr "Bannière/logo" + +#: ../../mod/admin.php:461 +msgid "Administrator Information" +msgstr "Informations sur l'administrateur" + +#: ../../mod/admin.php:461 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "Coordonnées de l'administrateur du site. Affichée sur la page 'siteinfo'. Vous pouvez utiliser du BBCode ici" + +#: ../../mod/admin.php:462 +msgid "System language" +msgstr "Langue du système" + +#: ../../mod/admin.php:463 +msgid "System theme" +msgstr "Thème du système" + +#: ../../mod/admin.php:463 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "Thème par défaut - il peut être changé pour chaque profil utilisateur - modifier le thème" + +#: ../../mod/admin.php:464 +msgid "Mobile system theme" +msgstr "Thème système pour mobile" + +#: ../../mod/admin.php:464 +msgid "Theme for mobile devices" +msgstr "Thème dédié aux périphériques mobiles" + +#: ../../mod/admin.php:465 +msgid "Accessibility system theme" +msgstr "Thème système pour l'accessibilité" + +#: ../../mod/admin.php:465 +msgid "Accessibility theme" +msgstr "Thème pour l'accessibilité" + +#: ../../mod/admin.php:466 +msgid "Channel to use for this website's static pages" +msgstr "Canal à utiliser pour les pages statiques de ce site" + +#: ../../mod/admin.php:466 +msgid "Site Channel" +msgstr "Canal de ce HUB" + +#: ../../mod/admin.php:468 +msgid "Maximum image size" +msgstr "Taille maximale des images" + +#: ../../mod/admin.php:468 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Taille maximum, en octets, des images envoyées. Par défaut 0, soit sans limite." + +#: ../../mod/admin.php:469 +msgid "Does this site allow new member registration?" +msgstr "Est-ce que l'enregistrement de nouveau membres sur ce site est autorisé?" + +#: ../../mod/admin.php:470 +msgid "Which best describes the types of account offered by this hub?" +msgstr "Choisissez le type de comptes offert sur ce hub?" + +#: ../../mod/admin.php:471 +msgid "Register text" +msgstr "Texte d'inscription" + +#: ../../mod/admin.php:471 +msgid "Will be displayed prominently on the registration page." +msgstr "Sera affiché de manière bien visible sur le formulaire d'inscription." + +#: ../../mod/admin.php:472 +msgid "Accounts abandoned after x days" +msgstr "Les comptes sont abandonnés après x jours" + +#: ../../mod/admin.php:472 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "Pour éviter de gaspiller les ressources du système en essayer de mettre à jour des comptes abandonnés. Mettez 0 pour ne pas avoir de limite de temps." + +#: ../../mod/admin.php:473 +msgid "Allowed friend domains" +msgstr "Domaines amicaux" + +#: ../../mod/admin.php:473 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "Liste de noms de domaines - séparés par des virgules - pour lesquels ce site acceptera les demandes d'amitié ou de mise en relation. Les caractères génériques (*) sont acceptés. Laissez vide pour accepter tous les domaines." + +#: ../../mod/admin.php:474 +msgid "Allowed email domains" +msgstr "Domaines de courriels amicaux" + +#: ../../mod/admin.php:474 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "Liste de noms de domaines - séparés par des virgules - dont les adresses de courriel seront autorisées lors de l'inscription à ce site. Les caractères génériques (*) sont acceptés. Laissez vide pour accepter tous les domaines." + +#: ../../mod/admin.php:475 +msgid "Block public" +msgstr "Bloquer public" + +#: ../../mod/admin.php:475 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Cocher pour interdire tout accès public, y compris aux pages marquées comme publiques, aux visiteurs anonymes." + +#: ../../mod/admin.php:476 +msgid "Force publish" +msgstr "Forcer publication" + +#: ../../mod/admin.php:476 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Cocher pour forcer la publication de tous les profils du site dans l'annuaire." + +#: ../../mod/admin.php:477 +msgid "Disable discovery tab" +msgstr "Désactiver l'onglet \"À découvrir\"" + +#: ../../mod/admin.php:477 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "Ne pas afficher d'onglet avec des contenus publics automatiquement rassemblées depuis des sources choisies pour ce site." + +#: ../../mod/admin.php:478 +msgid "No login on Homepage" +msgstr "Pas de connexion depuis la page d'accueil" + +#: ../../mod/admin.php:478 +msgid "" +"Check to hide the login form from your sites homepage when visitors arrive " +"who are not logged in (e.g. when you put the content of the homepage in via " +"the site channel)." +msgstr "Cocher pour ne pas montrer le formulaire de connexion sur la page d'accueil (typiquement, pour quand vous utilisez la page d'accueil pour afficher du contenu via le canal du site)." + +#: ../../mod/admin.php:480 +msgid "Proxy user" +msgstr "Utilisateurs du proxy" + +#: ../../mod/admin.php:481 +msgid "Proxy URL" +msgstr "URL du proxy (visiter @proxy-list)" + +#: ../../mod/admin.php:482 +msgid "Network timeout" +msgstr "Délai maximal du réseau" + +#: ../../mod/admin.php:482 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "En secondes. Mettre à 0 pour ne pas avoir de délai maximal (pas recommandé)." + +#: ../../mod/admin.php:483 +msgid "Delivery interval" +msgstr "Intervalle de distribution" + +#: ../../mod/admin.php:483 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Temporise le processus de distribution de tant de secondes pour réduire la charge sur le système. Valeurs recommandées : 4-5 pour les serveurs mutualisés, 2-3 pour les VPS. 0-1 pour les gros serveurs dédiés." + +#: ../../mod/admin.php:484 +msgid "Poll interval" +msgstr "Intervalle de scrutation" + +#: ../../mod/admin.php:484 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Temporise le processus de scrutation en tâche de fond de tant de secondes, pour réduire la charge. Si 0, utilise l'intervalle de distribution." + +#: ../../mod/admin.php:485 +msgid "Maximum Load Average" +msgstr "Charge moyenne maximale" + +#: ../../mod/admin.php:485 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Charge système maximale au-delà de laquelle distribution et scrutation sont mis en pause - par défaut 50." + +#: ../../mod/admin.php:541 +msgid "No server found" +msgstr "Serveur introuvable" + +#: ../../mod/admin.php:548 ../../mod/admin.php:772 +msgid "ID" +msgstr "ID" + +#: ../../mod/admin.php:548 +msgid "for channel" +msgstr "pour le canal" + +#: ../../mod/admin.php:548 +msgid "on server" +msgstr "sur le serveur" + +#: ../../mod/admin.php:548 +msgid "Status" +msgstr "État" + +#: ../../mod/admin.php:569 +msgid "Update has been marked successful" +msgstr "La mise à jour a été marquée comme réussie" + +#: ../../mod/admin.php:579 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "L'éxecution de %s a échoué. Merci de vérifier les journaux du système." + +#: ../../mod/admin.php:582 +#, php-format +msgid "Update %s was successfully applied." +msgstr "La mise à jour %s a été appliquée avec succès." + +#: ../../mod/admin.php:586 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "La mise à jour %s n'a pas retourné d'information. Impossible de savoir si elle a réussi ou non." + +#: ../../mod/admin.php:589 +#, php-format +msgid "Update function %s could not be found." +msgstr "La fonction de mise à jour %s est introuvable." + +#: ../../mod/admin.php:604 +msgid "No failed updates." +msgstr "Aucune mise à jour défaillante." + +#: ../../mod/admin.php:608 +msgid "Failed Updates" +msgstr "Mises à jour défaillantes" + +#: ../../mod/admin.php:610 +msgid "Mark success (if update was manually applied)" +msgstr "Marquer comme réussie (si la mise à jour a été réalisée manuellement)" + +#: ../../mod/admin.php:611 +msgid "Attempt to execute this update step automatically" +msgstr "Tenter de réaliser cette étape de mise à jour automatiquement" + +#: ../../mod/admin.php:637 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s utilisateur bloqué/débloqué" +msgstr[1] "%s utilisateurs bloqués/débloqués" + +#: ../../mod/admin.php:644 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s utilisateur supprimé" +msgstr[1] "%s utilisateurs supprimés" + +#: ../../mod/admin.php:675 +msgid "Account not found" +msgstr "Compte introuvable" + +#: ../../mod/admin.php:686 +#, php-format +msgid "User '%s' deleted" +msgstr "Utilisateur '%s' supprimé" + +#: ../../mod/admin.php:695 +#, php-format +msgid "User '%s' unblocked" +msgstr "Utilisateur '%s' débloqué" + +#: ../../mod/admin.php:695 +#, php-format +msgid "User '%s' blocked" +msgstr "Utilisateur '%s' bloqué" + +#: ../../mod/admin.php:759 ../../mod/admin.php:771 +msgid "Users" +msgstr "Utilisateurs" + +#: ../../mod/admin.php:761 ../../mod/admin.php:896 +msgid "select all" +msgstr "tout sélectionner" + +#: ../../mod/admin.php:762 +msgid "User registrations waiting for confirm" +msgstr "Inscriptions en attente d'approbation" + +#: ../../mod/admin.php:763 +msgid "Request date" +msgstr "Date de la demande" + +#: ../../mod/admin.php:764 +msgid "No registrations." +msgstr "Pas d'inscriptions." + +#: ../../mod/admin.php:765 +msgid "Approve" +msgstr "Approuver" + +#: ../../mod/admin.php:766 +msgid "Deny" +msgstr "Refuser" + +#: ../../mod/admin.php:772 +msgid "Register date" +msgstr "Date d'inscription" + +#: ../../mod/admin.php:772 +msgid "Last login" +msgstr "Dernière connexion" + +#: ../../mod/admin.php:772 +msgid "Expires" +msgstr "Expire" + +#: ../../mod/admin.php:772 +msgid "Service Class" +msgstr "Classe de service" + +#: ../../mod/admin.php:774 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Les utilisateurs sélectionnés seront supprimés!\\n\\nTout ce que ces utilisateurs ont publié sur ce site sera détruit de manière définitive!\\n\\nÊtes-vous certain?" + +#: ../../mod/admin.php:775 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "L'utilisateur {0} sera supprimé!\\n\\nTout ce que cet utilisateur a publié sur ce site sera détruit de manière définitive!\\n\\nÊtes-vous certain?" + +#: ../../mod/admin.php:808 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channelss censored/uncensored" +msgstr[0] "%s canal censuré/non-censuré" +msgstr[1] "%s canaux censurés/non-censurés" + +#: ../../mod/admin.php:815 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "%s canal supprimé" +msgstr[1] "%s canaux supprimés" + +#: ../../mod/admin.php:834 +msgid "Channel not found" +msgstr "Canal introuvable" + +#: ../../mod/admin.php:845 +#, php-format +msgid "Channel '%s' deleted" +msgstr "Canal '%s' supprimé" + +#: ../../mod/admin.php:855 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "Canal '%s' non-censuré" + +#: ../../mod/admin.php:855 +#, php-format +msgid "Channel '%s' censored" +msgstr "Canal '%s' censuré" + +#: ../../mod/admin.php:898 +msgid "Censor" +msgstr "Censurer" + +#: ../../mod/admin.php:899 +msgid "Uncensor" +msgstr "Ne plus censurer" + +#: ../../mod/admin.php:902 +msgid "UID" +msgstr "UID" + +#: ../../mod/admin.php:904 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Les canaux sélectionnés seront supprimés!\\n\\nTout ce qui a été publié dans ces canaux sur ce site sera définitivement supprimé!\\n\\nÊtes-vous certain?" + +#: ../../mod/admin.php:905 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Le canal {0} sera supprimé!\\n\\nTout ce qui a été publié sur ce canal sera définitivement supprimé!\\n\\nÊtes-vous certain?" + +#: ../../mod/admin.php:944 +#, php-format +msgid "Plugin %s disabled." +msgstr "Extension %s désactivée." + +#: ../../mod/admin.php:948 +#, php-format +msgid "Plugin %s enabled." +msgstr "Extension %s activée." + +#: ../../mod/admin.php:958 ../../mod/admin.php:1160 +msgid "Disable" +msgstr "Désactiver" + +#: ../../mod/admin.php:960 ../../mod/admin.php:1162 +msgid "Enable" +msgstr "Activer" + +#: ../../mod/admin.php:986 ../../mod/admin.php:1191 +msgid "Toggle" +msgstr "(Dés)activer" + +#: ../../mod/admin.php:994 ../../mod/admin.php:1201 +msgid "Author: " +msgstr "Auteur :" + +#: ../../mod/admin.php:995 ../../mod/admin.php:1202 +msgid "Maintainer: " +msgstr "Maintenu par :" + +#: ../../mod/admin.php:1124 +msgid "No themes found." +msgstr "Aucun thème trouvé." + +#: ../../mod/admin.php:1183 +msgid "Screenshot" +msgstr "Aperçu" + +#: ../../mod/admin.php:1231 +msgid "[Experimental]" +msgstr "[Expérimental]" + +#: ../../mod/admin.php:1232 +msgid "[Unsupported]" +msgstr "[Non-supporté]" + +#: ../../mod/admin.php:1259 +msgid "Log settings updated." +msgstr "Réglages du journal sauvegardés." + +#: ../../mod/admin.php:1315 +msgid "Clear" +msgstr "Vider" + +#: ../../mod/admin.php:1321 +msgid "Debugging" +msgstr "Débogage" + +#: ../../mod/admin.php:1322 +msgid "Log file" +msgstr "Fichier du journal" + +#: ../../mod/admin.php:1322 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "Doit être accessible en écriture par le serveur web. Chemin relatif à la racine de votre installation de la Matrice Rouge." + +#: ../../mod/admin.php:1323 +msgid "Log level" +msgstr "Niveau de journalisation" + +#: ../../mod/thing.php:98 +msgid "Thing updated" +msgstr "Chose mise à jour" + +#: ../../mod/thing.php:158 +msgid "Object store: failed" +msgstr "Stockage de l'objet : échec" + +#: ../../mod/thing.php:162 +msgid "Thing added" +msgstr "Chose ajoutée" + +#: ../../mod/thing.php:182 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "OBJ: %1$s %2$s %3$s" + +#: ../../mod/thing.php:234 +msgid "Show Thing" +msgstr "Montrer chose" + +#: ../../mod/thing.php:241 +msgid "item not found." +msgstr "élément introuvable." + +#: ../../mod/thing.php:272 +msgid "Edit Thing" +msgstr "Éditer chose" + +#: ../../mod/thing.php:274 ../../mod/thing.php:321 +msgid "Select a profile" +msgstr "Choisissez un profil" + +#: ../../mod/thing.php:278 ../../mod/thing.php:324 +msgid "Post an activity" +msgstr "Publier une activité" + +#: ../../mod/thing.php:278 ../../mod/thing.php:324 +msgid "Only sends to viewers of the applicable profile" +msgstr "Envoi exclusivement au membres autorisé de ce profil" + +#: ../../mod/thing.php:280 ../../mod/thing.php:326 +msgid "Name of thing e.g. something" +msgstr "Nom de la chose, p.ex. quelque-chose" + +#: ../../mod/thing.php:282 ../../mod/thing.php:327 +msgid "URL of thing (optional)" +msgstr "URL de la chose (optionnel)" + +#: ../../mod/thing.php:284 ../../mod/thing.php:328 +msgid "URL for photo of thing (optional)" +msgstr "URL de l'image de la chose (optionnel)" + +#: ../../mod/thing.php:319 +msgid "Add Thing to your Profile" +msgstr "Ajouter la chose à votre profil" + +#: ../../mod/import.php:36 +msgid "Nothing to import." +msgstr "Rien à importer." + +#: ../../mod/import.php:58 +msgid "Unable to download data from old server" +msgstr "Impossible de récupérer les données de l'ancien serveur" + +#: ../../mod/import.php:64 +msgid "Imported file is empty." +msgstr "Le fichier importé est vide." + +#: ../../mod/import.php:88 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "Impossible de créer un doublon d'un identifiant de canal. L'import a échoué." + +#: ../../mod/import.php:106 +msgid "Channel clone failed. Import failed." +msgstr "Le clonage du canal a échoué. L'import a échoué." + +#: ../../mod/import.php:116 +msgid "Cloned channel not found. Import failed." +msgstr "Le canal cloné n'a pas été trouvé. L'import a échoué." + +#: ../../mod/import.php:364 +msgid "Import completed." +msgstr "L'import est terminé." + +#: ../../mod/import.php:377 +msgid "You must be logged in to use this feature." +msgstr "Vous devez vous connecter pour utiliser cette fonctionnalité." + +#: ../../mod/import.php:382 +msgid "Import Channel" +msgstr "Importation de canal" + +#: ../../mod/import.php:383 +msgid "" +"Use this form to import an existing channel from a different server/hub. You" +" may retrieve the channel identity from the old server/hub via the network " +"or provide an export file. Only identity and connections/relationships will " +"be imported. Importation of content is not yet available." +msgstr "Utilisez ce formulaire pour importer un canal existant sur un serveur différent. Vous pouvez récupérer l'identité du canal sur l'ancien serveur directement par le réseau, ou bien fournir un fichier d'export. Seules les données d'identité et de relations seront importées. L'importation du contenu est toujours en développement." + +#: ../../mod/import.php:384 +msgid "File to Upload" +msgstr "Fichier à envoyer" + +#: ../../mod/import.php:385 +msgid "Or provide the old server/hub details" +msgstr "Ou fournissez les détails de l'ancien serveur" + +#: ../../mod/import.php:386 +msgid "Your old identity address (xyz@example.com)" +msgstr "Votre ancienne identité (zyx@exemple.com)" + +#: ../../mod/import.php:387 +msgid "Your old login email address" +msgstr "Votre ancienne adresse de courriel" + +#: ../../mod/import.php:388 +msgid "Your old login password" +msgstr "Votre ancien mot de passe" + +#: ../../mod/import.php:389 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be" +" able to post from either location, but only one can be marked as the " +"primary location for files, photos, and media." +msgstr "Quelle que soit l'option choisie, merci de décider si cette nouvelle adresse sera la primaire, ou si votre ancienne adresse continuera à jouer ce rôle. Vous pourrez publier depuis l'adresse de votre choix, mais une seule peut être déclarée comme stockage primaire de vos fichiers/photos/media." + +#: ../../mod/import.php:390 +msgid "Make this hub my primary location" +msgstr "Faire de ce hub l'adresse principale de ce canal" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "Limite du nombre total d'invitation dépassée." + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s : adresse courriel invalide." + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "Rejoignez-nous sur la Matrice Rouge" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Limite d'invitations dépassée. Merci de contacter l'administration de votre site." + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s : Échec dans la livraison du message." + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d message envoyé." +msgstr[1] "%d messages envoyés." + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "Vous ne disposez plus d'aucune invitation" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "Envoyer des invitations" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "Entrez les adresses de courriel, une par ligne :" + +#: ../../mod/invite.php:131 ../../mod/mail.php:225 ../../mod/mail.php:338 +msgid "Your message:" +msgstr "Votre message :" + +#: ../../mod/invite.php:132 +msgid "Please join my community on Hubzilla." +msgstr "Veuillez me rejoindre sur la Matrice Rouge." + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "Vous aurez besoin de fournir le code suivant:" + +#: ../../mod/invite.php:135 +msgid "1. Register at any Hubzilla location (they are all inter-connected)" +msgstr "1. Enregistrez-vous sur n'importe quel serveurs ( ils sont tous inter-connectés )" + +#: ../../mod/invite.php:137 +msgid "2. Enter my Hubzilla network address into the site searchbar." +msgstr "2. Saisissez l'adresse de mon canal dans la barre de recherche du site." + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "ou visitez" + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "3. Click sur [Ajouter]" + +#: ../../mod/item.php:146 +msgid "Unable to locate original post." +msgstr "Impossible de localiser la publication initiale." + +#: ../../mod/item.php:379 +msgid "Empty post discarded." +msgstr "Publication vide annulée." + +#: ../../mod/item.php:421 +msgid "Executable content type not permitted to this channel." +msgstr "Les contenus de type 'exécutable' ne sont pas autorisés sur ce canal." + +#: ../../mod/item.php:850 +msgid "System error. Post not saved." +msgstr "Erreur système. Publication non sauvegardée." + +#: ../../mod/item.php:1302 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "Vous avez atteint votre limite de %1$.0f contributions \"racine\"." + +#: ../../mod/item.php:1308 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "Vous avez atteint votre limite de %1$.0f pages web." + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +msgid "[Embedded content - reload page to view]" +msgstr "[Contenu embarqué - rechargez la page pour le voir]" + +#: ../../mod/layouts.php:62 +msgid "Help with this feature" +msgstr "Aide avec cette fonctionnalité" + +#: ../../mod/layouts.php:84 +msgid "Layout Name" +msgstr "Nom de la mise-en-page" + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "J'aime/Je Déteste" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "Cette action est réservée aux membres." + +#: ../../mod/like.php:21 +msgid "" +"Please login with your Hubzilla ID or register as a new Redmatrix.member to continue." +msgstr "SVP connectez-vous ou enregistrez-vous pour continuer." + +#: ../../mod/like.php:77 ../../mod/like.php:104 ../../mod/like.php:142 +msgid "Invalid request." +msgstr "Requête invalide." + +#: ../../mod/like.php:119 +msgid "thing" +msgstr "chose" + +#: ../../mod/like.php:165 +msgid "Channel unavailable." +msgstr "Canal indisponible." + +#: ../../mod/like.php:204 +msgid "Previous action reversed." +msgstr "Action précédente annulée." + +#: ../../mod/like.php:417 +msgid "Action completed." +msgstr "Action complétée." + +#: ../../mod/like.php:418 +msgid "Thank you." +msgstr "Merci." + +#: ../../mod/lockview.php:35 ../../mod/lockview.php:41 +msgid "Remote privacy information not available." +msgstr "Les informations de vie privée à distance ne sont pas disponibles." + +#: ../../mod/lockview.php:50 +msgid "Visible to:" +msgstr "Visible par :" + +#: ../../mod/viewconnections.php:58 +msgid "No connections." +msgstr "Pas de relation." + +#: ../../mod/viewconnections.php:71 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Visiter le profil de %s [%s]" + +#: ../../mod/viewconnections.php:86 +msgid "View Connnections" +msgstr "Voir les relations" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "Aucun compte valide trouvé." + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "Réinitialisation du mot de passe demandée. Vérifiez vos courriels." + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "Membre du site (%s)" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "Demande de réinitialisation du mot de passe sur %s" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "La demande n'a pas pu être vérifiée. (Peut-être l'avez vous déjà utilisée.) La réinitialisation a échoué." + +#: ../../mod/lostpass.php:85 ../../boot.php:1508 +msgid "Password Reset" +msgstr "Réinitialiser le mot de passe" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "Votre mot de passe a bien été réinitialisé." + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "Votre nouveau mot de passe est" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "Sauvez-le ou copiez-le, puis" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "cliquez ici pour vous connecter" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Votre mot de passe peut être changé depuis la page des Réglages une fois connecté." + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "Votre mot de passe de %s a été changé" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "Mot de passe oublié?" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Saisissez votre adresse de courriel, et validez, pour réinitialiser votre mot de passe. Vérifiez ensuite votre boîte à lettres pour la suite des instructions." + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "Adresse de courriel" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "Réinitialiser" + +#: ../../mod/magic.php:70 +msgid "Hub not found." +msgstr "Hub introuvable." + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "Total des votes" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "Évaluation moyenne" + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "Impossible de localiser le destinataire." + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "Impossible de communiquer avec le canal demandé." + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "Impossible de vérifier le canal demandé." + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "Le canal choisi a des restrictions quant aux messages privés. L'envoi a échoué." + +#: ../../mod/mail.php:121 ../../mod/message.php:31 +msgid "Messages" +msgstr "Messages" + +#: ../../mod/mail.php:132 +msgid "Message deleted." +msgstr "Message supprimé." + +#: ../../mod/mail.php:149 +msgid "Message recalled." +msgstr "Message annulé/rappelé." + +#: ../../mod/mail.php:215 +msgid "Send Private Message" +msgstr "Envoyer un Message Privé" + +#: ../../mod/mail.php:216 ../../mod/mail.php:333 +msgid "To:" +msgstr "À :" + +#: ../../mod/mail.php:221 ../../mod/mail.php:335 +msgid "Subject:" +msgstr "Sujet :" + +#: ../../mod/mail.php:232 +msgid "Send" +msgstr "Envoyer" + +#: ../../mod/mail.php:259 +msgid "Message not found." +msgstr "Message introuvable." + +#: ../../mod/mail.php:302 ../../mod/message.php:72 +msgid "Delete message" +msgstr "Supprimer message" + +#: ../../mod/mail.php:303 +msgid "Recall message" +msgstr "Rappeler/annuler le message" + +#: ../../mod/mail.php:305 +msgid "Message has been recalled." +msgstr "Le message a été rappelé." + +#: ../../mod/mail.php:322 +msgid "Private Conversation" +msgstr "Conversation privée" + +#: ../../mod/mail.php:326 +msgid "Delete conversation" +msgstr "Supprimer conversation" + +#: ../../mod/mail.php:328 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Aucune communication sécurisée n'est possible. Vous pourrez peut-être répondre depuis la page de profil de l'émetteur." + +#: ../../mod/mail.php:332 +msgid "Send Reply" +msgstr "Envoyer une réponse" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "Vous avez créé %1$.0f des %2$.0f canaux autorisés." + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "Créer un nouveau canal" + +#: ../../mod/manage.php:148 +msgid "Channel Manager" +msgstr "Gestionnaire du canal" + +#: ../../mod/manage.php:149 +msgid "Current Channel" +msgstr "Canal actif" + +#: ../../mod/manage.php:151 +msgid "Attach to one of your channels by selecting it." +msgstr "Branchez-vous à l'un de vos canaux en le selectionnant." + +#: ../../mod/manage.php:152 +msgid "Default Channel" +msgstr "Canal par défaut" + +#: ../../mod/manage.php:153 +msgid "Make Default" +msgstr "Définir comme défaut" + +#: ../../mod/wall_upload.php:34 +msgid "Wall Photos" +msgstr "Photos du mur" + +#: ../../mod/match.php:16 +msgid "Profile Match" +msgstr "Profils similaires" + +#: ../../mod/match.php:24 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "Aucun mot-clef à comparer. Merci d'ajouter des mots-clefs à votre profil par défaut." + +#: ../../mod/match.php:61 +msgid "is interested in:" +msgstr "s'intéresse à :" + +#: ../../mod/match.php:69 +msgid "No matches" +msgstr "Pas de correspondance" + +#: ../../mod/menu.php:21 +msgid "Menu updated." +msgstr "Menu mis à jour." + +#: ../../mod/menu.php:25 +msgid "Unable to update menu." +msgstr "Impossible de mettre le menu à jour." + +#: ../../mod/menu.php:30 +msgid "Menu created." +msgstr "Menu créé." + +#: ../../mod/menu.php:34 +msgid "Unable to create menu." +msgstr "Impossible de créer le menu." + +#: ../../mod/menu.php:57 +msgid "Manage Menus" +msgstr "Gérer les menus" + +#: ../../mod/menu.php:60 +msgid "Drop" +msgstr "Supprimer" + +#: ../../mod/menu.php:62 +msgid "Create a new menu" +msgstr "Créer un nouveau menu" + +#: ../../mod/menu.php:63 +msgid "Delete this menu" +msgstr "Supprimer ce menu" + +#: ../../mod/menu.php:64 ../../mod/menu.php:109 +msgid "Edit menu contents" +msgstr "Éditer le contenu du menu" + +#: ../../mod/menu.php:65 +msgid "Edit this menu" +msgstr "Éditer le menu" + +#: ../../mod/menu.php:80 +msgid "New Menu" +msgstr "Nouveau menu" + +#: ../../mod/menu.php:81 ../../mod/menu.php:110 +msgid "Menu name" +msgstr "Nom du menu" + +#: ../../mod/menu.php:81 ../../mod/menu.php:110 +msgid "Must be unique, only seen by you" +msgstr "Doit être unique, ne sera vu que par vous" + +#: ../../mod/menu.php:82 ../../mod/menu.php:111 +msgid "Menu title" +msgstr "Titre du menu" + +#: ../../mod/menu.php:82 ../../mod/menu.php:111 +msgid "Menu title as seen by others" +msgstr "Titre du menu tel que vu par les visiteurs" + +#: ../../mod/menu.php:83 ../../mod/menu.php:112 +msgid "Allow bookmarks" +msgstr "Autoriser l'usage de favoris" + +#: ../../mod/menu.php:83 ../../mod/menu.php:112 +msgid "Menu may be used to store saved bookmarks" +msgstr "Le menu pourra être utilisé pour stocker des favoris" + +#: ../../mod/menu.php:98 +msgid "Menu deleted." +msgstr "Menu supprimé." + +#: ../../mod/menu.php:100 +msgid "Menu could not be deleted." +msgstr "Impossible de supprimer le menu." + +#: ../../mod/menu.php:106 +msgid "Edit Menu" +msgstr "Éditer le menu" + +#: ../../mod/menu.php:108 +msgid "Add or remove entries to this menu" +msgstr "Ajouter/supprimer des entrées à ce menu" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "Conversation supprimée." + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "Pas de message." + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "D d Y - H:i" + +#: ../../mod/new_channel.php:107 +msgid "Add a Channel" +msgstr "Ajouter un canal" + +#: ../../mod/new_channel.php:108 +msgid "" +"A channel is your own collection of related web pages. A channel can be used" +" to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "Un canal est une collection de pages web reliées entre elles, sous votre contrôle. Il peut contenir des profils de réseau social, des blogs, des groupes de conversation, des forums, des pages de célébrités, et bien plus encore. Vous pouvez créer autant de canaux que votre administrateur de hub vous y autorise." + +#: ../../mod/new_channel.php:111 +msgid "Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " +msgstr "Exemples : \"Bob Jameson\", \"Lisa et ses chevaux sauvages\", \"Football\", \"Groupe des amateurs de tir à l'arc\"" + +#: ../../mod/new_channel.php:112 +msgid "Choose a short nickname" +msgstr "Choisissez un alias" + +#: ../../mod/new_channel.php:113 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "Cet alias sera utilisé pour créer une adresse de canal, facile à retenir - un peu comme une adresse de courriel - que vous pourrez partager avec d'autres." + +#: ../../mod/new_channel.php:114 +msgid "Or import an existing channel from another location" +msgstr "Ou importez un canal existant à un autre endroit" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "Identifiant de requête invalide." + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "Annuler" + +#: ../../mod/notifications.php:94 ../../mod/notify.php:53 +msgid "No more system notifications." +msgstr "Pas d'autre notification du système." + +#: ../../mod/notifications.php:98 ../../mod/notify.php:57 +msgid "System Notifications" +msgstr "Notifications du système" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "Impossible de trouver votre hub." + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "Contribution effectuée." + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "signature de la cible invalide" + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "Erreur du protocole OpenID. Pas d'ID retourné." + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "Application installée." + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "Erreur de l'application - Malformée." + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "Code intégré" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "Edition de l'Application" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "Création d'une Application" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "Nom de l'application" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "Emplacement (Lien) vers l'application" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "Lien (URL) de l'icône à utiliser pour cette photo" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "80 x 80 pixels - optionel" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "Version" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "Prix de l'application" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "Emplacement (LIEN) pour l'achat de l'application" + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "Sondage" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "Voir les Résultats" + +#: ../../mod/frphotos.php:79 +msgid "Friendica Photo Album Import" +msgstr "Importer votre Album Photo Friendica" + +#: ../../mod/frphotos.php:80 +msgid "This will import all your Friendica photo albums to this Red channel." +msgstr "Cette fonction va importer tous vos albums photos Friendica dans ce canal de la Matrice Rouge." + +#: ../../mod/frphotos.php:81 +msgid "Friendica Server base URL" +msgstr "URL vers le serveur Friendica" + +#: ../../mod/frphotos.php:82 +msgid "Friendica Login Username" +msgstr "Nom d'utilisateur Friendica" + +#: ../../mod/frphotos.php:83 +msgid "Friendica Login Password" +msgstr "Mot de passe Friendica" + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Il est impossible de supprimer un compte à l'intérieur de 48 heures après avoir changé le mot de passe d'un compte." + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "Supprimer ce Compte" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This will completely remove this account including all its channels from the" +" network. Once this has been done it is not recoverable." +msgstr "Cette fonction va complètement supprimer le compte incluant tous ses canaux sur la matrice. Attention, cette action est irréversible." + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "Supprimer ce compte, tous ses canaux et tous les clones sur la matrice." + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "Par défault, seuls les instances de canaux situés sur ce hub seront supprimer de la matrice." + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "Par défault" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "Sans-Serif" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "Monospace" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/blogga/php/config.php:69 +#: ../../view/theme/blogga/view/theme/blog/config.php:69 +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Theme settings" +msgstr "Réglages du thème" + +#: ../../view/theme/apw/php/config.php:260 +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Set scheme" +msgstr "Définir la palette de couleurs" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set font-size for posts and comments" +msgstr "Définir font-size pour contribution et commentaires" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "Définir la fonte" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "Définir le jeu d'icônes" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "Définir la taille des grandes ombres, par défaut 15px 15px 15px" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "Définir la taille des petites ombres, par défaut 5px 5px 5px" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "Définir la couleur des ombres, par défaut #000" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "Définir le rayon des arrondis, par défaut 5px" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "Définir line-height pour contributions et commentaires" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "Définir l'image d'arrière-plan" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "Image de fond - fichier" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "Définir la couleur d'arrière-plan" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "Définir l'image d'arrière-plan des sections" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "Définir la couleur d'arrière-plan des sections" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "Définir la couleur des éléments - en héxadécimal" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "Définir la couleur des liens - en héxadécimal" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "Définir la largeur maximal des éléments. Par défaut, 400px" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "Définir la largeur minimale des éléments. Par défaut, 240px" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "Définir la largeur du contenu. Par défaut, 48%" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "Définir la couleur des fontes - en héxadécimal" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "Définir background-size pour les éléments" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "Opacité des éléments" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "Afficher seulement l'aperçu des contributions" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "Afficher le panneau latéral sur la page du canal" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "Couleur de la barre de navigation" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "Alignement de l'élément" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "Décalage gauche de l'élément section" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "Décalage droit de l'élément section" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "Largeur de la section" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "Décalage gauche du panneau latéral" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "Décalage droit du panneau latéral" + +#: ../../view/theme/blogga/php/config.php:47 +#: ../../view/theme/blogga/view/theme/blog/config.php:47 +msgid "None" +msgstr "Aucun" + +#: ../../view/theme/blogga/php/config.php:70 +#: ../../view/theme/blogga/view/theme/blog/config.php:70 +msgid "Header image" +msgstr "Image de l'entête" + +#: ../../view/theme/blogga/php/config.php:71 +#: ../../view/theme/blogga/view/theme/blog/config.php:71 +msgid "Header image only on profile pages" +msgstr "Image de l'entête tel qu'elle est affichée sur la page du profil" + +#: ../../view/theme/redbasic/php/config.php:84 +msgid "Light (Hubzilla default)" +msgstr "Blanc (valeur par défaut)" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Narrow navbar" +msgstr "Barre de navigation fine" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar background color" +msgstr "Couleur de fond de la barre de navigation" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation bar gradient top color" +msgstr "Gradient de la barre de navigation HAUT" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation bar gradient bottom color" +msgstr "Gradient de la barre de navigation BAS" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation active button gradient top color" +msgstr "Gradient du bouton de navigation HAUT" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation active button gradient bottom color" +msgstr "Gradient du bouton de navigation BAS" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar border color " +msgstr "Couleur de la bordure de la barre de navigation" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "Navigation bar icon color " +msgstr "Couleur de l'icône de la barre de navigation" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Navigation bar active icon color " +msgstr "Couleur de l'icône active de la barre de navigation" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "link color" +msgstr "couleur des liens" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set font-color for banner" +msgstr "Définir la couleur du texte de la bannière" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color" +msgstr "Définir la couleur d'arrière-plan" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background image" +msgstr "Définir l'image d'arrière-plan" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the background color of items" +msgstr "Définir la couleur de fond des contributions" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the background color of comments" +msgstr "Couleur de fond des commentaires" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the border color of comments" +msgstr "Couleur de la bordure des commentaires" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the indent for comments" +msgstr "Indentation des commentaires" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set the basic color for item icons" +msgstr "Définir la couleur de base pour les icônes des éléments" + +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set the hover color for item icons" +msgstr "Définir la couleur de survol des icônes des éléments" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-size for the entire application" +msgstr "Définir la taille de police pour l'application entière" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set font-color for posts and comments" +msgstr "Définir font-colour pour les contributions et commentaires" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set radius of corners" +msgstr "Définir le rayon des arrondis" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Set shadow depth of photos" +msgstr "Définir la profondeur de l'ombre des photos" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set maximum width of conversation regions" +msgstr "Définir la largeur maximale des conversations" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Center conversation regions" +msgstr "Emplacement de la conversation - Centrer" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "Définir l'opacité minimum du bandeau de navigation - pour le cacher" + +#: ../../view/theme/redbasic/php/config.php:131 +msgid "Set size of conversation author photo" +msgstr "Définir la taille de la photo de l'auteur d'une conversation" + +#: ../../view/theme/redbasic/php/config.php:132 +msgid "Set size of followup author photos" +msgstr "Définir la taille de la photo de l'auteur d'une réponse" + +#: ../../view/theme/redbasic/php/config.php:133 +msgid "Sloppy photo albums" +msgstr "Albums photo \"en biais\"" + +#: ../../view/theme/redbasic/php/config.php:133 +msgid "Are you a clean desk or a messy desk person?" +msgstr "Vous êtes plutôt \"bureau bien rangé\" ou \"gros foutoir\"?" + +#: ../../boot.php:1296 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "La mise à jour %s a échoué. Merci de consulter les journaux d'erreur." + +#: ../../boot.php:1299 +#, php-format +msgid "Update Error at %s" +msgstr "Erreur de mise à jour sur %s" + +#: ../../boot.php:1473 +msgid "" +"Create an account to access services and applications within the Hubzilla" +msgstr "Créez un compte pour pouvoir accéder aux services et applications de la Matrice Red" + +#: ../../boot.php:1501 +msgid "Password" +msgstr "Mot de passe" + +#: ../../boot.php:1502 +msgid "Remember me" +msgstr "Se souvenir de moi" + +#: ../../boot.php:1507 +msgid "Forgot your password?" +msgstr "Mot de passe oublié?" + +#: ../../boot.php:1572 +msgid "permission denied" +msgstr "permission refusée" + +#: ../../boot.php:1573 +msgid "Got Zot?" +msgstr "Authentification magique a échouée. Êtes-vous toujours connecté à votre HUB?" + +#: ../../boot.php:2003 +msgid "toggle mobile" +msgstr "(dés)activer mobile" diff --git a/sources/view/fr/passchanged_eml.tpl b/sources/view/fr/passchanged_eml.tpl new file mode 100644 index 00000000..7c4e3d7b --- /dev/null +++ b/sources/view/fr/passchanged_eml.tpl @@ -0,0 +1,19 @@ + +Cher {{$username}}, + Votre mot de passe a bien été réinitialisé. +Veuillez conserver cette information (ou changer immédiatement ce mot de passe temporaire). + + +Voici les détails de connexion: + +Emplacement du site:⇥{{$siteurl}} +Utilisateur:⇥{{$email}} +Mot de passe:⇥{{$new_password}} + +Vous pouvez changer ce mot de passe à partir des réglages du profil après vous être connecté. + + +Sincèrement, + L'administrateur {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/fr/register_open_eml.tpl b/sources/view/fr/register_open_eml.tpl new file mode 100644 index 00000000..46390bc9 --- /dev/null +++ b/sources/view/fr/register_open_eml.tpl @@ -0,0 +1,18 @@ + +Un compte a été créé sur {{$sitename}} avec cette adresse de courriel. +Voici les détails de connexion: + +Emplacement du site:⇥{{$siteurl}} +Utilisateur:⇥{{$email}} +Mot de passe: (le mot de passe qui a été spécifié lors de l'enregistrement) + +Si ce compte a été créé sans votre accord, vous pouvez visiter ce site et réinitialiser le mot de passe. +Ceci vous permettra de supprimer le compte à partir de la page des réglages du profil. +Veuillez accepter nos excuses pour tous les désagréments engendrés. + +Merci et bienvenue sur {{$sitename}}. + +Sincèrement, + L'administrateur {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/fr/register_verify_eml.tpl b/sources/view/fr/register_verify_eml.tpl new file mode 100644 index 00000000..9d2be027 --- /dev/null +++ b/sources/view/fr/register_verify_eml.tpl @@ -0,0 +1,24 @@ + +Une demande d'enregistrement pour un nouvel utilisateur a été reçue par {{$sitename}} qui requiert +votre accord. + + +Voici les détails de connexion: + +Emplacement du site:⇥{{$siteurl}} +Utilisateur:⇥{{$email}} +Adresse IP: {{$details}} + +Pour confirmer votre accord, veuillez suivre le lien suivant: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +Pour supprimer ce compte, veuillez visiter: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Merci. diff --git a/sources/view/fr/register_verify_member.tpl b/sources/view/fr/register_verify_member.tpl new file mode 100644 index 00000000..3461c56a --- /dev/null +++ b/sources/view/fr/register_verify_member.tpl @@ -0,0 +1,24 @@ + +Merci de vous être enregistré sur {{$sitename}}. + +Voici les détails de connexion: + +Emplacement du site:⇥{{$siteurl}} +Utilisateur:⇥{{$email}} + +Connectez-vous avec le mot de passe que vous avez choisi au moment de l'enregistrement. + +Nous avons besoin de vérifier votre adresse de courriel avant d’autoriser votre accès au réseau. + +Si vous avez enregistré ce compte, suivre ce lien: + +{{$siteurl}}/regver/allow/{{$hash}} + + +Pour supprimer ce compte, veuillez visiter: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Merci. diff --git a/sources/view/fr/strings.php b/sources/view/fr/strings.php new file mode 100644 index 00000000..f73230b1 --- /dev/null +++ b/sources/view/fr/strings.php @@ -0,0 +1,1898 @@ + 1);; +}} +; +$a->strings["Cannot locate DNS info for database server '%s'"] = "Impossible de trouver les infos DNS du serveur de base de données '%s'"; +$a->strings["Profile Photos"] = "Photos du profil"; +$a->strings["%1\$s is now friends with %2\$s"] = "%1\$s et %2\$s sont maintenant amis."; +$a->strings["Sharing notification from Diaspora network"] = "Partage de vos notifications du réseau Diaspora"; +$a->strings["photo"] = "photo"; +$a->strings["status"] = "le statut"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "%1\$s aime %3\$s de %2\$s"; +$a->strings["Attachments:"] = "Pièces jointes:"; +$a->strings["Embedded content"] = "Contenu imbriqué"; +$a->strings["Embedding disabled"] = "Imbrication désactivée"; +$a->strings["created a new post"] = "a publié"; +$a->strings["commented on %s's post"] = "a commenté la publication de %s"; +$a->strings["Site Admin"] = "Administrateur"; +$a->strings["Bookmarks"] = "Favoris"; +$a->strings["Address Book"] = "Carnet d'adresses"; +$a->strings["Login"] = "Connexion"; +$a->strings["Channel Select"] = "Changer de canal"; +$a->strings["Matrix"] = "Matrice"; +$a->strings["Settings"] = "Réglages"; +$a->strings["Files"] = "Fichiers"; +$a->strings["Webpages"] = "Pages web"; +$a->strings["Channel Home"] = "Mon canal"; +$a->strings["Profile"] = "Profil"; +$a->strings["Photos"] = "Photos"; +$a->strings["Events"] = "Événements"; +$a->strings["Directory"] = "Annuaire"; +$a->strings["Help"] = "Aide"; +$a->strings["Mail"] = "Messages"; +$a->strings["Mood"] = "Humeur"; +$a->strings["Poke"] = "Cogner"; +$a->strings["Chat"] = "Clavardage"; +$a->strings["Search"] = "Recherche"; +$a->strings["Probe"] = "Sonder"; +$a->strings["Suggest"] = "Suggérer"; +$a->strings["Random Channel"] = "Un canal au hasard"; +$a->strings["Invite"] = "Invitation"; +$a->strings["Features"] = "Fonctionalités"; +$a->strings["Language"] = "Langue"; +$a->strings["Post"] = "Envoyer"; +$a->strings["Profile Photo"] = "Photo du profil"; +$a->strings["Update"] = "Mise à jour"; +$a->strings["Install"] = "Installer"; +$a->strings["Purchase"] = "Acheter"; +$a->strings["Edit"] = "Éditer"; +$a->strings["Delete"] = "Supprimer"; +$a->strings["Unknown"] = "Inconnu"; +$a->strings["prev"] = "préc."; +$a->strings["first"] = "premier"; +$a->strings["last"] = "dernier"; +$a->strings["next"] = "suiv."; +$a->strings["older"] = "plus ancien"; +$a->strings["newer"] = "plus récent"; +$a->strings["No connections"] = "Sans relations"; +$a->strings["%d Connection"] = array( + 0 => "%d relation", + 1 => "%d relations", +); +$a->strings["View Connections"] = "Voir les relations"; +$a->strings["Save"] = "Sauver"; +$a->strings["poke"] = "cogner"; +$a->strings["poked"] = "a cogné"; +$a->strings["ping"] = "solliciter"; +$a->strings["pinged"] = "a sollicité"; +$a->strings["prod"] = "encourager"; +$a->strings["prodded"] = "a encouragé"; +$a->strings["slap"] = "gifler"; +$a->strings["slapped"] = "a giflé"; +$a->strings["finger"] = "pointer"; +$a->strings["fingered"] = "a pointé"; +$a->strings["rebuff"] = "rejeter"; +$a->strings["rebuffed"] = "a rejeté"; +$a->strings["happy"] = "heureux"; +$a->strings["sad"] = "triste"; +$a->strings["mellow"] = "mélancolique"; +$a->strings["tired"] = "fatigué"; +$a->strings["perky"] = "impertinent"; +$a->strings["angry"] = "colérique"; +$a->strings["stupified"] = "stupéfié"; +$a->strings["puzzled"] = "perplexe"; +$a->strings["interested"] = "intéressé"; +$a->strings["bitter"] = "amer"; +$a->strings["cheerful"] = "joyeux"; +$a->strings["alive"] = "énergique"; +$a->strings["annoyed"] = "agacé"; +$a->strings["anxious"] = "anxieux"; +$a->strings["cranky"] = "énervé"; +$a->strings["disturbed"] = "perturbé"; +$a->strings["frustrated"] = "frustré"; +$a->strings["depressed"] = "déprimé"; +$a->strings["motivated"] = "motivé"; +$a->strings["relaxed"] = "détendu"; +$a->strings["surprised"] = "surpris"; +$a->strings["Monday"] = "Lundi"; +$a->strings["Tuesday"] = "Mardi"; +$a->strings["Wednesday"] = "Mercredi"; +$a->strings["Thursday"] = "Jeudi"; +$a->strings["Friday"] = "Vendredi"; +$a->strings["Saturday"] = "Samedi"; +$a->strings["Sunday"] = "Dimanche"; +$a->strings["January"] = "Janvier"; +$a->strings["February"] = "Février"; +$a->strings["March"] = "Mars"; +$a->strings["April"] = "Avril"; +$a->strings["May"] = "Mai"; +$a->strings["June"] = "Juin"; +$a->strings["July"] = "Juillet"; +$a->strings["August"] = "Août"; +$a->strings["September"] = "Septembre"; +$a->strings["October"] = "Octobre"; +$a->strings["November"] = "Novembre"; +$a->strings["December"] = "Décembre"; +$a->strings["unknown.???"] = "inconnu.???"; +$a->strings["bytes"] = "octets"; +$a->strings["remove category"] = "supprimer la catégorie"; +$a->strings["remove from file"] = "retirer du fichier"; +$a->strings["Click to open/close"] = "Cliquer pour ouvrir/fermer"; +$a->strings["Link to Source"] = "Lien vers la source"; +$a->strings["Select a page layout: "] = "Choisir une mise en page :"; +$a->strings["default"] = "défaut"; +$a->strings["Page content type: "] = "Type de contenu :"; +$a->strings["Select an alternate language"] = "Choisir une langue alternative"; +$a->strings["event"] = "événement"; +$a->strings["comment"] = "commentaire"; +$a->strings["activity"] = "activité"; +$a->strings["Design"] = "Conception"; +$a->strings["Blocks"] = "Blocs"; +$a->strings["Menus"] = "Menus"; +$a->strings["Layouts"] = "Mises-en-page"; +$a->strings["Pages"] = "Pages"; +$a->strings["New Page"] = "Nouvelle page"; +$a->strings["View"] = "Voir"; +$a->strings["Preview"] = "Aperçu"; +$a->strings["Actions"] = "Actions"; +$a->strings["Page Link"] = "Lien vers la page"; +$a->strings["Title"] = "Titre"; +$a->strings["Created"] = "Créé"; +$a->strings["Edited"] = "Édité"; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "Le formulaire n'est plus sécurisé, probablement parce qu'il est ouvert depuis trop longtemps (plus de 3 heures)."; +$a->strings["Not a valid email address"] = "Ce n'est pas une adresse de courriel valide"; +$a->strings["Your email domain is not among those allowed on this site"] = "Votre domaine de courriel ne fait pas partie de ceux autorisés par ce site"; +$a->strings["Your email address is already registered at this site."] = "Votre adresse de courriel est déjà inscrite sur ce site."; +$a->strings["An invitation is required."] = "Une invitation est requise."; +$a->strings["Invitation could not be verified."] = "Votre invitation n'a pas pu être vérifiée."; +$a->strings["Please enter the required information."] = "Merci d'entrer les informations requises."; +$a->strings["Failed to store account information."] = "Impossible de stocker les informations liées au compte."; +$a->strings["Registration confirmation for %s"] = "Confirmation de l'enregistrement pour %s"; +$a->strings["Registration request at %s"] = "Demande d'inscription sur %s"; +$a->strings["Administrator"] = "Administrateur"; +$a->strings["your registration password"] = "votre mot de passe d'inscription"; +$a->strings["Registration details for %s"] = "Détails de l'inscription à %s"; +$a->strings["Account approved."] = "Compte approuvé."; +$a->strings["Registration revoked for %s"] = "Inscription révoquée pour %s"; +$a->strings["Account verified. Please login."] = "Compte vérifié. Veuillez vous connecter."; +$a->strings["Permission denied."] = "Permission refusée."; +$a->strings["Image exceeds website size limit of %lu bytes"] = "L'image dépasse la taille limite de %lu octets"; +$a->strings["Image file is empty."] = "L'image est vide."; +$a->strings["Unable to process image"] = "Impossible de traiter l'image"; +$a->strings["Photo storage failed."] = "Le stockage de l'image a échoué."; +$a->strings["Photo Albums"] = "Albums photo"; +$a->strings["Upload New Photos"] = "Ajouter des photos"; +$a->strings["Visible to your default audience"] = "Visible pour vos contacts seulement."; +$a->strings["Show"] = "Voir plus"; +$a->strings["Don't show"] = "Cacher"; +$a->strings["Permissions"] = "Permissions"; +$a->strings["Close"] = "Fermer"; +$a->strings[" and "] = " et "; +$a->strings["public profile"] = "profil public"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s a changé %2\$s en “%3\$s”"; +$a->strings["Visit %1\$s's %2\$s"] = "Visiter %1\$s sur %2\$s"; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s a mis à jour %2\$s, modifiant %3\$s."; +$a->strings["Public Timeline"] = "Fil public"; +$a->strings["Item was not found."] = "Élément introuvable."; +$a->strings["No source file."] = "Pas de fichier source."; +$a->strings["Cannot locate file to replace"] = "Impossible de trouver le fichier à remplacer."; +$a->strings["Cannot locate file to revise/update"] = "Impossible de trouver le fichier à corriger/mettre à jour"; +$a->strings["File exceeds size limit of %d"] = "Le fichier dépasse la taille limite de %d"; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Vous avez atteint votre limite de %1$.0f méga-octets autorisés pour le stockage des pièces-jointes"; +$a->strings["File upload failed. Possible system limit or action terminated."] = "Envoi du fichier impossible. Limite système ou action avortée."; +$a->strings["Stored file could not be verified. Upload failed."] = "Le fichier stocké n'a pu être vérifié. Envoi impossible."; +$a->strings["Path not available."] = "Chemin non disponible."; +$a->strings["Empty pathname"] = "Chemin vide"; +$a->strings["duplicate filename or path"] = "doublon de chemin ou de fichier"; +$a->strings["Path not found."] = "Chemin introuvable."; +$a->strings["mkdir failed."] = "mkdir a échoué."; +$a->strings["database storage failed."] = "l'écriture dans la BD a échoué"; +$a->strings["Click here to upgrade."] = "Cliquez ici pour mettre à jour."; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Cette action outrepasserait les limites prévues par votre forfait."; +$a->strings["This action is not available under your subscription plan."] = "Cette action n'est pas possible avec la formule choisie."; +$a->strings["l F d, Y \\@ g:i A"] = "l d F Y \\à G\\hi"; +$a->strings["Starts:"] = "Début :"; +$a->strings["Finishes:"] = "Fin :"; +$a->strings["Location:"] = "Emplacement :"; +$a->strings["Logout"] = "Déconnexion"; +$a->strings["End this session"] = "Mettre fin à la session"; +$a->strings["Home"] = "Canal"; +$a->strings["Your posts and conversations"] = "Vos publications et conversations"; +$a->strings["View Profile"] = "Voir profil"; +$a->strings["Your profile page"] = "Votre profil"; +$a->strings["Edit Profiles"] = "Éditer les profils"; +$a->strings["Manage/Edit profiles"] = "Gérer/éditer les profils"; +$a->strings["Edit Profile"] = "Éditer le profil"; +$a->strings["Edit your profile"] = "Éditer votre profil"; +$a->strings["Your photos"] = "Vos photos"; +$a->strings["Your files"] = "Vos fichiers"; +$a->strings["Your chatrooms"] = "Vos salons"; +$a->strings["Your bookmarks"] = "Vos favoris"; +$a->strings["Your webpages"] = "Vos pages web"; +$a->strings["Sign in"] = "Connexion"; +$a->strings["%s - click to logout"] = "%s - cliquer ici pour déconnecter"; +$a->strings["Click to authenticate to your home hub"] = "S'authentifier auprès de votre hub"; +$a->strings["Home Page"] = "Page d'accueil"; +$a->strings["Register"] = "S'inscrire"; +$a->strings["Create an account"] = "Créer un compte"; +$a->strings["Help and documentation"] = "Aide et documentation"; +$a->strings["Apps"] = "Applications"; +$a->strings["Applications, utilities, links, games"] = "Applications, utilitaires, liens, jeux"; +$a->strings["Search site content"] = "Rechercher parmi le contenu du site"; +$a->strings["Channel Locator"] = "Localisation de canaux"; +$a->strings["Your matrix"] = "Votre matrice"; +$a->strings["Mark all matrix notifications seen"] = "Marquer toutes les notifications de la matrice comme vues"; +$a->strings["Channel home"] = "Mon canal"; +$a->strings["Mark all channel notifications seen"] = "Marquer toutes les notifications du canal comme vues"; +$a->strings["Connections"] = "Relations"; +$a->strings["Notices"] = "Notifications"; +$a->strings["Notifications"] = "Notifications"; +$a->strings["See all notifications"] = "Voir toutes les notifications"; +$a->strings["Mark all system notifications seen"] = "Marquer toutes les notifications système comme vues"; +$a->strings["Private mail"] = "Messages privés"; +$a->strings["See all private messages"] = "Voir tous les messages privés"; +$a->strings["Mark all private messages seen"] = "Marquer tous les messages privés comme vus"; +$a->strings["Inbox"] = "Boîte de réception"; +$a->strings["Outbox"] = "Boîte d'envoi"; +$a->strings["New Message"] = "Nouveau message"; +$a->strings["Event Calendar"] = "Calendrier des événements"; +$a->strings["See all events"] = "Voir tous les événements"; +$a->strings["Mark all events seen"] = "Marquer tous les événements comme vus"; +$a->strings["Manage Your Channels"] = "Gérer vos canaux"; +$a->strings["Account/Channel Settings"] = "Réglages du Compte/Canal"; +$a->strings["Admin"] = "Administrateur"; +$a->strings["Site Setup and Configuration"] = "Configuration du site"; +$a->strings["Nothing new here"] = "Aucun nouveau contenu trouvé"; +$a->strings["Please wait..."] = "Merci de patienter..."; +$a->strings["%1\$s's bookmarks"] = "Favoris de %1\$s"; +$a->strings["Tags"] = "Étiquettes"; +$a->strings["Keywords"] = "Mots-clefs"; +$a->strings["have"] = "ont"; +$a->strings["has"] = "a"; +$a->strings["want"] = "veulent"; +$a->strings["wants"] = "veut"; +$a->strings["like"] = "aime"; +$a->strings["likes"] = "aiment"; +$a->strings["dislike"] = "déteste"; +$a->strings["dislikes"] = "détestent"; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "J'aime", + 1 => "J'aime", +); +$a->strings["Default"] = "Défaut"; +$a->strings["Frequently"] = "Constamment"; +$a->strings["Hourly"] = "Chaque heure"; +$a->strings["Twice daily"] = "Deux fois par jour"; +$a->strings["Daily"] = "Chaque jour"; +$a->strings["Weekly"] = "Chaque semaine"; +$a->strings["Monthly"] = "Chaque mois"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Email"] = "Courriel"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "Linkedin"; +$a->strings["XMPP/IM"] = "XMPP/IM"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["%d invitation available"] = array( + 0 => "%d invitation disponible", + 1 => "%d invitations disponibles", +); +$a->strings["Advanced"] = "Avancé"; +$a->strings["Find Channels"] = "Trouver des canaux"; +$a->strings["Enter name or interest"] = "Saisir nom ou centre d'intérêt"; +$a->strings["Connect/Follow"] = "Ajouter/Suivre"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Exemples: Robert Morgenstein, Course à pieds"; +$a->strings["Find"] = "Trouver"; +$a->strings["Channel Suggestions"] = "Canaux suggérés"; +$a->strings["Random Profile"] = "Un profil au hasard"; +$a->strings["Invite Friends"] = "Inviter des amis"; +$a->strings["Exammple: name=fred and country=iceland"] = "Exemple: name=fred and country=iceland"; +$a->strings["Advanced Find"] = "Recherche avancée"; +$a->strings["Saved Folders"] = "Dossiers sauvegardés"; +$a->strings["Everything"] = "Tout"; +$a->strings["Categories"] = "Catégories"; +$a->strings["%d connection in common"] = array( + 0 => "%d relation en commun", + 1 => "%d relations en commun", +); +$a->strings["show more"] = "montrer plus"; +$a->strings["This event has been added to your calendar."] = "Cet événement a été ajouté à votre calendrier."; +$a->strings["Invalid data packet"] = "Paquet de données invalide"; +$a->strings["Unable to verify channel signature"] = "Impossible de vérifier la signature du canal"; +$a->strings["Unable to verify site signature for %s"] = "Impossible de vérifier la signature de site pour %s"; +$a->strings["Miscellaneous"] = "Divers"; +$a->strings["year"] = "année"; +$a->strings["month"] = "mois"; +$a->strings["day"] = "jour"; +$a->strings["never"] = "jamais"; +$a->strings["less than a second ago"] = "à l'instant"; +$a->strings["years"] = "années"; +$a->strings["months"] = "mois"; +$a->strings["week"] = "semaine"; +$a->strings["weeks"] = "semaines"; +$a->strings["days"] = "jours"; +$a->strings["hour"] = "heure"; +$a->strings["hours"] = "heures"; +$a->strings["minute"] = "minute"; +$a->strings["minutes"] = "minutes"; +$a->strings["second"] = "seconde"; +$a->strings["seconds"] = "secondes"; +$a->strings["%1\$d %2\$s ago"] = "il y a %1\$d %2\$s"; +$a->strings["%1\$s's birthday"] = "Anniversaire de %1\$s"; +$a->strings["Happy Birthday %1\$s"] = "Joyeux Anniversaire %1\$s"; +$a->strings["Sort Options"] = "Options de tri"; +$a->strings["Alphabetic"] = "Alphabétique"; +$a->strings["Reverse Alphabetic"] = "Alphabétique inversé"; +$a->strings["Newest to Oldest"] = "Anté-chronologique"; +$a->strings["Enable Safe Search"] = "Activer la recherche sûre"; +$a->strings["Disable Safe Search"] = "Désactiver la recherche sûre"; +$a->strings["Safe Mode"] = "Mode sûr"; +$a->strings["Hubzilla Notification"] = "Notification Matrice Rouge"; +$a->strings["hubzilla"] = "Matrice Rouge"; +$a->strings["Thank You,"] = "Merci,"; +$a->strings["%s Administrator"] = "l'administrateur de %s"; +$a->strings["%s "] = "%s "; +$a->strings["[Red:Notify] New mail received at %s"] = "[Red:Notification] Nouveau message reçu sur %s"; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, vous avez reçu un message privé sur %3\$s, de la part de %2\$s."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s vous a envoyé %2\$s."; +$a->strings["a private message"] = "un message privé"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Merci de visiter %s pour voir et/ou répondre à vos messages privés."; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s a commenté sur [zrl=%3\$s]%4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s a commenté sur [zrl=%3\$s]%5\$s de %4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s a commenté [zrl=%3\$s]votre %4\$s[/zrl]"; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Red:Notification] Commentaire de %2\$s sur conversation #%1\$d"; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s a commenté un élément de conversation que vous suivez."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Merci de visiter %s pour voir et/ou répondre sur cette conversation."; +$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Red:Notification] %s a publié sur votre profil"; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s a publié sur votre profil à %3\$s"; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s a publié sur [zrl=%3\$s]votre profil[/zrl]"; +$a->strings["[Red:Notify] %s tagged you"] = "[Red:Notification] %s vous a étiqueté"; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, vous avez été étiqueté sur %3\$s par %2\$s"; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]vous a étiqueté[/zrl]."; +$a->strings["[Red:Notify] %1\$s poked you"] = "[Red:Notification] %1\$s vous a cogné"; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s vous a cogné sur %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]vous a cogné[/zrl]."; +$a->strings["[Red:Notify] %s tagged your post"] = "[Red:Notification] %s a étiqueté votre publication"; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s a étiqueté votre publication sur %3\$s"; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s a étiqueté [zrl=%3\$s]votre publication[/zrl]"; +$a->strings["[Red:Notify] Introduction received"] = "[Red:Notification] Nouvelle introduction"; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, vous avez reçu une demande de mise en relation de '%2\$s' sur %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, vous avez reçu [zrl=%2\$s]une demande de mise en relation[/zrl] de %3\$s."; +$a->strings["You may visit their profile at %s"] = "Vous pouvez visiter leur profil sur %s"; +$a->strings["Please visit %s to approve or reject the connection request."] = "Merci de visiter %s avant d'approuver (ou non) cette demande de relation."; +$a->strings["[Red:Notify] Friend suggestion received"] = "[Red:Notification] Nouvelle suggestion d'amitié"; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, vous avez reçu une suggestion de relation de '%2\$s' à %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, avez reçu %3\$s comme [zrl=%2\$s]une suggestion de relation[/zrl] de %4\$s."; +$a->strings["Name:"] = "Nom :"; +$a->strings["Photo:"] = "Photo :"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Merci de visiter %s pour donner suite (ou non) à cette suggestion."; +$a->strings["[Red:Notify]"] = "[Red:Notification]"; +$a->strings["parent"] = "retour"; +$a->strings["Collection"] = "Collection"; +$a->strings["Principal"] = "Principal"; +$a->strings["Addressbook"] = "Carnet d'adresse"; +$a->strings["Calendar"] = "Calendrier"; +$a->strings["Schedule Inbox"] = "Calendrier - Message entrants"; +$a->strings["Schedule Outbox"] = "Calendrier - Message sortants"; +$a->strings["%1\$s used"] = "%1\$s utilisé"; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = "%1\$s utilisé de %2\$s (%3\$s%)"; +$a->strings["Name"] = "Nom"; +$a->strings["Type"] = "Type"; +$a->strings["Size"] = "Taille"; +$a->strings["Last Modified"] = "Modifié le"; +$a->strings["Total"] = "Total"; +$a->strings["Create new folder"] = "Nouveau dossier"; +$a->strings["Create"] = "Créer"; +$a->strings["Upload file"] = "Téléverser un fichier"; +$a->strings["Upload"] = "Envoyer"; +$a->strings["channel"] = "canal"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "%1\$s déteste %3\$s de %2\$s"; +$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s ajoute %2\$s à ses relations"; +$a->strings["%1\$s poked %2\$s"] = "%1\$s a cogné %2\$s"; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s est %2\$s"; +$a->strings["Select"] = "Sélectionner"; +$a->strings["Private Message"] = "Message Privé"; +$a->strings["Message is verified"] = "Message vérifié"; +$a->strings["View %s's profile @ %s"] = "Voir le profil de %s @ %s"; +$a->strings["Categories:"] = "Catégories :"; +$a->strings["Filed under:"] = "Classé sous :"; +$a->strings[" from %s"] = "de %s"; +$a->strings["last edited: %s"] = "dernière édition : %s"; +$a->strings["Expires: %s"] = "Expire : %s"; +$a->strings["View in context"] = "Voir en contexte"; +$a->strings["Please wait"] = "Merci de patienter"; +$a->strings["remove"] = "supprimer"; +$a->strings["Loading..."] = "Chargement..."; +$a->strings["Delete Selected Items"] = "Supprimer les éléments selectionnés"; +$a->strings["View Source"] = "Voir source"; +$a->strings["Follow Thread"] = "Suivre discussion"; +$a->strings["View Status"] = "Voir état"; +$a->strings["View Photos"] = "Voir photos"; +$a->strings["Matrix Activity"] = "Activité sur la matrice"; +$a->strings["Edit Contact"] = "Éditer contact"; +$a->strings["Send PM"] = "Envoyer un Message Privé"; +$a->strings["%s likes this."] = "%s aime ça."; +$a->strings["%s doesn't like this."] = "%s déteste ça."; +$a->strings["%2\$d people like this."] = array( + 0 => "", + 1 => "%2\$d personne(s) aime(nt) ça.", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "", + 1 => "%2\$d personne(s) déteste(nt) ça.", +); +$a->strings["and"] = "et"; +$a->strings[", and %d other people"] = array( + 0 => "", + 1 => ", et %d autre(s) personne(s)", +); +$a->strings["%s like this."] = "%s aime ça."; +$a->strings["%s don't like this."] = "%s déteste ça."; +$a->strings["Visible to everybody"] = "Visible par tout le monde"; +$a->strings["Please enter a link URL:"] = "Merci d'entrer l'URL d'un lien :"; +$a->strings["Please enter a video link/URL:"] = "Merci d'entrer l'URL d'une video :"; +$a->strings["Please enter an audio link/URL:"] = "Merci d'entrer l'URL d'un contenu audio :"; +$a->strings["Tag term:"] = "Étiquette :"; +$a->strings["Save to Folder:"] = "Classer dans le dossier :"; +$a->strings["Where are you right now?"] = "Où êtes-vous présentement?"; +$a->strings["Expires YYYY-MM-DD HH:MM"] = "Expire YYYY-MM-DD HH:MM"; +$a->strings["Share"] = "Partager"; +$a->strings["Page link title"] = "Titre du lien vers la page"; +$a->strings["Post as"] = "Publier en tant que"; +$a->strings["Upload photo"] = "Téléverser une photo"; +$a->strings["upload photo"] = "téléverser une photo"; +$a->strings["Attach file"] = "Attacher un fichier"; +$a->strings["attach file"] = "attacher un fichier"; +$a->strings["Insert web link"] = "Insérer lien web"; +$a->strings["web link"] = "lien web"; +$a->strings["Insert video link"] = "Insérer lien vidéo"; +$a->strings["video link"] = "lien vidéo"; +$a->strings["Insert audio link"] = "Insérer un lien audio"; +$a->strings["audio link"] = "lien audio"; +$a->strings["Set your location"] = "Spécifier votre emplacement géographique"; +$a->strings["set location"] = "spécifier l'emplacement géographique"; +$a->strings["Clear browser location"] = "Nettoyer l'emplacement géographique du navigateur"; +$a->strings["clear location"] = "nettoyer l'emplacement géographique"; +$a->strings["Set title"] = "Spécifier le titre"; +$a->strings["Categories (comma-separated list)"] = "Catégories (séparées par des virgules)"; +$a->strings["Permission settings"] = "Permissions"; +$a->strings["permissions"] = "permissions"; +$a->strings["Public post"] = "Contenu public"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Exemple: robert@exemple.com, marie@exemple.com"; +$a->strings["Set expiration date"] = "Définir la date d'expiration"; +$a->strings["Encrypt text"] = "Chiffrer le texte"; +$a->strings["OK"] = "Ok"; +$a->strings["Cancel"] = "Annuler"; +$a->strings["Discover"] = "À découvrir"; +$a->strings["Imported public streams"] = "Flux publics importés"; +$a->strings["Commented Order"] = "Commentaires Récents"; +$a->strings["Sort by Comment Date"] = "Trier par date de dernier commentaire"; +$a->strings["Posted Order"] = "Publications Récentes"; +$a->strings["Sort by Post Date"] = "Trier par date de publication"; +$a->strings["Personal"] = "Personnel"; +$a->strings["Posts that mention or involve you"] = "Publications qui vous mentionnent ou vous concernent d'une manière ou d'une autre"; +$a->strings["New"] = "Nouveautés"; +$a->strings["Activity Stream - by date"] = "Flux d'activité - par date"; +$a->strings["Starred"] = "Mis en avant"; +$a->strings["Favourite Posts"] = "Publications préférées"; +$a->strings["Spam"] = "Indésirable"; +$a->strings["Posts flagged as SPAM"] = "Publications marquées comme indésirables"; +$a->strings["Channel"] = "Canal"; +$a->strings["Status Messages and Posts"] = "Messages d'état et contributions"; +$a->strings["About"] = "À propos"; +$a->strings["Profile Details"] = "Détails du profil"; +$a->strings["Files and Storage"] = "Fichiers et Stockage"; +$a->strings["Chatrooms"] = "Salons de clavardage"; +$a->strings["Saved Bookmarks"] = "Favoris sauvegardés"; +$a->strings["Manage Webpages"] = "Gérer les pages web"; +$a->strings["General Features"] = "Fonctionnalités générales"; +$a->strings["Content Expiration"] = "Expiration de contenu"; +$a->strings["Remove posts/comments and/or private messages at a future time"] = "Supprimer les contributions/commentaires et/ou messages privés plus tard"; +$a->strings["Multiple Profiles"] = "Profils multiples"; +$a->strings["Ability to create multiple profiles"] = "Possibilité de créer plusieurs profils"; +$a->strings["Advanced Profiles"] = "Profils Avancés"; +$a->strings["Additional profile sections and selections"] = "Sections additionnelles du profil"; +$a->strings["Profile Import/Export"] = "Importer/Exporter le profil"; +$a->strings["Save and load profile details across sites/channels"] = "Distribuer les détails du profil sur la matrice."; +$a->strings["Web Pages"] = "Pages web"; +$a->strings["Provide managed web pages on your channel"] = "Fournir des pages web, sous votre contrôle, sur votre canal"; +$a->strings["Private Notes"] = "Notes privées"; +$a->strings["Enables a tool to store notes and reminders"] = "Active un outil pour stocker notes et mémos"; +$a->strings["Extended Identity Sharing"] = "Partage d'identité étendue"; +$a->strings["Share your identity with all websites on the internet. When disabled, identity is only shared with sites in the matrix."] = "Partage votre identité avec tous les sites web du Monde. Si décoché, l'identité sera seulement partagée avec les sites de la matrice."; +$a->strings["Expert Mode"] = "Mode expert"; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = "Activer le mode expert pour accéder aux options avancées"; +$a->strings["Premium Channel"] = "Canal VIP"; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = "Vous permet d'appliquer des règles et restrictions aux relations de votre canal"; +$a->strings["Post Composition Features"] = "Fonctionnalités de composition"; +$a->strings["Use Markdown"] = "Utiliser Markdown"; +$a->strings["Allow use of \"Markdown\" to format posts"] = "Authoriser l'usage de \"Markdown\" pour le format des partages"; +$a->strings["Post Preview"] = "Aperçu avant publication"; +$a->strings["Allow previewing posts and comments before publishing them"] = "Permettre de prévisualiser les publications/commentaires"; +$a->strings["Channel Sources"] = "Canaux sources"; +$a->strings["Automatically import channel content from other channels or feeds"] = "Importe automatiquement le contenus d'autres canaux ou flux dans le canal en cours"; +$a->strings["Even More Encryption"] = "Encore plus de chiffrement"; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = "Permettre le chiffrement - optionnel - du contenu de bout-en-bout au moyen d'un secret partagé"; +$a->strings["Network and Stream Filtering"] = "Filtrage du réseau et des flux"; +$a->strings["Search by Date"] = "Chercher par date"; +$a->strings["Ability to select posts by date ranges"] = "Pouvoir choisir des publications par date"; +$a->strings["Collections Filter"] = "Filtre des collections"; +$a->strings["Enable widget to display Network posts only from selected collections"] = "Activer une boîte qui permet de filtrer les publications du réseau parmi les collections selectionnées"; +$a->strings["Saved Searches"] = "Recherches sauvées"; +$a->strings["Save search terms for re-use"] = "Sauver des termes de recherche pour utilisation ultérieure"; +$a->strings["Network Personal Tab"] = "Onglet \"réseau personnel\""; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = "Activer un onglet affichant seulement les publications du réseau sur lesquelles vous êtes intervenu"; +$a->strings["Network New Tab"] = "Onglet \"nouveautés réseau\""; +$a->strings["Enable tab to display all new Network activity"] = "Activer un onglet avec toute activité récente sur le réseau"; +$a->strings["Affinity Tool"] = "Gérer l'affinité"; +$a->strings["Filter stream activity by depth of relationships"] = "Filtrer le flux d'activité en fonction de la profondeur des relations"; +$a->strings["Suggest Channels"] = "Suggérer des canaux"; +$a->strings["Show channel suggestions"] = "Montrer les suggestions de canaux"; +$a->strings["Post/Comment Tools"] = "Gérer les publications/commentaires"; +$a->strings["Edit Sent Posts"] = "Éditer les publications envoyées"; +$a->strings["Edit and correct posts and comments after sending"] = "Permettre d'éditer/corriger les publications/commentaires après envoi"; +$a->strings["Tagging"] = "Étiquettes"; +$a->strings["Ability to tag existing posts"] = "Permettre de marquer les publications existantes"; +$a->strings["Post Categories"] = "Catégoriser les publications"; +$a->strings["Add categories to your posts"] = "Ajouter des catégories à vos publications"; +$a->strings["Ability to file posts under folders"] = "Permettre de classer les publications dans des dossiers"; +$a->strings["Dislike Posts"] = "Détester les publications"; +$a->strings["Ability to dislike posts/comments"] = "Pouvoir détester les publications/commentaires"; +$a->strings["Star Posts"] = "Mettre en avant les publications"; +$a->strings["Ability to mark special posts with a star indicator"] = "Pouvoir marquer certaines publications d'une étoile"; +$a->strings["Tag Cloud"] = "Nuage de tags"; +$a->strings["Provide a personal tag cloud on your channel page"] = "Afficher un nuage de vos tags sur votre canal"; +$a->strings["Channel is blocked on this site."] = "Ce canal est bloqué sur ce site."; +$a->strings["Channel location missing."] = "Emplacement du canal introuvable."; +$a->strings["Response from remote channel was incomplete."] = "La réponse du canal distant était incomplète."; +$a->strings["Channel was deleted and no longer exists."] = "Le canal a été supprimé et n'existe plus."; +$a->strings["Channel discovery failed."] = "La tentative d'accéder au canal a échouée."; +$a->strings["local account not found."] = "compte local introuvable."; +$a->strings["Cannot connect to yourself."] = "Ne peut pas se connecter à vous."; +$a->strings["Missing room name"] = "Il manque le nom du salon"; +$a->strings["Duplicate room name"] = "Un salon de ce nom existe déjà"; +$a->strings["Invalid room specifier."] = "Identifiant de salon invalide."; +$a->strings["Room not found."] = "Salon introuvable."; +$a->strings["Room is full"] = "Le salon est plein"; +$a->strings["Permission denied"] = "Accès refusé"; +$a->strings["(Unknown)"] = "(Inconnu)"; +$a->strings["Visible to anybody on the internet."] = "Visible à tout le monde sur internet."; +$a->strings["Visible to you only."] = "Visible pour vous seulement."; +$a->strings["Visible to anybody in this network."] = "Visible sur toute la Matrice."; +$a->strings["Visible to anybody authenticated."] = "Visible aux utilisateurs authentifiés."; +$a->strings["Visible to anybody on %s."] = "Visible pour tous sur %s."; +$a->strings["Visible to all connections."] = "Visible pour tous les contacts."; +$a->strings["Visible to approved connections."] = "Visible aux contacts approuvés."; +$a->strings["Item not found."] = "Élément introuvable."; +$a->strings["Collection not found."] = "Collection introuvable."; +$a->strings["Collection is empty."] = "Collection vide."; +$a->strings["Collection: %s"] = "Collection : %s"; +$a->strings["Connection: %s"] = "Relation : %s"; +$a->strings["Connection not found."] = "Relation introuvable."; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "Un groupe supprimé portant ce nom a été ressuscité. Les permissions liées aux éléments existants peuvent s'appliquer au groupe et aux membres futurs. Si ce n'est pas ce que vous attendiez, merci de recréer un nouveau groupe avec un nom différent."; +$a->strings["Default privacy group for new contacts"] = "Groupe de confidentialité par défaut pour les nouveaux contacts"; +$a->strings["All Channels"] = "Tous canaux"; +$a->strings["edit"] = "éditer"; +$a->strings["Collections"] = "Collections"; +$a->strings["Edit collection"] = "Éditer collection"; +$a->strings["Create a new collection"] = "Créer une nouvelle collection"; +$a->strings["Channels not in any collection"] = "Ces canaux ne sont dans aucune collection"; +$a->strings["add"] = "ajouter"; +$a->strings["Unable to obtain identity information from database"] = "Impossible d'obtenir les données d'identité depuis la base de données"; +$a->strings["Empty name"] = "Nom vide"; +$a->strings["Name too long"] = "Nom trop long"; +$a->strings["No account identifier"] = "Pas d'identifiant de compte"; +$a->strings["Nickname is required."] = "Un surnom est requis."; +$a->strings["Reserved nickname. Please choose another."] = "Pseudonyme réservé. Merci d'en choisir un autre."; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = "Le surnom contient des caractères interdits, ou est déjà pris sur ce site."; +$a->strings["Unable to retrieve created identity"] = "Impossible de récupérer l'identité créée"; +$a->strings["Default Profile"] = "Profil par défaut"; +$a->strings["Friends"] = "Amis"; +$a->strings["Requested channel is not available."] = "Canal demandé non-disponible."; +$a->strings["Requested profile is not available."] = "Profil demandé inaccessible."; +$a->strings["Connect"] = "Ajouter"; +$a->strings["Change profile photo"] = "Changer la photo du profil"; +$a->strings["Profiles"] = "Profils"; +$a->strings["Manage/edit profiles"] = "Gérer/éditer les profils"; +$a->strings["Create New Profile"] = "Créer un nouveau profil"; +$a->strings["Profile Image"] = "Image du profil"; +$a->strings["visible to everybody"] = "visible pour tous"; +$a->strings["Edit visibility"] = "Éditer la visibilité"; +$a->strings["Gender:"] = "Sexe :"; +$a->strings["Status:"] = "État :"; +$a->strings["Homepage:"] = "Site web :"; +$a->strings["Online Now"] = "Connecté"; +$a->strings["g A l F d"] = "H:i l d F"; +$a->strings["F d"] = "d F"; +$a->strings["[today]"] = "[aujourd'hui]"; +$a->strings["Birthday Reminders"] = "Rappels d'anniversaires"; +$a->strings["Birthdays this week:"] = "Anniversaires cette semaine :"; +$a->strings["[No description]"] = "[Pas de description]"; +$a->strings["Event Reminders"] = "Rappels d'événements"; +$a->strings["Events this week:"] = "Événements cette semaine :"; +$a->strings["Full Name:"] = "Nom complet :"; +$a->strings["Like this channel"] = "J'aime ce canal"; +$a->strings["j F, Y"] = "j F Y"; +$a->strings["j F"] = "j F"; +$a->strings["Birthday:"] = "Date de naissance :"; +$a->strings["Age:"] = "Age :"; +$a->strings["for %1\$d %2\$s"] = "depuis %1\$d %2\$s"; +$a->strings["Sexual Preference:"] = "Orientation sexuelle :"; +$a->strings["Hometown:"] = "Ville natale :"; +$a->strings["Tags:"] = "Étiquettes :"; +$a->strings["Political Views:"] = "Opinions politiques :"; +$a->strings["Religion:"] = "Religion :"; +$a->strings["About:"] = "À propos :"; +$a->strings["Hobbies/Interests:"] = "Occupations/Centres d'intérêt :"; +$a->strings["Likes:"] = "Aime :"; +$a->strings["Dislikes:"] = "N'aime pas :"; +$a->strings["Contact information and Social Networks:"] = "Coordonnées et réseaux sociaux :"; +$a->strings["My other channels:"] = "Mes autres canaux :"; +$a->strings["Musical interests:"] = "Goûts musicaux :"; +$a->strings["Books, literature:"] = "Lectures, goûts littéraires :"; +$a->strings["Television:"] = "Télévision :"; +$a->strings["Film/dance/culture/entertainment:"] = "Cinéma/danse/culture/divertissement :"; +$a->strings["Love/Romance:"] = "Vie sentimentale/amoureuse :"; +$a->strings["Work/employment:"] = "Travail :"; +$a->strings["School/education:"] = "Cursus :"; +$a->strings["Like this thing"] = "J'aime ceci"; +$a->strings["view full size"] = "pleine taille"; +$a->strings["Image/photo"] = "Image/photo"; +$a->strings["Encrypted content"] = "Contenu chiffré"; +$a->strings["QR code"] = "code QR"; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s a écrit %2\$s qui suit %3\$s"; +$a->strings["post"] = "l'article"; +$a->strings["$1 wrote:"] = "$1 a écrit :"; +$a->strings["No recipient provided."] = "Pas de destinataire."; +$a->strings["[no subject]"] = "[sans objet]"; +$a->strings["Unable to determine sender."] = "Impossible de déterminer l'émetteur."; +$a->strings["Stored post could not be verified."] = "Le message stocké n'a pas pu être vérifié."; +$a->strings["System"] = "Système"; +$a->strings["Create Personal App"] = "Créer Votre Application"; +$a->strings["Edit Personal App"] = "Éditer Votre Application"; +$a->strings["Ignore/Hide"] = "Ignorer/Cacher"; +$a->strings["Suggestions"] = "Suggestion"; +$a->strings["See more..."] = "Voir plus..."; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = "Vous avez %1$.0f des %2$.0f relations autorisées."; +$a->strings["Add New Connection"] = "Ajouter une nouvelle relation"; +$a->strings["Enter the channel address"] = "Adresse du canal"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Exemple : bob@exemple.com, http://exemple.com/barbara"; +$a->strings["Notes"] = "Notes"; +$a->strings["Remove term"] = "Retirer le terme"; +$a->strings["Archives"] = "Archives"; +$a->strings["Refresh"] = "Actualiser"; +$a->strings["Me"] = "Moi"; +$a->strings["Best Friends"] = "Mes meilleurs amis"; +$a->strings["Co-workers"] = "Mes collègues"; +$a->strings["Former Friends"] = "Mes anciens amis"; +$a->strings["Acquaintances"] = "Mes connaissances"; +$a->strings["Everybody"] = "Tout le monde"; +$a->strings["Account settings"] = "Réglages du Compte"; +$a->strings["Channel settings"] = "Réglages du Canal"; +$a->strings["Additional features"] = "Fonctions supplémentaires"; +$a->strings["Feature settings"] = "Extensions"; +$a->strings["Display settings"] = "Réglages d'affichage"; +$a->strings["Connected apps"] = "Applications connectées"; +$a->strings["Export channel"] = "Exporter le canal"; +$a->strings["Automatic Permissions (Advanced)"] = "Permissions automatiques (avancé)"; +$a->strings["Premium Channel Settings"] = "Canal VIP"; +$a->strings["Check Mail"] = "Vérifier le courrier"; +$a->strings["Chat Rooms"] = "Salons de clavardage"; +$a->strings["Bookmarked Chatrooms"] = "Salons favoris"; +$a->strings["Suggested Chatrooms"] = "Salons suggérés"; +$a->strings["Save to Folder"] = "Sauvegarder dans le dossier"; +$a->strings["View all"] = "Voir tout"; +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "Je déteste", + 1 => "Je déteste", +); +$a->strings["Add Star"] = "Ajouter Étoile"; +$a->strings["Remove Star"] = "Supprimer Étoile"; +$a->strings["Toggle Star Status"] = "Changer le Statut des Étoiles"; +$a->strings["starred"] = "mis en avant"; +$a->strings["Add Tag"] = "Ajouter une balise"; +$a->strings["I like this (toggle)"] = "J'aime (oui/non)"; +$a->strings["I don't like this (toggle)"] = "Je déteste (oui/non)"; +$a->strings["Share This"] = "Partager"; +$a->strings["share"] = "partager"; +$a->strings["View %s's profile - %s"] = "Voir le profil de %s - %s"; +$a->strings["to"] = "à"; +$a->strings["via"] = "via"; +$a->strings["Wall-to-Wall"] = "Mur-mur"; +$a->strings["via Wall-To-Wall:"] = "par Mur-mur :"; +$a->strings["Save Bookmarks"] = "Enregistrer les favoris"; +$a->strings["Add to Calendar"] = "Ajouter au Calendrier"; +$a->strings["__ctx:noun__ Likes"] = "Aimes"; +$a->strings["__ctx:noun__ Dislikes"] = "Détestes"; +$a->strings["%d comment"] = array( + 0 => "%d commentaire", + 1 => "%d commentaires", +); +$a->strings["[+] show all"] = "[+] voir plus"; +$a->strings["This is you"] = "C'est vous"; +$a->strings["Comment"] = "Commenter"; +$a->strings["Submit"] = "Envoyer"; +$a->strings["Bold"] = "Gras"; +$a->strings["Italic"] = "Italique"; +$a->strings["Underline"] = "Souligné"; +$a->strings["Quote"] = "Citation"; +$a->strings["Code"] = "Code"; +$a->strings["Image"] = "Image"; +$a->strings["Link"] = "Lien/URL"; +$a->strings["Video"] = "Vidéo"; +$a->strings["Delete this item?"] = "Supprimer cet élément?"; +$a->strings["[-] show less"] = "[-] montrer moins"; +$a->strings["[+] expand"] = "[+] déplier"; +$a->strings["[-] collapse"] = "[-] replier"; +$a->strings["Password too short"] = "Mot de passe trop court"; +$a->strings["Passwords do not match"] = "Les mots de passe ne correspondent pas"; +$a->strings["everybody"] = "tout le monde"; +$a->strings["Secret Passphrase"] = "Phrase de passe secrète"; +$a->strings["Passphrase hint"] = "Indice pour la phrase de passe"; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = "Note : Les permissions ont changé, mais n'ont pas encore été soumises."; +$a->strings["close all"] = "fermer tout"; +$a->strings["timeago.prefixAgo"] = "Il y a"; +$a->strings["timeago.prefixFromNow"] = "timeago.prefixFromNow"; +$a->strings["ago"] = " "; +$a->strings["from now"] = "de maintenant"; +$a->strings["less than a minute"] = "moins d'une minute"; +$a->strings["about a minute"] = "environ une minute"; +$a->strings["%d minutes"] = "%d minutes"; +$a->strings["about an hour"] = "environ une heure"; +$a->strings["about %d hours"] = "environ %d heures"; +$a->strings["a day"] = "un jour"; +$a->strings["%d days"] = "%d jours"; +$a->strings["about a month"] = "environ un mois"; +$a->strings["%d months"] = "%d mois"; +$a->strings["about a year"] = "environ un an"; +$a->strings["%d years"] = "%d années"; +$a->strings[" "] = " "; +$a->strings["timeago.numbers"] = "timeago.numbers"; +$a->strings["New window"] = "Nouvelle fenêtre"; +$a->strings["Open the selected location in a different window or browser tab"] = "Ouvrir l'emplacement dans une fenêtre (ou un onglet) différent"; +$a->strings["Male"] = "Masculin"; +$a->strings["Female"] = "Féminin"; +$a->strings["Currently Male"] = "Actuellement masculin"; +$a->strings["Currently Female"] = "Actuellement féminin"; +$a->strings["Mostly Male"] = "Surtout masculin"; +$a->strings["Mostly Female"] = "Surtout féminin"; +$a->strings["Transgender"] = "Transgenre"; +$a->strings["Intersex"] = "Intersexuel"; +$a->strings["Transsexual"] = "Transsexuel"; +$a->strings["Hermaphrodite"] = "Hermaphrodite"; +$a->strings["Neuter"] = "Neutre"; +$a->strings["Non-specific"] = "Rien de spécifique"; +$a->strings["Other"] = "Autre"; +$a->strings["Undecided"] = "Indécis"; +$a->strings["Males"] = "Hommes"; +$a->strings["Females"] = "Femmes"; +$a->strings["Gay"] = "Gay"; +$a->strings["Lesbian"] = "Lesbienne"; +$a->strings["No Preference"] = "Sans préférence"; +$a->strings["Bisexual"] = "Bisexuel"; +$a->strings["Autosexual"] = "Autosexuel"; +$a->strings["Abstinent"] = "Abstinent"; +$a->strings["Virgin"] = "Vierge"; +$a->strings["Deviant"] = "Déviant"; +$a->strings["Fetish"] = "Fétichiste"; +$a->strings["Oodles"] = "Une floppée"; +$a->strings["Nonsexual"] = "Nonsexuel"; +$a->strings["Single"] = "Célibataire"; +$a->strings["Lonely"] = "Solitaire"; +$a->strings["Available"] = "Disponible"; +$a->strings["Unavailable"] = "Indisponible"; +$a->strings["Has crush"] = "A un béguin"; +$a->strings["Infatuated"] = "Amoureux transi"; +$a->strings["Dating"] = "Sort avec quelqu'un"; +$a->strings["Unfaithful"] = "Infidèle"; +$a->strings["Sex Addict"] = "Accro au sexe"; +$a->strings["Friends/Benefits"] = "Amis avec bénéfices"; +$a->strings["Casual"] = "Sans engagement"; +$a->strings["Engaged"] = "Fiancé(e)"; +$a->strings["Married"] = "Marié(e)"; +$a->strings["Imaginarily married"] = "Marié(e) dans ses rêves"; +$a->strings["Partners"] = "Partenaires"; +$a->strings["Cohabiting"] = "En cohabitation"; +$a->strings["Common law"] = "Conjoints de fait"; +$a->strings["Happy"] = "Heureux"; +$a->strings["Not looking"] = "Pas en recherche"; +$a->strings["Swinger"] = "Infidèle"; +$a->strings["Betrayed"] = "Trahi(e)"; +$a->strings["Separated"] = "Séparé(e)"; +$a->strings["Unstable"] = "Instable"; +$a->strings["Divorced"] = "Divorcé(e)"; +$a->strings["Imaginarily divorced"] = "Divorcé(e) dans ses rêves"; +$a->strings["Widowed"] = "Veuf/veuve"; +$a->strings["Uncertain"] = "Incertain"; +$a->strings["It's complicated"] = "C'est compliqué"; +$a->strings["Don't care"] = "S'en fiche"; +$a->strings["Ask me"] = "Me demander"; +$a->strings["Logged out."] = "Deconnecté."; +$a->strings["Failed authentication"] = "Échec de l'authentification"; +$a->strings["Login failed."] = "Échec de la connexion."; +$a->strings["Can view my normal stream and posts"] = "Peut voir les publications sur mon canal et ses partages."; +$a->strings["Can view my default channel profile"] = "Peut voir le profil du canal par défaut."; +$a->strings["Can view my photo albums"] = "Peut voir mon album photos"; +$a->strings["Can view my connections"] = "Peut voir mes connections"; +$a->strings["Can view my file storage"] = "Peut voir mes fichiers en partage"; +$a->strings["Can view my webpages"] = "Peut voir mes sites-web"; +$a->strings["Can send me their channel stream and posts"] = "Peut m'envoyer le flux et les publications de leur canal"; +$a->strings["Can post on my channel page (\"wall\")"] = "Peut poster sur la page de mon canal (\"mur\")"; +$a->strings["Can comment on or like my posts"] = "Peuvent commenter et/ou aimer mes publications"; +$a->strings["Can send me private mail messages"] = "Peut m'envoyer des messages privés"; +$a->strings["Can post photos to my photo albums"] = "Peut ajouter des photos à mes albums"; +$a->strings["Can like/dislike stuff"] = "Peuvent aimer/détester"; +$a->strings["Profiles and things other than posts/comments"] = "Profils et autres excluant les publications/commentaires."; +$a->strings["Can forward to all my channel contacts via post @mentions"] = "Peut faire suivre à tous les contacts du mon canal via @truc"; +$a->strings["Advanced - useful for creating group forum channels"] = "Avancé - utile seulement pour les canaux de type \"forum/groupe\""; +$a->strings["Can chat with me (when available)"] = "Peut discuter avec moi (sous réserve de disponibilité)"; +$a->strings["Can write to my file storage"] = "Peut écrire dans mon partage de fichiers"; +$a->strings["Can edit my webpages"] = "Peut modifier mes sites-web"; +$a->strings["Can source my public posts in derived channels"] = "Peut rediriger mes publications publiques dans des canaux dérivés"; +$a->strings["Somewhat advanced - very useful in open communities"] = "Plutôt avancé - très utile dans les communautés ouvertes"; +$a->strings["Can administer my channel resources"] = "Peut administrer les ressources de mon canal"; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Très avancé. Ne pas toucher, sauf si vous savez VRAIMENT ce que vous faites"; +$a->strings["Set your current mood and tell your friends"] = "Indiquez votre humeur du moment à vos amis"; +$a->strings["Menu not found."] = "Menu introuvable."; +$a->strings["Menu element updated."] = "Entrée de menu mis à jour."; +$a->strings["Unable to update menu element."] = "Impossible de mettre l'entrée de menu à jour."; +$a->strings["Menu element added."] = "Entrée de menu ajouté."; +$a->strings["Unable to add menu element."] = "Impossible d'ajouter l'entrée de menu."; +$a->strings["Not found."] = "Introuvable."; +$a->strings["Manage Menu Elements"] = "Gérer les entrées de menu"; +$a->strings["Edit menu"] = "Éditer le menu"; +$a->strings["Edit element"] = "Éditer l'entrée"; +$a->strings["Drop element"] = "Supprimer l'entrée"; +$a->strings["New element"] = "Nouvelle entrée"; +$a->strings["Edit this menu container"] = "Éditer ce bloc de menu"; +$a->strings["Add menu element"] = "Ajouter une entrée au menu"; +$a->strings["Delete this menu item"] = "Supprimer cet entrée du menu"; +$a->strings["Edit this menu item"] = "Éditer cette entrée du menu"; +$a->strings["New Menu Element"] = "Nouvelle entrée de menu"; +$a->strings["Menu Item Permissions"] = "Permissions de l'entrée de menu"; +$a->strings["(click to open/close)"] = "(cliquer pour ouvrir/fermer)"; +$a->strings["Link text"] = "Texte du lien"; +$a->strings["URL of link"] = "URL du lien"; +$a->strings["Use Red magic-auth if available"] = "Utiliser l'authentification magique, lorsque disponible"; +$a->strings["Open link in new window"] = "Ouvrir le lien dans une nouvelle fenêtre"; +$a->strings["Order in list"] = "Ordre dans la liste"; +$a->strings["Higher numbers will sink to bottom of listing"] = "Les nombres les plus élevés seront descendus au bas de la liste"; +$a->strings["Menu item not found."] = "Entrée de menu introuvable."; +$a->strings["Menu item deleted."] = "Entrée de menu supprimée."; +$a->strings["Menu item could not be deleted."] = "Impossible de supprimer l'entrée de menu."; +$a->strings["Edit Menu Element"] = "Éditer l'entrée de menu"; +$a->strings["Modify"] = "Modifier"; +$a->strings["sent you a private message"] = "vous a envoyé un message privé"; +$a->strings["added your channel"] = "a ajouté votre canal"; +$a->strings["posted an event"] = "a publié un événement"; +$a->strings["network"] = "réseau"; +$a->strings["Name is required"] = "Le nom est requis"; +$a->strings["Key and Secret are required"] = "Clef et secret sont requis"; +$a->strings["Passwords do not match. Password unchanged."] = "Les deux saisies du mot de passe ne correspondent pas. Il n'a donc pas été changé."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Le mot de passe ne peut pas être vide. Il n'a donc pas été changé."; +$a->strings["Password changed."] = "Le mot de passe a été changé."; +$a->strings["Password update failed. Please try again."] = "La mise à jour du mot de passe a échoué. Merci de recommencer."; +$a->strings["Not valid email."] = "Adresse de courriel non-valide."; +$a->strings["Protected email address. Cannot change to that email."] = "Adresse de courriel protégée. Impossible de l'utiliser."; +$a->strings["System failure storing new email. Please try again."] = "Défaillance système lors du stockage de la nouvelle adresse de courriel. Merci de ré-essayer."; +$a->strings["Settings updated."] = "Réglages sauvegardés."; +$a->strings["Add application"] = "Ajouter une application"; +$a->strings["Name of application"] = "Nom de l'application"; +$a->strings["Consumer Key"] = "Clef de consommateur"; +$a->strings["Automatically generated - change if desired. Max length 20"] = "Généré automatiquement - à changer si besoin. Longueur maximale 20 caractères."; +$a->strings["Consumer Secret"] = "Secret de consommateur"; +$a->strings["Redirect"] = "Redirection"; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = "URI de redirection - laissez blanc, sauf si l'application a demandé autrement"; +$a->strings["Icon url"] = "URL de l'icône"; +$a->strings["Optional"] = "Facultatif"; +$a->strings["You can't edit this application."] = "Vous ne pouvez pas éditer cette application."; +$a->strings["Connected Apps"] = "Applications connectées"; +$a->strings["Client key starts with"] = "La clef partagée commence par"; +$a->strings["No name"] = "Sans nom"; +$a->strings["Remove authorization"] = "Révoquer l'autorisation"; +$a->strings["No feature settings configured"] = "Pas de fonctionnalité à configurer"; +$a->strings["Feature Settings"] = "Extensions"; +$a->strings["Account Settings"] = "Compte"; +$a->strings["Password Settings"] = "Mot de passe"; +$a->strings["New Password:"] = "Nouveau mot de passe :"; +$a->strings["Confirm:"] = "Confirmation :"; +$a->strings["Leave password fields blank unless changing"] = "Laissez les mots de passe vides si vous ne voulez pas les modifier"; +$a->strings["Email Address:"] = "Adresse de courriel :"; +$a->strings["Remove Account"] = "Supprimer le compte"; +$a->strings["Warning: This action is permanent and cannot be reversed."] = "Attention : cette action est permanente et irréversible."; +$a->strings["Off"] = "Inactif"; +$a->strings["On"] = "Actif"; +$a->strings["Additional Features"] = "Fonctionnalités additionnelles"; +$a->strings["Connector Settings"] = "Connecteurs"; +$a->strings["No special theme for mobile devices"] = "Pas de thème spécifique aux périphériques mobiles"; +$a->strings["%s - (Experimental)"] = "%s - (Expérimental)"; +$a->strings["Display Settings"] = "Affichage"; +$a->strings["Display Theme:"] = "Thème :"; +$a->strings["Mobile Theme:"] = "Thème mobile :"; +$a->strings["Enable user zoom on mobile devices"] = "Permettre à l'utilisateur d'un mobile d'agrandir le contenu"; +$a->strings["Update browser every xx seconds"] = "Rafraîchir le navigateur toutes les xx secondes"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Minimum 10 secondes, pas de maximum"; +$a->strings["Maximum number of conversations to load at any time:"] = "Nombre maximal de conversations pouvant être chargées en même temps :"; +$a->strings["Maximum of 100 items"] = "100 éléments au maximum"; +$a->strings["Don't show emoticons"] = "Ne pas montrer les frimousses/émoticones"; +$a->strings["System Page Layout Editor - (advanced)"] = "Agencements des pages système - (avancé)"; +$a->strings["Nobody except yourself"] = "Personne sauf vous"; +$a->strings["Only those you specifically allow"] = "Seulement ceux que vous autorisez spécifiquement"; +$a->strings["Approved connections"] = "Contacts Approuvés"; +$a->strings["Any connections"] = "Tous les contacts"; +$a->strings["Anybody on this website"] = "Tous les utilisateurs du hub"; +$a->strings["Anybody in this network"] = "Tous les utilisateurs sur ce réseau"; +$a->strings["Anybody authenticated"] = "Tous les utilisateurs authentifiés"; +$a->strings["Anybody on the internet"] = "Tous les utilisateurs d'Internet"; +$a->strings["Publish your default profile in the network directory"] = "Publier votre profil par défaut dans l'annuaire du réseau"; +$a->strings["No"] = "Non"; +$a->strings["Yes"] = "Oui"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Nous autoriser à vous suggérer comme relation potentielle aux nouveaux membres?"; +$a->strings["or"] = "ou"; +$a->strings["Your channel address is"] = "Voici l'adresse de votre canal"; +$a->strings["Channel Settings"] = "Canal"; +$a->strings["Basic Settings"] = "Basique"; +$a->strings["Your Timezone:"] = "Fuseau horaire :"; +$a->strings["Default Post Location:"] = "Emplacement géographique par défaut :"; +$a->strings["Geographical location to display on your posts"] = "Emplacement géographique à afficher sur vos publications"; +$a->strings["Use Browser Location:"] = "Utiliser la géolocalisation fournie par le navigateur :"; +$a->strings["Adult Content"] = "Contenu \"adulte\""; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = "Ce canal publie plus ou moins fréquemment du contenu pour adultes. (Merci d'indiquer tout contenu pour adulte ou potentiellement choquant avec l'étiquette #NSFW - Not Safe For Work)"; +$a->strings["Security and Privacy Settings"] = "Réglages de sécurité et vie privée"; +$a->strings["Hide my online presence"] = "Cacher ma présence en ligne"; +$a->strings["Prevents displaying in your profile that you are online"] = "Cacher votre statut (en ligne/hors ligne) sur votre profil"; +$a->strings["Simple Privacy Settings:"] = "Réglages simples :"; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = "Très public - extrèmement permissif (à n'utiliser qu'en connaissance de cause)"; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = "Classique - public par défaut, privé en cas de besoin (comparable dans le principe aux réseaux sociaux centralisés, avec un mode privé plus efficace)"; +$a->strings["Private - default private, never open or public"] = "Privé - privé par défaut, jamais ouvert ni public"; +$a->strings["Blocked - default blocked to/from everybody"] = "Bloqué - par défaut, bloqué de/vers tout le monde"; +$a->strings["Allow others to tag your posts"] = "Autoriser les autres à \"étiqueter\" vos publications"; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = "Souvent utilisé par la communauté pour distinguer le contenu innaproprié"; +$a->strings["Advanced Privacy Settings"] = "Réglages avancés"; +$a->strings["Expire other channel content after this many days"] = "Faire expirer le contenu des autres canaux après n jours"; +$a->strings["0 or blank prevents expiration"] = "0, ou vide, pour ne pas faire expirer"; +$a->strings["Maximum Friend Requests/Day:"] = "Nombre maximum de mises en relation par jour :"; +$a->strings["May reduce spam activity"] = "Contribue à réduire l'impact des indésirables"; +$a->strings["Default Post Permissions"] = "Permissions par défaut des publications"; +$a->strings["Maximum private messages per day from unknown people:"] = "Nombre maximum de messages privés émanant d'inconnus, par jour :"; +$a->strings["Useful to reduce spamming"] = "Utile pour réduire les indésirables"; +$a->strings["Notification Settings"] = "Notifications"; +$a->strings["By default post a status message when:"] = "Par défaut, publier un statut quand:"; +$a->strings["accepting a friend request"] = "vous acceptez une mise en relation"; +$a->strings["joining a forum/community"] = "vous joignez un forum ou à une communauté"; +$a->strings["making an interesting profile change"] = "vous faites une modification intéressante de votre profil"; +$a->strings["Send a notification email when:"] = "Envoyer un courriel de notification quand :"; +$a->strings["You receive a connection request"] = "Vous recevez une demande de mise en relation"; +$a->strings["Your connections are confirmed"] = "Vous relations sont confirmées"; +$a->strings["Someone writes on your profile wall"] = "Quelqu'un a écrit sur votre mur"; +$a->strings["Someone writes a followup comment"] = "Quelqu'un a commenté sur vos publications"; +$a->strings["You receive a private message"] = "Vous recevez un message privé"; +$a->strings["You receive a friend suggestion"] = "Vous recevez une suggestion d'amitié/relation"; +$a->strings["You are tagged in a post"] = "Vous êtes étiqueté dans une publication"; +$a->strings["You are poked/prodded/etc. in a post"] = "Vous êtes cogné/encouragé/etc. dans une publication"; +$a->strings["Advanced Account/Page Type Settings"] = "Type de page/Compte (avancé)"; +$a->strings["Change the behaviour of this account for special situations"] = "Modifie le comportement de ce compte pour certains cas particuliers"; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = "Mode expert requis (Réglages > Fonctions supplémentaires) svp ajuster!"; +$a->strings["Miscellaneous Settings"] = "Divers"; +$a->strings["Personal menu to display in your channel pages"] = "Menu personnel tel qu'il apparaîtra sur les pages de votre canal"; +$a->strings["Remove this channel"] = "Supprimer ce canal"; +$a->strings["Poke/Prod"] = "Cogner/Encourager"; +$a->strings["poke, prod or do other things to somebody"] = "Cogner, encourager, et autres choses à faire à quelqu'un"; +$a->strings["Recipient"] = "Destinataire"; +$a->strings["Choose what you wish to do to recipient"] = "Choisir quoi lui faire"; +$a->strings["Make this post private"] = "Rendre cette contribution privée"; +$a->strings["Authorize application connection"] = "Autoriser l'application à se connecter"; +$a->strings["Return to your app and insert this Securty Code:"] = "Merci de retourner vers votre application, et d'y insérer ce Code de Sécurité :"; +$a->strings["Please login to continue."] = "Merci de vous connecter pour continuer."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Voulez-vous autoriser cette application à accéder à vos publications et contacts, et/ou à publier en votre nom?"; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "Authentification magique bloquée. Vous êtes connecté sur ce site localement. Merci de vous en déconnecter et réessayer."; +$a->strings["Welcome %s. Remote authentication successful."] = "Bienvenue %s. L'authentification magique a fonctionné."; +$a->strings["Item not available."] = "Élément indisponible."; +$a->strings["Fetching URL returns error: %1\$s"] = "Récupération d'URL échouée : %1\$s"; +$a->strings["Invalid item."] = "Élément invalide."; +$a->strings["Channel not found."] = "Canal introuvable."; +$a->strings["Page not found."] = "Page introuvable."; +$a->strings["Image uploaded but image cropping failed."] = "L'image a été téléversée, mais le recadrage a échoué."; +$a->strings["Image resize failed."] = "Le redimensionnement de l'image a échoué."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Shirt-rechargez votre page, ou videz le cache du navigateur si la photo ne s'affiche pas immédiatement."; +$a->strings["Image exceeds size limit of %d"] = "L'image dépasse la taille limite de %d"; +$a->strings["Unable to process image."] = "Impossible de traîter l'image."; +$a->strings["Photo not available."] = "Photo inaccessible."; +$a->strings["Upload File:"] = "Fichier :"; +$a->strings["Select a profile:"] = "Choisir un profil :"; +$a->strings["Upload Profile Photo"] = "Téléverser une photo de profil"; +$a->strings["skip this step"] = "passer cette étape"; +$a->strings["select a photo from your photo albums"] = "choisir une photo dans vos albums"; +$a->strings["Crop Image"] = "Recadrer l'image"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Merci d'ajuster le cadre pour une visualisation optimale."; +$a->strings["Done Editing"] = "J'ai terminé"; +$a->strings["Image uploaded successfully."] = "Image téléversée avec succès."; +$a->strings["Image upload failed."] = "Le téléversement a échoué."; +$a->strings["Image size reduction [%s] failed."] = "La réduction de taille [%s] a échoué."; +$a->strings["Block Name"] = "Nom du Bloc"; +$a->strings["Profile not found."] = "Profil introuvable."; +$a->strings["Profile deleted."] = "Profil supprimé."; +$a->strings["Profile-"] = "Profil-"; +$a->strings["New profile created."] = "Nouveau profil créé."; +$a->strings["Profile unavailable to clone."] = "Profil impossible à cloner."; +$a->strings["Profile unavailable to export."] = "Impossible d'exporter le profil."; +$a->strings["Profile Name is required."] = "Le nom du profil est requis."; +$a->strings["Marital Status"] = "Statut marital"; +$a->strings["Romantic Partner"] = "Partenaire"; +$a->strings["Likes"] = "Aime"; +$a->strings["Dislikes"] = "Déteste"; +$a->strings["Work/Employment"] = "Travail/Occupation"; +$a->strings["Religion"] = "Religion/Croyance"; +$a->strings["Political Views"] = "Opinions politiques"; +$a->strings["Gender"] = "Sexe/Genre"; +$a->strings["Sexual Preference"] = "Préférence sexuelle"; +$a->strings["Homepage"] = "Site Internet"; +$a->strings["Interests"] = "Centres d'intérêt"; +$a->strings["Address"] = "Adresse"; +$a->strings["Location"] = "Emplacement"; +$a->strings["Profile updated."] = "Profil mis à jour."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "Cacher vos contacts/relations aux visiteurs de ce profil?"; +$a->strings["Edit Profile Details"] = "Éditer les détails du profil"; +$a->strings["View this profile"] = "Voir le profil"; +$a->strings["Change Profile Photo"] = "Changer la photo du profil"; +$a->strings["Create a new profile using these settings"] = "Créer un nouveau profil avec ces réglages"; +$a->strings["Clone this profile"] = "Cloner le profil"; +$a->strings["Delete this profile"] = "Supprimer le profil"; +$a->strings["Import profile from file"] = "Importer le profil à partir d'un fichier"; +$a->strings["Export profile to file"] = "Exporter le profil vers un fichier."; +$a->strings["Profile Name:"] = "Nom du profil :"; +$a->strings["Your Full Name:"] = "Votre nom complet :"; +$a->strings["Title/Description:"] = "Titre/description :"; +$a->strings["Your Gender:"] = "Sexe/Genre :"; +$a->strings["Birthday (%s):"] = "Date de naissance (%s) :"; +$a->strings["Street Address:"] = "Adresse postale :"; +$a->strings["Locality/City:"] = "Ville/Localité :"; +$a->strings["Postal/Zip Code:"] = "Code postal :"; +$a->strings["Country:"] = "Pays :"; +$a->strings["Region/State:"] = "Région/Province/État :"; +$a->strings[" Marital Status:"] = "Statut marital :"; +$a->strings["Who: (if applicable)"] = "Avec : (si pertinent)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Exemples : cathy123, Cathy Williams, cathy@exemple.com"; +$a->strings["Since [date]:"] = "Depuis [date] :"; +$a->strings["Homepage URL:"] = "URL de mon site Internet :"; +$a->strings["Religious Views:"] = "Opinions religieuses :"; +$a->strings["Keywords:"] = "Mots-clefs :"; +$a->strings["Example: fishing photography software"] = "Exemple : escrime photographie modélisme"; +$a->strings["Used in directory listings"] = "Utilisé pour le référencement dans l'annuaire"; +$a->strings["Tell us about yourself..."] = "Parlez nous de vous..."; +$a->strings["Hobbies/Interests"] = "Loisirs/Centres d'intêret"; +$a->strings["Contact information and Social Networks"] = "Coordonnées et réseaux sociaux"; +$a->strings["My other channels"] = "Mes autres canaux"; +$a->strings["Musical interests"] = "Goûts musicaux"; +$a->strings["Books, literature"] = "Littérature"; +$a->strings["Television"] = "Télévision"; +$a->strings["Film/dance/culture/entertainment"] = "Cinéma/Danse/Culture/Divertissement"; +$a->strings["Love/romance"] = "Amour/Romance"; +$a->strings["Work/employment"] = "Travail/Occupation"; +$a->strings["School/education"] = "Études"; +$a->strings["This is your default profile."] = "Voilà votre profil par défault."; +$a->strings["Age: "] = "Age :"; +$a->strings["Edit/Manage Profiles"] = "Éditer/gérer les profils"; +$a->strings["Add profile things"] = "Ajouter des choses de profil"; +$a->strings["Include desirable objects in your profile"] = "Incluez des objets souhaitables dans votre profil"; +$a->strings["Bookmark added"] = "Favoris ajouté"; +$a->strings["My Bookmarks"] = "Mes Favoris"; +$a->strings["My Connections Bookmarks"] = "Favoris de mes relations"; +$a->strings["Invalid profile identifier."] = "Identifiant de profil invalide."; +$a->strings["Profile Visibility Editor"] = "Éditeur de visibilité de profil"; +$a->strings["Click on a contact to add or remove."] = "Cliquez sur un contact pour l'ajouter ou le retirer."; +$a->strings["Visible To"] = "Visible par"; +$a->strings["All Connections"] = "Toutes les relations"; +$a->strings["Public Sites"] = "Sites publics"; +$a->strings["The listed sites allow public registration into the Hubzilla. All sites in the matrix are interlinked so membership on any of them conveys membership in the matrix as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = "Les sites listés autorisent l'inscription pour tous. Tous sont liés entre eux, de manière à ce qu'un compte sur un seul d'entre eux soit valable sur l'ensemble de la matrice. Certains sites peuvent demander des frais de souscriptions, ou fournir des forfaits ajustés. Le lien \"fournisseur\" peut vous donner des détails supplémentaires."; +$a->strings["Site URL"] = "URL du site"; +$a->strings["Access Type"] = "Type d'accès"; +$a->strings["Registration Policy"] = "Politique d'inscription"; +$a->strings["You must be logged in to see this page."] = "Vous devez vous connecter pour voir cette page."; +$a->strings["Insufficient permissions. Request redirected to profile page."] = "Permissions insuffisantes. Demande redirigée à la page du profil."; +$a->strings["Select a bookmark folder"] = "Choisir un dossier de favoris"; +$a->strings["Save Bookmark"] = "Sauver le favoris"; +$a->strings["URL of bookmark"] = "URL du favoris"; +$a->strings["Description"] = "Description"; +$a->strings["Or enter new bookmark folder name"] = "Ou entrez le nom d'un nouveau dossier"; +$a->strings["Room not found"] = "Salon introuvable"; +$a->strings["Leave Room"] = "Quitter le salon"; +$a->strings["Delete This Room"] = "Supprimer le salon"; +$a->strings["I am away right now"] = "Je suis momentanément absent"; +$a->strings["I am online"] = "Je suis en ligne"; +$a->strings["Bookmark this room"] = "Marquer ce salon"; +$a->strings["New Chatroom"] = "Nouveau salon"; +$a->strings["Chatroom Name"] = "Nom du salon"; +$a->strings["%1\$s's Chatrooms"] = "Salons de %1\$s"; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "Nombre d'inscriptions quotidiennes dépassé. Merci de recommencer demain."; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Merci d'indiquer votre adhésion aux Règles du Service. L'inscription a échoué."; +$a->strings["Passwords do not match."] = "Les mots de passe ne concordent pas."; +$a->strings["Registration successful. Please check your email for validation instructions."] = "Inscription réussie. Merci de vérifier vos courriels pour valider votre compte."; +$a->strings["Your registration is pending approval by the site owner."] = "Votre inscription est en attente de l'approbation d'un administrateur."; +$a->strings["Your registration can not be processed."] = "Votre inscription ne peut être traîtée."; +$a->strings["Registration on this site/hub is by approval only."] = "L'inscription sur cette instance/ce site est soumise à une modération."; +$a->strings["Register at another affiliated site/hub"] = "S'inscrire sur un site/hub affilié"; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Ce site a dépassé le nombre de création de compte autorisé par jour. Merci de recommencer demain."; +$a->strings["Terms of Service"] = "Règles du Service"; +$a->strings["I accept the %s for this website"] = "J'accepte %s de ce site"; +$a->strings["I am over 13 years of age and accept the %s for this website"] = "J'ai plus de 13 ans et j'accepte les %s de ce site"; +$a->strings["Registration"] = "Inscription"; +$a->strings["Membership on this site is by invitation only."] = "L'inscription à ce site se fait uniquement sur invitation."; +$a->strings["Please enter your invitation code"] = "Merci de saisir votre code d'invitation"; +$a->strings["Your email address"] = "Votre adresse de courriel"; +$a->strings["Choose a password"] = "Choisissez un mot de passe"; +$a->strings["Please re-enter your password"] = "Confirmez-le"; +$a->strings["Away"] = "Absent"; +$a->strings["Online"] = "En ligne"; +$a->strings["Please login."] = "Merci de vous connecter."; +$a->strings["Hubzilla - Guests: Username: {your email address}, Password: +++"] = "Matrice Rouge - Pour les invités: Nom d'utilisateur = {votre courriel}, Mot de passe = +++"; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "Il est impossible de supprimer un canal à l'intérieur de 48 heures après avoir changé le mot de passe d'un compte."; +$a->strings["Remove This Channel"] = "Supprimer ce Canal"; +$a->strings["This will completely remove this channel from the network. Once this has been done it is not recoverable."] = "Ceci effacera complètement le canal du réseau. Une fois effacé, un canal ne PEUT PAS être récupéré."; +$a->strings["Please enter your password for verification:"] = "Merci de re-saisir votre mot de passe pour vérification :"; +$a->strings["Remove this channel and all its clones from the network"] = "Supprimer ce canal ainsi que tous ses clones sur la matrice"; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = "Par défaut, seule l'instance du canal présente sur ce hub sera supprimée du réseau"; +$a->strings["Remove Channel"] = "Enlever le canal"; +$a->strings["No channel."] = "Pas de canal."; +$a->strings["Common connections"] = "Relations communes"; +$a->strings["No connections in common."] = "Pas de relation en commun."; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Nous avons rencontré un problème avec l'OpenID que vous nous avez fourni. Merci de vérifier que l'ID est bien saisi."; +$a->strings["The error message was:"] = "Le message d'erreur était :"; +$a->strings["Authentication failed."] = "Échec de l'authentification."; +$a->strings["Remote Authentication"] = "Authentification distante"; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Entrez l'adresse de votre canal (p.ex. moncanal@monsite.com)"; +$a->strings["Authenticate"] = "Authentifier"; +$a->strings["Continue"] = "Continuer"; +$a->strings["Premium Channel Setup"] = "Configuration du canal VIP"; +$a->strings["Enable premium channel connection restrictions"] = "Activer les restrictions liées au canal VIP"; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Merci de saisir les restrictions et/ou conditions - reçu Paypal, transaction Bitcoin, ligne de conduite, ..."; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Avant d'autoriser la mise en relation, ce canal attire votre attention sur les conditions suivantes :"; +$a->strings["Potential connections will then see the following text before proceeding:"] = "Les relations potentielles verront ce qui suit avant de pouvoir continuer :"; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "En continuant, je certifie que je me suis acquitté de toutes les instructions indiquées"; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(Aucune instruction spécifique n'a été établie par le propriétaire du canal.)"; +$a->strings["Restricted or Premium Channel"] = "Canal VIP ou restreint"; +$a->strings["No such group"] = "Groupe introuvable"; +$a->strings["Search Results For:"] = "Résultats de recherche pour :"; +$a->strings["Collection is empty"] = "Collection vide"; +$a->strings["Collection: "] = "Collection :"; +$a->strings["Connection: "] = "Relation :"; +$a->strings["Invalid connection."] = "Relation invalide."; +$a->strings["Could not access contact record."] = "Impossible d'accéder aux détails du contact."; +$a->strings["Could not locate selected profile."] = "Impossible de localiser le profil sélectionné."; +$a->strings["Connection updated."] = "Connexion mise à jour."; +$a->strings["Failed to update connection record."] = "Impossible de mettre à jour les détails de la relation."; +$a->strings["Blocked"] = "Bloqué"; +$a->strings["Ignored"] = "Ignoré"; +$a->strings["Hidden"] = "Caché"; +$a->strings["Archived"] = "Archivé"; +$a->strings["All"] = "Tout"; +$a->strings["Suggest new connections"] = "Suggérer de nouvelles relations"; +$a->strings["New Connections"] = "Nouvelles relations"; +$a->strings["Show pending (new) connections"] = "Voir les (nouvelles) relations en attente"; +$a->strings["Show all connections"] = "Voir toutes les relations"; +$a->strings["Unblocked"] = "Non bloquées"; +$a->strings["Only show unblocked connections"] = "Ne montrer que les relations non-bloquées"; +$a->strings["Only show blocked connections"] = "Ne montrer que les relations bloquées"; +$a->strings["Only show ignored connections"] = "Ne montrer que les relations ignorées"; +$a->strings["Only show archived connections"] = "Ne montrer que les relations archivées"; +$a->strings["Only show hidden connections"] = "Ne montrer que les relations cachées"; +$a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]"; +$a->strings["Edit contact"] = "Éditer contact"; +$a->strings["Search your connections"] = "Chercher parmi vos relations"; +$a->strings["Finding: "] = "Recherche :"; +$a->strings["Edit post"] = "Éditer la contribution"; +$a->strings["is now connected to"] = "est maintenant connecté avec"; +$a->strings["Could not access address book record."] = "Impossible d'accéder aux détails du carnet d'adresses."; +$a->strings["Refresh failed - channel is currently unavailable."] = "Actualisation impossible - le canal est momentanément indisponible."; +$a->strings["Channel has been unblocked"] = "Le canal n'est plus bloqué"; +$a->strings["Channel has been blocked"] = "Le canal est bloqué"; +$a->strings["Unable to set address book parameters."] = "Impossible de régler les paramètres du carnet d'adresses."; +$a->strings["Channel has been unignored"] = "Le canal n'est plus ignoré"; +$a->strings["Channel has been ignored"] = "Le canal est ignoré"; +$a->strings["Channel has been unarchived"] = "Le canal n'est plus archivé"; +$a->strings["Channel has been archived"] = "Le canal est archivé"; +$a->strings["Channel has been unhidden"] = "Le canal n'est plus caché"; +$a->strings["Channel has been hidden"] = "Le canal est caché"; +$a->strings["Channel has been approved"] = "Le canal est approuvé"; +$a->strings["Channel has been unapproved"] = "Le canal n'est plus approuvé"; +$a->strings["Connection has been removed."] = "La relation a été supprimée"; +$a->strings["View %s's profile"] = "Voir le profil de %s"; +$a->strings["Refresh Permissions"] = "Actualiser les permissions"; +$a->strings["Fetch updated permissions"] = "Récupérer les permissions les plus récentes"; +$a->strings["Recent Activity"] = "Activité récente"; +$a->strings["View recent posts and comments"] = "Voir les contributions et commentaires récentes"; +$a->strings["Unblock"] = "Débloquer"; +$a->strings["Block"] = "Bloquer"; +$a->strings["Block or Unblock this connection"] = "Bloquer ou Débloquer cette relation"; +$a->strings["Unignore"] = "Ne plus ignorer"; +$a->strings["Ignore"] = "Ignorer"; +$a->strings["Ignore or Unignore this connection"] = "Ignorer ou ne plus ignorer cette relation"; +$a->strings["Unarchive"] = "Ne plus archiver"; +$a->strings["Archive"] = "Archiver"; +$a->strings["Archive or Unarchive this connection"] = "Archiver ou ne plus archiver cette relation"; +$a->strings["Unhide"] = "Ne plus cacher"; +$a->strings["Hide"] = "Cacher"; +$a->strings["Hide or Unhide this connection"] = "Cacher ou ne plus cacher cette relation"; +$a->strings["Delete this connection"] = "Supprimer cette relation"; +$a->strings["Approve this connection"] = "Approuver cette relation"; +$a->strings["Accept connection to allow communication"] = "Accepter la relation pour permettre la communication"; +$a->strings["Automatic Permissions Settings"] = "Permissions automatiques"; +$a->strings["Connections: settings for %s"] = "Relations : réglages pour %s"; +$a->strings["When receiving a channel introduction, any permissions provided here will be applied to the new connection automatically and the introduction approved. Leave this page if you do not wish to use this feature."] = "Pour chaque introduction reçue, toutes les permissions définies ici seront appliquées aux nouvelles relations automatiquement, et l'introduction sera approuvée. Laissez cette page telle quelle si vous ne souhaitez pas utiliser ce mécanisme."; +$a->strings["Slide to adjust your degree of friendship"] = "Faites glisser pour ajuster le niveau de la relation"; +$a->strings["inherited"] = "héritée"; +$a->strings["Connection has no individual permissions!"] = "Cette relation n'a aucune permission spécifique!"; +$a->strings["This may be appropriate based on your privacy settings, though you may wish to review the \"Advanced Permissions\"."] = "Ceci devrait correspondre à vos réglages de vie privée, mais vous pouvez toujours contrôler les \"Permissions avancées\"."; +$a->strings["Profile Visibility"] = "Visibilité du profil"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Merci de choisir le profil que vous souhaitez montrer quand %s visite votre profil de manière authentifiée."; +$a->strings["Contact Information / Notes"] = "Notes / Information de contact"; +$a->strings["Edit contact notes"] = "Éditer les notes du contact"; +$a->strings["Their Settings"] = "Ses réglages"; +$a->strings["My Settings"] = "Mes réglages"; +$a->strings["Clear/Disable Automatic Permissions"] = "Effacer/Désactiver les Permissions Automatiques"; +$a->strings["Forum Members"] = "Membres du forum"; +$a->strings["Soapbox"] = "Blogue"; +$a->strings["Full Sharing (typical social network permissions)"] = "Partage Complet (fonctionnement habituel des réseaux sociaux)"; +$a->strings["Cautious Sharing "] = "Partage modéré"; +$a->strings["Follow Only"] = "Suivre uniquement"; +$a->strings["Individual Permissions"] = "Permissions spécifiques"; +$a->strings["Some permissions may be inherited from your channel privacy settings, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect."] = "Certaines permissions peuvent être héritées de vos réglages de vie privée, lesquels sont prioritaires sur les réglages spécifiques. Changer ces permissions héritées sur la présente page n'aura aucun effet."; +$a->strings["Advanced Permissions"] = "Permissions avancées"; +$a->strings["Simple Permissions (select one and submit)"] = "Permissions simples (en choisir une, puis valider)"; +$a->strings["Visit %s's profile - %s"] = "Visiter le profil de %s - %s"; +$a->strings["Block/Unblock contact"] = "Bloquer/Débloquer le contact"; +$a->strings["Ignore contact"] = "Ignorer le contact"; +$a->strings["Repair URL settings"] = "Réparer les réglages d'URL"; +$a->strings["View conversations"] = "Voir les conversations"; +$a->strings["Delete contact"] = "Supprimer le contact"; +$a->strings["Last update:"] = "Dernière mise à jour :"; +$a->strings["Update public posts"] = "Mettre à jour les publications"; +$a->strings["Update now"] = "Mettre à jour maintenant"; +$a->strings["Currently blocked"] = "Actuellement bloqué"; +$a->strings["Currently ignored"] = "Actuellement ignoré"; +$a->strings["Currently archived"] = "Actuellement archivé"; +$a->strings["Currently pending"] = "Actuellement en attente"; +$a->strings["Hide this contact from others"] = "Dissimuler ce contact aux autres"; +$a->strings["Replies/likes to your public posts may still be visible"] = "Les réponses et autres réactions à vos contributions publiques pourraient être toujours visibles"; +$a->strings["No potential page delegates located."] = "Aucun délégué potentiel n'a été trouvé pour cette page."; +$a->strings["Delegate Page Management"] = "Gestion des délégués de la page"; +$a->strings["Delegates are able to manage all aspects of this account/page except for basic account settings. Please do not delegate your personal account to anybody that you do not trust completely."] = "Les délégués sont capables de gérer tous les aspects de ce compte ou de cette page, à l'exception des réglages basiques du compte. Merci de ne déléguer votre compte personnel qu'à quelqu'un en qui vous avez une confiance aveugle."; +$a->strings["Existing Page Managers"] = "Actuels gestionnaires de pages"; +$a->strings["Existing Page Delegates"] = "Actuels délégués"; +$a->strings["Potential Delegates"] = "Délégués potentiels"; +$a->strings["Remove"] = "Retirer"; +$a->strings["Add"] = "Ajouter"; +$a->strings["No entries."] = "Aucune entrée."; +$a->strings["Public access denied."] = "Accès public refusé."; +$a->strings["Gender: "] = "Sexe/genre :"; +$a->strings["Finding:"] = "Recherche :"; +$a->strings["No entries (some entries may be hidden)."] = "Pas d'entrées (certaines peuvent être cachées)."; +$a->strings["Status: "] = "État :"; +$a->strings["Sexual Preference: "] = "Orientation sexuelle :"; +$a->strings["Homepage: "] = "Site web :"; +$a->strings["Hometown: "] = "Ville natale :"; +$a->strings["About: "] = "À propos :"; +$a->strings["Keywords: "] = "Mots-clefs :"; +$a->strings["This site is not a directory server"] = "Ce site n'est pas un serveur d'annuaire"; +$a->strings["Hubzilla - "The Network""] = "La Matrice Rouge - "LE Réseau""; +$a->strings["Welcome to %s"] = "Bienvenue sur %s"; +$a->strings["Hubzilla Server - Setup"] = "Serveur de la Matrice Rouge - Configuration"; +$a->strings["Could not connect to database."] = "Impossible de se connecter à la base de données."; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "Impossible de se connecter au site par l'URL indiquée. Problème potentiel de certificat SSL/TLS ou de DNS."; +$a->strings["Could not create table."] = "Impossible de créer la table."; +$a->strings["Your site database has been installed."] = "La base de données de votre site a été installée."; +$a->strings["You may need to import the file \"install/database.sql\" manually using phpmyadmin or mysql."] = "Vous pourriez avoir besoin d'importer le fichier \"install/database.sql\" manuellement via phpmyadmin ou mysql."; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Merci de consulter le fichier \"install/INSTALL.txt\"."; +$a->strings["System check"] = "Vérification du système"; +$a->strings["Next"] = "Suivant"; +$a->strings["Check again"] = "Re-vérifier"; +$a->strings["Database connection"] = "Connexion à la base de données"; +$a->strings["In order to install Hubzilla we need to know how to connect to your database."] = "Pour installer la Matrice Rouge, nous avons besoin de savoir comment contacter votre base de données."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Merci de contacter votre prestataire d'hébergement ou votre administrateur système si vous avez des doutes à propos de ces paramètres."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "La base de données que vous allez spécifier doit exister. Si ce n'est pas déjà le cas, merci de la créer avant de continuer."; +$a->strings["Database Server Name"] = "Nom du serveur de la base de données"; +$a->strings["Default is localhost"] = "Par défaut, localhost"; +$a->strings["Database Port"] = "Port du serveur"; +$a->strings["Communication port number - use 0 for default"] = "Numéro TCP du port - utilisez 0 pour la valeur par défaut"; +$a->strings["Database Login Name"] = "Identifiant de connexion à la Base de Données"; +$a->strings["Database Login Password"] = "Mot de passe de connexion à la Base de Données"; +$a->strings["Database Name"] = "Nom de la Base de Données"; +$a->strings["Site administrator email address"] = "Adresse de courriel de l'administrateur du site"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "Votre compte devra utiliser la même adresse de courriel pour pouvoir utiliser l'administration web."; +$a->strings["Website URL"] = "URL du site"; +$a->strings["Please use SSL (https) URL if available."] = "Merci d'utiliser SSL/TLS (https) autant que possible."; +$a->strings["Please select a default timezone for your website"] = "Merci de choisir une zone de temps (fuseau horaire) pour votre site"; +$a->strings["Site settings"] = "Réglages du site"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Impossible de trouver une version CLI de PHP dans le PATH du serveur web."; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "En l'absence de version CLI de PHP sur votre serveur, vous ne pourrez pas utiliser la mise à jour en arrière-plan via cron."; +$a->strings["PHP executable path"] = "Chemin vers l'éxecutable PHP"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Entrez le chemin complet vers l'exécutable php. Vous pouvez continuer l'installation sans."; +$a->strings["Command line PHP"] = "PHP en ligne de commande (CLI)"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "La version CLI de PHP sur votre système n'a pas l'option \"register_argc_argv\" activée."; +$a->strings["This is required for message delivery to work."] = "Elle est nécessaire pour la livraison de messages."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Erreur : la fonction \"openssl_pkey_new\" de ce système n'est pas capable de générer des clefs de chiffrement"; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Si vous êtes sur un serveur Windows, merci de consulter \"http://www.php.net/manual/fr/openssl.installation.php\"."; +$a->strings["Generate encryption keys"] = "Générer les clefs de chiffrement"; +$a->strings["libCurl PHP module"] = "module PHP libCurl"; +$a->strings["GD graphics PHP module"] = "module PHP GD graphics"; +$a->strings["OpenSSL PHP module"] = "module PHP OpenSSL"; +$a->strings["mysqli PHP module"] = "module PHP mysqli"; +$a->strings["mb_string PHP module"] = "module PHP mb_string"; +$a->strings["mcrypt PHP module"] = "module PHP mcrypt"; +$a->strings["Apache mod_rewrite module"] = "module Apache mod_rewrite"; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Erreur : le module mod-rewrite du serveur web Apache est requis, mais pas installé."; +$a->strings["proc_open"] = "proc_open"; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Erreur : proc_open est requis, mais soit n'est pas installé, soit est désactivé dans le php.ini"; +$a->strings["Error: libCURL PHP module required but not installed."] = "Erreur : le module libCURL de PHP est requis, mais pas installé."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Erreur : le module GD de PHP (avec support JPEG) est requis, mais pas installé."; +$a->strings["Error: openssl PHP module required but not installed."] = "Erreur : le module openssl de PHP est requis, mais pas installé."; +$a->strings["Error: mysqli PHP module required but not installed."] = "Erreur : le module mysqli de PHP est requis, mais pas installé."; +$a->strings["Error: mb_string PHP module required but not installed."] = "Erreur : le module mb_string de PHP est requis, mais pas installé."; +$a->strings["Error: mcrypt PHP module required but not installed."] = "Erreur : le module mcrypt de PHP est requis, mais pas installé."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\ in the top folder of your web server and it is unable to do so."] = "L'installeur web a besoin de créer un fichier \".htconfig.php\" à la racine de votre serveur web, mais en est incapable."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "C'est généralement lié à un problème de droits, à cause duquel le serveur web est interdit d'écriture dans le répertoire concerné - alors que votre propre utilisateur a le droit."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Au terme de cette procédure, nous vous transmettrons un texte à sauvegarder dans un fichier nommé .htconfig.php, à la racine de votre installation de La Matrice Rouge."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Autrement, vous pouvez contourner toute cette procédure et réaliser l'installation manuellement. Merci de consulter le fichier \"install/INSTALL.txt\" pour les instructions détaillées."; +$a->strings[".htconfig.php is writable"] = "Le fichier .htconfig.php est accessible en écriture"; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "La Matrice Rouge utilise le moteur de template Smarty3 pour mettre son contenu en forme. Smarty3 compile ses modèles vers du PHP natif pour accélérer le rendu."; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "Pour utiliser ces modèles, le serveur doit avoir le droits d'écrire dans le dossier %s."; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Merci de vous assurer que l'utilisateur sous lequel le serveur web tourne (le plus souvent, www-data) a bien l'autorisation d'écrire dans ce répertoire."; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Note: Comme mesure de sécurité, assurez vous de donner les droits d'écriture sur %s au serveur web uniquement. Éviter de définir les permissions sur les fichiers individuels (.tpl)."; +$a->strings["%s is writable"] = "Permission d'écriture sur %s activée"; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Red utilise le répertoire 'store' - situé à la racine de votre installation de la Matrice Rouge - pour sauvegarder les fichiers envoyés. Le serveur web aura donc besoin de pouvoir y écrire."; +$a->strings["store is writable"] = "'store' est accessible en écriture"; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "Le certificat SSL/TLS n'a pas pu être validé. Merci de le corriger, ou de désactiver l'accès https à ce site."; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Si votre serveur supporte les connections encryptées SSL ou s'il permet les connections sur le port TCP 443 (le port utilisé par le protocole https), vous DEVEZ utiliser un certificat valide. Vous ne DEVEZ PAS utiliser un certificat que vous avez vous-mêmes signé!"; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Nous avons ajouté cette contrainte pour éviter que vos publications publiques ne fassent référence à des images sur votre propre hub."; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Si votre certificat n'est pas reconnu, les membres des autres sites (avec certificats valides) recevront des messages d'avertissement sur leur propre sites."; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Pour des raisons de compatibilité (sur l'ensemble de la matrice) nous nous devons d'insister sur ce prérequis."; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Il existe une plusieurs autorités de certification qui vous fourniront gratuitement un certificat valide."; +$a->strings["SSL certificate validation"] = "Validation du certificat SSL/TLS"; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration."] = "La réécriture d'URL définie dans le .htaccess ne fonctionne pas. Merci de vérifier la configuration de votre serveur web."; +$a->strings["Url rewrite is working"] = "La réécriture d'URL fonctionne"; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Le fichier de configuration de la base de données - \".htconfig.php\" - ne peut être écrit. Merci de copier le texte généré dans un fichier à ce nom, à la racine de votre serveur web."; +$a->strings["Errors encountered creating database tables."] = "Erreurs rencontrées pendant la création de tables de BD."; +$a->strings["

    What next

    "] = "

    Et maintenant

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "IMPORTANT : Vous devez créer [manuellement] une tâche planifiée pour les mises à jour."; +$a->strings["Item not found"] = "Élément introuvable"; +$a->strings["Edit Block"] = "Éditer bloc"; +$a->strings["Delete block?"] = "Supprimer le bloc?"; +$a->strings["Insert YouTube video"] = "Insérer une vidéo YouTube"; +$a->strings["Insert Vorbis [.ogg] video"] = "Insérer une vidéo Vorbis [.ogg]"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Insérer un son Vorbis [.ogg]"; +$a->strings["Delete Block"] = "Supprimer le bloc"; +$a->strings["Layout updated."] = "Agencement pris-en-compte."; +$a->strings["Edit System Page Description"] = "Éditer la description"; +$a->strings["Layout not found."] = "Agencement introuvable."; +$a->strings["Module Name:"] = "Nom du module :"; +$a->strings["Layout Help"] = "Aide à la mise en page"; +$a->strings["Edit Layout"] = "Éditer mise-en-page"; +$a->strings["Delete layout?"] = "Supprimer la mise-en-page?"; +$a->strings["Delete Layout"] = "Supprimer mise-en-page"; +$a->strings["Item is not editable"] = "Élément non-éditable"; +$a->strings["Delete item?"] = "Supprimer l'élément?"; +$a->strings["Edit Webpage"] = "Éditer page web"; +$a->strings["Delete webpage?"] = "Supprimer la page web?"; +$a->strings["Delete Webpage"] = "Supprimer page web"; +$a->strings["Version %s"] = "Version %s"; +$a->strings["Installed plugins/addons/apps:"] = "Extensions/applications installées :"; +$a->strings["No installed plugins/addons/apps"] = "Aucune extension/application installée"; +$a->strings["Red"] = "Rouge"; +$a->strings["This is a hub of the Hubzilla - a global cooperative network of decentralized privacy enhanced websites."] = "Ceci est un serveur de la Matrice Rouge - un réseau collaboratif de plusieurs serveurs qui assurent la protection de votre vie privée notamment par la décentralisation de votre identité."; +$a->strings["Running at web location"] = "Installée sur"; +$a->strings["Please visit GetZot.com to learn more about the Hubzilla."] = "Merci de visiter GetZot.com pour en apprendre davantage sur la Matrice Rouge."; +$a->strings["Bug reports and issues: please visit"] = "Pour remonter bogues et problèmes, merci de visiter"; +$a->strings["Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot com"] = "Suggestions, demandes, etc. - merci de vous adresser à \"hubzilla\" à librelist - point com"; +$a->strings["Site Administrators"] = "Administrateurs du site"; +$a->strings["Page owner information could not be retrieved."] = "Impossible d'obtenir des informations sur le propriétaire de la page."; +$a->strings["Album not found."] = "Album introuvable."; +$a->strings["Delete Album"] = "Supprimer album"; +$a->strings["Delete Photo"] = "Supprimer photo"; +$a->strings["No photos selected"] = "Aucune photo selectionnée"; +$a->strings["Access to this item is restricted."] = "L'accès à l'élément est restreint."; +$a->strings["You have used %1$.2f Mbytes of %2$.2f Mbytes photo storage."] = "Vous avez utilisé %1$.2f mégaoctets sur les %2$.2f autorisés pour le stockage des photos."; +$a->strings["You have used %1$.2f Mbytes of photo storage."] = "Vous avez utilisé %1$.2f mégaoctets pour le stockage des photos."; +$a->strings["Upload Photos"] = "Téléverser des photos"; +$a->strings["New album name: "] = "Créer un album :"; +$a->strings["or existing album name: "] = "ou choisir un album existant :"; +$a->strings["Do not show a status post for this upload"] = "Ne pas publier de statut pour cet envoi"; +$a->strings["Album name could not be decoded"] = "Le nom de l'Album n'a pu être décodé"; +$a->strings["Contact Photos"] = "Photos de contact"; +$a->strings["Edit Album"] = "Éditer l'album"; +$a->strings["Show Newest First"] = "Ordre anté-chronologique"; +$a->strings["Show Oldest First"] = "Ordre chronologique"; +$a->strings["View Photo"] = "Voir la photo"; +$a->strings["Permission denied. Access to this item may be restricted."] = "Permission refusée. L'accès à cet élément peut avoir été restreint."; +$a->strings["Photo not available"] = "Photo indisponible"; +$a->strings["Use as profile photo"] = "Utiliser comme photo du profil"; +$a->strings["View Full Size"] = "Voir en taille réelle"; +$a->strings["Edit photo"] = "Éditer la photo"; +$a->strings["Rotate CW (right)"] = "Rotation horaire (droite)"; +$a->strings["Rotate CCW (left)"] = "Rotation anti-horaire (gauche)"; +$a->strings["New album name"] = "Nouveau nom d'album :"; +$a->strings["Caption"] = "Titre/légende"; +$a->strings["Add a Tag"] = "Ajouter une étiquette"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com, #California, #camping"] = "Exemple : @bob, @Barbara_Jensen, @jim@exemple.com, #Ile_de_France, #marathon"; +$a->strings["In This Photo:"] = "Dans cette photo :"; +$a->strings["View Album"] = "Voir l'album"; +$a->strings["Recent Photos"] = "Photos récentes"; +$a->strings["Failed to create source. No channel selected."] = "Impossible de créer la source. Aucun canal selectionné."; +$a->strings["Source created."] = "Source créée."; +$a->strings["Source updated."] = "Source mise à jour."; +$a->strings["*"] = "*"; +$a->strings["Manage remote sources of content for your channel."] = "Gérer les sources distantes du contenu de votre canal."; +$a->strings["New Source"] = "Nouvelle Source"; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importer tout ou partie du contenu du canal suivant dans le canal en cours, et le distribuer en concordance avec les réglages de votre canal."; +$a->strings["Only import content with these words (one per line)"] = "N'importer le contenu que s'ils contient ces mots (un par ligne)"; +$a->strings["Leave blank to import all public content"] = "Laissez en blanc pour importer tout le contenu public"; +$a->strings["Channel Name"] = "Nom du Canal"; +$a->strings["Source not found."] = "Source introuvable."; +$a->strings["Edit Source"] = "Éditer la source"; +$a->strings["Delete Source"] = "Supprimer la source"; +$a->strings["Source removed"] = "Source supprimée"; +$a->strings["Unable to remove source."] = "Impossible de supprimer la source."; +$a->strings["- select -"] = "- choisir -"; +$a->strings["Event title and start time are required."] = "Un titre et une date de début sont requises pour l'événement."; +$a->strings["Event not found."] = "Événement introuvable."; +$a->strings["l, F j"] = "l j F"; +$a->strings["Edit event"] = "Éditer l'événement"; +$a->strings["Create New Event"] = "Créer événement"; +$a->strings["Previous"] = "Précédent"; +$a->strings["hour:minute"] = "heure:minute"; +$a->strings["Event details"] = "Détails de l'événement"; +$a->strings["Format is %s %s. Starting date and Title are required."] = "Le format est %s %s. Date de début et titre obligatoires."; +$a->strings["Event Starts:"] = "L'événement débute :"; +$a->strings["Required"] = "Requis"; +$a->strings["Finish date/time is not known or not relevant"] = "Date/heure de fin inconnue ou sans objet"; +$a->strings["Event Finishes:"] = "L'événement termine :"; +$a->strings["Adjust for viewer timezone"] = "Ajuster au fuseau horaire du visiteur"; +$a->strings["Description:"] = "Description:"; +$a->strings["Title:"] = "Titre:"; +$a->strings["Share this event"] = "Partager cet événement"; +$a->strings["Permission Denied."] = "Permission refusée."; +$a->strings["File not found."] = "Fichier introuvable."; +$a->strings["Edit file permissions"] = "Éditer les permissions du fichier"; +$a->strings["Set/edit permissions"] = "Définir/Édition des authorisations"; +$a->strings["Include all files and sub folders"] = "Inclure tous fichiers et sous-répertoires"; +$a->strings["Return to file list"] = "Retourner à la liste des fichiers"; +$a->strings["Copy/paste this code to attach file to a post"] = "Copiez/collez ce code pour joindre le fichier à une publication"; +$a->strings["Copy/paste this URL to link file from a web page"] = "Copiez/collez cette URL pour lier le fichier depuis une page web"; +$a->strings["Channel added."] = "Canal ajouté."; +$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s suit %3\$s de %2\$s"; +$a->strings["Contact not found."] = "Contact introuvable."; +$a->strings["Friend suggestion sent."] = "Suggestion d'amitié/relation envoyée."; +$a->strings["Suggest Friends"] = "Suggérer une relation"; +$a->strings["Suggest a friend for %s"] = "Suggérer une relation à %s"; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Pas de suggestions pour l'instant. Si le site est récent, merci de re-tenter dans 24 heures."; +$a->strings["Collection created."] = "Collection créée."; +$a->strings["Could not create collection."] = "Impossible de créer la collection."; +$a->strings["Collection updated."] = "Collection mise à jour."; +$a->strings["Create a collection of channels."] = "Créez une collection de canaux."; +$a->strings["Collection Name: "] = "Nom de la collection :"; +$a->strings["Members are visible to other channels"] = "Les membres sont visibles par les autres canaux"; +$a->strings["Collection removed."] = "Collection supprimée."; +$a->strings["Unable to remove collection."] = "Impossible de supprimer la collection."; +$a->strings["Collection Editor"] = "Éditeur de collection"; +$a->strings["Members"] = "Membres"; +$a->strings["All Connected Channels"] = "Tous canaux connectés"; +$a->strings["Click on a channel to add or remove."] = "Cliquer sur un canal pour l'ajouter ou le supprimer"; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s a étiqueté le %3\$s de %2\$s par %4\$s"; +$a->strings["Help:"] = "Aide :"; +$a->strings["Not Found"] = "Introuvable"; +$a->strings["Tag removed"] = "Étiquette retirée"; +$a->strings["Remove Item Tag"] = "Retirer une étiquette à l'élément"; +$a->strings["Select a tag to remove: "] = "Étiquette à retirer :"; +$a->strings["Theme settings updated."] = "Réglages du thème sauvegardés."; +$a->strings["Site"] = "Site"; +$a->strings["Accounts"] = "Comptes"; +$a->strings["Channels"] = "Canaux"; +$a->strings["Plugins"] = "Extensions"; +$a->strings["Themes"] = "Thèmes"; +$a->strings["Server"] = "Serveur"; +$a->strings["Profile Config"] = "Configurations du profil"; +$a->strings["DB updates"] = "MàJ BD"; +$a->strings["Logs"] = "Journaux"; +$a->strings["Plugin Features"] = "Fonctionnalités liées aux extensions"; +$a->strings["User registrations waiting for confirmation"] = "Inscriptions en attente"; +$a->strings["Message queues"] = "File des messages"; +$a->strings["Administration"] = "Administration"; +$a->strings["Summary"] = "Résumé"; +$a->strings["Registered users"] = "Utilisateurs inscrits"; +$a->strings["Pending registrations"] = "Inscriptions en attente"; +$a->strings["Version"] = "Version"; +$a->strings["Active plugins"] = "Extensions actives"; +$a->strings["Site settings updated."] = "Réglages du site sauvegardés."; +$a->strings["No special theme for accessibility"] = "Pas de thème spécifique pour l'accessibilité"; +$a->strings["Yes - with approval"] = "Oui - avec approbation"; +$a->strings["My site is not a public server"] = "Mon site n'est pas un serveur public"; +$a->strings["My site has paid access only"] = "Mon site est payant"; +$a->strings["My site has free access only"] = "Mon site est gratuit"; +$a->strings["My site offers free accounts with optional paid upgrades"] = "Mon site offre des comptes gratuits avec des ajouts payants"; +$a->strings["File upload"] = "Envoi de fichier"; +$a->strings["Policies"] = "Stratégies"; +$a->strings["Site name"] = "Nom du site"; +$a->strings["Banner/Logo"] = "Bannière/logo"; +$a->strings["Administrator Information"] = "Informations sur l'administrateur"; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = "Coordonnées de l'administrateur du site. Affichée sur la page 'siteinfo'. Vous pouvez utiliser du BBCode ici"; +$a->strings["System language"] = "Langue du système"; +$a->strings["System theme"] = "Thème du système"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "Thème par défaut - il peut être changé pour chaque profil utilisateur - modifier le thème"; +$a->strings["Mobile system theme"] = "Thème système pour mobile"; +$a->strings["Theme for mobile devices"] = "Thème dédié aux périphériques mobiles"; +$a->strings["Accessibility system theme"] = "Thème système pour l'accessibilité"; +$a->strings["Accessibility theme"] = "Thème pour l'accessibilité"; +$a->strings["Channel to use for this website's static pages"] = "Canal à utiliser pour les pages statiques de ce site"; +$a->strings["Site Channel"] = "Canal de ce HUB"; +$a->strings["Maximum image size"] = "Taille maximale des images"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Taille maximum, en octets, des images envoyées. Par défaut 0, soit sans limite."; +$a->strings["Does this site allow new member registration?"] = "Est-ce que l'enregistrement de nouveau membres sur ce site est autorisé?"; +$a->strings["Which best describes the types of account offered by this hub?"] = "Choisissez le type de comptes offert sur ce hub?"; +$a->strings["Register text"] = "Texte d'inscription"; +$a->strings["Will be displayed prominently on the registration page."] = "Sera affiché de manière bien visible sur le formulaire d'inscription."; +$a->strings["Accounts abandoned after x days"] = "Les comptes sont abandonnés après x jours"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "Pour éviter de gaspiller les ressources du système en essayer de mettre à jour des comptes abandonnés. Mettez 0 pour ne pas avoir de limite de temps."; +$a->strings["Allowed friend domains"] = "Domaines amicaux"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "Liste de noms de domaines - séparés par des virgules - pour lesquels ce site acceptera les demandes d'amitié ou de mise en relation. Les caractères génériques (*) sont acceptés. Laissez vide pour accepter tous les domaines."; +$a->strings["Allowed email domains"] = "Domaines de courriels amicaux"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "Liste de noms de domaines - séparés par des virgules - dont les adresses de courriel seront autorisées lors de l'inscription à ce site. Les caractères génériques (*) sont acceptés. Laissez vide pour accepter tous les domaines."; +$a->strings["Block public"] = "Bloquer public"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Cocher pour interdire tout accès public, y compris aux pages marquées comme publiques, aux visiteurs anonymes."; +$a->strings["Force publish"] = "Forcer publication"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Cocher pour forcer la publication de tous les profils du site dans l'annuaire."; +$a->strings["Disable discovery tab"] = "Désactiver l'onglet \"À découvrir\""; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = "Ne pas afficher d'onglet avec des contenus publics automatiquement rassemblées depuis des sources choisies pour ce site."; +$a->strings["No login on Homepage"] = "Pas de connexion depuis la page d'accueil"; +$a->strings["Check to hide the login form from your sites homepage when visitors arrive who are not logged in (e.g. when you put the content of the homepage in via the site channel)."] = "Cocher pour ne pas montrer le formulaire de connexion sur la page d'accueil (typiquement, pour quand vous utilisez la page d'accueil pour afficher du contenu via le canal du site)."; +$a->strings["Proxy user"] = "Utilisateurs du proxy"; +$a->strings["Proxy URL"] = "URL du proxy (visiter @proxy-list)"; +$a->strings["Network timeout"] = "Délai maximal du réseau"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "En secondes. Mettre à 0 pour ne pas avoir de délai maximal (pas recommandé)."; +$a->strings["Delivery interval"] = "Intervalle de distribution"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Temporise le processus de distribution de tant de secondes pour réduire la charge sur le système. Valeurs recommandées : 4-5 pour les serveurs mutualisés, 2-3 pour les VPS. 0-1 pour les gros serveurs dédiés."; +$a->strings["Poll interval"] = "Intervalle de scrutation"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Temporise le processus de scrutation en tâche de fond de tant de secondes, pour réduire la charge. Si 0, utilise l'intervalle de distribution."; +$a->strings["Maximum Load Average"] = "Charge moyenne maximale"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Charge système maximale au-delà de laquelle distribution et scrutation sont mis en pause - par défaut 50."; +$a->strings["No server found"] = "Serveur introuvable"; +$a->strings["ID"] = "ID"; +$a->strings["for channel"] = "pour le canal"; +$a->strings["on server"] = "sur le serveur"; +$a->strings["Status"] = "État"; +$a->strings["Update has been marked successful"] = "La mise à jour a été marquée comme réussie"; +$a->strings["Executing %s failed. Check system logs."] = "L'éxecution de %s a échoué. Merci de vérifier les journaux du système."; +$a->strings["Update %s was successfully applied."] = "La mise à jour %s a été appliquée avec succès."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "La mise à jour %s n'a pas retourné d'information. Impossible de savoir si elle a réussi ou non."; +$a->strings["Update function %s could not be found."] = "La fonction de mise à jour %s est introuvable."; +$a->strings["No failed updates."] = "Aucune mise à jour défaillante."; +$a->strings["Failed Updates"] = "Mises à jour défaillantes"; +$a->strings["Mark success (if update was manually applied)"] = "Marquer comme réussie (si la mise à jour a été réalisée manuellement)"; +$a->strings["Attempt to execute this update step automatically"] = "Tenter de réaliser cette étape de mise à jour automatiquement"; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "%s utilisateur bloqué/débloqué", + 1 => "%s utilisateurs bloqués/débloqués", +); +$a->strings["%s user deleted"] = array( + 0 => "%s utilisateur supprimé", + 1 => "%s utilisateurs supprimés", +); +$a->strings["Account not found"] = "Compte introuvable"; +$a->strings["User '%s' deleted"] = "Utilisateur '%s' supprimé"; +$a->strings["User '%s' unblocked"] = "Utilisateur '%s' débloqué"; +$a->strings["User '%s' blocked"] = "Utilisateur '%s' bloqué"; +$a->strings["Users"] = "Utilisateurs"; +$a->strings["select all"] = "tout sélectionner"; +$a->strings["User registrations waiting for confirm"] = "Inscriptions en attente d'approbation"; +$a->strings["Request date"] = "Date de la demande"; +$a->strings["No registrations."] = "Pas d'inscriptions."; +$a->strings["Approve"] = "Approuver"; +$a->strings["Deny"] = "Refuser"; +$a->strings["Register date"] = "Date d'inscription"; +$a->strings["Last login"] = "Dernière connexion"; +$a->strings["Expires"] = "Expire"; +$a->strings["Service Class"] = "Classe de service"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Les utilisateurs sélectionnés seront supprimés!\\n\\nTout ce que ces utilisateurs ont publié sur ce site sera détruit de manière définitive!\\n\\nÊtes-vous certain?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "L'utilisateur {0} sera supprimé!\\n\\nTout ce que cet utilisateur a publié sur ce site sera détruit de manière définitive!\\n\\nÊtes-vous certain?"; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "%s canal censuré/non-censuré", + 1 => "%s canaux censurés/non-censurés", +); +$a->strings["%s channel deleted"] = array( + 0 => "%s canal supprimé", + 1 => "%s canaux supprimés", +); +$a->strings["Channel not found"] = "Canal introuvable"; +$a->strings["Channel '%s' deleted"] = "Canal '%s' supprimé"; +$a->strings["Channel '%s' uncensored"] = "Canal '%s' non-censuré"; +$a->strings["Channel '%s' censored"] = "Canal '%s' censuré"; +$a->strings["Censor"] = "Censurer"; +$a->strings["Uncensor"] = "Ne plus censurer"; +$a->strings["UID"] = "UID"; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = "Les canaux sélectionnés seront supprimés!\\n\\nTout ce qui a été publié dans ces canaux sur ce site sera définitivement supprimé!\\n\\nÊtes-vous certain?"; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = "Le canal {0} sera supprimé!\\n\\nTout ce qui a été publié sur ce canal sera définitivement supprimé!\\n\\nÊtes-vous certain?"; +$a->strings["Plugin %s disabled."] = "Extension %s désactivée."; +$a->strings["Plugin %s enabled."] = "Extension %s activée."; +$a->strings["Disable"] = "Désactiver"; +$a->strings["Enable"] = "Activer"; +$a->strings["Toggle"] = "(Dés)activer"; +$a->strings["Author: "] = "Auteur :"; +$a->strings["Maintainer: "] = "Maintenu par :"; +$a->strings["No themes found."] = "Aucun thème trouvé."; +$a->strings["Screenshot"] = "Aperçu"; +$a->strings["[Experimental]"] = "[Expérimental]"; +$a->strings["[Unsupported]"] = "[Non-supporté]"; +$a->strings["Log settings updated."] = "Réglages du journal sauvegardés."; +$a->strings["Clear"] = "Vider"; +$a->strings["Debugging"] = "Débogage"; +$a->strings["Log file"] = "Fichier du journal"; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = "Doit être accessible en écriture par le serveur web. Chemin relatif à la racine de votre installation de la Matrice Rouge."; +$a->strings["Log level"] = "Niveau de journalisation"; +$a->strings["Thing updated"] = "Chose mise à jour"; +$a->strings["Object store: failed"] = "Stockage de l'objet : échec"; +$a->strings["Thing added"] = "Chose ajoutée"; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = "OBJ: %1\$s %2\$s %3\$s"; +$a->strings["Show Thing"] = "Montrer chose"; +$a->strings["item not found."] = "élément introuvable."; +$a->strings["Edit Thing"] = "Éditer chose"; +$a->strings["Select a profile"] = "Choisissez un profil"; +$a->strings["Post an activity"] = "Publier une activité"; +$a->strings["Only sends to viewers of the applicable profile"] = "Envoi exclusivement au membres autorisé de ce profil"; +$a->strings["Name of thing e.g. something"] = "Nom de la chose, p.ex. quelque-chose"; +$a->strings["URL of thing (optional)"] = "URL de la chose (optionnel)"; +$a->strings["URL for photo of thing (optional)"] = "URL de l'image de la chose (optionnel)"; +$a->strings["Add Thing to your Profile"] = "Ajouter la chose à votre profil"; +$a->strings["Nothing to import."] = "Rien à importer."; +$a->strings["Unable to download data from old server"] = "Impossible de récupérer les données de l'ancien serveur"; +$a->strings["Imported file is empty."] = "Le fichier importé est vide."; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "Impossible de créer un doublon d'un identifiant de canal. L'import a échoué."; +$a->strings["Channel clone failed. Import failed."] = "Le clonage du canal a échoué. L'import a échoué."; +$a->strings["Cloned channel not found. Import failed."] = "Le canal cloné n'a pas été trouvé. L'import a échoué."; +$a->strings["Import completed."] = "L'import est terminé."; +$a->strings["You must be logged in to use this feature."] = "Vous devez vous connecter pour utiliser cette fonctionnalité."; +$a->strings["Import Channel"] = "Importation de canal"; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = "Utilisez ce formulaire pour importer un canal existant sur un serveur différent. Vous pouvez récupérer l'identité du canal sur l'ancien serveur directement par le réseau, ou bien fournir un fichier d'export. Seules les données d'identité et de relations seront importées. L'importation du contenu est toujours en développement."; +$a->strings["File to Upload"] = "Fichier à envoyer"; +$a->strings["Or provide the old server/hub details"] = "Ou fournissez les détails de l'ancien serveur"; +$a->strings["Your old identity address (xyz@example.com)"] = "Votre ancienne identité (zyx@exemple.com)"; +$a->strings["Your old login email address"] = "Votre ancienne adresse de courriel"; +$a->strings["Your old login password"] = "Votre ancien mot de passe"; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Quelle que soit l'option choisie, merci de décider si cette nouvelle adresse sera la primaire, ou si votre ancienne adresse continuera à jouer ce rôle. Vous pourrez publier depuis l'adresse de votre choix, mais une seule peut être déclarée comme stockage primaire de vos fichiers/photos/media."; +$a->strings["Make this hub my primary location"] = "Faire de ce hub l'adresse principale de ce canal"; +$a->strings["Total invitation limit exceeded."] = "Limite du nombre total d'invitation dépassée."; +$a->strings["%s : Not a valid email address."] = "%s : adresse courriel invalide."; +$a->strings["Please join us on Red"] = "Rejoignez-nous sur la Matrice Rouge"; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = "Limite d'invitations dépassée. Merci de contacter l'administration de votre site."; +$a->strings["%s : Message delivery failed."] = "%s : Échec dans la livraison du message."; +$a->strings["%d message sent."] = array( + 0 => "%d message envoyé.", + 1 => "%d messages envoyés.", +); +$a->strings["You have no more invitations available"] = "Vous ne disposez plus d'aucune invitation"; +$a->strings["Send invitations"] = "Envoyer des invitations"; +$a->strings["Enter email addresses, one per line:"] = "Entrez les adresses de courriel, une par ligne :"; +$a->strings["Your message:"] = "Votre message :"; +$a->strings["Please join my community on Hubzilla."] = "Veuillez me rejoindre sur la Matrice Rouge."; +$a->strings["You will need to supply this invitation code: "] = "Vous aurez besoin de fournir le code suivant:"; +$a->strings["1. Register at any Hubzilla location (they are all inter-connected)"] = "1. Enregistrez-vous sur n'importe quel serveurs ( ils sont tous inter-connectés )"; +$a->strings["2. Enter my Hubzilla network address into the site searchbar."] = "2. Saisissez l'adresse de mon canal dans la barre de recherche du site."; +$a->strings["or visit "] = "ou visitez"; +$a->strings["3. Click [Connect]"] = "3. Click sur [Ajouter]"; +$a->strings["Unable to locate original post."] = "Impossible de localiser la publication initiale."; +$a->strings["Empty post discarded."] = "Publication vide annulée."; +$a->strings["Executable content type not permitted to this channel."] = "Les contenus de type 'exécutable' ne sont pas autorisés sur ce canal."; +$a->strings["System error. Post not saved."] = "Erreur système. Publication non sauvegardée."; +$a->strings["You have reached your limit of %1$.0f top level posts."] = "Vous avez atteint votre limite de %1$.0f contributions \"racine\"."; +$a->strings["You have reached your limit of %1$.0f webpages."] = "Vous avez atteint votre limite de %1$.0f pages web."; +$a->strings["[Embedded content - reload page to view]"] = "[Contenu embarqué - rechargez la page pour le voir]"; +$a->strings["Help with this feature"] = "Aide avec cette fonctionnalité"; +$a->strings["Layout Name"] = "Nom de la mise-en-page"; +$a->strings["Like/Dislike"] = "J'aime/Je Déteste"; +$a->strings["This action is restricted to members."] = "Cette action est réservée aux membres."; +$a->strings["Please login with your Hubzilla ID or register as a new Redmatrix.member to continue."] = "SVP connectez-vous ou enregistrez-vous pour continuer."; +$a->strings["Invalid request."] = "Requête invalide."; +$a->strings["thing"] = "chose"; +$a->strings["Channel unavailable."] = "Canal indisponible."; +$a->strings["Previous action reversed."] = "Action précédente annulée."; +$a->strings["Action completed."] = "Action complétée."; +$a->strings["Thank you."] = "Merci."; +$a->strings["Remote privacy information not available."] = "Les informations de vie privée à distance ne sont pas disponibles."; +$a->strings["Visible to:"] = "Visible par :"; +$a->strings["No connections."] = "Pas de relation."; +$a->strings["Visit %s's profile [%s]"] = "Visiter le profil de %s [%s]"; +$a->strings["View Connnections"] = "Voir les relations"; +$a->strings["No valid account found."] = "Aucun compte valide trouvé."; +$a->strings["Password reset request issued. Check your email."] = "Réinitialisation du mot de passe demandée. Vérifiez vos courriels."; +$a->strings["Site Member (%s)"] = "Membre du site (%s)"; +$a->strings["Password reset requested at %s"] = "Demande de réinitialisation du mot de passe sur %s"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "La demande n'a pas pu être vérifiée. (Peut-être l'avez vous déjà utilisée.) La réinitialisation a échoué."; +$a->strings["Password Reset"] = "Réinitialiser le mot de passe"; +$a->strings["Your password has been reset as requested."] = "Votre mot de passe a bien été réinitialisé."; +$a->strings["Your new password is"] = "Votre nouveau mot de passe est"; +$a->strings["Save or copy your new password - and then"] = "Sauvez-le ou copiez-le, puis"; +$a->strings["click here to login"] = "cliquez ici pour vous connecter"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Votre mot de passe peut être changé depuis la page des Réglages une fois connecté."; +$a->strings["Your password has changed at %s"] = "Votre mot de passe de %s a été changé"; +$a->strings["Forgot your Password?"] = "Mot de passe oublié?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Saisissez votre adresse de courriel, et validez, pour réinitialiser votre mot de passe. Vérifiez ensuite votre boîte à lettres pour la suite des instructions."; +$a->strings["Email Address"] = "Adresse de courriel"; +$a->strings["Reset"] = "Réinitialiser"; +$a->strings["Hub not found."] = "Hub introuvable."; +$a->strings["Total votes"] = "Total des votes"; +$a->strings["Average Rating"] = "Évaluation moyenne"; +$a->strings["Unable to lookup recipient."] = "Impossible de localiser le destinataire."; +$a->strings["Unable to communicate with requested channel."] = "Impossible de communiquer avec le canal demandé."; +$a->strings["Cannot verify requested channel."] = "Impossible de vérifier le canal demandé."; +$a->strings["Selected channel has private message restrictions. Send failed."] = "Le canal choisi a des restrictions quant aux messages privés. L'envoi a échoué."; +$a->strings["Messages"] = "Messages"; +$a->strings["Message deleted."] = "Message supprimé."; +$a->strings["Message recalled."] = "Message annulé/rappelé."; +$a->strings["Send Private Message"] = "Envoyer un Message Privé"; +$a->strings["To:"] = "À :"; +$a->strings["Subject:"] = "Sujet :"; +$a->strings["Send"] = "Envoyer"; +$a->strings["Message not found."] = "Message introuvable."; +$a->strings["Delete message"] = "Supprimer message"; +$a->strings["Recall message"] = "Rappeler/annuler le message"; +$a->strings["Message has been recalled."] = "Le message a été rappelé."; +$a->strings["Private Conversation"] = "Conversation privée"; +$a->strings["Delete conversation"] = "Supprimer conversation"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Aucune communication sécurisée n'est possible. Vous pourrez peut-être répondre depuis la page de profil de l'émetteur."; +$a->strings["Send Reply"] = "Envoyer une réponse"; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Vous avez créé %1$.0f des %2$.0f canaux autorisés."; +$a->strings["Create a new channel"] = "Créer un nouveau canal"; +$a->strings["Channel Manager"] = "Gestionnaire du canal"; +$a->strings["Current Channel"] = "Canal actif"; +$a->strings["Attach to one of your channels by selecting it."] = "Branchez-vous à l'un de vos canaux en le selectionnant."; +$a->strings["Default Channel"] = "Canal par défaut"; +$a->strings["Make Default"] = "Définir comme défaut"; +$a->strings["Wall Photos"] = "Photos du mur"; +$a->strings["Profile Match"] = "Profils similaires"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "Aucun mot-clef à comparer. Merci d'ajouter des mots-clefs à votre profil par défaut."; +$a->strings["is interested in:"] = "s'intéresse à :"; +$a->strings["No matches"] = "Pas de correspondance"; +$a->strings["Menu updated."] = "Menu mis à jour."; +$a->strings["Unable to update menu."] = "Impossible de mettre le menu à jour."; +$a->strings["Menu created."] = "Menu créé."; +$a->strings["Unable to create menu."] = "Impossible de créer le menu."; +$a->strings["Manage Menus"] = "Gérer les menus"; +$a->strings["Drop"] = "Supprimer"; +$a->strings["Create a new menu"] = "Créer un nouveau menu"; +$a->strings["Delete this menu"] = "Supprimer ce menu"; +$a->strings["Edit menu contents"] = "Éditer le contenu du menu"; +$a->strings["Edit this menu"] = "Éditer le menu"; +$a->strings["New Menu"] = "Nouveau menu"; +$a->strings["Menu name"] = "Nom du menu"; +$a->strings["Must be unique, only seen by you"] = "Doit être unique, ne sera vu que par vous"; +$a->strings["Menu title"] = "Titre du menu"; +$a->strings["Menu title as seen by others"] = "Titre du menu tel que vu par les visiteurs"; +$a->strings["Allow bookmarks"] = "Autoriser l'usage de favoris"; +$a->strings["Menu may be used to store saved bookmarks"] = "Le menu pourra être utilisé pour stocker des favoris"; +$a->strings["Menu deleted."] = "Menu supprimé."; +$a->strings["Menu could not be deleted."] = "Impossible de supprimer le menu."; +$a->strings["Edit Menu"] = "Éditer le menu"; +$a->strings["Add or remove entries to this menu"] = "Ajouter/supprimer des entrées à ce menu"; +$a->strings["Conversation removed."] = "Conversation supprimée."; +$a->strings["No messages."] = "Pas de message."; +$a->strings["D, d M Y - g:i A"] = "D d Y - H:i"; +$a->strings["Add a Channel"] = "Ajouter un canal"; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = "Un canal est une collection de pages web reliées entre elles, sous votre contrôle. Il peut contenir des profils de réseau social, des blogs, des groupes de conversation, des forums, des pages de célébrités, et bien plus encore. Vous pouvez créer autant de canaux que votre administrateur de hub vous y autorise."; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = "Exemples : \"Bob Jameson\", \"Lisa et ses chevaux sauvages\", \"Football\", \"Groupe des amateurs de tir à l'arc\""; +$a->strings["Choose a short nickname"] = "Choisissez un alias"; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "Cet alias sera utilisé pour créer une adresse de canal, facile à retenir - un peu comme une adresse de courriel - que vous pourrez partager avec d'autres."; +$a->strings["Or import an existing channel from another location"] = "Ou importez un canal existant à un autre endroit"; +$a->strings["Invalid request identifier."] = "Identifiant de requête invalide."; +$a->strings["Discard"] = "Annuler"; +$a->strings["No more system notifications."] = "Pas d'autre notification du système."; +$a->strings["System Notifications"] = "Notifications du système"; +$a->strings["Unable to find your hub."] = "Impossible de trouver votre hub."; +$a->strings["Post successful."] = "Contribution effectuée."; +$a->strings["invalid target signature"] = "signature de la cible invalide"; +$a->strings["OpenID protocol error. No ID returned."] = "Erreur du protocole OpenID. Pas d'ID retourné."; +$a->strings["App installed."] = "Application installée."; +$a->strings["Malformed app."] = "Erreur de l'application - Malformée."; +$a->strings["Embed code"] = "Code intégré"; +$a->strings["Edit App"] = "Edition de l'Application"; +$a->strings["Create App"] = "Création d'une Application"; +$a->strings["Name of app"] = "Nom de l'application"; +$a->strings["Location (URL) of app"] = "Emplacement (Lien) vers l'application"; +$a->strings["Photo icon URL"] = "Lien (URL) de l'icône à utiliser pour cette photo"; +$a->strings["80 x 80 pixels - optional"] = "80 x 80 pixels - optionel"; +$a->strings["Version ID"] = "Version"; +$a->strings["Price of app"] = "Prix de l'application"; +$a->strings["Location (URL) to purchase app"] = "Emplacement (LIEN) pour l'achat de l'application"; +$a->strings["Poll"] = "Sondage"; +$a->strings["View Results"] = "Voir les Résultats"; +$a->strings["Friendica Photo Album Import"] = "Importer votre Album Photo Friendica"; +$a->strings["This will import all your Friendica photo albums to this Red channel."] = "Cette fonction va importer tous vos albums photos Friendica dans ce canal de la Matrice Rouge."; +$a->strings["Friendica Server base URL"] = "URL vers le serveur Friendica"; +$a->strings["Friendica Login Username"] = "Nom d'utilisateur Friendica"; +$a->strings["Friendica Login Password"] = "Mot de passe Friendica"; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = "Il est impossible de supprimer un compte à l'intérieur de 48 heures après avoir changé le mot de passe d'un compte."; +$a->strings["Remove This Account"] = "Supprimer ce Compte"; +$a->strings["This will completely remove this account including all its channels from the network. Once this has been done it is not recoverable."] = "Cette fonction va complètement supprimer le compte incluant tous ses canaux sur la matrice. Attention, cette action est irréversible."; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = "Supprimer ce compte, tous ses canaux et tous les clones sur la matrice."; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = "Par défault, seuls les instances de canaux situés sur ce hub seront supprimer de la matrice."; +$a->strings["Schema Default"] = "Par défault"; +$a->strings["Sans-Serif"] = "Sans-Serif"; +$a->strings["Monospace"] = "Monospace"; +$a->strings["Theme settings"] = "Réglages du thème"; +$a->strings["Set scheme"] = "Définir la palette de couleurs"; +$a->strings["Set font-size for posts and comments"] = "Définir font-size pour contribution et commentaires"; +$a->strings["Set font face"] = "Définir la fonte"; +$a->strings["Set iconset"] = "Définir le jeu d'icônes"; +$a->strings["Set big shadow size, default 15px 15px 15px"] = "Définir la taille des grandes ombres, par défaut 15px 15px 15px"; +$a->strings["Set small shadow size, default 5px 5px 5px"] = "Définir la taille des petites ombres, par défaut 5px 5px 5px"; +$a->strings["Set shadow color, default #000"] = "Définir la couleur des ombres, par défaut #000"; +$a->strings["Set radius size, default 5px"] = "Définir le rayon des arrondis, par défaut 5px"; +$a->strings["Set line-height for posts and comments"] = "Définir line-height pour contributions et commentaires"; +$a->strings["Set background image"] = "Définir l'image d'arrière-plan"; +$a->strings["Set background attachment"] = "Image de fond - fichier"; +$a->strings["Set background color"] = "Définir la couleur d'arrière-plan"; +$a->strings["Set section background image"] = "Définir l'image d'arrière-plan des sections"; +$a->strings["Set section background color"] = "Définir la couleur d'arrière-plan des sections"; +$a->strings["Set color of items - use hex"] = "Définir la couleur des éléments - en héxadécimal"; +$a->strings["Set color of links - use hex"] = "Définir la couleur des liens - en héxadécimal"; +$a->strings["Set max-width for items. Default 400px"] = "Définir la largeur maximal des éléments. Par défaut, 400px"; +$a->strings["Set min-width for items. Default 240px"] = "Définir la largeur minimale des éléments. Par défaut, 240px"; +$a->strings["Set the generic content wrapper width. Default 48%"] = "Définir la largeur du contenu. Par défaut, 48%"; +$a->strings["Set color of fonts - use hex"] = "Définir la couleur des fontes - en héxadécimal"; +$a->strings["Set background-size element"] = "Définir background-size pour les éléments"; +$a->strings["Item opacity"] = "Opacité des éléments"; +$a->strings["Display post previews only"] = "Afficher seulement l'aperçu des contributions"; +$a->strings["Display side bar on channel page"] = "Afficher le panneau latéral sur la page du canal"; +$a->strings["Colour of the navigation bar"] = "Couleur de la barre de navigation"; +$a->strings["Item float"] = "Alignement de l'élément"; +$a->strings["Left offset of the section element"] = "Décalage gauche de l'élément section"; +$a->strings["Right offset of the section element"] = "Décalage droit de l'élément section"; +$a->strings["Section width"] = "Largeur de la section"; +$a->strings["Left offset of the aside"] = "Décalage gauche du panneau latéral"; +$a->strings["Right offset of the aside element"] = "Décalage droit du panneau latéral"; +$a->strings["None"] = "Aucun"; +$a->strings["Header image"] = "Image de l'entête"; +$a->strings["Header image only on profile pages"] = "Image de l'entête tel qu'elle est affichée sur la page du profil"; +$a->strings["Light (Hubzilla default)"] = "Blanc (valeur par défaut)"; +$a->strings["Narrow navbar"] = "Barre de navigation fine"; +$a->strings["Navigation bar background color"] = "Couleur de fond de la barre de navigation"; +$a->strings["Navigation bar gradient top color"] = "Gradient de la barre de navigation HAUT"; +$a->strings["Navigation bar gradient bottom color"] = "Gradient de la barre de navigation BAS"; +$a->strings["Navigation active button gradient top color"] = "Gradient du bouton de navigation HAUT"; +$a->strings["Navigation active button gradient bottom color"] = "Gradient du bouton de navigation BAS"; +$a->strings["Navigation bar border color "] = "Couleur de la bordure de la barre de navigation"; +$a->strings["Navigation bar icon color "] = "Couleur de l'icône de la barre de navigation"; +$a->strings["Navigation bar active icon color "] = "Couleur de l'icône active de la barre de navigation"; +$a->strings["link color"] = "couleur des liens"; +$a->strings["Set font-color for banner"] = "Définir la couleur du texte de la bannière"; +$a->strings["Set the background color"] = "Définir la couleur d'arrière-plan"; +$a->strings["Set the background image"] = "Définir l'image d'arrière-plan"; +$a->strings["Set the background color of items"] = "Définir la couleur de fond des contributions"; +$a->strings["Set the background color of comments"] = "Couleur de fond des commentaires"; +$a->strings["Set the border color of comments"] = "Couleur de la bordure des commentaires"; +$a->strings["Set the indent for comments"] = "Indentation des commentaires"; +$a->strings["Set the basic color for item icons"] = "Définir la couleur de base pour les icônes des éléments"; +$a->strings["Set the hover color for item icons"] = "Définir la couleur de survol des icônes des éléments"; +$a->strings["Set font-size for the entire application"] = "Définir la taille de police pour l'application entière"; +$a->strings["Set font-color for posts and comments"] = "Définir font-colour pour les contributions et commentaires"; +$a->strings["Set radius of corners"] = "Définir le rayon des arrondis"; +$a->strings["Set shadow depth of photos"] = "Définir la profondeur de l'ombre des photos"; +$a->strings["Set maximum width of conversation regions"] = "Définir la largeur maximale des conversations"; +$a->strings["Center conversation regions"] = "Emplacement de la conversation - Centrer"; +$a->strings["Set minimum opacity of nav bar - to hide it"] = "Définir l'opacité minimum du bandeau de navigation - pour le cacher"; +$a->strings["Set size of conversation author photo"] = "Définir la taille de la photo de l'auteur d'une conversation"; +$a->strings["Set size of followup author photos"] = "Définir la taille de la photo de l'auteur d'une réponse"; +$a->strings["Sloppy photo albums"] = "Albums photo \"en biais\""; +$a->strings["Are you a clean desk or a messy desk person?"] = "Vous êtes plutôt \"bureau bien rangé\" ou \"gros foutoir\"?"; +$a->strings["Update %s failed. See error logs."] = "La mise à jour %s a échoué. Merci de consulter les journaux d'erreur."; +$a->strings["Update Error at %s"] = "Erreur de mise à jour sur %s"; +$a->strings["Create an account to access services and applications within the Hubzilla"] = "Créez un compte pour pouvoir accéder aux services et applications de la Matrice Red"; +$a->strings["Password"] = "Mot de passe"; +$a->strings["Remember me"] = "Se souvenir de moi"; +$a->strings["Forgot your password?"] = "Mot de passe oublié?"; +$a->strings["permission denied"] = "permission refusée"; +$a->strings["Got Zot?"] = "Authentification magique a échouée. Êtes-vous toujours connecté à votre HUB?"; +$a->strings["toggle mobile"] = "(dés)activer mobile"; diff --git a/sources/view/fr/update_fail_eml.tpl b/sources/view/fr/update_fail_eml.tpl new file mode 100644 index 00000000..5fbad2c8 --- /dev/null +++ b/sources/view/fr/update_fail_eml.tpl @@ -0,0 +1,16 @@ +Bonjour, +Je suis le serveur web de {{$sitename}}; + +Les développeurs de la Matrice Rouge ont lancé une mise à jour {{$update}} récemment, +toutefois, lorsque j'ai essayé de l'installer, quelques choses d'inattendu s'est produit. + +Nous devons corriger la situation et cela requiert votre intervention. + +Veuillez contacter un développeur de la Matrice Rouge si vous avez des difficultés à déterminer +la meilleure approche pour résoudre le problème. Ma base de donnée est peut-être corrompue. + +Le message d'erreur est '{{$error}}'. + +Veuillez accepter mes plus humbles excuses pour les désagréments, + + votre serveur web a {{$siteurl}} \ No newline at end of file diff --git a/sources/view/img/dicons.png b/sources/view/img/dicons.png new file mode 100644 index 00000000..67c8f3f0 Binary files /dev/null and b/sources/view/img/dicons.png differ diff --git a/sources/view/img/jslider.png b/sources/view/img/jslider.png new file mode 100644 index 00000000..12d26cca Binary files /dev/null and b/sources/view/img/jslider.png differ diff --git a/sources/view/img/notifications.png b/sources/view/img/notifications.png new file mode 100644 index 00000000..66c432ea Binary files /dev/null and b/sources/view/img/notifications.png differ diff --git a/sources/view/it/htconfig.tpl b/sources/view/it/htconfig.tpl new file mode 100644 index 00000000..cc4087f9 --- /dev/null +++ b/sources/view/it/htconfig.tpl @@ -0,0 +1,70 @@ +config['system']['baseurl'] = '{{$siteurl}}'; +$a->config['system']['sitename'] = "Hubzilla"; +$a->config['system']['location_hash'] = '{{$site_id}}'; + +// Your choices are REGISTER_OPEN, REGISTER_APPROVE, or REGISTER_CLOSED. +// Be certain to create your own personal account before setting +// REGISTER_CLOSED. 'register_text' (if set) will be displayed prominently on +// the registration page. REGISTER_APPROVE requires you set 'admin_email' +// to the email address of an already registered person who can authorise +// and/or approve/deny the request. + +$a->config['system']['register_policy'] = REGISTER_OPEN; +$a->config['system']['register_text'] = ''; +$a->config['system']['admin_email'] = '{{$adminmail}}'; + +// Maximum size of an imported message, 0 is unlimited + +$a->config['system']['max_import_size'] = 200000; + +// maximum size of uploaded photos + +$a->config['system']['maximagesize'] = 8000000; + +// Location of PHP command line processor + +$a->config['system']['php_path'] = '{{$phpath}}'; + +// Configure how we communicate with directory servers. +// DIRECTORY_MODE_NORMAL = directory client, we will find a directory +// DIRECTORY_MODE_SECONDARY = caching directory or mirror +// DIRECTORY_MODE_PRIMARY = main directory server +// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services + +$a->config['system']['directory_mode'] = DIRECTORY_MODE_NORMAL; + +// default system theme + +$a->config['system']['theme'] = 'redbasic'; + diff --git a/sources/view/it/lostpass_eml.tpl b/sources/view/it/lostpass_eml.tpl new file mode 100644 index 00000000..20a65faa --- /dev/null +++ b/sources/view/it/lostpass_eml.tpl @@ -0,0 +1,32 @@ + +Ciao {{$username}}, + Su {{$sitename}} è arrivata la richiesta di azzerare la password del tuo account. +Per dare conferma, devi cliccare sul link di verifica che trovi qua sotto, +oppure puoi copiarlo e incollarlo sul tuo browser. + +Se NON hai richiesto tu il cambio password, NON cliccare assolutamente il link +e ignora (o cancella) questo messaggio. + +Così la tua password non cambierà finché non sarà certo +che la richiesta venga realmente da te! + +Questo è il link per confermare e verificare la tua identità: + +{{$reset_link}} + +Dopo riceverai un messaggio che conterrà la nuova password. + +Naturalmente potrai cambiarla dalla pagina delle 'Impostazioni' dopo aver effettuato l'accesso. + +I dettagli del tuo account: + +Sito: {{$siteurl}} +Nome utente: {{$email}} + + + + +Con affetto, + L'amministratore di {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/it/messages.po b/sources/view/it/messages.po new file mode 100644 index 00000000..4a0117f9 --- /dev/null +++ b/sources/view/it/messages.po @@ -0,0 +1,8934 @@ +# Hubzilla Project +# Copyright (C) 2012-2014 the Hubzilla Project +# This file is distributed under the same license as the Red package. +# +# Translators: +# fabrixxm , 2011 +# fabrixxm , 2011-2012 +# Francesco Apruzzese , 2012-2013 +# ufic , 2012 +# tuscanhobbit , 2012 +# tuscanhobbit , 2013-2015 +msgid "" +msgstr "" +"Project-Id-Version: Hubzilla\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2015-04-24 00:03-0700\n" +"PO-Revision-Date: 2015-05-04 14:29+0000\n" +"Last-Translator: tuscanhobbit \n" +"Language-Team: Italian (http://www.transifex.com/projects/p/red-matrix/language/it/)\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: it\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#: ../../include/dba/dba_driver.php:141 +#, php-format +msgid "Cannot locate DNS info for database server '%s'" +msgstr "Non trovo le informazioni DNS per il database server '%s'" + +#: ../../include/photo/photo_driver.php:687 ../../mod/profile_photo.php:143 +#: ../../mod/profile_photo.php:302 ../../mod/profile_photo.php:424 +#: ../../mod/photos.php:91 ../../mod/photos.php:625 +msgid "Profile Photos" +msgstr "Foto del profilo" + +#: ../../include/security.php:349 +msgid "" +"The form security token was not correct. This probably happened because the " +"form has been opened for too long (>3 hours) before submitting it." +msgstr "I controlli di sicurezza sono falliti. Probabilmente è accaduto perché la pagina è stata tenuta aperta troppo a lungo (ore?) prima di inviare il contenuto." + +#: ../../include/notify.php:23 +msgid "created a new post" +msgstr "Ha creato un nuovo articolo" + +#: ../../include/notify.php:24 +#, php-format +msgid "commented on %s's post" +msgstr "ha commentato l'articolo di %s" + +#: ../../include/group.php:26 +msgid "" +"A deleted group with this name was revived. Existing item permissions " +"may apply to this group and any future members. If this is " +"not what you intended, please create another group with a different name." +msgstr "È stato ripristinato un insieme con lo stesso nome che era stato eliminato in precedenza. I permessi già presenti potrebbero rimanere validi per i nuovi canali. Se non vuoi che ciò accada, devi creare un altro insieme con un nome diverso." + +#: ../../include/group.php:235 +msgid "Default privacy group for new contacts" +msgstr "Insieme predefinito per i canali che inizi a seguire" + +#: ../../include/group.php:254 ../../mod/admin.php:822 +msgid "All Channels" +msgstr "Tutti i canali" + +#: ../../include/group.php:276 +msgid "edit" +msgstr "modifica" + +#: ../../include/group.php:298 +msgid "Collections" +msgstr "Insiemi di canali" + +#: ../../include/group.php:299 +msgid "Edit collection" +msgstr "Modifica l'insieme di canali" + +#: ../../include/group.php:300 +msgid "Add new collection" +msgstr "Nuovo insieme" + +#: ../../include/group.php:301 +msgid "Channels not in any collection" +msgstr "Canali che non sono in un insieme" + +#: ../../include/group.php:303 ../../include/widgets.php:275 +msgid "add" +msgstr "aggiungi" + +#: ../../include/account.php:27 +msgid "Not a valid email address" +msgstr "Email non valida" + +#: ../../include/account.php:29 +msgid "Your email domain is not among those allowed on this site" +msgstr "Il dominio della tua email attualmente non è permesso su questo sito" + +#: ../../include/account.php:35 +msgid "Your email address is already registered at this site." +msgstr "La tua email è già registrata su questo sito." + +#: ../../include/account.php:67 +msgid "An invitation is required." +msgstr "È necessario un invito." + +#: ../../include/account.php:71 +msgid "Invitation could not be verified." +msgstr "L'invito non può essere verificato." + +#: ../../include/account.php:121 +msgid "Please enter the required information." +msgstr "Inserisci le informazioni richieste." + +#: ../../include/account.php:188 +msgid "Failed to store account information." +msgstr "Non è stato possibile salvare le informazioni del tuo account." + +#: ../../include/account.php:246 +#, php-format +msgid "Registration confirmation for %s" +msgstr "Registrazione di %s confermata" + +#: ../../include/account.php:312 +#, php-format +msgid "Registration request at %s" +msgstr "Richiesta di registrazione su %s" + +#: ../../include/account.php:314 ../../include/account.php:341 +#: ../../include/account.php:401 +msgid "Administrator" +msgstr "Amministratore" + +#: ../../include/account.php:336 +msgid "your registration password" +msgstr "la password di registrazione" + +#: ../../include/account.php:339 ../../include/account.php:399 +#, php-format +msgid "Registration details for %s" +msgstr "Dettagli della registrazione di %s" + +#: ../../include/account.php:408 +msgid "Account approved." +msgstr "Account approvato." + +#: ../../include/account.php:447 +#, php-format +msgid "Registration revoked for %s" +msgstr "Registrazione revocata per %s" + +#: ../../include/account.php:492 +msgid "Account verified. Please login." +msgstr "Registrazione verificata. Adesso puoi effettuare login." + +#: ../../include/account.php:705 ../../include/account.php:707 +msgid "Click here to upgrade." +msgstr "Clicca qui per aggiornare." + +#: ../../include/account.php:713 +msgid "This action exceeds the limits set by your subscription plan." +msgstr "Questa operazione supera i limiti del tuo abbonamento." + +#: ../../include/account.php:718 +msgid "This action is not available under your subscription plan." +msgstr "Questa operazione non è prevista dal tuo abbonamento." + +#: ../../include/datetime.php:48 +msgid "Miscellaneous" +msgstr "Altro" + +#: ../../include/datetime.php:132 +msgid "YYYY-MM-DD or MM-DD" +msgstr "AAAA-MM-GG oppure MM-GG" + +#: ../../include/datetime.php:235 ../../mod/events.php:635 +#: ../../mod/appman.php:91 ../../mod/appman.php:92 +msgid "Required" +msgstr "Obbligatorio" + +#: ../../include/datetime.php:262 ../../boot.php:2342 +msgid "never" +msgstr "mai" + +#: ../../include/datetime.php:268 +msgid "less than a second ago" +msgstr "meno di un secondo fa" + +#: ../../include/datetime.php:271 +msgid "year" +msgstr "anno" + +#: ../../include/datetime.php:271 +msgid "years" +msgstr "anni" + +#: ../../include/datetime.php:272 +msgid "month" +msgstr "mese" + +#: ../../include/datetime.php:272 +msgid "months" +msgstr "mesi" + +#: ../../include/datetime.php:273 +msgid "week" +msgstr "settimana" + +#: ../../include/datetime.php:273 +msgid "weeks" +msgstr "settimane" + +#: ../../include/datetime.php:274 +msgid "day" +msgstr "giorno" + +#: ../../include/datetime.php:274 +msgid "days" +msgstr "giorni" + +#: ../../include/datetime.php:275 +msgid "hour" +msgstr "ora" + +#: ../../include/datetime.php:275 +msgid "hours" +msgstr "ore" + +#: ../../include/datetime.php:276 +msgid "minute" +msgstr "minuto" + +#: ../../include/datetime.php:276 +msgid "minutes" +msgstr "minuti" + +#: ../../include/datetime.php:277 +msgid "second" +msgstr "secondo" + +#: ../../include/datetime.php:277 +msgid "seconds" +msgstr "secondi" + +#: ../../include/datetime.php:285 +#, php-format +msgctxt "e.g. 22 hours ago, 1 minute ago" +msgid "%1$d %2$s ago" +msgstr "%1$d %2$s fa" + +#: ../../include/datetime.php:519 +#, php-format +msgid "%1$s's birthday" +msgstr "Compleanno di %1$s" + +#: ../../include/datetime.php:520 +#, php-format +msgid "Happy Birthday %1$s" +msgstr "Buon compleanno %1$s" + +#: ../../include/page_widgets.php:6 +msgid "New Page" +msgstr "Nuova pagina web" + +#: ../../include/page_widgets.php:8 ../../include/page_widgets.php:36 +#: ../../include/RedDAV/RedBrowser.php:269 ../../include/ItemObject.php:100 +#: ../../include/apps.php:254 ../../include/menu.php:43 +#: ../../mod/settings.php:644 ../../mod/thing.php:227 +#: ../../mod/connections.php:382 ../../mod/connections.php:395 +#: ../../mod/connections.php:414 ../../mod/editlayout.php:139 +#: ../../mod/editwebpage.php:178 ../../mod/editpost.php:113 +#: ../../mod/menu.php:100 ../../mod/webpages.php:179 +#: ../../mod/editblock.php:140 ../../mod/blocks.php:148 +#: ../../mod/layouts.php:174 +msgid "Edit" +msgstr "Modifica" + +#: ../../include/page_widgets.php:39 ../../mod/webpages.php:185 +#: ../../mod/blocks.php:154 ../../mod/layouts.php:178 +msgid "View" +msgstr "Guarda" + +#: ../../include/page_widgets.php:40 ../../include/ItemObject.php:677 +#: ../../include/conversation.php:1153 ../../mod/events.php:653 +#: ../../mod/photos.php:970 ../../mod/editwebpage.php:214 +#: ../../mod/editpost.php:149 ../../mod/webpages.php:186 +#: ../../mod/editblock.php:176 +msgid "Preview" +msgstr "Anteprima" + +#: ../../include/page_widgets.php:41 ../../mod/webpages.php:187 +msgid "Actions" +msgstr "Azioni" + +#: ../../include/page_widgets.php:42 ../../mod/webpages.php:188 +msgid "Page Link" +msgstr "Link alla pagina" + +#: ../../include/page_widgets.php:43 +msgid "Title" +msgstr "Titolo" + +#: ../../include/page_widgets.php:44 ../../mod/webpages.php:190 +#: ../../mod/blocks.php:145 +msgid "Created" +msgstr "Creato" + +#: ../../include/page_widgets.php:45 ../../mod/webpages.php:191 +#: ../../mod/blocks.php:146 +msgid "Edited" +msgstr "Modificato" + +#: ../../include/api.php:1158 +msgid "Public Timeline" +msgstr "Diario pubblico" + +#: ../../include/comanche.php:34 ../../mod/admin.php:386 +#: ../../view/theme/apw/php/config.php:185 +msgid "Default" +msgstr "Predefinito" + +#: ../../include/dir_fns.php:143 +msgid "Directory Options" +msgstr "Opzioni elenco pubblico" + +#: ../../include/dir_fns.php:144 +msgid "Alphabetic" +msgstr "Alfabetico" + +#: ../../include/dir_fns.php:145 +msgid "Reverse Alphabetic" +msgstr "Alfabetico inverso" + +#: ../../include/dir_fns.php:146 +msgid "Newest to Oldest" +msgstr "Prima i più recenti" + +#: ../../include/dir_fns.php:147 +msgid "Oldest to Newest" +msgstr "Prima i più vecchi" + +#: ../../include/dir_fns.php:148 +msgid "Sort" +msgstr "Ordinamento" + +#: ../../include/dir_fns.php:152 +msgid "Safe Mode" +msgstr "Modalità SafeSearch" + +#: ../../include/dir_fns.php:154 +msgid "Public Forums Only" +msgstr "Solo forum pubblici" + +#: ../../include/dir_fns.php:155 +msgid "This Website Only" +msgstr "Solo in questo sito" + +#: ../../include/event.php:19 ../../include/bb2diaspora.php:451 +msgid "l F d, Y \\@ g:i A" +msgstr "l d F Y \\@ G:i" + +#: ../../include/event.php:27 ../../include/bb2diaspora.php:457 +msgid "Starts:" +msgstr "Inizio:" + +#: ../../include/event.php:37 ../../include/bb2diaspora.php:465 +msgid "Finishes:" +msgstr "Fine:" + +#: ../../include/event.php:47 ../../include/bb2diaspora.php:473 +#: ../../include/identity.php:874 ../../mod/events.php:647 +#: ../../mod/directory.php:234 +msgid "Location:" +msgstr "Luogo:" + +#: ../../include/event.php:391 +msgid "This event has been added to your calendar." +msgstr "Questo evento è stato aggiunto al tuo calendario" + +#: ../../include/js_strings.php:5 +msgid "Delete this item?" +msgstr "Eliminare questo elemento?" + +#: ../../include/js_strings.php:6 ../../include/ItemObject.php:667 +#: ../../mod/photos.php:968 ../../mod/photos.php:1086 +msgid "Comment" +msgstr "Commento" + +#: ../../include/js_strings.php:7 ../../include/ItemObject.php:384 +msgid "[+] show all" +msgstr "[+] mostra tutto" + +#: ../../include/js_strings.php:8 +msgid "[-] show less" +msgstr "[-] riduci" + +#: ../../include/js_strings.php:9 +msgid "[+] expand" +msgstr "[+] mostra tutto" + +#: ../../include/js_strings.php:10 +msgid "[-] collapse" +msgstr "[-] riduci" + +#: ../../include/js_strings.php:11 +msgid "Password too short" +msgstr "Password troppo corta" + +#: ../../include/js_strings.php:12 +msgid "Passwords do not match" +msgstr "Le password non corrispondono" + +#: ../../include/js_strings.php:13 ../../mod/photos.php:39 +msgid "everybody" +msgstr "tutti" + +#: ../../include/js_strings.php:14 +msgid "Secret Passphrase" +msgstr "Chiave segreta" + +#: ../../include/js_strings.php:15 +msgid "Passphrase hint" +msgstr "Suggerimento per la chiave segreta" + +#: ../../include/js_strings.php:16 +msgid "Notice: Permissions have changed but have not yet been submitted." +msgstr "Nota: i permessi sono stati modificati ma non ancora salvati." + +#: ../../include/js_strings.php:17 +msgid "close all" +msgstr "chiudi tutto" + +#: ../../include/js_strings.php:18 +msgid "Nothing new here" +msgstr "Niente di nuovo qui" + +#: ../../include/js_strings.php:19 +msgid "Rate This Channel (this is public)" +msgstr "Valuta questo canale (visibile a tutti)" + +#: ../../include/js_strings.php:20 ../../mod/rate.php:156 +msgid "Rating" +msgstr "Valutazioni" + +#: ../../include/js_strings.php:21 +msgid "Describe (optional)" +msgstr "Descrizione (facoltativa)" + +#: ../../include/js_strings.php:22 ../../include/ItemObject.php:668 +#: ../../mod/settings.php:582 ../../mod/settings.php:684 +#: ../../mod/settings.php:710 ../../mod/settings.php:738 +#: ../../mod/settings.php:761 ../../mod/settings.php:843 +#: ../../mod/settings.php:1039 ../../mod/xchan.php:11 ../../mod/connect.php:93 +#: ../../mod/thing.php:275 ../../mod/thing.php:318 ../../mod/events.php:656 +#: ../../mod/group.php:81 ../../mod/setup.php:313 ../../mod/setup.php:358 +#: ../../mod/photos.php:565 ../../mod/photos.php:642 ../../mod/photos.php:929 +#: ../../mod/photos.php:969 ../../mod/photos.php:1087 ../../mod/pdledit.php:58 +#: ../../mod/import.php:504 ../../mod/chat.php:177 ../../mod/chat.php:211 +#: ../../mod/rate.php:167 ../../mod/invite.php:142 ../../mod/locs.php:105 +#: ../../mod/sources.php:104 ../../mod/sources.php:138 +#: ../../mod/filestorage.php:156 ../../mod/fsuggest.php:108 +#: ../../mod/poke.php:166 ../../mod/profiles.php:667 ../../mod/mitem.php:229 +#: ../../mod/admin.php:446 ../../mod/admin.php:810 ../../mod/admin.php:946 +#: ../../mod/admin.php:1077 ../../mod/admin.php:1271 ../../mod/admin.php:1356 +#: ../../mod/mood.php:134 ../../mod/connedit.php:679 ../../mod/mail.php:355 +#: ../../mod/appman.php:99 ../../mod/poll.php:68 ../../mod/bulksetclose.php:24 +#: ../../view/theme/apw/php/config.php:256 +#: ../../view/theme/redbasic/php/config.php:97 +msgid "Submit" +msgstr "Salva" + +#: ../../include/js_strings.php:23 +msgid "Please enter a link URL" +msgstr "Inserisci l'URL di un link" + +#: ../../include/js_strings.php:24 +msgid "Unsaved changes. Are you sure you wish to leave this page?" +msgstr "Non hai salvato i cambiamenti. Vuoi davvero lasciare questa pagina?" + +#: ../../include/js_strings.php:26 +msgid "timeago.prefixAgo" +msgstr "timeago.prefixAgo" + +#: ../../include/js_strings.php:27 +msgid "timeago.prefixFromNow" +msgstr "timeago.prefixFromNow" + +#: ../../include/js_strings.php:28 +msgid "ago" +msgstr "fa" + +#: ../../include/js_strings.php:29 +msgid "from now" +msgstr "da adesso" + +#: ../../include/js_strings.php:30 +msgid "less than a minute" +msgstr "meno di un minuto" + +#: ../../include/js_strings.php:31 +msgid "about a minute" +msgstr "circa un minuto" + +#: ../../include/js_strings.php:32 +#, php-format +msgid "%d minutes" +msgstr "%d minuti" + +#: ../../include/js_strings.php:33 +msgid "about an hour" +msgstr "circa un’ora" + +#: ../../include/js_strings.php:34 +#, php-format +msgid "about %d hours" +msgstr "circa %d ore" + +#: ../../include/js_strings.php:35 +msgid "a day" +msgstr "un giorno" + +#: ../../include/js_strings.php:36 +#, php-format +msgid "%d days" +msgstr "%d giorni" + +#: ../../include/js_strings.php:37 +msgid "about a month" +msgstr "circa un mese" + +#: ../../include/js_strings.php:38 +#, php-format +msgid "%d months" +msgstr "%d mesi" + +#: ../../include/js_strings.php:39 +msgid "about a year" +msgstr "circa un anno" + +#: ../../include/js_strings.php:40 +#, php-format +msgid "%d years" +msgstr "%d anni" + +#: ../../include/js_strings.php:41 +msgid " " +msgstr " " + +#: ../../include/js_strings.php:42 +msgid "timeago.numbers" +msgstr "timeago.numbers" + +#: ../../include/RedDAV/RedBrowser.php:107 +#: ../../include/RedDAV/RedBrowser.php:268 +msgid "parent" +msgstr "cartella superiore" + +#: ../../include/RedDAV/RedBrowser.php:131 ../../include/text.php:2479 +msgid "Collection" +msgstr "Cartella" + +#: ../../include/RedDAV/RedBrowser.php:134 +msgid "Principal" +msgstr "Principale" + +#: ../../include/RedDAV/RedBrowser.php:137 +msgid "Addressbook" +msgstr "Rubrica" + +#: ../../include/RedDAV/RedBrowser.php:140 +msgid "Calendar" +msgstr "Calendario" + +#: ../../include/RedDAV/RedBrowser.php:143 +msgid "Schedule Inbox" +msgstr "Appuntamenti ricevuti" + +#: ../../include/RedDAV/RedBrowser.php:146 +msgid "Schedule Outbox" +msgstr "Appuntamenti inviati" + +#: ../../include/RedDAV/RedBrowser.php:164 ../../include/conversation.php:1019 +#: ../../include/apps.php:336 ../../include/apps.php:387 +#: ../../mod/photos.php:681 ../../mod/photos.php:1119 +msgid "Unknown" +msgstr "Sconosciuto" + +#: ../../include/RedDAV/RedBrowser.php:227 +#, php-format +msgid "%1$s used" +msgstr "%1$s occupati" + +#: ../../include/RedDAV/RedBrowser.php:232 +#, php-format +msgid "%1$s used of %2$s (%3$s%)" +msgstr "%1$s occupati di %2$s (%3$s%)" + +#: ../../include/RedDAV/RedBrowser.php:251 ../../include/nav.php:98 +#: ../../include/conversation.php:1606 ../../include/apps.php:135 +#: ../../mod/fbrowser.php:114 +msgid "Files" +msgstr "Archivio file" + +#: ../../include/RedDAV/RedBrowser.php:253 +msgid "Total" +msgstr "Totale" + +#: ../../include/RedDAV/RedBrowser.php:255 +msgid "Shared" +msgstr "Condiviso" + +#: ../../include/RedDAV/RedBrowser.php:256 +#: ../../include/RedDAV/RedBrowser.php:306 ../../mod/menu.php:104 +#: ../../mod/webpages.php:178 ../../mod/blocks.php:147 +#: ../../mod/layouts.php:170 ../../mod/new_channel.php:121 +msgid "Create" +msgstr "Crea" + +#: ../../include/RedDAV/RedBrowser.php:257 +#: ../../include/RedDAV/RedBrowser.php:308 ../../mod/profile_photo.php:362 +#: ../../mod/photos.php:706 ../../mod/photos.php:1236 +msgid "Upload" +msgstr "Carica" + +#: ../../include/RedDAV/RedBrowser.php:264 ../../mod/settings.php:584 +#: ../../mod/settings.php:610 ../../mod/admin.php:953 +#: ../../mod/sharedwithme.php:95 +msgid "Name" +msgstr "Nome" + +#: ../../include/RedDAV/RedBrowser.php:265 +msgid "Type" +msgstr "Tipo" + +#: ../../include/RedDAV/RedBrowser.php:266 ../../mod/sharedwithme.php:97 +msgid "Size" +msgstr "Dimensione" + +#: ../../include/RedDAV/RedBrowser.php:267 ../../mod/sharedwithme.php:98 +msgid "Last Modified" +msgstr "Ultima modifica" + +#: ../../include/RedDAV/RedBrowser.php:270 ../../include/ItemObject.php:120 +#: ../../include/conversation.php:660 ../../include/apps.php:255 +#: ../../mod/settings.php:645 ../../mod/thing.php:228 ../../mod/group.php:176 +#: ../../mod/photos.php:1050 ../../mod/editwebpage.php:225 +#: ../../mod/webpages.php:181 ../../mod/admin.php:817 ../../mod/admin.php:948 +#: ../../mod/editblock.php:113 ../../mod/blocks.php:150 +#: ../../mod/connedit.php:543 +msgid "Delete" +msgstr "Elimina" + +#: ../../include/RedDAV/RedBrowser.php:305 +msgid "Create new folder" +msgstr "Crea una nuova cartella" + +#: ../../include/RedDAV/RedBrowser.php:307 +msgid "Upload file" +msgstr "Carica un file" + +#: ../../include/bookmarks.php:35 +#, php-format +msgid "%1$s's bookmarks" +msgstr "I segnalibri di %1$s" + +#: ../../include/network.php:632 +msgid "view full size" +msgstr "guarda nelle dimensioni reali" + +#: ../../include/features.php:38 +msgid "General Features" +msgstr "Funzionalità di base" + +#: ../../include/features.php:40 +msgid "Content Expiration" +msgstr "Scadenza" + +#: ../../include/features.php:40 +msgid "Remove posts/comments and/or private messages at a future time" +msgstr "Elimina gli articoli, i commenti o i messaggi privati dopo un lasso di tempo" + +#: ../../include/features.php:41 +msgid "Multiple Profiles" +msgstr "Profili multipli" + +#: ../../include/features.php:41 +msgid "Ability to create multiple profiles" +msgstr "Abilitazione a creare profili multipli" + +#: ../../include/features.php:42 +msgid "Advanced Profiles" +msgstr "Profili avanzati" + +#: ../../include/features.php:42 +msgid "Additional profile sections and selections" +msgstr "Informazioni aggiuntive del profilo" + +#: ../../include/features.php:43 +msgid "Profile Import/Export" +msgstr "Importa/esporta il profilo" + +#: ../../include/features.php:43 +msgid "Save and load profile details across sites/channels" +msgstr "Salva o ripristina le informazioni del profilo su canali o siti diversi" + +#: ../../include/features.php:44 +msgid "Web Pages" +msgstr "Pagine web" + +#: ../../include/features.php:44 +msgid "Provide managed web pages on your channel" +msgstr "Attiva la creazione di pagine web sul tuo canale" + +#: ../../include/features.php:45 +msgid "Private Notes" +msgstr "Note private" + +#: ../../include/features.php:45 +msgid "Enables a tool to store notes and reminders" +msgstr "Abilita il riquadro per scrivere annotazioni" + +#: ../../include/features.php:46 +msgid "Navigation Channel Select" +msgstr "Scegli il canale attivo dal menu" + +#: ../../include/features.php:46 +msgid "Change channels directly from within the navigation dropdown menu" +msgstr "Scegli il canale attivo direttamente dal menu di navigazione" + +#: ../../include/features.php:47 +msgid "Photo Location" +msgstr "Posizione geografica" + +#: ../../include/features.php:47 +msgid "If location data is available on uploaded photos, link this to a map." +msgstr "Collega la foto a una mappa quando contiene indicazioni geografiche." + +#: ../../include/features.php:49 +msgid "Expert Mode" +msgstr "Modalità esperto" + +#: ../../include/features.php:49 +msgid "Enable Expert Mode to provide advanced configuration options" +msgstr "Abilita la modalità esperto per vedere le opzioni di configurazione avanzate" + +#: ../../include/features.php:50 +msgid "Premium Channel" +msgstr "Canale premium" + +#: ../../include/features.php:50 +msgid "" +"Allows you to set restrictions and terms on those that connect with your " +"channel" +msgstr "Ti permette di impostare delle restrizioni e dei termini d'uso a chi segue il canale" + +#: ../../include/features.php:55 +msgid "Post Composition Features" +msgstr "Modalità di scrittura articoli" + +#: ../../include/features.php:57 +msgid "Use Markdown" +msgstr "Usa il markdown" + +#: ../../include/features.php:57 +msgid "Allow use of \"Markdown\" to format posts" +msgstr "Consenti l'uso del markdown per formattare gli articoli" + +#: ../../include/features.php:58 +msgid "Large Photos" +msgstr "Foto grandi" + +#: ../../include/features.php:58 +msgid "" +"Include large (640px) photo thumbnails in posts. If not enabled, use small " +"(320px) photo thumbnails" +msgstr "Includi anteprime grandi delle foto nei post (640px). Se disabilitato le anteprime saranno piccole (320px)" + +#: ../../include/features.php:59 ../../include/widgets.php:546 +#: ../../mod/sources.php:88 +msgid "Channel Sources" +msgstr "Sorgenti del canale" + +#: ../../include/features.php:59 +msgid "Automatically import channel content from other channels or feeds" +msgstr "Importa automaticamente il contenuto del canale da altri canali o feed" + +#: ../../include/features.php:60 +msgid "Even More Encryption" +msgstr "Crittografia addizionale" + +#: ../../include/features.php:60 +msgid "" +"Allow optional encryption of content end-to-end with a shared secret key" +msgstr "Rendi possibile la crittografia tra mittente e destinatario che condividono una chiave segreta" + +#: ../../include/features.php:61 +msgid "Enable voting tools" +msgstr "Permetti i post con votazione" + +#: ../../include/features.php:61 +msgid "Provide a class of post which others can vote on" +msgstr "Rende possibile la creazione di articoli in cui sarà possibile votare" + +#: ../../include/features.php:67 +msgid "Network and Stream Filtering" +msgstr "Filtraggio dei contenuti" + +#: ../../include/features.php:68 +msgid "Search by Date" +msgstr "Ricerca per data" + +#: ../../include/features.php:68 +msgid "Ability to select posts by date ranges" +msgstr "Per selezionare gli articoli in un intervallo tra date" + +#: ../../include/features.php:69 +msgid "Collections Filter" +msgstr "Filtra per insiemi di canali" + +#: ../../include/features.php:69 +msgid "Enable widget to display Network posts only from selected collections" +msgstr "Mostra il riquadro per filtrare gli articoli di certi insiemi di canali" + +#: ../../include/features.php:70 ../../include/widgets.php:274 +msgid "Saved Searches" +msgstr "Ricerche salvate" + +#: ../../include/features.php:70 +msgid "Save search terms for re-use" +msgstr "Salva i termini delle ricerche per poterle ripetere" + +#: ../../include/features.php:71 +msgid "Network Personal Tab" +msgstr "Attività personale" + +#: ../../include/features.php:71 +msgid "Enable tab to display only Network posts that you've interacted on" +msgstr "Abilita il link per mostrare solamente i contenuti con cui hai interagito" + +#: ../../include/features.php:72 +msgid "Network New Tab" +msgstr "Contenuti nuovi" + +#: ../../include/features.php:72 +msgid "Enable tab to display all new Network activity" +msgstr "Abilita il link per visualizzare solo i nuovi contenuti" + +#: ../../include/features.php:73 +msgid "Affinity Tool" +msgstr "Filtro per affinità" + +#: ../../include/features.php:73 +msgid "Filter stream activity by depth of relationships" +msgstr "Permette di selezionare i contenuti in base al livello di amicizia" + +#: ../../include/features.php:74 +msgid "Suggest Channels" +msgstr "Suggerisci canali" + +#: ../../include/features.php:74 +msgid "Show channel suggestions" +msgstr "Mostra alcuni canali che potrebbero interessarti" + +#: ../../include/features.php:79 +msgid "Post/Comment Tools" +msgstr "Gestione articoli e commenti" + +#: ../../include/features.php:80 +msgid "Tagging" +msgstr "Tag" + +#: ../../include/features.php:80 +msgid "Ability to tag existing posts" +msgstr "Permetti l'aggiunta di tag su articoli già esistenti" + +#: ../../include/features.php:81 +msgid "Post Categories" +msgstr "Categorie degli articoli" + +#: ../../include/features.php:81 +msgid "Add categories to your posts" +msgstr "Abilita le categorie per i tuoi articoli" + +#: ../../include/features.php:82 ../../include/widgets.php:304 +#: ../../include/contact_widgets.php:57 +msgid "Saved Folders" +msgstr "Cartelle salvate" + +#: ../../include/features.php:82 +msgid "Ability to file posts under folders" +msgstr "Abilita la raccolta dei tuoi articoli in cartelle" + +#: ../../include/features.php:83 +msgid "Dislike Posts" +msgstr "Non mi piace" + +#: ../../include/features.php:83 +msgid "Ability to dislike posts/comments" +msgstr "Abilità la funzionalità \"non mi piace\" per i tuoi articoli" + +#: ../../include/features.php:84 +msgid "Star Posts" +msgstr "Articoli stella (preferiti)" + +#: ../../include/features.php:84 +msgid "Ability to mark special posts with a star indicator" +msgstr "Mostra la stella per scegliere gli articoli preferiti" + +#: ../../include/features.php:85 +msgid "Tag Cloud" +msgstr "Nuvola di tag" + +#: ../../include/features.php:85 +msgid "Provide a personal tag cloud on your channel page" +msgstr "Mostra la nuvola dei tag che usi di più sulla pagina del tuo canale" + +#: ../../include/widgets.php:35 ../../include/taxonomy.php:264 +#: ../../include/contact_widgets.php:92 +msgid "Categories" +msgstr "Categorie" + +#: ../../include/widgets.php:91 ../../include/nav.php:163 +#: ../../mod/apps.php:34 +msgid "Apps" +msgstr "Apps" + +#: ../../include/widgets.php:92 +msgid "System" +msgstr "Sistema" + +#: ../../include/widgets.php:94 ../../include/conversation.php:1501 +msgid "Personal" +msgstr "Personali" + +#: ../../include/widgets.php:95 +msgid "Create Personal App" +msgstr "Crea una app personale" + +#: ../../include/widgets.php:96 +msgid "Edit Personal App" +msgstr "Modifica una app personale" + +#: ../../include/widgets.php:136 ../../include/widgets.php:175 +#: ../../include/Contact.php:107 ../../include/conversation.php:945 +#: ../../include/identity.php:823 ../../mod/match.php:64 +#: ../../mod/directory.php:302 ../../mod/suggest.php:52 +msgid "Connect" +msgstr "Aggiungi" + +#: ../../include/widgets.php:138 ../../mod/suggest.php:54 +msgid "Ignore/Hide" +msgstr "Ignora/nascondi" + +#: ../../include/widgets.php:143 ../../mod/connections.php:268 +msgid "Suggestions" +msgstr "Suggerimenti" + +#: ../../include/widgets.php:144 +msgid "See more..." +msgstr "Altro..." + +#: ../../include/widgets.php:166 +#, php-format +msgid "You have %1$.0f of %2$.0f allowed connections." +msgstr "Hai attivato %1$.0f delle %2$.0f connessioni permesse." + +#: ../../include/widgets.php:172 +msgid "Add New Connection" +msgstr "Aggiungi un contatto" + +#: ../../include/widgets.php:173 +msgid "Enter the channel address" +msgstr "Scrivi l'indirizzo del canale" + +#: ../../include/widgets.php:174 +msgid "Example: bob@example.com, http://example.com/barbara" +msgstr "Per esempio: mario@pippo.it oppure http://pluto.com/barbara" + +#: ../../include/widgets.php:190 +msgid "Notes" +msgstr "Note" + +#: ../../include/widgets.php:192 ../../include/text.php:853 +#: ../../include/text.php:865 ../../mod/rbmark.php:28 ../../mod/rbmark.php:98 +#: ../../mod/filer.php:50 ../../mod/admin.php:1416 ../../mod/admin.php:1436 +msgid "Save" +msgstr "Salva" + +#: ../../include/widgets.php:266 +msgid "Remove term" +msgstr "Rimuovi termine" + +#: ../../include/widgets.php:307 ../../include/contact_widgets.php:60 +#: ../../include/contact_widgets.php:95 +msgid "Everything" +msgstr "Tutto" + +#: ../../include/widgets.php:349 +msgid "Archives" +msgstr "Archivi" + +#: ../../include/widgets.php:427 ../../mod/connedit.php:572 +msgid "Me" +msgstr "Io" + +#: ../../include/widgets.php:428 ../../mod/connedit.php:573 +msgid "Family" +msgstr "Famiglia" + +#: ../../include/widgets.php:429 ../../include/identity.php:394 +#: ../../include/identity.php:395 ../../include/identity.php:402 +#: ../../include/profile_selectors.php:80 ../../mod/settings.php:339 +#: ../../mod/settings.php:343 ../../mod/settings.php:344 +#: ../../mod/settings.php:347 ../../mod/settings.php:358 +#: ../../mod/connedit.php:574 +msgid "Friends" +msgstr "Amici" + +#: ../../include/widgets.php:430 ../../mod/connedit.php:575 +msgid "Acquaintances" +msgstr "Conoscenti" + +#: ../../include/widgets.php:431 ../../mod/connections.php:231 +#: ../../mod/connections.php:246 ../../mod/connedit.php:576 +msgid "All" +msgstr "Tutti" + +#: ../../include/widgets.php:450 +msgid "Refresh" +msgstr "Aggiorna" + +#: ../../include/widgets.php:485 +msgid "Account settings" +msgstr "Il tuo account" + +#: ../../include/widgets.php:491 +msgid "Channel settings" +msgstr "Impostazioni del canale" + +#: ../../include/widgets.php:497 +msgid "Additional features" +msgstr "Funzionalità opzionali" + +#: ../../include/widgets.php:503 +msgid "Feature/Addon settings" +msgstr "Impostazioni dei componenti aggiuntivi" + +#: ../../include/widgets.php:509 +msgid "Display settings" +msgstr "Aspetto" + +#: ../../include/widgets.php:515 +msgid "Connected apps" +msgstr "App connesse" + +#: ../../include/widgets.php:521 +msgid "Export channel" +msgstr "Esporta il canale" + +#: ../../include/widgets.php:530 ../../mod/connedit.php:653 +msgid "Connection Default Permissions" +msgstr "Permessi predefiniti dei nuovi contatti" + +#: ../../include/widgets.php:538 +msgid "Premium Channel Settings" +msgstr "Canale premium - impostazioni" + +#: ../../include/widgets.php:554 ../../include/nav.php:208 +#: ../../include/apps.php:134 ../../mod/admin.php:1038 +#: ../../mod/admin.php:1238 +msgid "Settings" +msgstr "Impostazioni" + +#: ../../include/widgets.php:567 ../../mod/message.php:31 +#: ../../mod/mail.php:128 +msgid "Messages" +msgstr "Messaggi" + +#: ../../include/widgets.php:570 +msgid "Check Mail" +msgstr "Controlla i messaggi" + +#: ../../include/widgets.php:575 ../../include/nav.php:199 +msgid "New Message" +msgstr "Nuovo messaggio" + +#: ../../include/widgets.php:650 +msgid "Chat Rooms" +msgstr "Aree chat attive" + +#: ../../include/widgets.php:670 +msgid "Bookmarked Chatrooms" +msgstr "Aree chat nei segnalibri" + +#: ../../include/widgets.php:690 +msgid "Suggested Chatrooms" +msgstr "Aree chat suggerite" + +#: ../../include/widgets.php:817 ../../include/widgets.php:875 +msgid "photo/image" +msgstr "foto/immagine" + +#: ../../include/widgets.php:970 ../../include/widgets.php:972 +msgid "Rate Me" +msgstr "Valutami" + +#: ../../include/widgets.php:976 +msgid "View Ratings" +msgstr "Vedi le valutazioni ricevute" + +#: ../../include/widgets.php:987 +msgid "Public Hubs" +msgstr "Hub pubblici" + +#: ../../include/enotify.php:58 +msgid "Hubzilla Notification" +msgstr "Notifica di Hubzilla" + +#: ../../include/enotify.php:59 +msgid "hubzilla" +msgstr "Hubzilla" + +#: ../../include/enotify.php:61 +msgid "Thank You," +msgstr "Grazie," + +#: ../../include/enotify.php:63 +#, php-format +msgid "%s Administrator" +msgstr "L'amministratore di %s" + +#: ../../include/enotify.php:96 +#, php-format +msgid "%s " +msgstr "%s " + +#: ../../include/enotify.php:100 +#, php-format +msgid "[Red:Notify] New mail received at %s" +msgstr "[Hubzilla] Nuovo messaggio su %s" + +#: ../../include/enotify.php:102 +#, php-format +msgid "%1$s, %2$s sent you a new private message at %3$s." +msgstr "%1$s, %2$s ti ha mandato un messaggio privato su %3$s." + +#: ../../include/enotify.php:103 +#, php-format +msgid "%1$s sent you %2$s." +msgstr "%1$s ti ha mandato %2$s." + +#: ../../include/enotify.php:103 +msgid "a private message" +msgstr "un messaggio privato" + +#: ../../include/enotify.php:104 +#, php-format +msgid "Please visit %s to view and/or reply to your private messages." +msgstr "Visita %s per leggere i tuoi messaggi privati e rispondere." + +#: ../../include/enotify.php:158 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]a %4$s[/zrl]" +msgstr "%1$s, %2$s ha commentato [zrl=%3$s]%4$s[/zrl]" + +#: ../../include/enotify.php:166 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]%4$s's %5$s[/zrl]" +msgstr "%1$s, %2$s ha commentato [zrl=%3$s]%5$s di %4$s[/zrl]" + +#: ../../include/enotify.php:175 +#, php-format +msgid "%1$s, %2$s commented on [zrl=%3$s]your %4$s[/zrl]" +msgstr "%1$s, %2$s ha commentato [zrl=%3$s]%4$s che hai creato[/zrl]" + +#: ../../include/enotify.php:186 +#, php-format +msgid "[Red:Notify] Comment to conversation #%1$d by %2$s" +msgstr "[Hubzilla] Nuovo commento di %2$s alla conversazione #%1$d" + +#: ../../include/enotify.php:187 +#, php-format +msgid "%1$s, %2$s commented on an item/conversation you have been following." +msgstr "%1$s, %2$s ha commentato un elemento che stavi seguendo." + +#: ../../include/enotify.php:190 ../../include/enotify.php:205 +#: ../../include/enotify.php:231 ../../include/enotify.php:249 +#: ../../include/enotify.php:263 +#, php-format +msgid "Please visit %s to view and/or reply to the conversation." +msgstr "Visita %s per leggere o commentare la conversazione." + +#: ../../include/enotify.php:196 +#, php-format +msgid "[Red:Notify] %s posted to your profile wall" +msgstr "[Hubzilla] %s ha scritto sulla tua bacheca" + +#: ../../include/enotify.php:198 +#, php-format +msgid "%1$s, %2$s posted to your profile wall at %3$s" +msgstr "%1$s, %2$s ha scritto sulla bacheca del tuo profilo su %3$s" + +#: ../../include/enotify.php:200 +#, php-format +msgid "%1$s, %2$s posted to [zrl=%3$s]your wall[/zrl]" +msgstr "%1$s, %2$s ha scritto sulla [zrl=%3$s]tua bacheca[/zrl]" + +#: ../../include/enotify.php:224 +#, php-format +msgid "[Red:Notify] %s tagged you" +msgstr "[Hubzilla] %s ti ha taggato" + +#: ../../include/enotify.php:225 +#, php-format +msgid "%1$s, %2$s tagged you at %3$s" +msgstr "%1$s, %2$s ti ha taggato su %3$s" + +#: ../../include/enotify.php:226 +#, php-format +msgid "%1$s, %2$s [zrl=%3$s]tagged you[/zrl]." +msgstr "%1$s, %2$s [zrl=%3$s]ti ha taggato[/zrl]." + +#: ../../include/enotify.php:238 +#, php-format +msgid "[Red:Notify] %1$s poked you" +msgstr "[Hubzilla] %1$s ti ha mandato un poke" + +#: ../../include/enotify.php:239 +#, php-format +msgid "%1$s, %2$s poked you at %3$s" +msgstr "%1$s, %2$s ti ha mandato un poke su %3$s" + +#: ../../include/enotify.php:240 +#, php-format +msgid "%1$s, %2$s [zrl=%2$s]poked you[/zrl]." +msgstr "%1$s, %2$s [zrl=%2$s]ti ha mandato un poke[/zrl]." + +#: ../../include/enotify.php:256 +#, php-format +msgid "[Red:Notify] %s tagged your post" +msgstr "[Hubzilla] %s ha taggato il tuo articolo" + +#: ../../include/enotify.php:257 +#, php-format +msgid "%1$s, %2$s tagged your post at %3$s" +msgstr "%1$s, %2$s ha taggato il tuo articolo su %3$s" + +#: ../../include/enotify.php:258 +#, php-format +msgid "%1$s, %2$s tagged [zrl=%3$s]your post[/zrl]" +msgstr "%1$s, %2$s ha taggato [zrl=%3$s]il tuo articolo[/zrl]" + +#: ../../include/enotify.php:270 +msgid "[Red:Notify] Introduction received" +msgstr "[Hubzilla] Hai una richiesta di amicizia" + +#: ../../include/enotify.php:271 +#, php-format +msgid "%1$s, you've received an new connection request from '%2$s' at %3$s" +msgstr "%1$s, hai ricevuto una richiesta di entrare in contatto da '%2$s' su %3$s" + +#: ../../include/enotify.php:272 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a new connection request[/zrl] from %3$s." +msgstr "%1$s, hai ricevuto una [zrl=%2$s]richiesta di entrare in contatto[/zrl] da %3$s." + +#: ../../include/enotify.php:276 ../../include/enotify.php:295 +#, php-format +msgid "You may visit their profile at %s" +msgstr "Puoi visitare il suo profilo su %s" + +#: ../../include/enotify.php:278 +#, php-format +msgid "Please visit %s to approve or reject the connection request." +msgstr "Visita %s per approvare o rifiutare la richiesta di entrare in contatto." + +#: ../../include/enotify.php:285 +msgid "[Red:Notify] Friend suggestion received" +msgstr "[Hubzilla] Ti è stato suggerito un amico" + +#: ../../include/enotify.php:286 +#, php-format +msgid "%1$s, you've received a friend suggestion from '%2$s' at %3$s" +msgstr "%1$s, ti è stato suggerito un amico da '%2$s' su %3$s" + +#: ../../include/enotify.php:287 +#, php-format +msgid "" +"%1$s, you've received [zrl=%2$s]a friend suggestion[/zrl] for %3$s from " +"%4$s." +msgstr "%1$s, %4$s ti [zrl=%2$s]ha suggerito %3$s[/zrl] come amico." + +#: ../../include/enotify.php:293 +msgid "Name:" +msgstr "Nome:" + +#: ../../include/enotify.php:294 +msgid "Photo:" +msgstr "Foto:" + +#: ../../include/enotify.php:297 +#, php-format +msgid "Please visit %s to approve or reject the suggestion." +msgstr "Visita %s per approvare o rifiutare il suggerimento." + +#: ../../include/enotify.php:508 +msgid "[Red:Notify]" +msgstr "[Hubzilla]" + +#: ../../include/contact_selectors.php:56 +msgid "Frequently" +msgstr "Frequentemente" + +#: ../../include/contact_selectors.php:57 +msgid "Hourly" +msgstr "Ogni ora" + +#: ../../include/contact_selectors.php:58 +msgid "Twice daily" +msgstr "Due volte al giorno" + +#: ../../include/contact_selectors.php:59 +msgid "Daily" +msgstr "Ogni giorno" + +#: ../../include/contact_selectors.php:60 +msgid "Weekly" +msgstr "Ogni settimana" + +#: ../../include/contact_selectors.php:61 +msgid "Monthly" +msgstr "Ogni mese" + +#: ../../include/contact_selectors.php:76 +msgid "Friendica" +msgstr "Friendica" + +#: ../../include/contact_selectors.php:77 +msgid "OStatus" +msgstr "OStatus" + +#: ../../include/contact_selectors.php:78 +msgid "RSS/Atom" +msgstr "RSS/Atom" + +#: ../../include/contact_selectors.php:79 ../../mod/admin.php:813 +#: ../../mod/admin.php:822 ../../mod/id.php:15 ../../mod/id.php:16 +#: ../../boot.php:1542 +msgid "Email" +msgstr "Email" + +#: ../../include/contact_selectors.php:80 +msgid "Diaspora" +msgstr "Diaspora" + +#: ../../include/contact_selectors.php:81 +msgid "Facebook" +msgstr "Facebook" + +#: ../../include/contact_selectors.php:82 +msgid "Zot!" +msgstr "Zot!" + +#: ../../include/contact_selectors.php:83 +msgid "LinkedIn" +msgstr "LinkedIn" + +#: ../../include/contact_selectors.php:84 +msgid "XMPP/IM" +msgstr "XMPP/IM" + +#: ../../include/contact_selectors.php:85 +msgid "MySpace" +msgstr "MySpace" + +#: ../../include/message.php:18 +msgid "No recipient provided." +msgstr "Devi scegliere un destinatario." + +#: ../../include/message.php:23 +msgid "[no subject]" +msgstr "[nessun titolo]" + +#: ../../include/message.php:45 +msgid "Unable to determine sender." +msgstr "Impossibile determinare il mittente." + +#: ../../include/message.php:200 +msgid "Stored post could not be verified." +msgstr "Non è stato possibile verificare l'articolo inserito." + +#: ../../include/follow.php:28 +msgid "Channel is blocked on this site." +msgstr "Il canale è bloccato per questo sito." + +#: ../../include/follow.php:33 +msgid "Channel location missing." +msgstr "Manca l'indirizzo del canale." + +#: ../../include/follow.php:83 +msgid "Response from remote channel was incomplete." +msgstr "La risposta dal canale non è completa." + +#: ../../include/follow.php:100 +msgid "Channel was deleted and no longer exists." +msgstr "Il canale è stato rimosso e non esiste più." + +#: ../../include/follow.php:135 ../../include/follow.php:197 +msgid "Protocol disabled." +msgstr "Protocollo disabilitato." + +#: ../../include/follow.php:170 +msgid "Channel discovery failed." +msgstr "La ricerca del canale non ha avuto successo." + +#: ../../include/follow.php:186 +msgid "local account not found." +msgstr "l'account locale non è stato trovato." + +#: ../../include/follow.php:215 +msgid "Cannot connect to yourself." +msgstr "Non puoi connetterti a te stesso." + +#: ../../include/ItemObject.php:89 ../../include/conversation.php:667 +msgid "Private Message" +msgstr "Messaggio privato" + +#: ../../include/ItemObject.php:126 ../../include/conversation.php:659 +msgid "Select" +msgstr "Seleziona" + +#: ../../include/ItemObject.php:130 +msgid "Save to Folder" +msgstr "Salva nella cartella" + +#: ../../include/ItemObject.php:151 +msgid "I will attend" +msgstr "Parteciperò" + +#: ../../include/ItemObject.php:151 +msgid "I will not attend" +msgstr "Non parteciperò" + +#: ../../include/ItemObject.php:151 +msgid "I might attend" +msgstr "Forse parteciperò" + +#: ../../include/ItemObject.php:161 +msgid "I agree" +msgstr "Sono d'accordo" + +#: ../../include/ItemObject.php:161 +msgid "I disagree" +msgstr "Non sono d'accordo" + +#: ../../include/ItemObject.php:161 +msgid "I abstain" +msgstr "Mi astengo" + +#: ../../include/ItemObject.php:175 ../../include/ItemObject.php:187 +#: ../../include/conversation.php:1674 ../../mod/photos.php:1003 +#: ../../mod/photos.php:1015 +msgid "View all" +msgstr "Vedi tutto" + +#: ../../include/ItemObject.php:179 ../../include/taxonomy.php:396 +#: ../../include/conversation.php:1698 ../../include/identity.php:1133 +#: ../../mod/photos.php:1007 +msgctxt "noun" +msgid "Like" +msgid_plural "Likes" +msgstr[0] "Mi piace" +msgstr[1] "Mi piace" + +#: ../../include/ItemObject.php:184 ../../include/conversation.php:1701 +#: ../../mod/photos.php:1012 +msgctxt "noun" +msgid "Dislike" +msgid_plural "Dislikes" +msgstr[0] "Non mi piace" +msgstr[1] "Non mi piace" + +#: ../../include/ItemObject.php:212 +msgid "Add Star" +msgstr "Aggiungi ai preferiti" + +#: ../../include/ItemObject.php:213 +msgid "Remove Star" +msgstr "Rimuovi dai preferiti" + +#: ../../include/ItemObject.php:214 +msgid "Toggle Star Status" +msgstr "Attiva/disattiva preferito" + +#: ../../include/ItemObject.php:218 +msgid "starred" +msgstr "preferito" + +#: ../../include/ItemObject.php:227 ../../include/conversation.php:674 +msgid "Message signature validated" +msgstr "Messaggio con firma verificata" + +#: ../../include/ItemObject.php:228 ../../include/conversation.php:675 +msgid "Message signature incorrect" +msgstr "Massaggio con firma non corretta" + +#: ../../include/ItemObject.php:236 +msgid "Add Tag" +msgstr "Aggiungi un tag" + +#: ../../include/ItemObject.php:254 ../../mod/photos.php:947 +msgid "I like this (toggle)" +msgstr "Attiva/disattiva Mi piace" + +#: ../../include/ItemObject.php:254 ../../include/taxonomy.php:310 +msgid "like" +msgstr "mi piace" + +#: ../../include/ItemObject.php:255 ../../mod/photos.php:948 +msgid "I don't like this (toggle)" +msgstr "Attiva/disattiva Non mi piace" + +#: ../../include/ItemObject.php:255 ../../include/taxonomy.php:311 +msgid "dislike" +msgstr "non mi piace" + +#: ../../include/ItemObject.php:259 +msgid "Share This" +msgstr "Condividi" + +#: ../../include/ItemObject.php:259 +msgid "share" +msgstr "condividi" + +#: ../../include/ItemObject.php:276 +#, php-format +msgid "%d comment" +msgid_plural "%d comments" +msgstr[0] "%d commento" +msgstr[1] "%d commenti" + +#: ../../include/ItemObject.php:294 ../../include/ItemObject.php:295 +#, php-format +msgid "View %s's profile - %s" +msgstr "Guarda il profilo di %s - %s" + +#: ../../include/ItemObject.php:298 +msgid "to" +msgstr "a" + +#: ../../include/ItemObject.php:299 +msgid "via" +msgstr "via" + +#: ../../include/ItemObject.php:300 +msgid "Wall-to-Wall" +msgstr "Da bacheca a bacheca" + +#: ../../include/ItemObject.php:301 +msgid "via Wall-To-Wall:" +msgstr "da bacheca a bacheca:" + +#: ../../include/ItemObject.php:312 ../../include/conversation.php:716 +#, php-format +msgid "from %s" +msgstr "da %s" + +#: ../../include/ItemObject.php:315 ../../include/conversation.php:719 +#, php-format +msgid "last edited: %s" +msgstr "ultima modifica: %s" + +#: ../../include/ItemObject.php:316 ../../include/conversation.php:720 +#, php-format +msgid "Expires: %s" +msgstr "Scadenza: %s" + +#: ../../include/ItemObject.php:337 +msgid "Save Bookmarks" +msgstr "Salva segnalibro" + +#: ../../include/ItemObject.php:338 +msgid "Add to Calendar" +msgstr "Aggiungi al calendario" + +#: ../../include/ItemObject.php:347 +msgid "Mark all seen" +msgstr "Marca tutto come letto" + +#: ../../include/ItemObject.php:353 ../../mod/photos.php:1133 +msgctxt "noun" +msgid "Likes" +msgstr "Mi piace" + +#: ../../include/ItemObject.php:354 ../../mod/photos.php:1134 +msgctxt "noun" +msgid "Dislikes" +msgstr "Non mi piace" + +#: ../../include/ItemObject.php:359 ../../include/acl_selectors.php:249 +#: ../../mod/photos.php:1139 +msgid "Close" +msgstr "Chiudi" + +#: ../../include/ItemObject.php:364 ../../include/conversation.php:737 +#: ../../include/conversation.php:1206 ../../mod/photos.php:950 +#: ../../mod/editlayout.php:153 ../../mod/editwebpage.php:192 +#: ../../mod/editpost.php:130 ../../mod/editblock.php:155 +#: ../../mod/mail.php:241 ../../mod/mail.php:356 +msgid "Please wait" +msgstr "Attendere" + +#: ../../include/ItemObject.php:665 ../../mod/photos.php:966 +#: ../../mod/photos.php:1084 +msgid "This is you" +msgstr "Questo sei tu" + +#: ../../include/ItemObject.php:669 ../../include/conversation.php:1179 +#: ../../mod/editlayout.php:140 ../../mod/editwebpage.php:179 +#: ../../mod/editpost.php:114 ../../mod/editblock.php:141 +msgid "Bold" +msgstr "Grassetto" + +#: ../../include/ItemObject.php:670 ../../include/conversation.php:1180 +#: ../../mod/editlayout.php:141 ../../mod/editwebpage.php:180 +#: ../../mod/editpost.php:115 ../../mod/editblock.php:142 +msgid "Italic" +msgstr "Corsivo" + +#: ../../include/ItemObject.php:671 ../../include/conversation.php:1181 +#: ../../mod/editlayout.php:142 ../../mod/editwebpage.php:181 +#: ../../mod/editpost.php:116 ../../mod/editblock.php:143 +msgid "Underline" +msgstr "Sottolineato" + +#: ../../include/ItemObject.php:672 ../../include/conversation.php:1182 +#: ../../mod/editlayout.php:143 ../../mod/editwebpage.php:182 +#: ../../mod/editpost.php:117 ../../mod/editblock.php:144 +msgid "Quote" +msgstr "Citazione" + +#: ../../include/ItemObject.php:673 ../../include/conversation.php:1183 +#: ../../mod/editlayout.php:144 ../../mod/editwebpage.php:183 +#: ../../mod/editpost.php:118 ../../mod/editblock.php:145 +msgid "Code" +msgstr "Codice" + +#: ../../include/ItemObject.php:674 +msgid "Image" +msgstr "Immagine" + +#: ../../include/ItemObject.php:675 +msgid "Insert Link" +msgstr "Collegamento" + +#: ../../include/ItemObject.php:676 +msgid "Video" +msgstr "Video" + +#: ../../include/ItemObject.php:680 ../../include/conversation.php:1233 +#: ../../mod/editpost.php:157 ../../mod/mail.php:247 ../../mod/mail.php:361 +msgid "Encrypt text" +msgstr "Crittografia del testo" + +#: ../../include/Contact.php:124 +msgid "New window" +msgstr "Nuova finestra" + +#: ../../include/Contact.php:125 +msgid "Open the selected location in a different window or browser tab" +msgstr "Apri l'indirizzo selezionato in una nuova scheda o finestra" + +#: ../../include/Contact.php:215 ../../mod/admin.php:730 +#, php-format +msgid "User '%s' deleted" +msgstr "Utente '%s' eliminato" + +#: ../../include/bb2diaspora.php:373 +msgid "Attachments:" +msgstr "Allegati:" + +#: ../../include/bb2diaspora.php:453 +msgid "Hubzilla event notification:" +msgstr "Notifica eventi Hubzilla:" + +#: ../../include/text.php:329 +msgid "prev" +msgstr "prec" + +#: ../../include/text.php:331 +msgid "first" +msgstr "inizio" + +#: ../../include/text.php:360 +msgid "last" +msgstr "fine" + +#: ../../include/text.php:363 +msgid "next" +msgstr "succ" + +#: ../../include/text.php:373 +msgid "older" +msgstr "più recenti" + +#: ../../include/text.php:375 +msgid "newer" +msgstr "più nuovi" + +#: ../../include/text.php:768 +msgid "No connections" +msgstr "Nessun contatto" + +#: ../../include/text.php:782 +#, php-format +msgid "%d Connection" +msgid_plural "%d Connections" +msgstr[0] "%d contatto" +msgstr[1] "%d contatti" + +#: ../../include/text.php:795 ../../mod/viewconnections.php:104 +msgid "View Connections" +msgstr "Elenco contatti" + +#: ../../include/text.php:852 ../../include/text.php:864 +#: ../../include/nav.php:165 ../../include/apps.php:147 +#: ../../mod/search.php:38 +msgid "Search" +msgstr "Cerca" + +#: ../../include/text.php:928 +msgid "poke" +msgstr "poke" + +#: ../../include/text.php:928 ../../include/conversation.php:243 +msgid "poked" +msgstr "ha ricevuto un poke" + +#: ../../include/text.php:929 +msgid "ping" +msgstr "ping" + +#: ../../include/text.php:929 +msgid "pinged" +msgstr "ha ricevuto un ping" + +#: ../../include/text.php:930 +msgid "prod" +msgstr "spintone" + +#: ../../include/text.php:930 +msgid "prodded" +msgstr "ha ricevuto uno spintone" + +#: ../../include/text.php:931 +msgid "slap" +msgstr "schiaffo" + +#: ../../include/text.php:931 +msgid "slapped" +msgstr "ha ricevuto uno schiaffo" + +#: ../../include/text.php:932 +msgid "finger" +msgstr "finger" + +#: ../../include/text.php:932 +msgid "fingered" +msgstr "ha ricevuto un finger" + +#: ../../include/text.php:933 +msgid "rebuff" +msgstr "rifiuto" + +#: ../../include/text.php:933 +msgid "rebuffed" +msgstr "ha ricevuto un rifiuto" + +#: ../../include/text.php:943 +msgid "happy" +msgstr "felice" + +#: ../../include/text.php:944 +msgid "sad" +msgstr "triste" + +#: ../../include/text.php:945 +msgid "mellow" +msgstr "calmo" + +#: ../../include/text.php:946 +msgid "tired" +msgstr "stanco" + +#: ../../include/text.php:947 +msgid "perky" +msgstr "vivace" + +#: ../../include/text.php:948 +msgid "angry" +msgstr "arrabbiato" + +#: ../../include/text.php:949 +msgid "stupified" +msgstr "stordito" + +#: ../../include/text.php:950 +msgid "puzzled" +msgstr "confuso" + +#: ../../include/text.php:951 +msgid "interested" +msgstr "attento" + +#: ../../include/text.php:952 +msgid "bitter" +msgstr "amaro" + +#: ../../include/text.php:953 +msgid "cheerful" +msgstr "allegro" + +#: ../../include/text.php:954 +msgid "alive" +msgstr "vivace" + +#: ../../include/text.php:955 +msgid "annoyed" +msgstr "seccato" + +#: ../../include/text.php:956 +msgid "anxious" +msgstr "ansioso" + +#: ../../include/text.php:957 +msgid "cranky" +msgstr "irritabile" + +#: ../../include/text.php:958 +msgid "disturbed" +msgstr "turbato" + +#: ../../include/text.php:959 +msgid "frustrated" +msgstr "frustrato" + +#: ../../include/text.php:960 +msgid "depressed" +msgstr "in depressione" + +#: ../../include/text.php:961 +msgid "motivated" +msgstr "motivato" + +#: ../../include/text.php:962 +msgid "relaxed" +msgstr "rilassato" + +#: ../../include/text.php:963 +msgid "surprised" +msgstr "sorpreso" + +#: ../../include/text.php:1135 +msgid "Monday" +msgstr "lunedì" + +#: ../../include/text.php:1135 +msgid "Tuesday" +msgstr "martedì" + +#: ../../include/text.php:1135 +msgid "Wednesday" +msgstr "mercoledì" + +#: ../../include/text.php:1135 +msgid "Thursday" +msgstr "giovedì" + +#: ../../include/text.php:1135 +msgid "Friday" +msgstr "venerdì" + +#: ../../include/text.php:1135 +msgid "Saturday" +msgstr "sabato" + +#: ../../include/text.php:1135 +msgid "Sunday" +msgstr "domenica" + +#: ../../include/text.php:1139 +msgid "January" +msgstr "gennaio" + +#: ../../include/text.php:1139 +msgid "February" +msgstr "febbraio" + +#: ../../include/text.php:1139 +msgid "March" +msgstr "marzo" + +#: ../../include/text.php:1139 +msgid "April" +msgstr "aprile" + +#: ../../include/text.php:1139 +msgid "May" +msgstr "maggio" + +#: ../../include/text.php:1139 +msgid "June" +msgstr "giugno" + +#: ../../include/text.php:1139 +msgid "July" +msgstr "luglio" + +#: ../../include/text.php:1139 +msgid "August" +msgstr "agosto" + +#: ../../include/text.php:1139 +msgid "September" +msgstr "settembre" + +#: ../../include/text.php:1139 +msgid "October" +msgstr "ottobre" + +#: ../../include/text.php:1139 +msgid "November" +msgstr "novembre" + +#: ../../include/text.php:1139 +msgid "December" +msgstr "dicembre" + +#: ../../include/text.php:1236 +msgid "unknown.???" +msgstr "sconosciuto???" + +#: ../../include/text.php:1237 +msgid "bytes" +msgstr "byte" + +#: ../../include/text.php:1273 +msgid "remove category" +msgstr "rimuovi la categoria" + +#: ../../include/text.php:1348 +msgid "remove from file" +msgstr "rimuovi dal file" + +#: ../../include/text.php:1424 ../../include/text.php:1435 +#: ../../mod/connedit.php:661 +msgid "Click to open/close" +msgstr "Clicca per aprire/chiudere" + +#: ../../include/text.php:1591 ../../mod/events.php:444 +msgid "Link to Source" +msgstr "Link al sito d'origine" + +#: ../../include/text.php:1612 ../../include/text.php:1683 +msgid "default" +msgstr "predefinito" + +#: ../../include/text.php:1620 +msgid "Page layout" +msgstr "Layout della pagina" + +#: ../../include/text.php:1620 +msgid "You can create your own with the layouts tool" +msgstr "Con gli strumenti di design puoi creare il tuo" + +#: ../../include/text.php:1661 +msgid "Page content type" +msgstr "Tipo di contenuto della pagina" + +#: ../../include/text.php:1695 +msgid "Select an alternate language" +msgstr "Seleziona una lingua diversa" + +#: ../../include/text.php:1814 ../../include/conversation.php:120 +#: ../../include/diaspora.php:2081 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +#: ../../mod/tagger.php:43 +msgid "photo" +msgstr "la foto" + +#: ../../include/text.php:1817 ../../include/conversation.php:123 +#: ../../mod/like.php:348 ../../mod/tagger.php:47 +msgid "event" +msgstr "l'evento" + +#: ../../include/text.php:1820 ../../include/conversation.php:148 +#: ../../include/diaspora.php:2081 ../../mod/like.php:346 +#: ../../mod/subthread.php:72 ../../mod/subthread.php:174 +#: ../../mod/tagger.php:51 +msgid "status" +msgstr "il messaggio di stato" + +#: ../../include/text.php:1822 ../../include/conversation.php:150 +#: ../../mod/tagger.php:53 +msgid "comment" +msgstr "il commento" + +#: ../../include/text.php:1827 +msgid "activity" +msgstr "l'attività" + +#: ../../include/text.php:2122 +msgid "Design Tools" +msgstr "Strumenti di design" + +#: ../../include/text.php:2125 ../../mod/blocks.php:143 +msgid "Blocks" +msgstr "Riquadri" + +#: ../../include/text.php:2126 ../../mod/menu.php:95 +msgid "Menus" +msgstr "Menù" + +#: ../../include/text.php:2127 ../../mod/layouts.php:169 +msgid "Layouts" +msgstr "Layout" + +#: ../../include/text.php:2128 +msgid "Pages" +msgstr "Pagine" + +#: ../../include/nav.php:87 ../../include/nav.php:120 ../../boot.php:1539 +msgid "Logout" +msgstr "Esci" + +#: ../../include/nav.php:87 ../../include/nav.php:120 +msgid "End this session" +msgstr "Chiudi questa sessione" + +#: ../../include/nav.php:90 ../../include/nav.php:151 +msgid "Home" +msgstr "Bacheca" + +#: ../../include/nav.php:90 +msgid "Your posts and conversations" +msgstr "I tuoi articoli e conversazioni" + +#: ../../include/nav.php:91 ../../include/conversation.php:942 +#: ../../mod/connedit.php:494 ../../mod/connedit.php:660 +msgid "View Profile" +msgstr "Profilo" + +#: ../../include/nav.php:91 +msgid "Your profile page" +msgstr "Il tuo profilo" + +#: ../../include/nav.php:93 +msgid "Edit Profiles" +msgstr "Modifica i profili" + +#: ../../include/nav.php:93 +msgid "Manage/Edit profiles" +msgstr "Gestisci/modifica i profili" + +#: ../../include/nav.php:95 ../../include/identity.php:846 +msgid "Edit Profile" +msgstr "Modifica il profilo" + +#: ../../include/nav.php:95 +msgid "Edit your profile" +msgstr "Modifica il profilo" + +#: ../../include/nav.php:97 ../../include/conversation.php:1597 +#: ../../include/apps.php:139 ../../mod/fbrowser.php:25 +msgid "Photos" +msgstr "Foto" + +#: ../../include/nav.php:97 +msgid "Your photos" +msgstr "Le tue foto" + +#: ../../include/nav.php:98 +msgid "Your files" +msgstr "I tuoi file" + +#: ../../include/nav.php:103 ../../include/apps.php:146 +msgid "Chat" +msgstr "Area chat" + +#: ../../include/nav.php:103 +msgid "Your chatrooms" +msgstr "Le tue aree chat" + +#: ../../include/nav.php:109 ../../include/conversation.php:1632 +#: ../../include/apps.php:129 +msgid "Bookmarks" +msgstr "Segnalibri" + +#: ../../include/nav.php:109 +msgid "Your bookmarks" +msgstr "I tuoi segnalibri" + +#: ../../include/nav.php:113 ../../include/conversation.php:1642 +#: ../../include/apps.php:136 ../../mod/webpages.php:176 +msgid "Webpages" +msgstr "Pagine web" + +#: ../../include/nav.php:113 +msgid "Your webpages" +msgstr "Le tue pagine web" + +#: ../../include/nav.php:117 ../../include/apps.php:131 ../../boot.php:1540 +msgid "Login" +msgstr "Accedi" + +#: ../../include/nav.php:117 +msgid "Sign in" +msgstr "Accedi" + +#: ../../include/nav.php:134 +#, php-format +msgid "%s - click to logout" +msgstr "%s - clicca per uscire" + +#: ../../include/nav.php:137 +msgid "Remote authentication" +msgstr "Autenticazione magica dal tuo server" + +#: ../../include/nav.php:137 +msgid "Click to authenticate to your home hub" +msgstr "Clicca per autenticarti sul tuo server principale" + +#: ../../include/nav.php:151 +msgid "Home Page" +msgstr "Bacheca" + +#: ../../include/nav.php:155 ../../mod/register.php:224 ../../boot.php:1516 +msgid "Register" +msgstr "Iscriviti" + +#: ../../include/nav.php:155 +msgid "Create an account" +msgstr "Crea un account" + +#: ../../include/nav.php:160 ../../include/apps.php:142 ../../mod/help.php:67 +#: ../../mod/help.php:72 ../../mod/layouts.php:171 +msgid "Help" +msgstr "Guida" + +#: ../../include/nav.php:160 +msgid "Help and documentation" +msgstr "Guida e documentazione" + +#: ../../include/nav.php:163 +msgid "Applications, utilities, links, games" +msgstr "Applicazioni, utilità, link, giochi" + +#: ../../include/nav.php:165 +msgid "Search site content" +msgstr "Cerca nel sito" + +#: ../../include/nav.php:168 ../../include/apps.php:141 +#: ../../mod/directory.php:366 +msgid "Directory" +msgstr "Elenco pubblico" + +#: ../../include/nav.php:168 +msgid "Channel Directory" +msgstr "Elenco pubblico canali" + +#: ../../include/nav.php:180 ../../include/apps.php:133 +msgid "Matrix" +msgstr "Hubzilla" + +#: ../../include/nav.php:180 +msgid "Your matrix" +msgstr "La tua rete" + +#: ../../include/nav.php:181 +msgid "Mark all matrix notifications seen" +msgstr "Segna come lette le notifiche della tua rete" + +#: ../../include/nav.php:183 ../../include/apps.php:137 +msgid "Channel Home" +msgstr "Bacheca del canale" + +#: ../../include/nav.php:183 +msgid "Channel home" +msgstr "Bacheca del canale" + +#: ../../include/nav.php:184 +msgid "Mark all channel notifications seen" +msgstr "Segna come lette le notifiche del canale" + +#: ../../include/nav.php:187 ../../mod/connections.php:407 +msgid "Connections" +msgstr "Contatti" + +#: ../../include/nav.php:190 +msgid "Notices" +msgstr "Avvisi" + +#: ../../include/nav.php:190 +msgid "Notifications" +msgstr "Notifiche" + +#: ../../include/nav.php:191 +msgid "See all notifications" +msgstr "Vedi tutte le notifiche" + +#: ../../include/nav.php:192 ../../mod/notifications.php:99 +msgid "Mark all system notifications seen" +msgstr "Segna come lette le notifiche di sistema" + +#: ../../include/nav.php:194 ../../include/apps.php:143 +msgid "Mail" +msgstr "Messaggi" + +#: ../../include/nav.php:194 +msgid "Private mail" +msgstr "Messaggi privati" + +#: ../../include/nav.php:195 +msgid "See all private messages" +msgstr "Guarda tutti i messaggi privati" + +#: ../../include/nav.php:196 +msgid "Mark all private messages seen" +msgstr "Segna come letti tutti i messaggi privati" + +#: ../../include/nav.php:197 +msgid "Inbox" +msgstr "In arrivo" + +#: ../../include/nav.php:198 +msgid "Outbox" +msgstr "Inviati" + +#: ../../include/nav.php:202 ../../include/apps.php:140 +#: ../../mod/events.php:472 +msgid "Events" +msgstr "Eventi" + +#: ../../include/nav.php:202 +msgid "Event Calendar" +msgstr "Calendario" + +#: ../../include/nav.php:203 +msgid "See all events" +msgstr "Guarda tutti gli eventi" + +#: ../../include/nav.php:204 +msgid "Mark all events seen" +msgstr "Marca come letti tutti gli eventi" + +#: ../../include/nav.php:206 ../../include/apps.php:132 +#: ../../mod/manage.php:166 +msgid "Channel Manager" +msgstr "Gestione canali" + +#: ../../include/nav.php:206 +msgid "Manage Your Channels" +msgstr "Gestisci i tuoi canali" + +#: ../../include/nav.php:208 +msgid "Account/Channel Settings" +msgstr "Impostazioni dell'account e del canale" + +#: ../../include/nav.php:216 ../../mod/admin.php:120 +msgid "Admin" +msgstr "Amministrazione" + +#: ../../include/nav.php:216 +msgid "Site Setup and Configuration" +msgstr "Installazione e configurazione del sito" + +#: ../../include/nav.php:247 ../../include/conversation.php:850 +msgid "Loading..." +msgstr "Caricamento in corso..." + +#: ../../include/nav.php:252 +msgid "@name, #tag, content" +msgstr "@nome, #tag, testo" + +#: ../../include/nav.php:253 +msgid "Please wait..." +msgstr "Attendere..." + +#: ../../include/taxonomy.php:222 ../../include/taxonomy.php:243 +msgid "Tags" +msgstr "Tag" + +#: ../../include/taxonomy.php:287 +msgid "Keywords" +msgstr "Parole chiave" + +#: ../../include/taxonomy.php:308 +msgid "have" +msgstr "ho" + +#: ../../include/taxonomy.php:308 +msgid "has" +msgstr "ha" + +#: ../../include/taxonomy.php:309 +msgid "want" +msgstr "voglio" + +#: ../../include/taxonomy.php:309 +msgid "wants" +msgstr "vuole" + +#: ../../include/taxonomy.php:310 +msgid "likes" +msgstr "gli piace" + +#: ../../include/taxonomy.php:311 +msgid "dislikes" +msgstr "non gli piace" + +#: ../../include/activities.php:39 +msgid " and " +msgstr "e" + +#: ../../include/activities.php:47 +msgid "public profile" +msgstr "profilo pubblico" + +#: ../../include/activities.php:56 +#, php-format +msgid "%1$s changed %2$s to “%3$s”" +msgstr "%1$s ha cambiato %2$s in “%3$s”" + +#: ../../include/activities.php:57 +#, php-format +msgid "Visit %1$s's %2$s" +msgstr "Guarda %2$s di %1$s " + +#: ../../include/activities.php:60 +#, php-format +msgid "%1$s has an updated %2$s, changing %3$s." +msgstr "%1$s ha aggiornato %2$s cambiando %3$s." + +#: ../../include/bbcode.php:122 ../../include/bbcode.php:735 +#: ../../include/bbcode.php:738 ../../include/bbcode.php:743 +#: ../../include/bbcode.php:746 ../../include/bbcode.php:749 +#: ../../include/bbcode.php:752 ../../include/bbcode.php:757 +#: ../../include/bbcode.php:760 ../../include/bbcode.php:765 +#: ../../include/bbcode.php:768 ../../include/bbcode.php:771 +#: ../../include/bbcode.php:774 +msgid "Image/photo" +msgstr "Immagine" + +#: ../../include/bbcode.php:161 ../../include/bbcode.php:785 +msgid "Encrypted content" +msgstr "Contenuto crittografato" + +#: ../../include/bbcode.php:177 +msgid "Install design element: " +msgstr "Installa il componente di design:" + +#: ../../include/bbcode.php:190 +msgid "QR code" +msgstr "QR code" + +#: ../../include/bbcode.php:241 +#, php-format +msgid "%1$s wrote the following %2$s %3$s" +msgstr "%1$s ha scritto %2$s %3$s" + +#: ../../include/bbcode.php:243 +msgid "post" +msgstr "l'articolo" + +#: ../../include/bbcode.php:485 +msgid "Different viewers will see this text differently" +msgstr "Ad altri questo testo potrebbe apparire in modo differente" + +#: ../../include/bbcode.php:696 +msgid "$1 spoiler" +msgstr "$1 spoiler" + +#: ../../include/bbcode.php:723 +msgid "$1 wrote:" +msgstr "$1 ha scritto:" + +#: ../../include/items.php:399 ../../mod/like.php:270 +#: ../../mod/subthread.php:49 ../../mod/group.php:68 ../../mod/profperm.php:23 +#: ../../mod/bulksetclose.php:11 ../../index.php:392 +msgid "Permission denied" +msgstr "Permesso negato" + +#: ../../include/items.php:1012 ../../include/items.php:1058 +msgid "(Unknown)" +msgstr "(Sconosciuto)" + +#: ../../include/items.php:1226 +msgid "Visible to anybody on the internet." +msgstr "Visibile a chiunque su internet." + +#: ../../include/items.php:1228 +msgid "Visible to you only." +msgstr "Visibile solo a te." + +#: ../../include/items.php:1230 +msgid "Visible to anybody in this network." +msgstr "Visibile a tutti su questa rete." + +#: ../../include/items.php:1232 +msgid "Visible to anybody authenticated." +msgstr "Visibile a chiunque sia autenticato." + +#: ../../include/items.php:1234 +#, php-format +msgid "Visible to anybody on %s." +msgstr "Visibile a tutti in %s." + +#: ../../include/items.php:1236 +msgid "Visible to all connections." +msgstr "Visibile a tutti coloro che ti seguono." + +#: ../../include/items.php:1238 +msgid "Visible to approved connections." +msgstr "Visibile ai contatti approvati." + +#: ../../include/items.php:1240 +msgid "Visible to specific connections." +msgstr "Visibile ad alcuni contatti scelti." + +#: ../../include/items.php:4051 ../../mod/thing.php:74 +#: ../../mod/display.php:36 ../../mod/filestorage.php:27 +#: ../../mod/viewsrc.php:20 ../../mod/admin.php:167 ../../mod/admin.php:984 +#: ../../mod/admin.php:1184 +msgid "Item not found." +msgstr "Elemento non trovato." + +#: ../../include/items.php:4124 ../../include/photos.php:26 +#: ../../include/attach.php:136 ../../include/attach.php:183 +#: ../../include/attach.php:246 ../../include/attach.php:260 +#: ../../include/attach.php:304 ../../include/attach.php:318 +#: ../../include/attach.php:343 ../../include/attach.php:539 +#: ../../include/attach.php:611 ../../include/chat.php:131 +#: ../../mod/profile.php:64 ../../mod/profile.php:72 +#: ../../mod/achievements.php:30 ../../mod/manage.php:6 +#: ../../mod/settings.php:564 ../../mod/api.php:26 ../../mod/api.php:31 +#: ../../mod/thing.php:241 ../../mod/thing.php:256 ../../mod/thing.php:290 +#: ../../mod/profile_photo.php:264 ../../mod/profile_photo.php:277 +#: ../../mod/block.php:22 ../../mod/block.php:72 ../../mod/like.php:178 +#: ../../mod/events.php:219 ../../mod/group.php:9 ../../mod/setup.php:207 +#: ../../mod/common.php:35 ../../mod/connections.php:169 +#: ../../mod/photos.php:68 ../../mod/pdledit.php:21 ../../mod/authtest.php:13 +#: ../../mod/editlayout.php:64 ../../mod/editlayout.php:89 +#: ../../mod/chat.php:90 ../../mod/chat.php:95 ../../mod/editwebpage.php:64 +#: ../../mod/editwebpage.php:86 ../../mod/editwebpage.php:101 +#: ../../mod/editwebpage.php:125 ../../mod/rate.php:110 +#: ../../mod/editpost.php:13 ../../mod/invite.php:13 ../../mod/invite.php:104 +#: ../../mod/locs.php:77 ../../mod/sources.php:66 ../../mod/menu.php:69 +#: ../../mod/filestorage.php:18 ../../mod/filestorage.php:73 +#: ../../mod/filestorage.php:88 ../../mod/filestorage.php:115 +#: ../../mod/fsuggest.php:78 ../../mod/poke.php:128 ../../mod/webpages.php:69 +#: ../../mod/profiles.php:188 ../../mod/profiles.php:576 +#: ../../mod/viewsrc.php:14 ../../mod/mitem.php:115 +#: ../../mod/viewconnections.php:22 ../../mod/viewconnections.php:27 +#: ../../mod/editblock.php:65 ../../mod/register.php:72 ../../mod/item.php:206 +#: ../../mod/item.php:214 ../../mod/item.php:962 ../../mod/blocks.php:69 +#: ../../mod/blocks.php:76 ../../mod/id.php:71 ../../mod/message.php:16 +#: ../../mod/layouts.php:69 ../../mod/layouts.php:76 ../../mod/layouts.php:87 +#: ../../mod/mood.php:111 ../../mod/connedit.php:331 ../../mod/mail.php:114 +#: ../../mod/notifications.php:66 ../../mod/regmod.php:17 +#: ../../mod/new_channel.php:68 ../../mod/new_channel.php:99 +#: ../../mod/appman.php:66 ../../mod/network.php:12 ../../mod/page.php:28 +#: ../../mod/page.php:79 ../../mod/bookmarks.php:46 ../../mod/channel.php:100 +#: ../../mod/channel.php:219 ../../mod/channel.php:262 +#: ../../mod/suggest.php:26 ../../mod/service_limits.php:7 +#: ../../mod/sharedwithme.php:7 ../../index.php:190 ../../index.php:393 +msgid "Permission denied." +msgstr "Permesso negato." + +#: ../../include/items.php:4524 ../../mod/group.php:38 ../../mod/group.php:140 +#: ../../mod/bulksetclose.php:51 +msgid "Collection not found." +msgstr "Insieme di canali non trovato." + +#: ../../include/items.php:4540 +msgid "Collection is empty." +msgstr "L'insieme di canali è vuoto." + +#: ../../include/items.php:4547 +#, php-format +msgid "Collection: %s" +msgstr "Insieme: %s" + +#: ../../include/items.php:4557 +#, php-format +msgid "Connection: %s" +msgstr "Contatto: %s" + +#: ../../include/items.php:4559 +msgid "Connection not found." +msgstr "Contatto non trovato." + +#: ../../include/permissions.php:26 +msgid "Can view my normal stream and posts" +msgstr "Può vedere i miei contenuti e articoli normali" + +#: ../../include/permissions.php:27 +msgid "Can view my default channel profile" +msgstr "Può vedere il profilo predefinito del canale" + +#: ../../include/permissions.php:28 +msgid "Can view my photo albums" +msgstr "Può vedere i miei album fotografici" + +#: ../../include/permissions.php:29 +msgid "Can view my connections" +msgstr "Può vedere i miei contatti" + +#: ../../include/permissions.php:30 +msgid "Can view my file storage" +msgstr "Può vedere i miei file condivisi" + +#: ../../include/permissions.php:31 +msgid "Can view my webpages" +msgstr "Può vedere le mie pagine web" + +#: ../../include/permissions.php:34 +msgid "Can send me their channel stream and posts" +msgstr "È tra i canali che seguo" + +#: ../../include/permissions.php:35 +msgid "Can post on my channel page (\"wall\")" +msgstr "Può scrivere sulla bacheca del mio canale" + +#: ../../include/permissions.php:36 +msgid "Can comment on or like my posts" +msgstr "Può commentare o aggiungere \"mi piace\" ai miei articoli" + +#: ../../include/permissions.php:37 +msgid "Can send me private mail messages" +msgstr "Può inviarmi messaggi privati" + +#: ../../include/permissions.php:38 +msgid "Can post photos to my photo albums" +msgstr "Può aggiungere foto ai miei album" + +#: ../../include/permissions.php:39 +msgid "Can like/dislike stuff" +msgstr "Può aggiungere \"mi piace\"" + +#: ../../include/permissions.php:39 +msgid "Profiles and things other than posts/comments" +msgstr "Profili e tutto ciò che non è articoli e commenti" + +#: ../../include/permissions.php:41 +msgid "Can forward to all my channel contacts via post @mentions" +msgstr "Può inoltrare articoli a tutti i contatti del canale tramite una @menzione" + +#: ../../include/permissions.php:41 +msgid "Advanced - useful for creating group forum channels" +msgstr "Impostazione avanzata - utile per creare un canale-forum di discussione" + +#: ../../include/permissions.php:42 +msgid "Can chat with me (when available)" +msgstr "Può aprire una chat con me (se disponibile)" + +#: ../../include/permissions.php:43 +msgid "Can write to my file storage" +msgstr "Può scrivere sul mio archivio file" + +#: ../../include/permissions.php:44 +msgid "Can edit my webpages" +msgstr "Può modificare le mie pagine web" + +#: ../../include/permissions.php:46 +msgid "Can source my public posts in derived channels" +msgstr "Può usare i miei articoli pubblici per creare canali derivati" + +#: ../../include/permissions.php:46 +msgid "Somewhat advanced - very useful in open communities" +msgstr "Piuttosto avanzato - molto utile nelle comunità aperte" + +#: ../../include/permissions.php:48 +msgid "Can administer my channel resources" +msgstr "Può amministrare i contenuti del mio canale" + +#: ../../include/permissions.php:48 +msgid "" +"Extremely advanced. Leave this alone unless you know what you are doing" +msgstr "Impostazione pericolosa - lasciare il valore predefinito se non si è assolutamente sicuri" + +#: ../../include/permissions.php:809 +msgid "Social Networking" +msgstr "Social network" + +#: ../../include/permissions.php:809 ../../include/permissions.php:810 +#: ../../include/permissions.php:811 +msgid "Mostly Public" +msgstr "Prevalentemente pubblico" + +#: ../../include/permissions.php:809 ../../include/permissions.php:810 +#: ../../include/permissions.php:811 +msgid "Restricted" +msgstr "Con restrizioni" + +#: ../../include/permissions.php:809 ../../include/permissions.php:810 +msgid "Private" +msgstr "Privato" + +#: ../../include/permissions.php:810 +msgid "Community Forum" +msgstr "Forum di discussione" + +#: ../../include/permissions.php:811 +msgid "Feed Republish" +msgstr "Aggregatore di feed esterni" + +#: ../../include/permissions.php:812 +msgid "Special Purpose" +msgstr "Per finalità speciali" + +#: ../../include/permissions.php:812 +msgid "Celebrity/Soapbox" +msgstr "Pagina per fan" + +#: ../../include/permissions.php:812 +msgid "Group Repository" +msgstr "Repository di gruppo" + +#: ../../include/permissions.php:813 ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 +#: ../../include/profile_selectors.php:61 +#: ../../include/profile_selectors.php:97 +msgid "Other" +msgstr "Altro" + +#: ../../include/permissions.php:813 +msgid "Custom/Expert Mode" +msgstr "Personalizzazione per esperti" + +#: ../../include/conversation.php:126 ../../mod/like.php:113 +msgid "channel" +msgstr "canale" + +#: ../../include/conversation.php:164 ../../include/diaspora.php:2110 +#: ../../mod/like.php:394 +#, php-format +msgid "%1$s likes %2$s's %3$s" +msgstr "A %1$s piace %3$s di %2$s" + +#: ../../include/conversation.php:167 ../../mod/like.php:396 +#, php-format +msgid "%1$s doesn't like %2$s's %3$s" +msgstr "A %1$s non piace %3$s di %2$s" + +#: ../../include/conversation.php:204 +#, php-format +msgid "%1$s is now connected with %2$s" +msgstr "%1$s adesso è connesso con %2$s" + +#: ../../include/conversation.php:239 +#, php-format +msgid "%1$s poked %2$s" +msgstr "%1$s ha mandato un poke a %2$s" + +#: ../../include/conversation.php:260 ../../mod/mood.php:63 +#, php-format +msgctxt "mood" +msgid "%1$s is %2$s" +msgstr "%1$s è %2$s" + +#: ../../include/conversation.php:572 ../../mod/photos.php:984 +msgctxt "title" +msgid "Likes" +msgstr "Mi piace" + +#: ../../include/conversation.php:572 ../../mod/photos.php:984 +msgctxt "title" +msgid "Dislikes" +msgstr "Non mi piace" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Agree" +msgstr "D'accordo" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Disagree" +msgstr "Non d'accordo" + +#: ../../include/conversation.php:573 ../../mod/photos.php:985 +msgctxt "title" +msgid "Abstain" +msgstr "Astenuti" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Attending" +msgstr "Partecipano" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Not attending" +msgstr "Non partecipano" + +#: ../../include/conversation.php:574 ../../mod/photos.php:986 +msgctxt "title" +msgid "Might attend" +msgstr "Forse partecipano" + +#: ../../include/conversation.php:692 +#, php-format +msgid "View %s's profile @ %s" +msgstr "Vedi il profilo di %s @ %s" + +#: ../../include/conversation.php:707 +msgid "Categories:" +msgstr "Categorie:" + +#: ../../include/conversation.php:708 +msgid "Filed under:" +msgstr "Classificato come:" + +#: ../../include/conversation.php:735 +msgid "View in context" +msgstr "Vedi nel contesto" + +#: ../../include/conversation.php:846 +msgid "remove" +msgstr "rimuovi" + +#: ../../include/conversation.php:851 +msgid "Delete Selected Items" +msgstr "Elimina gli oggetti selezionati" + +#: ../../include/conversation.php:939 +msgid "View Source" +msgstr "Vedi il sorgente" + +#: ../../include/conversation.php:940 +msgid "Follow Thread" +msgstr "Segui la discussione" + +#: ../../include/conversation.php:941 +msgid "View Status" +msgstr "Guarda il messaggio di stato" + +#: ../../include/conversation.php:943 +msgid "View Photos" +msgstr "Guarda le foto" + +#: ../../include/conversation.php:944 +msgid "Matrix Activity" +msgstr "Attività nella tua rete" + +#: ../../include/conversation.php:946 +msgid "Edit Contact" +msgstr "Modifica il contatto" + +#: ../../include/conversation.php:947 +msgid "Send PM" +msgstr "Invia messaggio privato" + +#: ../../include/conversation.php:948 ../../include/apps.php:145 +msgid "Poke" +msgstr "Poke" + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s likes this." +msgstr "Piace a %s." + +#: ../../include/conversation.php:1062 +#, php-format +msgid "%s doesn't like this." +msgstr "Non piace a %s." + +#: ../../include/conversation.php:1066 +#, php-format +msgid "%2$d people like this." +msgid_plural "%2$d people like this." +msgstr[0] "" +msgstr[1] "Piace a %2$d persone." + +#: ../../include/conversation.php:1068 +#, php-format +msgid "%2$d people don't like this." +msgid_plural "%2$d people don't like this." +msgstr[0] "" +msgstr[1] "Non piace a %2$d persone." + +#: ../../include/conversation.php:1074 +msgid "and" +msgstr "e" + +#: ../../include/conversation.php:1077 +#, php-format +msgid ", and %d other people" +msgid_plural ", and %d other people" +msgstr[0] "" +msgstr[1] "e altre %d persone" + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s like this." +msgstr "Piace a %s." + +#: ../../include/conversation.php:1078 +#, php-format +msgid "%s don't like this." +msgstr "Non piace a %s." + +#: ../../include/conversation.php:1138 +msgid "Visible to everybody" +msgstr "Visibile a tutti" + +#: ../../include/conversation.php:1139 ../../mod/mail.php:174 +#: ../../mod/mail.php:289 +msgid "Please enter a link URL:" +msgstr "Inserisci l'indirizzo del link:" + +#: ../../include/conversation.php:1140 +msgid "Please enter a video link/URL:" +msgstr "Inserisci l'indirizzo del video:" + +#: ../../include/conversation.php:1141 +msgid "Please enter an audio link/URL:" +msgstr "Inserisci l'indirizzo dell'audio:" + +#: ../../include/conversation.php:1142 +msgid "Tag term:" +msgstr "Tag:" + +#: ../../include/conversation.php:1143 ../../mod/filer.php:49 +msgid "Save to Folder:" +msgstr "Salva nella cartella:" + +#: ../../include/conversation.php:1144 +msgid "Where are you right now?" +msgstr "Dove sei ora?" + +#: ../../include/conversation.php:1145 ../../mod/editpost.php:52 +#: ../../mod/mail.php:175 ../../mod/mail.php:290 +msgid "Expires YYYY-MM-DD HH:MM" +msgstr "Scade il YYYY-MM-DD HH:MM" + +#: ../../include/conversation.php:1172 ../../mod/photos.php:949 +#: ../../mod/editlayout.php:197 ../../mod/webpages.php:180 +#: ../../mod/blocks.php:149 ../../mod/layouts.php:175 +msgid "Share" +msgstr "Condividi" + +#: ../../include/conversation.php:1174 +msgid "Page link name" +msgstr "Nome del link alla pagina" + +#: ../../include/conversation.php:1177 +msgid "Post as" +msgstr "Pubblica come " + +#: ../../include/conversation.php:1184 ../../mod/editlayout.php:145 +#: ../../mod/editwebpage.php:184 ../../mod/editpost.php:119 +#: ../../mod/editblock.php:147 ../../mod/mail.php:238 ../../mod/mail.php:352 +msgid "Upload photo" +msgstr "Carica foto" + +#: ../../include/conversation.php:1185 +msgid "upload photo" +msgstr "carica foto" + +#: ../../include/conversation.php:1186 ../../mod/editlayout.php:146 +#: ../../mod/editwebpage.php:185 ../../mod/editpost.php:120 +#: ../../mod/editblock.php:148 ../../mod/mail.php:239 ../../mod/mail.php:353 +msgid "Attach file" +msgstr "Allega file" + +#: ../../include/conversation.php:1187 +msgid "attach file" +msgstr "allega file" + +#: ../../include/conversation.php:1188 ../../mod/editlayout.php:147 +#: ../../mod/editwebpage.php:186 ../../mod/editpost.php:121 +#: ../../mod/editblock.php:149 ../../mod/mail.php:240 ../../mod/mail.php:354 +msgid "Insert web link" +msgstr "Inserisci un indirizzo web" + +#: ../../include/conversation.php:1189 +msgid "web link" +msgstr "link web" + +#: ../../include/conversation.php:1190 +msgid "Insert video link" +msgstr "Inserisci l'indirizzo di un video" + +#: ../../include/conversation.php:1191 +msgid "video link" +msgstr "link video" + +#: ../../include/conversation.php:1192 +msgid "Insert audio link" +msgstr "Inserisci l'indirizzo di un audio" + +#: ../../include/conversation.php:1193 +msgid "audio link" +msgstr "link audio" + +#: ../../include/conversation.php:1194 ../../mod/editlayout.php:151 +#: ../../mod/editwebpage.php:190 ../../mod/editpost.php:125 +#: ../../mod/editblock.php:153 +msgid "Set your location" +msgstr "La tua località" + +#: ../../include/conversation.php:1195 +msgid "set location" +msgstr "la tua località" + +#: ../../include/conversation.php:1196 ../../mod/editpost.php:127 +msgid "Toggle voting" +msgstr "Abilita/disabilita il voto" + +#: ../../include/conversation.php:1199 ../../mod/editlayout.php:152 +#: ../../mod/editwebpage.php:191 ../../mod/editpost.php:126 +#: ../../mod/editblock.php:154 +msgid "Clear browser location" +msgstr "Rimuovi la località data dal browser" + +#: ../../include/conversation.php:1200 +msgid "clear location" +msgstr "rimuovi la località" + +#: ../../include/conversation.php:1202 ../../mod/editlayout.php:164 +#: ../../mod/editwebpage.php:207 ../../mod/editpost.php:141 +#: ../../mod/editblock.php:167 +msgid "Title (optional)" +msgstr "Titolo (opzionale)" + +#: ../../include/conversation.php:1205 ../../mod/editlayout.php:167 +#: ../../mod/editwebpage.php:209 ../../mod/editpost.php:143 +#: ../../mod/editblock.php:170 +msgid "Categories (optional, comma-separated list)" +msgstr "Categorie (lista separata da virgole)" + +#: ../../include/conversation.php:1207 ../../mod/editlayout.php:154 +#: ../../mod/editwebpage.php:193 ../../mod/editpost.php:131 +#: ../../mod/editblock.php:156 +msgid "Permission settings" +msgstr "Impostazioni permessi" + +#: ../../include/conversation.php:1208 +msgid "permissions" +msgstr "permessi" + +#: ../../include/conversation.php:1216 ../../mod/editlayout.php:161 +#: ../../mod/editwebpage.php:202 ../../mod/editpost.php:138 +#: ../../mod/editblock.php:164 +msgid "Public post" +msgstr "Articolo pubblico" + +#: ../../include/conversation.php:1218 ../../mod/editlayout.php:168 +#: ../../mod/editwebpage.php:210 ../../mod/editpost.php:144 +#: ../../mod/editblock.php:171 +msgid "Example: bob@example.com, mary@example.com" +msgstr "Per esempio: mario@esempio.com, simona@esempio.com" + +#: ../../include/conversation.php:1231 ../../mod/editlayout.php:177 +#: ../../mod/editwebpage.php:219 ../../mod/editpost.php:155 +#: ../../mod/editblock.php:181 ../../mod/mail.php:245 ../../mod/mail.php:359 +msgid "Set expiration date" +msgstr "Data di scadenza" + +#: ../../include/conversation.php:1235 ../../mod/events.php:637 +#: ../../mod/editpost.php:159 +msgid "OK" +msgstr "OK" + +#: ../../include/conversation.php:1236 ../../mod/settings.php:583 +#: ../../mod/settings.php:609 ../../mod/tagrm.php:11 ../../mod/tagrm.php:134 +#: ../../mod/events.php:636 ../../mod/fbrowser.php:82 +#: ../../mod/fbrowser.php:117 ../../mod/editpost.php:160 +msgid "Cancel" +msgstr "Annulla" + +#: ../../include/conversation.php:1478 +msgid "Discover" +msgstr "Scopri" + +#: ../../include/conversation.php:1481 +msgid "Imported public streams" +msgstr "Contenuti pubblici importati" + +#: ../../include/conversation.php:1486 +msgid "Commented Order" +msgstr "Ultimi commenti" + +#: ../../include/conversation.php:1489 +msgid "Sort by Comment Date" +msgstr "Per data del commento" + +#: ../../include/conversation.php:1493 +msgid "Posted Order" +msgstr "Ultimi articoli" + +#: ../../include/conversation.php:1496 +msgid "Sort by Post Date" +msgstr "Per data di creazione" + +#: ../../include/conversation.php:1504 +msgid "Posts that mention or involve you" +msgstr "Articoli che ti riguardano o ti menzionano" + +#: ../../include/conversation.php:1510 ../../mod/connections.php:212 +#: ../../mod/connections.php:225 ../../mod/menu.php:102 +msgid "New" +msgstr "Novità" + +#: ../../include/conversation.php:1513 +msgid "Activity Stream - by date" +msgstr "Elenco attività - per data" + +#: ../../include/conversation.php:1519 +msgid "Starred" +msgstr "Preferiti" + +#: ../../include/conversation.php:1522 +msgid "Favourite Posts" +msgstr "Articoli preferiti" + +#: ../../include/conversation.php:1529 +msgid "Spam" +msgstr "Spam" + +#: ../../include/conversation.php:1532 +msgid "Posts flagged as SPAM" +msgstr "Articoli marcati come spam" + +#: ../../include/conversation.php:1576 ../../mod/admin.php:952 +msgid "Channel" +msgstr "Canale" + +#: ../../include/conversation.php:1579 +msgid "Status Messages and Posts" +msgstr "Articoli e messaggi di stato" + +#: ../../include/conversation.php:1588 +msgid "About" +msgstr "Informazioni" + +#: ../../include/conversation.php:1591 +msgid "Profile Details" +msgstr "Dettagli del profilo" + +#: ../../include/conversation.php:1600 ../../include/photos.php:359 +msgid "Photo Albums" +msgstr "Album foto" + +#: ../../include/conversation.php:1609 +msgid "Files and Storage" +msgstr "Archivio file" + +#: ../../include/conversation.php:1619 ../../include/conversation.php:1622 +msgid "Chatrooms" +msgstr "Area chat" + +#: ../../include/conversation.php:1635 +msgid "Saved Bookmarks" +msgstr "Segnalibri salvati" + +#: ../../include/conversation.php:1645 +msgid "Manage Webpages" +msgstr "Gestisci le pagine web" + +#: ../../include/conversation.php:1704 +msgctxt "noun" +msgid "Attending" +msgid_plural "Attending" +msgstr[0] "Partecipa" +msgstr[1] "Partecipano" + +#: ../../include/conversation.php:1707 +msgctxt "noun" +msgid "Not Attending" +msgid_plural "Not Attending" +msgstr[0] "Non partecipa" +msgstr[1] "Non partecipano" + +#: ../../include/conversation.php:1710 +msgctxt "noun" +msgid "Undecided" +msgid_plural "Undecided" +msgstr[0] "Indeciso" +msgstr[1] "Indecisi" + +#: ../../include/conversation.php:1713 +msgctxt "noun" +msgid "Agree" +msgid_plural "Agrees" +msgstr[0] "D'accordo" +msgstr[1] "D'accordo" + +#: ../../include/conversation.php:1716 +msgctxt "noun" +msgid "Disagree" +msgid_plural "Disagrees" +msgstr[0] "Non d'accordo" +msgstr[1] "Non d'accordo" + +#: ../../include/conversation.php:1719 +msgctxt "noun" +msgid "Abstain" +msgid_plural "Abstains" +msgstr[0] "Astenuto" +msgstr[1] "Astenuti" + +#: ../../include/photos.php:94 +#, php-format +msgid "Image exceeds website size limit of %lu bytes" +msgstr "L'immagine supera il limite massimo di %lu bytes" + +#: ../../include/photos.php:101 +msgid "Image file is empty." +msgstr "Il file dell'immagine è vuoto." + +#: ../../include/photos.php:128 ../../mod/profile_photo.php:217 +msgid "Unable to process image" +msgstr "Impossibile elaborare l'immagine" + +#: ../../include/photos.php:199 +msgid "Photo storage failed." +msgstr "Impossibile caricare la foto." + +#: ../../include/photos.php:363 +msgid "Upload New Photos" +msgstr "Carica nuove foto" + +#: ../../include/zot.php:666 +msgid "Invalid data packet" +msgstr "Dati non validi" + +#: ../../include/zot.php:682 +msgid "Unable to verify channel signature" +msgstr "Impossibile verificare la firma elettronica del canale" + +#: ../../include/zot.php:2108 +#, php-format +msgid "Unable to verify site signature for %s" +msgstr "Impossibile verificare la firma elettronica del sito %s" + +#: ../../include/oembed.php:183 +msgid "Embedded content" +msgstr "Contenuti incorporati" + +#: ../../include/oembed.php:192 +msgid "Embedding disabled" +msgstr "Disabilita la creazione di contenuti incorporati" + +#: ../../include/auth.php:131 +msgid "Logged out." +msgstr "Uscita effettuata." + +#: ../../include/auth.php:272 +msgid "Failed authentication" +msgstr "Autenticazione fallita" + +#: ../../include/auth.php:286 ../../mod/openid.php:190 +msgid "Login failed." +msgstr "Accesso fallito." + +#: ../../include/contact_widgets.php:14 +#, php-format +msgid "%d invitation available" +msgid_plural "%d invitations available" +msgstr[0] "%d invito disponibile" +msgstr[1] "%d inviti disponibili" + +#: ../../include/contact_widgets.php:19 ../../mod/admin.php:450 +msgid "Advanced" +msgstr "Avanzate" + +#: ../../include/contact_widgets.php:22 +msgid "Find Channels" +msgstr "Ricerca canali" + +#: ../../include/contact_widgets.php:23 +msgid "Enter name or interest" +msgstr "Scrivi un nome o un interesse" + +#: ../../include/contact_widgets.php:24 +msgid "Connect/Follow" +msgstr "Aggiungi" + +#: ../../include/contact_widgets.php:25 +msgid "Examples: Robert Morgenstein, Fishing" +msgstr "Per esempio: Mario Rossi, Pesca" + +#: ../../include/contact_widgets.php:26 ../../mod/connections.php:413 +#: ../../mod/directory.php:362 ../../mod/directory.php:367 +msgid "Find" +msgstr "Cerca" + +#: ../../include/contact_widgets.php:27 ../../mod/directory.php:366 +#: ../../mod/suggest.php:60 +msgid "Channel Suggestions" +msgstr "Canali suggeriti" + +#: ../../include/contact_widgets.php:29 +msgid "Random Profile" +msgstr "Profilo casuale" + +#: ../../include/contact_widgets.php:30 +msgid "Invite Friends" +msgstr "Invita amici" + +#: ../../include/contact_widgets.php:32 +msgid "Advanced example: name=fred and country=iceland" +msgstr "Per esempio: name=mario e country=italy" + +#: ../../include/contact_widgets.php:125 +#, php-format +msgid "%d connection in common" +msgid_plural "%d connections in common" +msgstr[0] "%d contatto in comune" +msgstr[1] "%d contatti in comune" + +#: ../../include/contact_widgets.php:130 +msgid "show more" +msgstr "mostra tutto" + +#: ../../include/acl_selectors.php:240 +msgid "Visible to your default audience" +msgstr "Visibile secondo le impostazioni predefinite" + +#: ../../include/acl_selectors.php:241 +msgid "Show" +msgstr "Mostra" + +#: ../../include/acl_selectors.php:242 +msgid "Don't show" +msgstr "Non mostrare" + +#: ../../include/acl_selectors.php:248 ../../mod/events.php:654 +#: ../../mod/photos.php:559 ../../mod/photos.php:922 ../../mod/chat.php:209 +#: ../../mod/filestorage.php:147 +msgid "Permissions" +msgstr "Permessi" + +#: ../../include/attach.php:241 ../../include/attach.php:299 +msgid "Item was not found." +msgstr "Elemento non trovato." + +#: ../../include/attach.php:356 +msgid "No source file." +msgstr "Nessun file di origine." + +#: ../../include/attach.php:374 +msgid "Cannot locate file to replace" +msgstr "Il file da sostituire non è stato trovato" + +#: ../../include/attach.php:392 +msgid "Cannot locate file to revise/update" +msgstr "Il file da aggiornare non è stato trovato" + +#: ../../include/attach.php:403 +#, php-format +msgid "File exceeds size limit of %d" +msgstr "Il file supera la dimensione massima di %d" + +#: ../../include/attach.php:415 +#, php-format +msgid "You have reached your limit of %1$.0f Mbytes attachment storage." +msgstr "Hai raggiunto il limite complessivo di %1$.0f Mbytes per gli allegati." + +#: ../../include/attach.php:498 +msgid "File upload failed. Possible system limit or action terminated." +msgstr "Caricamento file fallito, potrebbe essere stato interrotto o potrebbe aver superato lo spazio assegnato." + +#: ../../include/attach.php:510 +msgid "Stored file could not be verified. Upload failed." +msgstr "Il file non può essere verificato. Caricamento fallito." + +#: ../../include/attach.php:554 ../../include/attach.php:571 +msgid "Path not available." +msgstr "Percorso non disponibile." + +#: ../../include/attach.php:616 +msgid "Empty pathname" +msgstr "Il percorso del file è vuoto" + +#: ../../include/attach.php:632 +msgid "duplicate filename or path" +msgstr "il file o il percorso del file è duplicato" + +#: ../../include/attach.php:656 +msgid "Path not found." +msgstr "Percorso del file non trovato." + +#: ../../include/attach.php:707 +msgid "mkdir failed." +msgstr "mkdir fallito." + +#: ../../include/attach.php:711 +msgid "database storage failed." +msgstr "scrittura su database fallita." + +#: ../../include/identity.php:33 +msgid "Unable to obtain identity information from database" +msgstr "Impossibile ottenere le informazioni di identificazione dal database" + +#: ../../include/identity.php:67 +msgid "Empty name" +msgstr "Nome vuoto" + +#: ../../include/identity.php:70 +msgid "Name too long" +msgstr "Nome troppo lungo" + +#: ../../include/identity.php:186 +msgid "No account identifier" +msgstr "Account senza identificativo" + +#: ../../include/identity.php:198 +msgid "Nickname is required." +msgstr "Il nome dell'account è obbligatorio." + +#: ../../include/identity.php:212 +msgid "Reserved nickname. Please choose another." +msgstr "Nome utente riservato. Per favore scegline un altro." + +#: ../../include/identity.php:217 ../../include/dimport.php:34 +msgid "" +"Nickname has unsupported characters or is already being used on this site." +msgstr "Il nome dell'account è già in uso oppure ha dei caratteri non supportati." + +#: ../../include/identity.php:292 +msgid "Unable to retrieve created identity" +msgstr "Impossibile caricare l'identità creata" + +#: ../../include/identity.php:350 +msgid "Default Profile" +msgstr "Profilo predefinito" + +#: ../../include/identity.php:630 +msgid "Requested channel is not available." +msgstr "Il canale che cerchi non è disponibile." + +#: ../../include/identity.php:677 ../../mod/profile.php:16 +#: ../../mod/achievements.php:11 ../../mod/connect.php:13 +#: ../../mod/hcard.php:8 ../../mod/editlayout.php:28 +#: ../../mod/editwebpage.php:28 ../../mod/filestorage.php:54 +#: ../../mod/webpages.php:29 ../../mod/editblock.php:29 +#: ../../mod/blocks.php:29 ../../mod/layouts.php:29 +msgid "Requested profile is not available." +msgstr "Il profilo richiesto non è disponibile." + +#: ../../include/identity.php:836 ../../mod/profiles.php:774 +msgid "Change profile photo" +msgstr "Cambia la foto del profilo" + +#: ../../include/identity.php:842 +msgid "Profiles" +msgstr "Profili" + +#: ../../include/identity.php:842 +msgid "Manage/edit profiles" +msgstr "Gestisci/modifica i profili" + +#: ../../include/identity.php:843 ../../mod/profiles.php:775 +msgid "Create New Profile" +msgstr "Crea un nuovo profilo" + +#: ../../include/identity.php:858 ../../mod/profiles.php:786 +msgid "Profile Image" +msgstr "Immagine del profilo" + +#: ../../include/identity.php:861 +msgid "visible to everybody" +msgstr "visibile a tutti" + +#: ../../include/identity.php:862 ../../mod/profiles.php:669 +#: ../../mod/profiles.php:790 +msgid "Edit visibility" +msgstr "Cambia la visibilità" + +#: ../../include/identity.php:878 ../../include/identity.php:1117 +msgid "Gender:" +msgstr "Sesso:" + +#: ../../include/identity.php:879 ../../include/identity.php:1161 +msgid "Status:" +msgstr "Stato:" + +#: ../../include/identity.php:880 ../../include/identity.php:1172 +msgid "Homepage:" +msgstr "Home page:" + +#: ../../include/identity.php:881 +msgid "Online Now" +msgstr "Online adesso" + +#: ../../include/identity.php:964 ../../include/identity.php:1042 +#: ../../mod/ping.php:324 +msgid "g A l F d" +msgstr "g A l d F" + +#: ../../include/identity.php:965 ../../include/identity.php:1043 +msgid "F d" +msgstr "d F" + +#: ../../include/identity.php:1010 ../../include/identity.php:1082 +#: ../../mod/ping.php:346 +msgid "[today]" +msgstr "[oggi]" + +#: ../../include/identity.php:1021 +msgid "Birthday Reminders" +msgstr "Promemoria compleanni" + +#: ../../include/identity.php:1022 +msgid "Birthdays this week:" +msgstr "Compleanni questa settimana:" + +#: ../../include/identity.php:1075 +msgid "[No description]" +msgstr "[Nessuna descrizione]" + +#: ../../include/identity.php:1093 +msgid "Event Reminders" +msgstr "Promemoria" + +#: ../../include/identity.php:1094 +msgid "Events this week:" +msgstr "Eventi di questa settimana:" + +#: ../../include/identity.php:1107 ../../include/identity.php:1224 +#: ../../include/apps.php:138 ../../mod/profperm.php:112 +msgid "Profile" +msgstr "Profilo" + +#: ../../include/identity.php:1115 ../../mod/settings.php:1045 +msgid "Full Name:" +msgstr "Nome completo:" + +#: ../../include/identity.php:1122 +msgid "Like this channel" +msgstr "Mi piace questo canale" + +#: ../../include/identity.php:1146 +msgid "j F, Y" +msgstr "j F Y" + +#: ../../include/identity.php:1147 +msgid "j F" +msgstr "j F" + +#: ../../include/identity.php:1154 +msgid "Birthday:" +msgstr "Compleanno:" + +#: ../../include/identity.php:1158 +msgid "Age:" +msgstr "Età:" + +#: ../../include/identity.php:1167 +#, php-format +msgid "for %1$d %2$s" +msgstr "per %1$d %2$s" + +#: ../../include/identity.php:1170 ../../mod/profiles.php:691 +msgid "Sexual Preference:" +msgstr "Preferenze sessuali:" + +#: ../../include/identity.php:1174 ../../mod/profiles.php:693 +msgid "Hometown:" +msgstr "Città dove vivo:" + +#: ../../include/identity.php:1176 +msgid "Tags:" +msgstr "Tag:" + +#: ../../include/identity.php:1178 ../../mod/profiles.php:694 +msgid "Political Views:" +msgstr "Orientamento politico:" + +#: ../../include/identity.php:1180 +msgid "Religion:" +msgstr "Religione:" + +#: ../../include/identity.php:1182 +msgid "About:" +msgstr "Informazioni:" + +#: ../../include/identity.php:1184 +msgid "Hobbies/Interests:" +msgstr "Interessi e hobby:" + +#: ../../include/identity.php:1186 ../../mod/profiles.php:697 +msgid "Likes:" +msgstr "Mi piace:" + +#: ../../include/identity.php:1188 ../../mod/profiles.php:698 +msgid "Dislikes:" +msgstr "Non mi piace:" + +#: ../../include/identity.php:1190 +msgid "Contact information and Social Networks:" +msgstr "Contatti e social network:" + +#: ../../include/identity.php:1192 +msgid "My other channels:" +msgstr "I miei altri canali:" + +#: ../../include/identity.php:1194 +msgid "Musical interests:" +msgstr "Gusti musicali:" + +#: ../../include/identity.php:1196 +msgid "Books, literature:" +msgstr "Libri, letteratura:" + +#: ../../include/identity.php:1198 +msgid "Television:" +msgstr "Televisione:" + +#: ../../include/identity.php:1200 +msgid "Film/dance/culture/entertainment:" +msgstr "Film, danza, cultura, intrattenimento:" + +#: ../../include/identity.php:1202 +msgid "Love/Romance:" +msgstr "Amore:" + +#: ../../include/identity.php:1204 +msgid "Work/employment:" +msgstr "Lavoro:" + +#: ../../include/identity.php:1206 +msgid "School/education:" +msgstr "Scuola:" + +#: ../../include/identity.php:1226 +msgid "Like this thing" +msgstr "Mi piace questo Oggetto" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:103 +msgid "Male" +msgstr "Maschio" + +#: ../../include/profile_selectors.php:6 +#: ../../include/profile_selectors.php:23 ../../mod/id.php:105 +msgid "Female" +msgstr "Femmina" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Male" +msgstr "Al momento maschio" + +#: ../../include/profile_selectors.php:6 +msgid "Currently Female" +msgstr "Al momento femmina" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Male" +msgstr "Prevalentemente maschio" + +#: ../../include/profile_selectors.php:6 +msgid "Mostly Female" +msgstr "Prevalentemente femmina" + +#: ../../include/profile_selectors.php:6 +msgid "Transgender" +msgstr "Transgender" + +#: ../../include/profile_selectors.php:6 +msgid "Intersex" +msgstr "Intersex" + +#: ../../include/profile_selectors.php:6 +msgid "Transsexual" +msgstr "Transessuale" + +#: ../../include/profile_selectors.php:6 +msgid "Hermaphrodite" +msgstr "Ermafrodito" + +#: ../../include/profile_selectors.php:6 +msgid "Neuter" +msgstr "Neutro" + +#: ../../include/profile_selectors.php:6 +msgid "Non-specific" +msgstr "Non specificato" + +#: ../../include/profile_selectors.php:6 +msgid "Undecided" +msgstr "Indeciso" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Males" +msgstr "Maschi" + +#: ../../include/profile_selectors.php:42 +#: ../../include/profile_selectors.php:61 +msgid "Females" +msgstr "Femmine" + +#: ../../include/profile_selectors.php:42 +msgid "Gay" +msgstr "Gay" + +#: ../../include/profile_selectors.php:42 +msgid "Lesbian" +msgstr "Lesbica" + +#: ../../include/profile_selectors.php:42 +msgid "No Preference" +msgstr "Senza preferenza" + +#: ../../include/profile_selectors.php:42 +msgid "Bisexual" +msgstr "Bisessuale" + +#: ../../include/profile_selectors.php:42 +msgid "Autosexual" +msgstr "Autosessuale" + +#: ../../include/profile_selectors.php:42 +msgid "Abstinent" +msgstr "Astinente" + +#: ../../include/profile_selectors.php:42 +msgid "Virgin" +msgstr "Vergine" + +#: ../../include/profile_selectors.php:42 +msgid "Deviant" +msgstr "Deviato" + +#: ../../include/profile_selectors.php:42 +msgid "Fetish" +msgstr "Feticista" + +#: ../../include/profile_selectors.php:42 +msgid "Oodles" +msgstr "Un sacco" + +#: ../../include/profile_selectors.php:42 +msgid "Nonsexual" +msgstr "Asessuato" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Single" +msgstr "Single" + +#: ../../include/profile_selectors.php:80 +msgid "Lonely" +msgstr "Da solo" + +#: ../../include/profile_selectors.php:80 +msgid "Available" +msgstr "Disponibile" + +#: ../../include/profile_selectors.php:80 +msgid "Unavailable" +msgstr "Non disponibile" + +#: ../../include/profile_selectors.php:80 +msgid "Has crush" +msgstr "Ha una cotta" + +#: ../../include/profile_selectors.php:80 +msgid "Infatuated" +msgstr "Infatuato/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Dating" +msgstr "Disponibile a un incontro" + +#: ../../include/profile_selectors.php:80 +msgid "Unfaithful" +msgstr "Infedele" + +#: ../../include/profile_selectors.php:80 +msgid "Sex Addict" +msgstr "Sesso-dipendente" + +#: ../../include/profile_selectors.php:80 +msgid "Friends/Benefits" +msgstr "Amici con qualcosa in più" + +#: ../../include/profile_selectors.php:80 +msgid "Casual" +msgstr "Casual" + +#: ../../include/profile_selectors.php:80 +msgid "Engaged" +msgstr "Impegnato" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Married" +msgstr "Sposato/a" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily married" +msgstr "Con matrimonio immaginario" + +#: ../../include/profile_selectors.php:80 +msgid "Partners" +msgstr "Partner" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Cohabiting" +msgstr "Convivente" + +#: ../../include/profile_selectors.php:80 +msgid "Common law" +msgstr "Matrimonio regolare" + +#: ../../include/profile_selectors.php:80 +msgid "Happy" +msgstr "Felice" + +#: ../../include/profile_selectors.php:80 +msgid "Not looking" +msgstr "Non in cerca" + +#: ../../include/profile_selectors.php:80 +msgid "Swinger" +msgstr "Scambista" + +#: ../../include/profile_selectors.php:80 +msgid "Betrayed" +msgstr "Tradito/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Separated" +msgstr "Separato/a" + +#: ../../include/profile_selectors.php:80 +msgid "Unstable" +msgstr "Instabile" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Divorced" +msgstr "Divorziato/a" + +#: ../../include/profile_selectors.php:80 +msgid "Imaginarily divorced" +msgstr "Sogna il divorzio" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "Widowed" +msgstr "Vedovo/a" + +#: ../../include/profile_selectors.php:80 +msgid "Uncertain" +msgstr "Incerto/a" + +#: ../../include/profile_selectors.php:80 +#: ../../include/profile_selectors.php:97 +msgid "It's complicated" +msgstr "Relazione complicata" + +#: ../../include/profile_selectors.php:80 +msgid "Don't care" +msgstr "Chi se ne frega" + +#: ../../include/profile_selectors.php:80 +msgid "Ask me" +msgstr "Chiedimelo" + +#: ../../include/apps.php:128 +msgid "Site Admin" +msgstr "Amministrazione sito" + +#: ../../include/apps.php:130 +msgid "Address Book" +msgstr "Rubrica" + +#: ../../include/apps.php:144 ../../mod/mood.php:130 +msgid "Mood" +msgstr "Umore" + +#: ../../include/apps.php:148 +msgid "Probe" +msgstr "Diagnostica" + +#: ../../include/apps.php:149 +msgid "Suggest" +msgstr "Suggerisci" + +#: ../../include/apps.php:150 +msgid "Random Channel" +msgstr "Canale casuale" + +#: ../../include/apps.php:151 +msgid "Invite" +msgstr "Invita" + +#: ../../include/apps.php:152 +msgid "Features" +msgstr "Funzionalità" + +#: ../../include/apps.php:153 ../../mod/id.php:28 +msgid "Language" +msgstr "Lingua" + +#: ../../include/apps.php:154 +msgid "Post" +msgstr "Articolo" + +#: ../../include/apps.php:155 ../../mod/id.php:17 ../../mod/id.php:18 +#: ../../mod/id.php:19 +msgid "Profile Photo" +msgstr "Foto del profilo" + +#: ../../include/apps.php:247 ../../mod/settings.php:84 +#: ../../mod/settings.php:608 +msgid "Update" +msgstr "Aggiorna" + +#: ../../include/apps.php:247 +msgid "Install" +msgstr "Installa" + +#: ../../include/apps.php:252 +msgid "Purchase" +msgstr "Acquista" + +#: ../../include/chat.php:23 +msgid "Missing room name" +msgstr "Area chat senza nome" + +#: ../../include/chat.php:32 +msgid "Duplicate room name" +msgstr "Il nome dell'area chat è duplicato" + +#: ../../include/chat.php:82 ../../include/chat.php:90 +msgid "Invalid room specifier." +msgstr "Il nome dell'area chat non è valido." + +#: ../../include/chat.php:120 +msgid "Room not found." +msgstr "Area chat non trovata." + +#: ../../include/chat.php:141 +msgid "Room is full" +msgstr "L'area chat è al completo" + +#: ../../mod/achievements.php:34 +msgid "Some blurb about what to do when you're new here" +msgstr "Qualche suggerimento per i nuovi utenti su cosa fare" + +#: ../../mod/manage.php:136 +#, php-format +msgid "You have created %1$.0f of %2$.0f allowed channels." +msgstr "Hai creato %1$.0f dei %2$.0f canali permessi." + +#: ../../mod/manage.php:144 +msgid "Create a new channel" +msgstr "Crea un nuovo canale" + +#: ../../mod/manage.php:167 +msgid "Current Channel" +msgstr "Canale attuale" + +#: ../../mod/manage.php:169 +msgid "Switch to one of your channels by selecting it." +msgstr "Per passare a un altro tuo canale selezionalo." + +#: ../../mod/manage.php:170 +msgid "Default Channel" +msgstr "Canale predefinito" + +#: ../../mod/manage.php:171 +msgid "Make Default" +msgstr "Rendi predefinito" + +#: ../../mod/manage.php:174 +#, php-format +msgid "%d new messages" +msgstr "%d nuovi messaggi" + +#: ../../mod/manage.php:175 +#, php-format +msgid "%d new introductions" +msgstr "%d nuove richieste di entrare in contatto" + +#: ../../mod/manage.php:177 +msgid "Delegated Channels" +msgstr "Canali delegati" + +#: ../../mod/settings.php:76 +msgid "Name is required" +msgstr "Il nome è obbligatorio" + +#: ../../mod/settings.php:80 +msgid "Key and Secret are required" +msgstr "Key e Secret sono richiesti" + +#: ../../mod/settings.php:124 +msgid "Diaspora Policy Settings updated." +msgstr "Le regole per Diaspora sono state aggiornate." + +#: ../../mod/settings.php:232 +msgid "Passwords do not match. Password unchanged." +msgstr "Le password non corrispondono. Password non cambiata." + +#: ../../mod/settings.php:236 +msgid "Empty passwords are not allowed. Password unchanged." +msgstr "Le password non possono essere vuote. Password non cambiata." + +#: ../../mod/settings.php:250 +msgid "Password changed." +msgstr "Password cambiata." + +#: ../../mod/settings.php:252 +msgid "Password update failed. Please try again." +msgstr "Modifica password fallita. Prova ancora." + +#: ../../mod/settings.php:266 +msgid "Not valid email." +msgstr "Email non valida." + +#: ../../mod/settings.php:269 +msgid "Protected email address. Cannot change to that email." +msgstr "È un indirizzo email riservato. Non puoi sceglierlo." + +#: ../../mod/settings.php:278 +msgid "System failure storing new email. Please try again." +msgstr "Errore di sistema. Non è stato possibile memorizzare il tuo messaggio, riprova per favore." + +#: ../../mod/settings.php:517 +msgid "Settings updated." +msgstr "Impostazioni aggiornate." + +#: ../../mod/settings.php:573 ../../mod/api.php:106 ../../mod/photos.php:556 +#: ../../mod/menu.php:88 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:424 +#: ../../mod/removeme.php:60 ../../view/theme/redbasic/php/config.php:102 +#: ../../view/theme/redbasic/php/config.php:127 ../../boot.php:1544 +msgid "No" +msgstr "No" + +#: ../../mod/settings.php:573 ../../mod/api.php:105 ../../mod/photos.php:556 +#: ../../mod/menu.php:88 ../../mod/filestorage.php:151 +#: ../../mod/filestorage.php:159 ../../mod/admin.php:426 +#: ../../mod/removeme.php:60 ../../view/theme/redbasic/php/config.php:102 +#: ../../view/theme/redbasic/php/config.php:127 ../../boot.php:1544 +msgid "Yes" +msgstr "Si" + +#: ../../mod/settings.php:581 ../../mod/settings.php:607 +#: ../../mod/settings.php:643 +msgid "Add application" +msgstr "Aggiungi una app" + +#: ../../mod/settings.php:584 +msgid "Name of application" +msgstr "Nome dell'applicazione" + +#: ../../mod/settings.php:585 ../../mod/settings.php:611 +msgid "Consumer Key" +msgstr "Consumer Key" + +#: ../../mod/settings.php:585 ../../mod/settings.php:586 +msgid "Automatically generated - change if desired. Max length 20" +msgstr "Generato automaticamente - è possibile cambiarlo. Lunghezza massima 20" + +#: ../../mod/settings.php:586 ../../mod/settings.php:612 +msgid "Consumer Secret" +msgstr "Consumer Secret" + +#: ../../mod/settings.php:587 ../../mod/settings.php:613 +msgid "Redirect" +msgstr "Redirect" + +#: ../../mod/settings.php:587 +msgid "" +"Redirect URI - leave blank unless your application specifically requires " +"this" +msgstr "URI ridirezionato - lasciare bianco se non richiesto specificamente dall'applicazione." + +#: ../../mod/settings.php:588 ../../mod/settings.php:614 +msgid "Icon url" +msgstr "Url icona" + +#: ../../mod/settings.php:588 +msgid "Optional" +msgstr "Opzionale" + +#: ../../mod/settings.php:599 +msgid "You can't edit this application." +msgstr "Non puoi modificare questa applicazione." + +#: ../../mod/settings.php:642 +msgid "Connected Apps" +msgstr "App connesse" + +#: ../../mod/settings.php:646 +msgid "Client key starts with" +msgstr "La client key inizia con" + +#: ../../mod/settings.php:647 +msgid "No name" +msgstr "Nessun nome" + +#: ../../mod/settings.php:648 +msgid "Remove authorization" +msgstr "Revoca l'autorizzazione" + +#: ../../mod/settings.php:662 +msgid "No feature settings configured" +msgstr "Non hai componenti aggiuntivi da personalizzare" + +#: ../../mod/settings.php:678 +msgid "Feature/Addon Settings" +msgstr "Impostazioni dei componenti aggiuntivi" + +#: ../../mod/settings.php:680 +msgid "Settings for the built-in Diaspora emulator" +msgstr "Interconnessione con Diaspora" + +#: ../../mod/settings.php:681 +msgid "Allow any Diaspora member to comment on your public posts" +msgstr "Permetti a tutti gli utenti di Diaspora di commentare i tuoi post pubblici" + +#: ../../mod/settings.php:682 +msgid "Diaspora Policy Settings" +msgstr "Regole per Diaspora" + +#: ../../mod/settings.php:683 +msgid "Prevent your hashtags from being redirected to other sites" +msgstr "Impedisci che i tuoi #tag puntino su altri siti" + +#: ../../mod/settings.php:707 +msgid "Account Settings" +msgstr "Il tuo account" + +#: ../../mod/settings.php:708 +msgid "Enter New Password:" +msgstr "Inserisci la nuova password:" + +#: ../../mod/settings.php:709 +msgid "Confirm New Password:" +msgstr "Conferma la nuova password:" + +#: ../../mod/settings.php:709 +msgid "Leave password fields blank unless changing" +msgstr "Lascia questi campi in bianco per non cambiare la password" + +#: ../../mod/settings.php:711 ../../mod/settings.php:1046 +msgid "Email Address:" +msgstr "Indirizzo email:" + +#: ../../mod/settings.php:712 ../../mod/removeaccount.php:61 +msgid "Remove Account" +msgstr "Elimina l'account" + +#: ../../mod/settings.php:713 +msgid "Remove this account including all its channels" +msgstr "Elimina questo account e tutti i suoi canali" + +#: ../../mod/settings.php:729 +msgid "Off" +msgstr "Off" + +#: ../../mod/settings.php:729 +msgid "On" +msgstr "On" + +#: ../../mod/settings.php:736 +msgid "Additional Features" +msgstr "Funzionalità opzionali" + +#: ../../mod/settings.php:760 +msgid "Connector Settings" +msgstr "Impostazioni del connettore" + +#: ../../mod/settings.php:799 +msgid "No special theme for mobile devices" +msgstr "Nessun tema per dispositivi mobili" + +#: ../../mod/settings.php:802 +#, php-format +msgid "%s - (Experimental)" +msgstr "%s - (Sperimentale)" + +#: ../../mod/settings.php:805 ../../mod/admin.php:396 +msgid "mobile" +msgstr "mobile" + +#: ../../mod/settings.php:841 +msgid "Display Settings" +msgstr "Aspetto" + +#: ../../mod/settings.php:847 +msgid "Display Theme:" +msgstr "Tema per schermi medio grandi:" + +#: ../../mod/settings.php:848 +msgid "Mobile Theme:" +msgstr "Tema per dispositivi mobili:" + +#: ../../mod/settings.php:849 +msgid "Enable user zoom on mobile devices" +msgstr "Attiva la possibilità di fare zoom sui dispositivi mobili" + +#: ../../mod/settings.php:850 +msgid "Update browser every xx seconds" +msgstr "Aggiorna il browser ogni x secondi" + +#: ../../mod/settings.php:850 +msgid "Minimum of 10 seconds, no maximum" +msgstr "Minimo 10 secondi, nessun limite massimo" + +#: ../../mod/settings.php:851 +msgid "Maximum number of conversations to load at any time:" +msgstr "Massimo numero di conversazioni da mostrare ogni volta:" + +#: ../../mod/settings.php:851 +msgid "Maximum of 100 items" +msgstr "Massimo 100" + +#: ../../mod/settings.php:852 +msgid "Show emoticons (smilies) as images" +msgstr "Mostra le faccine (smilies) come immagini" + +#: ../../mod/settings.php:853 +msgid "Link post titles to source" +msgstr "Il link del titolo di un articolo porta al sito originale" + +#: ../../mod/settings.php:854 +msgid "System Page Layout Editor - (advanced)" +msgstr "Modifica i layout di sistema (avanzato)" + +#: ../../mod/settings.php:857 +msgid "Use blog/list mode on channel page" +msgstr "Mostra il canale nella modalità blog" + +#: ../../mod/settings.php:857 ../../mod/settings.php:858 +msgid "(comments displayed separately)" +msgstr "(i commenti sono mostrati separatamente)" + +#: ../../mod/settings.php:858 +msgid "Use blog/list mode on matrix page" +msgstr "Mostra la tua rete in modalità blog" + +#: ../../mod/settings.php:859 +msgid "Channel page max height of content (in pixels)" +msgstr "Altezza massima dei contenuti del canale (in pixel)" + +#: ../../mod/settings.php:859 ../../mod/settings.php:860 +msgid "click to expand content exceeding this height" +msgstr "dovrai cliccare per mostrare i contenuti di dimensioni maggiori" + +#: ../../mod/settings.php:860 +msgid "Matrix page max height of content (in pixels)" +msgstr "Altezza massima dei contenuti della tua rete (in pixel)" + +#: ../../mod/settings.php:894 +msgid "Nobody except yourself" +msgstr "Nessuno tranne te" + +#: ../../mod/settings.php:895 +msgid "Only those you specifically allow" +msgstr "Solo chi riceve il mio permesso" + +#: ../../mod/settings.php:896 +msgid "Approved connections" +msgstr "Contatti approvati" + +#: ../../mod/settings.php:897 +msgid "Any connections" +msgstr "Tutti i contatti" + +#: ../../mod/settings.php:898 +msgid "Anybody on this website" +msgstr "Chiunque su questo sito" + +#: ../../mod/settings.php:899 +msgid "Anybody in this network" +msgstr "Chiunque su Red" + +#: ../../mod/settings.php:900 +msgid "Anybody authenticated" +msgstr "Chiunque sia autenticato" + +#: ../../mod/settings.php:901 +msgid "Anybody on the internet" +msgstr "Chiunque su internet" + +#: ../../mod/settings.php:975 +msgid "Publish your default profile in the network directory" +msgstr "Mostra il mio profilo predefinito nell'elenco pubblico dei canali" + +#: ../../mod/settings.php:980 +msgid "Allow us to suggest you as a potential friend to new members?" +msgstr "Vuoi essere suggerito come amico ai nuovi membri?" + +#: ../../mod/settings.php:984 ../../mod/profile_photo.php:366 +msgid "or" +msgstr "o" + +#: ../../mod/settings.php:989 +msgid "Your channel address is" +msgstr "L'indirizzo del tuo canale è" + +#: ../../mod/settings.php:1037 +msgid "Channel Settings" +msgstr "Impostazioni del canale" + +#: ../../mod/settings.php:1044 +msgid "Basic Settings" +msgstr "Impostazioni di base" + +#: ../../mod/settings.php:1047 +msgid "Your Timezone:" +msgstr "Il tuo fuso orario:" + +#: ../../mod/settings.php:1048 +msgid "Default Post Location:" +msgstr "Località predefinita:" + +#: ../../mod/settings.php:1048 +msgid "Geographical location to display on your posts" +msgstr "Posizione geografica da mostrare sui tuoi post" + +#: ../../mod/settings.php:1049 +msgid "Use Browser Location:" +msgstr "Usa la località rilevata dal browser:" + +#: ../../mod/settings.php:1051 +msgid "Adult Content" +msgstr "Contenuto per adulti" + +#: ../../mod/settings.php:1051 +msgid "" +"This channel frequently or regularly publishes adult content. (Please tag " +"any adult material and/or nudity with #NSFW)" +msgstr "Questo canale pubblica frequentemente contenuto per adulti. (I contenuti per adulti vanno taggati #NSFW - Not Safe For Work)" + +#: ../../mod/settings.php:1053 +msgid "Security and Privacy Settings" +msgstr "Impostazioni di sicurezza e privacy" + +#: ../../mod/settings.php:1055 +msgid "Your permissions are already configured. Click to view/adjust" +msgstr "I tuoi permessi sono già stati configurati. Clicca per vederli o modificarli" + +#: ../../mod/settings.php:1057 +msgid "Hide my online presence" +msgstr "Nascondi la mia presenza online" + +#: ../../mod/settings.php:1057 +msgid "Prevents displaying in your profile that you are online" +msgstr "Evita che sul tuo profilo compaia la tua presenza online" + +#: ../../mod/settings.php:1059 +msgid "Simple Privacy Settings:" +msgstr "Impostazioni di privacy semplificate" + +#: ../../mod/settings.php:1060 +msgid "" +"Very Public - extremely permissive (should be used with caution)" +msgstr "Tutto pubblico - estremamente permissivo (da usare con cautela)" + +#: ../../mod/settings.php:1061 +msgid "" +"Typical - default public, privacy when desired (similar to social " +"network permissions but with improved privacy)" +msgstr "Standard - contenuti normalmente pubblici, ma anche privati se necessario (simile ai social network ma con privacy migliorata)" + +#: ../../mod/settings.php:1062 +msgid "Private - default private, never open or public" +msgstr "Privato - contenuti normalmente privati, nulla è aperto o pubblico" + +#: ../../mod/settings.php:1063 +msgid "Blocked - default blocked to/from everybody" +msgstr "Bloccato - bloccato in invio e ricezione dei contenuti" + +#: ../../mod/settings.php:1065 +msgid "Allow others to tag your posts" +msgstr "Permetti ad altri di taggare i tuoi articoli" + +#: ../../mod/settings.php:1065 +msgid "" +"Often used by the community to retro-actively flag inappropriate content" +msgstr "Usato spesso dalla comunità per marcare contenuti inappropriati già esistenti" + +#: ../../mod/settings.php:1067 +msgid "Advanced Privacy Settings" +msgstr "Impostazioni di privacy avanzate" + +#: ../../mod/settings.php:1069 +msgid "Expire other channel content after this many days" +msgstr "Giorni dopo cui mettere in scadenza gli altri contenuti del canale" + +#: ../../mod/settings.php:1069 +msgid "0 or blank prevents expiration" +msgstr "Lascia vuoto oppure 0 per non impostare scadenze" + +#: ../../mod/settings.php:1070 +msgid "Maximum Friend Requests/Day:" +msgstr "Numero massimo giornaliero di richieste di amicizia:" + +#: ../../mod/settings.php:1070 +msgid "May reduce spam activity" +msgstr "Serve e ridurre lo spam" + +#: ../../mod/settings.php:1071 +msgid "Default Post Permissions" +msgstr "Permessi predefiniti per gli articoli" + +#: ../../mod/settings.php:1072 ../../mod/mitem.php:152 ../../mod/mitem.php:221 +msgid "(click to open/close)" +msgstr "(clicca per aprire/chiudere)" + +#: ../../mod/settings.php:1076 +msgid "Channel permissions category:" +msgstr "Categorie di permessi dei canali:" + +#: ../../mod/settings.php:1082 +msgid "Maximum private messages per day from unknown people:" +msgstr "Numero massimo giornaliero di messaggi privati da utenti sconosciuti:" + +#: ../../mod/settings.php:1082 +msgid "Useful to reduce spamming" +msgstr "Serve e ridurre lo spam" + +#: ../../mod/settings.php:1085 +msgid "Notification Settings" +msgstr "Impostazioni di notifica" + +#: ../../mod/settings.php:1086 +msgid "By default post a status message when:" +msgstr "Pubblica un messaggio di stato quando:" + +#: ../../mod/settings.php:1087 +msgid "accepting a friend request" +msgstr "accetto una nuova amicizia" + +#: ../../mod/settings.php:1088 +msgid "joining a forum/community" +msgstr "entro a far parte di un forum" + +#: ../../mod/settings.php:1089 +msgid "making an interesting profile change" +msgstr "faccio un cambiamento interessante al mio profilo" + +#: ../../mod/settings.php:1090 +msgid "Send a notification email when:" +msgstr "Invia una email di notifica quando:" + +#: ../../mod/settings.php:1091 +msgid "You receive a connection request" +msgstr "Ricevi una richiesta di entrare in contatto" + +#: ../../mod/settings.php:1092 +msgid "Your connections are confirmed" +msgstr "I tuoi contatti sono confermati" + +#: ../../mod/settings.php:1093 +msgid "Someone writes on your profile wall" +msgstr "Qualcuno scrive sulla tua bacheca" + +#: ../../mod/settings.php:1094 +msgid "Someone writes a followup comment" +msgstr "Qualcuno scrive un commento a un tuo articolo" + +#: ../../mod/settings.php:1095 +msgid "You receive a private message" +msgstr "Ricevi un messaggio privato" + +#: ../../mod/settings.php:1096 +msgid "You receive a friend suggestion" +msgstr "Ti viene suggerito un amico" + +#: ../../mod/settings.php:1097 +msgid "You are tagged in a post" +msgstr "Sei taggato in un articolo" + +#: ../../mod/settings.php:1098 +msgid "You are poked/prodded/etc. in a post" +msgstr "Ricevi un poke in un articolo" + +#: ../../mod/settings.php:1101 +msgid "Show visual notifications including:" +msgstr "Mostra queste notifiche a schermo:" + +#: ../../mod/settings.php:1103 +msgid "Unseen matrix activity" +msgstr "Nuove attività nella rete" + +#: ../../mod/settings.php:1104 +msgid "Unseen channel activity" +msgstr "Novità nei canali" + +#: ../../mod/settings.php:1105 +msgid "Unseen private messages" +msgstr "Nuovi messaggi privati" + +#: ../../mod/settings.php:1105 ../../mod/settings.php:1110 +#: ../../mod/settings.php:1111 ../../mod/settings.php:1112 +msgid "Recommended" +msgstr "Consigliato" + +#: ../../mod/settings.php:1106 +msgid "Upcoming events" +msgstr "Prossimi eventi" + +#: ../../mod/settings.php:1107 +msgid "Events today" +msgstr "Eventi di oggi" + +#: ../../mod/settings.php:1108 +msgid "Upcoming birthdays" +msgstr "Prossimi compleanni" + +#: ../../mod/settings.php:1108 +msgid "Not available in all themes" +msgstr "Non disponibile in tutti i temi" + +#: ../../mod/settings.php:1109 +msgid "System (personal) notifications" +msgstr "Notifiche personali dal sistema" + +#: ../../mod/settings.php:1110 +msgid "System info messages" +msgstr "Notifiche di sistema" + +#: ../../mod/settings.php:1111 +msgid "System critical alerts" +msgstr "Avvisi critici di sistema" + +#: ../../mod/settings.php:1112 +msgid "New connections" +msgstr "Nuovi contatti" + +#: ../../mod/settings.php:1113 +msgid "System Registrations" +msgstr "Registrazioni" + +#: ../../mod/settings.php:1114 +msgid "" +"Also show new wall posts, private messages and connections under Notices" +msgstr "Mostra negli avvisi anche i nuovi articoli, i messaggi privati e i nuovi contatti" + +#: ../../mod/settings.php:1116 +msgid "Notify me of events this many days in advance" +msgstr "Giorni di anticipo per notificare gli eventi" + +#: ../../mod/settings.php:1116 +msgid "Must be greater than 0" +msgstr "Maggiore di 0" + +#: ../../mod/settings.php:1118 +msgid "Advanced Account/Page Type Settings" +msgstr "Impostazioni avanzate" + +#: ../../mod/settings.php:1119 +msgid "Change the behaviour of this account for special situations" +msgstr "Cambia il funzionamento di questo account per necessità particolari" + +#: ../../mod/settings.php:1122 +msgid "" +"Please enable expert mode (in Settings > " +"Additional features) to adjust!" +msgstr "Abilita la modalità esperto per fare cambiamenti! (in Impostazioni > Funzionalità opzionali)" + +#: ../../mod/settings.php:1123 +msgid "Miscellaneous Settings" +msgstr "Impostazioni varie" + +#: ../../mod/settings.php:1125 +msgid "Personal menu to display in your channel pages" +msgstr "Menu personale da mostrare sulle pagine del tuo canale" + +#: ../../mod/settings.php:1126 ../../mod/removeme.php:61 +msgid "Remove Channel" +msgstr "Elimina questo canale" + +#: ../../mod/settings.php:1127 +msgid "Remove this channel." +msgstr "Elimina questo canale." + +#: ../../mod/xchan.php:6 +msgid "Xchan Lookup" +msgstr "Ricerca canale" + +#: ../../mod/xchan.php:9 +msgid "Lookup xchan beginning with (or webbie): " +msgstr "Cerca un canale (o un webbie) che inizia per:" + +#: ../../mod/xchan.php:37 ../../mod/menu.php:149 ../../mod/mitem.php:120 +msgid "Not found." +msgstr "Non trovato." + +#: ../../mod/api.php:76 ../../mod/api.php:102 +msgid "Authorize application connection" +msgstr "Autorizza la app" + +#: ../../mod/api.php:77 +msgid "Return to your app and insert this Securty Code:" +msgstr "Torna alla app e inserisci questo codice di sicurezza:" + +#: ../../mod/api.php:89 +msgid "Please login to continue." +msgstr "Accedi al sito per continuare." + +#: ../../mod/api.php:104 +msgid "" +"Do you want to authorize this application to access your posts and contacts," +" and/or create new posts for you?" +msgstr "Vuoi autorizzare questa app ad accedere ai messaggi e ai contatti o creare nuovi messaggi per te?" + +#: ../../mod/follow.php:25 +msgid "Channel added." +msgstr "Canale aggiunto." + +#: ../../mod/tagrm.php:44 ../../mod/tagrm.php:94 +msgid "Tag removed" +msgstr "Tag rimosso" + +#: ../../mod/tagrm.php:119 +msgid "Remove Item Tag" +msgstr "Rimuovi il tag" + +#: ../../mod/tagrm.php:121 +msgid "Select a tag to remove: " +msgstr "Seleziona un tag da rimuovere: " + +#: ../../mod/tagrm.php:133 ../../mod/photos.php:875 +msgid "Remove" +msgstr "Rimuovi" + +#: ../../mod/connect.php:56 ../../mod/connect.php:104 +msgid "Continue" +msgstr "Continua" + +#: ../../mod/connect.php:85 +msgid "Premium Channel Setup" +msgstr "Canale premium - installazione" + +#: ../../mod/connect.php:87 +msgid "Enable premium channel connection restrictions" +msgstr "Abilita le restrizioni del canale premium" + +#: ../../mod/connect.php:88 +msgid "" +"Please enter your restrictions or conditions, such as paypal receipt, usage " +"guidelines, etc." +msgstr "Scrivi le condizioni d'uso e le restrizioni di questo canale, come per esempio le linee guida, il sistema di pagamento, ecc." + +#: ../../mod/connect.php:90 ../../mod/connect.php:110 +msgid "" +"This channel may require additional steps or acknowledgement of the " +"following conditions prior to connecting:" +msgstr "Prima di connetterti a questo canale è necessario che tu accetti le seguenti condizioni:" + +#: ../../mod/connect.php:91 +msgid "" +"Potential connections will then see the following text before proceeding:" +msgstr "Il testo seguente comparirà a chi vorrà seguire il canale:" + +#: ../../mod/connect.php:92 ../../mod/connect.php:113 +msgid "" +"By continuing, I certify that I have complied with any instructions provided" +" on this page." +msgstr "Continuando dichiaro di aver seguito tutte le indicazioni e le istruzioni fornite in questa pagina." + +#: ../../mod/connect.php:101 +msgid "(No specific instructions have been provided by the channel owner.)" +msgstr "(Il gestore del canale non ha fornito istruzioni specifiche)" + +#: ../../mod/connect.php:109 +msgid "Restricted or Premium Channel" +msgstr "Canale premium - con restrizioni" + +#: ../../mod/thing.php:94 +msgid "Thing updated" +msgstr "L'Oggetto è stato aggiornato" + +#: ../../mod/thing.php:153 +msgid "Object store: failed" +msgstr "Impossibile memorizzare l'oggetto." + +#: ../../mod/thing.php:157 +msgid "Thing added" +msgstr "L'Oggetto è stato aggiunto" + +#: ../../mod/thing.php:175 +#, php-format +msgid "OBJ: %1$s %2$s %3$s" +msgstr "OBJ: %1$s %2$s %3$s" + +#: ../../mod/thing.php:226 +msgid "Show Thing" +msgstr "Mostra l'Oggetto" + +#: ../../mod/thing.php:233 +msgid "item not found." +msgstr "non trovato." + +#: ../../mod/thing.php:261 +msgid "Edit Thing" +msgstr "Modifica l'Oggetto" + +#: ../../mod/thing.php:263 ../../mod/thing.php:310 +msgid "Select a profile" +msgstr "Scegli un profilo" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Post an activity" +msgstr "Pubblica un'attività" + +#: ../../mod/thing.php:267 ../../mod/thing.php:313 +msgid "Only sends to viewers of the applicable profile" +msgstr "Invia solo a chi segue il relativo canale" + +#: ../../mod/thing.php:269 ../../mod/thing.php:315 +msgid "Name of thing e.g. something" +msgstr "Nome dell'Oggetto" + +#: ../../mod/thing.php:271 ../../mod/thing.php:316 +msgid "URL of thing (optional)" +msgstr "Indirizzo web dell'Oggetto (opzionale)" + +#: ../../mod/thing.php:273 ../../mod/thing.php:317 +msgid "URL for photo of thing (optional)" +msgstr "Indirizzo di un'immagine dell'Oggetto (facoltativo)" + +#: ../../mod/thing.php:308 +msgid "Add Thing to your Profile" +msgstr "Aggiungi l'Oggetto al tuo profilo" + +#: ../../mod/attach.php:9 +msgid "Item not available." +msgstr "Elemento non disponibile." + +#: ../../mod/probe.php:23 ../../mod/probe.php:29 +#, php-format +msgid "Fetching URL returns error: %1$s" +msgstr "La chiamata all'URL restituisce questo errore: %1$s" + +#: ../../mod/home.php:53 +msgid "Hubzilla - "The Network"" +msgstr "Hubzilla - "La tua rete"" + +#: ../../mod/home.php:124 +#, php-format +msgid "Welcome to %s" +msgstr "%s ti dà il benvenuto" + +#: ../../mod/profile_photo.php:108 +msgid "Image uploaded but image cropping failed." +msgstr "L'immagine è stata caricata, ma il non è stato possibile ritagliarla." + +#: ../../mod/profile_photo.php:162 +msgid "Image resize failed." +msgstr "Il ridimensionamento dell'immagine è fallito." + +#: ../../mod/profile_photo.php:206 +msgid "" +"Shift-reload the page or clear browser cache if the new photo does not " +"display immediately." +msgstr "Ricarica la pagina con shift+F5 o cancella la cache del browser se la nuova foto non viene mostrata immediatamente." + +#: ../../mod/profile_photo.php:233 +#, php-format +msgid "Image exceeds size limit of %d" +msgstr "La dimensione dell'immagine supera il limite di %d" + +#: ../../mod/profile_photo.php:242 +msgid "Unable to process image." +msgstr "Impossibile elaborare l'immagine." + +#: ../../mod/profile_photo.php:291 ../../mod/profile_photo.php:340 +msgid "Photo not available." +msgstr "Foto non disponibile." + +#: ../../mod/profile_photo.php:359 +msgid "Upload File:" +msgstr "Carica un file:" + +#: ../../mod/profile_photo.php:360 +msgid "Select a profile:" +msgstr "Seleziona un profilo:" + +#: ../../mod/profile_photo.php:361 +msgid "Upload Profile Photo" +msgstr "Carica la foto del profilo" + +#: ../../mod/profile_photo.php:366 +msgid "skip this step" +msgstr "salta questo passaggio" + +#: ../../mod/profile_photo.php:366 +msgid "select a photo from your photo albums" +msgstr "seleziona una foto dai tuoi album" + +#: ../../mod/profile_photo.php:382 +msgid "Crop Image" +msgstr "Ritaglia immagine" + +#: ../../mod/profile_photo.php:383 +msgid "Please adjust the image cropping for optimum viewing." +msgstr "Ritaglia l'immagine per migliorarne la visualizzazione." + +#: ../../mod/profile_photo.php:385 +msgid "Done Editing" +msgstr "Modifica terminata" + +#: ../../mod/profile_photo.php:428 +msgid "Image uploaded successfully." +msgstr "Immagine caricata con successo." + +#: ../../mod/profile_photo.php:430 +msgid "Image upload failed." +msgstr "Il caricamento dell'immagine è fallito." + +#: ../../mod/profile_photo.php:439 +#, php-format +msgid "Image size reduction [%s] failed." +msgstr "Il ridimensionamento del'immagine [%s] è fallito." + +#: ../../mod/block.php:27 ../../mod/page.php:33 +msgid "Invalid item." +msgstr "Elemento non valido." + +#: ../../mod/block.php:39 ../../mod/wall_upload.php:29 ../../mod/page.php:45 +msgid "Channel not found." +msgstr "Canale non trovato." + +#: ../../mod/block.php:75 ../../mod/help.php:79 ../../mod/display.php:106 +#: ../../mod/page.php:82 ../../index.php:241 +msgid "Page not found." +msgstr "Pagina non trovata." + +#: ../../mod/like.php:15 +msgid "Like/Dislike" +msgstr "Mi piace/Non mi piace" + +#: ../../mod/like.php:20 +msgid "This action is restricted to members." +msgstr "Questa funzionalità è riservata agli iscritti." + +#: ../../mod/like.php:21 +msgid "" +"Please login with your Hubzilla ID or register as a new Redmatrix.member to continue." +msgstr "Per favore accedi con il tuo identificativo Hubzilla o registrati su Hubzilla per continuare." + +#: ../../mod/like.php:101 ../../mod/like.php:128 ../../mod/like.php:166 +msgid "Invalid request." +msgstr "Richiesta non valida." + +#: ../../mod/like.php:143 +msgid "thing" +msgstr "Oggetto" + +#: ../../mod/like.php:189 +msgid "Channel unavailable." +msgstr "Canale non trovato." + +#: ../../mod/like.php:228 +msgid "Previous action reversed." +msgstr "Il comando precedente è stato annullato." + +#: ../../mod/like.php:398 +#, php-format +msgid "%1$s agrees with %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s è d'accordo" + +#: ../../mod/like.php:400 +#, php-format +msgid "%1$s doesn't agree with %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s non è d'accordo" + +#: ../../mod/like.php:402 +#, php-format +msgid "%1$s abstains from a decision on %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s non ha preso una decisione" + +#: ../../mod/like.php:404 +#, php-format +msgid "%1$s is attending %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s partecipa" + +#: ../../mod/like.php:406 +#, php-format +msgid "%1$s is not attending %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s non partecipa" + +#: ../../mod/like.php:408 +#, php-format +msgid "%1$s may attend %2$s's %3$s" +msgstr "%3$s di %2$s: %1$s forse partecipa" + +#: ../../mod/like.php:492 +msgid "Action completed." +msgstr "Comando completato." + +#: ../../mod/like.php:493 +msgid "Thank you." +msgstr "Grazie." + +#: ../../mod/events.php:87 +msgid "Event can not end before it has started." +msgstr "Un evento non può terminare prima del suo inizio." + +#: ../../mod/events.php:89 ../../mod/events.php:98 ../../mod/events.php:116 +msgid "Unable to generate preview." +msgstr "Impossibile creare un'anteprima." + +#: ../../mod/events.php:96 +msgid "Event title and start time are required." +msgstr "Sono necessari il titolo e l'ora d'inizio dell'evento." + +#: ../../mod/events.php:114 +msgid "Event not found." +msgstr "Evento non trovato." + +#: ../../mod/events.php:396 +msgid "l, F j" +msgstr "l j F" + +#: ../../mod/events.php:418 +msgid "Edit event" +msgstr "Modifica l'evento" + +#: ../../mod/events.php:419 +msgid "Delete event" +msgstr "Elimina l'evento" + +#: ../../mod/events.php:473 +msgid "Create New Event" +msgstr "Crea un nuovo evento" + +#: ../../mod/events.php:474 ../../mod/photos.php:827 +msgid "Previous" +msgstr "Precendente" + +#: ../../mod/events.php:475 ../../mod/setup.php:265 ../../mod/photos.php:836 +msgid "Next" +msgstr "Successivo" + +#: ../../mod/events.php:476 +msgid "Export" +msgstr "Esporta" + +#: ../../mod/events.php:504 +msgid "Event removed" +msgstr "Evento eliminato" + +#: ../../mod/events.php:507 +msgid "Failed to remove event" +msgstr "Impossibile eliminare l'evento" + +#: ../../mod/events.php:627 +msgid "Event details" +msgstr "Dettagli evento" + +#: ../../mod/events.php:628 +msgid "Starting date and Title are required." +msgstr "Titolo e data d'inizio sono obbligatori." + +#: ../../mod/events.php:630 +msgid "Categories (comma-separated list)" +msgstr "Categorie (separate da virgola)" + +#: ../../mod/events.php:632 +msgid "Event Starts:" +msgstr "Inizio:" + +#: ../../mod/events.php:639 +msgid "Finish date/time is not known or not relevant" +msgstr "La data/ora di fine non è rilevante" + +#: ../../mod/events.php:641 +msgid "Event Finishes:" +msgstr "Fine:" + +#: ../../mod/events.php:643 ../../mod/events.php:644 +msgid "Adjust for viewer timezone" +msgstr "Adatta al fuso orario di chi legge" + +#: ../../mod/events.php:643 +msgid "" +"Important for events that happen in a particular place. Not practical for " +"global holidays." +msgstr "Importante per eventi che avvengono in base all'orario di un luogo particolare." + +#: ../../mod/events.php:645 +msgid "Description:" +msgstr "Descrizione:" + +#: ../../mod/events.php:649 +msgid "Title:" +msgstr "Titolo:" + +#: ../../mod/events.php:651 +msgid "Share this event" +msgstr "Condividi questo evento" + +#: ../../mod/subthread.php:103 +#, php-format +msgid "%1$s is following %2$s's %3$s" +msgstr "%1$s sta seguendo %3$s di %2$s" + +#: ../../mod/pubsites.php:16 +msgid "Public Sites" +msgstr "Siti pubblici" + +#: ../../mod/pubsites.php:19 +msgid "" +"The listed sites allow public registration into the Hubzilla. All sites in" +" the matrix are interlinked so membership on any of them conveys membership " +"in the matrix as a whole. Some sites may require subscription or provide " +"tiered service plans. The provider links may provide " +"additional details." +msgstr "Gli indirizzi elencati permettono la registrazione su Hubzilla. Tutti i siti di questa rete sono interconnessi, quindi essere registrati su uno è come essere registrati ovunque. Alcuni potrebbero richiedere un'iscrizione a pagamento o prevedere diverse tipologie di abbonamento. Eventualmente potrai trovare maggiori informazioni visitando ciascun sito." + +#: ../../mod/pubsites.php:25 +msgid "Rate this hub" +msgstr "Valuta questo hub" + +#: ../../mod/pubsites.php:26 +msgid "Site URL" +msgstr "URL del sito" + +#: ../../mod/pubsites.php:26 +msgid "Access Type" +msgstr "Tipo di accesso" + +#: ../../mod/pubsites.php:26 +msgid "Registration Policy" +msgstr "Politica di registrazione" + +#: ../../mod/pubsites.php:26 ../../mod/profiles.php:454 +msgid "Location" +msgstr "Posizione geografica" + +#: ../../mod/pubsites.php:26 +msgid "View hub ratings" +msgstr "Vedi le valutazioni del hub" + +#: ../../mod/pubsites.php:30 +msgid "Rate" +msgstr "Valuta" + +#: ../../mod/pubsites.php:31 +msgid "View ratings" +msgstr "Vedi le valutazioni" + +#: ../../mod/rpost.php:131 ../../mod/editpost.php:42 +msgid "Edit post" +msgstr "Modifica articolo" + +#: ../../mod/dav.php:121 +msgid "Hubzilla channel" +msgstr "Canale Hubzilla" + +#: ../../mod/group.php:20 +msgid "Collection created." +msgstr "L'insieme di canali è stato creato." + +#: ../../mod/group.php:26 +msgid "Could not create collection." +msgstr "Impossibile creare l'insieme." + +#: ../../mod/group.php:54 +msgid "Collection updated." +msgstr "Insieme aggiornato." + +#: ../../mod/group.php:86 +msgid "Create a collection of channels." +msgstr "Crea un insieme di canali." + +#: ../../mod/group.php:87 ../../mod/group.php:183 +msgid "Collection Name: " +msgstr "Nome dell'insieme:" + +#: ../../mod/group.php:89 ../../mod/group.php:186 +msgid "Members are visible to other channels" +msgstr "I membri potranno vedere gli altri canali dell'insieme" + +#: ../../mod/group.php:107 +msgid "Collection removed." +msgstr "Insieme rimosso." + +#: ../../mod/group.php:109 +msgid "Unable to remove collection." +msgstr "Impossibile rimuovere l'insieme." + +#: ../../mod/group.php:182 +msgid "Collection Editor" +msgstr "Modifica l'insieme" + +#: ../../mod/group.php:196 ../../mod/bulksetclose.php:89 +msgid "Members" +msgstr "Membri" + +#: ../../mod/group.php:198 ../../mod/bulksetclose.php:91 +msgid "All Connected Channels" +msgstr "Tutti i canali connessi" + +#: ../../mod/group.php:233 ../../mod/bulksetclose.php:126 +msgid "Click on a channel to add or remove." +msgstr "Clicca su un canale per aggiungerlo o rimuoverlo." + +#: ../../mod/siteinfo.php:112 +#, php-format +msgid "Version %s" +msgstr "Versione %s" + +#: ../../mod/siteinfo.php:133 +msgid "Installed plugins/addons/apps:" +msgstr "App e componenti installati:" + +#: ../../mod/siteinfo.php:146 +msgid "No installed plugins/addons/apps" +msgstr "Nessuna app o componente installato" + +#: ../../mod/siteinfo.php:155 +msgid "Red" +msgstr "Hubzilla" + +#: ../../mod/siteinfo.php:156 +msgid "" +"This is a hub of hubzilla - a global cooperative network of decentralized " +"privacy enhanced websites." +msgstr "Questo è un hub di Hubzilla - una rete cooperativa e decentralizzata di siti ad elevata privacy. " + +#: ../../mod/siteinfo.php:158 +msgid "Tag: " +msgstr "Tag: " + +#: ../../mod/siteinfo.php:160 +msgid "Last background fetch: " +msgstr "Ultima acquisizione:" + +#: ../../mod/siteinfo.php:163 +msgid "Running at web location" +msgstr "In esecuzione sull'indirizzo web" + +#: ../../mod/siteinfo.php:164 +msgid "" +"Please visit redmatrix.me to learn more" +" about the Hubzilla." +msgstr "Visita Redmatrix.me per scoprire cosa è Hubzilla." + +#: ../../mod/siteinfo.php:165 +msgid "Bug reports and issues: please visit" +msgstr "Per segnalare bug e problemi: visita" + +#: ../../mod/siteinfo.php:168 +msgid "" +"Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot " +"com" +msgstr "Per consigli, ringraziamenti, ecc. - scrivi a \"hubzilla\" at librelist - dot com" + +#: ../../mod/siteinfo.php:170 +msgid "Site Administrators" +msgstr "Amministratori del sito" + +#: ../../mod/help.php:49 ../../mod/help.php:55 ../../mod/help.php:61 +msgid "Help:" +msgstr "Guida:" + +#: ../../mod/help.php:76 ../../index.php:238 +msgid "Not Found" +msgstr "Non disponibile" + +#: ../../mod/setup.php:166 +msgid "Hubzilla Server - Setup" +msgstr "Hubzilla Server - Installazione" + +#: ../../mod/setup.php:172 +msgid "Could not connect to database." +msgstr " Impossibile connettersi al database." + +#: ../../mod/setup.php:176 +msgid "" +"Could not connect to specified site URL. Possible SSL certificate or DNS " +"issue." +msgstr "Non è possibile raggiungere l'indirizzo del sito specificato. Potrebbe essere un problema di SSL o DNS." + +#: ../../mod/setup.php:183 +msgid "Could not create table." +msgstr "Impossibile creare le tabelle." + +#: ../../mod/setup.php:189 +msgid "Your site database has been installed." +msgstr "Il database del sito è stato installato." + +#: ../../mod/setup.php:194 +msgid "" +"You may need to import the file \"install/schema_xxx.sql\" manually using a " +"database client." +msgstr "Potresti dover importare il file 'install/schema_xxx.sql' manualmente usando un client per collegarti al db." + +#: ../../mod/setup.php:195 ../../mod/setup.php:264 ../../mod/setup.php:662 +msgid "Please see the file \"install/INSTALL.txt\"." +msgstr "Leggi il file 'install/INSTALL.txt'." + +#: ../../mod/setup.php:261 +msgid "System check" +msgstr "Verifica del sistema" + +#: ../../mod/setup.php:266 +msgid "Check again" +msgstr "Verifica di nuovo" + +#: ../../mod/setup.php:289 +msgid "Database connection" +msgstr "Connessione al database" + +#: ../../mod/setup.php:290 +msgid "" +"In order to install Hubzilla we need to know how to connect to your " +"database." +msgstr "Per installare Hubzilla è necessario conoscere i parametri di connessione al database." + +#: ../../mod/setup.php:291 +msgid "" +"Please contact your hosting provider or site administrator if you have " +"questions about these settings." +msgstr "Contatta il tuo fornitore di hosting o l'amministratore del sito se hai domande su queste impostazioni." + +#: ../../mod/setup.php:292 +msgid "" +"The database you specify below should already exist. If it does not, please " +"create it before continuing." +msgstr "Il database deve già esistere. Se non esiste, crealo prima di continuare." + +#: ../../mod/setup.php:296 +msgid "Database Server Name" +msgstr "Server del database" + +#: ../../mod/setup.php:296 +msgid "Default is localhost" +msgstr "'localhost' è il predefinito" + +#: ../../mod/setup.php:297 +msgid "Database Port" +msgstr "Port del database" + +#: ../../mod/setup.php:297 +msgid "Communication port number - use 0 for default" +msgstr "Scrivi 0 per usare il valore standard" + +#: ../../mod/setup.php:298 +msgid "Database Login Name" +msgstr "Utente database" + +#: ../../mod/setup.php:299 +msgid "Database Login Password" +msgstr "Password utente database" + +#: ../../mod/setup.php:300 +msgid "Database Name" +msgstr "Nome database" + +#: ../../mod/setup.php:301 +msgid "Database Type" +msgstr "Tipo database" + +#: ../../mod/setup.php:303 ../../mod/setup.php:347 +msgid "Site administrator email address" +msgstr "Indirizzo email dell'amministratore del sito" + +#: ../../mod/setup.php:303 ../../mod/setup.php:347 +msgid "" +"Your account email address must match this in order to use the web admin " +"panel." +msgstr "Il tuo indirizzo email deve corrispondere a questo per poter usare il pannello di amministrazione web." + +#: ../../mod/setup.php:304 ../../mod/setup.php:349 +msgid "Website URL" +msgstr "URL completo del sito" + +#: ../../mod/setup.php:304 ../../mod/setup.php:349 +msgid "Please use SSL (https) URL if available." +msgstr "Se disponibile, usa l'indirizzo SSL (https)." + +#: ../../mod/setup.php:307 ../../mod/setup.php:352 +msgid "Please select a default timezone for your website" +msgstr "Seleziona il fuso orario predefinito per il tuo sito web" + +#: ../../mod/setup.php:335 +msgid "Site settings" +msgstr "Impostazioni del sito" + +#: ../../mod/setup.php:395 +msgid "Could not find a command line version of PHP in the web server PATH." +msgstr "Non è possibile trovare la versione di PHP da riga di comando nel PATH del server web" + +#: ../../mod/setup.php:396 +msgid "" +"If you don't have a command line version of PHP installed on server, you " +"will not be able to run background polling via cron." +msgstr "Se non hai installata la versione di PHP da riga di comando non potrai attivare il polling in background tramite cron." + +#: ../../mod/setup.php:400 +msgid "PHP executable path" +msgstr "Path del comando PHP" + +#: ../../mod/setup.php:400 +msgid "" +"Enter full path to php executable. You can leave this blank to continue the " +"installation." +msgstr "Inserisci il percorso dell'eseguibile PHP. Puoi lasciarlo vuoto per continuare l'installazione." + +#: ../../mod/setup.php:405 +msgid "Command line PHP" +msgstr "PHP da riga di comando" + +#: ../../mod/setup.php:414 +msgid "" +"The command line version of PHP on your system does not have " +"\"register_argc_argv\" enabled." +msgstr "La versione da riga di comando di PHP nel sistema non ha abilitato \"register_argc_argv\"." + +#: ../../mod/setup.php:415 +msgid "This is required for message delivery to work." +msgstr "E' necessario perché funzioni la consegna dei messaggi." + +#: ../../mod/setup.php:417 +msgid "PHP register_argc_argv" +msgstr "PHP register_argc_argv" + +#: ../../mod/setup.php:438 +msgid "" +"Error: the \"openssl_pkey_new\" function on this system is not able to " +"generate encryption keys" +msgstr "Errore: la funzione \"openssl_pkey_new\" su questo sistema non è in grado di generare le chiavi di criptazione" + +#: ../../mod/setup.php:439 +msgid "" +"If running under Windows, please see " +"\"http://www.php.net/manual/en/openssl.installation.php\"." +msgstr "Se stai usando un server windows, guarda \"http://www.php.net/manual/en/openssl.installation.php\"." + +#: ../../mod/setup.php:441 +msgid "Generate encryption keys" +msgstr "Genera chiavi di criptazione" + +#: ../../mod/setup.php:448 +msgid "libCurl PHP module" +msgstr "modulo PHP libCurl" + +#: ../../mod/setup.php:449 +msgid "GD graphics PHP module" +msgstr "modulo PHP GD graphics" + +#: ../../mod/setup.php:450 +msgid "OpenSSL PHP module" +msgstr "modulo PHP OpenSSL" + +#: ../../mod/setup.php:451 +msgid "mysqli or postgres PHP module" +msgstr "modulo PHP per mysqli oppure prostgres" + +#: ../../mod/setup.php:452 +msgid "mb_string PHP module" +msgstr "modulo PHP mb_string" + +#: ../../mod/setup.php:453 +msgid "mcrypt PHP module" +msgstr "modulo PHP mcrypt" + +#: ../../mod/setup.php:458 ../../mod/setup.php:460 +msgid "Apache mod_rewrite module" +msgstr "modulo Apache mod_rewrite" + +#: ../../mod/setup.php:458 +msgid "" +"Error: Apache webserver mod-rewrite module is required but not installed." +msgstr "Errore: il modulo mod-rewrite di Apache è richiesto ma non installato" + +#: ../../mod/setup.php:464 ../../mod/setup.php:467 +msgid "proc_open" +msgstr "proc_open" + +#: ../../mod/setup.php:464 +msgid "" +"Error: proc_open is required but is either not installed or has been " +"disabled in php.ini" +msgstr "Errore: proc_open è richiesto ma non è installato o è disabilitato in php.ini" + +#: ../../mod/setup.php:472 +msgid "Error: libCURL PHP module required but not installed." +msgstr "Errore: il modulo libCURL di PHP è richiesto ma non installato." + +#: ../../mod/setup.php:476 +msgid "" +"Error: GD graphics PHP module with JPEG support required but not installed." +msgstr "Errore: Il modulo GD graphics di PHP con supporto a JPEG è richiesto ma non installato." + +#: ../../mod/setup.php:480 +msgid "Error: openssl PHP module required but not installed." +msgstr "Errore: il modulo openssl di PHP è richiesto ma non installato." + +#: ../../mod/setup.php:484 +msgid "" +"Error: mysqli or postgres PHP module required but neither are installed." +msgstr "Errore: il modulo PHP per mysqli o postgres è richiesto ma non installato" + +#: ../../mod/setup.php:488 +msgid "Error: mb_string PHP module required but not installed." +msgstr "Errore: il modulo PHP mb_string è richiesto ma non installato." + +#: ../../mod/setup.php:492 +msgid "Error: mcrypt PHP module required but not installed." +msgstr "Errore: il modulo PHP mcrypt è richiesto ma non installato." + +#: ../../mod/setup.php:508 +msgid "" +"The web installer needs to be able to create a file called \".htconfig.php\"" +" in the top folder of your web server and it is unable to do so." +msgstr "L'installazione web deve poter creare un file chiamato \".htconfig.php\" nella cartella di Hubzilla ma non è in grado di farlo." + +#: ../../mod/setup.php:509 +msgid "" +"This is most often a permission setting, as the web server may not be able " +"to write files in your folder - even if you can." +msgstr "Spesso ciò è dovuto ai permessi di accesso al disco: il web server potrebbe non aver diritto di scrivere il file nella cartella, anche se tu puoi." + +#: ../../mod/setup.php:510 +msgid "" +"At the end of this procedure, we will give you a text to save in a file " +"named .htconfig.php in your Red top folder." +msgstr "Alla fine di questa procedura ti sarà dato il testo da salvare in un file di nome .htconfig.php dentro la cartella principale di Hubzilla." + +#: ../../mod/setup.php:511 +msgid "" +"You can alternatively skip this procedure and perform a manual installation." +" Please see the file \"install/INSTALL.txt\" for instructions." +msgstr "Puoi anche saltare questa procedura ed effettuare un'installazione manuale. Guarda il file 'install/INSTALL.txt' per le istruzioni." + +#: ../../mod/setup.php:514 +msgid ".htconfig.php is writable" +msgstr ".htconfig.php è scrivibile" + +#: ../../mod/setup.php:524 +msgid "" +"Red uses the Smarty3 template engine to render its web views. Smarty3 " +"compiles templates to PHP to speed up rendering." +msgstr "Red usa il sistema Smarty3 per costruire i suoi template grafici. Smarty3 è molto veloce perché compila i template delle pagine direttamente in PHP." + +#: ../../mod/setup.php:525 +#, php-format +msgid "" +"In order to store these compiled templates, the web server needs to have " +"write access to the directory %s under the Red top level folder." +msgstr "Per poter memorizzare i template compilati, il web server deve avere accesso in scrittura a %s sotto la cartella di installazione di Hubzilla." + +#: ../../mod/setup.php:526 ../../mod/setup.php:544 +msgid "" +"Please ensure that the user that your web server runs as (e.g. www-data) has" +" write access to this folder." +msgstr "Assicurati che il tuo web server sia in esecuzione da parte di un utente che ha diritto di scrittura su quella cartella (ad esempio www-data)." + +#: ../../mod/setup.php:527 +#, php-format +msgid "" +"Note: as a security measure, you should give the web server write access to " +"%s only--not the template files (.tpl) that it contains." +msgstr "Nota bene: come precauzione, dovresti dare i diritti di scrittura solamente su %s e non sui file template (.tpl) che contiene." + +#: ../../mod/setup.php:530 +#, php-format +msgid "%s is writable" +msgstr "%s è scrivibile" + +#: ../../mod/setup.php:543 +msgid "" +"Red uses the store directory to save uploaded files. The web server needs to" +" have write access to the store directory under the Red top level folder" +msgstr "Hubzilla salva i file caricati nella cartella \"store\" sul server. Il server deve avere i diritti di scrittura su quella cartella che si trova dentro l'installazione di Hubzilla" + +#: ../../mod/setup.php:547 +msgid "store is writable" +msgstr "l'archivio è scrivibile" + +#: ../../mod/setup.php:577 +msgid "" +"SSL certificate cannot be validated. Fix certificate or disable https access" +" to this site." +msgstr "Il certificato SSL non può essere validato. Correggi l'errore o disabilita l'accesso https al sito." + +#: ../../mod/setup.php:578 +msgid "" +"If you have https access to your website or allow connections to TCP port " +"443 (the https: port), you MUST use a browser-valid certificate. You MUST " +"NOT use self-signed certificates!" +msgstr "Se abiliti https per il tuo sito o permetti connessioni TCP su port 443 (quella di https), DEVI usare un certificato riconosciuto dai browser internet. NON DEVI usare certificati generati da te!" + +#: ../../mod/setup.php:579 +msgid "" +"This restriction is incorporated because public posts from you may for " +"example contain references to images on your own hub." +msgstr "Questa restrizione è necessaria perché i tuoi post pubblici potrebbero contenere riferimenti a immagini sul tuo server." + +#: ../../mod/setup.php:580 +msgid "" +"If your certificate is not recognized, members of other sites (who may " +"themselves have valid certificates) will get a warning message on their own " +"site complaining about security issues." +msgstr "Se il tuo certificato non è riconosciuto, gli utenti che ti seguono da altri siti (che avranno certificati validi) riceveranno gravi avvisi di sicurezza dal browser." + +#: ../../mod/setup.php:581 +msgid "" +"This can cause usability issues elsewhere (not just on your own site) so we " +"must insist on this requirement." +msgstr "Ciò può creare seri problemi di usabilità (non solo sul tuo sito), quindi dobbiamo insistere su questo punto." + +#: ../../mod/setup.php:582 +msgid "" +"Providers are available that issue free certificates which are browser-" +"valid." +msgstr "Eventualmente, considera che esistono provider che rilasciano certificati gratuiti riconosciuti dai browser." + +#: ../../mod/setup.php:584 +msgid "SSL certificate validation" +msgstr "Validazione del certificato SSL" + +#: ../../mod/setup.php:590 +msgid "" +"Url rewrite in .htaccess is not working. Check your server " +"configuration.Test: " +msgstr "In .htaccess la funzionalità url rewrite non funziona. Controlla la configurazione del server. Test:" + +#: ../../mod/setup.php:592 +msgid "Url rewrite is working" +msgstr "Url rewrite funziona correttamente" + +#: ../../mod/setup.php:602 +msgid "" +"The database configuration file \".htconfig.php\" could not be written. " +"Please use the enclosed text to create a configuration file in your web " +"server root." +msgstr "Il file di configurazione del database \".htconfig.php\" non puo' essere scritto. Usa il testo qui di seguito per creare questo file di configurazione nella cartella principale del tuo sito." + +#: ../../mod/setup.php:625 +msgid "Errors encountered creating database tables." +msgstr "La creazione delle tabelle del database ha generato errori." + +#: ../../mod/setup.php:660 +msgid "

    What next

    " +msgstr "

    I prossimi passi

    " + +#: ../../mod/setup.php:661 +msgid "" +"IMPORTANT: You will need to [manually] setup a scheduled task for the " +"poller." +msgstr "IMPORTANTE: Devi creare [manualmente] la pianificazione del polling." + +#: ../../mod/common.php:10 +msgid "No channel." +msgstr "Nessun canale." + +#: ../../mod/common.php:39 +msgid "Common connections" +msgstr "Contatti in comune" + +#: ../../mod/common.php:44 +msgid "No connections in common." +msgstr "Nessun contatto in comune." + +#: ../../mod/regdir.php:45 ../../mod/dirsearch.php:21 +msgid "This site is not a directory server" +msgstr "Questo sito non è un server di elenchi pubblici" + +#: ../../mod/connections.php:37 ../../mod/connedit.php:75 +msgid "Could not access contact record." +msgstr "Non è possibile accedere alle informazioni sul contatto." + +#: ../../mod/connections.php:51 ../../mod/connedit.php:99 +msgid "Could not locate selected profile." +msgstr "Non riesco a trovare il profilo selezionato." + +#: ../../mod/connections.php:94 ../../mod/connedit.php:214 +msgid "Connection updated." +msgstr "Contatto aggiornato." + +#: ../../mod/connections.php:96 ../../mod/connedit.php:216 +msgid "Failed to update connection record." +msgstr "Impossibile aggiornare le informazioni del contatto." + +#: ../../mod/connections.php:192 ../../mod/connections.php:293 +msgid "Blocked" +msgstr "Bloccati" + +#: ../../mod/connections.php:197 ../../mod/connections.php:300 +msgid "Ignored" +msgstr "Ignorati" + +#: ../../mod/connections.php:202 ../../mod/connections.php:314 +msgid "Hidden" +msgstr "Nascosti" + +#: ../../mod/connections.php:207 ../../mod/connections.php:307 +msgid "Archived" +msgstr "Archiviati" + +#: ../../mod/connections.php:271 +msgid "Suggest new connections" +msgstr "Suggerisci nuovi contatti" + +#: ../../mod/connections.php:274 +msgid "New Connections" +msgstr "Nuovi contatti" + +#: ../../mod/connections.php:277 +msgid "Show pending (new) connections" +msgstr "Richieste di contatto in attesa" + +#: ../../mod/connections.php:280 ../../mod/profperm.php:139 +msgid "All Connections" +msgstr "Tutti i contatti" + +#: ../../mod/connections.php:283 +msgid "Show all connections" +msgstr "Mostra tutti i contatti" + +#: ../../mod/connections.php:286 +msgid "Unblocked" +msgstr "Non bloccati" + +#: ../../mod/connections.php:289 +msgid "Only show unblocked connections" +msgstr "Mostra solo i contatti non bloccati" + +#: ../../mod/connections.php:296 +msgid "Only show blocked connections" +msgstr "Mostra solo i contatti bloccati" + +#: ../../mod/connections.php:303 +msgid "Only show ignored connections" +msgstr "Mostra solo i contatti ignorati" + +#: ../../mod/connections.php:310 +msgid "Only show archived connections" +msgstr "Mostra solo i contatti archiviati" + +#: ../../mod/connections.php:317 +msgid "Only show hidden connections" +msgstr "Mostra solo i contatti nascosti" + +#: ../../mod/connections.php:372 +#, php-format +msgid "%1$s [%2$s]" +msgstr "%1$s [%2$s]" + +#: ../../mod/connections.php:373 +msgid "Edit connection" +msgstr "Modifica il contatto" + +#: ../../mod/connections.php:411 +msgid "Search your connections" +msgstr "Cerca tra i contatti" + +#: ../../mod/connections.php:412 +msgid "Finding: " +msgstr "Ricerca: " + +#: ../../mod/impel.php:33 +msgid "webpage" +msgstr "pagina web" + +#: ../../mod/impel.php:38 +msgid "block" +msgstr "riquadro" + +#: ../../mod/impel.php:43 +msgid "layout" +msgstr "layout" + +#: ../../mod/impel.php:117 +#, php-format +msgid "%s element installed" +msgstr "%s elemento installato" + +#: ../../mod/tagger.php:96 +#, php-format +msgid "%1$s tagged %2$s's %3$s with %4$s" +msgstr "%1$s ha taggato %3$s di %2$s con %4$s" + +#: ../../mod/cloud.php:120 +msgid "Hubzilla - Guests: Username: {your email address}, Password: +++" +msgstr "Accesso a Hubzilla. {Inserisci l'email con cui sei registrato e la password.}" + +#: ../../mod/photos.php:77 +msgid "Page owner information could not be retrieved." +msgstr "Impossibile ottenere informazioni sul proprietario della pagina." + +#: ../../mod/photos.php:97 +msgid "Album not found." +msgstr "Album non trovato." + +#: ../../mod/photos.php:119 ../../mod/photos.php:643 +msgid "Delete Album" +msgstr "Elimina album" + +#: ../../mod/photos.php:159 ../../mod/photos.php:930 +msgid "Delete Photo" +msgstr "Elimina foto" + +#: ../../mod/photos.php:429 ../../mod/search.php:13 ../../mod/display.php:13 +#: ../../mod/ratings.php:82 ../../mod/directory.php:47 +#: ../../mod/viewconnections.php:17 +msgid "Public access denied." +msgstr "Accesso pubblico negato." + +#: ../../mod/photos.php:440 +msgid "No photos selected" +msgstr "Nessuna foto selezionata" + +#: ../../mod/photos.php:484 +msgid "Access to this item is restricted." +msgstr "Questo elemento non è visibile a tutti." + +#: ../../mod/photos.php:523 +#, php-format +msgid "%1$.2f MB of %2$.2f MB photo storage used." +msgstr "Hai usato %1$.2f Mb dei %2$.2f Mb di spazio disponibile." + +#: ../../mod/photos.php:526 +#, php-format +msgid "%1$.2f MB photo storage used." +msgstr "Hai usato %1$.2f Mb del tuo spazio disponibile." + +#: ../../mod/photos.php:550 +msgid "Upload Photos" +msgstr "Carica foto" + +#: ../../mod/photos.php:554 ../../mod/photos.php:636 ../../mod/photos.php:915 +msgid "Enter a new album name" +msgstr "Inserisci il nome di un nuovo album" + +#: ../../mod/photos.php:555 ../../mod/photos.php:637 ../../mod/photos.php:916 +msgid "or select an existing one (doubleclick)" +msgstr "o seleziona uno esistente (doppio click)" + +#: ../../mod/photos.php:556 +msgid "Create a status post for this upload" +msgstr "Pubblica l'oggetto caricato sulla bacheca" + +#: ../../mod/photos.php:584 +msgid "Album name could not be decoded" +msgstr "Non è stato possibile leggere il nome dell'album" + +#: ../../mod/photos.php:625 ../../mod/photos.php:1157 +#: ../../mod/photos.php:1173 +msgid "Contact Photos" +msgstr "Foto dei contatti" + +#: ../../mod/photos.php:649 +msgid "Show Newest First" +msgstr "Prima i più recenti" + +#: ../../mod/photos.php:651 +msgid "Show Oldest First" +msgstr "Prima i più vecchi" + +#: ../../mod/photos.php:675 ../../mod/photos.php:1205 +msgid "View Photo" +msgstr "Guarda la foto" + +#: ../../mod/photos.php:704 +msgid "Edit Album" +msgstr "Modifica album" + +#: ../../mod/photos.php:749 +msgid "Permission denied. Access to this item may be restricted." +msgstr "Permesso negato. L'accesso a questo elemento può essere stato limitato." + +#: ../../mod/photos.php:751 +msgid "Photo not available" +msgstr "Foto non disponibile" + +#: ../../mod/photos.php:809 +msgid "Use as profile photo" +msgstr "Usa come foto del profilo" + +#: ../../mod/photos.php:816 +msgid "Private Photo" +msgstr "Foto privata" + +#: ../../mod/photos.php:831 +msgid "View Full Size" +msgstr "Vedi nelle dimensioni originali" + +#: ../../mod/photos.php:909 +msgid "Edit photo" +msgstr "Modifica la foto" + +#: ../../mod/photos.php:911 +msgid "Rotate CW (right)" +msgstr "Ruota (senso orario)" + +#: ../../mod/photos.php:912 +msgid "Rotate CCW (left)" +msgstr "Ruota (senso antiorario)" + +#: ../../mod/photos.php:919 +msgid "Caption" +msgstr "Titolo" + +#: ../../mod/photos.php:921 +msgid "Add a Tag" +msgstr "Aggiungi tag" + +#: ../../mod/photos.php:925 +msgid "Example: @bob, @Barbara_Jensen, @jim@example.com" +msgstr "Esempio: @bob, @Barbara_Jensen, @jim@example.com" + +#: ../../mod/photos.php:928 +msgid "Flag as adult in album view" +msgstr "Marca come 'per adulti'" + +#: ../../mod/photos.php:1120 +msgid "In This Photo:" +msgstr "In questa foto:" + +#: ../../mod/photos.php:1125 +msgid "Map" +msgstr "Mappa" + +#: ../../mod/photos.php:1211 +msgid "View Album" +msgstr "Guarda l'album" + +#: ../../mod/photos.php:1234 +msgid "Recent Photos" +msgstr "Foto recenti" + +#: ../../mod/match.php:22 +msgid "Profile Match" +msgstr "Profili corrispondenti" + +#: ../../mod/match.php:31 +msgid "No keywords to match. Please add keywords to your default profile." +msgstr "Non hai scritto parole chiave. Aggiungi parole chiave al tuo profilo predefinito per comparire nelle ricerche." + +#: ../../mod/match.php:63 +msgid "is interested in:" +msgstr "interessi personali:" + +#: ../../mod/match.php:70 +msgid "No matches" +msgstr "Nessun risultato" + +#: ../../mod/chatsvc.php:111 +msgid "Away" +msgstr "Assente" + +#: ../../mod/chatsvc.php:115 +msgid "Online" +msgstr "Online" + +#: ../../mod/rbmark.php:88 +msgid "Select a bookmark folder" +msgstr "Scegli una cartella di segnalibri" + +#: ../../mod/rbmark.php:93 +msgid "Save Bookmark" +msgstr "Salva segnalibro" + +#: ../../mod/rbmark.php:94 +msgid "URL of bookmark" +msgstr "URL del segnalibro" + +#: ../../mod/rbmark.php:95 ../../mod/appman.php:93 +msgid "Description" +msgstr "Descrizione" + +#: ../../mod/rbmark.php:99 +msgid "Or enter new bookmark folder name" +msgstr "O inserisci il nome di una nuova cartella di segnalibri" + +#: ../../mod/notify.php:53 ../../mod/notifications.php:94 +msgid "No more system notifications." +msgstr "Non ci sono nuove notifiche di sistema." + +#: ../../mod/notify.php:57 ../../mod/notifications.php:98 +msgid "System Notifications" +msgstr "Notifiche di sistema" + +#: ../../mod/acl.php:231 +msgid "network" +msgstr "rete" + +#: ../../mod/acl.php:241 +msgid "RSS" +msgstr "RSS" + +#: ../../mod/pdledit.php:13 +msgid "Layout updated." +msgstr "Layout aggiornato." + +#: ../../mod/pdledit.php:28 ../../mod/pdledit.php:53 +msgid "Edit System Page Description" +msgstr "Modifica i layout di sistema" + +#: ../../mod/pdledit.php:48 +msgid "Layout not found." +msgstr "Layout non trovato." + +#: ../../mod/pdledit.php:54 +msgid "Module Name:" +msgstr "Nome del modulo:" + +#: ../../mod/pdledit.php:55 ../../mod/layouts.php:108 +msgid "Layout Help" +msgstr "Guida al layout" + +#: ../../mod/filer.php:49 +msgid "- select -" +msgstr "- scegli -" + +#: ../../mod/import.php:25 +#, php-format +msgid "Your service plan only allows %d channels." +msgstr "Il tuo account permette di creare al massimo %d canali." + +#: ../../mod/import.php:51 +msgid "Nothing to import." +msgstr "Non c'è niente da importare." + +#: ../../mod/import.php:75 +msgid "Unable to download data from old server" +msgstr "Impossibile importare i dati dal vecchio server" + +#: ../../mod/import.php:81 +msgid "Imported file is empty." +msgstr "Il file da importare è vuoto." + +#: ../../mod/import.php:106 +msgid "" +"Cannot create a duplicate channel identifier on this system. Import failed." +msgstr "Non posso creare un canale con un identificativo che già esiste su questo sistema. L'importazione è fallita." + +#: ../../mod/import.php:127 +msgid "Unable to create a unique channel address. Import failed." +msgstr "Impossibile creare un indirizzo univoco per il canale. L'import è fallito." + +#: ../../mod/import.php:147 +msgid "Channel clone failed. Import failed." +msgstr "Impossibile clonare il canale. L'importazione è fallita." + +#: ../../mod/import.php:157 +msgid "Cloned channel not found. Import failed." +msgstr "Impossibile trovare il canale clonato. L'importazione è fallita." + +#: ../../mod/import.php:475 +msgid "Import completed." +msgstr "L'importazione è terminata con successo!" + +#: ../../mod/import.php:487 +msgid "You must be logged in to use this feature." +msgstr "Per questa funzionalità devi aver effettuato l'accesso." + +#: ../../mod/import.php:492 +msgid "Import Channel" +msgstr "Importa un canale" + +#: ../../mod/import.php:493 +msgid "" +"Use this form to import an existing channel from a different server/hub. You" +" may retrieve the channel identity from the old server/hub via the network " +"or provide an export file. Only identity and connections/relationships will " +"be imported. Importation of content is not yet available." +msgstr "Usa questo modulo per importare un tuo canale da un altro server/hub. Puoi scaricare i dati identificativi del canale direttamente dall'altro server/hub oppure tramite un file che hai esportato. Saranno importati solamente l'identità e i contatti. L'importazione dei contenuti non è ancora disponibile." + +#: ../../mod/import.php:494 +msgid "File to Upload" +msgstr "File da caricare" + +#: ../../mod/import.php:495 +msgid "Or provide the old server/hub details" +msgstr "Oppure fornisci i dettagli del vecchio server/hub" + +#: ../../mod/import.php:496 +msgid "Your old identity address (xyz@example.com)" +msgstr "Il tuo vecchio identificativo (per esempio pippo@esempio.com)" + +#: ../../mod/import.php:497 +msgid "Your old login email address" +msgstr "L'email che usavi per accedere sul vecchio server" + +#: ../../mod/import.php:498 +msgid "Your old login password" +msgstr "La password per il vecchio server" + +#: ../../mod/import.php:499 +msgid "" +"For either option, please choose whether to make this hub your new primary " +"address, or whether your old location should continue this role. You will be" +" able to post from either location, but only one can be marked as the " +"primary location for files, photos, and media." +msgstr "Scegli se vuoi spostare il tuo indirizzo primario su questo server, oppure se preferisci che quello vecchio resti tale. Potrai pubblicare da entrambi i server, ma solamente uno sarà indicato come posizione in cui risiedono i tuoi file, foto, ecc." + +#: ../../mod/import.php:500 +msgid "Make this hub my primary location" +msgstr "Rendi questo server il mio indirizzo primario" + +#: ../../mod/import.php:501 +msgid "Import existing posts if possible" +msgstr "Importazione dei post esistenti, se possibile" + +#: ../../mod/editlayout.php:78 ../../mod/editwebpage.php:77 +#: ../../mod/editpost.php:20 ../../mod/editblock.php:78 +#: ../../mod/editblock.php:94 +msgid "Item not found" +msgstr "Elemento non trovato" + +#: ../../mod/editlayout.php:108 +msgid "Edit Layout" +msgstr "Modifica il layout" + +#: ../../mod/editlayout.php:117 +msgid "Delete layout?" +msgstr "Vuoi eliminare questo layout?" + +#: ../../mod/editlayout.php:148 ../../mod/editwebpage.php:187 +#: ../../mod/editpost.php:122 ../../mod/editblock.php:150 +msgid "Insert YouTube video" +msgstr "Inserisci video da YouTube" + +#: ../../mod/editlayout.php:149 ../../mod/editwebpage.php:188 +#: ../../mod/editpost.php:123 ../../mod/editblock.php:151 +msgid "Insert Vorbis [.ogg] video" +msgstr "Inserisci video Vorbis [.ogg]" + +#: ../../mod/editlayout.php:150 ../../mod/editwebpage.php:189 +#: ../../mod/editpost.php:124 ../../mod/editblock.php:152 +msgid "Insert Vorbis [.ogg] audio" +msgstr "Inserisci audio Vorbis [.ogg]" + +#: ../../mod/editlayout.php:182 +msgid "Delete Layout" +msgstr "Elimina il layout" + +#: ../../mod/chat.php:19 ../../mod/channel.php:25 +msgid "You must be logged in to see this page." +msgstr "Devi aver effettuato l'accesso per vedere questa pagina." + +#: ../../mod/chat.php:167 +msgid "Room not found" +msgstr "Area chat non trovata" + +#: ../../mod/chat.php:178 +msgid "Leave Room" +msgstr "Lascia l'area chat" + +#: ../../mod/chat.php:179 +msgid "Delete This Room" +msgstr "Elimina questa area chat" + +#: ../../mod/chat.php:180 +msgid "I am away right now" +msgstr "Non sono presente" + +#: ../../mod/chat.php:181 +msgid "I am online" +msgstr "Sono online" + +#: ../../mod/chat.php:183 +msgid "Bookmark this room" +msgstr "Aggiungi l'area chat ai segnalibri" + +#: ../../mod/chat.php:207 ../../mod/chat.php:229 +msgid "New Chatroom" +msgstr "Nuova area chat" + +#: ../../mod/chat.php:208 +msgid "Chatroom Name" +msgstr "Nome dell'area chat" + +#: ../../mod/chat.php:225 +#, php-format +msgid "%1$s's Chatrooms" +msgstr "Le aree chat di %1$s" + +#: ../../mod/editwebpage.php:152 +msgid "Delete webpage?" +msgstr "Vuoi eliminare questa pagina web?" + +#: ../../mod/editwebpage.php:173 +msgid "Page link title" +msgstr "Link del titolo" + +#: ../../mod/editwebpage.php:224 +msgid "Edit Webpage" +msgstr "Modifica la pagina web" + +#: ../../mod/dirsearch.php:29 +msgid "This directory server requires an access token" +msgstr "Questo server di elenchi pubblici necessita di un token di autenticazione" + +#: ../../mod/lostpass.php:15 +msgid "No valid account found." +msgstr "Nessun account valido trovato." + +#: ../../mod/lostpass.php:29 +msgid "Password reset request issued. Check your email." +msgstr "La richiesta per reimpostare la password è stata inviata. Controlla la tua email." + +#: ../../mod/lostpass.php:35 ../../mod/lostpass.php:102 +#, php-format +msgid "Site Member (%s)" +msgstr "Utente del sito (%s)" + +#: ../../mod/lostpass.php:40 +#, php-format +msgid "Password reset requested at %s" +msgstr "È stato richiesto di reimpostare password su %s" + +#: ../../mod/lostpass.php:63 +msgid "" +"Request could not be verified. (You may have previously submitted it.) " +"Password reset failed." +msgstr "La richiesta non può essere verificata (potresti averla già usata precedentemente). La password non sarà reimpostata." + +#: ../../mod/lostpass.php:85 ../../boot.php:1548 +msgid "Password Reset" +msgstr "Reimposta la password" + +#: ../../mod/lostpass.php:86 +msgid "Your password has been reset as requested." +msgstr "La password è stata reimpostata come richiesto." + +#: ../../mod/lostpass.php:87 +msgid "Your new password is" +msgstr "La tua nuova password è" + +#: ../../mod/lostpass.php:88 +msgid "Save or copy your new password - and then" +msgstr "Salva o copia la tua nuova password, quindi" + +#: ../../mod/lostpass.php:89 +msgid "click here to login" +msgstr "clicca qui per accedere" + +#: ../../mod/lostpass.php:90 +msgid "" +"Your password may be changed from the Settings page after " +"successful login." +msgstr "Puoi cambiare la tua password dalla pagina delle Impostazioni dopo aver effettuato l'accesso." + +#: ../../mod/lostpass.php:107 +#, php-format +msgid "Your password has changed at %s" +msgstr "La tua password su %s è cambiata" + +#: ../../mod/lostpass.php:122 +msgid "Forgot your Password?" +msgstr "Hai dimenticato la password?" + +#: ../../mod/lostpass.php:123 +msgid "" +"Enter your email address and submit to have your password reset. Then check " +"your email for further instructions." +msgstr "Inserisci il tuo indirizzo email per reimpostare la password. Dopo aver inviato la richiesta, controlla l'email e troverai le istruzioni per continuare." + +#: ../../mod/lostpass.php:124 +msgid "Email Address" +msgstr "Indirizzo email" + +#: ../../mod/lostpass.php:125 +msgid "Reset" +msgstr "Reimposta" + +#: ../../mod/rate.php:157 +msgid "Website:" +msgstr "Sito web:" + +#: ../../mod/rate.php:160 +#, php-format +msgid "Remote Channel [%s] (not yet known on this site)" +msgstr "Canale remoto [%s] (non ancora conosciuto da questo sito)" + +#: ../../mod/rate.php:161 ../../mod/connedit.php:663 +msgid "Rating (this information is public)" +msgstr "Valutazione (visibile a tutti)" + +#: ../../mod/rate.php:162 ../../mod/connedit.php:664 +msgid "Optionally explain your rating (this information is public)" +msgstr "Commento alla valutazione (facoltativo, visibile a tutti)" + +#: ../../mod/editpost.php:31 +msgid "Item is not editable" +msgstr "L'elemento non è modificabile" + +#: ../../mod/editpost.php:53 +msgid "Delete item?" +msgstr "Eliminare questo elemento?" + +#: ../../mod/invite.php:25 +msgid "Total invitation limit exceeded." +msgstr "Hai superato il numero massimo di inviti." + +#: ../../mod/invite.php:49 +#, php-format +msgid "%s : Not a valid email address." +msgstr "%s: non è un indirizzo email valido." + +#: ../../mod/invite.php:76 +msgid "Please join us on Red" +msgstr "Vieni con noi su Hubzilla" + +#: ../../mod/invite.php:87 +msgid "Invitation limit exceeded. Please contact your site administrator." +msgstr "Hai superato il numero massimo di inviti. Contatta l'amministratore se necessario." + +#: ../../mod/invite.php:92 +#, php-format +msgid "%s : Message delivery failed." +msgstr "%s: la consegna del messaggio è fallita." + +#: ../../mod/invite.php:96 +#, php-format +msgid "%d message sent." +msgid_plural "%d messages sent." +msgstr[0] "%d messaggio inviato." +msgstr[1] "%d messaggi inviati." + +#: ../../mod/invite.php:115 +msgid "You have no more invitations available" +msgstr "Non hai altri inviti disponibili" + +#: ../../mod/invite.php:129 +msgid "Send invitations" +msgstr "Spedisci inviti" + +#: ../../mod/invite.php:130 +msgid "Enter email addresses, one per line:" +msgstr "Inserisci gli indirizzi email, uno per riga:" + +#: ../../mod/invite.php:131 ../../mod/mail.php:235 ../../mod/mail.php:348 +msgid "Your message:" +msgstr "Il tuo messaggio:" + +#: ../../mod/invite.php:132 +msgid "Please join my community on Hubzilla." +msgstr "Entra a far parte della mia comunità su Hubzilla." + +#: ../../mod/invite.php:134 +msgid "You will need to supply this invitation code: " +msgstr "Dovrai fornire questo codice di invito:" + +#: ../../mod/invite.php:135 +msgid "1. Register at any Hubzilla location (they are all inter-connected)" +msgstr "1. Registrati su un qualsiasi sito Hubzilla (sono tutti interconnessi)" + +#: ../../mod/invite.php:137 +msgid "2. Enter my Hubzilla network address into the site searchbar." +msgstr "2. Inserisci il mio indirizzo Hubzilla nella barra di ricerca che compare nella pagina." + +#: ../../mod/invite.php:138 +msgid "or visit " +msgstr "oppure visita " + +#: ../../mod/invite.php:140 +msgid "3. Click [Connect]" +msgstr "3. Clicca su [Aggiungi]" + +#: ../../mod/locs.php:21 ../../mod/locs.php:52 +msgid "Location not found." +msgstr "Indirizzo non trovato." + +#: ../../mod/locs.php:56 +msgid "Primary location cannot be removed." +msgstr "L'indirizzo principale non può essere rimosso." + +#: ../../mod/locs.php:88 +msgid "No locations found." +msgstr "Nessun indirizzo trovato." + +#: ../../mod/locs.php:101 +msgid "Manage Channel Locations" +msgstr "Modifica gli indirizzi del canale" + +#: ../../mod/locs.php:102 +msgid "Location (address)" +msgstr "Indirizzo" + +#: ../../mod/locs.php:103 +msgid "Primary Location" +msgstr "Indirizzo primario" + +#: ../../mod/locs.php:104 +msgid "Drop location" +msgstr "Elimina un indirizzo" + +#: ../../mod/sources.php:32 +msgid "Failed to create source. No channel selected." +msgstr "Impossibile creare la sorgente. Nessun canale selezionato." + +#: ../../mod/sources.php:45 +msgid "Source created." +msgstr "Sorgente creata." + +#: ../../mod/sources.php:57 +msgid "Source updated." +msgstr "Sorgente aggiornata." + +#: ../../mod/sources.php:82 +msgid "*" +msgstr "*" + +#: ../../mod/sources.php:89 +msgid "Manage remote sources of content for your channel." +msgstr "Gestisci le sorgenti dei contenuti del tuo canale." + +#: ../../mod/sources.php:90 ../../mod/sources.php:100 +msgid "New Source" +msgstr "Nuova sorgente" + +#: ../../mod/sources.php:101 ../../mod/sources.php:133 +msgid "" +"Import all or selected content from the following channel into this channel " +"and distribute it according to your channel settings." +msgstr "Importa nel tuo canale tutti o una parte dei contenuti dal canale seguente." + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Only import content with these words (one per line)" +msgstr "Importa solo i contenuti che hanno queste parole (una per riga)" + +#: ../../mod/sources.php:102 ../../mod/sources.php:134 +msgid "Leave blank to import all public content" +msgstr "Lascia vuoto per importare tutti i contenuti pubblici" + +#: ../../mod/sources.php:103 ../../mod/sources.php:137 +#: ../../mod/new_channel.php:112 +msgid "Channel Name" +msgstr "Nome del canale" + +#: ../../mod/sources.php:123 ../../mod/sources.php:150 +msgid "Source not found." +msgstr "Sorgente non trovata." + +#: ../../mod/sources.php:130 +msgid "Edit Source" +msgstr "Modifica la sorgente" + +#: ../../mod/sources.php:131 +msgid "Delete Source" +msgstr "Elimina la sorgente" + +#: ../../mod/sources.php:158 +msgid "Source removed" +msgstr "Sorgente eliminata" + +#: ../../mod/sources.php:160 +msgid "Unable to remove source." +msgstr "Impossibile rimuovere la sorgente." + +#: ../../mod/menu.php:44 +msgid "Unable to update menu." +msgstr "Impossibile aggiornare il menù." + +#: ../../mod/menu.php:53 +msgid "Unable to create menu." +msgstr "Impossibile creare il menù." + +#: ../../mod/menu.php:86 ../../mod/menu.php:98 +msgid "Menu Name" +msgstr "Nome del menu" + +#: ../../mod/menu.php:86 +msgid "Unique name (not visible on webpage) - required" +msgstr "Identificativo unico (non visibile sulla pagina) - obbligatorio" + +#: ../../mod/menu.php:87 ../../mod/menu.php:99 +msgid "Menu Title" +msgstr "Titolo del menu" + +#: ../../mod/menu.php:87 +msgid "Visible on webpage - leave empty for no title" +msgstr "Visibile sulla pagina - lascia vuoto per non avere un titolo" + +#: ../../mod/menu.php:88 +msgid "Allow Bookmarks" +msgstr "Permetti l'aggiunta ai segnalibri" + +#: ../../mod/menu.php:88 ../../mod/menu.php:140 +msgid "Menu may be used to store saved bookmarks" +msgstr "Puoi salvare i segnalibri nei menù" + +#: ../../mod/menu.php:89 +msgid "Submit and proceed" +msgstr "Salva e procedi" + +#: ../../mod/menu.php:101 +msgid "Drop" +msgstr "Elimina" + +#: ../../mod/menu.php:103 +msgid "Bookmarks allowed" +msgstr "Permetti segnalibri" + +#: ../../mod/menu.php:105 +msgid "Delete this menu" +msgstr "Elimina questo menù" + +#: ../../mod/menu.php:106 ../../mod/menu.php:137 +msgid "Edit menu contents" +msgstr "Modifica i contenuti del menù" + +#: ../../mod/menu.php:107 +msgid "Edit this menu" +msgstr "Modifica questo menù" + +#: ../../mod/menu.php:121 +msgid "Menu could not be deleted." +msgstr "Il menù non può essere eliminato." + +#: ../../mod/menu.php:129 ../../mod/mitem.php:24 +msgid "Menu not found." +msgstr "Menù non trovato." + +#: ../../mod/menu.php:134 +msgid "Edit Menu" +msgstr "Modifica menù" + +#: ../../mod/menu.php:136 +msgid "Add or remove entries to this menu" +msgstr "Aggiungi o rimuovi elementi di questo menù" + +#: ../../mod/menu.php:138 +msgid "Menu name" +msgstr "Nome del menù" + +#: ../../mod/menu.php:138 +msgid "Must be unique, only seen by you" +msgstr "Deve essere unico, lo vedrai solo tu" + +#: ../../mod/menu.php:139 +msgid "Menu title" +msgstr "Titolo del menù" + +#: ../../mod/menu.php:139 +msgid "Menu title as seen by others" +msgstr "Titolo del menù come comparirà a tutti" + +#: ../../mod/menu.php:140 +msgid "Allow bookmarks" +msgstr "Permetti l'invio di segnalibri" + +#: ../../mod/menu.php:142 +msgid "Modify" +msgstr "Modifica" + +#: ../../mod/filestorage.php:82 +msgid "Permission Denied." +msgstr "Permesso negato." + +#: ../../mod/filestorage.php:98 +msgid "File not found." +msgstr "File non trovato." + +#: ../../mod/filestorage.php:141 +msgid "Edit file permissions" +msgstr "Modifica i permessi del file" + +#: ../../mod/filestorage.php:150 +msgid "Set/edit permissions" +msgstr "Modifica i permessi" + +#: ../../mod/filestorage.php:151 +msgid "Include all files and sub folders" +msgstr "Includi tutti i file e le sottocartelle" + +#: ../../mod/filestorage.php:152 +msgid "Return to file list" +msgstr "Torna all'elenco dei file" + +#: ../../mod/filestorage.php:154 +msgid "Copy/paste this code to attach file to a post" +msgstr "Copia/incolla questo codice per far comparire il file in un articolo" + +#: ../../mod/filestorage.php:155 +msgid "Copy/paste this URL to link file from a web page" +msgstr "Copia/incolla questo indirizzo in una pagina web per avere un link al file" + +#: ../../mod/filestorage.php:157 +msgid "Share this file" +msgstr "Condividi questo file" + +#: ../../mod/filestorage.php:158 +msgid "Show URL to this file" +msgstr "Mostra l'URL del file" + +#: ../../mod/filestorage.php:159 +msgid "Notify your contacts about this file" +msgstr "Notifica ai tuoi contatti che hai caricato il file" + +#: ../../mod/fsuggest.php:20 ../../mod/fsuggest.php:92 +msgid "Contact not found." +msgstr "Contatto non trovato." + +#: ../../mod/fsuggest.php:63 +msgid "Friend suggestion sent." +msgstr "Suggerimento di amicizia inviato." + +#: ../../mod/fsuggest.php:97 +msgid "Suggest Friends" +msgstr "Suggerisci amici" + +#: ../../mod/fsuggest.php:99 +#, php-format +msgid "Suggest a friend for %s" +msgstr "Suggerisci un amico a %s" + +#: ../../mod/magic.php:69 +msgid "Hub not found." +msgstr "Server non trovato." + +#: ../../mod/poke.php:159 +msgid "Poke/Prod" +msgstr "Poke/Prod" + +#: ../../mod/poke.php:160 +msgid "poke, prod or do other things to somebody" +msgstr "Manda un poke, un prod o altro" + +#: ../../mod/poke.php:161 +msgid "Recipient" +msgstr "Destinatario" + +#: ../../mod/poke.php:162 +msgid "Choose what you wish to do to recipient" +msgstr "Scegli cosa vuoi inviare al destinatario" + +#: ../../mod/poke.php:165 +msgid "Make this post private" +msgstr "Rendi privato questo articolo" + +#: ../../mod/profperm.php:29 ../../mod/profperm.php:58 +msgid "Invalid profile identifier." +msgstr "Indentificativo del profilo non valido." + +#: ../../mod/profperm.php:110 +msgid "Profile Visibility Editor" +msgstr "Modifica la visibilità del profilo" + +#: ../../mod/profperm.php:114 +msgid "Click on a contact to add or remove." +msgstr "Clicca su un contatto per aggiungerlo o rimuoverlo." + +#: ../../mod/profperm.php:123 +msgid "Visible To" +msgstr "Visibile a" + +#: ../../mod/webpages.php:189 +msgid "Page Title" +msgstr "Titolo della pagina" + +#: ../../mod/profiles.php:18 ../../mod/profiles.php:174 +#: ../../mod/profiles.php:231 ../../mod/profiles.php:600 +msgid "Profile not found." +msgstr "Profilo non trovato." + +#: ../../mod/profiles.php:38 +msgid "Profile deleted." +msgstr "Profilo eliminato." + +#: ../../mod/profiles.php:56 ../../mod/profiles.php:92 +msgid "Profile-" +msgstr "Profilo-" + +#: ../../mod/profiles.php:77 ../../mod/profiles.php:120 +msgid "New profile created." +msgstr "Il nuovo profilo è stato creato." + +#: ../../mod/profiles.php:98 +msgid "Profile unavailable to clone." +msgstr "Impossibile duplicare il profilo." + +#: ../../mod/profiles.php:136 +msgid "Profile unavailable to export." +msgstr "Il profilo non è disponibile per l'export." + +#: ../../mod/profiles.php:241 +msgid "Profile Name is required." +msgstr "Il nome del profilo è obbligatorio ." + +#: ../../mod/profiles.php:404 +msgid "Marital Status" +msgstr "Stato sentimentale" + +#: ../../mod/profiles.php:408 +msgid "Romantic Partner" +msgstr "Partner affettivo" + +#: ../../mod/profiles.php:412 +msgid "Likes" +msgstr "Mi piace" + +#: ../../mod/profiles.php:416 +msgid "Dislikes" +msgstr "Non mi piace" + +#: ../../mod/profiles.php:420 +msgid "Work/Employment" +msgstr "Lavoro/impiego" + +#: ../../mod/profiles.php:423 +msgid "Religion" +msgstr "Religione" + +#: ../../mod/profiles.php:427 +msgid "Political Views" +msgstr "Orientamento politico" + +#: ../../mod/profiles.php:431 ../../mod/id.php:33 +msgid "Gender" +msgstr "Sesso" + +#: ../../mod/profiles.php:435 +msgid "Sexual Preference" +msgstr "Preferenze sessuali" + +#: ../../mod/profiles.php:439 +msgid "Homepage" +msgstr "Home page" + +#: ../../mod/profiles.php:443 +msgid "Interests" +msgstr "Interessi" + +#: ../../mod/profiles.php:447 ../../mod/admin.php:953 +msgid "Address" +msgstr "Indirizzo" + +#: ../../mod/profiles.php:537 +msgid "Profile updated." +msgstr "Profilo aggiornato." + +#: ../../mod/profiles.php:626 +msgid "Hide your contact/friend list from viewers of this profile?" +msgstr "Nascondi la tua lista di contatti/amici ai visitatori di questo profilo?" + +#: ../../mod/profiles.php:666 +msgid "Edit Profile Details" +msgstr "Modifica i dettagli del profilo" + +#: ../../mod/profiles.php:668 +msgid "View this profile" +msgstr "Guarda questo profilo" + +#: ../../mod/profiles.php:670 +msgid "Change Profile Photo" +msgstr "Cambia la foto del profilo" + +#: ../../mod/profiles.php:671 +msgid "Create a new profile using these settings" +msgstr "Crea un nuovo profilo usando queste impostazioni" + +#: ../../mod/profiles.php:672 +msgid "Clone this profile" +msgstr "Clona questo profilo" + +#: ../../mod/profiles.php:673 +msgid "Delete this profile" +msgstr "Elimina questo profilo" + +#: ../../mod/profiles.php:675 +msgid "Import profile from file" +msgstr "Importa il profilo da un file" + +#: ../../mod/profiles.php:676 +msgid "Export profile to file" +msgstr "Esporta il profilo in un file" + +#: ../../mod/profiles.php:677 +msgid "Profile Name:" +msgstr "Nome del profilo:" + +#: ../../mod/profiles.php:678 +msgid "Your Full Name:" +msgstr "Il tuo nome completo:" + +#: ../../mod/profiles.php:679 +msgid "Title/Description:" +msgstr "Titolo/descrizione:" + +#: ../../mod/profiles.php:680 +msgid "Your Gender:" +msgstr "Sesso:" + +#: ../../mod/profiles.php:681 +msgid "Birthday :" +msgstr "Compleanno:" + +#: ../../mod/profiles.php:682 +msgid "Street Address:" +msgstr "Indirizzo (via/piazza):" + +#: ../../mod/profiles.php:683 +msgid "Locality/City:" +msgstr "Località:" + +#: ../../mod/profiles.php:684 +msgid "Postal/Zip Code:" +msgstr "CAP:" + +#: ../../mod/profiles.php:685 +msgid "Country:" +msgstr "Nazione:" + +#: ../../mod/profiles.php:686 +msgid "Region/State:" +msgstr "Regione/stato:" + +#: ../../mod/profiles.php:687 +msgid " Marital Status:" +msgstr " Stato sentimentale:" + +#: ../../mod/profiles.php:688 +msgid "Who: (if applicable)" +msgstr "Con chi: (se possibile)" + +#: ../../mod/profiles.php:689 +msgid "Examples: cathy123, Cathy Williams, cathy@example.com" +msgstr "Per esempio: cathy123, Cathy Williams, cathy@example.com" + +#: ../../mod/profiles.php:690 +msgid "Since [date]:" +msgstr "dal [data]:" + +#: ../../mod/profiles.php:692 +msgid "Homepage URL:" +msgstr "Indirizzo home page:" + +#: ../../mod/profiles.php:695 +msgid "Religious Views:" +msgstr "Orientamento religioso:" + +#: ../../mod/profiles.php:696 +msgid "Keywords:" +msgstr "Parole chiave, tag:" + +#: ../../mod/profiles.php:699 +msgid "Example: fishing photography software" +msgstr "Per esempio: pesca fotografia programmazione" + +#: ../../mod/profiles.php:700 +msgid "Used in directory listings" +msgstr "Visibile nell'elenco pubblico di canali" + +#: ../../mod/profiles.php:701 +msgid "Tell us about yourself..." +msgstr "Raccontaci di te..." + +#: ../../mod/profiles.php:702 +msgid "Hobbies/Interests" +msgstr "Hobby/interessi" + +#: ../../mod/profiles.php:703 +msgid "Contact information and Social Networks" +msgstr "Contatti personali e i tuoi social network" + +#: ../../mod/profiles.php:704 +msgid "My other channels" +msgstr "I miei altri canali" + +#: ../../mod/profiles.php:705 +msgid "Musical interests" +msgstr "Interessi musicali" + +#: ../../mod/profiles.php:706 +msgid "Books, literature" +msgstr "Libri, letteratura" + +#: ../../mod/profiles.php:707 +msgid "Television" +msgstr "Televisione" + +#: ../../mod/profiles.php:708 +msgid "Film/dance/culture/entertainment" +msgstr "Film/danza/cultura/intrattenimento" + +#: ../../mod/profiles.php:709 +msgid "Love/romance" +msgstr "Amore" + +#: ../../mod/profiles.php:710 +msgid "Work/employment" +msgstr "Lavoro/impiego" + +#: ../../mod/profiles.php:711 +msgid "School/education" +msgstr "Scuola/educazione" + +#: ../../mod/profiles.php:717 +msgid "This is your default profile." +msgstr "Questo è il tuo profilo predefinito." + +#: ../../mod/profiles.php:728 ../../mod/directory.php:218 +msgid "Age: " +msgstr "Età:" + +#: ../../mod/profiles.php:771 +msgid "Edit/Manage Profiles" +msgstr "Modifica/gestisci i profili" + +#: ../../mod/profiles.php:772 +msgid "Add profile things" +msgstr "Aggiungi Oggetti al profilo" + +#: ../../mod/profiles.php:773 +msgid "Include desirable objects in your profile" +msgstr "Aggiungi oggetti interessanti al tuo profilo" + +#: ../../mod/ratings.php:69 +msgid "No ratings" +msgstr "Nessuna valutazione" + +#: ../../mod/ratings.php:99 +msgid "Ratings" +msgstr "Valutazioni" + +#: ../../mod/ratings.php:100 +msgid "Rating: " +msgstr "Valutazione:" + +#: ../../mod/ratings.php:101 +msgid "Website: " +msgstr "Sito web:" + +#: ../../mod/ratings.php:103 +msgid "Description: " +msgstr "Descrizione:" + +#: ../../mod/viewsrc.php:38 +msgid "Source of Item" +msgstr "Sorgente" + +#: ../../mod/mitem.php:51 +msgid "Unable to create element." +msgstr "Impossibile creare l'elemento." + +#: ../../mod/mitem.php:74 +msgid "Unable to update menu element." +msgstr "Non è possibile aggiornare l'elemento del menù." + +#: ../../mod/mitem.php:89 +msgid "Unable to add menu element." +msgstr "Impossibile aggiungere l'elemento al menù." + +#: ../../mod/mitem.php:151 ../../mod/mitem.php:220 +msgid "Menu Item Permissions" +msgstr "Permessi del menu" + +#: ../../mod/mitem.php:154 ../../mod/mitem.php:168 +msgid "Link Name" +msgstr "Nome link" + +#: ../../mod/mitem.php:155 ../../mod/mitem.php:169 +msgid "Link Target" +msgstr "Destinazione link" + +#: ../../mod/mitem.php:156 ../../mod/mitem.php:226 +msgid "Use Hubzilla magic-auth if available" +msgstr "Usa l'autenticazione magica di Hubzilla, se disponibile" + +#: ../../mod/mitem.php:157 ../../mod/mitem.php:227 +msgid "Open link in new window" +msgstr "Apri il link in una nuova finestra" + +#: ../../mod/mitem.php:158 ../../mod/mitem.php:228 +msgid "Order in list" +msgstr "Ordine dell'elenco" + +#: ../../mod/mitem.php:158 ../../mod/mitem.php:228 +msgid "Higher numbers will sink to bottom of listing" +msgstr "I numeri più alti andranno in fondo all'elenco" + +#: ../../mod/mitem.php:159 +msgid "Submit and finish" +msgstr "Salva e termina" + +#: ../../mod/mitem.php:160 +msgid "Submit and continue" +msgstr "Salva e continua" + +#: ../../mod/mitem.php:166 +msgid "Menu:" +msgstr "Menu:" + +#: ../../mod/mitem.php:172 +msgid "Edit menu" +msgstr "Modifica il menù" + +#: ../../mod/mitem.php:175 +msgid "Edit element" +msgstr "Modifica l'elemento" + +#: ../../mod/mitem.php:176 +msgid "Drop element" +msgstr "Elimina l'elemento" + +#: ../../mod/mitem.php:177 +msgid "New element" +msgstr "Nuovo elemento" + +#: ../../mod/mitem.php:178 +msgid "Edit this menu container" +msgstr "Modifica il contenitore del menù" + +#: ../../mod/mitem.php:179 +msgid "Add menu element" +msgstr "Aggiungi un elemento al menù" + +#: ../../mod/mitem.php:180 +msgid "Delete this menu item" +msgstr "Elimina questo elemento del menù" + +#: ../../mod/mitem.php:181 +msgid "Edit this menu item" +msgstr "Modifica questo elemento del menù" + +#: ../../mod/mitem.php:198 +msgid "Menu item not found." +msgstr "L'elemento del menù non è stato trovato." + +#: ../../mod/mitem.php:209 +msgid "Menu item deleted." +msgstr "L'elemento del menù è stato eliminato." + +#: ../../mod/mitem.php:211 +msgid "Menu item could not be deleted." +msgstr "L'elemento del menù non può essere eliminato." + +#: ../../mod/mitem.php:218 +msgid "Edit Menu Element" +msgstr "Modifica l'elemento del menù" + +#: ../../mod/mitem.php:224 +msgid "Link text" +msgstr "Testo del link" + +#: ../../mod/mitem.php:225 +msgid "URL of link" +msgstr "Indirizzo del link" + +#: ../../mod/openid.php:26 +msgid "OpenID protocol error. No ID returned." +msgstr "Errore del protocollo OpenID. Nessun ID ricevuto in risposta." + +#: ../../mod/openid.php:72 ../../mod/openid.php:180 ../../mod/post.php:286 +#, php-format +msgid "Welcome %s. Remote authentication successful." +msgstr "Ciao %s. L'autenticazione magica è avvenuta con successo." + +#: ../../mod/directory.php:224 +#, php-format +msgid "%d rating" +msgid_plural "%d ratings" +msgstr[0] "%d valutazione" +msgstr[1] "%d valutazioni" + +#: ../../mod/directory.php:236 +msgid "Gender: " +msgstr "Sesso:" + +#: ../../mod/directory.php:238 +msgid "Status: " +msgstr "Stato:" + +#: ../../mod/directory.php:240 +msgid "Homepage: " +msgstr "Homepage:" + +#: ../../mod/directory.php:243 +msgid "Hometown: " +msgstr "Città dove vivo:" + +#: ../../mod/directory.php:245 +msgid "About: " +msgstr "Informazioni:" + +#: ../../mod/directory.php:303 +msgid "Public Forum:" +msgstr "Forum pubblico:" + +#: ../../mod/directory.php:306 +msgid "Keywords: " +msgstr "Parole chiave:" + +#: ../../mod/directory.php:311 +#, php-format +msgid "Common connections: %s" +msgstr "Contatti in comune: %s" + +#: ../../mod/directory.php:363 +msgid "Finding:" +msgstr "Ricerca:" + +#: ../../mod/directory.php:368 +msgid "next page" +msgstr "pagina successiva" + +#: ../../mod/directory.php:368 +msgid "previous page" +msgstr "pagina precedente" + +#: ../../mod/directory.php:385 +msgid "No entries (some entries may be hidden)." +msgstr "Nessun risultato (qualche elemento potrebbe essere nascosto)." + +#: ../../mod/uexport.php:33 ../../mod/uexport.php:34 +msgid "Export Channel" +msgstr "Esporta il canale" + +#: ../../mod/uexport.php:35 +msgid "" +"Export your basic channel information to a small file. This acts as a " +"backup of your connections, permissions, profile and basic data, which can " +"be used to import your data to a new hub, but\tdoes not contain your " +"content." +msgstr "Esporta le informazioni di base del tuo canale in un piccolo file. E' utile per avere un salvataggio di sicurezza dei tuoi contatti, del tuo profilo ed altre informazioni fondamentali. Può essere usato per importare il tuo canale su un nuovo server, ma\tnon include i contenuti, per esempio articoli e foto." + +#: ../../mod/uexport.php:36 +msgid "Export Content" +msgstr "Esporta i contenuti" + +#: ../../mod/uexport.php:37 +msgid "" +"Export your channel information and all the content to a JSON backup. This " +"backs up all of your connections, permissions, profile data and all of your " +"content, but is generally not suitable for importing a channel to a new hub " +"as this file may be VERY large. Please be patient - it may take several " +"minutes for this download to begin." +msgstr "Esporta i dati del canale e i contenuti in un file in formato JSON. E' un salvataggio dei tuoi contatti, dei dati del profilo e anche di tutti i contenuti. Questa non è la soluzione opportuna per importare il tuo canale su un nuovo server, visto che il file potrebbe avere dimensioni NOTEVOLI. Devi pazientare - ci vorranno alcuni minuti per raccogliere i dati prima che inizi lo scaricamento." + +#: ../../mod/viewconnections.php:62 +msgid "No connections." +msgstr "Nessun contatto." + +#: ../../mod/viewconnections.php:75 +#, php-format +msgid "Visit %s's profile [%s]" +msgstr "Visita il profilo di %s [%s]" + +#: ../../mod/zfinger.php:23 +msgid "invalid target signature" +msgstr "la firma ricevuta non è valida" + +#: ../../mod/admin.php:52 +msgid "Theme settings updated." +msgstr "Le impostazioni del tema sono state aggiornate." + +#: ../../mod/admin.php:93 ../../mod/admin.php:445 +msgid "Site" +msgstr "Sito" + +#: ../../mod/admin.php:94 +msgid "Accounts" +msgstr "Account" + +#: ../../mod/admin.php:95 ../../mod/admin.php:945 +msgid "Channels" +msgstr "Canali" + +#: ../../mod/admin.php:96 ../../mod/admin.php:1036 ../../mod/admin.php:1076 +msgid "Plugins" +msgstr "Plugin" + +#: ../../mod/admin.php:97 ../../mod/admin.php:1236 ../../mod/admin.php:1270 +msgid "Themes" +msgstr "Temi" + +#: ../../mod/admin.php:98 +msgid "Inspect queue" +msgstr "Coda di attesa" + +#: ../../mod/admin.php:100 +msgid "Profile Config" +msgstr "Configurazione del profilo" + +#: ../../mod/admin.php:101 +msgid "DB updates" +msgstr "Aggiornamenti al DB" + +#: ../../mod/admin.php:115 ../../mod/admin.php:122 ../../mod/admin.php:1355 +msgid "Logs" +msgstr "Log" + +#: ../../mod/admin.php:121 +msgid "Plugin Features" +msgstr "Plugin" + +#: ../../mod/admin.php:123 +msgid "User registrations waiting for confirmation" +msgstr "Registrazioni in attesa" + +#: ../../mod/admin.php:200 +msgid "# Accounts" +msgstr "# account" + +#: ../../mod/admin.php:201 +msgid "# blocked accounts" +msgstr "# account bloccati" + +#: ../../mod/admin.php:202 +msgid "# expired accounts" +msgstr "# account scaduti" + +#: ../../mod/admin.php:203 +msgid "# expiring accounts" +msgstr "# account in scadenza" + +#: ../../mod/admin.php:216 +msgid "# Channels" +msgstr "# canali" + +#: ../../mod/admin.php:217 +msgid "# primary" +msgstr "# primari" + +#: ../../mod/admin.php:218 +msgid "# clones" +msgstr "# cloni" + +#: ../../mod/admin.php:224 +msgid "Message queues" +msgstr "Coda messaggi in uscita" + +#: ../../mod/admin.php:240 ../../mod/admin.php:444 ../../mod/admin.php:539 +#: ../../mod/admin.php:808 ../../mod/admin.php:944 ../../mod/admin.php:1035 +#: ../../mod/admin.php:1075 ../../mod/admin.php:1235 ../../mod/admin.php:1269 +#: ../../mod/admin.php:1354 +msgid "Administration" +msgstr "Amministrazione" + +#: ../../mod/admin.php:241 +msgid "Summary" +msgstr "Riepilogo" + +#: ../../mod/admin.php:244 +msgid "Registered accounts" +msgstr "Account creati" + +#: ../../mod/admin.php:245 ../../mod/admin.php:543 +msgid "Pending registrations" +msgstr "Registrazioni da approvare" + +#: ../../mod/admin.php:246 +msgid "Registered channels" +msgstr "Canali creati" + +#: ../../mod/admin.php:247 ../../mod/admin.php:544 +msgid "Active plugins" +msgstr "Plugin attivi" + +#: ../../mod/admin.php:248 +msgid "Version" +msgstr "Versione" + +#: ../../mod/admin.php:359 +msgid "Site settings updated." +msgstr "Impostazioni del sito salvate correttamente." + +#: ../../mod/admin.php:398 +msgid "experimental" +msgstr "sperimentale" + +#: ../../mod/admin.php:400 +msgid "unsupported" +msgstr "non supportato" + +#: ../../mod/admin.php:425 +msgid "Yes - with approval" +msgstr "Sì - con approvazione" + +#: ../../mod/admin.php:431 +msgid "My site is not a public server" +msgstr "Non è un server pubblico" + +#: ../../mod/admin.php:432 +msgid "My site has paid access only" +msgstr "È un servizio a pagamento" + +#: ../../mod/admin.php:433 +msgid "My site has free access only" +msgstr "È un servizio gratuito" + +#: ../../mod/admin.php:434 +msgid "My site offers free accounts with optional paid upgrades" +msgstr "È un servizio gratuito con opzioni aggiuntive a pagamento" + +#: ../../mod/admin.php:447 ../../mod/register.php:207 +msgid "Registration" +msgstr "Registrazione" + +#: ../../mod/admin.php:448 +msgid "File upload" +msgstr "Caricamento file" + +#: ../../mod/admin.php:449 +msgid "Policies" +msgstr "Politiche" + +#: ../../mod/admin.php:454 +msgid "Site name" +msgstr "Nome del sito" + +#: ../../mod/admin.php:455 +msgid "Banner/Logo" +msgstr "Banner o logo" + +#: ../../mod/admin.php:456 +msgid "Administrator Information" +msgstr "Informazioni sull'amministratore" + +#: ../../mod/admin.php:456 +msgid "" +"Contact information for site administrators. Displayed on siteinfo page. " +"BBCode can be used here" +msgstr "Informazioni per contattare gli amministratori del sito. Saranno mostrate sulla pagina di informazioni. È consentito il BBcode" + +#: ../../mod/admin.php:457 +msgid "System language" +msgstr "Lingua di sistema" + +#: ../../mod/admin.php:458 +msgid "System theme" +msgstr "Tema di sistema" + +#: ../../mod/admin.php:458 +msgid "" +"Default system theme - may be over-ridden by user profiles - change theme settings" +msgstr "Il tema di sistema può essere cambiato dai profili dei singoli utenti - Cambia le impostazioni del tema" + +#: ../../mod/admin.php:459 +msgid "Mobile system theme" +msgstr "Tema di sistema per dispositivi mobili" + +#: ../../mod/admin.php:459 +msgid "Theme for mobile devices" +msgstr "Tema per i dispositivi mobili" + +#: ../../mod/admin.php:461 +msgid "Enable Diaspora Protocol" +msgstr "Abilita la comunicazione con Diaspora" + +#: ../../mod/admin.php:461 +msgid "Communicate with Diaspora and Friendica - experimental" +msgstr "Sperimentale - per comunicare con Diaspora e Friendica" + +#: ../../mod/admin.php:462 +msgid "Allow Feeds as Connections" +msgstr "Permetti di aggiungere i feed come contatti" + +#: ../../mod/admin.php:462 +msgid "(Heavy system resource usage)" +msgstr "(Uso intenso delle risorse di sistema!)" + +#: ../../mod/admin.php:463 +msgid "Maximum image size" +msgstr "Dimensione massima immagini" + +#: ../../mod/admin.php:463 +msgid "" +"Maximum size in bytes of uploaded images. Default is 0, which means no " +"limits." +msgstr "Massima dimensione in byte delle immagini caricate. Il default è 0, cioè nessun limite." + +#: ../../mod/admin.php:464 +msgid "Does this site allow new member registration?" +msgstr "Questo sito permette a nuovi utenti di registrarsi?" + +#: ../../mod/admin.php:465 +msgid "Which best describes the types of account offered by this hub?" +msgstr "Come descriveresti il tipo di servizio proposto da questo server?" + +#: ../../mod/admin.php:466 +msgid "Register text" +msgstr "Testo di registrazione" + +#: ../../mod/admin.php:466 +msgid "Will be displayed prominently on the registration page." +msgstr "Sarà mostrato ben visibile nella pagina di registrazione." + +#: ../../mod/admin.php:467 +msgid "Accounts abandoned after x days" +msgstr "Account abbandonati dopo X giorni" + +#: ../../mod/admin.php:467 +msgid "" +"Will not waste system resources polling external sites for abandonded " +"accounts. Enter 0 for no time limit." +msgstr "Eviterà di sprecare risorse di sistema controllando se i siti esterni hanno account abbandonati. Immettere 0 per non imporre nessun limite di tempo." + +#: ../../mod/admin.php:468 +msgid "Allowed friend domains" +msgstr "Domini fidati e consentiti" + +#: ../../mod/admin.php:468 +msgid "" +"Comma separated list of domains which are allowed to establish friendships " +"with this site. Wildcards are accepted. Empty to allow any domains" +msgstr "Elenco separato da virglola dei domini che possono stabilire amicizie con questo sito. Sono accettati caratteri jolly. Lascia vuoto per accettare connessioni da qualsiasi dominio." + +#: ../../mod/admin.php:469 +msgid "Allowed email domains" +msgstr "Domini email consentiti" + +#: ../../mod/admin.php:469 +msgid "" +"Comma separated list of domains which are allowed in email addresses for " +"registrations to this site. Wildcards are accepted. Empty to allow any " +"domains" +msgstr "Elenco separato da virgola dei domini permessi come indirizzi email in fase di registrazione. Sono accettati caratteri jolly. Lascia vuoto per accettare qualsiasi dominio email" + +#: ../../mod/admin.php:470 +msgid "Not allowed email domains" +msgstr "Domini email non consentiti" + +#: ../../mod/admin.php:470 +msgid "" +"Comma separated list of domains which are not allowed in email addresses for" +" registrations to this site. Wildcards are accepted. Empty to allow any " +"domains, unless allowed domains have been defined." +msgstr "Elenco separato da virgola dei domini permessi come indirizzi email in fase di registrazione a questo sito. Sono accettati caratteri jolly. Lascalo vuoto per accettare qualsiasi dominio." + +#: ../../mod/admin.php:471 +msgid "Block public" +msgstr "Blocca pagine pubbliche" + +#: ../../mod/admin.php:471 +msgid "" +"Check to block public access to all otherwise public personal pages on this " +"site unless you are currently logged in." +msgstr "Seleziona per impedire di vedere le pagine personali di questo sito a chi non ha effettuato l'accesso." + +#: ../../mod/admin.php:472 +msgid "Verify Email Addresses" +msgstr "Verifica l'indirizzo email" + +#: ../../mod/admin.php:472 +msgid "" +"Check to verify email addresses used in account registration (recommended)." +msgstr "Attiva per richiedere la verifica degli indirizzi email dei nuovi utenti (consigliato)." + +#: ../../mod/admin.php:473 +msgid "Force publish" +msgstr "Forza la publicazione del profilo" + +#: ../../mod/admin.php:473 +msgid "" +"Check to force all profiles on this site to be listed in the site directory." +msgstr "Seleziona per mostrare nell'elenco pubblico tutti i profili registrati su questo sito." + +#: ../../mod/admin.php:474 +msgid "Disable discovery tab" +msgstr "Disabilita la funzione 'scopri'" + +#: ../../mod/admin.php:474 +msgid "" +"Remove the tab in the network view with public content pulled from sources " +"chosen for this site." +msgstr "Nell'area della rete personale non comparirà più la scheda con i contenuti acquisiti da altri siti." + +#: ../../mod/admin.php:475 +msgid "No login on Homepage" +msgstr "Non mostrare il login sulla homepage" + +#: ../../mod/admin.php:475 +msgid "" +"Check to hide the login form from your sites homepage when visitors arrive " +"who are not logged in (e.g. when you put the content of the homepage in via " +"the site channel)." +msgstr "Per nascondere la possibilità di fare login ai visitatori (per esempio, quando il contenuto della homepage del sito è alimentato da un canale)." + +#: ../../mod/admin.php:477 +msgid "Proxy user" +msgstr "Utente proxy" + +#: ../../mod/admin.php:478 +msgid "Proxy URL" +msgstr "URL proxy" + +#: ../../mod/admin.php:479 +msgid "Network timeout" +msgstr "Timeout rete" + +#: ../../mod/admin.php:479 +msgid "Value is in seconds. Set to 0 for unlimited (not recommended)." +msgstr "Valore in secondi. Imposta a 0 per illimitato (sconsigliato)." + +#: ../../mod/admin.php:480 +msgid "Delivery interval" +msgstr "Recapito ritardato" + +#: ../../mod/admin.php:480 +msgid "" +"Delay background delivery processes by this many seconds to reduce system " +"load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 " +"for large dedicated servers." +msgstr "Numero di secondi di cui può essere ritardato il recapito, per ridurre il carico di sistema. Consigliati: 4-5 secondi per hosting condiviso, 2-3 per i VPS, 0-1 per grandi server dedicati." + +#: ../../mod/admin.php:481 +msgid "Poll interval" +msgstr "Intervallo di polling" + +#: ../../mod/admin.php:481 +msgid "" +"Delay background polling processes by this many seconds to reduce system " +"load. If 0, use delivery interval." +msgstr "Numero di secondi di cui può essere ritardato il polling in background, per ridurre il carico del sistema. Se 0, verrà usato lo stesso valore del 'Recapito ritardato'." + +#: ../../mod/admin.php:482 +msgid "Maximum Load Average" +msgstr "Carico massimo medio" + +#: ../../mod/admin.php:482 +msgid "" +"Maximum system load before delivery and poll processes are deferred - " +"default 50." +msgstr "Carico di sistema massimo perché i processi di recapito e polling siano ritardati - il valore predefinito è 50." + +#: ../../mod/admin.php:483 +msgid "Expiration period in days for imported (matrix/network) content" +msgstr "Scadenza dei contenuti importati da altri siti (in giorni)" + +#: ../../mod/admin.php:483 +msgid "0 for no expiration of imported content" +msgstr "0 per non avere scadenza" + +#: ../../mod/admin.php:531 +msgid "No server found" +msgstr "Server non trovato" + +#: ../../mod/admin.php:538 ../../mod/admin.php:822 +msgid "ID" +msgstr "ID" + +#: ../../mod/admin.php:538 +msgid "for channel" +msgstr "per canale" + +#: ../../mod/admin.php:538 +msgid "on server" +msgstr "sul server" + +#: ../../mod/admin.php:538 +msgid "Status" +msgstr "Stato" + +#: ../../mod/admin.php:540 +msgid "Server" +msgstr "Server" + +#: ../../mod/admin.php:557 +msgid "Update has been marked successful" +msgstr "L'aggiornamento è stato marcato come eseguito." + +#: ../../mod/admin.php:567 +#, php-format +msgid "Executing %s failed. Check system logs." +msgstr "Fallita l'esecuzione di %s. Maggiori informazioni sui log di sistema." + +#: ../../mod/admin.php:570 +#, php-format +msgid "Update %s was successfully applied." +msgstr "L'aggiornamento %s è terminato correttamente." + +#: ../../mod/admin.php:574 +#, php-format +msgid "Update %s did not return a status. Unknown if it succeeded." +msgstr "L'aggiornamento %s non ha dato risposta. Impossibile determinare se è terminato correttamente." + +#: ../../mod/admin.php:577 +#, php-format +msgid "Update function %s could not be found." +msgstr "Impossibile trovare la funzione di aggiornamento %s" + +#: ../../mod/admin.php:593 +msgid "No failed updates." +msgstr "Nessun aggiornamento fallito." + +#: ../../mod/admin.php:597 +msgid "Failed Updates" +msgstr "Aggiornamenti falliti." + +#: ../../mod/admin.php:599 +msgid "Mark success (if update was manually applied)" +msgstr "Marca come eseguito (se applicato manualmente)." + +#: ../../mod/admin.php:600 +msgid "Attempt to execute this update step automatically" +msgstr "Tenta di eseguire in automatico questo passaggio dell'aggiornamento." + +#: ../../mod/admin.php:632 +msgid "Queue Statistics" +msgstr "Statistiche della coda" + +#: ../../mod/admin.php:633 +msgid "Total Entries" +msgstr "Totale" + +#: ../../mod/admin.php:634 +msgid "Priority" +msgstr "Priorità" + +#: ../../mod/admin.php:635 +msgid "Destination URL" +msgstr "URL di destinazione" + +#: ../../mod/admin.php:636 +msgid "Mark hub permanently offline" +msgstr "Questo hub è definitivamente offline" + +#: ../../mod/admin.php:637 +msgid "Empty queue for this hub" +msgstr "Svuota la coda per questo hub" + +#: ../../mod/admin.php:638 +msgid "Last known contact" +msgstr "Ultimo scambio dati" + +#: ../../mod/admin.php:674 +#, php-format +msgid "%s user blocked/unblocked" +msgid_plural "%s users blocked/unblocked" +msgstr[0] "%s utente bloccato/sbloccato" +msgstr[1] "%s utenti bloccati/sbloccati" + +#: ../../mod/admin.php:682 +#, php-format +msgid "%s user deleted" +msgid_plural "%s users deleted" +msgstr[0] "%s utente cancellato" +msgstr[1] "%s utenti cancellati" + +#: ../../mod/admin.php:718 +msgid "Account not found" +msgstr "Account non trovato" + +#: ../../mod/admin.php:738 +#, php-format +msgid "User '%s' blocked" +msgstr "Utente '%s' bloccato" + +#: ../../mod/admin.php:746 +#, php-format +msgid "User '%s' unblocked" +msgstr "Utente '%s' sbloccato" + +#: ../../mod/admin.php:809 ../../mod/admin.php:821 +msgid "Users" +msgstr "Utenti" + +#: ../../mod/admin.php:811 ../../mod/admin.php:947 +msgid "select all" +msgstr "seleziona tutti" + +#: ../../mod/admin.php:812 +msgid "User registrations waiting for confirm" +msgstr "Richieste di registrazione in attesa di conferma" + +#: ../../mod/admin.php:813 +msgid "Request date" +msgstr "Data richiesta" + +#: ../../mod/admin.php:814 +msgid "No registrations." +msgstr "Nessuna registrazione." + +#: ../../mod/admin.php:815 +msgid "Approve" +msgstr "Approva" + +#: ../../mod/admin.php:816 +msgid "Deny" +msgstr "Nega" + +#: ../../mod/admin.php:818 ../../mod/connedit.php:517 +#: ../../mod/connedit.php:720 +msgid "Block" +msgstr "Blocca" + +#: ../../mod/admin.php:819 ../../mod/connedit.php:517 +#: ../../mod/connedit.php:720 +msgid "Unblock" +msgstr "Sblocca" + +#: ../../mod/admin.php:822 +msgid "Register date" +msgstr "Data registrazione" + +#: ../../mod/admin.php:822 +msgid "Last login" +msgstr "Ultimo accesso" + +#: ../../mod/admin.php:822 +msgid "Expires" +msgstr "Con scadenza" + +#: ../../mod/admin.php:822 +msgid "Service Class" +msgstr "Classe dell'account" + +#: ../../mod/admin.php:824 +msgid "" +"Selected users will be deleted!\\n\\nEverything these users had posted on " +"this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Gli utenti selezionati saranno eliminati!\\n\\nTutto quello che gli utenti hanno pubblicato su questo sito sarà permanentemente eliminato!\\n\\nConfermi?" + +#: ../../mod/admin.php:825 +msgid "" +"The user {0} will be deleted!\\n\\nEverything this user has posted on this " +"site will be permanently deleted!\\n\\nAre you sure?" +msgstr "L'utente {0} sarà eliminato!\\n\\nTutto quello che ha pubblicato su questo sito sarà permanentemente eliminato!\\n\\nConfermi?" + +#: ../../mod/admin.php:859 +#, php-format +msgid "%s channel censored/uncensored" +msgid_plural "%s channels censored/uncensored" +msgstr[0] "Censura modificata per %s canale" +msgstr[1] "Censura modificata per %s canali" + +#: ../../mod/admin.php:866 +#, php-format +msgid "%s channel deleted" +msgid_plural "%s channels deleted" +msgstr[0] "%s canale è stato rimosso" +msgstr[1] "%s canali sono stati rimossi" + +#: ../../mod/admin.php:886 +msgid "Channel not found" +msgstr "Canale non trovato" + +#: ../../mod/admin.php:897 +#, php-format +msgid "Channel '%s' deleted" +msgstr "Il canale '%s' è stato rimosso" + +#: ../../mod/admin.php:908 +#, php-format +msgid "Channel '%s' uncensored" +msgstr "Rimossa la censura dal canale '%s'" + +#: ../../mod/admin.php:908 +#, php-format +msgid "Channel '%s' censored" +msgstr "Applicata una censura al canale '%s'" + +#: ../../mod/admin.php:949 +msgid "Censor" +msgstr "Applica una censura" + +#: ../../mod/admin.php:950 +msgid "Uncensor" +msgstr "Rimuovi la censura" + +#: ../../mod/admin.php:953 +msgid "UID" +msgstr "UID" + +#: ../../mod/admin.php:955 +msgid "" +"Selected channels will be deleted!\\n\\nEverything that was posted in these " +"channels on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "I canali selezionati saranno rimossi!\\n\\nTutto ciò che è stato pubblicato su questo server tramite questi canali sarà irreversibilmente eliminato!\\n\\nVuoi confermare?" + +#: ../../mod/admin.php:956 +msgid "" +"The channel {0} will be deleted!\\n\\nEverything that was posted in this " +"channel on this site will be permanently deleted!\\n\\nAre you sure?" +msgstr "Il canale {0} sarà rimosso!\\n\\nTutto ciò che è stato pubblicato su questo server tramite questo canale sarà irreversibilmente eliminato!\\n\\nVuoi confermare?" + +#: ../../mod/admin.php:996 +#, php-format +msgid "Plugin %s disabled." +msgstr "Plugin %s non attivo." + +#: ../../mod/admin.php:1000 +#, php-format +msgid "Plugin %s enabled." +msgstr "Plugin %s attivo." + +#: ../../mod/admin.php:1010 ../../mod/admin.php:1208 +msgid "Disable" +msgstr "Disattiva" + +#: ../../mod/admin.php:1013 ../../mod/admin.php:1210 +msgid "Enable" +msgstr "Attiva" + +#: ../../mod/admin.php:1037 ../../mod/admin.php:1237 +msgid "Toggle" +msgstr "Attiva/disattiva" + +#: ../../mod/admin.php:1045 ../../mod/admin.php:1247 +msgid "Author: " +msgstr "Autore:" + +#: ../../mod/admin.php:1046 ../../mod/admin.php:1248 +msgid "Maintainer: " +msgstr "Gestore:" + +#: ../../mod/admin.php:1173 +msgid "No themes found." +msgstr "Nessun tema trovato." + +#: ../../mod/admin.php:1229 +msgid "Screenshot" +msgstr "Istantanea dello schermo" + +#: ../../mod/admin.php:1275 +msgid "[Experimental]" +msgstr "[Sperimentale]" + +#: ../../mod/admin.php:1276 +msgid "[Unsupported]" +msgstr "[Non supportato]" + +#: ../../mod/admin.php:1300 +msgid "Log settings updated." +msgstr "Impostazioni di log aggiornate." + +#: ../../mod/admin.php:1357 +msgid "Clear" +msgstr "Pulisci" + +#: ../../mod/admin.php:1363 +msgid "Debugging" +msgstr "Debugging" + +#: ../../mod/admin.php:1364 +msgid "Log file" +msgstr "File di log" + +#: ../../mod/admin.php:1364 +msgid "" +"Must be writable by web server. Relative to your Red top-level directory." +msgstr "Deve essere scrivibile dal web server. La posizione è relativa alla cartella dove è installato Hubzilla." + +#: ../../mod/admin.php:1365 +msgid "Log level" +msgstr "Livello di log" + +#: ../../mod/admin.php:1411 +msgid "New Profile Field" +msgstr "Nuovo campo del profilo" + +#: ../../mod/admin.php:1412 ../../mod/admin.php:1432 +msgid "Field nickname" +msgstr "Nome breve del campo" + +#: ../../mod/admin.php:1412 ../../mod/admin.php:1432 +msgid "System name of field" +msgstr "Nome di sistema del campo" + +#: ../../mod/admin.php:1413 ../../mod/admin.php:1433 +msgid "Input type" +msgstr "Tipo di dati" + +#: ../../mod/admin.php:1414 ../../mod/admin.php:1434 +msgid "Field Name" +msgstr "Nome del campo" + +#: ../../mod/admin.php:1414 ../../mod/admin.php:1434 +msgid "Label on profile pages" +msgstr "Etichetta da mostrare sulla pagina del profilo" + +#: ../../mod/admin.php:1415 ../../mod/admin.php:1435 +msgid "Help text" +msgstr "Testo di aiuto" + +#: ../../mod/admin.php:1415 ../../mod/admin.php:1435 +msgid "Additional info (optional)" +msgstr "Informazioni aggiuntive (opzionali)" + +#: ../../mod/admin.php:1425 +msgid "Field definition not found" +msgstr "Impossibile trovare la definizione del campo" + +#: ../../mod/admin.php:1431 +msgid "Edit Profile Field" +msgstr "Modifica campo del profilo" + +#: ../../mod/oexchange.php:23 +msgid "Unable to find your hub." +msgstr "Impossibile raggiungere il tuo hub." + +#: ../../mod/oexchange.php:37 +msgid "Post successful." +msgstr "Inviato!" + +#: ../../mod/editblock.php:112 +msgid "Edit Block" +msgstr "Modifica il riquadro" + +#: ../../mod/editblock.php:123 +msgid "Delete block?" +msgstr "Vuoi eliminare questo riquadro?" + +#: ../../mod/register.php:44 +msgid "Maximum daily site registrations exceeded. Please try again tomorrow." +msgstr "È stato superato il numero massimo giornaliero di registrazioni a questo sito. Riprova domani!" + +#: ../../mod/register.php:50 +msgid "" +"Please indicate acceptance of the Terms of Service. Registration failed." +msgstr "Impossibile proseguire. Devi prima accettare le Condizioni d'Uso del servizio." + +#: ../../mod/register.php:84 +msgid "Passwords do not match." +msgstr "Le password non corrispondono." + +#: ../../mod/register.php:117 +msgid "" +"Registration successful. Please check your email for validation " +"instructions." +msgstr "La registrazione è terminata correttamente. Per continuare controlla l'email che ti è stata inviata." + +#: ../../mod/register.php:123 +msgid "Your registration is pending approval by the site owner." +msgstr "La tua richiesta è in attesa di approvazione da parte dell'amministratore del sito." + +#: ../../mod/register.php:126 +msgid "Your registration can not be processed." +msgstr "La tua registrazione non puo' essere processata." + +#: ../../mod/register.php:163 +msgid "Registration on this site/hub is by approval only." +msgstr "La registrazione su questo sito è soggetta ad approvazione." + +#: ../../mod/register.php:164 +msgid "Register at another affiliated site/hub" +msgstr "Registrati su un altro server affiliato" + +#: ../../mod/register.php:174 +msgid "" +"This site has exceeded the number of allowed daily account registrations. " +"Please try again tomorrow." +msgstr "Questo sito ha superato il numero di registrazioni giornaliere consentite. Prova di nuovo domani." + +#: ../../mod/register.php:185 +msgid "Terms of Service" +msgstr "Condizioni d'Uso" + +#: ../../mod/register.php:191 +#, php-format +msgid "I accept the %s for this website" +msgstr "Accetto le %s di questo sito" + +#: ../../mod/register.php:193 +#, php-format +msgid "I am over 13 years of age and accept the %s for this website" +msgstr "Ho più di 13 anni e accetto le %s di questo sito" + +#: ../../mod/register.php:212 +msgid "Membership on this site is by invitation only." +msgstr "Per registrarsi su questo sito è necessario un invito." + +#: ../../mod/register.php:213 +msgid "Please enter your invitation code" +msgstr "Inserisci il codice dell'invito" + +#: ../../mod/register.php:216 +msgid "Your email address" +msgstr "Il tuo indirizzo email" + +#: ../../mod/register.php:217 +msgid "Choose a password" +msgstr "Scegli una password" + +#: ../../mod/register.php:218 +msgid "Please re-enter your password" +msgstr "Ripeti la password per verifica" + +#: ../../mod/removeaccount.php:30 +msgid "" +"Account removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Non è possibile eliminare il tuo account prima di 48 ore dall'ultimo cambio password." + +#: ../../mod/removeaccount.php:57 +msgid "Remove This Account" +msgstr "Elimina questo account" + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "WARNING: " +msgstr "ATTENZIONE:" + +#: ../../mod/removeaccount.php:58 +msgid "" +"This account and all its channels will be completely removed from the " +"network. " +msgstr "Questo account e tutti i suoi canali saranno completamente eliminati dalla rete." + +#: ../../mod/removeaccount.php:58 ../../mod/removeme.php:58 +msgid "This action is permanent and can not be undone!" +msgstr "Questo comando è definitivo e non può essere annullato!" + +#: ../../mod/removeaccount.php:59 ../../mod/removeme.php:59 +msgid "Please enter your password for verification:" +msgstr "Inserisci la tua password per verifica:" + +#: ../../mod/removeaccount.php:60 +msgid "" +"Remove this account, all its channels and all its channel clones from the " +"network" +msgstr "Elimina dalla rete questo account, tutti i suoi canali e ANCHE tutti gli eventuali canali clonati." + +#: ../../mod/removeaccount.php:60 +msgid "" +"By default only the instances of the channels located on this hub will be " +"removed from the network" +msgstr "A meno che tu non lo richieda espressamente, solo i canali presenti su questo server saranno rimossi dalla rete." + +#: ../../mod/item.php:174 +msgid "Unable to locate original post." +msgstr "Impossibile trovare il messaggio originale." + +#: ../../mod/item.php:437 +msgid "Empty post discarded." +msgstr "L'articolo vuoto è stato ignorato." + +#: ../../mod/item.php:479 +msgid "Executable content type not permitted to this channel." +msgstr "I contenuti eseguibili non sono permessi su questo canale." + +#: ../../mod/item.php:885 +msgid "System error. Post not saved." +msgstr "Errore di sistema. Articolo non salvato." + +#: ../../mod/item.php:1103 +msgid "Unable to obtain post information from database." +msgstr "Impossibile caricare l'articolo dal database." + +#: ../../mod/item.php:1110 +#, php-format +msgid "You have reached your limit of %1$.0f top level posts." +msgstr "Hai raggiunto il limite massimo di %1$.0f articoli sulla pagina principale." + +#: ../../mod/item.php:1117 +#, php-format +msgid "You have reached your limit of %1$.0f webpages." +msgstr "Hai raggiunto il limite massimo di %1$.0f pagine web." + +#: ../../mod/update_channel.php:43 ../../mod/update_display.php:25 +#: ../../mod/update_network.php:23 ../../mod/update_search.php:46 +#: ../../mod/update_home.php:21 +msgid "[Embedded content - reload page to view]" +msgstr "[Contenuto incorporato - ricarica la pagina per visualizzarlo correttamente]" + +#: ../../mod/lockview.php:37 +msgid "Remote privacy information not available." +msgstr "Le informazioni remote sulla privacy non sono disponibili." + +#: ../../mod/lockview.php:58 +msgid "Visible to:" +msgstr "Visibile a:" + +#: ../../mod/blocks.php:95 ../../mod/blocks.php:144 +msgid "Block Name" +msgstr "Nome del riquadro" + +#: ../../mod/id.php:11 +msgid "First Name" +msgstr "Nome" + +#: ../../mod/id.php:12 +msgid "Last Name" +msgstr "Cognome" + +#: ../../mod/id.php:13 +msgid "Nickname" +msgstr "Nick" + +#: ../../mod/id.php:14 +msgid "Full Name" +msgstr "Nome e cognome" + +#: ../../mod/id.php:20 +msgid "Profile Photo 16px" +msgstr "Foto del profilo 16px" + +#: ../../mod/id.php:21 +msgid "Profile Photo 32px" +msgstr "Foto del profilo 32px" + +#: ../../mod/id.php:22 +msgid "Profile Photo 48px" +msgstr "Foto del profilo 48px" + +#: ../../mod/id.php:23 +msgid "Profile Photo 64px" +msgstr "Foto del profilo 64px" + +#: ../../mod/id.php:24 +msgid "Profile Photo 80px" +msgstr "Foto del profilo 80px" + +#: ../../mod/id.php:25 +msgid "Profile Photo 128px" +msgstr "Foto del profilo 128px" + +#: ../../mod/id.php:26 +msgid "Timezone" +msgstr "Fuso orario" + +#: ../../mod/id.php:27 +msgid "Homepage URL" +msgstr "Indirizzo home page" + +#: ../../mod/id.php:29 +msgid "Birth Year" +msgstr "Anno di nascita" + +#: ../../mod/id.php:30 +msgid "Birth Month" +msgstr "Mese di nascita" + +#: ../../mod/id.php:31 +msgid "Birth Day" +msgstr "Giorno di nascita" + +#: ../../mod/id.php:32 +msgid "Birthdate" +msgstr "Data di nascita" + +#: ../../mod/message.php:41 +msgid "Conversation removed." +msgstr "Conversazione rimossa." + +#: ../../mod/message.php:56 +msgid "No messages." +msgstr "Nessun messaggio." + +#: ../../mod/message.php:72 ../../mod/mail.php:336 +msgid "Delete conversation" +msgstr "Elimina la conversazione" + +#: ../../mod/message.php:74 +msgid "D, d M Y - g:i A" +msgstr "D d M Y - G:i" + +#: ../../mod/layouts.php:111 +msgid "Help with this feature" +msgstr "La guida per questa funzionalità" + +#: ../../mod/layouts.php:132 +msgid "Layout Name" +msgstr "Nome layout" + +#: ../../mod/layouts.php:171 +msgid "Comanche page description language help" +msgstr "Guida di Comanche Page Description Language" + +#: ../../mod/mood.php:131 +msgid "Set your current mood and tell your friends" +msgstr "Scegli il tuo umore attuale per mostrarlo agli amici" + +#: ../../mod/vote.php:97 +msgid "Total votes" +msgstr "Voti totali" + +#: ../../mod/vote.php:98 +msgid "Average Rating" +msgstr "Valutazione media" + +#: ../../mod/removeme.php:29 +msgid "" +"Channel removals are not allowed within 48 hours of changing the account " +"password." +msgstr "Non è possibile eliminare un canale prima di 48 ore dall'ultimo cambio password." + +#: ../../mod/removeme.php:57 +msgid "Remove This Channel" +msgstr "Elimina questo canale" + +#: ../../mod/removeme.php:58 +msgid "This channel will be completely removed from the network. " +msgstr "Questo canale sarà completamente eliminato dalla rete." + +#: ../../mod/removeme.php:60 +msgid "Remove this channel and all its clones from the network" +msgstr "Rimuovi questo canale e tutti i suoi cloni dalla rete" + +#: ../../mod/removeme.php:60 +msgid "" +"By default only the instance of the channel located on this hub will be " +"removed from the network" +msgstr "L'impostazione predefinita è che sia eliminata solo l'istanza del canale presente su questo hub, non gli eventuali cloni" + +#: ../../mod/connedit.php:262 +msgid "is now connected to" +msgstr "ha come nuovo contatto" + +#: ../../mod/connedit.php:375 +msgid "Could not access address book record." +msgstr "Impossibile accedere alle informazioni della rubrica." + +#: ../../mod/connedit.php:389 +msgid "Refresh failed - channel is currently unavailable." +msgstr "Il canale non è disponibile - impossibile aggiornare." + +#: ../../mod/connedit.php:396 +msgid "Channel has been unblocked" +msgstr "Il canale è stato sbloccato" + +#: ../../mod/connedit.php:397 +msgid "Channel has been blocked" +msgstr "Il canale è stato bloccato" + +#: ../../mod/connedit.php:401 ../../mod/connedit.php:413 +#: ../../mod/connedit.php:425 ../../mod/connedit.php:437 +#: ../../mod/connedit.php:453 +msgid "Unable to set address book parameters." +msgstr "Impossibile impostare i parametri della rubrica." + +#: ../../mod/connedit.php:408 +msgid "Channel has been unignored" +msgstr "Il canale non sarà più ignorato" + +#: ../../mod/connedit.php:409 +msgid "Channel has been ignored" +msgstr "Il canale sarà ignorato" + +#: ../../mod/connedit.php:420 +msgid "Channel has been unarchived" +msgstr "Il canale non è più archiviato" + +#: ../../mod/connedit.php:421 +msgid "Channel has been archived" +msgstr "Il canale è stato archiviato" + +#: ../../mod/connedit.php:432 +msgid "Channel has been unhidden" +msgstr "Il canale non è più nascosto" + +#: ../../mod/connedit.php:433 +msgid "Channel has been hidden" +msgstr "Il canale è stato nascosto" + +#: ../../mod/connedit.php:448 +msgid "Channel has been approved" +msgstr "Il canale è stato approvato" + +#: ../../mod/connedit.php:449 +msgid "Channel has been unapproved" +msgstr "Il canale non è più approvato" + +#: ../../mod/connedit.php:477 +msgid "Connection has been removed." +msgstr "Il contatto è stato rimosso." + +#: ../../mod/connedit.php:497 +#, php-format +msgid "View %s's profile" +msgstr "Guarda il profilo di %s" + +#: ../../mod/connedit.php:501 +msgid "Refresh Permissions" +msgstr "Modifica i permessi" + +#: ../../mod/connedit.php:504 +msgid "Fetch updated permissions" +msgstr "Guarda e modifica i permessi assegnati" + +#: ../../mod/connedit.php:508 +msgid "Recent Activity" +msgstr "Attività recenti" + +#: ../../mod/connedit.php:511 +msgid "View recent posts and comments" +msgstr "Leggi i post recenti e i commenti" + +#: ../../mod/connedit.php:520 +msgid "Block (or Unblock) all communications with this connection" +msgstr "Blocca ogni interazione con questo contatto (abilita/disabilita)" + +#: ../../mod/connedit.php:524 ../../mod/connedit.php:721 +msgid "Unignore" +msgstr "Non ignorare" + +#: ../../mod/connedit.php:524 ../../mod/connedit.php:721 +#: ../../mod/notifications.php:51 +msgid "Ignore" +msgstr "Ignora" + +#: ../../mod/connedit.php:527 +msgid "Ignore (or Unignore) all inbound communications from this connection" +msgstr "Ignora tutte le comunicazioni in arrivo da questo contatto (abilita/disabilita)" + +#: ../../mod/connedit.php:530 +msgid "Unarchive" +msgstr "Non archiviare" + +#: ../../mod/connedit.php:530 +msgid "Archive" +msgstr "Archivia" + +#: ../../mod/connedit.php:533 +msgid "" +"Archive (or Unarchive) this connection - mark channel dead but keep content" +msgstr "Archivia questo contatto (abilita/disabilita) - segna il canale come non più attivo ma ne conserva i contenuti" + +#: ../../mod/connedit.php:536 +msgid "Unhide" +msgstr "Non nascondere" + +#: ../../mod/connedit.php:536 +msgid "Hide" +msgstr "Nascondi" + +#: ../../mod/connedit.php:539 +msgid "Hide or Unhide this connection from your other connections" +msgstr "Nascondi questo contatto a tutti gli altri (abilita/disabilita)" + +#: ../../mod/connedit.php:546 +msgid "Delete this connection" +msgstr "Elimina questo contatto" + +#: ../../mod/connedit.php:637 ../../mod/connedit.php:675 +msgid "Approve this connection" +msgstr "Approva questo contatto" + +#: ../../mod/connedit.php:637 +msgid "Accept connection to allow communication" +msgstr "Entra in contatto per poter comunicare" + +#: ../../mod/connedit.php:653 +#, php-format +msgid "Connections: settings for %s" +msgstr "Contatti: impostazioni per %s" + +#: ../../mod/connedit.php:654 +msgid "Apply these permissions automatically" +msgstr "Applica automaticamente questi permessi" + +#: ../../mod/connedit.php:658 +msgid "Apply the permissions indicated on this page to all new connections." +msgstr "Applica i permessi indicati su questa pagina a tutti i nuovi contatti." + +#: ../../mod/connedit.php:662 +msgid "Slide to adjust your degree of friendship" +msgstr "Trascina per restringere il grado di amicizia da mostrare" + +#: ../../mod/connedit.php:671 +msgid "" +"Default permissions for your channel type have (just) been applied. They " +"have not yet been submitted. Please review the permissions on this page and " +"make any desired changes at this time. This new connection may not " +"be able to communicate with you until you submit this page, which will " +"install and apply the selected permissions." +msgstr "I tuoi nuovi contatti potrebbero non essere abilitati a comunicare con te finché non salverai questa pagina (perché non hai permessi impostati). Sono stati selezionati i permessi standard per il tipo di canale che hai scelto. Non sono stati ancora salvati però. Puoi verificare le impostazioni e fare i cambiamenti che preferisci prima di salvare. " + +#: ../../mod/connedit.php:674 +msgid "inherited" +msgstr "derivato" + +#: ../../mod/connedit.php:677 +msgid "Connection has no individual permissions!" +msgstr "Non hai assegnato permessi individuali a questo contatto!" + +#: ../../mod/connedit.php:678 +msgid "" +"This may be appropriate based on your privacy " +"settings, though you may wish to review the \"Advanced Permissions\"." +msgstr "Questo corrisponde alle tue impostazioni di privacy, ma puoi anche dare un'occhiata ai 'Permessi avanzati' per opzioni più dettagliate." + +#: ../../mod/connedit.php:680 +msgid "Profile Visibility" +msgstr "Visibilità del profilo" + +#: ../../mod/connedit.php:681 +#, php-format +msgid "" +"Please choose the profile you would like to display to %s when viewing your " +"profile securely." +msgstr "Seleziona il profilo che vuoi mostrare a %s quando visita il tuo profilo in modo sicuro." + +#: ../../mod/connedit.php:682 +msgid "Contact Information / Notes" +msgstr "Informazioni e annotazioni sul contatto" + +#: ../../mod/connedit.php:683 +msgid "Edit contact notes" +msgstr "Modifica le informazioni sul contatto" + +#: ../../mod/connedit.php:685 +msgid "Their Settings" +msgstr "Permessi concessi a te" + +#: ../../mod/connedit.php:686 +msgid "My Settings" +msgstr "I permessi che concedo" + +#: ../../mod/connedit.php:688 +msgid "" +"Default permissions for this channel type have (just) been applied. They " +"have not been saved and there are currently no stored default " +"permissions. Please review/edit the applied settings and click [Submit] to " +"finalize." +msgstr "A questo canale sono stati applicati i permessi predefiniti ma non sono stati salvati. In realtà non esistono ancora dei permessi predefiniti da usare su questo sito. Controlla e verifica le impostazioni, [Salva] per confermare." + +#: ../../mod/connedit.php:689 +msgid "Clear/Disable Automatic Permissions" +msgstr "Rimuovi/disabilita i permessi automatici" + +#: ../../mod/connedit.php:690 +msgid "Forum Members" +msgstr "Membro di un forum" + +#: ../../mod/connedit.php:691 +msgid "Soapbox" +msgstr "Comunicati e annunci" + +#: ../../mod/connedit.php:692 +msgid "Full Sharing (typical social network permissions)" +msgstr "Condivisione completa (permessi tipici dei social network)" + +#: ../../mod/connedit.php:693 +msgid "Cautious Sharing " +msgstr "Condivisione prudente" + +#: ../../mod/connedit.php:694 +msgid "Follow Only" +msgstr "Follower" + +#: ../../mod/connedit.php:695 +msgid "Individual Permissions" +msgstr "Permessi individuali" + +#: ../../mod/connedit.php:696 +msgid "" +"Some permissions may be inherited from your channel privacy settings, which have higher priority than " +"individual settings. Changing those inherited settings on this page will " +"have no effect." +msgstr "I permessi nelle impostazioni di privacy hanno priorità su quelli mostrati in questa pagina. Non avrà alcun effetto cambiarli qui, se sono indicati come derivati." + +#: ../../mod/connedit.php:697 +msgid "Advanced Permissions" +msgstr "Permessi avanzati" + +#: ../../mod/connedit.php:698 +msgid "Simple Permissions (select one and submit)" +msgstr "Permessi semplificati (seleziona e salva)" + +#: ../../mod/connedit.php:702 +#, php-format +msgid "Visit %s's profile - %s" +msgstr "Guarda il profilo di %s - %s" + +#: ../../mod/connedit.php:703 +msgid "Block/Unblock contact" +msgstr "Blocca/sblocca contatto" + +#: ../../mod/connedit.php:704 +msgid "Ignore contact" +msgstr "Ignora il contatto" + +#: ../../mod/connedit.php:705 +msgid "Repair URL settings" +msgstr "Ripara le impostazioni URL" + +#: ../../mod/connedit.php:706 +msgid "View conversations" +msgstr "Leggi le conversazioni" + +#: ../../mod/connedit.php:708 +msgid "Delete contact" +msgstr "Elimina contatto" + +#: ../../mod/connedit.php:712 +msgid "Last update:" +msgstr "Ultimo aggiornamento:" + +#: ../../mod/connedit.php:714 +msgid "Update public posts" +msgstr "Aggiorna gli articoli pubblici" + +#: ../../mod/connedit.php:716 +msgid "Update now" +msgstr "Aggiorna adesso" + +#: ../../mod/connedit.php:722 +msgid "Currently blocked" +msgstr "Attualmente bloccato" + +#: ../../mod/connedit.php:723 +msgid "Currently ignored" +msgstr "Attualmente ignorato" + +#: ../../mod/connedit.php:724 +msgid "Currently archived" +msgstr "Attualmente archiviato" + +#: ../../mod/connedit.php:725 +msgid "Currently pending" +msgstr "Attualmente da approvare" + +#: ../../mod/rmagic.php:40 +msgid "" +"We encountered a problem while logging in with the OpenID you provided. " +"Please check the correct spelling of the ID." +msgstr "Non è possibile effettuare login con l'OpenID che hai fornito. Per favore controlla che sia scritto correttamente." + +#: ../../mod/rmagic.php:40 +msgid "The error message was:" +msgstr "Messaggio di errore ricevuto:" + +#: ../../mod/rmagic.php:44 +msgid "Authentication failed." +msgstr "Autenticazione fallita." + +#: ../../mod/rmagic.php:84 +msgid "Remote Authentication" +msgstr "Autenticazione a distanza" + +#: ../../mod/rmagic.php:85 +msgid "Enter your channel address (e.g. channel@example.com)" +msgstr "Inserisci l'indirizzo del tuo canale (ad esempio lucia@esempio.com)" + +#: ../../mod/rmagic.php:86 +msgid "Authenticate" +msgstr "Autenticazione" + +#: ../../mod/mail.php:33 +msgid "Unable to lookup recipient." +msgstr "Impossibile associare un destinatario." + +#: ../../mod/mail.php:41 +msgid "Unable to communicate with requested channel." +msgstr "Impossibile comunicare con il canale richiesto." + +#: ../../mod/mail.php:48 +msgid "Cannot verify requested channel." +msgstr "Impossibile verificare il canale richiesto." + +#: ../../mod/mail.php:74 +msgid "Selected channel has private message restrictions. Send failed." +msgstr "Il canale ha delle regole restrittive per la ricezione dei messaggi privati. Invio fallito." + +#: ../../mod/mail.php:139 +msgid "Message deleted." +msgstr "Messaggio eliminato." + +#: ../../mod/mail.php:156 +msgid "Message recalled." +msgstr "Messaggio revocato." + +#: ../../mod/mail.php:225 +msgid "Send Private Message" +msgstr "Invia un messaggio privato" + +#: ../../mod/mail.php:226 ../../mod/mail.php:343 +msgid "To:" +msgstr "A:" + +#: ../../mod/mail.php:231 ../../mod/mail.php:345 +msgid "Subject:" +msgstr "Oggetto:" + +#: ../../mod/mail.php:242 +msgid "Send" +msgstr "Invia" + +#: ../../mod/mail.php:269 +msgid "Message not found." +msgstr "Messaggio non trovato." + +#: ../../mod/mail.php:312 +msgid "Delete message" +msgstr "Elimina il messaggio" + +#: ../../mod/mail.php:313 +msgid "Recall message" +msgstr "Revoca il messaggio" + +#: ../../mod/mail.php:315 +msgid "Message has been recalled." +msgstr "Il messaggio è stato revocato." + +#: ../../mod/mail.php:332 +msgid "Private Conversation" +msgstr "Conversazione privata" + +#: ../../mod/mail.php:338 +msgid "" +"No secure communications available. You may be able to " +"respond from the sender's profile page." +msgstr "Non è disponibile alcuna tecnologia per comunicare in modo sicuro. Se possibile, prova a rispondere direttamente dalla pagina del profilo del mittente." + +#: ../../mod/mail.php:342 +msgid "Send Reply" +msgstr "Invia la risposta" + +#: ../../mod/notifications.php:26 +msgid "Invalid request identifier." +msgstr "L'identificativo della richiesta non è valido." + +#: ../../mod/notifications.php:35 +msgid "Discard" +msgstr "Rifiuta" + +#: ../../mod/regmod.php:11 +msgid "Please login." +msgstr "Effettua l'accesso." + +#: ../../mod/post.php:235 +msgid "" +"Remote authentication blocked. You are logged into this site locally. Please" +" logout and retry." +msgstr "L'autenticazione magica dal tuo sito non è disponibile. Hai accesso solamente a questo sito. Puoi provare a disconnetterti per tentare di nuovo." + +#: ../../mod/new_channel.php:109 +msgid "Add a Channel" +msgstr "Aggiungi un canale" + +#: ../../mod/new_channel.php:110 +msgid "" +"A channel is your own collection of related web pages. A channel can be used" +" to hold social network profiles, blogs, conversation groups and forums, " +"celebrity pages, and much more. You may create as many channels as your " +"service provider allows." +msgstr "I contenuti che pubblichi sono mostrati nel tuo \"canale\". Un canale può essere usato come bacheca personale, come blog, oppure può essere un forum di discussione, un gruppo di interesse, una pagina di celebrità e molto altro. Puoi creare tanti canali quanti ne permette il tuo sito." + +#: ../../mod/new_channel.php:113 +msgid "Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" " +msgstr "Per esempio: \"Mario Rossi\", \"Lisa e le sue ricette\", \"Il campionato\", \"Il gruppo di escursionismo\"" + +#: ../../mod/new_channel.php:114 +msgid "Choose a short nickname" +msgstr "Scegli un nome breve" + +#: ../../mod/new_channel.php:115 +msgid "" +"Your nickname will be used to create an easily remembered channel address " +"(like an email address) which you can share with others." +msgstr "Il nome breve sarà usato per creare un indirizzo facile da ricordare per il tuo canale (simile a una email). Così potrai condividerlo e gli altri potranno trovarti." + +#: ../../mod/new_channel.php:116 +msgid "Or import an existing channel from another location" +msgstr "Oppure importa un tuo canale esistente da un altro server/hub" + +#: ../../mod/new_channel.php:118 +msgid "" +"Please choose a channel type (such as social networking or community forum) " +"and privacy requirements so we can select the best permissions for you" +msgstr "Descrivi il tipo di canale che vorresti creare (per esempio se ti interessa più usarlo come social network, come un forum di discussione...) e il tipo di privacy che preferisci. Hubzilla sceglierà per te i permessi più adatti." + +#: ../../mod/new_channel.php:119 +msgid "Channel Type" +msgstr "Tipo di canale" + +#: ../../mod/new_channel.php:119 +msgid "Read more about roles" +msgstr "Maggiori informazioni sui ruoli" + +#: ../../mod/appman.php:28 ../../mod/appman.php:44 +msgid "App installed." +msgstr "App installata" + +#: ../../mod/appman.php:37 +msgid "Malformed app." +msgstr "App non corretta" + +#: ../../mod/appman.php:80 +msgid "Embed code" +msgstr "Inserisci del codice" + +#: ../../mod/appman.php:86 +msgid "Edit App" +msgstr "Modifica app" + +#: ../../mod/appman.php:86 +msgid "Create App" +msgstr "Crea una app" + +#: ../../mod/appman.php:91 +msgid "Name of app" +msgstr "Nome app" + +#: ../../mod/appman.php:92 +msgid "Location (URL) of app" +msgstr "Indirizzo (URL) della app" + +#: ../../mod/appman.php:94 +msgid "Photo icon URL" +msgstr "URL icona" + +#: ../../mod/appman.php:94 +msgid "80 x 80 pixels - optional" +msgstr "80 x 80 pixel - facoltativa" + +#: ../../mod/appman.php:95 +msgid "Version ID" +msgstr "ID versione" + +#: ../../mod/appman.php:96 +msgid "Price of app" +msgstr "Prezzo app" + +#: ../../mod/appman.php:97 +msgid "Location (URL) to purchase app" +msgstr "Indirizzo (URL) per acquistare la app" + +#: ../../mod/ping.php:263 +msgid "sent you a private message" +msgstr "ti ha inviato un messaggio privato" + +#: ../../mod/ping.php:314 +msgid "added your channel" +msgstr "ha aggiunto il tuo canale" + +#: ../../mod/ping.php:355 +msgid "posted an event" +msgstr "ha creato un evento" + +#: ../../mod/network.php:91 +msgid "No such group" +msgstr "Impossibile trovare l'insieme" + +#: ../../mod/network.php:129 +msgid "No such channel" +msgstr "Canale sconosciuto" + +#: ../../mod/network.php:143 +msgid "Search Results For:" +msgstr "Cerca risultati con:" + +#: ../../mod/network.php:198 +msgid "Collection is empty" +msgstr "L'insieme di canali è vuoto" + +#: ../../mod/network.php:207 +msgid "Collection: " +msgstr "Insieme:" + +#: ../../mod/network.php:226 +msgid "Connection: " +msgstr "Contatto:" + +#: ../../mod/network.php:233 +msgid "Invalid connection." +msgstr "Contatto non valido." + +#: ../../mod/page.php:119 +msgid "Ipsum Lorem" +msgstr "Ipsum Lorem" + +#: ../../mod/bookmarks.php:38 +msgid "Bookmark added" +msgstr "Segnalibro aggiunto" + +#: ../../mod/bookmarks.php:60 +msgid "My Bookmarks" +msgstr "I miei segnalibri" + +#: ../../mod/bookmarks.php:71 +msgid "My Connections Bookmarks" +msgstr "I segnalibri dei miei contatti" + +#: ../../mod/channel.php:97 +msgid "Insufficient permissions. Request redirected to profile page." +msgstr "Permessi insufficienti. Sarà visualizzata la pagina del profilo." + +#: ../../mod/suggest.php:35 +msgid "" +"No suggestions available. If this is a new site, please try again in 24 " +"hours." +msgstr "Nessun suggerimento disponibile. Se questo sito è nuovo, riprova tra 24 ore." + +#: ../../mod/poll.php:64 +msgid "Poll" +msgstr "Sondaggio" + +#: ../../mod/poll.php:69 +msgid "View Results" +msgstr "Guarda i risultati" + +#: ../../mod/service_limits.php:19 +msgid "No service class restrictions found." +msgstr "Non esistono restrizioni su questa classe di account." + +#: ../../mod/sharedwithme.php:94 +msgid "Files: shared with me" +msgstr "File: condivisi con me" + +#: ../../mod/sharedwithme.php:96 +msgid "NEW" +msgstr "NOVITÀ" + +#: ../../mod/sharedwithme.php:99 +msgid "Remove all files" +msgstr "Elimina tutti i file" + +#: ../../mod/sharedwithme.php:100 +msgid "Remove this file" +msgstr "Elimina questo file" + +#: ../../view/theme/apw/php/config.php:202 +#: ../../view/theme/apw/php/config.php:236 +msgid "Schema Default" +msgstr "Schema predefinito" + +#: ../../view/theme/apw/php/config.php:203 +msgid "Sans-Serif" +msgstr "Sans-serif" + +#: ../../view/theme/apw/php/config.php:204 +msgid "Monospace" +msgstr "Monospace" + +#: ../../view/theme/apw/php/config.php:259 +#: ../../view/theme/redbasic/php/config.php:100 +msgid "Theme settings" +msgstr "Impostazioni del tema" + +#: ../../view/theme/apw/php/config.php:260 +msgid "Set scheme" +msgstr "Schema" + +#: ../../view/theme/apw/php/config.php:261 +#: ../../view/theme/redbasic/php/config.php:122 +msgid "Set font-size for posts and comments" +msgstr "Dimensioni del carattere per articoli e commenti" + +#: ../../view/theme/apw/php/config.php:262 +msgid "Set font face" +msgstr "Tipo di carattere" + +#: ../../view/theme/apw/php/config.php:263 +msgid "Set iconset" +msgstr "Icone" + +#: ../../view/theme/apw/php/config.php:264 +msgid "Set big shadow size, default 15px 15px 15px" +msgstr "Ombra grande, predefinita 15px 15px 15px" + +#: ../../view/theme/apw/php/config.php:265 +msgid "Set small shadow size, default 5px 5px 5px" +msgstr "Ombra piccola, predefinita 5px 5px 5px" + +#: ../../view/theme/apw/php/config.php:266 +msgid "Set shadow color, default #000" +msgstr "Colore dell'ombra, predefinito #000" + +#: ../../view/theme/apw/php/config.php:267 +msgid "Set radius size, default 5px" +msgstr "Raggio degli angoli, predefinito 5px" + +#: ../../view/theme/apw/php/config.php:268 +msgid "Set line-height for posts and comments" +msgstr "Altezza della riga per articoli e commenti" + +#: ../../view/theme/apw/php/config.php:269 +msgid "Set background image" +msgstr "Immagine di sfondo" + +#: ../../view/theme/apw/php/config.php:270 +msgid "Set background attachment" +msgstr "Allega uno sfondo" + +#: ../../view/theme/apw/php/config.php:271 +msgid "Set background color" +msgstr "Colore di sfondo" + +#: ../../view/theme/apw/php/config.php:272 +msgid "Set section background image" +msgstr "Immagine di sfondo della sezione" + +#: ../../view/theme/apw/php/config.php:273 +msgid "Set section background color" +msgstr "Colore di sfondo dell'area principale" + +#: ../../view/theme/apw/php/config.php:274 +msgid "Set color of items - use hex" +msgstr "Colore degli elementi della pagina - esadecimale" + +#: ../../view/theme/apw/php/config.php:275 +msgid "Set color of links - use hex" +msgstr "Colore dei link - esadecimale" + +#: ../../view/theme/apw/php/config.php:276 +msgid "Set max-width for items. Default 400px" +msgstr "Larghezza massima degli elementi della pagina. Predefinita: 400px" + +#: ../../view/theme/apw/php/config.php:277 +msgid "Set min-width for items. Default 240px" +msgstr "Larghezza minima degli elementi della pagina. Predefinita: 240px" + +#: ../../view/theme/apw/php/config.php:278 +msgid "Set the generic content wrapper width. Default 48%" +msgstr "Larghezza di tutta l'area dei contenuti. Predefinita: 48%" + +#: ../../view/theme/apw/php/config.php:279 +msgid "Set color of fonts - use hex" +msgstr "Colore dei caratteri - esadecimale" + +#: ../../view/theme/apw/php/config.php:280 +msgid "Set background-size element" +msgstr "Background-size element" + +#: ../../view/theme/apw/php/config.php:281 +msgid "Item opacity" +msgstr "Opacità degli elementi della pagina" + +#: ../../view/theme/apw/php/config.php:282 +msgid "Display post previews only" +msgstr "Mostra le anteprime solo degli articoli" + +#: ../../view/theme/apw/php/config.php:283 +msgid "Display side bar on channel page" +msgstr "Mostra la colonna laterale sulla pagina del canale" + +#: ../../view/theme/apw/php/config.php:284 +msgid "Colour of the navigation bar" +msgstr "Colore della barra di navigazione" + +#: ../../view/theme/apw/php/config.php:285 +msgid "Item float" +msgstr "Float degli oggetti della pagina" + +#: ../../view/theme/apw/php/config.php:286 +msgid "Left offset of the section element" +msgstr "Margine sinistro dell'area principale" + +#: ../../view/theme/apw/php/config.php:287 +msgid "Right offset of the section element" +msgstr "Margine destro dell'area principale" + +#: ../../view/theme/apw/php/config.php:288 +msgid "Section width" +msgstr "Larghezza dell'area principale" + +#: ../../view/theme/apw/php/config.php:289 +msgid "Left offset of the aside" +msgstr "Margine sinistro della colonna laterale" + +#: ../../view/theme/apw/php/config.php:290 +msgid "Right offset of the aside element" +msgstr "Margine destro della colonna laterale" + +#: ../../view/theme/redbasic/php/config.php:82 +msgid "Light (Hubzilla default)" +msgstr "Light (predefinito)" + +#: ../../view/theme/redbasic/php/config.php:101 +msgid "Select scheme" +msgstr "Scegli uno schema" + +#: ../../view/theme/redbasic/php/config.php:102 +msgid "Narrow navbar" +msgstr "Barra di navigazione ristretta" + +#: ../../view/theme/redbasic/php/config.php:103 +msgid "Navigation bar background color" +msgstr "Barra di navigazione: Colore di sfondo" + +#: ../../view/theme/redbasic/php/config.php:104 +msgid "Navigation bar gradient top color" +msgstr "Barra di navigazione: Gradiente superiore" + +#: ../../view/theme/redbasic/php/config.php:105 +msgid "Navigation bar gradient bottom color" +msgstr "Barra di navigazione: Gradiente inferiore" + +#: ../../view/theme/redbasic/php/config.php:106 +msgid "Navigation active button gradient top color" +msgstr "Bottone di navigazione attivo: Gradiente superiore" + +#: ../../view/theme/redbasic/php/config.php:107 +msgid "Navigation active button gradient bottom color" +msgstr "Bottone di navigazione attivo: Gradiente inferiore" + +#: ../../view/theme/redbasic/php/config.php:108 +msgid "Navigation bar border color " +msgstr "Barra di navigazione: Colore del bordo" + +#: ../../view/theme/redbasic/php/config.php:109 +msgid "Navigation bar icon color " +msgstr "Barra di navigazione: Colore delle icone" + +#: ../../view/theme/redbasic/php/config.php:110 +msgid "Navigation bar active icon color " +msgstr "Barra di navigazione: Colore dell'icona attiva" + +#: ../../view/theme/redbasic/php/config.php:111 +msgid "link color" +msgstr "colore del link" + +#: ../../view/theme/redbasic/php/config.php:112 +msgid "Set font-color for banner" +msgstr "Colore del font del banner" + +#: ../../view/theme/redbasic/php/config.php:113 +msgid "Set the background color" +msgstr "Imposta il colore di sfondo" + +#: ../../view/theme/redbasic/php/config.php:114 +msgid "Set the background image" +msgstr "Immagine di sfondo" + +#: ../../view/theme/redbasic/php/config.php:115 +msgid "Set the background color of items" +msgstr "Imposta il colore di sfondo degli oggetti" + +#: ../../view/theme/redbasic/php/config.php:116 +msgid "Set the background color of comments" +msgstr "Imposta il colore di sfondo dei commenti" + +#: ../../view/theme/redbasic/php/config.php:117 +msgid "Set the border color of comments" +msgstr "Imposta il colore del bordo dei commenti" + +#: ../../view/theme/redbasic/php/config.php:118 +msgid "Set the indent for comments" +msgstr "Imposta il lo spostamento a destra dei commenti" + +#: ../../view/theme/redbasic/php/config.php:119 +msgid "Set the basic color for item icons" +msgstr "Colore di base per le icone" + +#: ../../view/theme/redbasic/php/config.php:120 +msgid "Set the hover color for item icons" +msgstr "Colore per le icone in mouse-over" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Set font-size for the entire application" +msgstr "Dimensione font per tutto il sito" + +#: ../../view/theme/redbasic/php/config.php:121 +msgid "Example: 14px" +msgstr "Esempio: 14px" + +#: ../../view/theme/redbasic/php/config.php:123 +msgid "Set font-color for posts and comments" +msgstr "Imposta il colore del carattere per articoli e commenti" + +#: ../../view/theme/redbasic/php/config.php:124 +msgid "Set radius of corners" +msgstr "Raggio degli angoli stondati" + +#: ../../view/theme/redbasic/php/config.php:125 +msgid "Set shadow depth of photos" +msgstr "Profondità dell'ombra delle foto" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Set maximum width of content region in pixel" +msgstr "Larghezza massima dell'area dei contenuti in pixel" + +#: ../../view/theme/redbasic/php/config.php:126 +msgid "Leave empty for default width" +msgstr "Lascia vuoto per usare il valore predefinito" + +#: ../../view/theme/redbasic/php/config.php:127 +msgid "Center page content" +msgstr "Centra il contenuto della pagina" + +#: ../../view/theme/redbasic/php/config.php:128 +msgid "Set minimum opacity of nav bar - to hide it" +msgstr "Imposta l'opacità minima della barra di navigazione per nasconderla" + +#: ../../view/theme/redbasic/php/config.php:129 +msgid "Set size of conversation author photo" +msgstr "Dimensione foto dell'autore della conversazione" + +#: ../../view/theme/redbasic/php/config.php:130 +msgid "Set size of followup author photos" +msgstr "Dimensione foto dei partecipanti alla conversazione" + +#: ../../boot.php:1345 +#, php-format +msgid "Update %s failed. See error logs." +msgstr "%s: aggiornamento fallito. Controlla i log di errore." + +#: ../../boot.php:1348 +#, php-format +msgid "Update Error at %s" +msgstr "Errore di aggiornamento su %s" + +#: ../../boot.php:1515 +msgid "" +"Create an account to access services and applications within the Hubzilla" +msgstr "Registrati per accedere ai servizi e alle applicazioni di Hubzilla" + +#: ../../boot.php:1543 +msgid "Password" +msgstr "Password" + +#: ../../boot.php:1544 +msgid "Remember me" +msgstr "Resta connesso" + +#: ../../boot.php:1547 +msgid "Forgot your password?" +msgstr "Hai dimenticato la password?" + +#: ../../boot.php:2166 +msgid "toggle mobile" +msgstr "attiva/disattiva versione mobile" + +#: ../../boot.php:2301 +msgid "Website SSL certificate is not valid. Please correct." +msgstr "Il certificato SSL del sito non è valido. Si prega di intervenire." + +#: ../../boot.php:2304 +#, php-format +msgid "[red] Website SSL error for %s" +msgstr "[red] Errore SSL %s " + +#: ../../boot.php:2341 +msgid "Cron/Scheduled tasks not running." +msgstr "Processi/cron non avviati." + +#: ../../boot.php:2345 +#, php-format +msgid "[red] Cron tasks not running on %s" +msgstr "[red] Processi non avviati su %s" diff --git a/sources/view/it/passchanged_eml.tpl b/sources/view/it/passchanged_eml.tpl new file mode 100644 index 00000000..30d3159e --- /dev/null +++ b/sources/view/it/passchanged_eml.tpl @@ -0,0 +1,20 @@ + +Ciao {{$username}}, + Come richiesto, la tua password è stata cambiata. + Prendi nota di questo cambiamento oppure +sostituisci subito la password con quella che preferisci. + + +Questi sono i dati che ti serviranno a effettuare l'accesso: + +Sito: {{$siteurl}} +Nome utente: {{$email}} +Password: {{$new_password}} + +Ricorda che potrai cambiare la password dalla pagina delle 'Impostazioni' dopo aver effettuato l'accesso. + + +Saluti, + L'amministratore di {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/it/register_open_eml.tpl b/sources/view/it/register_open_eml.tpl new file mode 100644 index 00000000..f84dac4a --- /dev/null +++ b/sources/view/it/register_open_eml.tpl @@ -0,0 +1,19 @@ + +Sul sito {{$sitename}} è stato appena creato un account abbinato a questo indirizzo email. +Ecco i dati per effettuare l'accesso: + +Sito: {{$siteurl}} +Nome utente: {{$email}} +Password: (la password che hai scelto durante la registrazione) + +Se questo account non è stato creato da te e non desideri che continui a esistere, +allora accedi al sito e resetta la password. Facendo così avrai la possibilità +di rimuovere l'account dalla pagina delle 'Impostazioni'. +(Nel caso, ci scusiamo per l'inconveniente!!) + +Grazie e benvenuto su {{$sitename}}. + +Con affetto, + L'amministratore di {{$sitename}} + + \ No newline at end of file diff --git a/sources/view/it/register_verify_eml.tpl b/sources/view/it/register_verify_eml.tpl new file mode 100644 index 00000000..116f22e7 --- /dev/null +++ b/sources/view/it/register_verify_eml.tpl @@ -0,0 +1,24 @@ + +Su {{$sitename}} è appena arrivata una nuova richiesta di registrazione +che necessita della tua approvazione. + + +Questi sono i dati dell'account: + +Sito: {{$siteurl}} +Nome utente: {{$email}} +Indirizzo IP: {{$details}} + +Per approvare la richiesta devi cliccare su questo link: + + +{{$siteurl}}/regmod/allow/{{$hash}} + + +Per annullare la richiesta e rimuovere l'account, clicca qui: + + +{{$siteurl}}/regmod/deny/{{$hash}} + + +Grazie mille! diff --git a/sources/view/it/register_verify_member.tpl b/sources/view/it/register_verify_member.tpl new file mode 100644 index 00000000..6127e752 --- /dev/null +++ b/sources/view/it/register_verify_member.tpl @@ -0,0 +1,24 @@ + +Grazie per la tua registrazione su {{$sitename}}! + +Questi sono i dati per effettuare l'accesso: + +Sito: {{$siteurl}} +Nome utente: {{$email}} + +Dovrai inserire la password che hai scelto al momento della registrazione. + +Ricorda però che è necessario verificare l'indirizzo email perché tu possa avere l'accesso completo. + +Se l'account è stato creato da te, allora visita questo link di verifica: + +{{$siteurl}}/regver/allow/{{$hash}} + + +Se preferisci cancellare la richiesta e rimuovere l'account, allora clicca su quest'altro link: + + +{{$siteurl}}/regver/deny/{{$hash}} + + +Grazie. diff --git a/sources/view/it/strings.php b/sources/view/it/strings.php new file mode 100644 index 00000000..38b8c745 --- /dev/null +++ b/sources/view/it/strings.php @@ -0,0 +1,2118 @@ +strings["Cannot locate DNS info for database server '%s'"] = "Non trovo le informazioni DNS per il database server '%s'"; +$a->strings["Profile Photos"] = "Foto del profilo"; +$a->strings["The form security token was not correct. This probably happened because the form has been opened for too long (>3 hours) before submitting it."] = "I controlli di sicurezza sono falliti. Probabilmente è accaduto perché la pagina è stata tenuta aperta troppo a lungo (ore?) prima di inviare il contenuto."; +$a->strings["created a new post"] = "Ha creato un nuovo articolo"; +$a->strings["commented on %s's post"] = "ha commentato l'articolo di %s"; +$a->strings["A deleted group with this name was revived. Existing item permissions may apply to this group and any future members. If this is not what you intended, please create another group with a different name."] = "È stato ripristinato un insieme con lo stesso nome che era stato eliminato in precedenza. I permessi già presenti potrebbero rimanere validi per i nuovi canali. Se non vuoi che ciò accada, devi creare un altro insieme con un nome diverso."; +$a->strings["Default privacy group for new contacts"] = "Insieme predefinito per i canali che inizi a seguire"; +$a->strings["All Channels"] = "Tutti i canali"; +$a->strings["edit"] = "modifica"; +$a->strings["Collections"] = "Insiemi di canali"; +$a->strings["Edit collection"] = "Modifica l'insieme di canali"; +$a->strings["Add new collection"] = "Nuovo insieme"; +$a->strings["Channels not in any collection"] = "Canali che non sono in un insieme"; +$a->strings["add"] = "aggiungi"; +$a->strings["Not a valid email address"] = "Email non valida"; +$a->strings["Your email domain is not among those allowed on this site"] = "Il dominio della tua email attualmente non è permesso su questo sito"; +$a->strings["Your email address is already registered at this site."] = "La tua email è già registrata su questo sito."; +$a->strings["An invitation is required."] = "È necessario un invito."; +$a->strings["Invitation could not be verified."] = "L'invito non può essere verificato."; +$a->strings["Please enter the required information."] = "Inserisci le informazioni richieste."; +$a->strings["Failed to store account information."] = "Non è stato possibile salvare le informazioni del tuo account."; +$a->strings["Registration confirmation for %s"] = "Registrazione di %s confermata"; +$a->strings["Registration request at %s"] = "Richiesta di registrazione su %s"; +$a->strings["Administrator"] = "Amministratore"; +$a->strings["your registration password"] = "la password di registrazione"; +$a->strings["Registration details for %s"] = "Dettagli della registrazione di %s"; +$a->strings["Account approved."] = "Account approvato."; +$a->strings["Registration revoked for %s"] = "Registrazione revocata per %s"; +$a->strings["Account verified. Please login."] = "Registrazione verificata. Adesso puoi effettuare login."; +$a->strings["Click here to upgrade."] = "Clicca qui per aggiornare."; +$a->strings["This action exceeds the limits set by your subscription plan."] = "Questa operazione supera i limiti del tuo abbonamento."; +$a->strings["This action is not available under your subscription plan."] = "Questa operazione non è prevista dal tuo abbonamento."; +$a->strings["Miscellaneous"] = "Altro"; +$a->strings["YYYY-MM-DD or MM-DD"] = "AAAA-MM-GG oppure MM-GG"; +$a->strings["Required"] = "Obbligatorio"; +$a->strings["never"] = "mai"; +$a->strings["less than a second ago"] = "meno di un secondo fa"; +$a->strings["year"] = "anno"; +$a->strings["years"] = "anni"; +$a->strings["month"] = "mese"; +$a->strings["months"] = "mesi"; +$a->strings["week"] = "settimana"; +$a->strings["weeks"] = "settimane"; +$a->strings["day"] = "giorno"; +$a->strings["days"] = "giorni"; +$a->strings["hour"] = "ora"; +$a->strings["hours"] = "ore"; +$a->strings["minute"] = "minuto"; +$a->strings["minutes"] = "minuti"; +$a->strings["second"] = "secondo"; +$a->strings["seconds"] = "secondi"; +$a->strings["__ctx:e.g. 22 hours ago, 1 minute ago__ %1\$d %2\$s ago"] = "%1\$d %2\$s fa"; +$a->strings["%1\$s's birthday"] = "Compleanno di %1\$s"; +$a->strings["Happy Birthday %1\$s"] = "Buon compleanno %1\$s"; +$a->strings["New Page"] = "Nuova pagina web"; +$a->strings["Edit"] = "Modifica"; +$a->strings["View"] = "Guarda"; +$a->strings["Preview"] = "Anteprima"; +$a->strings["Actions"] = "Azioni"; +$a->strings["Page Link"] = "Link alla pagina"; +$a->strings["Title"] = "Titolo"; +$a->strings["Created"] = "Creato"; +$a->strings["Edited"] = "Modificato"; +$a->strings["Public Timeline"] = "Diario pubblico"; +$a->strings["Default"] = "Predefinito"; +$a->strings["Directory Options"] = "Opzioni elenco pubblico"; +$a->strings["Alphabetic"] = "Alfabetico"; +$a->strings["Reverse Alphabetic"] = "Alfabetico inverso"; +$a->strings["Newest to Oldest"] = "Prima i più recenti"; +$a->strings["Oldest to Newest"] = "Prima i più vecchi"; +$a->strings["Sort"] = "Ordinamento"; +$a->strings["Safe Mode"] = "Modalità SafeSearch"; +$a->strings["Public Forums Only"] = "Solo forum pubblici"; +$a->strings["This Website Only"] = "Solo in questo sito"; +$a->strings["l F d, Y \\@ g:i A"] = "l d F Y \\@ G:i"; +$a->strings["Starts:"] = "Inizio:"; +$a->strings["Finishes:"] = "Fine:"; +$a->strings["Location:"] = "Luogo:"; +$a->strings["This event has been added to your calendar."] = "Questo evento è stato aggiunto al tuo calendario"; +$a->strings["Delete this item?"] = "Eliminare questo elemento?"; +$a->strings["Comment"] = "Commento"; +$a->strings["[+] show all"] = "[+] mostra tutto"; +$a->strings["[-] show less"] = "[-] riduci"; +$a->strings["[+] expand"] = "[+] mostra tutto"; +$a->strings["[-] collapse"] = "[-] riduci"; +$a->strings["Password too short"] = "Password troppo corta"; +$a->strings["Passwords do not match"] = "Le password non corrispondono"; +$a->strings["everybody"] = "tutti"; +$a->strings["Secret Passphrase"] = "Chiave segreta"; +$a->strings["Passphrase hint"] = "Suggerimento per la chiave segreta"; +$a->strings["Notice: Permissions have changed but have not yet been submitted."] = "Nota: i permessi sono stati modificati ma non ancora salvati."; +$a->strings["close all"] = "chiudi tutto"; +$a->strings["Nothing new here"] = "Niente di nuovo qui"; +$a->strings["Rate This Channel (this is public)"] = "Valuta questo canale (visibile a tutti)"; +$a->strings["Rating"] = "Valutazioni"; +$a->strings["Describe (optional)"] = "Descrizione (facoltativa)"; +$a->strings["Submit"] = "Salva"; +$a->strings["Please enter a link URL"] = "Inserisci l'URL di un link"; +$a->strings["Unsaved changes. Are you sure you wish to leave this page?"] = "Non hai salvato i cambiamenti. Vuoi davvero lasciare questa pagina?"; +$a->strings["timeago.prefixAgo"] = "timeago.prefixAgo"; +$a->strings["timeago.prefixFromNow"] = "timeago.prefixFromNow"; +$a->strings["ago"] = "fa"; +$a->strings["from now"] = "da adesso"; +$a->strings["less than a minute"] = "meno di un minuto"; +$a->strings["about a minute"] = "circa un minuto"; +$a->strings["%d minutes"] = "%d minuti"; +$a->strings["about an hour"] = "circa un’ora"; +$a->strings["about %d hours"] = "circa %d ore"; +$a->strings["a day"] = "un giorno"; +$a->strings["%d days"] = "%d giorni"; +$a->strings["about a month"] = "circa un mese"; +$a->strings["%d months"] = "%d mesi"; +$a->strings["about a year"] = "circa un anno"; +$a->strings["%d years"] = "%d anni"; +$a->strings[" "] = " "; +$a->strings["timeago.numbers"] = "timeago.numbers"; +$a->strings["parent"] = "cartella superiore"; +$a->strings["Collection"] = "Cartella"; +$a->strings["Principal"] = "Principale"; +$a->strings["Addressbook"] = "Rubrica"; +$a->strings["Calendar"] = "Calendario"; +$a->strings["Schedule Inbox"] = "Appuntamenti ricevuti"; +$a->strings["Schedule Outbox"] = "Appuntamenti inviati"; +$a->strings["Unknown"] = "Sconosciuto"; +$a->strings["%1\$s used"] = "%1\$s occupati"; +$a->strings["%1\$s used of %2\$s (%3\$s%)"] = "%1\$s occupati di %2\$s (%3\$s%)"; +$a->strings["Files"] = "Archivio file"; +$a->strings["Total"] = "Totale"; +$a->strings["Shared"] = "Condiviso"; +$a->strings["Create"] = "Crea"; +$a->strings["Upload"] = "Carica"; +$a->strings["Name"] = "Nome"; +$a->strings["Type"] = "Tipo"; +$a->strings["Size"] = "Dimensione"; +$a->strings["Last Modified"] = "Ultima modifica"; +$a->strings["Delete"] = "Elimina"; +$a->strings["Create new folder"] = "Crea una nuova cartella"; +$a->strings["Upload file"] = "Carica un file"; +$a->strings["%1\$s's bookmarks"] = "I segnalibri di %1\$s"; +$a->strings["view full size"] = "guarda nelle dimensioni reali"; +$a->strings["General Features"] = "Funzionalità di base"; +$a->strings["Content Expiration"] = "Scadenza"; +$a->strings["Remove posts/comments and/or private messages at a future time"] = "Elimina gli articoli, i commenti o i messaggi privati dopo un lasso di tempo"; +$a->strings["Multiple Profiles"] = "Profili multipli"; +$a->strings["Ability to create multiple profiles"] = "Abilitazione a creare profili multipli"; +$a->strings["Advanced Profiles"] = "Profili avanzati"; +$a->strings["Additional profile sections and selections"] = "Informazioni aggiuntive del profilo"; +$a->strings["Profile Import/Export"] = "Importa/esporta il profilo"; +$a->strings["Save and load profile details across sites/channels"] = "Salva o ripristina le informazioni del profilo su canali o siti diversi"; +$a->strings["Web Pages"] = "Pagine web"; +$a->strings["Provide managed web pages on your channel"] = "Attiva la creazione di pagine web sul tuo canale"; +$a->strings["Private Notes"] = "Note private"; +$a->strings["Enables a tool to store notes and reminders"] = "Abilita il riquadro per scrivere annotazioni"; +$a->strings["Navigation Channel Select"] = "Scegli il canale attivo dal menu"; +$a->strings["Change channels directly from within the navigation dropdown menu"] = "Scegli il canale attivo direttamente dal menu di navigazione"; +$a->strings["Photo Location"] = "Posizione geografica"; +$a->strings["If location data is available on uploaded photos, link this to a map."] = "Collega la foto a una mappa quando contiene indicazioni geografiche."; +$a->strings["Expert Mode"] = "Modalità esperto"; +$a->strings["Enable Expert Mode to provide advanced configuration options"] = "Abilita la modalità esperto per vedere le opzioni di configurazione avanzate"; +$a->strings["Premium Channel"] = "Canale premium"; +$a->strings["Allows you to set restrictions and terms on those that connect with your channel"] = "Ti permette di impostare delle restrizioni e dei termini d'uso a chi segue il canale"; +$a->strings["Post Composition Features"] = "Modalità di scrittura articoli"; +$a->strings["Use Markdown"] = "Usa il markdown"; +$a->strings["Allow use of \"Markdown\" to format posts"] = "Consenti l'uso del markdown per formattare gli articoli"; +$a->strings["Large Photos"] = "Foto grandi"; +$a->strings["Include large (640px) photo thumbnails in posts. If not enabled, use small (320px) photo thumbnails"] = "Includi anteprime grandi delle foto nei post (640px). Se disabilitato le anteprime saranno piccole (320px)"; +$a->strings["Channel Sources"] = "Sorgenti del canale"; +$a->strings["Automatically import channel content from other channels or feeds"] = "Importa automaticamente il contenuto del canale da altri canali o feed"; +$a->strings["Even More Encryption"] = "Crittografia addizionale"; +$a->strings["Allow optional encryption of content end-to-end with a shared secret key"] = "Rendi possibile la crittografia tra mittente e destinatario che condividono una chiave segreta"; +$a->strings["Enable voting tools"] = "Permetti i post con votazione"; +$a->strings["Provide a class of post which others can vote on"] = "Rende possibile la creazione di articoli in cui sarà possibile votare"; +$a->strings["Network and Stream Filtering"] = "Filtraggio dei contenuti"; +$a->strings["Search by Date"] = "Ricerca per data"; +$a->strings["Ability to select posts by date ranges"] = "Per selezionare gli articoli in un intervallo tra date"; +$a->strings["Collections Filter"] = "Filtra per insiemi di canali"; +$a->strings["Enable widget to display Network posts only from selected collections"] = "Mostra il riquadro per filtrare gli articoli di certi insiemi di canali"; +$a->strings["Saved Searches"] = "Ricerche salvate"; +$a->strings["Save search terms for re-use"] = "Salva i termini delle ricerche per poterle ripetere"; +$a->strings["Network Personal Tab"] = "Attività personale"; +$a->strings["Enable tab to display only Network posts that you've interacted on"] = "Abilita il link per mostrare solamente i contenuti con cui hai interagito"; +$a->strings["Network New Tab"] = "Contenuti nuovi"; +$a->strings["Enable tab to display all new Network activity"] = "Abilita il link per visualizzare solo i nuovi contenuti"; +$a->strings["Affinity Tool"] = "Filtro per affinità"; +$a->strings["Filter stream activity by depth of relationships"] = "Permette di selezionare i contenuti in base al livello di amicizia"; +$a->strings["Suggest Channels"] = "Suggerisci canali"; +$a->strings["Show channel suggestions"] = "Mostra alcuni canali che potrebbero interessarti"; +$a->strings["Post/Comment Tools"] = "Gestione articoli e commenti"; +$a->strings["Tagging"] = "Tag"; +$a->strings["Ability to tag existing posts"] = "Permetti l'aggiunta di tag su articoli già esistenti"; +$a->strings["Post Categories"] = "Categorie degli articoli"; +$a->strings["Add categories to your posts"] = "Abilita le categorie per i tuoi articoli"; +$a->strings["Saved Folders"] = "Cartelle salvate"; +$a->strings["Ability to file posts under folders"] = "Abilita la raccolta dei tuoi articoli in cartelle"; +$a->strings["Dislike Posts"] = "Non mi piace"; +$a->strings["Ability to dislike posts/comments"] = "Abilità la funzionalità \"non mi piace\" per i tuoi articoli"; +$a->strings["Star Posts"] = "Articoli stella (preferiti)"; +$a->strings["Ability to mark special posts with a star indicator"] = "Mostra la stella per scegliere gli articoli preferiti"; +$a->strings["Tag Cloud"] = "Nuvola di tag"; +$a->strings["Provide a personal tag cloud on your channel page"] = "Mostra la nuvola dei tag che usi di più sulla pagina del tuo canale"; +$a->strings["Categories"] = "Categorie"; +$a->strings["Apps"] = "Apps"; +$a->strings["System"] = "Sistema"; +$a->strings["Personal"] = "Personali"; +$a->strings["Create Personal App"] = "Crea una app personale"; +$a->strings["Edit Personal App"] = "Modifica una app personale"; +$a->strings["Connect"] = "Aggiungi"; +$a->strings["Ignore/Hide"] = "Ignora/nascondi"; +$a->strings["Suggestions"] = "Suggerimenti"; +$a->strings["See more..."] = "Altro..."; +$a->strings["You have %1$.0f of %2$.0f allowed connections."] = "Hai attivato %1$.0f delle %2$.0f connessioni permesse."; +$a->strings["Add New Connection"] = "Aggiungi un contatto"; +$a->strings["Enter the channel address"] = "Scrivi l'indirizzo del canale"; +$a->strings["Example: bob@example.com, http://example.com/barbara"] = "Per esempio: mario@pippo.it oppure http://pluto.com/barbara"; +$a->strings["Notes"] = "Note"; +$a->strings["Save"] = "Salva"; +$a->strings["Remove term"] = "Rimuovi termine"; +$a->strings["Everything"] = "Tutto"; +$a->strings["Archives"] = "Archivi"; +$a->strings["Me"] = "Io"; +$a->strings["Family"] = "Famiglia"; +$a->strings["Friends"] = "Amici"; +$a->strings["Acquaintances"] = "Conoscenti"; +$a->strings["All"] = "Tutti"; +$a->strings["Refresh"] = "Aggiorna"; +$a->strings["Account settings"] = "Il tuo account"; +$a->strings["Channel settings"] = "Impostazioni del canale"; +$a->strings["Additional features"] = "Funzionalità opzionali"; +$a->strings["Feature/Addon settings"] = "Impostazioni dei componenti aggiuntivi"; +$a->strings["Display settings"] = "Aspetto"; +$a->strings["Connected apps"] = "App connesse"; +$a->strings["Export channel"] = "Esporta il canale"; +$a->strings["Connection Default Permissions"] = "Permessi predefiniti dei nuovi contatti"; +$a->strings["Premium Channel Settings"] = "Canale premium - impostazioni"; +$a->strings["Settings"] = "Impostazioni"; +$a->strings["Messages"] = "Messaggi"; +$a->strings["Check Mail"] = "Controlla i messaggi"; +$a->strings["New Message"] = "Nuovo messaggio"; +$a->strings["Chat Rooms"] = "Aree chat attive"; +$a->strings["Bookmarked Chatrooms"] = "Aree chat nei segnalibri"; +$a->strings["Suggested Chatrooms"] = "Aree chat suggerite"; +$a->strings["photo/image"] = "foto/immagine"; +$a->strings["Rate Me"] = "Valutami"; +$a->strings["View Ratings"] = "Vedi le valutazioni ricevute"; +$a->strings["Public Hubs"] = "Hub pubblici"; +$a->strings["Hubzilla Notification"] = "Notifica di Hubzilla"; +$a->strings["hubzilla"] = "Hubzilla"; +$a->strings["Thank You,"] = "Grazie,"; +$a->strings["%s Administrator"] = "L'amministratore di %s"; +$a->strings["%s "] = "%s "; +$a->strings["[Red:Notify] New mail received at %s"] = "[Hubzilla] Nuovo messaggio su %s"; +$a->strings["%1\$s, %2\$s sent you a new private message at %3\$s."] = "%1\$s, %2\$s ti ha mandato un messaggio privato su %3\$s."; +$a->strings["%1\$s sent you %2\$s."] = "%1\$s ti ha mandato %2\$s."; +$a->strings["a private message"] = "un messaggio privato"; +$a->strings["Please visit %s to view and/or reply to your private messages."] = "Visita %s per leggere i tuoi messaggi privati e rispondere."; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]a %4\$s[/zrl]"] = "%1\$s, %2\$s ha commentato [zrl=%3\$s]%4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]%4\$s's %5\$s[/zrl]"] = "%1\$s, %2\$s ha commentato [zrl=%3\$s]%5\$s di %4\$s[/zrl]"; +$a->strings["%1\$s, %2\$s commented on [zrl=%3\$s]your %4\$s[/zrl]"] = "%1\$s, %2\$s ha commentato [zrl=%3\$s]%4\$s che hai creato[/zrl]"; +$a->strings["[Red:Notify] Comment to conversation #%1\$d by %2\$s"] = "[Hubzilla] Nuovo commento di %2\$s alla conversazione #%1\$d"; +$a->strings["%1\$s, %2\$s commented on an item/conversation you have been following."] = "%1\$s, %2\$s ha commentato un elemento che stavi seguendo."; +$a->strings["Please visit %s to view and/or reply to the conversation."] = "Visita %s per leggere o commentare la conversazione."; +$a->strings["[Red:Notify] %s posted to your profile wall"] = "[Hubzilla] %s ha scritto sulla tua bacheca"; +$a->strings["%1\$s, %2\$s posted to your profile wall at %3\$s"] = "%1\$s, %2\$s ha scritto sulla bacheca del tuo profilo su %3\$s"; +$a->strings["%1\$s, %2\$s posted to [zrl=%3\$s]your wall[/zrl]"] = "%1\$s, %2\$s ha scritto sulla [zrl=%3\$s]tua bacheca[/zrl]"; +$a->strings["[Red:Notify] %s tagged you"] = "[Hubzilla] %s ti ha taggato"; +$a->strings["%1\$s, %2\$s tagged you at %3\$s"] = "%1\$s, %2\$s ti ha taggato su %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%3\$s]tagged you[/zrl]."] = "%1\$s, %2\$s [zrl=%3\$s]ti ha taggato[/zrl]."; +$a->strings["[Red:Notify] %1\$s poked you"] = "[Hubzilla] %1\$s ti ha mandato un poke"; +$a->strings["%1\$s, %2\$s poked you at %3\$s"] = "%1\$s, %2\$s ti ha mandato un poke su %3\$s"; +$a->strings["%1\$s, %2\$s [zrl=%2\$s]poked you[/zrl]."] = "%1\$s, %2\$s [zrl=%2\$s]ti ha mandato un poke[/zrl]."; +$a->strings["[Red:Notify] %s tagged your post"] = "[Hubzilla] %s ha taggato il tuo articolo"; +$a->strings["%1\$s, %2\$s tagged your post at %3\$s"] = "%1\$s, %2\$s ha taggato il tuo articolo su %3\$s"; +$a->strings["%1\$s, %2\$s tagged [zrl=%3\$s]your post[/zrl]"] = "%1\$s, %2\$s ha taggato [zrl=%3\$s]il tuo articolo[/zrl]"; +$a->strings["[Red:Notify] Introduction received"] = "[Hubzilla] Hai una richiesta di amicizia"; +$a->strings["%1\$s, you've received an new connection request from '%2\$s' at %3\$s"] = "%1\$s, hai ricevuto una richiesta di entrare in contatto da '%2\$s' su %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a new connection request[/zrl] from %3\$s."] = "%1\$s, hai ricevuto una [zrl=%2\$s]richiesta di entrare in contatto[/zrl] da %3\$s."; +$a->strings["You may visit their profile at %s"] = "Puoi visitare il suo profilo su %s"; +$a->strings["Please visit %s to approve or reject the connection request."] = "Visita %s per approvare o rifiutare la richiesta di entrare in contatto."; +$a->strings["[Red:Notify] Friend suggestion received"] = "[Hubzilla] Ti è stato suggerito un amico"; +$a->strings["%1\$s, you've received a friend suggestion from '%2\$s' at %3\$s"] = "%1\$s, ti è stato suggerito un amico da '%2\$s' su %3\$s"; +$a->strings["%1\$s, you've received [zrl=%2\$s]a friend suggestion[/zrl] for %3\$s from %4\$s."] = "%1\$s, %4\$s ti [zrl=%2\$s]ha suggerito %3\$s[/zrl] come amico."; +$a->strings["Name:"] = "Nome:"; +$a->strings["Photo:"] = "Foto:"; +$a->strings["Please visit %s to approve or reject the suggestion."] = "Visita %s per approvare o rifiutare il suggerimento."; +$a->strings["[Red:Notify]"] = "[Hubzilla]"; +$a->strings["Frequently"] = "Frequentemente"; +$a->strings["Hourly"] = "Ogni ora"; +$a->strings["Twice daily"] = "Due volte al giorno"; +$a->strings["Daily"] = "Ogni giorno"; +$a->strings["Weekly"] = "Ogni settimana"; +$a->strings["Monthly"] = "Ogni mese"; +$a->strings["Friendica"] = "Friendica"; +$a->strings["OStatus"] = "OStatus"; +$a->strings["RSS/Atom"] = "RSS/Atom"; +$a->strings["Email"] = "Email"; +$a->strings["Diaspora"] = "Diaspora"; +$a->strings["Facebook"] = "Facebook"; +$a->strings["Zot!"] = "Zot!"; +$a->strings["LinkedIn"] = "LinkedIn"; +$a->strings["XMPP/IM"] = "XMPP/IM"; +$a->strings["MySpace"] = "MySpace"; +$a->strings["No recipient provided."] = "Devi scegliere un destinatario."; +$a->strings["[no subject]"] = "[nessun titolo]"; +$a->strings["Unable to determine sender."] = "Impossibile determinare il mittente."; +$a->strings["Stored post could not be verified."] = "Non è stato possibile verificare l'articolo inserito."; +$a->strings["Channel is blocked on this site."] = "Il canale è bloccato per questo sito."; +$a->strings["Channel location missing."] = "Manca l'indirizzo del canale."; +$a->strings["Response from remote channel was incomplete."] = "La risposta dal canale non è completa."; +$a->strings["Channel was deleted and no longer exists."] = "Il canale è stato rimosso e non esiste più."; +$a->strings["Protocol disabled."] = "Protocollo disabilitato."; +$a->strings["Channel discovery failed."] = "La ricerca del canale non ha avuto successo."; +$a->strings["local account not found."] = "l'account locale non è stato trovato."; +$a->strings["Cannot connect to yourself."] = "Non puoi connetterti a te stesso."; +$a->strings["Private Message"] = "Messaggio privato"; +$a->strings["Select"] = "Seleziona"; +$a->strings["Save to Folder"] = "Salva nella cartella"; +$a->strings["I will attend"] = "Parteciperò"; +$a->strings["I will not attend"] = "Non parteciperò"; +$a->strings["I might attend"] = "Forse parteciperò"; +$a->strings["I agree"] = "Sono d'accordo"; +$a->strings["I disagree"] = "Non sono d'accordo"; +$a->strings["I abstain"] = "Mi astengo"; +$a->strings["View all"] = "Vedi tutto"; +$a->strings["__ctx:noun__ Like"] = array( + 0 => "Mi piace", + 1 => "Mi piace", +); +$a->strings["__ctx:noun__ Dislike"] = array( + 0 => "Non mi piace", + 1 => "Non mi piace", +); +$a->strings["Add Star"] = "Aggiungi ai preferiti"; +$a->strings["Remove Star"] = "Rimuovi dai preferiti"; +$a->strings["Toggle Star Status"] = "Attiva/disattiva preferito"; +$a->strings["starred"] = "preferito"; +$a->strings["Message signature validated"] = "Messaggio con firma verificata"; +$a->strings["Message signature incorrect"] = "Massaggio con firma non corretta"; +$a->strings["Add Tag"] = "Aggiungi un tag"; +$a->strings["I like this (toggle)"] = "Attiva/disattiva Mi piace"; +$a->strings["like"] = "mi piace"; +$a->strings["I don't like this (toggle)"] = "Attiva/disattiva Non mi piace"; +$a->strings["dislike"] = "non mi piace"; +$a->strings["Share This"] = "Condividi"; +$a->strings["share"] = "condividi"; +$a->strings["%d comment"] = array( + 0 => "%d commento", + 1 => "%d commenti", +); +$a->strings["View %s's profile - %s"] = "Guarda il profilo di %s - %s"; +$a->strings["to"] = "a"; +$a->strings["via"] = "via"; +$a->strings["Wall-to-Wall"] = "Da bacheca a bacheca"; +$a->strings["via Wall-To-Wall:"] = "da bacheca a bacheca:"; +$a->strings["from %s"] = "da %s"; +$a->strings["last edited: %s"] = "ultima modifica: %s"; +$a->strings["Expires: %s"] = "Scadenza: %s"; +$a->strings["Save Bookmarks"] = "Salva segnalibro"; +$a->strings["Add to Calendar"] = "Aggiungi al calendario"; +$a->strings["Mark all seen"] = "Marca tutto come letto"; +$a->strings["__ctx:noun__ Likes"] = "Mi piace"; +$a->strings["__ctx:noun__ Dislikes"] = "Non mi piace"; +$a->strings["Close"] = "Chiudi"; +$a->strings["Please wait"] = "Attendere"; +$a->strings["This is you"] = "Questo sei tu"; +$a->strings["Bold"] = "Grassetto"; +$a->strings["Italic"] = "Corsivo"; +$a->strings["Underline"] = "Sottolineato"; +$a->strings["Quote"] = "Citazione"; +$a->strings["Code"] = "Codice"; +$a->strings["Image"] = "Immagine"; +$a->strings["Insert Link"] = "Collegamento"; +$a->strings["Video"] = "Video"; +$a->strings["Encrypt text"] = "Crittografia del testo"; +$a->strings["New window"] = "Nuova finestra"; +$a->strings["Open the selected location in a different window or browser tab"] = "Apri l'indirizzo selezionato in una nuova scheda o finestra"; +$a->strings["User '%s' deleted"] = "Utente '%s' eliminato"; +$a->strings["Attachments:"] = "Allegati:"; +$a->strings["Hubzilla event notification:"] = "Notifica eventi Hubzilla:"; +$a->strings["prev"] = "prec"; +$a->strings["first"] = "inizio"; +$a->strings["last"] = "fine"; +$a->strings["next"] = "succ"; +$a->strings["older"] = "più recenti"; +$a->strings["newer"] = "più nuovi"; +$a->strings["No connections"] = "Nessun contatto"; +$a->strings["%d Connection"] = array( + 0 => "%d contatto", + 1 => "%d contatti", +); +$a->strings["View Connections"] = "Elenco contatti"; +$a->strings["Search"] = "Cerca"; +$a->strings["poke"] = "poke"; +$a->strings["poked"] = "ha ricevuto un poke"; +$a->strings["ping"] = "ping"; +$a->strings["pinged"] = "ha ricevuto un ping"; +$a->strings["prod"] = "spintone"; +$a->strings["prodded"] = "ha ricevuto uno spintone"; +$a->strings["slap"] = "schiaffo"; +$a->strings["slapped"] = "ha ricevuto uno schiaffo"; +$a->strings["finger"] = "finger"; +$a->strings["fingered"] = "ha ricevuto un finger"; +$a->strings["rebuff"] = "rifiuto"; +$a->strings["rebuffed"] = "ha ricevuto un rifiuto"; +$a->strings["happy"] = "felice"; +$a->strings["sad"] = "triste"; +$a->strings["mellow"] = "calmo"; +$a->strings["tired"] = "stanco"; +$a->strings["perky"] = "vivace"; +$a->strings["angry"] = "arrabbiato"; +$a->strings["stupified"] = "stordito"; +$a->strings["puzzled"] = "confuso"; +$a->strings["interested"] = "attento"; +$a->strings["bitter"] = "amaro"; +$a->strings["cheerful"] = "allegro"; +$a->strings["alive"] = "vivace"; +$a->strings["annoyed"] = "seccato"; +$a->strings["anxious"] = "ansioso"; +$a->strings["cranky"] = "irritabile"; +$a->strings["disturbed"] = "turbato"; +$a->strings["frustrated"] = "frustrato"; +$a->strings["depressed"] = "in depressione"; +$a->strings["motivated"] = "motivato"; +$a->strings["relaxed"] = "rilassato"; +$a->strings["surprised"] = "sorpreso"; +$a->strings["Monday"] = "lunedì"; +$a->strings["Tuesday"] = "martedì"; +$a->strings["Wednesday"] = "mercoledì"; +$a->strings["Thursday"] = "giovedì"; +$a->strings["Friday"] = "venerdì"; +$a->strings["Saturday"] = "sabato"; +$a->strings["Sunday"] = "domenica"; +$a->strings["January"] = "gennaio"; +$a->strings["February"] = "febbraio"; +$a->strings["March"] = "marzo"; +$a->strings["April"] = "aprile"; +$a->strings["May"] = "maggio"; +$a->strings["June"] = "giugno"; +$a->strings["July"] = "luglio"; +$a->strings["August"] = "agosto"; +$a->strings["September"] = "settembre"; +$a->strings["October"] = "ottobre"; +$a->strings["November"] = "novembre"; +$a->strings["December"] = "dicembre"; +$a->strings["unknown.???"] = "sconosciuto???"; +$a->strings["bytes"] = "byte"; +$a->strings["remove category"] = "rimuovi la categoria"; +$a->strings["remove from file"] = "rimuovi dal file"; +$a->strings["Click to open/close"] = "Clicca per aprire/chiudere"; +$a->strings["Link to Source"] = "Link al sito d'origine"; +$a->strings["default"] = "predefinito"; +$a->strings["Page layout"] = "Layout della pagina"; +$a->strings["You can create your own with the layouts tool"] = "Con gli strumenti di design puoi creare il tuo"; +$a->strings["Page content type"] = "Tipo di contenuto della pagina"; +$a->strings["Select an alternate language"] = "Seleziona una lingua diversa"; +$a->strings["photo"] = "la foto"; +$a->strings["event"] = "l'evento"; +$a->strings["status"] = "il messaggio di stato"; +$a->strings["comment"] = "il commento"; +$a->strings["activity"] = "l'attività"; +$a->strings["Design Tools"] = "Strumenti di design"; +$a->strings["Blocks"] = "Riquadri"; +$a->strings["Menus"] = "Menù"; +$a->strings["Layouts"] = "Layout"; +$a->strings["Pages"] = "Pagine"; +$a->strings["Logout"] = "Esci"; +$a->strings["End this session"] = "Chiudi questa sessione"; +$a->strings["Home"] = "Bacheca"; +$a->strings["Your posts and conversations"] = "I tuoi articoli e conversazioni"; +$a->strings["View Profile"] = "Profilo"; +$a->strings["Your profile page"] = "Il tuo profilo"; +$a->strings["Edit Profiles"] = "Modifica i profili"; +$a->strings["Manage/Edit profiles"] = "Gestisci/modifica i profili"; +$a->strings["Edit Profile"] = "Modifica il profilo"; +$a->strings["Edit your profile"] = "Modifica il profilo"; +$a->strings["Photos"] = "Foto"; +$a->strings["Your photos"] = "Le tue foto"; +$a->strings["Your files"] = "I tuoi file"; +$a->strings["Chat"] = "Area chat"; +$a->strings["Your chatrooms"] = "Le tue aree chat"; +$a->strings["Bookmarks"] = "Segnalibri"; +$a->strings["Your bookmarks"] = "I tuoi segnalibri"; +$a->strings["Webpages"] = "Pagine web"; +$a->strings["Your webpages"] = "Le tue pagine web"; +$a->strings["Login"] = "Accedi"; +$a->strings["Sign in"] = "Accedi"; +$a->strings["%s - click to logout"] = "%s - clicca per uscire"; +$a->strings["Remote authentication"] = "Autenticazione magica dal tuo server"; +$a->strings["Click to authenticate to your home hub"] = "Clicca per autenticarti sul tuo server principale"; +$a->strings["Home Page"] = "Bacheca"; +$a->strings["Register"] = "Iscriviti"; +$a->strings["Create an account"] = "Crea un account"; +$a->strings["Help"] = "Guida"; +$a->strings["Help and documentation"] = "Guida e documentazione"; +$a->strings["Applications, utilities, links, games"] = "Applicazioni, utilità, link, giochi"; +$a->strings["Search site content"] = "Cerca nel sito"; +$a->strings["Directory"] = "Elenco pubblico"; +$a->strings["Channel Directory"] = "Elenco pubblico canali"; +$a->strings["Matrix"] = "Hubzilla"; +$a->strings["Your matrix"] = "La tua rete"; +$a->strings["Mark all matrix notifications seen"] = "Segna come lette le notifiche della tua rete"; +$a->strings["Channel Home"] = "Bacheca del canale"; +$a->strings["Channel home"] = "Bacheca del canale"; +$a->strings["Mark all channel notifications seen"] = "Segna come lette le notifiche del canale"; +$a->strings["Connections"] = "Contatti"; +$a->strings["Notices"] = "Avvisi"; +$a->strings["Notifications"] = "Notifiche"; +$a->strings["See all notifications"] = "Vedi tutte le notifiche"; +$a->strings["Mark all system notifications seen"] = "Segna come lette le notifiche di sistema"; +$a->strings["Mail"] = "Messaggi"; +$a->strings["Private mail"] = "Messaggi privati"; +$a->strings["See all private messages"] = "Guarda tutti i messaggi privati"; +$a->strings["Mark all private messages seen"] = "Segna come letti tutti i messaggi privati"; +$a->strings["Inbox"] = "In arrivo"; +$a->strings["Outbox"] = "Inviati"; +$a->strings["Events"] = "Eventi"; +$a->strings["Event Calendar"] = "Calendario"; +$a->strings["See all events"] = "Guarda tutti gli eventi"; +$a->strings["Mark all events seen"] = "Marca come letti tutti gli eventi"; +$a->strings["Channel Manager"] = "Gestione canali"; +$a->strings["Manage Your Channels"] = "Gestisci i tuoi canali"; +$a->strings["Account/Channel Settings"] = "Impostazioni dell'account e del canale"; +$a->strings["Admin"] = "Amministrazione"; +$a->strings["Site Setup and Configuration"] = "Installazione e configurazione del sito"; +$a->strings["Loading..."] = "Caricamento in corso..."; +$a->strings["@name, #tag, content"] = "@nome, #tag, testo"; +$a->strings["Please wait..."] = "Attendere..."; +$a->strings["Tags"] = "Tag"; +$a->strings["Keywords"] = "Parole chiave"; +$a->strings["have"] = "ho"; +$a->strings["has"] = "ha"; +$a->strings["want"] = "voglio"; +$a->strings["wants"] = "vuole"; +$a->strings["likes"] = "gli piace"; +$a->strings["dislikes"] = "non gli piace"; +$a->strings[" and "] = "e"; +$a->strings["public profile"] = "profilo pubblico"; +$a->strings["%1\$s changed %2\$s to “%3\$s”"] = "%1\$s ha cambiato %2\$s in “%3\$s”"; +$a->strings["Visit %1\$s's %2\$s"] = "Guarda %2\$s di %1\$s "; +$a->strings["%1\$s has an updated %2\$s, changing %3\$s."] = "%1\$s ha aggiornato %2\$s cambiando %3\$s."; +$a->strings["Image/photo"] = "Immagine"; +$a->strings["Encrypted content"] = "Contenuto crittografato"; +$a->strings["Install design element: "] = "Installa il componente di design:"; +$a->strings["QR code"] = "QR code"; +$a->strings["%1\$s wrote the following %2\$s %3\$s"] = "%1\$s ha scritto %2\$s %3\$s"; +$a->strings["post"] = "l'articolo"; +$a->strings["Different viewers will see this text differently"] = "Ad altri questo testo potrebbe apparire in modo differente"; +$a->strings["$1 spoiler"] = "$1 spoiler"; +$a->strings["$1 wrote:"] = "$1 ha scritto:"; +$a->strings["Permission denied"] = "Permesso negato"; +$a->strings["(Unknown)"] = "(Sconosciuto)"; +$a->strings["Visible to anybody on the internet."] = "Visibile a chiunque su internet."; +$a->strings["Visible to you only."] = "Visibile solo a te."; +$a->strings["Visible to anybody in this network."] = "Visibile a tutti su questa rete."; +$a->strings["Visible to anybody authenticated."] = "Visibile a chiunque sia autenticato."; +$a->strings["Visible to anybody on %s."] = "Visibile a tutti in %s."; +$a->strings["Visible to all connections."] = "Visibile a tutti coloro che ti seguono."; +$a->strings["Visible to approved connections."] = "Visibile ai contatti approvati."; +$a->strings["Visible to specific connections."] = "Visibile ad alcuni contatti scelti."; +$a->strings["Item not found."] = "Elemento non trovato."; +$a->strings["Permission denied."] = "Permesso negato."; +$a->strings["Collection not found."] = "Insieme di canali non trovato."; +$a->strings["Collection is empty."] = "L'insieme di canali è vuoto."; +$a->strings["Collection: %s"] = "Insieme: %s"; +$a->strings["Connection: %s"] = "Contatto: %s"; +$a->strings["Connection not found."] = "Contatto non trovato."; +$a->strings["Can view my normal stream and posts"] = "Può vedere i miei contenuti e articoli normali"; +$a->strings["Can view my default channel profile"] = "Può vedere il profilo predefinito del canale"; +$a->strings["Can view my photo albums"] = "Può vedere i miei album fotografici"; +$a->strings["Can view my connections"] = "Può vedere i miei contatti"; +$a->strings["Can view my file storage"] = "Può vedere i miei file condivisi"; +$a->strings["Can view my webpages"] = "Può vedere le mie pagine web"; +$a->strings["Can send me their channel stream and posts"] = "È tra i canali che seguo"; +$a->strings["Can post on my channel page (\"wall\")"] = "Può scrivere sulla bacheca del mio canale"; +$a->strings["Can comment on or like my posts"] = "Può commentare o aggiungere \"mi piace\" ai miei articoli"; +$a->strings["Can send me private mail messages"] = "Può inviarmi messaggi privati"; +$a->strings["Can post photos to my photo albums"] = "Può aggiungere foto ai miei album"; +$a->strings["Can like/dislike stuff"] = "Può aggiungere \"mi piace\""; +$a->strings["Profiles and things other than posts/comments"] = "Profili e tutto ciò che non è articoli e commenti"; +$a->strings["Can forward to all my channel contacts via post @mentions"] = "Può inoltrare articoli a tutti i contatti del canale tramite una @menzione"; +$a->strings["Advanced - useful for creating group forum channels"] = "Impostazione avanzata - utile per creare un canale-forum di discussione"; +$a->strings["Can chat with me (when available)"] = "Può aprire una chat con me (se disponibile)"; +$a->strings["Can write to my file storage"] = "Può scrivere sul mio archivio file"; +$a->strings["Can edit my webpages"] = "Può modificare le mie pagine web"; +$a->strings["Can source my public posts in derived channels"] = "Può usare i miei articoli pubblici per creare canali derivati"; +$a->strings["Somewhat advanced - very useful in open communities"] = "Piuttosto avanzato - molto utile nelle comunità aperte"; +$a->strings["Can administer my channel resources"] = "Può amministrare i contenuti del mio canale"; +$a->strings["Extremely advanced. Leave this alone unless you know what you are doing"] = "Impostazione pericolosa - lasciare il valore predefinito se non si è assolutamente sicuri"; +$a->strings["Social Networking"] = "Social network"; +$a->strings["Mostly Public"] = "Prevalentemente pubblico"; +$a->strings["Restricted"] = "Con restrizioni"; +$a->strings["Private"] = "Privato"; +$a->strings["Community Forum"] = "Forum di discussione"; +$a->strings["Feed Republish"] = "Aggregatore di feed esterni"; +$a->strings["Special Purpose"] = "Per finalità speciali"; +$a->strings["Celebrity/Soapbox"] = "Pagina per fan"; +$a->strings["Group Repository"] = "Repository di gruppo"; +$a->strings["Other"] = "Altro"; +$a->strings["Custom/Expert Mode"] = "Personalizzazione per esperti"; +$a->strings["channel"] = "canale"; +$a->strings["%1\$s likes %2\$s's %3\$s"] = "A %1\$s piace %3\$s di %2\$s"; +$a->strings["%1\$s doesn't like %2\$s's %3\$s"] = "A %1\$s non piace %3\$s di %2\$s"; +$a->strings["%1\$s is now connected with %2\$s"] = "%1\$s adesso è connesso con %2\$s"; +$a->strings["%1\$s poked %2\$s"] = "%1\$s ha mandato un poke a %2\$s"; +$a->strings["__ctx:mood__ %1\$s is %2\$s"] = "%1\$s è %2\$s"; +$a->strings["__ctx:title__ Likes"] = "Mi piace"; +$a->strings["__ctx:title__ Dislikes"] = "Non mi piace"; +$a->strings["__ctx:title__ Agree"] = "D'accordo"; +$a->strings["__ctx:title__ Disagree"] = "Non d'accordo"; +$a->strings["__ctx:title__ Abstain"] = "Astenuti"; +$a->strings["__ctx:title__ Attending"] = "Partecipano"; +$a->strings["__ctx:title__ Not attending"] = "Non partecipano"; +$a->strings["__ctx:title__ Might attend"] = "Forse partecipano"; +$a->strings["View %s's profile @ %s"] = "Vedi il profilo di %s @ %s"; +$a->strings["Categories:"] = "Categorie:"; +$a->strings["Filed under:"] = "Classificato come:"; +$a->strings["View in context"] = "Vedi nel contesto"; +$a->strings["remove"] = "rimuovi"; +$a->strings["Delete Selected Items"] = "Elimina gli oggetti selezionati"; +$a->strings["View Source"] = "Vedi il sorgente"; +$a->strings["Follow Thread"] = "Segui la discussione"; +$a->strings["View Status"] = "Guarda il messaggio di stato"; +$a->strings["View Photos"] = "Guarda le foto"; +$a->strings["Matrix Activity"] = "Attività nella tua rete"; +$a->strings["Edit Contact"] = "Modifica il contatto"; +$a->strings["Send PM"] = "Invia messaggio privato"; +$a->strings["Poke"] = "Poke"; +$a->strings["%s likes this."] = "Piace a %s."; +$a->strings["%s doesn't like this."] = "Non piace a %s."; +$a->strings["%2\$d people like this."] = array( + 0 => "", + 1 => "Piace a %2\$d persone.", +); +$a->strings["%2\$d people don't like this."] = array( + 0 => "", + 1 => "Non piace a %2\$d persone.", +); +$a->strings["and"] = "e"; +$a->strings[", and %d other people"] = array( + 0 => "", + 1 => "e altre %d persone", +); +$a->strings["%s like this."] = "Piace a %s."; +$a->strings["%s don't like this."] = "Non piace a %s."; +$a->strings["Visible to everybody"] = "Visibile a tutti"; +$a->strings["Please enter a link URL:"] = "Inserisci l'indirizzo del link:"; +$a->strings["Please enter a video link/URL:"] = "Inserisci l'indirizzo del video:"; +$a->strings["Please enter an audio link/URL:"] = "Inserisci l'indirizzo dell'audio:"; +$a->strings["Tag term:"] = "Tag:"; +$a->strings["Save to Folder:"] = "Salva nella cartella:"; +$a->strings["Where are you right now?"] = "Dove sei ora?"; +$a->strings["Expires YYYY-MM-DD HH:MM"] = "Scade il YYYY-MM-DD HH:MM"; +$a->strings["Share"] = "Condividi"; +$a->strings["Page link name"] = "Nome del link alla pagina"; +$a->strings["Post as"] = "Pubblica come "; +$a->strings["Upload photo"] = "Carica foto"; +$a->strings["upload photo"] = "carica foto"; +$a->strings["Attach file"] = "Allega file"; +$a->strings["attach file"] = "allega file"; +$a->strings["Insert web link"] = "Inserisci un indirizzo web"; +$a->strings["web link"] = "link web"; +$a->strings["Insert video link"] = "Inserisci l'indirizzo di un video"; +$a->strings["video link"] = "link video"; +$a->strings["Insert audio link"] = "Inserisci l'indirizzo di un audio"; +$a->strings["audio link"] = "link audio"; +$a->strings["Set your location"] = "La tua località"; +$a->strings["set location"] = "la tua località"; +$a->strings["Toggle voting"] = "Abilita/disabilita il voto"; +$a->strings["Clear browser location"] = "Rimuovi la località data dal browser"; +$a->strings["clear location"] = "rimuovi la località"; +$a->strings["Title (optional)"] = "Titolo (opzionale)"; +$a->strings["Categories (optional, comma-separated list)"] = "Categorie (lista separata da virgole)"; +$a->strings["Permission settings"] = "Impostazioni permessi"; +$a->strings["permissions"] = "permessi"; +$a->strings["Public post"] = "Articolo pubblico"; +$a->strings["Example: bob@example.com, mary@example.com"] = "Per esempio: mario@esempio.com, simona@esempio.com"; +$a->strings["Set expiration date"] = "Data di scadenza"; +$a->strings["OK"] = "OK"; +$a->strings["Cancel"] = "Annulla"; +$a->strings["Discover"] = "Scopri"; +$a->strings["Imported public streams"] = "Contenuti pubblici importati"; +$a->strings["Commented Order"] = "Ultimi commenti"; +$a->strings["Sort by Comment Date"] = "Per data del commento"; +$a->strings["Posted Order"] = "Ultimi articoli"; +$a->strings["Sort by Post Date"] = "Per data di creazione"; +$a->strings["Posts that mention or involve you"] = "Articoli che ti riguardano o ti menzionano"; +$a->strings["New"] = "Novità"; +$a->strings["Activity Stream - by date"] = "Elenco attività - per data"; +$a->strings["Starred"] = "Preferiti"; +$a->strings["Favourite Posts"] = "Articoli preferiti"; +$a->strings["Spam"] = "Spam"; +$a->strings["Posts flagged as SPAM"] = "Articoli marcati come spam"; +$a->strings["Channel"] = "Canale"; +$a->strings["Status Messages and Posts"] = "Articoli e messaggi di stato"; +$a->strings["About"] = "Informazioni"; +$a->strings["Profile Details"] = "Dettagli del profilo"; +$a->strings["Photo Albums"] = "Album foto"; +$a->strings["Files and Storage"] = "Archivio file"; +$a->strings["Chatrooms"] = "Area chat"; +$a->strings["Saved Bookmarks"] = "Segnalibri salvati"; +$a->strings["Manage Webpages"] = "Gestisci le pagine web"; +$a->strings["__ctx:noun__ Attending"] = array( + 0 => "Partecipa", + 1 => "Partecipano", +); +$a->strings["__ctx:noun__ Not Attending"] = array( + 0 => "Non partecipa", + 1 => "Non partecipano", +); +$a->strings["__ctx:noun__ Undecided"] = array( + 0 => "Indeciso", + 1 => "Indecisi", +); +$a->strings["__ctx:noun__ Agree"] = array( + 0 => "D'accordo", + 1 => "D'accordo", +); +$a->strings["__ctx:noun__ Disagree"] = array( + 0 => "Non d'accordo", + 1 => "Non d'accordo", +); +$a->strings["__ctx:noun__ Abstain"] = array( + 0 => "Astenuto", + 1 => "Astenuti", +); +$a->strings["Image exceeds website size limit of %lu bytes"] = "L'immagine supera il limite massimo di %lu bytes"; +$a->strings["Image file is empty."] = "Il file dell'immagine è vuoto."; +$a->strings["Unable to process image"] = "Impossibile elaborare l'immagine"; +$a->strings["Photo storage failed."] = "Impossibile caricare la foto."; +$a->strings["Upload New Photos"] = "Carica nuove foto"; +$a->strings["Invalid data packet"] = "Dati non validi"; +$a->strings["Unable to verify channel signature"] = "Impossibile verificare la firma elettronica del canale"; +$a->strings["Unable to verify site signature for %s"] = "Impossibile verificare la firma elettronica del sito %s"; +$a->strings["Embedded content"] = "Contenuti incorporati"; +$a->strings["Embedding disabled"] = "Disabilita la creazione di contenuti incorporati"; +$a->strings["Logged out."] = "Uscita effettuata."; +$a->strings["Failed authentication"] = "Autenticazione fallita"; +$a->strings["Login failed."] = "Accesso fallito."; +$a->strings["%d invitation available"] = array( + 0 => "%d invito disponibile", + 1 => "%d inviti disponibili", +); +$a->strings["Advanced"] = "Avanzate"; +$a->strings["Find Channels"] = "Ricerca canali"; +$a->strings["Enter name or interest"] = "Scrivi un nome o un interesse"; +$a->strings["Connect/Follow"] = "Aggiungi"; +$a->strings["Examples: Robert Morgenstein, Fishing"] = "Per esempio: Mario Rossi, Pesca"; +$a->strings["Find"] = "Cerca"; +$a->strings["Channel Suggestions"] = "Canali suggeriti"; +$a->strings["Random Profile"] = "Profilo casuale"; +$a->strings["Invite Friends"] = "Invita amici"; +$a->strings["Advanced example: name=fred and country=iceland"] = "Per esempio: name=mario e country=italy"; +$a->strings["%d connection in common"] = array( + 0 => "%d contatto in comune", + 1 => "%d contatti in comune", +); +$a->strings["show more"] = "mostra tutto"; +$a->strings["Visible to your default audience"] = "Visibile secondo le impostazioni predefinite"; +$a->strings["Show"] = "Mostra"; +$a->strings["Don't show"] = "Non mostrare"; +$a->strings["Permissions"] = "Permessi"; +$a->strings["Item was not found."] = "Elemento non trovato."; +$a->strings["No source file."] = "Nessun file di origine."; +$a->strings["Cannot locate file to replace"] = "Il file da sostituire non è stato trovato"; +$a->strings["Cannot locate file to revise/update"] = "Il file da aggiornare non è stato trovato"; +$a->strings["File exceeds size limit of %d"] = "Il file supera la dimensione massima di %d"; +$a->strings["You have reached your limit of %1$.0f Mbytes attachment storage."] = "Hai raggiunto il limite complessivo di %1$.0f Mbytes per gli allegati."; +$a->strings["File upload failed. Possible system limit or action terminated."] = "Caricamento file fallito, potrebbe essere stato interrotto o potrebbe aver superato lo spazio assegnato."; +$a->strings["Stored file could not be verified. Upload failed."] = "Il file non può essere verificato. Caricamento fallito."; +$a->strings["Path not available."] = "Percorso non disponibile."; +$a->strings["Empty pathname"] = "Il percorso del file è vuoto"; +$a->strings["duplicate filename or path"] = "il file o il percorso del file è duplicato"; +$a->strings["Path not found."] = "Percorso del file non trovato."; +$a->strings["mkdir failed."] = "mkdir fallito."; +$a->strings["database storage failed."] = "scrittura su database fallita."; +$a->strings["Unable to obtain identity information from database"] = "Impossibile ottenere le informazioni di identificazione dal database"; +$a->strings["Empty name"] = "Nome vuoto"; +$a->strings["Name too long"] = "Nome troppo lungo"; +$a->strings["No account identifier"] = "Account senza identificativo"; +$a->strings["Nickname is required."] = "Il nome dell'account è obbligatorio."; +$a->strings["Reserved nickname. Please choose another."] = "Nome utente riservato. Per favore scegline un altro."; +$a->strings["Nickname has unsupported characters or is already being used on this site."] = "Il nome dell'account è già in uso oppure ha dei caratteri non supportati."; +$a->strings["Unable to retrieve created identity"] = "Impossibile caricare l'identità creata"; +$a->strings["Default Profile"] = "Profilo predefinito"; +$a->strings["Requested channel is not available."] = "Il canale che cerchi non è disponibile."; +$a->strings["Requested profile is not available."] = "Il profilo richiesto non è disponibile."; +$a->strings["Change profile photo"] = "Cambia la foto del profilo"; +$a->strings["Profiles"] = "Profili"; +$a->strings["Manage/edit profiles"] = "Gestisci/modifica i profili"; +$a->strings["Create New Profile"] = "Crea un nuovo profilo"; +$a->strings["Profile Image"] = "Immagine del profilo"; +$a->strings["visible to everybody"] = "visibile a tutti"; +$a->strings["Edit visibility"] = "Cambia la visibilità"; +$a->strings["Gender:"] = "Sesso:"; +$a->strings["Status:"] = "Stato:"; +$a->strings["Homepage:"] = "Home page:"; +$a->strings["Online Now"] = "Online adesso"; +$a->strings["g A l F d"] = "g A l d F"; +$a->strings["F d"] = "d F"; +$a->strings["[today]"] = "[oggi]"; +$a->strings["Birthday Reminders"] = "Promemoria compleanni"; +$a->strings["Birthdays this week:"] = "Compleanni questa settimana:"; +$a->strings["[No description]"] = "[Nessuna descrizione]"; +$a->strings["Event Reminders"] = "Promemoria"; +$a->strings["Events this week:"] = "Eventi di questa settimana:"; +$a->strings["Profile"] = "Profilo"; +$a->strings["Full Name:"] = "Nome completo:"; +$a->strings["Like this channel"] = "Mi piace questo canale"; +$a->strings["j F, Y"] = "j F Y"; +$a->strings["j F"] = "j F"; +$a->strings["Birthday:"] = "Compleanno:"; +$a->strings["Age:"] = "Età:"; +$a->strings["for %1\$d %2\$s"] = "per %1\$d %2\$s"; +$a->strings["Sexual Preference:"] = "Preferenze sessuali:"; +$a->strings["Hometown:"] = "Città dove vivo:"; +$a->strings["Tags:"] = "Tag:"; +$a->strings["Political Views:"] = "Orientamento politico:"; +$a->strings["Religion:"] = "Religione:"; +$a->strings["About:"] = "Informazioni:"; +$a->strings["Hobbies/Interests:"] = "Interessi e hobby:"; +$a->strings["Likes:"] = "Mi piace:"; +$a->strings["Dislikes:"] = "Non mi piace:"; +$a->strings["Contact information and Social Networks:"] = "Contatti e social network:"; +$a->strings["My other channels:"] = "I miei altri canali:"; +$a->strings["Musical interests:"] = "Gusti musicali:"; +$a->strings["Books, literature:"] = "Libri, letteratura:"; +$a->strings["Television:"] = "Televisione:"; +$a->strings["Film/dance/culture/entertainment:"] = "Film, danza, cultura, intrattenimento:"; +$a->strings["Love/Romance:"] = "Amore:"; +$a->strings["Work/employment:"] = "Lavoro:"; +$a->strings["School/education:"] = "Scuola:"; +$a->strings["Like this thing"] = "Mi piace questo Oggetto"; +$a->strings["Male"] = "Maschio"; +$a->strings["Female"] = "Femmina"; +$a->strings["Currently Male"] = "Al momento maschio"; +$a->strings["Currently Female"] = "Al momento femmina"; +$a->strings["Mostly Male"] = "Prevalentemente maschio"; +$a->strings["Mostly Female"] = "Prevalentemente femmina"; +$a->strings["Transgender"] = "Transgender"; +$a->strings["Intersex"] = "Intersex"; +$a->strings["Transsexual"] = "Transessuale"; +$a->strings["Hermaphrodite"] = "Ermafrodito"; +$a->strings["Neuter"] = "Neutro"; +$a->strings["Non-specific"] = "Non specificato"; +$a->strings["Undecided"] = "Indeciso"; +$a->strings["Males"] = "Maschi"; +$a->strings["Females"] = "Femmine"; +$a->strings["Gay"] = "Gay"; +$a->strings["Lesbian"] = "Lesbica"; +$a->strings["No Preference"] = "Senza preferenza"; +$a->strings["Bisexual"] = "Bisessuale"; +$a->strings["Autosexual"] = "Autosessuale"; +$a->strings["Abstinent"] = "Astinente"; +$a->strings["Virgin"] = "Vergine"; +$a->strings["Deviant"] = "Deviato"; +$a->strings["Fetish"] = "Feticista"; +$a->strings["Oodles"] = "Un sacco"; +$a->strings["Nonsexual"] = "Asessuato"; +$a->strings["Single"] = "Single"; +$a->strings["Lonely"] = "Da solo"; +$a->strings["Available"] = "Disponibile"; +$a->strings["Unavailable"] = "Non disponibile"; +$a->strings["Has crush"] = "Ha una cotta"; +$a->strings["Infatuated"] = "Infatuato/a"; +$a->strings["Dating"] = "Disponibile a un incontro"; +$a->strings["Unfaithful"] = "Infedele"; +$a->strings["Sex Addict"] = "Sesso-dipendente"; +$a->strings["Friends/Benefits"] = "Amici con qualcosa in più"; +$a->strings["Casual"] = "Casual"; +$a->strings["Engaged"] = "Impegnato"; +$a->strings["Married"] = "Sposato/a"; +$a->strings["Imaginarily married"] = "Con matrimonio immaginario"; +$a->strings["Partners"] = "Partner"; +$a->strings["Cohabiting"] = "Convivente"; +$a->strings["Common law"] = "Matrimonio regolare"; +$a->strings["Happy"] = "Felice"; +$a->strings["Not looking"] = "Non in cerca"; +$a->strings["Swinger"] = "Scambista"; +$a->strings["Betrayed"] = "Tradito/a"; +$a->strings["Separated"] = "Separato/a"; +$a->strings["Unstable"] = "Instabile"; +$a->strings["Divorced"] = "Divorziato/a"; +$a->strings["Imaginarily divorced"] = "Sogna il divorzio"; +$a->strings["Widowed"] = "Vedovo/a"; +$a->strings["Uncertain"] = "Incerto/a"; +$a->strings["It's complicated"] = "Relazione complicata"; +$a->strings["Don't care"] = "Chi se ne frega"; +$a->strings["Ask me"] = "Chiedimelo"; +$a->strings["Site Admin"] = "Amministrazione sito"; +$a->strings["Address Book"] = "Rubrica"; +$a->strings["Mood"] = "Umore"; +$a->strings["Probe"] = "Diagnostica"; +$a->strings["Suggest"] = "Suggerisci"; +$a->strings["Random Channel"] = "Canale casuale"; +$a->strings["Invite"] = "Invita"; +$a->strings["Features"] = "Funzionalità"; +$a->strings["Language"] = "Lingua"; +$a->strings["Post"] = "Articolo"; +$a->strings["Profile Photo"] = "Foto del profilo"; +$a->strings["Update"] = "Aggiorna"; +$a->strings["Install"] = "Installa"; +$a->strings["Purchase"] = "Acquista"; +$a->strings["Missing room name"] = "Area chat senza nome"; +$a->strings["Duplicate room name"] = "Il nome dell'area chat è duplicato"; +$a->strings["Invalid room specifier."] = "Il nome dell'area chat non è valido."; +$a->strings["Room not found."] = "Area chat non trovata."; +$a->strings["Room is full"] = "L'area chat è al completo"; +$a->strings["Some blurb about what to do when you're new here"] = "Qualche suggerimento per i nuovi utenti su cosa fare"; +$a->strings["You have created %1$.0f of %2$.0f allowed channels."] = "Hai creato %1$.0f dei %2$.0f canali permessi."; +$a->strings["Create a new channel"] = "Crea un nuovo canale"; +$a->strings["Current Channel"] = "Canale attuale"; +$a->strings["Switch to one of your channels by selecting it."] = "Per passare a un altro tuo canale selezionalo."; +$a->strings["Default Channel"] = "Canale predefinito"; +$a->strings["Make Default"] = "Rendi predefinito"; +$a->strings["%d new messages"] = "%d nuovi messaggi"; +$a->strings["%d new introductions"] = "%d nuove richieste di entrare in contatto"; +$a->strings["Delegated Channels"] = "Canali delegati"; +$a->strings["Name is required"] = "Il nome è obbligatorio"; +$a->strings["Key and Secret are required"] = "Key e Secret sono richiesti"; +$a->strings["Diaspora Policy Settings updated."] = "Le regole per Diaspora sono state aggiornate."; +$a->strings["Passwords do not match. Password unchanged."] = "Le password non corrispondono. Password non cambiata."; +$a->strings["Empty passwords are not allowed. Password unchanged."] = "Le password non possono essere vuote. Password non cambiata."; +$a->strings["Password changed."] = "Password cambiata."; +$a->strings["Password update failed. Please try again."] = "Modifica password fallita. Prova ancora."; +$a->strings["Not valid email."] = "Email non valida."; +$a->strings["Protected email address. Cannot change to that email."] = "È un indirizzo email riservato. Non puoi sceglierlo."; +$a->strings["System failure storing new email. Please try again."] = "Errore di sistema. Non è stato possibile memorizzare il tuo messaggio, riprova per favore."; +$a->strings["Settings updated."] = "Impostazioni aggiornate."; +$a->strings["No"] = "No"; +$a->strings["Yes"] = "Si"; +$a->strings["Add application"] = "Aggiungi una app"; +$a->strings["Name of application"] = "Nome dell'applicazione"; +$a->strings["Consumer Key"] = "Consumer Key"; +$a->strings["Automatically generated - change if desired. Max length 20"] = "Generato automaticamente - è possibile cambiarlo. Lunghezza massima 20"; +$a->strings["Consumer Secret"] = "Consumer Secret"; +$a->strings["Redirect"] = "Redirect"; +$a->strings["Redirect URI - leave blank unless your application specifically requires this"] = "URI ridirezionato - lasciare bianco se non richiesto specificamente dall'applicazione."; +$a->strings["Icon url"] = "Url icona"; +$a->strings["Optional"] = "Opzionale"; +$a->strings["You can't edit this application."] = "Non puoi modificare questa applicazione."; +$a->strings["Connected Apps"] = "App connesse"; +$a->strings["Client key starts with"] = "La client key inizia con"; +$a->strings["No name"] = "Nessun nome"; +$a->strings["Remove authorization"] = "Revoca l'autorizzazione"; +$a->strings["No feature settings configured"] = "Non hai componenti aggiuntivi da personalizzare"; +$a->strings["Feature/Addon Settings"] = "Impostazioni dei componenti aggiuntivi"; +$a->strings["Settings for the built-in Diaspora emulator"] = "Interconnessione con Diaspora"; +$a->strings["Allow any Diaspora member to comment on your public posts"] = "Permetti a tutti gli utenti di Diaspora di commentare i tuoi post pubblici"; +$a->strings["Diaspora Policy Settings"] = "Regole per Diaspora"; +$a->strings["Prevent your hashtags from being redirected to other sites"] = "Impedisci che i tuoi #tag puntino su altri siti"; +$a->strings["Account Settings"] = "Il tuo account"; +$a->strings["Enter New Password:"] = "Inserisci la nuova password:"; +$a->strings["Confirm New Password:"] = "Conferma la nuova password:"; +$a->strings["Leave password fields blank unless changing"] = "Lascia questi campi in bianco per non cambiare la password"; +$a->strings["Email Address:"] = "Indirizzo email:"; +$a->strings["Remove Account"] = "Elimina l'account"; +$a->strings["Remove this account including all its channels"] = "Elimina questo account e tutti i suoi canali"; +$a->strings["Off"] = "Off"; +$a->strings["On"] = "On"; +$a->strings["Additional Features"] = "Funzionalità opzionali"; +$a->strings["Connector Settings"] = "Impostazioni del connettore"; +$a->strings["No special theme for mobile devices"] = "Nessun tema per dispositivi mobili"; +$a->strings["%s - (Experimental)"] = "%s - (Sperimentale)"; +$a->strings["mobile"] = "mobile"; +$a->strings["Display Settings"] = "Aspetto"; +$a->strings["Display Theme:"] = "Tema per schermi medio grandi:"; +$a->strings["Mobile Theme:"] = "Tema per dispositivi mobili:"; +$a->strings["Enable user zoom on mobile devices"] = "Attiva la possibilità di fare zoom sui dispositivi mobili"; +$a->strings["Update browser every xx seconds"] = "Aggiorna il browser ogni x secondi"; +$a->strings["Minimum of 10 seconds, no maximum"] = "Minimo 10 secondi, nessun limite massimo"; +$a->strings["Maximum number of conversations to load at any time:"] = "Massimo numero di conversazioni da mostrare ogni volta:"; +$a->strings["Maximum of 100 items"] = "Massimo 100"; +$a->strings["Show emoticons (smilies) as images"] = "Mostra le faccine (smilies) come immagini"; +$a->strings["Link post titles to source"] = "Il link del titolo di un articolo porta al sito originale"; +$a->strings["System Page Layout Editor - (advanced)"] = "Modifica i layout di sistema (avanzato)"; +$a->strings["Use blog/list mode on channel page"] = "Mostra il canale nella modalità blog"; +$a->strings["(comments displayed separately)"] = "(i commenti sono mostrati separatamente)"; +$a->strings["Use blog/list mode on matrix page"] = "Mostra la tua rete in modalità blog"; +$a->strings["Channel page max height of content (in pixels)"] = "Altezza massima dei contenuti del canale (in pixel)"; +$a->strings["click to expand content exceeding this height"] = "dovrai cliccare per mostrare i contenuti di dimensioni maggiori"; +$a->strings["Matrix page max height of content (in pixels)"] = "Altezza massima dei contenuti della tua rete (in pixel)"; +$a->strings["Nobody except yourself"] = "Nessuno tranne te"; +$a->strings["Only those you specifically allow"] = "Solo chi riceve il mio permesso"; +$a->strings["Approved connections"] = "Contatti approvati"; +$a->strings["Any connections"] = "Tutti i contatti"; +$a->strings["Anybody on this website"] = "Chiunque su questo sito"; +$a->strings["Anybody in this network"] = "Chiunque su Red"; +$a->strings["Anybody authenticated"] = "Chiunque sia autenticato"; +$a->strings["Anybody on the internet"] = "Chiunque su internet"; +$a->strings["Publish your default profile in the network directory"] = "Mostra il mio profilo predefinito nell'elenco pubblico dei canali"; +$a->strings["Allow us to suggest you as a potential friend to new members?"] = "Vuoi essere suggerito come amico ai nuovi membri?"; +$a->strings["or"] = "o"; +$a->strings["Your channel address is"] = "L'indirizzo del tuo canale è"; +$a->strings["Channel Settings"] = "Impostazioni del canale"; +$a->strings["Basic Settings"] = "Impostazioni di base"; +$a->strings["Your Timezone:"] = "Il tuo fuso orario:"; +$a->strings["Default Post Location:"] = "Località predefinita:"; +$a->strings["Geographical location to display on your posts"] = "Posizione geografica da mostrare sui tuoi post"; +$a->strings["Use Browser Location:"] = "Usa la località rilevata dal browser:"; +$a->strings["Adult Content"] = "Contenuto per adulti"; +$a->strings["This channel frequently or regularly publishes adult content. (Please tag any adult material and/or nudity with #NSFW)"] = "Questo canale pubblica frequentemente contenuto per adulti. (I contenuti per adulti vanno taggati #NSFW - Not Safe For Work)"; +$a->strings["Security and Privacy Settings"] = "Impostazioni di sicurezza e privacy"; +$a->strings["Your permissions are already configured. Click to view/adjust"] = "I tuoi permessi sono già stati configurati. Clicca per vederli o modificarli"; +$a->strings["Hide my online presence"] = "Nascondi la mia presenza online"; +$a->strings["Prevents displaying in your profile that you are online"] = "Evita che sul tuo profilo compaia la tua presenza online"; +$a->strings["Simple Privacy Settings:"] = "Impostazioni di privacy semplificate"; +$a->strings["Very Public - extremely permissive (should be used with caution)"] = "Tutto pubblico - estremamente permissivo (da usare con cautela)"; +$a->strings["Typical - default public, privacy when desired (similar to social network permissions but with improved privacy)"] = "Standard - contenuti normalmente pubblici, ma anche privati se necessario (simile ai social network ma con privacy migliorata)"; +$a->strings["Private - default private, never open or public"] = "Privato - contenuti normalmente privati, nulla è aperto o pubblico"; +$a->strings["Blocked - default blocked to/from everybody"] = "Bloccato - bloccato in invio e ricezione dei contenuti"; +$a->strings["Allow others to tag your posts"] = "Permetti ad altri di taggare i tuoi articoli"; +$a->strings["Often used by the community to retro-actively flag inappropriate content"] = "Usato spesso dalla comunità per marcare contenuti inappropriati già esistenti"; +$a->strings["Advanced Privacy Settings"] = "Impostazioni di privacy avanzate"; +$a->strings["Expire other channel content after this many days"] = "Giorni dopo cui mettere in scadenza gli altri contenuti del canale"; +$a->strings["0 or blank prevents expiration"] = "Lascia vuoto oppure 0 per non impostare scadenze"; +$a->strings["Maximum Friend Requests/Day:"] = "Numero massimo giornaliero di richieste di amicizia:"; +$a->strings["May reduce spam activity"] = "Serve e ridurre lo spam"; +$a->strings["Default Post Permissions"] = "Permessi predefiniti per gli articoli"; +$a->strings["(click to open/close)"] = "(clicca per aprire/chiudere)"; +$a->strings["Channel permissions category:"] = "Categorie di permessi dei canali:"; +$a->strings["Maximum private messages per day from unknown people:"] = "Numero massimo giornaliero di messaggi privati da utenti sconosciuti:"; +$a->strings["Useful to reduce spamming"] = "Serve e ridurre lo spam"; +$a->strings["Notification Settings"] = "Impostazioni di notifica"; +$a->strings["By default post a status message when:"] = "Pubblica un messaggio di stato quando:"; +$a->strings["accepting a friend request"] = "accetto una nuova amicizia"; +$a->strings["joining a forum/community"] = "entro a far parte di un forum"; +$a->strings["making an interesting profile change"] = "faccio un cambiamento interessante al mio profilo"; +$a->strings["Send a notification email when:"] = "Invia una email di notifica quando:"; +$a->strings["You receive a connection request"] = "Ricevi una richiesta di entrare in contatto"; +$a->strings["Your connections are confirmed"] = "I tuoi contatti sono confermati"; +$a->strings["Someone writes on your profile wall"] = "Qualcuno scrive sulla tua bacheca"; +$a->strings["Someone writes a followup comment"] = "Qualcuno scrive un commento a un tuo articolo"; +$a->strings["You receive a private message"] = "Ricevi un messaggio privato"; +$a->strings["You receive a friend suggestion"] = "Ti viene suggerito un amico"; +$a->strings["You are tagged in a post"] = "Sei taggato in un articolo"; +$a->strings["You are poked/prodded/etc. in a post"] = "Ricevi un poke in un articolo"; +$a->strings["Show visual notifications including:"] = "Mostra queste notifiche a schermo:"; +$a->strings["Unseen matrix activity"] = "Nuove attività nella rete"; +$a->strings["Unseen channel activity"] = "Novità nei canali"; +$a->strings["Unseen private messages"] = "Nuovi messaggi privati"; +$a->strings["Recommended"] = "Consigliato"; +$a->strings["Upcoming events"] = "Prossimi eventi"; +$a->strings["Events today"] = "Eventi di oggi"; +$a->strings["Upcoming birthdays"] = "Prossimi compleanni"; +$a->strings["Not available in all themes"] = "Non disponibile in tutti i temi"; +$a->strings["System (personal) notifications"] = "Notifiche personali dal sistema"; +$a->strings["System info messages"] = "Notifiche di sistema"; +$a->strings["System critical alerts"] = "Avvisi critici di sistema"; +$a->strings["New connections"] = "Nuovi contatti"; +$a->strings["System Registrations"] = "Registrazioni"; +$a->strings["Also show new wall posts, private messages and connections under Notices"] = "Mostra negli avvisi anche i nuovi articoli, i messaggi privati e i nuovi contatti"; +$a->strings["Notify me of events this many days in advance"] = "Giorni di anticipo per notificare gli eventi"; +$a->strings["Must be greater than 0"] = "Maggiore di 0"; +$a->strings["Advanced Account/Page Type Settings"] = "Impostazioni avanzate"; +$a->strings["Change the behaviour of this account for special situations"] = "Cambia il funzionamento di questo account per necessità particolari"; +$a->strings["Please enable expert mode (in Settings > Additional features) to adjust!"] = "Abilita la modalità esperto per fare cambiamenti! (in Impostazioni > Funzionalità opzionali)"; +$a->strings["Miscellaneous Settings"] = "Impostazioni varie"; +$a->strings["Personal menu to display in your channel pages"] = "Menu personale da mostrare sulle pagine del tuo canale"; +$a->strings["Remove Channel"] = "Elimina questo canale"; +$a->strings["Remove this channel."] = "Elimina questo canale."; +$a->strings["Xchan Lookup"] = "Ricerca canale"; +$a->strings["Lookup xchan beginning with (or webbie): "] = "Cerca un canale (o un webbie) che inizia per:"; +$a->strings["Not found."] = "Non trovato."; +$a->strings["Authorize application connection"] = "Autorizza la app"; +$a->strings["Return to your app and insert this Securty Code:"] = "Torna alla app e inserisci questo codice di sicurezza:"; +$a->strings["Please login to continue."] = "Accedi al sito per continuare."; +$a->strings["Do you want to authorize this application to access your posts and contacts, and/or create new posts for you?"] = "Vuoi autorizzare questa app ad accedere ai messaggi e ai contatti o creare nuovi messaggi per te?"; +$a->strings["Channel added."] = "Canale aggiunto."; +$a->strings["Tag removed"] = "Tag rimosso"; +$a->strings["Remove Item Tag"] = "Rimuovi il tag"; +$a->strings["Select a tag to remove: "] = "Seleziona un tag da rimuovere: "; +$a->strings["Remove"] = "Rimuovi"; +$a->strings["Continue"] = "Continua"; +$a->strings["Premium Channel Setup"] = "Canale premium - installazione"; +$a->strings["Enable premium channel connection restrictions"] = "Abilita le restrizioni del canale premium"; +$a->strings["Please enter your restrictions or conditions, such as paypal receipt, usage guidelines, etc."] = "Scrivi le condizioni d'uso e le restrizioni di questo canale, come per esempio le linee guida, il sistema di pagamento, ecc."; +$a->strings["This channel may require additional steps or acknowledgement of the following conditions prior to connecting:"] = "Prima di connetterti a questo canale è necessario che tu accetti le seguenti condizioni:"; +$a->strings["Potential connections will then see the following text before proceeding:"] = "Il testo seguente comparirà a chi vorrà seguire il canale:"; +$a->strings["By continuing, I certify that I have complied with any instructions provided on this page."] = "Continuando dichiaro di aver seguito tutte le indicazioni e le istruzioni fornite in questa pagina."; +$a->strings["(No specific instructions have been provided by the channel owner.)"] = "(Il gestore del canale non ha fornito istruzioni specifiche)"; +$a->strings["Restricted or Premium Channel"] = "Canale premium - con restrizioni"; +$a->strings["Thing updated"] = "L'Oggetto è stato aggiornato"; +$a->strings["Object store: failed"] = "Impossibile memorizzare l'oggetto."; +$a->strings["Thing added"] = "L'Oggetto è stato aggiunto"; +$a->strings["OBJ: %1\$s %2\$s %3\$s"] = "OBJ: %1\$s %2\$s %3\$s"; +$a->strings["Show Thing"] = "Mostra l'Oggetto"; +$a->strings["item not found."] = "non trovato."; +$a->strings["Edit Thing"] = "Modifica l'Oggetto"; +$a->strings["Select a profile"] = "Scegli un profilo"; +$a->strings["Post an activity"] = "Pubblica un'attività"; +$a->strings["Only sends to viewers of the applicable profile"] = "Invia solo a chi segue il relativo canale"; +$a->strings["Name of thing e.g. something"] = "Nome dell'Oggetto"; +$a->strings["URL of thing (optional)"] = "Indirizzo web dell'Oggetto (opzionale)"; +$a->strings["URL for photo of thing (optional)"] = "Indirizzo di un'immagine dell'Oggetto (facoltativo)"; +$a->strings["Add Thing to your Profile"] = "Aggiungi l'Oggetto al tuo profilo"; +$a->strings["Item not available."] = "Elemento non disponibile."; +$a->strings["Fetching URL returns error: %1\$s"] = "La chiamata all'URL restituisce questo errore: %1\$s"; +$a->strings["Hubzilla - "The Network""] = "Hubzilla - "La tua rete""; +$a->strings["Welcome to %s"] = "%s ti dà il benvenuto"; +$a->strings["Image uploaded but image cropping failed."] = "L'immagine è stata caricata, ma il non è stato possibile ritagliarla."; +$a->strings["Image resize failed."] = "Il ridimensionamento dell'immagine è fallito."; +$a->strings["Shift-reload the page or clear browser cache if the new photo does not display immediately."] = "Ricarica la pagina con shift+F5 o cancella la cache del browser se la nuova foto non viene mostrata immediatamente."; +$a->strings["Image exceeds size limit of %d"] = "La dimensione dell'immagine supera il limite di %d"; +$a->strings["Unable to process image."] = "Impossibile elaborare l'immagine."; +$a->strings["Photo not available."] = "Foto non disponibile."; +$a->strings["Upload File:"] = "Carica un file:"; +$a->strings["Select a profile:"] = "Seleziona un profilo:"; +$a->strings["Upload Profile Photo"] = "Carica la foto del profilo"; +$a->strings["skip this step"] = "salta questo passaggio"; +$a->strings["select a photo from your photo albums"] = "seleziona una foto dai tuoi album"; +$a->strings["Crop Image"] = "Ritaglia immagine"; +$a->strings["Please adjust the image cropping for optimum viewing."] = "Ritaglia l'immagine per migliorarne la visualizzazione."; +$a->strings["Done Editing"] = "Modifica terminata"; +$a->strings["Image uploaded successfully."] = "Immagine caricata con successo."; +$a->strings["Image upload failed."] = "Il caricamento dell'immagine è fallito."; +$a->strings["Image size reduction [%s] failed."] = "Il ridimensionamento del'immagine [%s] è fallito."; +$a->strings["Invalid item."] = "Elemento non valido."; +$a->strings["Channel not found."] = "Canale non trovato."; +$a->strings["Page not found."] = "Pagina non trovata."; +$a->strings["Like/Dislike"] = "Mi piace/Non mi piace"; +$a->strings["This action is restricted to members."] = "Questa funzionalità è riservata agli iscritti."; +$a->strings["Please login with your Hubzilla ID or register as a new Redmatrix.member to continue."] = "Per favore accedi con il tuo identificativo Hubzilla o registrati su Hubzilla per continuare."; +$a->strings["Invalid request."] = "Richiesta non valida."; +$a->strings["thing"] = "Oggetto"; +$a->strings["Channel unavailable."] = "Canale non trovato."; +$a->strings["Previous action reversed."] = "Il comando precedente è stato annullato."; +$a->strings["%1\$s agrees with %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s è d'accordo"; +$a->strings["%1\$s doesn't agree with %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s non è d'accordo"; +$a->strings["%1\$s abstains from a decision on %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s non ha preso una decisione"; +$a->strings["%1\$s is attending %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s partecipa"; +$a->strings["%1\$s is not attending %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s non partecipa"; +$a->strings["%1\$s may attend %2\$s's %3\$s"] = "%3\$s di %2\$s: %1\$s forse partecipa"; +$a->strings["Action completed."] = "Comando completato."; +$a->strings["Thank you."] = "Grazie."; +$a->strings["Event can not end before it has started."] = "Un evento non può terminare prima del suo inizio."; +$a->strings["Unable to generate preview."] = "Impossibile creare un'anteprima."; +$a->strings["Event title and start time are required."] = "Sono necessari il titolo e l'ora d'inizio dell'evento."; +$a->strings["Event not found."] = "Evento non trovato."; +$a->strings["l, F j"] = "l j F"; +$a->strings["Edit event"] = "Modifica l'evento"; +$a->strings["Delete event"] = "Elimina l'evento"; +$a->strings["Create New Event"] = "Crea un nuovo evento"; +$a->strings["Previous"] = "Precendente"; +$a->strings["Next"] = "Successivo"; +$a->strings["Export"] = "Esporta"; +$a->strings["Event removed"] = "Evento eliminato"; +$a->strings["Failed to remove event"] = "Impossibile eliminare l'evento"; +$a->strings["Event details"] = "Dettagli evento"; +$a->strings["Starting date and Title are required."] = "Titolo e data d'inizio sono obbligatori."; +$a->strings["Categories (comma-separated list)"] = "Categorie (separate da virgola)"; +$a->strings["Event Starts:"] = "Inizio:"; +$a->strings["Finish date/time is not known or not relevant"] = "La data/ora di fine non è rilevante"; +$a->strings["Event Finishes:"] = "Fine:"; +$a->strings["Adjust for viewer timezone"] = "Adatta al fuso orario di chi legge"; +$a->strings["Important for events that happen in a particular place. Not practical for global holidays."] = "Importante per eventi che avvengono in base all'orario di un luogo particolare."; +$a->strings["Description:"] = "Descrizione:"; +$a->strings["Title:"] = "Titolo:"; +$a->strings["Share this event"] = "Condividi questo evento"; +$a->strings["%1\$s is following %2\$s's %3\$s"] = "%1\$s sta seguendo %3\$s di %2\$s"; +$a->strings["Public Sites"] = "Siti pubblici"; +$a->strings["The listed sites allow public registration into the Hubzilla. All sites in the matrix are interlinked so membership on any of them conveys membership in the matrix as a whole. Some sites may require subscription or provide tiered service plans. The provider links may provide additional details."] = "Gli indirizzi elencati permettono la registrazione su Hubzilla. Tutti i siti di questa rete sono interconnessi, quindi essere registrati su uno è come essere registrati ovunque. Alcuni potrebbero richiedere un'iscrizione a pagamento o prevedere diverse tipologie di abbonamento. Eventualmente potrai trovare maggiori informazioni visitando ciascun sito."; +$a->strings["Rate this hub"] = "Valuta questo hub"; +$a->strings["Site URL"] = "URL del sito"; +$a->strings["Access Type"] = "Tipo di accesso"; +$a->strings["Registration Policy"] = "Politica di registrazione"; +$a->strings["Location"] = "Posizione geografica"; +$a->strings["View hub ratings"] = "Vedi le valutazioni del hub"; +$a->strings["Rate"] = "Valuta"; +$a->strings["View ratings"] = "Vedi le valutazioni"; +$a->strings["Edit post"] = "Modifica articolo"; +$a->strings["Hubzilla channel"] = "Canale Hubzilla"; +$a->strings["Collection created."] = "L'insieme di canali è stato creato."; +$a->strings["Could not create collection."] = "Impossibile creare l'insieme."; +$a->strings["Collection updated."] = "Insieme aggiornato."; +$a->strings["Create a collection of channels."] = "Crea un insieme di canali."; +$a->strings["Collection Name: "] = "Nome dell'insieme:"; +$a->strings["Members are visible to other channels"] = "I membri potranno vedere gli altri canali dell'insieme"; +$a->strings["Collection removed."] = "Insieme rimosso."; +$a->strings["Unable to remove collection."] = "Impossibile rimuovere l'insieme."; +$a->strings["Collection Editor"] = "Modifica l'insieme"; +$a->strings["Members"] = "Membri"; +$a->strings["All Connected Channels"] = "Tutti i canali connessi"; +$a->strings["Click on a channel to add or remove."] = "Clicca su un canale per aggiungerlo o rimuoverlo."; +$a->strings["Version %s"] = "Versione %s"; +$a->strings["Installed plugins/addons/apps:"] = "App e componenti installati:"; +$a->strings["No installed plugins/addons/apps"] = "Nessuna app o componente installato"; +$a->strings["Red"] = "Hubzilla"; +$a->strings["This is a hub of hubzilla - a global cooperative network of decentralized privacy enhanced websites."] = "Questo è un hub di Hubzilla - una rete cooperativa e decentralizzata di siti ad elevata privacy. "; +$a->strings["Tag: "] = "Tag: "; +$a->strings["Last background fetch: "] = "Ultima acquisizione:"; +$a->strings["Running at web location"] = "In esecuzione sull'indirizzo web"; +$a->strings["Please visit redmatrix.me to learn more about the Hubzilla."] = "Visita Redmatrix.me per scoprire cosa è Hubzilla."; +$a->strings["Bug reports and issues: please visit"] = "Per segnalare bug e problemi: visita"; +$a->strings["Suggestions, praise, etc. - please email \"hubzilla\" at librelist - dot com"] = "Per consigli, ringraziamenti, ecc. - scrivi a \"hubzilla\" at librelist - dot com"; +$a->strings["Site Administrators"] = "Amministratori del sito"; +$a->strings["Help:"] = "Guida:"; +$a->strings["Not Found"] = "Non disponibile"; +$a->strings["Hubzilla Server - Setup"] = "Hubzilla Server - Installazione"; +$a->strings["Could not connect to database."] = " Impossibile connettersi al database."; +$a->strings["Could not connect to specified site URL. Possible SSL certificate or DNS issue."] = "Non è possibile raggiungere l'indirizzo del sito specificato. Potrebbe essere un problema di SSL o DNS."; +$a->strings["Could not create table."] = "Impossibile creare le tabelle."; +$a->strings["Your site database has been installed."] = "Il database del sito è stato installato."; +$a->strings["You may need to import the file \"install/schema_xxx.sql\" manually using a database client."] = "Potresti dover importare il file 'install/schema_xxx.sql' manualmente usando un client per collegarti al db."; +$a->strings["Please see the file \"install/INSTALL.txt\"."] = "Leggi il file 'install/INSTALL.txt'."; +$a->strings["System check"] = "Verifica del sistema"; +$a->strings["Check again"] = "Verifica di nuovo"; +$a->strings["Database connection"] = "Connessione al database"; +$a->strings["In order to install Hubzilla we need to know how to connect to your database."] = "Per installare Hubzilla è necessario conoscere i parametri di connessione al database."; +$a->strings["Please contact your hosting provider or site administrator if you have questions about these settings."] = "Contatta il tuo fornitore di hosting o l'amministratore del sito se hai domande su queste impostazioni."; +$a->strings["The database you specify below should already exist. If it does not, please create it before continuing."] = "Il database deve già esistere. Se non esiste, crealo prima di continuare."; +$a->strings["Database Server Name"] = "Server del database"; +$a->strings["Default is localhost"] = "'localhost' è il predefinito"; +$a->strings["Database Port"] = "Port del database"; +$a->strings["Communication port number - use 0 for default"] = "Scrivi 0 per usare il valore standard"; +$a->strings["Database Login Name"] = "Utente database"; +$a->strings["Database Login Password"] = "Password utente database"; +$a->strings["Database Name"] = "Nome database"; +$a->strings["Database Type"] = "Tipo database"; +$a->strings["Site administrator email address"] = "Indirizzo email dell'amministratore del sito"; +$a->strings["Your account email address must match this in order to use the web admin panel."] = "Il tuo indirizzo email deve corrispondere a questo per poter usare il pannello di amministrazione web."; +$a->strings["Website URL"] = "URL completo del sito"; +$a->strings["Please use SSL (https) URL if available."] = "Se disponibile, usa l'indirizzo SSL (https)."; +$a->strings["Please select a default timezone for your website"] = "Seleziona il fuso orario predefinito per il tuo sito web"; +$a->strings["Site settings"] = "Impostazioni del sito"; +$a->strings["Could not find a command line version of PHP in the web server PATH."] = "Non è possibile trovare la versione di PHP da riga di comando nel PATH del server web"; +$a->strings["If you don't have a command line version of PHP installed on server, you will not be able to run background polling via cron."] = "Se non hai installata la versione di PHP da riga di comando non potrai attivare il polling in background tramite cron."; +$a->strings["PHP executable path"] = "Path del comando PHP"; +$a->strings["Enter full path to php executable. You can leave this blank to continue the installation."] = "Inserisci il percorso dell'eseguibile PHP. Puoi lasciarlo vuoto per continuare l'installazione."; +$a->strings["Command line PHP"] = "PHP da riga di comando"; +$a->strings["The command line version of PHP on your system does not have \"register_argc_argv\" enabled."] = "La versione da riga di comando di PHP nel sistema non ha abilitato \"register_argc_argv\"."; +$a->strings["This is required for message delivery to work."] = "E' necessario perché funzioni la consegna dei messaggi."; +$a->strings["PHP register_argc_argv"] = "PHP register_argc_argv"; +$a->strings["Error: the \"openssl_pkey_new\" function on this system is not able to generate encryption keys"] = "Errore: la funzione \"openssl_pkey_new\" su questo sistema non è in grado di generare le chiavi di criptazione"; +$a->strings["If running under Windows, please see \"http://www.php.net/manual/en/openssl.installation.php\"."] = "Se stai usando un server windows, guarda \"http://www.php.net/manual/en/openssl.installation.php\"."; +$a->strings["Generate encryption keys"] = "Genera chiavi di criptazione"; +$a->strings["libCurl PHP module"] = "modulo PHP libCurl"; +$a->strings["GD graphics PHP module"] = "modulo PHP GD graphics"; +$a->strings["OpenSSL PHP module"] = "modulo PHP OpenSSL"; +$a->strings["mysqli or postgres PHP module"] = "modulo PHP per mysqli oppure prostgres"; +$a->strings["mb_string PHP module"] = "modulo PHP mb_string"; +$a->strings["mcrypt PHP module"] = "modulo PHP mcrypt"; +$a->strings["Apache mod_rewrite module"] = "modulo Apache mod_rewrite"; +$a->strings["Error: Apache webserver mod-rewrite module is required but not installed."] = "Errore: il modulo mod-rewrite di Apache è richiesto ma non installato"; +$a->strings["proc_open"] = "proc_open"; +$a->strings["Error: proc_open is required but is either not installed or has been disabled in php.ini"] = "Errore: proc_open è richiesto ma non è installato o è disabilitato in php.ini"; +$a->strings["Error: libCURL PHP module required but not installed."] = "Errore: il modulo libCURL di PHP è richiesto ma non installato."; +$a->strings["Error: GD graphics PHP module with JPEG support required but not installed."] = "Errore: Il modulo GD graphics di PHP con supporto a JPEG è richiesto ma non installato."; +$a->strings["Error: openssl PHP module required but not installed."] = "Errore: il modulo openssl di PHP è richiesto ma non installato."; +$a->strings["Error: mysqli or postgres PHP module required but neither are installed."] = "Errore: il modulo PHP per mysqli o postgres è richiesto ma non installato"; +$a->strings["Error: mb_string PHP module required but not installed."] = "Errore: il modulo PHP mb_string è richiesto ma non installato."; +$a->strings["Error: mcrypt PHP module required but not installed."] = "Errore: il modulo PHP mcrypt è richiesto ma non installato."; +$a->strings["The web installer needs to be able to create a file called \".htconfig.php\" in the top folder of your web server and it is unable to do so."] = "L'installazione web deve poter creare un file chiamato \".htconfig.php\" nella cartella di Hubzilla ma non è in grado di farlo."; +$a->strings["This is most often a permission setting, as the web server may not be able to write files in your folder - even if you can."] = "Spesso ciò è dovuto ai permessi di accesso al disco: il web server potrebbe non aver diritto di scrivere il file nella cartella, anche se tu puoi."; +$a->strings["At the end of this procedure, we will give you a text to save in a file named .htconfig.php in your Red top folder."] = "Alla fine di questa procedura ti sarà dato il testo da salvare in un file di nome .htconfig.php dentro la cartella principale di Hubzilla."; +$a->strings["You can alternatively skip this procedure and perform a manual installation. Please see the file \"install/INSTALL.txt\" for instructions."] = "Puoi anche saltare questa procedura ed effettuare un'installazione manuale. Guarda il file 'install/INSTALL.txt' per le istruzioni."; +$a->strings[".htconfig.php is writable"] = ".htconfig.php è scrivibile"; +$a->strings["Red uses the Smarty3 template engine to render its web views. Smarty3 compiles templates to PHP to speed up rendering."] = "Red usa il sistema Smarty3 per costruire i suoi template grafici. Smarty3 è molto veloce perché compila i template delle pagine direttamente in PHP."; +$a->strings["In order to store these compiled templates, the web server needs to have write access to the directory %s under the Red top level folder."] = "Per poter memorizzare i template compilati, il web server deve avere accesso in scrittura a %s sotto la cartella di installazione di Hubzilla."; +$a->strings["Please ensure that the user that your web server runs as (e.g. www-data) has write access to this folder."] = "Assicurati che il tuo web server sia in esecuzione da parte di un utente che ha diritto di scrittura su quella cartella (ad esempio www-data)."; +$a->strings["Note: as a security measure, you should give the web server write access to %s only--not the template files (.tpl) that it contains."] = "Nota bene: come precauzione, dovresti dare i diritti di scrittura solamente su %s e non sui file template (.tpl) che contiene."; +$a->strings["%s is writable"] = "%s è scrivibile"; +$a->strings["Red uses the store directory to save uploaded files. The web server needs to have write access to the store directory under the Red top level folder"] = "Hubzilla salva i file caricati nella cartella \"store\" sul server. Il server deve avere i diritti di scrittura su quella cartella che si trova dentro l'installazione di Hubzilla"; +$a->strings["store is writable"] = "l'archivio è scrivibile"; +$a->strings["SSL certificate cannot be validated. Fix certificate or disable https access to this site."] = "Il certificato SSL non può essere validato. Correggi l'errore o disabilita l'accesso https al sito."; +$a->strings["If you have https access to your website or allow connections to TCP port 443 (the https: port), you MUST use a browser-valid certificate. You MUST NOT use self-signed certificates!"] = "Se abiliti https per il tuo sito o permetti connessioni TCP su port 443 (quella di https), DEVI usare un certificato riconosciuto dai browser internet. NON DEVI usare certificati generati da te!"; +$a->strings["This restriction is incorporated because public posts from you may for example contain references to images on your own hub."] = "Questa restrizione è necessaria perché i tuoi post pubblici potrebbero contenere riferimenti a immagini sul tuo server."; +$a->strings["If your certificate is not recognized, members of other sites (who may themselves have valid certificates) will get a warning message on their own site complaining about security issues."] = "Se il tuo certificato non è riconosciuto, gli utenti che ti seguono da altri siti (che avranno certificati validi) riceveranno gravi avvisi di sicurezza dal browser."; +$a->strings["This can cause usability issues elsewhere (not just on your own site) so we must insist on this requirement."] = "Ciò può creare seri problemi di usabilità (non solo sul tuo sito), quindi dobbiamo insistere su questo punto."; +$a->strings["Providers are available that issue free certificates which are browser-valid."] = "Eventualmente, considera che esistono provider che rilasciano certificati gratuiti riconosciuti dai browser."; +$a->strings["SSL certificate validation"] = "Validazione del certificato SSL"; +$a->strings["Url rewrite in .htaccess is not working. Check your server configuration.Test: "] = "In .htaccess la funzionalità url rewrite non funziona. Controlla la configurazione del server. Test:"; +$a->strings["Url rewrite is working"] = "Url rewrite funziona correttamente"; +$a->strings["The database configuration file \".htconfig.php\" could not be written. Please use the enclosed text to create a configuration file in your web server root."] = "Il file di configurazione del database \".htconfig.php\" non puo' essere scritto. Usa il testo qui di seguito per creare questo file di configurazione nella cartella principale del tuo sito."; +$a->strings["Errors encountered creating database tables."] = "La creazione delle tabelle del database ha generato errori."; +$a->strings["

    What next

    "] = "

    I prossimi passi

    "; +$a->strings["IMPORTANT: You will need to [manually] setup a scheduled task for the poller."] = "IMPORTANTE: Devi creare [manualmente] la pianificazione del polling."; +$a->strings["No channel."] = "Nessun canale."; +$a->strings["Common connections"] = "Contatti in comune"; +$a->strings["No connections in common."] = "Nessun contatto in comune."; +$a->strings["This site is not a directory server"] = "Questo sito non è un server di elenchi pubblici"; +$a->strings["Could not access contact record."] = "Non è possibile accedere alle informazioni sul contatto."; +$a->strings["Could not locate selected profile."] = "Non riesco a trovare il profilo selezionato."; +$a->strings["Connection updated."] = "Contatto aggiornato."; +$a->strings["Failed to update connection record."] = "Impossibile aggiornare le informazioni del contatto."; +$a->strings["Blocked"] = "Bloccati"; +$a->strings["Ignored"] = "Ignorati"; +$a->strings["Hidden"] = "Nascosti"; +$a->strings["Archived"] = "Archiviati"; +$a->strings["Suggest new connections"] = "Suggerisci nuovi contatti"; +$a->strings["New Connections"] = "Nuovi contatti"; +$a->strings["Show pending (new) connections"] = "Richieste di contatto in attesa"; +$a->strings["All Connections"] = "Tutti i contatti"; +$a->strings["Show all connections"] = "Mostra tutti i contatti"; +$a->strings["Unblocked"] = "Non bloccati"; +$a->strings["Only show unblocked connections"] = "Mostra solo i contatti non bloccati"; +$a->strings["Only show blocked connections"] = "Mostra solo i contatti bloccati"; +$a->strings["Only show ignored connections"] = "Mostra solo i contatti ignorati"; +$a->strings["Only show archived connections"] = "Mostra solo i contatti archiviati"; +$a->strings["Only show hidden connections"] = "Mostra solo i contatti nascosti"; +$a->strings["%1\$s [%2\$s]"] = "%1\$s [%2\$s]"; +$a->strings["Edit connection"] = "Modifica il contatto"; +$a->strings["Search your connections"] = "Cerca tra i contatti"; +$a->strings["Finding: "] = "Ricerca: "; +$a->strings["webpage"] = "pagina web"; +$a->strings["block"] = "riquadro"; +$a->strings["layout"] = "layout"; +$a->strings["%s element installed"] = "%s elemento installato"; +$a->strings["%1\$s tagged %2\$s's %3\$s with %4\$s"] = "%1\$s ha taggato %3\$s di %2\$s con %4\$s"; +$a->strings["Hubzilla - Guests: Username: {your email address}, Password: +++"] = "Accesso a Hubzilla. {Inserisci l'email con cui sei registrato e la password.}"; +$a->strings["Page owner information could not be retrieved."] = "Impossibile ottenere informazioni sul proprietario della pagina."; +$a->strings["Album not found."] = "Album non trovato."; +$a->strings["Delete Album"] = "Elimina album"; +$a->strings["Delete Photo"] = "Elimina foto"; +$a->strings["Public access denied."] = "Accesso pubblico negato."; +$a->strings["No photos selected"] = "Nessuna foto selezionata"; +$a->strings["Access to this item is restricted."] = "Questo elemento non è visibile a tutti."; +$a->strings["%1$.2f MB of %2$.2f MB photo storage used."] = "Hai usato %1$.2f Mb dei %2$.2f Mb di spazio disponibile."; +$a->strings["%1$.2f MB photo storage used."] = "Hai usato %1$.2f Mb del tuo spazio disponibile."; +$a->strings["Upload Photos"] = "Carica foto"; +$a->strings["Enter a new album name"] = "Inserisci il nome di un nuovo album"; +$a->strings["or select an existing one (doubleclick)"] = "o seleziona uno esistente (doppio click)"; +$a->strings["Create a status post for this upload"] = "Pubblica l'oggetto caricato sulla bacheca"; +$a->strings["Album name could not be decoded"] = "Non è stato possibile leggere il nome dell'album"; +$a->strings["Contact Photos"] = "Foto dei contatti"; +$a->strings["Show Newest First"] = "Prima i più recenti"; +$a->strings["Show Oldest First"] = "Prima i più vecchi"; +$a->strings["View Photo"] = "Guarda la foto"; +$a->strings["Edit Album"] = "Modifica album"; +$a->strings["Permission denied. Access to this item may be restricted."] = "Permesso negato. L'accesso a questo elemento può essere stato limitato."; +$a->strings["Photo not available"] = "Foto non disponibile"; +$a->strings["Use as profile photo"] = "Usa come foto del profilo"; +$a->strings["Private Photo"] = "Foto privata"; +$a->strings["View Full Size"] = "Vedi nelle dimensioni originali"; +$a->strings["Edit photo"] = "Modifica la foto"; +$a->strings["Rotate CW (right)"] = "Ruota (senso orario)"; +$a->strings["Rotate CCW (left)"] = "Ruota (senso antiorario)"; +$a->strings["Caption"] = "Titolo"; +$a->strings["Add a Tag"] = "Aggiungi tag"; +$a->strings["Example: @bob, @Barbara_Jensen, @jim@example.com"] = "Esempio: @bob, @Barbara_Jensen, @jim@example.com"; +$a->strings["Flag as adult in album view"] = "Marca come 'per adulti'"; +$a->strings["In This Photo:"] = "In questa foto:"; +$a->strings["Map"] = "Mappa"; +$a->strings["View Album"] = "Guarda l'album"; +$a->strings["Recent Photos"] = "Foto recenti"; +$a->strings["Profile Match"] = "Profili corrispondenti"; +$a->strings["No keywords to match. Please add keywords to your default profile."] = "Non hai scritto parole chiave. Aggiungi parole chiave al tuo profilo predefinito per comparire nelle ricerche."; +$a->strings["is interested in:"] = "interessi personali:"; +$a->strings["No matches"] = "Nessun risultato"; +$a->strings["Away"] = "Assente"; +$a->strings["Online"] = "Online"; +$a->strings["Select a bookmark folder"] = "Scegli una cartella di segnalibri"; +$a->strings["Save Bookmark"] = "Salva segnalibro"; +$a->strings["URL of bookmark"] = "URL del segnalibro"; +$a->strings["Description"] = "Descrizione"; +$a->strings["Or enter new bookmark folder name"] = "O inserisci il nome di una nuova cartella di segnalibri"; +$a->strings["No more system notifications."] = "Non ci sono nuove notifiche di sistema."; +$a->strings["System Notifications"] = "Notifiche di sistema"; +$a->strings["network"] = "rete"; +$a->strings["RSS"] = "RSS"; +$a->strings["Layout updated."] = "Layout aggiornato."; +$a->strings["Edit System Page Description"] = "Modifica i layout di sistema"; +$a->strings["Layout not found."] = "Layout non trovato."; +$a->strings["Module Name:"] = "Nome del modulo:"; +$a->strings["Layout Help"] = "Guida al layout"; +$a->strings["- select -"] = "- scegli -"; +$a->strings["Your service plan only allows %d channels."] = "Il tuo account permette di creare al massimo %d canali."; +$a->strings["Nothing to import."] = "Non c'è niente da importare."; +$a->strings["Unable to download data from old server"] = "Impossibile importare i dati dal vecchio server"; +$a->strings["Imported file is empty."] = "Il file da importare è vuoto."; +$a->strings["Cannot create a duplicate channel identifier on this system. Import failed."] = "Non posso creare un canale con un identificativo che già esiste su questo sistema. L'importazione è fallita."; +$a->strings["Unable to create a unique channel address. Import failed."] = "Impossibile creare un indirizzo univoco per il canale. L'import è fallito."; +$a->strings["Channel clone failed. Import failed."] = "Impossibile clonare il canale. L'importazione è fallita."; +$a->strings["Cloned channel not found. Import failed."] = "Impossibile trovare il canale clonato. L'importazione è fallita."; +$a->strings["Import completed."] = "L'importazione è terminata con successo!"; +$a->strings["You must be logged in to use this feature."] = "Per questa funzionalità devi aver effettuato l'accesso."; +$a->strings["Import Channel"] = "Importa un canale"; +$a->strings["Use this form to import an existing channel from a different server/hub. You may retrieve the channel identity from the old server/hub via the network or provide an export file. Only identity and connections/relationships will be imported. Importation of content is not yet available."] = "Usa questo modulo per importare un tuo canale da un altro server/hub. Puoi scaricare i dati identificativi del canale direttamente dall'altro server/hub oppure tramite un file che hai esportato. Saranno importati solamente l'identità e i contatti. L'importazione dei contenuti non è ancora disponibile."; +$a->strings["File to Upload"] = "File da caricare"; +$a->strings["Or provide the old server/hub details"] = "Oppure fornisci i dettagli del vecchio server/hub"; +$a->strings["Your old identity address (xyz@example.com)"] = "Il tuo vecchio identificativo (per esempio pippo@esempio.com)"; +$a->strings["Your old login email address"] = "L'email che usavi per accedere sul vecchio server"; +$a->strings["Your old login password"] = "La password per il vecchio server"; +$a->strings["For either option, please choose whether to make this hub your new primary address, or whether your old location should continue this role. You will be able to post from either location, but only one can be marked as the primary location for files, photos, and media."] = "Scegli se vuoi spostare il tuo indirizzo primario su questo server, oppure se preferisci che quello vecchio resti tale. Potrai pubblicare da entrambi i server, ma solamente uno sarà indicato come posizione in cui risiedono i tuoi file, foto, ecc."; +$a->strings["Make this hub my primary location"] = "Rendi questo server il mio indirizzo primario"; +$a->strings["Import existing posts if possible"] = "Importazione dei post esistenti, se possibile"; +$a->strings["Item not found"] = "Elemento non trovato"; +$a->strings["Edit Layout"] = "Modifica il layout"; +$a->strings["Delete layout?"] = "Vuoi eliminare questo layout?"; +$a->strings["Insert YouTube video"] = "Inserisci video da YouTube"; +$a->strings["Insert Vorbis [.ogg] video"] = "Inserisci video Vorbis [.ogg]"; +$a->strings["Insert Vorbis [.ogg] audio"] = "Inserisci audio Vorbis [.ogg]"; +$a->strings["Delete Layout"] = "Elimina il layout"; +$a->strings["You must be logged in to see this page."] = "Devi aver effettuato l'accesso per vedere questa pagina."; +$a->strings["Room not found"] = "Area chat non trovata"; +$a->strings["Leave Room"] = "Lascia l'area chat"; +$a->strings["Delete This Room"] = "Elimina questa area chat"; +$a->strings["I am away right now"] = "Non sono presente"; +$a->strings["I am online"] = "Sono online"; +$a->strings["Bookmark this room"] = "Aggiungi l'area chat ai segnalibri"; +$a->strings["New Chatroom"] = "Nuova area chat"; +$a->strings["Chatroom Name"] = "Nome dell'area chat"; +$a->strings["%1\$s's Chatrooms"] = "Le aree chat di %1\$s"; +$a->strings["Delete webpage?"] = "Vuoi eliminare questa pagina web?"; +$a->strings["Page link title"] = "Link del titolo"; +$a->strings["Edit Webpage"] = "Modifica la pagina web"; +$a->strings["This directory server requires an access token"] = "Questo server di elenchi pubblici necessita di un token di autenticazione"; +$a->strings["No valid account found."] = "Nessun account valido trovato."; +$a->strings["Password reset request issued. Check your email."] = "La richiesta per reimpostare la password è stata inviata. Controlla la tua email."; +$a->strings["Site Member (%s)"] = "Utente del sito (%s)"; +$a->strings["Password reset requested at %s"] = "È stato richiesto di reimpostare password su %s"; +$a->strings["Request could not be verified. (You may have previously submitted it.) Password reset failed."] = "La richiesta non può essere verificata (potresti averla già usata precedentemente). La password non sarà reimpostata."; +$a->strings["Password Reset"] = "Reimposta la password"; +$a->strings["Your password has been reset as requested."] = "La password è stata reimpostata come richiesto."; +$a->strings["Your new password is"] = "La tua nuova password è"; +$a->strings["Save or copy your new password - and then"] = "Salva o copia la tua nuova password, quindi"; +$a->strings["click here to login"] = "clicca qui per accedere"; +$a->strings["Your password may be changed from the Settings page after successful login."] = "Puoi cambiare la tua password dalla pagina delle Impostazioni dopo aver effettuato l'accesso."; +$a->strings["Your password has changed at %s"] = "La tua password su %s è cambiata"; +$a->strings["Forgot your Password?"] = "Hai dimenticato la password?"; +$a->strings["Enter your email address and submit to have your password reset. Then check your email for further instructions."] = "Inserisci il tuo indirizzo email per reimpostare la password. Dopo aver inviato la richiesta, controlla l'email e troverai le istruzioni per continuare."; +$a->strings["Email Address"] = "Indirizzo email"; +$a->strings["Reset"] = "Reimposta"; +$a->strings["Website:"] = "Sito web:"; +$a->strings["Remote Channel [%s] (not yet known on this site)"] = "Canale remoto [%s] (non ancora conosciuto da questo sito)"; +$a->strings["Rating (this information is public)"] = "Valutazione (visibile a tutti)"; +$a->strings["Optionally explain your rating (this information is public)"] = "Commento alla valutazione (facoltativo, visibile a tutti)"; +$a->strings["Item is not editable"] = "L'elemento non è modificabile"; +$a->strings["Delete item?"] = "Eliminare questo elemento?"; +$a->strings["Total invitation limit exceeded."] = "Hai superato il numero massimo di inviti."; +$a->strings["%s : Not a valid email address."] = "%s: non è un indirizzo email valido."; +$a->strings["Please join us on Red"] = "Vieni con noi su Hubzilla"; +$a->strings["Invitation limit exceeded. Please contact your site administrator."] = "Hai superato il numero massimo di inviti. Contatta l'amministratore se necessario."; +$a->strings["%s : Message delivery failed."] = "%s: la consegna del messaggio è fallita."; +$a->strings["%d message sent."] = array( + 0 => "%d messaggio inviato.", + 1 => "%d messaggi inviati.", +); +$a->strings["You have no more invitations available"] = "Non hai altri inviti disponibili"; +$a->strings["Send invitations"] = "Spedisci inviti"; +$a->strings["Enter email addresses, one per line:"] = "Inserisci gli indirizzi email, uno per riga:"; +$a->strings["Your message:"] = "Il tuo messaggio:"; +$a->strings["Please join my community on Hubzilla."] = "Entra a far parte della mia comunità su Hubzilla."; +$a->strings["You will need to supply this invitation code: "] = "Dovrai fornire questo codice di invito:"; +$a->strings["1. Register at any Hubzilla location (they are all inter-connected)"] = "1. Registrati su un qualsiasi sito Hubzilla (sono tutti interconnessi)"; +$a->strings["2. Enter my Hubzilla network address into the site searchbar."] = "2. Inserisci il mio indirizzo Hubzilla nella barra di ricerca che compare nella pagina."; +$a->strings["or visit "] = "oppure visita "; +$a->strings["3. Click [Connect]"] = "3. Clicca su [Aggiungi]"; +$a->strings["Location not found."] = "Indirizzo non trovato."; +$a->strings["Primary location cannot be removed."] = "L'indirizzo principale non può essere rimosso."; +$a->strings["No locations found."] = "Nessun indirizzo trovato."; +$a->strings["Manage Channel Locations"] = "Modifica gli indirizzi del canale"; +$a->strings["Location (address)"] = "Indirizzo"; +$a->strings["Primary Location"] = "Indirizzo primario"; +$a->strings["Drop location"] = "Elimina un indirizzo"; +$a->strings["Failed to create source. No channel selected."] = "Impossibile creare la sorgente. Nessun canale selezionato."; +$a->strings["Source created."] = "Sorgente creata."; +$a->strings["Source updated."] = "Sorgente aggiornata."; +$a->strings["*"] = "*"; +$a->strings["Manage remote sources of content for your channel."] = "Gestisci le sorgenti dei contenuti del tuo canale."; +$a->strings["New Source"] = "Nuova sorgente"; +$a->strings["Import all or selected content from the following channel into this channel and distribute it according to your channel settings."] = "Importa nel tuo canale tutti o una parte dei contenuti dal canale seguente."; +$a->strings["Only import content with these words (one per line)"] = "Importa solo i contenuti che hanno queste parole (una per riga)"; +$a->strings["Leave blank to import all public content"] = "Lascia vuoto per importare tutti i contenuti pubblici"; +$a->strings["Channel Name"] = "Nome del canale"; +$a->strings["Source not found."] = "Sorgente non trovata."; +$a->strings["Edit Source"] = "Modifica la sorgente"; +$a->strings["Delete Source"] = "Elimina la sorgente"; +$a->strings["Source removed"] = "Sorgente eliminata"; +$a->strings["Unable to remove source."] = "Impossibile rimuovere la sorgente."; +$a->strings["Unable to update menu."] = "Impossibile aggiornare il menù."; +$a->strings["Unable to create menu."] = "Impossibile creare il menù."; +$a->strings["Menu Name"] = "Nome del menu"; +$a->strings["Unique name (not visible on webpage) - required"] = "Identificativo unico (non visibile sulla pagina) - obbligatorio"; +$a->strings["Menu Title"] = "Titolo del menu"; +$a->strings["Visible on webpage - leave empty for no title"] = "Visibile sulla pagina - lascia vuoto per non avere un titolo"; +$a->strings["Allow Bookmarks"] = "Permetti l'aggiunta ai segnalibri"; +$a->strings["Menu may be used to store saved bookmarks"] = "Puoi salvare i segnalibri nei menù"; +$a->strings["Submit and proceed"] = "Salva e procedi"; +$a->strings["Drop"] = "Elimina"; +$a->strings["Bookmarks allowed"] = "Permetti segnalibri"; +$a->strings["Delete this menu"] = "Elimina questo menù"; +$a->strings["Edit menu contents"] = "Modifica i contenuti del menù"; +$a->strings["Edit this menu"] = "Modifica questo menù"; +$a->strings["Menu could not be deleted."] = "Il menù non può essere eliminato."; +$a->strings["Menu not found."] = "Menù non trovato."; +$a->strings["Edit Menu"] = "Modifica menù"; +$a->strings["Add or remove entries to this menu"] = "Aggiungi o rimuovi elementi di questo menù"; +$a->strings["Menu name"] = "Nome del menù"; +$a->strings["Must be unique, only seen by you"] = "Deve essere unico, lo vedrai solo tu"; +$a->strings["Menu title"] = "Titolo del menù"; +$a->strings["Menu title as seen by others"] = "Titolo del menù come comparirà a tutti"; +$a->strings["Allow bookmarks"] = "Permetti l'invio di segnalibri"; +$a->strings["Modify"] = "Modifica"; +$a->strings["Permission Denied."] = "Permesso negato."; +$a->strings["File not found."] = "File non trovato."; +$a->strings["Edit file permissions"] = "Modifica i permessi del file"; +$a->strings["Set/edit permissions"] = "Modifica i permessi"; +$a->strings["Include all files and sub folders"] = "Includi tutti i file e le sottocartelle"; +$a->strings["Return to file list"] = "Torna all'elenco dei file"; +$a->strings["Copy/paste this code to attach file to a post"] = "Copia/incolla questo codice per far comparire il file in un articolo"; +$a->strings["Copy/paste this URL to link file from a web page"] = "Copia/incolla questo indirizzo in una pagina web per avere un link al file"; +$a->strings["Share this file"] = "Condividi questo file"; +$a->strings["Show URL to this file"] = "Mostra l'URL del file"; +$a->strings["Notify your contacts about this file"] = "Notifica ai tuoi contatti che hai caricato il file"; +$a->strings["Contact not found."] = "Contatto non trovato."; +$a->strings["Friend suggestion sent."] = "Suggerimento di amicizia inviato."; +$a->strings["Suggest Friends"] = "Suggerisci amici"; +$a->strings["Suggest a friend for %s"] = "Suggerisci un amico a %s"; +$a->strings["Hub not found."] = "Server non trovato."; +$a->strings["Poke/Prod"] = "Poke/Prod"; +$a->strings["poke, prod or do other things to somebody"] = "Manda un poke, un prod o altro"; +$a->strings["Recipient"] = "Destinatario"; +$a->strings["Choose what you wish to do to recipient"] = "Scegli cosa vuoi inviare al destinatario"; +$a->strings["Make this post private"] = "Rendi privato questo articolo"; +$a->strings["Invalid profile identifier."] = "Indentificativo del profilo non valido."; +$a->strings["Profile Visibility Editor"] = "Modifica la visibilità del profilo"; +$a->strings["Click on a contact to add or remove."] = "Clicca su un contatto per aggiungerlo o rimuoverlo."; +$a->strings["Visible To"] = "Visibile a"; +$a->strings["Page Title"] = "Titolo della pagina"; +$a->strings["Profile not found."] = "Profilo non trovato."; +$a->strings["Profile deleted."] = "Profilo eliminato."; +$a->strings["Profile-"] = "Profilo-"; +$a->strings["New profile created."] = "Il nuovo profilo è stato creato."; +$a->strings["Profile unavailable to clone."] = "Impossibile duplicare il profilo."; +$a->strings["Profile unavailable to export."] = "Il profilo non è disponibile per l'export."; +$a->strings["Profile Name is required."] = "Il nome del profilo è obbligatorio ."; +$a->strings["Marital Status"] = "Stato sentimentale"; +$a->strings["Romantic Partner"] = "Partner affettivo"; +$a->strings["Likes"] = "Mi piace"; +$a->strings["Dislikes"] = "Non mi piace"; +$a->strings["Work/Employment"] = "Lavoro/impiego"; +$a->strings["Religion"] = "Religione"; +$a->strings["Political Views"] = "Orientamento politico"; +$a->strings["Gender"] = "Sesso"; +$a->strings["Sexual Preference"] = "Preferenze sessuali"; +$a->strings["Homepage"] = "Home page"; +$a->strings["Interests"] = "Interessi"; +$a->strings["Address"] = "Indirizzo"; +$a->strings["Profile updated."] = "Profilo aggiornato."; +$a->strings["Hide your contact/friend list from viewers of this profile?"] = "Nascondi la tua lista di contatti/amici ai visitatori di questo profilo?"; +$a->strings["Edit Profile Details"] = "Modifica i dettagli del profilo"; +$a->strings["View this profile"] = "Guarda questo profilo"; +$a->strings["Change Profile Photo"] = "Cambia la foto del profilo"; +$a->strings["Create a new profile using these settings"] = "Crea un nuovo profilo usando queste impostazioni"; +$a->strings["Clone this profile"] = "Clona questo profilo"; +$a->strings["Delete this profile"] = "Elimina questo profilo"; +$a->strings["Import profile from file"] = "Importa il profilo da un file"; +$a->strings["Export profile to file"] = "Esporta il profilo in un file"; +$a->strings["Profile Name:"] = "Nome del profilo:"; +$a->strings["Your Full Name:"] = "Il tuo nome completo:"; +$a->strings["Title/Description:"] = "Titolo/descrizione:"; +$a->strings["Your Gender:"] = "Sesso:"; +$a->strings["Birthday :"] = "Compleanno:"; +$a->strings["Street Address:"] = "Indirizzo (via/piazza):"; +$a->strings["Locality/City:"] = "Località:"; +$a->strings["Postal/Zip Code:"] = "CAP:"; +$a->strings["Country:"] = "Nazione:"; +$a->strings["Region/State:"] = "Regione/stato:"; +$a->strings[" Marital Status:"] = " Stato sentimentale:"; +$a->strings["Who: (if applicable)"] = "Con chi: (se possibile)"; +$a->strings["Examples: cathy123, Cathy Williams, cathy@example.com"] = "Per esempio: cathy123, Cathy Williams, cathy@example.com"; +$a->strings["Since [date]:"] = "dal [data]:"; +$a->strings["Homepage URL:"] = "Indirizzo home page:"; +$a->strings["Religious Views:"] = "Orientamento religioso:"; +$a->strings["Keywords:"] = "Parole chiave, tag:"; +$a->strings["Example: fishing photography software"] = "Per esempio: pesca fotografia programmazione"; +$a->strings["Used in directory listings"] = "Visibile nell'elenco pubblico di canali"; +$a->strings["Tell us about yourself..."] = "Raccontaci di te..."; +$a->strings["Hobbies/Interests"] = "Hobby/interessi"; +$a->strings["Contact information and Social Networks"] = "Contatti personali e i tuoi social network"; +$a->strings["My other channels"] = "I miei altri canali"; +$a->strings["Musical interests"] = "Interessi musicali"; +$a->strings["Books, literature"] = "Libri, letteratura"; +$a->strings["Television"] = "Televisione"; +$a->strings["Film/dance/culture/entertainment"] = "Film/danza/cultura/intrattenimento"; +$a->strings["Love/romance"] = "Amore"; +$a->strings["Work/employment"] = "Lavoro/impiego"; +$a->strings["School/education"] = "Scuola/educazione"; +$a->strings["This is your default profile."] = "Questo è il tuo profilo predefinito."; +$a->strings["Age: "] = "Età:"; +$a->strings["Edit/Manage Profiles"] = "Modifica/gestisci i profili"; +$a->strings["Add profile things"] = "Aggiungi Oggetti al profilo"; +$a->strings["Include desirable objects in your profile"] = "Aggiungi oggetti interessanti al tuo profilo"; +$a->strings["No ratings"] = "Nessuna valutazione"; +$a->strings["Ratings"] = "Valutazioni"; +$a->strings["Rating: "] = "Valutazione:"; +$a->strings["Website: "] = "Sito web:"; +$a->strings["Description: "] = "Descrizione:"; +$a->strings["Source of Item"] = "Sorgente"; +$a->strings["Unable to create element."] = "Impossibile creare l'elemento."; +$a->strings["Unable to update menu element."] = "Non è possibile aggiornare l'elemento del menù."; +$a->strings["Unable to add menu element."] = "Impossibile aggiungere l'elemento al menù."; +$a->strings["Menu Item Permissions"] = "Permessi del menu"; +$a->strings["Link Name"] = "Nome link"; +$a->strings["Link Target"] = "Destinazione link"; +$a->strings["Use Hubzilla magic-auth if available"] = "Usa l'autenticazione magica di Hubzilla, se disponibile"; +$a->strings["Open link in new window"] = "Apri il link in una nuova finestra"; +$a->strings["Order in list"] = "Ordine dell'elenco"; +$a->strings["Higher numbers will sink to bottom of listing"] = "I numeri più alti andranno in fondo all'elenco"; +$a->strings["Submit and finish"] = "Salva e termina"; +$a->strings["Submit and continue"] = "Salva e continua"; +$a->strings["Menu:"] = "Menu:"; +$a->strings["Edit menu"] = "Modifica il menù"; +$a->strings["Edit element"] = "Modifica l'elemento"; +$a->strings["Drop element"] = "Elimina l'elemento"; +$a->strings["New element"] = "Nuovo elemento"; +$a->strings["Edit this menu container"] = "Modifica il contenitore del menù"; +$a->strings["Add menu element"] = "Aggiungi un elemento al menù"; +$a->strings["Delete this menu item"] = "Elimina questo elemento del menù"; +$a->strings["Edit this menu item"] = "Modifica questo elemento del menù"; +$a->strings["Menu item not found."] = "L'elemento del menù non è stato trovato."; +$a->strings["Menu item deleted."] = "L'elemento del menù è stato eliminato."; +$a->strings["Menu item could not be deleted."] = "L'elemento del menù non può essere eliminato."; +$a->strings["Edit Menu Element"] = "Modifica l'elemento del menù"; +$a->strings["Link text"] = "Testo del link"; +$a->strings["URL of link"] = "Indirizzo del link"; +$a->strings["OpenID protocol error. No ID returned."] = "Errore del protocollo OpenID. Nessun ID ricevuto in risposta."; +$a->strings["Welcome %s. Remote authentication successful."] = "Ciao %s. L'autenticazione magica è avvenuta con successo."; +$a->strings["%d rating"] = array( + 0 => "%d valutazione", + 1 => "%d valutazioni", +); +$a->strings["Gender: "] = "Sesso:"; +$a->strings["Status: "] = "Stato:"; +$a->strings["Homepage: "] = "Homepage:"; +$a->strings["Hometown: "] = "Città dove vivo:"; +$a->strings["About: "] = "Informazioni:"; +$a->strings["Public Forum:"] = "Forum pubblico:"; +$a->strings["Keywords: "] = "Parole chiave:"; +$a->strings["Common connections: %s"] = "Contatti in comune: %s"; +$a->strings["Finding:"] = "Ricerca:"; +$a->strings["next page"] = "pagina successiva"; +$a->strings["previous page"] = "pagina precedente"; +$a->strings["No entries (some entries may be hidden)."] = "Nessun risultato (qualche elemento potrebbe essere nascosto)."; +$a->strings["Export Channel"] = "Esporta il canale"; +$a->strings["Export your basic channel information to a small file. This acts as a backup of your connections, permissions, profile and basic data, which can be used to import your data to a new hub, but\tdoes not contain your content."] = "Esporta le informazioni di base del tuo canale in un piccolo file. E' utile per avere un salvataggio di sicurezza dei tuoi contatti, del tuo profilo ed altre informazioni fondamentali. Può essere usato per importare il tuo canale su un nuovo server, ma\tnon include i contenuti, per esempio articoli e foto."; +$a->strings["Export Content"] = "Esporta i contenuti"; +$a->strings["Export your channel information and all the content to a JSON backup. This backs up all of your connections, permissions, profile data and all of your content, but is generally not suitable for importing a channel to a new hub as this file may be VERY large. Please be patient - it may take several minutes for this download to begin."] = "Esporta i dati del canale e i contenuti in un file in formato JSON. E' un salvataggio dei tuoi contatti, dei dati del profilo e anche di tutti i contenuti. Questa non è la soluzione opportuna per importare il tuo canale su un nuovo server, visto che il file potrebbe avere dimensioni NOTEVOLI. Devi pazientare - ci vorranno alcuni minuti per raccogliere i dati prima che inizi lo scaricamento."; +$a->strings["No connections."] = "Nessun contatto."; +$a->strings["Visit %s's profile [%s]"] = "Visita il profilo di %s [%s]"; +$a->strings["invalid target signature"] = "la firma ricevuta non è valida"; +$a->strings["Theme settings updated."] = "Le impostazioni del tema sono state aggiornate."; +$a->strings["Site"] = "Sito"; +$a->strings["Accounts"] = "Account"; +$a->strings["Channels"] = "Canali"; +$a->strings["Plugins"] = "Plugin"; +$a->strings["Themes"] = "Temi"; +$a->strings["Inspect queue"] = "Coda di attesa"; +$a->strings["Profile Config"] = "Configurazione del profilo"; +$a->strings["DB updates"] = "Aggiornamenti al DB"; +$a->strings["Logs"] = "Log"; +$a->strings["Plugin Features"] = "Plugin"; +$a->strings["User registrations waiting for confirmation"] = "Registrazioni in attesa"; +$a->strings["# Accounts"] = "# account"; +$a->strings["# blocked accounts"] = "# account bloccati"; +$a->strings["# expired accounts"] = "# account scaduti"; +$a->strings["# expiring accounts"] = "# account in scadenza"; +$a->strings["# Channels"] = "# canali"; +$a->strings["# primary"] = "# primari"; +$a->strings["# clones"] = "# cloni"; +$a->strings["Message queues"] = "Coda messaggi in uscita"; +$a->strings["Administration"] = "Amministrazione"; +$a->strings["Summary"] = "Riepilogo"; +$a->strings["Registered accounts"] = "Account creati"; +$a->strings["Pending registrations"] = "Registrazioni da approvare"; +$a->strings["Registered channels"] = "Canali creati"; +$a->strings["Active plugins"] = "Plugin attivi"; +$a->strings["Version"] = "Versione"; +$a->strings["Site settings updated."] = "Impostazioni del sito salvate correttamente."; +$a->strings["experimental"] = "sperimentale"; +$a->strings["unsupported"] = "non supportato"; +$a->strings["Yes - with approval"] = "Sì - con approvazione"; +$a->strings["My site is not a public server"] = "Non è un server pubblico"; +$a->strings["My site has paid access only"] = "È un servizio a pagamento"; +$a->strings["My site has free access only"] = "È un servizio gratuito"; +$a->strings["My site offers free accounts with optional paid upgrades"] = "È un servizio gratuito con opzioni aggiuntive a pagamento"; +$a->strings["Registration"] = "Registrazione"; +$a->strings["File upload"] = "Caricamento file"; +$a->strings["Policies"] = "Politiche"; +$a->strings["Site name"] = "Nome del sito"; +$a->strings["Banner/Logo"] = "Banner o logo"; +$a->strings["Administrator Information"] = "Informazioni sull'amministratore"; +$a->strings["Contact information for site administrators. Displayed on siteinfo page. BBCode can be used here"] = "Informazioni per contattare gli amministratori del sito. Saranno mostrate sulla pagina di informazioni. È consentito il BBcode"; +$a->strings["System language"] = "Lingua di sistema"; +$a->strings["System theme"] = "Tema di sistema"; +$a->strings["Default system theme - may be over-ridden by user profiles - change theme settings"] = "Il tema di sistema può essere cambiato dai profili dei singoli utenti - Cambia le impostazioni del tema"; +$a->strings["Mobile system theme"] = "Tema di sistema per dispositivi mobili"; +$a->strings["Theme for mobile devices"] = "Tema per i dispositivi mobili"; +$a->strings["Enable Diaspora Protocol"] = "Abilita la comunicazione con Diaspora"; +$a->strings["Communicate with Diaspora and Friendica - experimental"] = "Sperimentale - per comunicare con Diaspora e Friendica"; +$a->strings["Allow Feeds as Connections"] = "Permetti di aggiungere i feed come contatti"; +$a->strings["(Heavy system resource usage)"] = "(Uso intenso delle risorse di sistema!)"; +$a->strings["Maximum image size"] = "Dimensione massima immagini"; +$a->strings["Maximum size in bytes of uploaded images. Default is 0, which means no limits."] = "Massima dimensione in byte delle immagini caricate. Il default è 0, cioè nessun limite."; +$a->strings["Does this site allow new member registration?"] = "Questo sito permette a nuovi utenti di registrarsi?"; +$a->strings["Which best describes the types of account offered by this hub?"] = "Come descriveresti il tipo di servizio proposto da questo server?"; +$a->strings["Register text"] = "Testo di registrazione"; +$a->strings["Will be displayed prominently on the registration page."] = "Sarà mostrato ben visibile nella pagina di registrazione."; +$a->strings["Accounts abandoned after x days"] = "Account abbandonati dopo X giorni"; +$a->strings["Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit."] = "Eviterà di sprecare risorse di sistema controllando se i siti esterni hanno account abbandonati. Immettere 0 per non imporre nessun limite di tempo."; +$a->strings["Allowed friend domains"] = "Domini fidati e consentiti"; +$a->strings["Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains"] = "Elenco separato da virglola dei domini che possono stabilire amicizie con questo sito. Sono accettati caratteri jolly. Lascia vuoto per accettare connessioni da qualsiasi dominio."; +$a->strings["Allowed email domains"] = "Domini email consentiti"; +$a->strings["Comma separated list of domains which are allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains"] = "Elenco separato da virgola dei domini permessi come indirizzi email in fase di registrazione. Sono accettati caratteri jolly. Lascia vuoto per accettare qualsiasi dominio email"; +$a->strings["Not allowed email domains"] = "Domini email non consentiti"; +$a->strings["Comma separated list of domains which are not allowed in email addresses for registrations to this site. Wildcards are accepted. Empty to allow any domains, unless allowed domains have been defined."] = "Elenco separato da virgola dei domini permessi come indirizzi email in fase di registrazione a questo sito. Sono accettati caratteri jolly. Lascalo vuoto per accettare qualsiasi dominio."; +$a->strings["Block public"] = "Blocca pagine pubbliche"; +$a->strings["Check to block public access to all otherwise public personal pages on this site unless you are currently logged in."] = "Seleziona per impedire di vedere le pagine personali di questo sito a chi non ha effettuato l'accesso."; +$a->strings["Verify Email Addresses"] = "Verifica l'indirizzo email"; +$a->strings["Check to verify email addresses used in account registration (recommended)."] = "Attiva per richiedere la verifica degli indirizzi email dei nuovi utenti (consigliato)."; +$a->strings["Force publish"] = "Forza la publicazione del profilo"; +$a->strings["Check to force all profiles on this site to be listed in the site directory."] = "Seleziona per mostrare nell'elenco pubblico tutti i profili registrati su questo sito."; +$a->strings["Disable discovery tab"] = "Disabilita la funzione 'scopri'"; +$a->strings["Remove the tab in the network view with public content pulled from sources chosen for this site."] = "Nell'area della rete personale non comparirà più la scheda con i contenuti acquisiti da altri siti."; +$a->strings["No login on Homepage"] = "Non mostrare il login sulla homepage"; +$a->strings["Check to hide the login form from your sites homepage when visitors arrive who are not logged in (e.g. when you put the content of the homepage in via the site channel)."] = "Per nascondere la possibilità di fare login ai visitatori (per esempio, quando il contenuto della homepage del sito è alimentato da un canale)."; +$a->strings["Proxy user"] = "Utente proxy"; +$a->strings["Proxy URL"] = "URL proxy"; +$a->strings["Network timeout"] = "Timeout rete"; +$a->strings["Value is in seconds. Set to 0 for unlimited (not recommended)."] = "Valore in secondi. Imposta a 0 per illimitato (sconsigliato)."; +$a->strings["Delivery interval"] = "Recapito ritardato"; +$a->strings["Delay background delivery processes by this many seconds to reduce system load. Recommend: 4-5 for shared hosts, 2-3 for virtual private servers. 0-1 for large dedicated servers."] = "Numero di secondi di cui può essere ritardato il recapito, per ridurre il carico di sistema. Consigliati: 4-5 secondi per hosting condiviso, 2-3 per i VPS, 0-1 per grandi server dedicati."; +$a->strings["Poll interval"] = "Intervallo di polling"; +$a->strings["Delay background polling processes by this many seconds to reduce system load. If 0, use delivery interval."] = "Numero di secondi di cui può essere ritardato il polling in background, per ridurre il carico del sistema. Se 0, verrà usato lo stesso valore del 'Recapito ritardato'."; +$a->strings["Maximum Load Average"] = "Carico massimo medio"; +$a->strings["Maximum system load before delivery and poll processes are deferred - default 50."] = "Carico di sistema massimo perché i processi di recapito e polling siano ritardati - il valore predefinito è 50."; +$a->strings["Expiration period in days for imported (matrix/network) content"] = "Scadenza dei contenuti importati da altri siti (in giorni)"; +$a->strings["0 for no expiration of imported content"] = "0 per non avere scadenza"; +$a->strings["No server found"] = "Server non trovato"; +$a->strings["ID"] = "ID"; +$a->strings["for channel"] = "per canale"; +$a->strings["on server"] = "sul server"; +$a->strings["Status"] = "Stato"; +$a->strings["Server"] = "Server"; +$a->strings["Update has been marked successful"] = "L'aggiornamento è stato marcato come eseguito."; +$a->strings["Executing %s failed. Check system logs."] = "Fallita l'esecuzione di %s. Maggiori informazioni sui log di sistema."; +$a->strings["Update %s was successfully applied."] = "L'aggiornamento %s è terminato correttamente."; +$a->strings["Update %s did not return a status. Unknown if it succeeded."] = "L'aggiornamento %s non ha dato risposta. Impossibile determinare se è terminato correttamente."; +$a->strings["Update function %s could not be found."] = "Impossibile trovare la funzione di aggiornamento %s"; +$a->strings["No failed updates."] = "Nessun aggiornamento fallito."; +$a->strings["Failed Updates"] = "Aggiornamenti falliti."; +$a->strings["Mark success (if update was manually applied)"] = "Marca come eseguito (se applicato manualmente)."; +$a->strings["Attempt to execute this update step automatically"] = "Tenta di eseguire in automatico questo passaggio dell'aggiornamento."; +$a->strings["Queue Statistics"] = "Statistiche della coda"; +$a->strings["Total Entries"] = "Totale"; +$a->strings["Priority"] = "Priorità"; +$a->strings["Destination URL"] = "URL di destinazione"; +$a->strings["Mark hub permanently offline"] = "Questo hub è definitivamente offline"; +$a->strings["Empty queue for this hub"] = "Svuota la coda per questo hub"; +$a->strings["Last known contact"] = "Ultimo scambio dati"; +$a->strings["%s user blocked/unblocked"] = array( + 0 => "%s utente bloccato/sbloccato", + 1 => "%s utenti bloccati/sbloccati", +); +$a->strings["%s user deleted"] = array( + 0 => "%s utente cancellato", + 1 => "%s utenti cancellati", +); +$a->strings["Account not found"] = "Account non trovato"; +$a->strings["User '%s' blocked"] = "Utente '%s' bloccato"; +$a->strings["User '%s' unblocked"] = "Utente '%s' sbloccato"; +$a->strings["Users"] = "Utenti"; +$a->strings["select all"] = "seleziona tutti"; +$a->strings["User registrations waiting for confirm"] = "Richieste di registrazione in attesa di conferma"; +$a->strings["Request date"] = "Data richiesta"; +$a->strings["No registrations."] = "Nessuna registrazione."; +$a->strings["Approve"] = "Approva"; +$a->strings["Deny"] = "Nega"; +$a->strings["Block"] = "Blocca"; +$a->strings["Unblock"] = "Sblocca"; +$a->strings["Register date"] = "Data registrazione"; +$a->strings["Last login"] = "Ultimo accesso"; +$a->strings["Expires"] = "Con scadenza"; +$a->strings["Service Class"] = "Classe dell'account"; +$a->strings["Selected users will be deleted!\\n\\nEverything these users had posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "Gli utenti selezionati saranno eliminati!\\n\\nTutto quello che gli utenti hanno pubblicato su questo sito sarà permanentemente eliminato!\\n\\nConfermi?"; +$a->strings["The user {0} will be deleted!\\n\\nEverything this user has posted on this site will be permanently deleted!\\n\\nAre you sure?"] = "L'utente {0} sarà eliminato!\\n\\nTutto quello che ha pubblicato su questo sito sarà permanentemente eliminato!\\n\\nConfermi?"; +$a->strings["%s channel censored/uncensored"] = array( + 0 => "Censura modificata per %s canale", + 1 => "Censura modificata per %s canali", +); +$a->strings["%s channel deleted"] = array( + 0 => "%s canale è stato rimosso", + 1 => "%s canali sono stati rimossi", +); +$a->strings["Channel not found"] = "Canale non trovato"; +$a->strings["Channel '%s' deleted"] = "Il canale '%s' è stato rimosso"; +$a->strings["Channel '%s' uncensored"] = "Rimossa la censura dal canale '%s'"; +$a->strings["Channel '%s' censored"] = "Applicata una censura al canale '%s'"; +$a->strings["Censor"] = "Applica una censura"; +$a->strings["Uncensor"] = "Rimuovi la censura"; +$a->strings["UID"] = "UID"; +$a->strings["Selected channels will be deleted!\\n\\nEverything that was posted in these channels on this site will be permanently deleted!\\n\\nAre you sure?"] = "I canali selezionati saranno rimossi!\\n\\nTutto ciò che è stato pubblicato su questo server tramite questi canali sarà irreversibilmente eliminato!\\n\\nVuoi confermare?"; +$a->strings["The channel {0} will be deleted!\\n\\nEverything that was posted in this channel on this site will be permanently deleted!\\n\\nAre you sure?"] = "Il canale {0} sarà rimosso!\\n\\nTutto ciò che è stato pubblicato su questo server tramite questo canale sarà irreversibilmente eliminato!\\n\\nVuoi confermare?"; +$a->strings["Plugin %s disabled."] = "Plugin %s non attivo."; +$a->strings["Plugin %s enabled."] = "Plugin %s attivo."; +$a->strings["Disable"] = "Disattiva"; +$a->strings["Enable"] = "Attiva"; +$a->strings["Toggle"] = "Attiva/disattiva"; +$a->strings["Author: "] = "Autore:"; +$a->strings["Maintainer: "] = "Gestore:"; +$a->strings["No themes found."] = "Nessun tema trovato."; +$a->strings["Screenshot"] = "Istantanea dello schermo"; +$a->strings["[Experimental]"] = "[Sperimentale]"; +$a->strings["[Unsupported]"] = "[Non supportato]"; +$a->strings["Log settings updated."] = "Impostazioni di log aggiornate."; +$a->strings["Clear"] = "Pulisci"; +$a->strings["Debugging"] = "Debugging"; +$a->strings["Log file"] = "File di log"; +$a->strings["Must be writable by web server. Relative to your Red top-level directory."] = "Deve essere scrivibile dal web server. La posizione è relativa alla cartella dove è installato Hubzilla."; +$a->strings["Log level"] = "Livello di log"; +$a->strings["New Profile Field"] = "Nuovo campo del profilo"; +$a->strings["Field nickname"] = "Nome breve del campo"; +$a->strings["System name of field"] = "Nome di sistema del campo"; +$a->strings["Input type"] = "Tipo di dati"; +$a->strings["Field Name"] = "Nome del campo"; +$a->strings["Label on profile pages"] = "Etichetta da mostrare sulla pagina del profilo"; +$a->strings["Help text"] = "Testo di aiuto"; +$a->strings["Additional info (optional)"] = "Informazioni aggiuntive (opzionali)"; +$a->strings["Field definition not found"] = "Impossibile trovare la definizione del campo"; +$a->strings["Edit Profile Field"] = "Modifica campo del profilo"; +$a->strings["Unable to find your hub."] = "Impossibile raggiungere il tuo hub."; +$a->strings["Post successful."] = "Inviato!"; +$a->strings["Edit Block"] = "Modifica il riquadro"; +$a->strings["Delete block?"] = "Vuoi eliminare questo riquadro?"; +$a->strings["Maximum daily site registrations exceeded. Please try again tomorrow."] = "È stato superato il numero massimo giornaliero di registrazioni a questo sito. Riprova domani!"; +$a->strings["Please indicate acceptance of the Terms of Service. Registration failed."] = "Impossibile proseguire. Devi prima accettare le Condizioni d'Uso del servizio."; +$a->strings["Passwords do not match."] = "Le password non corrispondono."; +$a->strings["Registration successful. Please check your email for validation instructions."] = "La registrazione è terminata correttamente. Per continuare controlla l'email che ti è stata inviata."; +$a->strings["Your registration is pending approval by the site owner."] = "La tua richiesta è in attesa di approvazione da parte dell'amministratore del sito."; +$a->strings["Your registration can not be processed."] = "La tua registrazione non puo' essere processata."; +$a->strings["Registration on this site/hub is by approval only."] = "La registrazione su questo sito è soggetta ad approvazione."; +$a->strings["Register at another affiliated site/hub"] = "Registrati su un altro server affiliato"; +$a->strings["This site has exceeded the number of allowed daily account registrations. Please try again tomorrow."] = "Questo sito ha superato il numero di registrazioni giornaliere consentite. Prova di nuovo domani."; +$a->strings["Terms of Service"] = "Condizioni d'Uso"; +$a->strings["I accept the %s for this website"] = "Accetto le %s di questo sito"; +$a->strings["I am over 13 years of age and accept the %s for this website"] = "Ho più di 13 anni e accetto le %s di questo sito"; +$a->strings["Membership on this site is by invitation only."] = "Per registrarsi su questo sito è necessario un invito."; +$a->strings["Please enter your invitation code"] = "Inserisci il codice dell'invito"; +$a->strings["Your email address"] = "Il tuo indirizzo email"; +$a->strings["Choose a password"] = "Scegli una password"; +$a->strings["Please re-enter your password"] = "Ripeti la password per verifica"; +$a->strings["Account removals are not allowed within 48 hours of changing the account password."] = "Non è possibile eliminare il tuo account prima di 48 ore dall'ultimo cambio password."; +$a->strings["Remove This Account"] = "Elimina questo account"; +$a->strings["WARNING: "] = "ATTENZIONE:"; +$a->strings["This account and all its channels will be completely removed from the network. "] = "Questo account e tutti i suoi canali saranno completamente eliminati dalla rete."; +$a->strings["This action is permanent and can not be undone!"] = "Questo comando è definitivo e non può essere annullato!"; +$a->strings["Please enter your password for verification:"] = "Inserisci la tua password per verifica:"; +$a->strings["Remove this account, all its channels and all its channel clones from the network"] = "Elimina dalla rete questo account, tutti i suoi canali e ANCHE tutti gli eventuali canali clonati."; +$a->strings["By default only the instances of the channels located on this hub will be removed from the network"] = "A meno che tu non lo richieda espressamente, solo i canali presenti su questo server saranno rimossi dalla rete."; +$a->strings["Unable to locate original post."] = "Impossibile trovare il messaggio originale."; +$a->strings["Empty post discarded."] = "L'articolo vuoto è stato ignorato."; +$a->strings["Executable content type not permitted to this channel."] = "I contenuti eseguibili non sono permessi su questo canale."; +$a->strings["System error. Post not saved."] = "Errore di sistema. Articolo non salvato."; +$a->strings["Unable to obtain post information from database."] = "Impossibile caricare l'articolo dal database."; +$a->strings["You have reached your limit of %1$.0f top level posts."] = "Hai raggiunto il limite massimo di %1$.0f articoli sulla pagina principale."; +$a->strings["You have reached your limit of %1$.0f webpages."] = "Hai raggiunto il limite massimo di %1$.0f pagine web."; +$a->strings["[Embedded content - reload page to view]"] = "[Contenuto incorporato - ricarica la pagina per visualizzarlo correttamente]"; +$a->strings["Remote privacy information not available."] = "Le informazioni remote sulla privacy non sono disponibili."; +$a->strings["Visible to:"] = "Visibile a:"; +$a->strings["Block Name"] = "Nome del riquadro"; +$a->strings["First Name"] = "Nome"; +$a->strings["Last Name"] = "Cognome"; +$a->strings["Nickname"] = "Nick"; +$a->strings["Full Name"] = "Nome e cognome"; +$a->strings["Profile Photo 16px"] = "Foto del profilo 16px"; +$a->strings["Profile Photo 32px"] = "Foto del profilo 32px"; +$a->strings["Profile Photo 48px"] = "Foto del profilo 48px"; +$a->strings["Profile Photo 64px"] = "Foto del profilo 64px"; +$a->strings["Profile Photo 80px"] = "Foto del profilo 80px"; +$a->strings["Profile Photo 128px"] = "Foto del profilo 128px"; +$a->strings["Timezone"] = "Fuso orario"; +$a->strings["Homepage URL"] = "Indirizzo home page"; +$a->strings["Birth Year"] = "Anno di nascita"; +$a->strings["Birth Month"] = "Mese di nascita"; +$a->strings["Birth Day"] = "Giorno di nascita"; +$a->strings["Birthdate"] = "Data di nascita"; +$a->strings["Conversation removed."] = "Conversazione rimossa."; +$a->strings["No messages."] = "Nessun messaggio."; +$a->strings["Delete conversation"] = "Elimina la conversazione"; +$a->strings["D, d M Y - g:i A"] = "D d M Y - G:i"; +$a->strings["Help with this feature"] = "La guida per questa funzionalità"; +$a->strings["Layout Name"] = "Nome layout"; +$a->strings["Comanche page description language help"] = "Guida di Comanche Page Description Language"; +$a->strings["Set your current mood and tell your friends"] = "Scegli il tuo umore attuale per mostrarlo agli amici"; +$a->strings["Total votes"] = "Voti totali"; +$a->strings["Average Rating"] = "Valutazione media"; +$a->strings["Channel removals are not allowed within 48 hours of changing the account password."] = "Non è possibile eliminare un canale prima di 48 ore dall'ultimo cambio password."; +$a->strings["Remove This Channel"] = "Elimina questo canale"; +$a->strings["This channel will be completely removed from the network. "] = "Questo canale sarà completamente eliminato dalla rete."; +$a->strings["Remove this channel and all its clones from the network"] = "Rimuovi questo canale e tutti i suoi cloni dalla rete"; +$a->strings["By default only the instance of the channel located on this hub will be removed from the network"] = "L'impostazione predefinita è che sia eliminata solo l'istanza del canale presente su questo hub, non gli eventuali cloni"; +$a->strings["is now connected to"] = "ha come nuovo contatto"; +$a->strings["Could not access address book record."] = "Impossibile accedere alle informazioni della rubrica."; +$a->strings["Refresh failed - channel is currently unavailable."] = "Il canale non è disponibile - impossibile aggiornare."; +$a->strings["Channel has been unblocked"] = "Il canale è stato sbloccato"; +$a->strings["Channel has been blocked"] = "Il canale è stato bloccato"; +$a->strings["Unable to set address book parameters."] = "Impossibile impostare i parametri della rubrica."; +$a->strings["Channel has been unignored"] = "Il canale non sarà più ignorato"; +$a->strings["Channel has been ignored"] = "Il canale sarà ignorato"; +$a->strings["Channel has been unarchived"] = "Il canale non è più archiviato"; +$a->strings["Channel has been archived"] = "Il canale è stato archiviato"; +$a->strings["Channel has been unhidden"] = "Il canale non è più nascosto"; +$a->strings["Channel has been hidden"] = "Il canale è stato nascosto"; +$a->strings["Channel has been approved"] = "Il canale è stato approvato"; +$a->strings["Channel has been unapproved"] = "Il canale non è più approvato"; +$a->strings["Connection has been removed."] = "Il contatto è stato rimosso."; +$a->strings["View %s's profile"] = "Guarda il profilo di %s"; +$a->strings["Refresh Permissions"] = "Modifica i permessi"; +$a->strings["Fetch updated permissions"] = "Guarda e modifica i permessi assegnati"; +$a->strings["Recent Activity"] = "Attività recenti"; +$a->strings["View recent posts and comments"] = "Leggi i post recenti e i commenti"; +$a->strings["Block (or Unblock) all communications with this connection"] = "Blocca ogni interazione con questo contatto (abilita/disabilita)"; +$a->strings["Unignore"] = "Non ignorare"; +$a->strings["Ignore"] = "Ignora"; +$a->strings["Ignore (or Unignore) all inbound communications from this connection"] = "Ignora tutte le comunicazioni in arrivo da questo contatto (abilita/disabilita)"; +$a->strings["Unarchive"] = "Non archiviare"; +$a->strings["Archive"] = "Archivia"; +$a->strings["Archive (or Unarchive) this connection - mark channel dead but keep content"] = "Archivia questo contatto (abilita/disabilita) - segna il canale come non più attivo ma ne conserva i contenuti"; +$a->strings["Unhide"] = "Non nascondere"; +$a->strings["Hide"] = "Nascondi"; +$a->strings["Hide or Unhide this connection from your other connections"] = "Nascondi questo contatto a tutti gli altri (abilita/disabilita)"; +$a->strings["Delete this connection"] = "Elimina questo contatto"; +$a->strings["Approve this connection"] = "Approva questo contatto"; +$a->strings["Accept connection to allow communication"] = "Entra in contatto per poter comunicare"; +$a->strings["Connections: settings for %s"] = "Contatti: impostazioni per %s"; +$a->strings["Apply these permissions automatically"] = "Applica automaticamente questi permessi"; +$a->strings["Apply the permissions indicated on this page to all new connections."] = "Applica i permessi indicati su questa pagina a tutti i nuovi contatti."; +$a->strings["Slide to adjust your degree of friendship"] = "Trascina per restringere il grado di amicizia da mostrare"; +$a->strings["Default permissions for your channel type have (just) been applied. They have not yet been submitted. Please review the permissions on this page and make any desired changes at this time. This new connection may not be able to communicate with you until you submit this page, which will install and apply the selected permissions."] = "I tuoi nuovi contatti potrebbero non essere abilitati a comunicare con te finché non salverai questa pagina (perché non hai permessi impostati). Sono stati selezionati i permessi standard per il tipo di canale che hai scelto. Non sono stati ancora salvati però. Puoi verificare le impostazioni e fare i cambiamenti che preferisci prima di salvare. "; +$a->strings["inherited"] = "derivato"; +$a->strings["Connection has no individual permissions!"] = "Non hai assegnato permessi individuali a questo contatto!"; +$a->strings["This may be appropriate based on your privacy settings, though you may wish to review the \"Advanced Permissions\"."] = "Questo corrisponde alle tue impostazioni di privacy, ma puoi anche dare un'occhiata ai 'Permessi avanzati' per opzioni più dettagliate."; +$a->strings["Profile Visibility"] = "Visibilità del profilo"; +$a->strings["Please choose the profile you would like to display to %s when viewing your profile securely."] = "Seleziona il profilo che vuoi mostrare a %s quando visita il tuo profilo in modo sicuro."; +$a->strings["Contact Information / Notes"] = "Informazioni e annotazioni sul contatto"; +$a->strings["Edit contact notes"] = "Modifica le informazioni sul contatto"; +$a->strings["Their Settings"] = "Permessi concessi a te"; +$a->strings["My Settings"] = "I permessi che concedo"; +$a->strings["Default permissions for this channel type have (just) been applied. They have not been saved and there are currently no stored default permissions. Please review/edit the applied settings and click [Submit] to finalize."] = "A questo canale sono stati applicati i permessi predefiniti ma non sono stati salvati. In realtà non esistono ancora dei permessi predefiniti da usare su questo sito. Controlla e verifica le impostazioni, [Salva] per confermare."; +$a->strings["Clear/Disable Automatic Permissions"] = "Rimuovi/disabilita i permessi automatici"; +$a->strings["Forum Members"] = "Membro di un forum"; +$a->strings["Soapbox"] = "Comunicati e annunci"; +$a->strings["Full Sharing (typical social network permissions)"] = "Condivisione completa (permessi tipici dei social network)"; +$a->strings["Cautious Sharing "] = "Condivisione prudente"; +$a->strings["Follow Only"] = "Follower"; +$a->strings["Individual Permissions"] = "Permessi individuali"; +$a->strings["Some permissions may be inherited from your channel privacy settings, which have higher priority than individual settings. Changing those inherited settings on this page will have no effect."] = "I permessi nelle impostazioni di privacy hanno priorità su quelli mostrati in questa pagina. Non avrà alcun effetto cambiarli qui, se sono indicati come derivati."; +$a->strings["Advanced Permissions"] = "Permessi avanzati"; +$a->strings["Simple Permissions (select one and submit)"] = "Permessi semplificati (seleziona e salva)"; +$a->strings["Visit %s's profile - %s"] = "Guarda il profilo di %s - %s"; +$a->strings["Block/Unblock contact"] = "Blocca/sblocca contatto"; +$a->strings["Ignore contact"] = "Ignora il contatto"; +$a->strings["Repair URL settings"] = "Ripara le impostazioni URL"; +$a->strings["View conversations"] = "Leggi le conversazioni"; +$a->strings["Delete contact"] = "Elimina contatto"; +$a->strings["Last update:"] = "Ultimo aggiornamento:"; +$a->strings["Update public posts"] = "Aggiorna gli articoli pubblici"; +$a->strings["Update now"] = "Aggiorna adesso"; +$a->strings["Currently blocked"] = "Attualmente bloccato"; +$a->strings["Currently ignored"] = "Attualmente ignorato"; +$a->strings["Currently archived"] = "Attualmente archiviato"; +$a->strings["Currently pending"] = "Attualmente da approvare"; +$a->strings["We encountered a problem while logging in with the OpenID you provided. Please check the correct spelling of the ID."] = "Non è possibile effettuare login con l'OpenID che hai fornito. Per favore controlla che sia scritto correttamente."; +$a->strings["The error message was:"] = "Messaggio di errore ricevuto:"; +$a->strings["Authentication failed."] = "Autenticazione fallita."; +$a->strings["Remote Authentication"] = "Autenticazione a distanza"; +$a->strings["Enter your channel address (e.g. channel@example.com)"] = "Inserisci l'indirizzo del tuo canale (ad esempio lucia@esempio.com)"; +$a->strings["Authenticate"] = "Autenticazione"; +$a->strings["Unable to lookup recipient."] = "Impossibile associare un destinatario."; +$a->strings["Unable to communicate with requested channel."] = "Impossibile comunicare con il canale richiesto."; +$a->strings["Cannot verify requested channel."] = "Impossibile verificare il canale richiesto."; +$a->strings["Selected channel has private message restrictions. Send failed."] = "Il canale ha delle regole restrittive per la ricezione dei messaggi privati. Invio fallito."; +$a->strings["Message deleted."] = "Messaggio eliminato."; +$a->strings["Message recalled."] = "Messaggio revocato."; +$a->strings["Send Private Message"] = "Invia un messaggio privato"; +$a->strings["To:"] = "A:"; +$a->strings["Subject:"] = "Oggetto:"; +$a->strings["Send"] = "Invia"; +$a->strings["Message not found."] = "Messaggio non trovato."; +$a->strings["Delete message"] = "Elimina il messaggio"; +$a->strings["Recall message"] = "Revoca il messaggio"; +$a->strings["Message has been recalled."] = "Il messaggio è stato revocato."; +$a->strings["Private Conversation"] = "Conversazione privata"; +$a->strings["No secure communications available. You may be able to respond from the sender's profile page."] = "Non è disponibile alcuna tecnologia per comunicare in modo sicuro. Se possibile, prova a rispondere direttamente dalla pagina del profilo del mittente."; +$a->strings["Send Reply"] = "Invia la risposta"; +$a->strings["Invalid request identifier."] = "L'identificativo della richiesta non è valido."; +$a->strings["Discard"] = "Rifiuta"; +$a->strings["Please login."] = "Effettua l'accesso."; +$a->strings["Remote authentication blocked. You are logged into this site locally. Please logout and retry."] = "L'autenticazione magica dal tuo sito non è disponibile. Hai accesso solamente a questo sito. Puoi provare a disconnetterti per tentare di nuovo."; +$a->strings["Add a Channel"] = "Aggiungi un canale"; +$a->strings["A channel is your own collection of related web pages. A channel can be used to hold social network profiles, blogs, conversation groups and forums, celebrity pages, and much more. You may create as many channels as your service provider allows."] = "I contenuti che pubblichi sono mostrati nel tuo \"canale\". Un canale può essere usato come bacheca personale, come blog, oppure può essere un forum di discussione, un gruppo di interesse, una pagina di celebrità e molto altro. Puoi creare tanti canali quanti ne permette il tuo sito."; +$a->strings["Examples: \"Bob Jameson\", \"Lisa and her Horses\", \"Soccer\", \"Aviation Group\" "] = "Per esempio: \"Mario Rossi\", \"Lisa e le sue ricette\", \"Il campionato\", \"Il gruppo di escursionismo\""; +$a->strings["Choose a short nickname"] = "Scegli un nome breve"; +$a->strings["Your nickname will be used to create an easily remembered channel address (like an email address) which you can share with others."] = "Il nome breve sarà usato per creare un indirizzo facile da ricordare per il tuo canale (simile a una email). Così potrai condividerlo e gli altri potranno trovarti."; +$a->strings["Or import an existing channel from another location"] = "Oppure importa un tuo canale esistente da un altro server/hub"; +$a->strings["Please choose a channel type (such as social networking or community forum) and privacy requirements so we can select the best permissions for you"] = "Descrivi il tipo di canale che vorresti creare (per esempio se ti interessa più usarlo come social network, come un forum di discussione...) e il tipo di privacy che preferisci. Hubzilla sceglierà per te i permessi più adatti."; +$a->strings["Channel Type"] = "Tipo di canale"; +$a->strings["Read more about roles"] = "Maggiori informazioni sui ruoli"; +$a->strings["App installed."] = "App installata"; +$a->strings["Malformed app."] = "App non corretta"; +$a->strings["Embed code"] = "Inserisci del codice"; +$a->strings["Edit App"] = "Modifica app"; +$a->strings["Create App"] = "Crea una app"; +$a->strings["Name of app"] = "Nome app"; +$a->strings["Location (URL) of app"] = "Indirizzo (URL) della app"; +$a->strings["Photo icon URL"] = "URL icona"; +$a->strings["80 x 80 pixels - optional"] = "80 x 80 pixel - facoltativa"; +$a->strings["Version ID"] = "ID versione"; +$a->strings["Price of app"] = "Prezzo app"; +$a->strings["Location (URL) to purchase app"] = "Indirizzo (URL) per acquistare la app"; +$a->strings["sent you a private message"] = "ti ha inviato un messaggio privato"; +$a->strings["added your channel"] = "ha aggiunto il tuo canale"; +$a->strings["posted an event"] = "ha creato un evento"; +$a->strings["No such group"] = "Impossibile trovare l'insieme"; +$a->strings["No such channel"] = "Canale sconosciuto"; +$a->strings["Search Results For:"] = "Cerca risultati con:"; +$a->strings["Collection is empty"] = "L'insieme di canali è vuoto"; +$a->strings["Collection: "] = "Insieme:"; +$a->strings["Connection: "] = "Contatto:"; +$a->strings["Invalid connection."] = "Contatto non valido."; +$a->strings["Ipsum Lorem"] = "Ipsum Lorem"; +$a->strings["Bookmark added"] = "Segnalibro aggiunto"; +$a->strings["My Bookmarks"] = "I miei segnalibri"; +$a->strings["My Connections Bookmarks"] = "I segnalibri dei miei contatti"; +$a->strings["Insufficient permissions. Request redirected to profile page."] = "Permessi insufficienti. Sarà visualizzata la pagina del profilo."; +$a->strings["No suggestions available. If this is a new site, please try again in 24 hours."] = "Nessun suggerimento disponibile. Se questo sito è nuovo, riprova tra 24 ore."; +$a->strings["Poll"] = "Sondaggio"; +$a->strings["View Results"] = "Guarda i risultati"; +$a->strings["No service class restrictions found."] = "Non esistono restrizioni su questa classe di account."; +$a->strings["Files: shared with me"] = "File: condivisi con me"; +$a->strings["NEW"] = "NOVITÀ"; +$a->strings["Remove all files"] = "Elimina tutti i file"; +$a->strings["Remove this file"] = "Elimina questo file"; +$a->strings["Schema Default"] = "Schema predefinito"; +$a->strings["Sans-Serif"] = "Sans-serif"; +$a->strings["Monospace"] = "Monospace"; +$a->strings["Theme settings"] = "Impostazioni del tema"; +$a->strings["Set scheme"] = "Schema"; +$a->strings["Set font-size for posts and comments"] = "Dimensioni del carattere per articoli e commenti"; +$a->strings["Set font face"] = "Tipo di carattere"; +$a->strings["Set iconset"] = "Icone"; +$a->strings["Set big shadow size, default 15px 15px 15px"] = "Ombra grande, predefinita 15px 15px 15px"; +$a->strings["Set small shadow size, default 5px 5px 5px"] = "Ombra piccola, predefinita 5px 5px 5px"; +$a->strings["Set shadow color, default #000"] = "Colore dell'ombra, predefinito #000"; +$a->strings["Set radius size, default 5px"] = "Raggio degli angoli, predefinito 5px"; +$a->strings["Set line-height for posts and comments"] = "Altezza della riga per articoli e commenti"; +$a->strings["Set background image"] = "Immagine di sfondo"; +$a->strings["Set background attachment"] = "Allega uno sfondo"; +$a->strings["Set background color"] = "Colore di sfondo"; +$a->strings["Set section background image"] = "Immagine di sfondo della sezione"; +$a->strings["Set section background color"] = "Colore di sfondo dell'area principale"; +$a->strings["Set color of items - use hex"] = "Colore degli elementi della pagina - esadecimale"; +$a->strings["Set color of links - use hex"] = "Colore dei link - esadecimale"; +$a->strings["Set max-width for items. Default 400px"] = "Larghezza massima degli elementi della pagina. Predefinita: 400px"; +$a->strings["Set min-width for items. Default 240px"] = "Larghezza minima degli elementi della pagina. Predefinita: 240px"; +$a->strings["Set the generic content wrapper width. Default 48%"] = "Larghezza di tutta l'area dei contenuti. Predefinita: 48%"; +$a->strings["Set color of fonts - use hex"] = "Colore dei caratteri - esadecimale"; +$a->strings["Set background-size element"] = "Background-size element"; +$a->strings["Item opacity"] = "Opacità degli elementi della pagina"; +$a->strings["Display post previews only"] = "Mostra le anteprime solo degli articoli"; +$a->strings["Display side bar on channel page"] = "Mostra la colonna laterale sulla pagina del canale"; +$a->strings["Colour of the navigation bar"] = "Colore della barra di navigazione"; +$a->strings["Item float"] = "Float degli oggetti della pagina"; +$a->strings["Left offset of the section element"] = "Margine sinistro dell'area principale"; +$a->strings["Right offset of the section element"] = "Margine destro dell'area principale"; +$a->strings["Section width"] = "Larghezza dell'area principale"; +$a->strings["Left offset of the aside"] = "Margine sinistro della colonna laterale"; +$a->strings["Right offset of the aside element"] = "Margine destro della colonna laterale"; +$a->strings["Light (Hubzilla default)"] = "Light (predefinito)"; +$a->strings["Select scheme"] = "Scegli uno schema"; +$a->strings["Narrow navbar"] = "Barra di navigazione ristretta"; +$a->strings["Navigation bar background color"] = "Barra di navigazione: Colore di sfondo"; +$a->strings["Navigation bar gradient top color"] = "Barra di navigazione: Gradiente superiore"; +$a->strings["Navigation bar gradient bottom color"] = "Barra di navigazione: Gradiente inferiore"; +$a->strings["Navigation active button gradient top color"] = "Bottone di navigazione attivo: Gradiente superiore"; +$a->strings["Navigation active button gradient bottom color"] = "Bottone di navigazione attivo: Gradiente inferiore"; +$a->strings["Navigation bar border color "] = "Barra di navigazione: Colore del bordo"; +$a->strings["Navigation bar icon color "] = "Barra di navigazione: Colore delle icone"; +$a->strings["Navigation bar active icon color "] = "Barra di navigazione: Colore dell'icona attiva"; +$a->strings["link color"] = "colore del link"; +$a->strings["Set font-color for banner"] = "Colore del font del banner"; +$a->strings["Set the background color"] = "Imposta il colore di sfondo"; +$a->strings["Set the background image"] = "Immagine di sfondo"; +$a->strings["Set the background color of items"] = "Imposta il colore di sfondo degli oggetti"; +$a->strings["Set the background color of comments"] = "Imposta il colore di sfondo dei commenti"; +$a->strings["Set the border color of comments"] = "Imposta il colore del bordo dei commenti"; +$a->strings["Set the indent for comments"] = "Imposta il lo spostamento a destra dei commenti"; +$a->strings["Set the basic color for item icons"] = "Colore di base per le icone"; +$a->strings["Set the hover color for item icons"] = "Colore per le icone in mouse-over"; +$a->strings["Set font-size for the entire application"] = "Dimensione font per tutto il sito"; +$a->strings["Example: 14px"] = "Esempio: 14px"; +$a->strings["Set font-color for posts and comments"] = "Imposta il colore del carattere per articoli e commenti"; +$a->strings["Set radius of corners"] = "Raggio degli angoli stondati"; +$a->strings["Set shadow depth of photos"] = "Profondità dell'ombra delle foto"; +$a->strings["Set maximum width of content region in pixel"] = "Larghezza massima dell'area dei contenuti in pixel"; +$a->strings["Leave empty for default width"] = "Lascia vuoto per usare il valore predefinito"; +$a->strings["Center page content"] = "Centra il contenuto della pagina"; +$a->strings["Set minimum opacity of nav bar - to hide it"] = "Imposta l'opacità minima della barra di navigazione per nasconderla"; +$a->strings["Set size of conversation author photo"] = "Dimensione foto dell'autore della conversazione"; +$a->strings["Set size of followup author photos"] = "Dimensione foto dei partecipanti alla conversazione"; +$a->strings["Update %s failed. See error logs."] = "%s: aggiornamento fallito. Controlla i log di errore."; +$a->strings["Update Error at %s"] = "Errore di aggiornamento su %s"; +$a->strings["Create an account to access services and applications within the Hubzilla"] = "Registrati per accedere ai servizi e alle applicazioni di Hubzilla"; +$a->strings["Password"] = "Password"; +$a->strings["Remember me"] = "Resta connesso"; +$a->strings["Forgot your password?"] = "Hai dimenticato la password?"; +$a->strings["toggle mobile"] = "attiva/disattiva versione mobile"; +$a->strings["Website SSL certificate is not valid. Please correct."] = "Il certificato SSL del sito non è valido. Si prega di intervenire."; +$a->strings["[red] Website SSL error for %s"] = "[red] Errore SSL %s "; +$a->strings["Cron/Scheduled tasks not running."] = "Processi/cron non avviati."; +$a->strings["[red] Cron tasks not running on %s"] = "[red] Processi non avviati su %s"; +$a->strings["Source of Item"] = "Sorgente dell'Elemento"; diff --git a/sources/view/it/update_fail_eml.tpl b/sources/view/it/update_fail_eml.tpl new file mode 100644 index 00000000..97ab5220 --- /dev/null +++ b/sources/view/it/update_fail_eml.tpl @@ -0,0 +1,13 @@ +Ehilà! +Sono il tuo fedele server {{$sitename}}; + +Gli sviluppatori di Hubzilla hanno rilasciato l'update {{$update}}, +ma quando ho cercato di installarlo c'è stato qualcosa che non è filato liscio, per usare un eufemismo. +Dovrebbe essere effettuata al più presto una correzione, ma sarà necessario l'intervento umano. +Ti consiglio di contattare uno sviluppatore di Red se non riesci a capire come risolvere +il problema per conto tuo. Per esempio, il database potrebbe non essere più valido. + +Il messaggio di errore è '{{$error}}'. + +Sono mortificato per l'inconveniente, + Il tuo povero server web {{$siteurl}} \ No newline at end of file diff --git a/sources/view/js/acl.js b/sources/view/js/acl.js new file mode 100644 index 00000000..626d1a75 --- /dev/null +++ b/sources/view/js/acl.js @@ -0,0 +1,272 @@ +function ACL(backend_url, preset) { + that = this; + + that.url = backend_url; + + that.kp_timer = null; + + if (preset === undefined) preset = []; + that.allow_cid = (preset[0] || []); + that.allow_gid = (preset[1] || []); + that.deny_cid = (preset[2] || []); + that.deny_gid = (preset[3] || []); + that.group_uids = []; + that.nw = 4; //items per row. should be calulated from #acl-list.width + + that.list_content = $("#acl-list-content"); + that.item_tpl = unescape($(".acl-list-item[rel=acl-template]").html()); + that.showall = $("#acl-showall"); + + // set the initial ACL lists in case the enclosing form gets submitted before the ajax loader completes. + that.on_submit(); + + if (preset.length === 0) that.showall.removeClass("btn-default").addClass("btn-warning"); + + /*events*/ + + $(document).ready(function() { +// setTimeout( function() { + that.showall.click(that.on_showall); + $(document).on('click','.acl-button-show',that.on_button_show); + $(document).on('click','.acl-button-hide',that.on_button_hide); + $("#acl-search").keypress(that.on_search); + + /* startup! */ + that.get(0,100); + that.on_submit(); +// }, 5000 ); + }); +} + +// no longer called on submit - call to update whenever a change occurs to the acl list. + +ACL.prototype.on_submit = function() { + aclfileds = $("#acl-fields").html(""); + $(that.allow_gid).each(function(i,v) { + aclfileds.append(""); + }); + $(that.allow_cid).each(function(i,v) { + aclfileds.append(""); + }); + $(that.deny_gid).each(function(i,v) { + aclfileds.append(""); + }); + $(that.deny_cid).each(function(i,v) { + aclfileds.append(""); + }); + + //areYouSure jquery plugin: recheck the form here + $('form').trigger('checkform.areYouSure'); +}; + +ACL.prototype.search = function() { + var srcstr = $("#acl-search").val(); + that.list_content.html(""); + that.get(0, 100, srcstr); +}; + +ACL.prototype.on_search = function(event) { + if (that.kp_timer) clearTimeout(that.kp_timer); + that.kp_timer = setTimeout( that.search, 1000); +}; + +ACL.prototype.on_showall = function(event) { + event.preventDefault(); + event.stopPropagation(); + + if (that.showall.hasClass("btn-warning")) { + return false; + } + that.showall.removeClass("btn-default").addClass("btn-warning"); + + that.allow_cid = []; + that.allow_gid = []; + that.deny_cid = []; + that.deny_gid = []; + + that.update_view(); + that.on_submit(); + + return false; +}; + +ACL.prototype.on_button_show = function(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + event.stopPropagation(); + + /*that.showall.removeClass("selected"); + $(this).siblings(".acl-button-hide").removeClass("selected"); + $(this).toggleClass("selected");*/ + + that.set_allow($(this).parent().attr('id')); + that.on_submit(); + + return false; +}; + +ACL.prototype.on_button_hide = function(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + event.stopPropagation(); + + /*that.showall.removeClass("selected"); + $(this).siblings(".acl-button-show").removeClass("selected"); + $(this).toggleClass("selected");*/ + + that.set_deny($(this).parent().attr('id')); + that.on_submit(); + + return false; +}; + +ACL.prototype.set_allow = function(itemid) { + type = itemid[0]; + id = itemid.substr(1); + switch(type) { + case "g": + if (that.allow_gid.indexOf(id)<0) { + that.allow_gid.push(id); + }else { + that.allow_gid.remove(id); + } + if (that.deny_gid.indexOf(id)>=0) that.deny_gid.remove(id); + break; + case "c": + if (that.allow_cid.indexOf(id)<0) { + that.allow_cid.push(id); + } else { + that.allow_cid.remove(id); + } + if (that.deny_cid.indexOf(id)>=0) that.deny_cid.remove(id); + break; + } + that.update_view(); +}; + +ACL.prototype.set_deny = function(itemid) { + type = itemid[0]; + id = itemid.substr(1); + switch(type) { + case "g": + if (that.deny_gid.indexOf(id)<0) { + that.deny_gid.push(id); + } else { + that.deny_gid.remove(id); + } + if (that.allow_gid.indexOf(id)>=0) that.allow_gid.remove(id); + break; + case "c": + if (that.deny_cid.indexOf(id)<0) { + that.deny_cid.push(id); + } else { + that.deny_cid.remove(id); + } + if (that.allow_cid.indexOf(id)>=0) that.allow_cid.remove(id); + break; + } + that.update_view(); +}; + +ACL.prototype.update_view = function() { + if (that.allow_gid.length === 0 && that.allow_cid.length === 0 && + that.deny_gid.length === 0 && that.deny_cid.length === 0) { + that.showall.removeClass("btn-default").addClass("btn-warning"); + /* jot acl */ + $('#jot-perms-icon').removeClass('icon-lock').addClass('icon-unlock'); + $('#jot-public').show(); + $('.profile-jot-net input').attr('disabled', false); + if(typeof editor !== 'undefined' && editor !== false) { + $('#profile-jot-desc').html(ispublic); + } + } else { + that.showall.removeClass("btn-warning").addClass("btn-default"); + /* jot acl */ + $('#jot-perms-icon').removeClass('icon-unlock').addClass('icon-lock'); + $('#jot-public').hide(); + $('.profile-jot-net input').attr('disabled', 'disabled'); + $('#profile-jot-desc').html(' '); + } + $("#acl-list-content .acl-list-item").each(function() { + $(this).removeClass("groupshow grouphide"); + }); + $("#acl-list-content .acl-list-item").each(function() { + itemid = $(this).attr('id'); + type = itemid[0]; + id = itemid.substr(1); + + btshow = $(this).children(".acl-button-show").removeClass("btn-success").addClass("btn-default"); + bthide = $(this).children(".acl-button-hide").removeClass("btn-danger").addClass("btn-default"); + + switch(type) { + case "g": + var uclass = ""; + if (that.allow_gid.indexOf(id)>=0) { + btshow.removeClass("btn-default").addClass("btn-success"); + bthide.removeClass("btn-danger").addClass("btn-default"); + uclass="groupshow"; + } + if (that.deny_gid.indexOf(id)>=0) { + btshow.removeClass("btn-success").addClass("btn-default"); + bthide.removeClass("btn-default").addClass("btn-danger"); + uclass = "grouphide"; + } + $(that.group_uids[id]).each(function(i, v) { + if(uclass == "grouphide") + $("#c"+v).removeClass("groupshow"); + if(uclass !== "") { + var cls = $("#c"+v).attr('class'); + if( cls === undefined) + return true; + var hiding = cls.indexOf('grouphide'); + if(hiding == -1) + $("#c"+v).addClass(uclass); + } + }); + break; + case "c": + if (that.allow_cid.indexOf(id)>=0){ + btshow.removeClass("btn-default").addClass("btn-success"); + bthide.removeClass("btn-danger").addClass("btn-default"); + } + if (that.deny_cid.indexOf(id)>=0){ + btshow.removeClass("btn-success").addClass("btn-default"); + bthide.removeClass("btn-default").addClass("btn-danger"); + } + } + }); +}; + +ACL.prototype.get = function(start, count, search) { + var postdata = { + start: start, + count: count, + search: search, + }; + + $.ajax({ + type: 'POST', + url: that.url, + data: postdata, + dataType: 'json', + success: that.populate + }); +}; + +ACL.prototype.populate = function(data) { + var height = Math.ceil(data.items.length / that.nw) * 42; + that.list_content.height(height); + $(data.items).each(function(){ + html = "
    "+that.item_tpl+"
    "; + html = html.format(this.photo, this.name, this.type, this.xid, '', this.self, this.link, this.taggable); + if (this.uids !== undefined) that.group_uids[this.id] = this.uids; + //console.log(html); + that.list_content.append(html); + }); + $("#acl-list-content .acl-list-item img[data-src]").each(function(i, el) { + // Replace data-src attribute with src attribute for every image + $(el).attr('src', $(el).data("src")); + $(el).removeAttr("data-src"); + }); + that.update_view(); +}; \ No newline at end of file diff --git a/sources/view/js/ajaxupload.js b/sources/view/js/ajaxupload.js new file mode 100644 index 00000000..c7d587dd --- /dev/null +++ b/sources/view/js/ajaxupload.js @@ -0,0 +1,724 @@ +/** + * AJAX Upload ( http://valums.com/ajax-upload/ ) + * Copyright (c) Andris Valums + * Licensed under the MIT license ( http://valums.com/mit-license/ ) + * Thanks to Gary Haran, David Mark, Corey Burns and others for contributions. + */ + +(function () { + /* global window */ + /* jslint browser: true, devel: true, undef: true, nomen: true, bitwise: true, regexp: true, newcap: true, immed: true */ + + /** + * Wrapper for FireBug's console.log + */ + function log(){ + if (typeof(console) != 'undefined' && typeof(console.log) == 'function'){ + Array.prototype.unshift.call(arguments, '[Ajax Upload]'); + console.log( Array.prototype.join.call(arguments, ' ')); + } + } + + /** + * Attaches event to a dom element. + * @param {Element} el + * @param type event name + * @param fn callback This refers to the passed element + */ + function addEvent(el, type, fn){ + if (el.addEventListener) { + el.addEventListener(type, fn, false); + } else if (el.attachEvent) { + el.attachEvent('on' + type, function(){ + fn.call(el); + }); + } else { + throw new Error('not supported or DOM not loaded'); + } + } + + /** + * Attaches resize event to a window, limiting + * number of event fired. Fires only when encounteres + * delay of 100 after series of events. + * + * Some browsers fire event multiple times when resizing + * http://www.quirksmode.org/dom/events/resize.html + * + * @param fn callback This refers to the passed element + */ + function addResizeEvent(fn){ + var timeout; + + addEvent(window, 'resize', function(){ + if (timeout){ + clearTimeout(timeout); + } + timeout = setTimeout(fn, 100); + }); + } + + // Get offset adding all offsets, slow fall-back method + var getOffsetSlow = function(el){ + var top = 0, left = 0; + do { + top += el.offsetTop || 0; + left += el.offsetLeft || 0; + el = el.offsetParent; + } while (el); + + return { + left: left, + top: top + }; + }; + + + + + + // Needs more testing, will be rewriten for next version + // getOffset function copied from jQuery lib (http://jquery.com/) + if (document.documentElement.getBoundingClientRect){ + // Get Offset using getBoundingClientRect + // http://ejohn.org/blog/getboundingclientrect-is-awesome/ + var getOffset = function(el){ + var box = el.getBoundingClientRect(); + var doc = el.ownerDocument; + var body = doc.body; + var docElem = doc.documentElement; // for ie + var clientTop = docElem.clientTop || body.clientTop || 0; + var clientLeft = docElem.clientLeft || body.clientLeft || 0; + + // In Internet Explorer 7 getBoundingClientRect property is treated as physical, + // while others are logical. Make all logical, like in IE8. + var zoom = 1; + if (body.getBoundingClientRect) { + var bound = body.getBoundingClientRect(); + zoom = (bound.right - bound.left) / body.clientWidth; + } + + // some CSS layouts gives 0 width and/or bounding boxes + // in this case we fall back to the slow method + if (zoom == 0 || body.clientWidth == 0) + return getOffsetSlow(el); + + if (zoom > 1) { + clientTop = 0; + clientLeft = 0; + } + + var top = box.top / zoom + (window.pageYOffset || docElem && docElem.scrollTop / zoom || body.scrollTop / zoom) - clientTop, left = box.left / zoom + (window.pageXOffset || docElem && docElem.scrollLeft / zoom || body.scrollLeft / zoom) - clientLeft; + + return { + top: top, + left: left + }; + }; + } else { +// // Get offset adding all offsets + // var getOffset = function(el){ + // var top = 0, left = 0; + // do { + // top += el.offsetTop || 0; + // left += el.offsetLeft || 0; + // el = el.offsetParent; + // } while (el); + + // return { + // left: left, + // top: top + // }; + // }; + var getOffset = getOffsetSlowl + } + + /** + * Returns left, top, right and bottom properties describing the border-box, + * in pixels, with the top-left relative to the body + * @param {Element} el + * @return {Object} Contains left, top, right,bottom + */ + function getBox(el){ + var left, right, top, bottom; + var offset = getOffset(el); + left = offset.left; + top = offset.top; + + right = left + el.offsetWidth; + bottom = top + el.offsetHeight; + + return { + left: left, + right: right, + top: top, + bottom: bottom + }; + } + + /** + * Helper that takes object literal + * and add all properties to element.style + * @param {Element} el + * @param {Object} styles + */ + function addStyles(el, styles){ + for (var name in styles) { + if (styles.hasOwnProperty(name)) { + el.style[name] = styles[name]; + } + } + } + + /** + * Function places an absolutely positioned + * element on top of the specified element + * copying position and dimentions. + * @param {Element} from + * @param {Element} to + */ + function copyLayout(from, to){ + var box = getBox(from); + + addStyles(to, { + position: 'absolute', + left : box.left + 'px', + top : box.top + 'px', + width : from.offsetWidth + 'px', + height : from.offsetHeight + 'px' + }); + to.title = from.title; + + } + + /** + * Creates and returns element from html chunk + * Uses innerHTML to create an element + */ + var toElement = (function(){ + var div = document.createElement('div'); + return function(html){ + div.innerHTML = html; + var el = div.firstChild; + return div.removeChild(el); + }; + })(); + + /** + * Function generates unique id + * @return unique id + */ + var getUID = (function(){ + var id = 0; + return function(){ + return 'ValumsAjaxUpload' + id++; + }; + })(); + + /** + * Get file name from path + * @param {String} file path to file + * @return filename + */ + function fileFromPath(file){ + return file.replace(/.*(\/|\\)/, ""); + } + + /** + * Get file extension lowercase + * @param {String} file name + * @return file extenstion + */ + function getExt(file){ + return (-1 !== file.indexOf('.')) ? file.replace(/.*[.]/, '') : ''; + } + + function hasClass(el, name){ + var re = new RegExp('\\b' + name + '\\b'); + return re.test(el.className); + } + function addClass(el, name){ + if ( ! hasClass(el, name)){ + el.className += ' ' + name; + } + } + function removeClass(el, name){ + var re = new RegExp('\\b' + name + '\\b'); + el.className = el.className.replace(re, ''); + } + + function removeNode(el){ + el.parentNode.removeChild(el); + } + + /** + * Easy styling and uploading + * @constructor + * @param button An element you want convert to + * upload button. Tested dimentions up to 500x500px + * @param {Object} options See defaults below. + */ + window.AjaxUpload = function(button, options){ + this._settings = { + // Location of the server-side upload script + action: 'upload.php', + // File upload name + name: 'userfile', + + title: 'Upload', + + // Additional data to send + data: {}, + // Submit file as soon as it's selected + autoSubmit: true, + // The type of data that you're expecting back from the server. + // html and xml are detected automatically. + // Only useful when you are using json data as a response. + // Set to "json" in that case. + responseType: false, + // Class applied to button when mouse is hovered + hoverClass: 'hover', + // Class applied to button when button is focused + focusClass: 'focus', + // Class applied to button when AU is disabled + disabledClass: 'disabled', + // When user selects a file, useful with autoSubmit disabled + // You can return false to cancel upload + onChange: function(file, extension){ + }, + // Callback to fire before file is uploaded + // You can return false to cancel upload + onSubmit: function(file, extension){ + }, + // Fired when file upload is completed + // WARNING! DO NOT USE "FALSE" STRING AS A RESPONSE! + onComplete: function(file, response){ + } + }; + + // Merge the users options with our defaults + for (var i in options) { + if (options.hasOwnProperty(i)){ + this._settings[i] = options[i]; + } + } + + // button isn't necessary a dom element + if (button.jquery){ + // jQuery object was passed + button = button[0]; + } else if (typeof button == "string") { + if (/^#.*/.test(button)){ + // If jQuery user passes #elementId don't break it + button = button.slice(1); + } + + button = document.getElementById(button); + } + + if ( ! button || button.nodeType !== 1){ + throw new Error("Please make sure that you're passing a valid element"); + } + + if ( button.nodeName.toUpperCase() == 'A'){ + // disable link + addEvent(button, 'click', function(e){ + if (e && e.preventDefault){ + e.preventDefault(); + } else if (window.event){ + window.event.returnValue = false; + } + }); + } + + // DOM element + this._button = button; + // DOM element + this._input = null; + // If disabled clicking on button won't do anything + this._disabled = false; + + // if the button was disabled before refresh if will remain + // disabled in FireFox, let's fix it + this.enable(); + + this._rerouteClicks(); + }; + + // assigning methods to our class + AjaxUpload.prototype = { + setData: function(data){ + this._settings.data = data; + }, + disable: function(){ + addClass(this._button, this._settings.disabledClass); + this._disabled = true; + + var nodeName = this._button.nodeName.toUpperCase(); + if (nodeName == 'INPUT' || nodeName == 'BUTTON'){ + this._button.setAttribute('disabled', 'disabled'); + } + + // hide input + if (this._input){ + // We use visibility instead of display to fix problem with Safari 4 + // The problem is that the value of input doesn't change if it + // has display none when user selects a file + this._input.parentNode.style.visibility = 'hidden'; + } + }, + enable: function(){ + removeClass(this._button, this._settings.disabledClass); + this._button.removeAttribute('disabled'); + this._disabled = false; + + }, + /** + * Creates invisible file input + * that will hover above the button + *
    + */ + _createInput: function(){ + var self = this; + + var input = document.createElement("input"); + input.setAttribute('type', 'file'); + input.setAttribute('title',this._settings.title); + input.setAttribute('name', this._settings.name); + + addStyles(input, { + 'position' : 'absolute', + // in Opera only 'browse' button + // is clickable and it is located at + // the right side of the input + 'right' : 0, + 'margin' : 0, + 'padding' : 0, + 'fontSize' : '480px', + // in Firefox if font-family is set to + // 'inherit' the input doesn't work + 'fontFamily' : 'sans-serif', + 'cursor' : 'pointer' + }); + + var div = document.createElement("div"); + addStyles(div, { + 'display' : 'block', + 'position' : 'absolute', + 'overflow' : 'hidden', + 'margin' : 0, + 'padding' : 0, + 'opacity' : 0, + // Make sure browse button is in the right side + // in Internet Explorer + 'direction' : 'ltr', + //Max zIndex supported by Opera 9.0-9.2 + 'zIndex': 2147483583, + 'cursor' : 'pointer' + + }); + + // Make sure that element opacity exists. + // Otherwise use IE filter + if ( div.style.opacity !== "0") { + if (typeof(div.filters) == 'undefined'){ + throw new Error('Opacity not supported by the browser'); + } + div.style.filter = "alpha(opacity=0)"; + } + + addEvent(input, 'change', function(){ + + if ( ! input || input.value === ''){ + return; + } + + // Get filename from input, required + // as some browsers have path instead of it + var file = fileFromPath(input.value); + + if (false === self._settings.onChange.call(self, file, getExt(file))){ + self._clearInput(); + return; + } + + // Submit form when value is changed + if (self._settings.autoSubmit) { + self.submit(); + } + }); + + addEvent(input, 'mouseover', function(){ + addClass(self._button, self._settings.hoverClass); + }); + + addEvent(input, 'mouseout', function(){ + removeClass(self._button, self._settings.hoverClass); + removeClass(self._button, self._settings.focusClass); + + // We use visibility instead of display to fix problem with Safari 4 + // The problem is that the value of input doesn't change if it + // has display none when user selects a file + input.parentNode.style.visibility = 'hidden'; + + }); + + addEvent(input, 'focus', function(){ + addClass(self._button, self._settings.focusClass); + }); + + addEvent(input, 'blur', function(){ + removeClass(self._button, self._settings.focusClass); + }); + + div.appendChild(input); + document.body.appendChild(div); + + this._input = input; + }, + _clearInput : function(){ + if (!this._input){ + return; + } + + // this._input.value = ''; Doesn't work in IE6 + removeNode(this._input.parentNode); + this._input = null; + this._createInput(); + + removeClass(this._button, this._settings.hoverClass); + removeClass(this._button, this._settings.focusClass); + }, + /** + * Function makes sure that when user clicks upload button, + * the this._input is clicked instead + */ + _rerouteClicks: function(){ + var self = this; + + // IE will later display 'access denied' error + // if you use using self._input.click() + // other browsers just ignore click() + + addEvent(self._button, 'mouseover', function(){ + if (self._disabled){ + return; + } + + if ( ! self._input){ + self._createInput(); + } + + var div = self._input.parentNode; + copyLayout(self._button, div); + div.style.visibility = 'visible'; + + }); + + + // commented because we now hide input on mouseleave + /** + * When the window is resized the elements + * can be misaligned if button position depends + * on window size + */ + //addResizeEvent(function(){ + // if (self._input){ + // copyLayout(self._button, self._input.parentNode); + // } + //}); + + }, + /** + * Creates iframe with unique name + * @return {Element} iframe + */ + _createIframe: function(){ + // We can't use getTime, because it sometimes return + // same value in safari :( + var id = getUID(); + + // We can't use following code as the name attribute + // won't be properly registered in IE6, and new window + // on form submit will open + // var iframe = document.createElement('iframe'); + // iframe.setAttribute('name', id); + + var iframe = toElement(' --> + +
    diff --git a/sources/view/tpl/admin_plugins.tpl b/sources/view/tpl/admin_plugins.tpl new file mode 100755 index 00000000..0f76cc4f --- /dev/null +++ b/sources/view/tpl/admin_plugins.tpl @@ -0,0 +1,15 @@ +
    +

    {{$title}} - {{$page}}

    + +
      + {{foreach $plugins as $p}} +
    • + + {{$p.2.name}} - {{$p.2.version}} + {{if $p.2.experimental}} {{$experimental}} {{/if}}{{if $p.2.unsupported}} {{$unsupported}} {{/if}} + +
      {{$p.2.description}}
      +
    • + {{/foreach}} +
    +
    diff --git a/sources/view/tpl/admin_plugins_details.tpl b/sources/view/tpl/admin_plugins_details.tpl new file mode 100755 index 00000000..bdcc82c0 --- /dev/null +++ b/sources/view/tpl/admin_plugins_details.tpl @@ -0,0 +1,36 @@ +
    +

    {{$title}} - {{$page}}

    + +

    {{$info.name}} - {{$info.version}} : {{$action}}

    +

    {{$info.description}}

    + +

    {{$str_author}} + {{foreach $info.author as $a}} + {{if $a.link}}{{$a.name}}{{else}}{{$a.name}}{{/if}}, + {{/foreach}} +

    + +

    {{$str_maintainer}} + {{foreach $info.maintainer as $a}} + {{if $a.link}}{{$a.name}}{{else}}{{$a.name}}{{/if}}, + {{/foreach}} +

    + + {{if $screenshot}} + {{$screenshot.1}} + {{/if}} + + {{if $admin_form}} +

    {{$settings}}

    +
    + {{$admin_form}} +
    + {{/if}} + + {{if $readme}} +

    Readme

    +
    + {{$readme}} +
    + {{/if}} +
    diff --git a/sources/view/tpl/admin_queue.tpl b/sources/view/tpl/admin_queue.tpl new file mode 100644 index 00000000..85b47626 --- /dev/null +++ b/sources/view/tpl/admin_queue.tpl @@ -0,0 +1,14 @@ +

    {{$banner}}

    + +{{if $hasentries}} + + + +{{foreach $entries as $e}} + +{{if $expert}}{{/if}} +{{/foreach}} + +
    {{$numentries}}  {{$desturl}}{{$priority}}  
    {{$e.total}}{{$e.outq_posturl}}{{$e.priority}}
    + +{{/if}} \ No newline at end of file diff --git a/sources/view/tpl/admin_site.tpl b/sources/view/tpl/admin_site.tpl new file mode 100755 index 00000000..e2ce3c55 --- /dev/null +++ b/sources/view/tpl/admin_site.tpl @@ -0,0 +1,89 @@ + +
    +

    {{$title}} - {{$page}}

    + +
    + + + {{include file="field_input.tpl" field=$sitename}} + {{include file="field_textarea.tpl" field=$banner}} + {{include file="field_textarea.tpl" field=$admininfo}} + {{include file="field_select.tpl" field=$language}} + {{include file="field_select.tpl" field=$theme}} + {{include file="field_select.tpl" field=$theme_mobile}} + {{include file="field_input.tpl" field=$frontpage}} + {{include file="field_checkbox.tpl" field=$mirror_frontpage}} + {{include file="field_checkbox.tpl" field=$login_on_homepage}} + + +
    + +

    {{$registration}}

    + {{include file="field_input.tpl" field=$register_text}} + {{include file="field_select.tpl" field=$register_policy}} + {{include file="field_select.tpl" field=$access_policy}} + {{include file="field_textarea.tpl" field=$allowed_email}} + {{include file="field_textarea.tpl" field=$not_allowed_email}} +
    + +

    {{$upload}}

    + {{include file="field_input.tpl" field=$maximagesize}} + +

    {{$corporate}}

    + {{include file="field_checkbox.tpl" field=$block_public}} + {{include file="field_checkbox.tpl" field=$verify_email}} + {{include file="field_checkbox.tpl" field=$feed_contacts}} + {{include file="field_checkbox.tpl" field=$force_publish}} + {{include file="field_checkbox.tpl" field=$disable_discover_tab}} + +
    + +

    {{$advanced}}

    + {{include file="field_input.tpl" field=$proxy}} + {{include file="field_input.tpl" field=$proxyuser}} + {{include file="field_input.tpl" field=$timeout}} + {{include file="field_input.tpl" field=$delivery_interval}} + {{include file="field_input.tpl" field=$poll_interval}} + {{include file="field_input.tpl" field=$maxloadavg}} + {{include file="field_input.tpl" field=$abandon_days}} + {{include file="field_input.tpl" field=$default_expire_days}} + +
    + +
    +
    diff --git a/sources/view/tpl/admin_summary.tpl b/sources/view/tpl/admin_summary.tpl new file mode 100755 index 00000000..25964084 --- /dev/null +++ b/sources/view/tpl/admin_summary.tpl @@ -0,0 +1,32 @@ +
    +

    {{$title}} - {{$page}}

    +{{if $adminalertmsg}} + +{{/if}} +
    +
    {{$queues.label}}
    +
    {{$queues.queue}}
    +
    +
    +
    {{$accounts.0}}
    +
    {{foreach from=$accounts.1 item=acc name=account}}{{$acc.val}}{{if !$smarty.foreach.account.last}} / {{/if}}{{/foreach}}
    +
    +
    +
    {{$pending.0}}
    +
    {{$pending.1}} +
    +
    +
    {{$channels.0}}
    +
    {{foreach from=$channels.1 item=ch name=chan}}{{$ch.val}}{{if !$smarty.foreach.chan.last}} / {{/if}}{{/foreach}}
    +
    +
    +
    {{$plugins.0}}
    +
    + {{foreach $plugins.1 as $p}} {{$p}} {{/foreach}} +
    +
    +
    +
    {{$version.0}}
    +
    {{$version.1}} - {{$build}}
    +
    +
    \ No newline at end of file diff --git a/sources/view/tpl/admin_users.tpl b/sources/view/tpl/admin_users.tpl new file mode 100755 index 00000000..f372911a --- /dev/null +++ b/sources/view/tpl/admin_users.tpl @@ -0,0 +1,88 @@ + +
    +

    {{$title}} - {{$page}}

    + +
    + + +

    {{$h_pending}}

    + {{if $pending}} + + + + {{foreach $th_pending as $th}}{{/foreach}} + + + + + + {{foreach $pending as $u}} + + + + + + + {{/foreach}} + +
    {{$th}}
    {{$u.account_created}} + + +
    + +
    + {{else}} +

    {{$no_pending}}

    + {{/if}} + + +

    {{$h_users}}

    + {{if $users}} + + + + {{foreach $th_users as $th}}{{/foreach}} + + + + + + {{foreach $users as $u}} + + + + + + + + + + + + {{/foreach}} + +
    {{$th}}
    {{$u.channels}}{{$u.account_created}}{{$u.account_service_class}} + +
    + +
    + {{else}} + NO USERS?!? + {{/if}} +
    +
    \ No newline at end of file diff --git a/sources/view/tpl/album_edit.tpl b/sources/view/tpl/album_edit.tpl new file mode 100755 index 00000000..f5495f14 --- /dev/null +++ b/sources/view/tpl/album_edit.tpl @@ -0,0 +1,22 @@ +
    +
    +
    + + + + {{foreach $albums as $al}} + {{if $al.text}} + +
    +
    + + +
    +
    +
    +
    + + diff --git a/sources/view/tpl/alt_pager.tpl b/sources/view/tpl/alt_pager.tpl new file mode 100644 index 00000000..b46dc766 --- /dev/null +++ b/sources/view/tpl/alt_pager.tpl @@ -0,0 +1,4 @@ +
    +{{if $has_less}}{{$less}}{{/if}} +{{if $has_more}}{{if $has_less}} | {{/if}}{{$more}}{{/if}} +
    diff --git a/sources/view/tpl/api_config_xml.tpl b/sources/view/tpl/api_config_xml.tpl new file mode 100755 index 00000000..8c0766c7 --- /dev/null +++ b/sources/view/tpl/api_config_xml.tpl @@ -0,0 +1,66 @@ + + + {{$config.site.name}} + {{$config.site.server}} + default + + {{$config.site.logo}} + + true + en + {{$config.site.email}} + + + UTC + {{$config.site.closed}} + + false + {{$config.site.private}} + {{$config.site.textlimit}} + {{$config.site.ssl}} + {{$config.site.sslserver}} + 30 + + + + cc + + http://creativecommons.org/licenses/by/3.0/ + Creative Commons Attribution 3.0 + http://i.creativecommons.org/l/by/3.0/80x15.png + + + + + + + + + + + + + + + + + false + 20 + 600 + + + + false + INVALID SERVER + 5222 + update + + + StatusNet + + + + false + 0 + + diff --git a/sources/view/tpl/api_friends_xml.tpl b/sources/view/tpl/api_friends_xml.tpl new file mode 100755 index 00000000..f2a7234d --- /dev/null +++ b/sources/view/tpl/api_friends_xml.tpl @@ -0,0 +1,5 @@ + + {{foreach $users as $user}} + {{include file="api_user_xml.tpl"}} + {{/foreach}} + diff --git a/sources/view/tpl/api_ratelimit_xml.tpl b/sources/view/tpl/api_ratelimit_xml.tpl new file mode 100755 index 00000000..e4b470a2 --- /dev/null +++ b/sources/view/tpl/api_ratelimit_xml.tpl @@ -0,0 +1,6 @@ + + {{$hash.remaining_hits}} + {{$hash.hourly_limit}} + {{$hash.reset_time}} + {{$hash.resettime_in_seconds}} + diff --git a/sources/view/tpl/api_status_xml.tpl b/sources/view/tpl/api_status_xml.tpl new file mode 100755 index 00000000..cbb736e2 --- /dev/null +++ b/sources/view/tpl/api_status_xml.tpl @@ -0,0 +1,46 @@ +{{if $status}} + {{$status.created_at}} + {{$status.id}} + {{$status.text}} + {{$status.source}} + {{$status.truncated}} + {{$status.in_reply_to_status_id}} + {{$status.in_reply_to_user_id}} + {{$status.favorited}} + {{$status.in_reply_to_screen_name}} + {{$status.geo}} + {{$status.coordinates}} + {{$status.place}} + {{$status.contributors}} + + {{$status.user.id}} + {{$status.user.name}} + {{$status.user.screen_name}} + {{$status.user.location}} + {{$status.user.description}} + {{$status.user.profile_image_url}} + {{$status.user.url}} + {{$status.user.protected}} + {{$status.user.followers}} + {{$status.user.profile_background_color}} + {{$status.user.profile_text_color}} + {{$status.user.profile_link_color}} + {{$status.user.profile_sidebar_fill_color}} + {{$status.user.profile_sidebar_border_color}} + {{$status.user.friends_count}} + {{$status.user.created_at}} + {{$status.user.favourites_count}} + {{$status.user.utc_offset}} + {{$status.user.time_zone}} + {{$status.user.profile_background_image_url}} + {{$status.user.profile_background_tile}} + {{$status.user.profile_use_background_image}} + + {{$status.user.geo_enabled}} + {{$status.user.verified}} + + {{$status.user.statuses_count}} + {{$status.user.lang}} + {{$status.user.contributors_enabled}} + +{{/if}} diff --git a/sources/view/tpl/api_test_xml.tpl b/sources/view/tpl/api_test_xml.tpl new file mode 100755 index 00000000..80a541c3 --- /dev/null +++ b/sources/view/tpl/api_test_xml.tpl @@ -0,0 +1 @@ +{{$ok}} diff --git a/sources/view/tpl/api_timeline_atom.tpl b/sources/view/tpl/api_timeline_atom.tpl new file mode 100755 index 00000000..e8bfb689 --- /dev/null +++ b/sources/view/tpl/api_timeline_atom.tpl @@ -0,0 +1,90 @@ + + StatusNet + {{$rss.self}} + Friendika + Friendika API feed + {{$rss.logo}} + {{$rss.atom_updated}} + + + + + + http://activitystrea.ms/schema/1.0/person + {{$user.url}} + {{$user.name}} + + + + + + + {{$user.screen_name}} + {{$user.name}} + + homepage + {{$user.url}} + true + + + + + + + http://activitystrea.ms/schema/1.0/person + {{$user.contact_url}} + {{$user.name}} + + + + + + {{$user.screen_name}} + {{$user.name}} + + homepage + {{$user.url}} + true + + + + + + {{foreach $statuses as $status}} + + {{$status.objecttype}} + {{$status.message_id}} + {{$status.text}} + {{$status.statusnet_html}} + + {{$status.verb}} + {{$status.published}} + {{$status.updated}} + + + + + + + + http://activitystrea.ms/schema/1.0/person + {{$status.user.url}} + {{$status.user.name}} + + + + + {{$status.user.screen_name}} + {{$status.user.name}} + + + homepage + {{$status.user.url}} + true + + + + + + {{/foreach}} + diff --git a/sources/view/tpl/api_timeline_rss.tpl b/sources/view/tpl/api_timeline_rss.tpl new file mode 100755 index 00000000..86c645e9 --- /dev/null +++ b/sources/view/tpl/api_timeline_rss.tpl @@ -0,0 +1,26 @@ + + + Friendika + {{$rss.alternate}} + + Friendika timeline + {{$rss.language}} + 40 + + {{$user.link}} + {{$user.name}}'s items + {{$user.profile_image_url}} + + +{{foreach $statuses as $status}} + + {{$status.user.name}}: {{$status.text}} + {{$status.text}} + {{$status.created_at}} + {{$status.url}} + {{$status.url}} + {{$status.source}} + +{{/foreach}} + + diff --git a/sources/view/tpl/api_timeline_xml.tpl b/sources/view/tpl/api_timeline_xml.tpl new file mode 100755 index 00000000..f14d73e9 --- /dev/null +++ b/sources/view/tpl/api_timeline_xml.tpl @@ -0,0 +1,20 @@ + +{{foreach $statuses as $status}} + {{$status.text}} + {{$status.truncated}} + {{$status.created_at}} + {{$status.in_reply_to_status_id}} + {{$status.source}} + {{$status.id}} + {{$status.in_reply_to_user_id}} + {{$status.in_reply_to_screen_name}} + {{$status.geo}} + {{$status.favorited}} +{{include file="api_user_xml.tpl" user=$status.user}} {{$status.statusnet_html}} + {{$status.statusnet_conversation_id}} + {{$status.url}} + {{$status.coordinates}} + {{$status.place}} + {{$status.contributors}} + +{{/foreach}} diff --git a/sources/view/tpl/api_user_xml.tpl b/sources/view/tpl/api_user_xml.tpl new file mode 100755 index 00000000..3b51992f --- /dev/null +++ b/sources/view/tpl/api_user_xml.tpl @@ -0,0 +1,46 @@ + + {{$user.id}} + {{$user.name}} + {{$user.screen_name}} + {{$user.location}} + {{$user.description}} + {{$user.profile_image_url}} + {{$user.url}} + {{$user.protected}} + {{$user.followers_count}} + {{$user.friends_count}} + {{$user.created_at}} + {{$user.favourites_count}} + {{$user.utc_offset}} + {{$user.time_zone}} + {{$user.statuses_count}} + {{$user.following}} + {{$user.profile_background_color}} + {{$user.profile_text_color}} + {{$user.profile_link_color}} + {{$user.profile_sidebar_fill_color}} + {{$user.profile_sidebar_border_color}} + {{$user.profile_background_image_url}} + {{$user.profile_background_tile}} + {{$user.profile_use_background_image}} + {{$user.notifications}} + {{$user.geo_enabled}} + {{$user.verified}} + {{$user.lang}} + {{$user.contributors_enabled}} + {{if $user.status}} + {{$user.status.created_at}} + {{$user.status.id}} + {{$user.status.text}} + {{$user.status.source}} + {{$user.status.truncated}} + {{$user.status.in_reply_to_status_id}} + {{$user.status.in_reply_to_user_id}} + {{$user.status.favorited}} + {{$user.status.in_reply_to_screen_name}} + {{$user.status.geo}} + {{$user.status.coordinates}} + {{$user.status.place}} + {{$user.status.contributors}} + {{/if}} + diff --git a/sources/view/tpl/app.tpl b/sources/view/tpl/app.tpl new file mode 100644 index 00000000..cebc17d4 --- /dev/null +++ b/sources/view/tpl/app.tpl @@ -0,0 +1,19 @@ +
    + +
    {{$app.name}}
    +
    +{{if $app.type !== 'system'}} +{{if $purchase}} + +{{/if}} +{{if $install || $update || $delete }} +
    + +{{if $install}}{{/if}} +{{if $edit}}{{/if}} +{{if $delete}}{{/if}} +
    +{{/if}} +{{/if}} +
    + diff --git a/sources/view/tpl/app_create.tpl b/sources/view/tpl/app_create.tpl new file mode 100644 index 00000000..ff28e059 --- /dev/null +++ b/sources/view/tpl/app_create.tpl @@ -0,0 +1,30 @@ +

    {{$banner}}

    + + +
    +{{if $guid}} + +{{/if}} +{{if $author}} + +{{/if}} +{{if $addr}} + +{{/if}} + +{{include file="field_input.tpl" field=$name}} +{{include file="field_input.tpl" field=$url}} +{{include file="field_textarea.tpl" field=$desc}} +{{include file="field_input.tpl" field=$photo}} +{{include file="field_input.tpl" field=$version}} +{{include file="field_input.tpl" field=$price}} +{{include file="field_input.tpl" field=$page}} + +{{if $embed}} +{{include file="field_textarea.tpl" field=$embed}} +{{/if}} + + + +
    + diff --git a/sources/view/tpl/app_select.tpl b/sources/view/tpl/app_select.tpl new file mode 100644 index 00000000..527d01ea --- /dev/null +++ b/sources/view/tpl/app_select.tpl @@ -0,0 +1,10 @@ +{{if $authed}} +
    +

    {{$title}}

    + +
    +{{/if}} + diff --git a/sources/view/tpl/atom_feed.tpl b/sources/view/tpl/atom_feed.tpl new file mode 100755 index 00000000..9e5b5a5b --- /dev/null +++ b/sources/view/tpl/atom_feed.tpl @@ -0,0 +1,33 @@ + + + + {{$feed_id}} + {{$feed_title}} + {{$red}} + + +{{if $hub}} + {{$hub}} +{{/if}} +{{if $salmon}} + {{$salmon}} +{{/if}} + + {{$feed_updated}} + + + {{$name}} + {{$profile_page}} + + + diff --git a/sources/view/tpl/attach_edit.tpl b/sources/view/tpl/attach_edit.tpl new file mode 100644 index 00000000..44d230ae --- /dev/null +++ b/sources/view/tpl/attach_edit.tpl @@ -0,0 +1,33 @@ +
    + + + + + {{if !$isadir}}{{include file="field_checkbox.tpl" field=$notify}}{{/if}} + {{if $isadir}}{{include file="field_checkbox.tpl" field=$recurse}}{{/if}} +
    + {{if !$isadir}} + + + + {{/if}} + +
    +
    + + +
    + {{$aclselect}} + + +
    + diff --git a/sources/view/tpl/birthdays_reminder.tpl b/sources/view/tpl/birthdays_reminder.tpl new file mode 100755 index 00000000..d0500364 --- /dev/null +++ b/sources/view/tpl/birthdays_reminder.tpl @@ -0,0 +1,10 @@ +{{if $count}} + + +{{/if}} + diff --git a/sources/view/tpl/blocklist.tpl b/sources/view/tpl/blocklist.tpl new file mode 100644 index 00000000..27dbcbf0 --- /dev/null +++ b/sources/view/tpl/blocklist.tpl @@ -0,0 +1,69 @@ +
    +
    + {{if $editor}} +
    + +
    + {{/if}} +

    {{$title}}

    +
    +
    + {{if $editor}} +
    + {{$editor}} +
    + {{/if}} + {{if $pages}} +
    + + + + + + + + + + + {{foreach $pages as $key => $items}} + {{foreach $items as $item}} + + + + + + + + + + {{/foreach}} + {{/foreach}} +
    {{$name}}{{$blocktitle}}
    + {{if $view}} + {{$item.name}} + {{else}} + {{$item.name}} + {{/if}} + + {{$item.title}} + + {{if $edit}} + + {{/if}} + + {{if $item.bb_element}} + + {{/if}} + + {{if $edit}} + + {{/if}} +
    +
    +
    + {{/if}} +
    diff --git a/sources/view/tpl/bookmarkedchats.tpl b/sources/view/tpl/bookmarkedchats.tpl new file mode 100644 index 00000000..7635bb82 --- /dev/null +++ b/sources/view/tpl/bookmarkedchats.tpl @@ -0,0 +1,10 @@ +{{if $rooms}} +
    +

    {{$header}}

    + +
    +{{/if}} \ No newline at end of file diff --git a/sources/view/tpl/build_query.tpl b/sources/view/tpl/build_query.tpl new file mode 100755 index 00000000..62f81b61 --- /dev/null +++ b/sources/view/tpl/build_query.tpl @@ -0,0 +1,61 @@ + + diff --git a/sources/view/tpl/categories_widget.tpl b/sources/view/tpl/categories_widget.tpl new file mode 100755 index 00000000..ea6d28df --- /dev/null +++ b/sources/view/tpl/categories_widget.tpl @@ -0,0 +1,12 @@ +
    +

    {{$title}}

    +
    {{$desc}}
    + + + +
    diff --git a/sources/view/tpl/channel.tpl b/sources/view/tpl/channel.tpl new file mode 100755 index 00000000..af80e7b4 --- /dev/null +++ b/sources/view/tpl/channel.tpl @@ -0,0 +1,12 @@ +
    +{{if $channel.default_links}} +{{if $channel.default}} +
    {{$msg_default}}
    +{{else}} +
    +{{/if}} +{{/if}} +{{$channel.channel_name}} + +
    {{$channel.channel_name}}
    +
    diff --git a/sources/view/tpl/channel_id_select.tpl b/sources/view/tpl/channel_id_select.tpl new file mode 100644 index 00000000..ecebd4bc --- /dev/null +++ b/sources/view/tpl/channel_id_select.tpl @@ -0,0 +1,7 @@ +{{if $channels}} + +{{/if}} \ No newline at end of file diff --git a/sources/view/tpl/channel_import.tpl b/sources/view/tpl/channel_import.tpl new file mode 100755 index 00000000..6974e4d3 --- /dev/null +++ b/sources/view/tpl/channel_import.tpl @@ -0,0 +1,43 @@ +

    {{$title}}

    + +
    + +
    {{$desc}}
    + + + +
    + +
    {{$choice}}
    + + + +
    + + + +
    + + + +
    + + + +
    + + +
    {{$common}}
    + + + +
    + + +
    + +
    {{$pleasewait}}
    + + +
    + diff --git a/sources/view/tpl/channels.tpl b/sources/view/tpl/channels.tpl new file mode 100755 index 00000000..44daa0a3 --- /dev/null +++ b/sources/view/tpl/channels.tpl @@ -0,0 +1,38 @@ +
    +

    {{$header}}

    + +{{if $links}} +{{foreach $links as $l}} +{{$l.2}} +{{/foreach}} +{{/if}} +
    + +{{if $channel_usage_message}} +
    +{{$channel_usage_message}} +
    +{{/if}} +
    {{$desc}}
    + +
    +{{foreach $all_channels as $chn}} +{{include file="channel.tpl" channel=$chn}} +{{/foreach}} +
    + +
    + +{{if $delegates}} +
    +

    {{$delegate_header}}

    +
    +{{foreach $delegates as $chn}} +{{include file="channel.tpl" channel=$chn}} +{{/foreach}} +
    + +
    +{{/if}} + +
    diff --git a/sources/view/tpl/chanview.tpl b/sources/view/tpl/chanview.tpl new file mode 100755 index 00000000..a43ea1b5 --- /dev/null +++ b/sources/view/tpl/chanview.tpl @@ -0,0 +1,2 @@ + + diff --git a/sources/view/tpl/chat.tpl b/sources/view/tpl/chat.tpl new file mode 100644 index 00000000..9f95d299 --- /dev/null +++ b/sources/view/tpl/chat.tpl @@ -0,0 +1,128 @@ +

    {{$room_name}}

    +
    + +
    +
    +
    + +
    + {{if $is_owner}} +
    +
    + + + +
    +

    + {{/if}} + +

    +
    +
    +
    +
    + +
    + +
    + +
    + + {{$leave}} | {{$away}} | {{$online}}{{if $bookmark_link}} | {{$bookmark}}{{/if}} + +
    + +
    + + + diff --git a/sources/view/tpl/chatroom_new.tpl b/sources/view/tpl/chatroom_new.tpl new file mode 100644 index 00000000..a559dba5 --- /dev/null +++ b/sources/view/tpl/chatroom_new.tpl @@ -0,0 +1,13 @@ +

    {{$header}}

    + +
    +{{include file="field_input.tpl" field=$name}} + +{{$acl}} +
    +
    +
    + +
    + + diff --git a/sources/view/tpl/chatroomlist.tpl b/sources/view/tpl/chatroomlist.tpl new file mode 100644 index 00000000..71fec820 --- /dev/null +++ b/sources/view/tpl/chatroomlist.tpl @@ -0,0 +1,11 @@ +
    +

    {{$header}}

    +{{if $items}} + +{{foreach $items as $item}} + +{{/foreach}} +
    {{$item.cr_name}}{{$item.cr_inroom}}
    +{{/if}} +
    + diff --git a/sources/view/tpl/chatrooms.tpl b/sources/view/tpl/chatrooms.tpl new file mode 100644 index 00000000..c3dae662 --- /dev/null +++ b/sources/view/tpl/chatrooms.tpl @@ -0,0 +1,10 @@ +

    {{$header}}

    + +{{if $is_owner}} +

    +{{$newroom}} +

    +{{/if}} + +{{$rooms}} + diff --git a/sources/view/tpl/cloud.tpl b/sources/view/tpl/cloud.tpl new file mode 100644 index 00000000..d1567af9 --- /dev/null +++ b/sources/view/tpl/cloud.tpl @@ -0,0 +1,4 @@ +
    +{{include file="cloud_header.tpl"}} +{{include file="cloud_directory.tpl"}} +
    diff --git a/sources/view/tpl/cloud_actionspanel.tpl b/sources/view/tpl/cloud_actionspanel.tpl new file mode 100644 index 00000000..da708a98 --- /dev/null +++ b/sources/view/tpl/cloud_actionspanel.tpl @@ -0,0 +1,19 @@ +
    + +
    + + + +
    +
    +
    +
    + +
    + + + + +
    +
    +
    diff --git a/sources/view/tpl/cloud_directory.tpl b/sources/view/tpl/cloud_directory.tpl new file mode 100644 index 00000000..0c7892c2 --- /dev/null +++ b/sources/view/tpl/cloud_directory.tpl @@ -0,0 +1,43 @@ +
    + + + + + + + + + + {{if $parentpath}} + + + + + + + + + {{/if}} + {{foreach $entries as $item}} + + + + {{if $item.is_owner}} + + + + + + {{else}} + + {{/if}} + + + + + + + + {{/foreach}} +
    {{$name}}{{*{{$type}}*}}
    {{*{{$parentpath.icon}}*}}..{{*[{{$parent}}]*}}
    {{$item.displayName}}{{$item.attachIcon}}{{*{{$item.type}}*}}
    +
    diff --git a/sources/view/tpl/cloud_header.tpl b/sources/view/tpl/cloud_header.tpl new file mode 100644 index 00000000..c75815d0 --- /dev/null +++ b/sources/view/tpl/cloud_header.tpl @@ -0,0 +1,16 @@ +
    + {{if $actionspanel}} +
    + {{if $is_owner}} +  {{$shared}} + {{/if}} + + +
    + {{/if}} +

    {{$header}}

    +
    +
    +{{if $actionspanel}} + {{$actionspanel}} +{{/if}} diff --git a/sources/view/tpl/comment_item.tpl b/sources/view/tpl/comment_item.tpl new file mode 100755 index 00000000..49c6af76 --- /dev/null +++ b/sources/view/tpl/comment_item.tpl @@ -0,0 +1,72 @@ + {{if $threaded}} +
    + {{else}} +
    + {{/if}} +
    + + + + + + + + {{if $qcomment}} + + {{/if}} +
    +
    +
    +
    + + + + + +
    +
    + + + +
    + {{if $feature_encrypt}} +
    + +
    + {{/if}} +
    +
    + {{if $preview}} + + {{/if}} + +
    +
    +
    +
    +
    diff --git a/sources/view/tpl/common_friends.tpl b/sources/view/tpl/common_friends.tpl new file mode 100755 index 00000000..489717e7 --- /dev/null +++ b/sources/view/tpl/common_friends.tpl @@ -0,0 +1,15 @@ +
    +
    + + {{$name}} + +
    +
    +
    + {{$name}} +
    + {{if $note}} +
    {{$note}}
    + {{/if}} +
    +
    diff --git a/sources/view/tpl/common_tabs.tpl b/sources/view/tpl/common_tabs.tpl new file mode 100755 index 00000000..fa6bfbdf --- /dev/null +++ b/sources/view/tpl/common_tabs.tpl @@ -0,0 +1,8 @@ + +
    diff --git a/sources/view/tpl/connection_template.tpl b/sources/view/tpl/connection_template.tpl new file mode 100755 index 00000000..47f01ef5 --- /dev/null +++ b/sources/view/tpl/connection_template.tpl @@ -0,0 +1,9 @@ +
    +
    + {{$contact.name}} +
    +
    +
    {{$contact.name}}
    +
    {{$contact.edit}}
    +
    +
    diff --git a/sources/view/tpl/connections.tpl b/sources/view/tpl/connections.tpl new file mode 100755 index 00000000..8e526697 --- /dev/null +++ b/sources/view/tpl/connections.tpl @@ -0,0 +1,27 @@ +
    + +

    {{$header}}{{if $total}} ({{$total}}){{/if}}

    + +{{if $finding}}

    {{$finding}}

    {{/if}} + +
    +
    +{{$desc}} + + +
    +
    +
    + +{{$tabs}} + +
    +{{foreach $contacts as $contact}} + {{include file="connection_template.tpl"}} +{{/foreach}} +
    +
    +
    +
    + +
    diff --git a/sources/view/tpl/contact_block.tpl b/sources/view/tpl/contact_block.tpl new file mode 100755 index 00000000..d1ce5ca6 --- /dev/null +++ b/sources/view/tpl/contact_block.tpl @@ -0,0 +1,12 @@ +
    +
    {{$contacts}}
    +{{if $micropro}} + {{$viewconnections}} +
    + {{foreach $micropro as $m}} + {{$m}} + {{/foreach}} +
    +{{/if}} +
    +
    diff --git a/sources/view/tpl/contact_head.tpl b/sources/view/tpl/contact_head.tpl new file mode 100755 index 00000000..72e7edbf --- /dev/null +++ b/sources/view/tpl/contact_head.tpl @@ -0,0 +1,30 @@ + + + diff --git a/sources/view/tpl/contact_slider.tpl b/sources/view/tpl/contact_slider.tpl new file mode 100755 index 00000000..550abc14 --- /dev/null +++ b/sources/view/tpl/contact_slider.tpl @@ -0,0 +1,20 @@ +
    + diff --git a/sources/view/tpl/contact_template.tpl b/sources/view/tpl/contact_template.tpl new file mode 100755 index 00000000..3d1bfa4a --- /dev/null +++ b/sources/view/tpl/contact_template.tpl @@ -0,0 +1,8 @@ +
    +
    + {{$contact.name}} +
    +
    +
    {{$contact.name}}
    +
    +
    diff --git a/sources/view/tpl/contactsajax.tpl b/sources/view/tpl/contactsajax.tpl new file mode 100644 index 00000000..a6b5ad79 --- /dev/null +++ b/sources/view/tpl/contactsajax.tpl @@ -0,0 +1,3 @@ +{{foreach $contacts as $contact}} +{{include file="connection_template.tpl"}} +{{/foreach}} diff --git a/sources/view/tpl/conv.tpl b/sources/view/tpl/conv.tpl new file mode 100755 index 00000000..ddb959b8 --- /dev/null +++ b/sources/view/tpl/conv.tpl @@ -0,0 +1,17 @@ +{{foreach $threads as $thread}} +
    + {{foreach $thread.items as $item}} + {{if $item.comment_firstcollapsed}} +
    + {{$thread.num_comments}} {{$thread.hide_text}} +
    + {{/if}} + + {{include file="{{$item.template}}"}} + + + {{/foreach}} +
    +{{/foreach}} diff --git a/sources/view/tpl/conv_frame.tpl b/sources/view/tpl/conv_frame.tpl new file mode 100755 index 00000000..aa7b55e9 --- /dev/null +++ b/sources/view/tpl/conv_frame.tpl @@ -0,0 +1,5 @@ +
    +
    +
    +
    + diff --git a/sources/view/tpl/conv_item.tpl b/sources/view/tpl/conv_item.tpl new file mode 100755 index 00000000..30a007bd --- /dev/null +++ b/sources/view/tpl/conv_item.tpl @@ -0,0 +1,185 @@ +{{if $item.comment_firstcollapsed}} + + +{{/if}} diff --git a/sources/view/tpl/conv_list.tpl b/sources/view/tpl/conv_list.tpl new file mode 100755 index 00000000..5487d593 --- /dev/null +++ b/sources/view/tpl/conv_list.tpl @@ -0,0 +1,187 @@ +{{if $item.comment_firstcollapsed}} + + +{{/if}} diff --git a/sources/view/tpl/conversation.tpl b/sources/view/tpl/conversation.tpl new file mode 100755 index 00000000..82c7be92 --- /dev/null +++ b/sources/view/tpl/conversation.tpl @@ -0,0 +1,20 @@ +
    +{{foreach $threads as $thread}} +
    + {{foreach $thread.items as $item}} + {{if $item.comment_firstcollapsed}} +
    + {{$thread.num_comments}} {{$thread.hide_text}} +
    + {{/if}} + + {{include file="{{$item.template}}"}} + + + {{/foreach}} +
    +{{/foreach}} +
    +
    diff --git a/sources/view/tpl/convobj.tpl b/sources/view/tpl/convobj.tpl new file mode 100755 index 00000000..d5cee117 --- /dev/null +++ b/sources/view/tpl/convobj.tpl @@ -0,0 +1,4 @@ +{{foreach $threads as $item}} +{{include file="{{$item.template}}"}} +{{/foreach}} + diff --git a/sources/view/tpl/cropbody.tpl b/sources/view/tpl/cropbody.tpl new file mode 100755 index 00000000..4794c0b8 --- /dev/null +++ b/sources/view/tpl/cropbody.tpl @@ -0,0 +1,58 @@ +

    {{$title}}

    +

    +{{$desc}} +

    +
    +{{$title}} +
    +
    +
    +
    + + + +
    + + + + + + + + + + + +
    + +
    + +
    diff --git a/sources/view/tpl/crophead.tpl b/sources/view/tpl/crophead.tpl new file mode 100755 index 00000000..48f37542 --- /dev/null +++ b/sources/view/tpl/crophead.tpl @@ -0,0 +1,4 @@ + + + + diff --git a/sources/view/tpl/delegate.tpl b/sources/view/tpl/delegate.tpl new file mode 100755 index 00000000..cbaa8da8 --- /dev/null +++ b/sources/view/tpl/delegate.tpl @@ -0,0 +1,57 @@ +

    {{$header}}

    + +
    {{$desc}}
    + +{{if $managers}} +

    {{$head_managers}}

    + +{{foreach $managers as $x}} + +
    + + + +
    + +{{/foreach}} +
    +
    +{{/if}} + + +

    {{$head_delegates}}

    + +{{if $delegates}} +{{foreach $delegates as $x}} + +
    + + + +
    + +{{/foreach}} +
    +{{else}} +{{$none}} +{{/if}} +
    + + +

    {{$head_potentials}}

    +{{if $potentials}} +{{foreach $potentials as $x}} + +
    + + + +
    + +{{/foreach}} +
    +{{else}} +{{$none}} +{{/if}} +
    + diff --git a/sources/view/tpl/design_tools.tpl b/sources/view/tpl/design_tools.tpl new file mode 100644 index 00000000..dffeeafa --- /dev/null +++ b/sources/view/tpl/design_tools.tpl @@ -0,0 +1,9 @@ + diff --git a/sources/view/tpl/diaspora_comment.tpl b/sources/view/tpl/diaspora_comment.tpl new file mode 100644 index 00000000..27ec3dff --- /dev/null +++ b/sources/view/tpl/diaspora_comment.tpl @@ -0,0 +1,11 @@ + + + + {{$guid}} + {{$parent_guid}} + {{$authorsig}} + {{$body}} + {{$handle}} + + + \ No newline at end of file diff --git a/sources/view/tpl/diaspora_comment_relay.tpl b/sources/view/tpl/diaspora_comment_relay.tpl new file mode 100644 index 00000000..37a9e88b --- /dev/null +++ b/sources/view/tpl/diaspora_comment_relay.tpl @@ -0,0 +1,12 @@ + + + + {{$guid}} + {{$parent_guid}} + {{$parentsig}} + {{$authorsig}} + {{$body}} + {{$handle}} + + + \ No newline at end of file diff --git a/sources/view/tpl/diaspora_consensus.tpl b/sources/view/tpl/diaspora_consensus.tpl new file mode 100644 index 00000000..b6b7cf13 --- /dev/null +++ b/sources/view/tpl/diaspora_consensus.tpl @@ -0,0 +1,17 @@ + +{{$guid_q}} +{{$question}} + + {{$guid_y}} + {{$agree}} + + + {{$guid_n}} + {{$disagree}} + + + {{$guid_a}} + {{$abstain}} + + + diff --git a/sources/view/tpl/diaspora_conversation.tpl b/sources/view/tpl/diaspora_conversation.tpl new file mode 100644 index 00000000..dc4482e4 --- /dev/null +++ b/sources/view/tpl/diaspora_conversation.tpl @@ -0,0 +1,29 @@ + + + + {{$conv.guid}} + {{$conv.subject}} + {{$conv.created_at}} + + {{foreach $conv.messages as $msg}} + + + {{$msg.guid}} + {{$msg.parent_guid}} + {{if $msg.parent_author_signature}} + {{$msg.parent_author_signature}} + {{/if}} + {{$msg.author_signature}} + {{$msg.text}} + {{$msg.created_at}} + {{$msg.diaspora_handle}} + {{$msg.conversation_guid}} + + + {{/foreach}} + + {{$conv.diaspora_handle}} + {{$conv.participant_handles}} + + + diff --git a/sources/view/tpl/diaspora_like.tpl b/sources/view/tpl/diaspora_like.tpl new file mode 100644 index 00000000..a27e9224 --- /dev/null +++ b/sources/view/tpl/diaspora_like.tpl @@ -0,0 +1,12 @@ + + + + {{$positive}} + {{$guid}} + {{$target_type}} + {{$parent_guid}} + {{$authorsig}} + {{$handle}} + + + diff --git a/sources/view/tpl/diaspora_like_relay.tpl b/sources/view/tpl/diaspora_like_relay.tpl new file mode 100644 index 00000000..8209540c --- /dev/null +++ b/sources/view/tpl/diaspora_like_relay.tpl @@ -0,0 +1,13 @@ + + + + {{$positive}} + {{$guid}} + {{$target_type}} + {{$parent_guid}} + {{$parentsig}} + {{$authorsig}} + {{$handle}} + + + diff --git a/sources/view/tpl/diaspora_message.tpl b/sources/view/tpl/diaspora_message.tpl new file mode 100644 index 00000000..3413d79b --- /dev/null +++ b/sources/view/tpl/diaspora_message.tpl @@ -0,0 +1,13 @@ + + + + {{$msg.guid}} + {{$msg.parent_guid}} + {{$msg.author_signature}} + {{$msg.text}} + {{$msg.created_at}} + {{$msg.diaspora_handle}} + {{$msg.conversation_guid}} + + + diff --git a/sources/view/tpl/diaspora_photo.tpl b/sources/view/tpl/diaspora_photo.tpl new file mode 100644 index 00000000..256459d8 --- /dev/null +++ b/sources/view/tpl/diaspora_photo.tpl @@ -0,0 +1,13 @@ + + + + {{$guid}} + {{$handle}} + {{$public}} + {{$created_at}} + {{$path}} + {{$filename}} + {{$msg_guid}} + + + diff --git a/sources/view/tpl/diaspora_post.tpl b/sources/view/tpl/diaspora_post.tpl new file mode 100644 index 00000000..ebfe9e5b --- /dev/null +++ b/sources/view/tpl/diaspora_post.tpl @@ -0,0 +1,13 @@ + + + + {{$body}} + {{$guid}} + {{$handle}} + {{$poll}} + {{$public}} + {{$created}} + {{$provider}} + + + diff --git a/sources/view/tpl/diaspora_relay_retraction.tpl b/sources/view/tpl/diaspora_relay_retraction.tpl new file mode 100644 index 00000000..5e7aed41 --- /dev/null +++ b/sources/view/tpl/diaspora_relay_retraction.tpl @@ -0,0 +1,10 @@ + + + + {{$type}} + {{$guid}} + {{$signature}} + {{$handle}} + + + diff --git a/sources/view/tpl/diaspora_relayable_retraction.tpl b/sources/view/tpl/diaspora_relayable_retraction.tpl new file mode 100644 index 00000000..4e3ff324 --- /dev/null +++ b/sources/view/tpl/diaspora_relayable_retraction.tpl @@ -0,0 +1,11 @@ + + + + {{$parentsig}} + {{$guid}} + {{$target_type}} + {{$handle}} + {{$authorsig}} + + + diff --git a/sources/view/tpl/diaspora_reshare.tpl b/sources/view/tpl/diaspora_reshare.tpl new file mode 100644 index 00000000..963bb9e1 --- /dev/null +++ b/sources/view/tpl/diaspora_reshare.tpl @@ -0,0 +1,13 @@ + + + + {{$root_handle}} + {{$root_guid}} + {{$guid}} + {{$handle}} + {{$public}} + {{$created}} + {{$provider}} + + + diff --git a/sources/view/tpl/diaspora_retract.tpl b/sources/view/tpl/diaspora_retract.tpl new file mode 100644 index 00000000..9df066d3 --- /dev/null +++ b/sources/view/tpl/diaspora_retract.tpl @@ -0,0 +1,9 @@ + + + + {{$guid}} + {{$handle}} + {{$type}} + + + diff --git a/sources/view/tpl/diaspora_share.tpl b/sources/view/tpl/diaspora_share.tpl new file mode 100644 index 00000000..59eb0612 --- /dev/null +++ b/sources/view/tpl/diaspora_share.tpl @@ -0,0 +1,8 @@ + + + + {{$sender}} + {{$recipient}} + + + \ No newline at end of file diff --git a/sources/view/tpl/diaspora_signed_retract.tpl b/sources/view/tpl/diaspora_signed_retract.tpl new file mode 100644 index 00000000..f0f346da --- /dev/null +++ b/sources/view/tpl/diaspora_signed_retract.tpl @@ -0,0 +1,10 @@ + + + + {{$guid}} + {{$type}} + {{$handle}} + {{$signature}} + + + diff --git a/sources/view/tpl/diaspora_vcard.tpl b/sources/view/tpl/diaspora_vcard.tpl new file mode 100644 index 00000000..f9dac930 --- /dev/null +++ b/sources/view/tpl/diaspora_vcard.tpl @@ -0,0 +1,57 @@ +
    +
    +
    Nickname
    +
    + {{$diaspora.fullname}} +
    +
    +
    +
    Full name
    +
    + {{$diaspora.fullname}} +
    +
    + +
    +
    First name
    +
    + {{$diaspora.firstname}} +
    +
    +
    +
    Family name
    +
    + {{$diaspora.lastname}} +
    +
    +
    +
    URL
    +
    + {{$diaspora.podloc}}/ +
    +
    +
    +
    Photo
    +
    + +
    +
    +
    +
    Photo
    +
    + +
    +
    +
    +
    Photo
    +
    + +
    +
    +
    +
    Searchable
    +
    + {{$diaspora.searchable}} +
    +
    +
    diff --git a/sources/view/tpl/dir_sort_links.tpl b/sources/view/tpl/dir_sort_links.tpl new file mode 100644 index 00000000..9346a745 --- /dev/null +++ b/sources/view/tpl/dir_sort_links.tpl @@ -0,0 +1,8 @@ + diff --git a/sources/view/tpl/directajax.tpl b/sources/view/tpl/directajax.tpl new file mode 100644 index 00000000..8faec422 --- /dev/null +++ b/sources/view/tpl/directajax.tpl @@ -0,0 +1,4 @@ +{{foreach $entries as $entry}} +{{include file="direntry.tpl"}} +{{/foreach}} + diff --git a/sources/view/tpl/directory_header.tpl b/sources/view/tpl/directory_header.tpl new file mode 100755 index 00000000..79598fc9 --- /dev/null +++ b/sources/view/tpl/directory_header.tpl @@ -0,0 +1,24 @@ +
    +
    + +

    {{$dirlbl}}{{if $search}}: {{$safetxt}}{{/if}}

    +
    +
    + {{foreach $entries as $entry}} + {{include file="direntry.tpl"}} + {{/foreach}} +
    +
    +
    + +
    diff --git a/sources/view/tpl/direntry.tpl b/sources/view/tpl/direntry.tpl new file mode 100755 index 00000000..6407f1ed --- /dev/null +++ b/sources/view/tpl/direntry.tpl @@ -0,0 +1,75 @@ +
    +
    +
    + {{if $entry.viewrate}} + {{if $entry.canrate}}{{/if}} + {{if $entry.total_ratings}}{{$entry.total_ratings}}{{/if}} + {{/if}} + {{if $entry.ignlink}} + {{$entry.ignore_label}} + {{/if}} + {{if $entry.connect}} + {{$entry.conn_label}} + {{/if}} +
    +

    {{if $entry.public_forum}} {{/if}}{{$entry.name}}{{if $entry.online}} {{/if}}

    +
    +
    +
    +
    + + {{$entry.alttext}} + +
    +
    +
    + {{if $entry.common_friends}} +
    + {{$entry.common_label}} {{$entry.common_count}} +
    + {{/if}} + + {{if $entry.pdesc}} +
    + {{$entry.pdesc_label}} {{$entry.pdesc}} +
    + {{/if}} + + {{if $entry.age}} +
    + {{$entry.age_label}} {{$entry.age}} +
    + {{/if}} + + {{if $entry.location}} +
    + {{$entry.location_label}} {{$entry.location}} +
    + {{/if}} + + {{if $entry.hometown}} +
    + {{$entry.hometown_label}} {{$entry.hometown}} +
    + {{/if}} + + {{if $entry.homepage}} +
    + {{$entry.homepage}} {{$entry.homepageurl}} +
    + {{/if}} + + {{if $entry.kw}} +
    + {{$entry.kw}} {{$entry.keywords}} +
    + {{/if}} + + {{if $entry.about}} +
    + {{$entry.about_label}} {{$entry.about}} +
    + {{/if}} +
    +
    +
    diff --git a/sources/view/tpl/display-head.tpl b/sources/view/tpl/display-head.tpl new file mode 100755 index 00000000..913784d9 --- /dev/null +++ b/sources/view/tpl/display-head.tpl @@ -0,0 +1,8 @@ + + diff --git a/sources/view/tpl/edpost_head.tpl b/sources/view/tpl/edpost_head.tpl new file mode 100755 index 00000000..3be40e97 --- /dev/null +++ b/sources/view/tpl/edpost_head.tpl @@ -0,0 +1,14 @@ +
    +
    + {{if $delete}} + + {{/if}} +

    {{$title}}

    +
    +
    +
    + {{$editor}} +
    +
    diff --git a/sources/view/tpl/email_notify_html.tpl b/sources/view/tpl/email_notify_html.tpl new file mode 100755 index 00000000..ae3e8c01 --- /dev/null +++ b/sources/view/tpl/email_notify_html.tpl @@ -0,0 +1,27 @@ + + + + {{$banner}} + + + + + + + + + + + + + + + + + + + + +
    {{$product}}
    {{$preamble}}
    {{$source_name}}
    {{$title}}
    {{$htmlversion}}
    {{$hsitelink}}
    {{$hitemlink}}
    {{$thanks}}
    {{$site_admin}}
    + + diff --git a/sources/view/tpl/email_notify_text.tpl b/sources/view/tpl/email_notify_text.tpl new file mode 100755 index 00000000..bdab4c27 --- /dev/null +++ b/sources/view/tpl/email_notify_text.tpl @@ -0,0 +1,12 @@ +{{$preamble}} + +{{$title}} + +{{$textversion}} + +{{$tsitelink}} +{{$titemlink}} + +{{$thanks}} +{{$site_admin}} + diff --git a/sources/view/tpl/event.tpl b/sources/view/tpl/event.tpl new file mode 100755 index 00000000..5dfc91eb --- /dev/null +++ b/sources/view/tpl/event.tpl @@ -0,0 +1,16 @@ +{{foreach $events as $event}} +
    +
    +
    + {{if $event.item.author.xchan_name}}{{$event.item.author.xchan_name}}{{/if}} +
    + {{$event.html}} +
    + {{if $event.item.plink}}{{/if}} + {{if $event.edit}}{{/if}} + {{if $event.drop}}{{/if}} +
    +
    +
    +
    +{{/foreach}} diff --git a/sources/view/tpl/event_form.tpl b/sources/view/tpl/event_form.tpl new file mode 100755 index 00000000..15505397 --- /dev/null +++ b/sources/view/tpl/event_form.tpl @@ -0,0 +1,177 @@ +
    + +

    {{$title}}

    + +

    +{{$desc}} +

    + +
    + + + + + + + + +
    {{$t_text}}
    +{{$required}} + +
    + +
    {{$s_text}}
    + +{{$s_dsel}} + +

    + +
    + +
    +
    +
    + +
    + +
    +
    {{$f_text}}
    +{{$f_dsel}} +
    + +
    + +{{include file="field_checkbox.tpl" field=$adjust}} + +
    + + + +{{if $catsenabled}} +
    + +
    +{{/if}} + + + +
    {{$d_text}}
    + + +
    +
    +
    +
    + + + + + +
    + +
    + + + +
    + +
    +
    + +
    + +
    {{$l_text}}
    + + + +
    +
    +
    +
    + + + + + +
    + +
    + + + + +
    + +
    + + +
    + + + +
    + +
    + +{{if ! $eid}} + +
    + +
    +
    +
    + + +
    + + + + +{{$acl}} + +{{/if}} + +
    + + + + +
    + +
    diff --git a/sources/view/tpl/event_head.tpl b/sources/view/tpl/event_head.tpl new file mode 100755 index 00000000..fd0ef0d9 --- /dev/null +++ b/sources/view/tpl/event_head.tpl @@ -0,0 +1,171 @@ + + + + + +{{if $editselect != 'none'}} + + + diff --git a/sources/view/tpl/events-js.tpl b/sources/view/tpl/events-js.tpl new file mode 100755 index 00000000..bb6ca63a --- /dev/null +++ b/sources/view/tpl/events-js.tpl @@ -0,0 +1,30 @@ +{{$tabs}} +
    +

    {{$title}}

    + +
    +   +
    + + + + +
    +
    +
    +
    diff --git a/sources/view/tpl/events_reminder.tpl b/sources/view/tpl/events_reminder.tpl new file mode 100755 index 00000000..fd6a1a5c --- /dev/null +++ b/sources/view/tpl/events_reminder.tpl @@ -0,0 +1,10 @@ +{{if $count}} + + +{{/if}} + diff --git a/sources/view/tpl/failed_updates.tpl b/sources/view/tpl/failed_updates.tpl new file mode 100755 index 00000000..f53f1f47 --- /dev/null +++ b/sources/view/tpl/failed_updates.tpl @@ -0,0 +1,18 @@ +
    +

    {{$banner}}

    + +
    {{$desc}}
    + +{{if $failed}} +{{foreach $failed as $f}} + +

    {{$f}}

    + + +
    +{{/foreach}} +{{/if}} +
    diff --git a/sources/view/tpl/field.tpl b/sources/view/tpl/field.tpl new file mode 100755 index 00000000..942cfcef --- /dev/null +++ b/sources/view/tpl/field.tpl @@ -0,0 +1,3 @@ + {{if $field.0==select}} + {{include file="field_select.tpl"}} + {{/if}} diff --git a/sources/view/tpl/field_acheckbox.tpl b/sources/view/tpl/field_acheckbox.tpl new file mode 100755 index 00000000..e99128bb --- /dev/null +++ b/sources/view/tpl/field_acheckbox.tpl @@ -0,0 +1,22 @@ + + +
    + {{$field.6}} + + {{if $notself}} + + {{if $field.2}}{{else}}{{/if}} + + {{/if}} + + {{if $self || !$field.5}} + + {{/if}} + {{if $notself && $field.5}} + {{if $field.3}}{{else}}{{/if}} + {{/if}} + + + {{if $field.5}}{{$inherited}}{{if $self}}{{if $field.7}} {{else}} {{/if}}{{/if}}{{/if}} + + diff --git a/sources/view/tpl/field_checkbox.tpl b/sources/view/tpl/field_checkbox.tpl new file mode 100755 index 00000000..6785e522 --- /dev/null +++ b/sources/view/tpl/field_checkbox.tpl @@ -0,0 +1,6 @@ +
    + +
    + {{$field.3}} +
    +
    diff --git a/sources/view/tpl/field_colorinput.tpl b/sources/view/tpl/field_colorinput.tpl new file mode 100644 index 00000000..9b6f3346 --- /dev/null +++ b/sources/view/tpl/field_colorinput.tpl @@ -0,0 +1,6 @@ +
    + + {{if $field.4}} {{$field.4}} {{/if}} + {{$field.3}} +
    +
    diff --git a/sources/view/tpl/field_combobox.tpl b/sources/view/tpl/field_combobox.tpl new file mode 100755 index 00000000..337c6067 --- /dev/null +++ b/sources/view/tpl/field_combobox.tpl @@ -0,0 +1,17 @@ +
    + + {{* html5 don't work on Chrome, Safari and IE9 see https://github.com/thgreasi/datalist-polyfill + + + {{foreach $field.4 as $opt=>$val}} *}} + + + + + {{$field.3}} +
    + diff --git a/sources/view/tpl/field_custom.tpl b/sources/view/tpl/field_custom.tpl new file mode 100755 index 00000000..907b4c50 --- /dev/null +++ b/sources/view/tpl/field_custom.tpl @@ -0,0 +1,5 @@ +
    + + {{$field.2}} + {{$field.3}} +
    diff --git a/sources/view/tpl/field_input.tpl b/sources/view/tpl/field_input.tpl new file mode 100755 index 00000000..128bbfbe --- /dev/null +++ b/sources/view/tpl/field_input.tpl @@ -0,0 +1,6 @@ +
    + + + {{$field.3}} +
    +
    diff --git a/sources/view/tpl/field_intcheckbox.tpl b/sources/view/tpl/field_intcheckbox.tpl new file mode 100755 index 00000000..565f9776 --- /dev/null +++ b/sources/view/tpl/field_intcheckbox.tpl @@ -0,0 +1,6 @@ +
    + +
    + {{$field.4}} +
    +
    diff --git a/sources/view/tpl/field_password.tpl b/sources/view/tpl/field_password.tpl new file mode 100755 index 00000000..d19bc941 --- /dev/null +++ b/sources/view/tpl/field_password.tpl @@ -0,0 +1,5 @@ +
    + + {{if $field.4}} {{$field.4}} {{/if}} + {{$field.3}} +
    diff --git a/sources/view/tpl/field_radio.tpl b/sources/view/tpl/field_radio.tpl new file mode 100755 index 00000000..6b5f52de --- /dev/null +++ b/sources/view/tpl/field_radio.tpl @@ -0,0 +1,8 @@ +
    + + {{$field.3}} +
    +
    diff --git a/sources/view/tpl/field_richtext.tpl b/sources/view/tpl/field_richtext.tpl new file mode 100755 index 00000000..378e02a6 --- /dev/null +++ b/sources/view/tpl/field_richtext.tpl @@ -0,0 +1,5 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_select.tpl b/sources/view/tpl/field_select.tpl new file mode 100755 index 00000000..76244729 --- /dev/null +++ b/sources/view/tpl/field_select.tpl @@ -0,0 +1,7 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_select_disabled.tpl b/sources/view/tpl/field_select_disabled.tpl new file mode 100644 index 00000000..ee5e1508 --- /dev/null +++ b/sources/view/tpl/field_select_disabled.tpl @@ -0,0 +1,7 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_select_grouped.tpl b/sources/view/tpl/field_select_grouped.tpl new file mode 100644 index 00000000..e6d1479d --- /dev/null +++ b/sources/view/tpl/field_select_grouped.tpl @@ -0,0 +1,12 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_select_raw.tpl b/sources/view/tpl/field_select_raw.tpl new file mode 100755 index 00000000..2780df58 --- /dev/null +++ b/sources/view/tpl/field_select_raw.tpl @@ -0,0 +1,7 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_textarea.tpl b/sources/view/tpl/field_textarea.tpl new file mode 100755 index 00000000..01fdc23f --- /dev/null +++ b/sources/view/tpl/field_textarea.tpl @@ -0,0 +1,5 @@ +
    + + + {{$field.3}} +
    diff --git a/sources/view/tpl/field_themeselect.tpl b/sources/view/tpl/field_themeselect.tpl new file mode 100755 index 00000000..250f9fcf --- /dev/null +++ b/sources/view/tpl/field_themeselect.tpl @@ -0,0 +1,9 @@ + {{if $field.5=='preview'}}{{/if}} +
    + + + {{$field.3}} + {{if $field.5=='preview'}}
    {{/if}} +
    diff --git a/sources/view/tpl/field_yesno.tpl b/sources/view/tpl/field_yesno.tpl new file mode 100755 index 00000000..f5a90983 --- /dev/null +++ b/sources/view/tpl/field_yesno.tpl @@ -0,0 +1,13 @@ + diff --git a/sources/view/tpl/fileas_widget.tpl b/sources/view/tpl/fileas_widget.tpl new file mode 100755 index 00000000..a92440cb --- /dev/null +++ b/sources/view/tpl/fileas_widget.tpl @@ -0,0 +1,12 @@ +
    +

    {{$title}}

    +
    {{$desc}}
    + + + +
    diff --git a/sources/view/tpl/filebrowser.tpl b/sources/view/tpl/filebrowser.tpl new file mode 100755 index 00000000..787f7c0c --- /dev/null +++ b/sources/view/tpl/filebrowser.tpl @@ -0,0 +1,84 @@ + + + + + + + + + +
    +
      +
    • FileBrowser
    • +
    +
    +
    + +
    +
    + {{foreach $path as $p}}{{$p.1}}{{/foreach}} +
    +
    +
      + {{foreach $folders as $f}}
    • {{$f.1}}
    • {{/foreach}} +
    +
    +
    +
      + {{foreach $files as $f}} +
    • {{$f.1}}
    • + {{/foreach}} +
    +
    +
    +
    +
    + +
    + + + diff --git a/sources/view/tpl/filer_dialog.tpl b/sources/view/tpl/filer_dialog.tpl new file mode 100755 index 00000000..ae59ab71 --- /dev/null +++ b/sources/view/tpl/filer_dialog.tpl @@ -0,0 +1,4 @@ +{{include file="field_combobox.tpl"}} +
    + +
    diff --git a/sources/view/tpl/follow.tpl b/sources/view/tpl/follow.tpl new file mode 100755 index 00000000..f643a359 --- /dev/null +++ b/sources/view/tpl/follow.tpl @@ -0,0 +1,12 @@ +
    +

    {{$connect}}

    +
    {{$desc}}
    +
    + + +
    + {{if $abook_usage_message}} +
    {{$abook_usage_message}}
    + {{/if}} +
    + diff --git a/sources/view/tpl/generic_addon_settings.tpl b/sources/view/tpl/generic_addon_settings.tpl new file mode 100644 index 00000000..bf39b2ae --- /dev/null +++ b/sources/view/tpl/generic_addon_settings.tpl @@ -0,0 +1,19 @@ +
    + +
    +
    + {{$content}} + {{if $addon.0}} +
    + +
    + {{/if}} +
    +
    +
    diff --git a/sources/view/tpl/generic_links_widget.tpl b/sources/view/tpl/generic_links_widget.tpl new file mode 100755 index 00000000..d7c234a8 --- /dev/null +++ b/sources/view/tpl/generic_links_widget.tpl @@ -0,0 +1,11 @@ +
    + {{if $title}}

    {{$title}}

    {{/if}} + {{if $desc}}
    {{$desc}}
    {{/if}} + + + +
    diff --git a/sources/view/tpl/group_drop.tpl b/sources/view/tpl/group_drop.tpl new file mode 100755 index 00000000..34ee3e3f --- /dev/null +++ b/sources/view/tpl/group_drop.tpl @@ -0,0 +1,7 @@ +
    + +
    +
    diff --git a/sources/view/tpl/group_edit.tpl b/sources/view/tpl/group_edit.tpl new file mode 100755 index 00000000..eb658624 --- /dev/null +++ b/sources/view/tpl/group_edit.tpl @@ -0,0 +1,24 @@ +

    {{$title}}

    + + +
    +
    + + + {{include file="field_input.tpl" field=$gname}} + {{include file="field_checkbox.tpl" field=$public}} + {{if $drop}}{{$drop}}{{/if}} +
    + +
    +
    +
    +
    + + +{{if $groupeditor}} +
    + {{include file="groupeditor.tpl"}} +
    +{{/if}} +{{if $desc}}
    {{$desc}}
    {{/if}} diff --git a/sources/view/tpl/group_selection.tpl b/sources/view/tpl/group_selection.tpl new file mode 100755 index 00000000..270d2aa7 --- /dev/null +++ b/sources/view/tpl/group_selection.tpl @@ -0,0 +1,8 @@ +
    + + +
    diff --git a/sources/view/tpl/group_side.tpl b/sources/view/tpl/group_side.tpl new file mode 100755 index 00000000..95275707 --- /dev/null +++ b/sources/view/tpl/group_side.tpl @@ -0,0 +1,28 @@ +
    +

    {{$title}}

    +
    + + +
    +
    + + + + diff --git a/sources/view/tpl/groupeditor.tpl b/sources/view/tpl/groupeditor.tpl new file mode 100755 index 00000000..c79bb0a2 --- /dev/null +++ b/sources/view/tpl/groupeditor.tpl @@ -0,0 +1,16 @@ +
    +

    {{$groupeditor.label_members}}

    +
    +{{foreach $groupeditor.members as $c}} {{$c}} {{/foreach}} +
    +
    +
    +
    + +
    +

    {{$groupeditor.label_contacts}}

    +
    +{{foreach $groupeditor.contacts as $m}} {{$m}} {{/foreach}} +
    +
    +
    diff --git a/sources/view/tpl/hdr.tpl b/sources/view/tpl/hdr.tpl new file mode 100644 index 00000000..c3f0700f --- /dev/null +++ b/sources/view/tpl/hdr.tpl @@ -0,0 +1,5 @@ + + + diff --git a/sources/view/tpl/head.tpl b/sources/view/tpl/head.tpl new file mode 100755 index 00000000..8a007232 --- /dev/null +++ b/sources/view/tpl/head.tpl @@ -0,0 +1,35 @@ + + + + + + + +{{$head_css}} + +{{$js_strings}} + +{{$head_js}} + + + + + + + + + diff --git a/sources/view/tpl/help.tpl b/sources/view/tpl/help.tpl new file mode 100644 index 00000000..22180bda --- /dev/null +++ b/sources/view/tpl/help.tpl @@ -0,0 +1,8 @@ +
    +
    +

    {{$title}}

    +
    +
    + {{$content}} +
    +
    diff --git a/sources/view/tpl/install.tpl b/sources/view/tpl/install.tpl new file mode 100755 index 00000000..0e77aa97 --- /dev/null +++ b/sources/view/tpl/install.tpl @@ -0,0 +1,9 @@ +

    {{$title}}

    +

    {{$pass}}

    + + +{{if $status}} +

    {{$status}}

    +{{/if}} + +{{$text}} diff --git a/sources/view/tpl/install_checks.tpl b/sources/view/tpl/install_checks.tpl new file mode 100755 index 00000000..2f773f74 --- /dev/null +++ b/sources/view/tpl/install_checks.tpl @@ -0,0 +1,24 @@ +

    {{$title}}

    +

    {{$pass}}

    +
    + +{{foreach $checks as $check}} + + {{if $check.help}} + + {{/if}} +{{/foreach}} +
    {{$check.title}} {{if $check.required}}(required){{/if}}
    {{$check.help}}
    + +{{if $phpath}} + +{{/if}} + +{{if $passed}} + + +{{else}} + + +{{/if}} +
    diff --git a/sources/view/tpl/install_db.tpl b/sources/view/tpl/install_db.tpl new file mode 100755 index 00000000..1a58de12 --- /dev/null +++ b/sources/view/tpl/install_db.tpl @@ -0,0 +1,30 @@ +

    {{$title}}

    +

    {{$pass}}

    + + +

    +{{$info_01}}
    +{{$info_02}}
    +{{$info_03}} +

    + +{{if $status}} +

    {{$status}}

    +{{/if}} + +
    + + + + +{{include file="field_input.tpl" field=$dbhost}} +{{include file="field_input.tpl" field=$dbport}} +{{include file="field_input.tpl" field=$dbuser}} +{{include file="field_password.tpl" field=$dbpass}} +{{include file="field_input.tpl" field=$dbdata}} +{{include file="field_select.tpl" field=$dbtype}} + + + +
    + diff --git a/sources/view/tpl/install_settings.tpl b/sources/view/tpl/install_settings.tpl new file mode 100755 index 00000000..62dcbb8b --- /dev/null +++ b/sources/view/tpl/install_settings.tpl @@ -0,0 +1,28 @@ +

    {{$title}}

    +

    {{$pass}}

    + + +{{if $status}} +

    {{$status}}

    +{{/if}} + +
    + + + + + + + + + + +{{include file="field_input.tpl" field=$adminmail}} +{{include file="field_input.tpl" field=$siteurl}} + +{{include file="field_select_grouped.tpl" field=$timezone}} + + + +
    + diff --git a/sources/view/tpl/invite.tpl b/sources/view/tpl/invite.tpl new file mode 100755 index 00000000..2b7ab9cf --- /dev/null +++ b/sources/view/tpl/invite.tpl @@ -0,0 +1,30 @@ +
    + + + +
    + +

    {{$invite}}

    + +
    +{{$addr_text}} +
    + +
    + +
    + +
    +{{$msg_text}} +
    + +
    + +
    + +
    + +
    + +
    +
    diff --git a/sources/view/tpl/item_attach.tpl b/sources/view/tpl/item_attach.tpl new file mode 100644 index 00000000..eeea2596 --- /dev/null +++ b/sources/view/tpl/item_attach.tpl @@ -0,0 +1,8 @@ +
    +{{if $attaches}} +
    + {{foreach $attaches as $a}} + + {{/foreach}} +
    +{{/if}} diff --git a/sources/view/tpl/item_categories.tpl b/sources/view/tpl/item_categories.tpl new file mode 100644 index 00000000..ec2639a6 --- /dev/null +++ b/sources/view/tpl/item_categories.tpl @@ -0,0 +1,8 @@ +{{if $categories}} +
    +{{foreach $categories as $cat}} + {{if $cat.url}}{{$cat.term}}{{else}}{{$cat.term}}{{/if}} +{{/foreach}} +
    +{{/if}} + diff --git a/sources/view/tpl/item_filer.tpl b/sources/view/tpl/item_filer.tpl new file mode 100644 index 00000000..07163d59 --- /dev/null +++ b/sources/view/tpl/item_filer.tpl @@ -0,0 +1,8 @@ +{{if $categories}} +
    +{{foreach $categories as $cat}} + {{$cat.term}}  +{{/foreach}} +
    +{{/if}} + diff --git a/sources/view/tpl/item_import.tpl b/sources/view/tpl/item_import.tpl new file mode 100755 index 00000000..65de7fca --- /dev/null +++ b/sources/view/tpl/item_import.tpl @@ -0,0 +1,15 @@ +

    {{$title}}

    + +
    + +
    {{$desc}}
    + + + +
    + + +
    + +
    + diff --git a/sources/view/tpl/jot-header.tpl b/sources/view/tpl/jot-header.tpl new file mode 100755 index 00000000..424d856e --- /dev/null +++ b/sources/view/tpl/jot-header.tpl @@ -0,0 +1,368 @@ + + + + + diff --git a/sources/view/tpl/jot.tpl b/sources/view/tpl/jot.tpl new file mode 100755 index 00000000..100dd15b --- /dev/null +++ b/sources/view/tpl/jot.tpl @@ -0,0 +1,185 @@ +
    +
    + {{if $parent}} + + {{/if}} + + + + + + + + + + + + + {{if $showacl}}{{$acl}}{{/if}} + {{$mimeselect}} + {{$layoutselect}} + {{if $id_select}} +
    + {{$id_seltext}} {{$id_select}} +
    + {{/if}} + {{if $webpage}} +
    + +
    + {{/if}} +
    + +
    + {{if $catsenabled}} +
    + +
    + {{/if}} +
    + +
    + {{if $attachment}} +
    + +
    + {{/if}} +
    +
    +
    + + + + + +
    + {{if $visitor}} + + +
    +
    +
    +
    + {{if $showacl}} + + {{/if}} + {{if $preview}} + + {{/if}} + +
    +
    +
    + {{$jotplugins}} +
    +
    +
    +
    + + +
    + + + + +{{if $content || $attachment || $expanded}} + +{{/if}} diff --git a/sources/view/tpl/jot_geotag.tpl b/sources/view/tpl/jot_geotag.tpl new file mode 100755 index 00000000..60f12885 --- /dev/null +++ b/sources/view/tpl/jot_geotag.tpl @@ -0,0 +1,7 @@ + if(navigator.geolocation) { + navigator.geolocation.getCurrentPosition(function(position) { + $('#jot-coord').val(position.coords.latitude + ' ' + position.coords.longitude); + $('#profile-nolocation-wrapper').attr('disabled', false); + }); + } + diff --git a/sources/view/tpl/js_strings.tpl b/sources/view/tpl/js_strings.tpl new file mode 100755 index 00000000..38cf8edb --- /dev/null +++ b/sources/view/tpl/js_strings.tpl @@ -0,0 +1,56 @@ + + diff --git a/sources/view/tpl/lang_selector.tpl b/sources/view/tpl/lang_selector.tpl new file mode 100755 index 00000000..b512c759 --- /dev/null +++ b/sources/view/tpl/lang_selector.tpl @@ -0,0 +1,11 @@ +

    {{$title}}

    +
    +
    +
    + +
    +
    diff --git a/sources/view/tpl/layoutlist.tpl b/sources/view/tpl/layoutlist.tpl new file mode 100644 index 00000000..cf172e19 --- /dev/null +++ b/sources/view/tpl/layoutlist.tpl @@ -0,0 +1,71 @@ +
    +
    + {{if $editor}} +
    + +  {{$help.text}} +
    + {{/if}} +

    {{$title}}

    +
    +
    + {{if $editor}} +
    + {{$editor}} +
    + {{/if}} + + {{if $pages}} +
    + + + + + + + + + + + {{foreach $pages as $key => $items}} + {{foreach $items as $item}} + + + + + + + + + + {{/foreach}} + {{/foreach}} +
    {{$name}}{{$descr}}
    + {{if $view}} + {{$item.title}} + {{else}} + {{$item.title}} + {{/if}} + + {{$item.descr}} + + {{if $edit}} + + {{/if}} + + {{if $item.bb_element}} + + {{/if}} + + {{if $edit}} + + {{/if}} +
    +
    +
    + {{/if}} +
    diff --git a/sources/view/tpl/like_noshare.tpl b/sources/view/tpl/like_noshare.tpl new file mode 100755 index 00000000..3ce7eb49 --- /dev/null +++ b/sources/view/tpl/like_noshare.tpl @@ -0,0 +1,5 @@ + diff --git a/sources/view/tpl/locmanage.tpl b/sources/view/tpl/locmanage.tpl new file mode 100644 index 00000000..40f91a8b --- /dev/null +++ b/sources/view/tpl/locmanage.tpl @@ -0,0 +1,26 @@ +

    {{$header}}

    + + + + + +{{foreach $hubs as $hub}} + + + + +{{/foreach}} +
    {{$loc}}{{$mkprm}}{{$drop}}
    +{{if $hub.deleted}}{{/if}} +{{$hub.hubloc_url}} ({{$hub.hubloc_addr}}){{if $hub.deleted}}{{/if}} + +{{if $hub.primary}}{{else}}{{/if}} +{{if $hub.primary}}{{else}}{{if ! $hub.deleted}}{{/if}}{{/if}}
    + diff --git a/sources/view/tpl/login.tpl b/sources/view/tpl/login.tpl new file mode 100755 index 00000000..9472bd96 --- /dev/null +++ b/sources/view/tpl/login.tpl @@ -0,0 +1,19 @@ +
    + +
    +
    + {{include file="field_input.tpl" field=$lname}} + {{include file="field_password.tpl" field=$lpassword}} + {{include file="field_checkbox.tpl" field=$remember}} + +
    + +
    + {{foreach $hiddens as $k=>$v}} + + {{/foreach}} +
    + diff --git a/sources/view/tpl/logout.tpl b/sources/view/tpl/logout.tpl new file mode 100755 index 00000000..7548ed19 --- /dev/null +++ b/sources/view/tpl/logout.tpl @@ -0,0 +1,6 @@ +
    +
    + + +
    +
    diff --git a/sources/view/tpl/lostpass.tpl b/sources/view/tpl/lostpass.tpl new file mode 100755 index 00000000..f6fdb28d --- /dev/null +++ b/sources/view/tpl/lostpass.tpl @@ -0,0 +1,18 @@ +

    {{$title}}

    + +

    +{{$desc}} +

    + +
    +
    + + +
    +
    +
    + +
    +
    +
    + diff --git a/sources/view/tpl/mail_conv.tpl b/sources/view/tpl/mail_conv.tpl new file mode 100755 index 00000000..ec8f8c1e --- /dev/null +++ b/sources/view/tpl/mail_conv.tpl @@ -0,0 +1,18 @@ +
    +
    + {{$mail.from_name}} +
    {{$mail.from_name}}
    +
    +
    + {{if $mail.is_recalled}}{{$mail.is_recalled}}{{/if}} +
    {{$mail.date}}
    +
    {{$mail.subject}}
    +
    {{$mail.body}}
    +
    + {{if $mail.can_recall}} +
    + {{/if}} +
    +
    +
    +
    diff --git a/sources/view/tpl/mail_display.tpl b/sources/view/tpl/mail_display.tpl new file mode 100755 index 00000000..523a9160 --- /dev/null +++ b/sources/view/tpl/mail_display.tpl @@ -0,0 +1,12 @@ +

    {{$prvmsg_header}}

    +
    +{{foreach $mails as $mail}} + {{include file="mail_conv.tpl"}} +{{/foreach}} + +{{if $canreply}} +{{include file="prv_message.tpl"}} +{{else}} +{{$unknown_text}} +{{/if}} +
    diff --git a/sources/view/tpl/mail_head.tpl b/sources/view/tpl/mail_head.tpl new file mode 100755 index 00000000..1cd7145e --- /dev/null +++ b/sources/view/tpl/mail_head.tpl @@ -0,0 +1,3 @@ +

    {{$messages}}

    + +{{$tab_content}} diff --git a/sources/view/tpl/mail_list.tpl b/sources/view/tpl/mail_list.tpl new file mode 100755 index 00000000..1d499e12 --- /dev/null +++ b/sources/view/tpl/mail_list.tpl @@ -0,0 +1,8 @@ +
    + {{$from_name}} + {{$from_name}} + {{$subject}} + {{$date}} + +
     
    +
    diff --git a/sources/view/tpl/main_slider.tpl b/sources/view/tpl/main_slider.tpl new file mode 100755 index 00000000..a4e2e192 --- /dev/null +++ b/sources/view/tpl/main_slider.tpl @@ -0,0 +1,38 @@ +
    + diff --git a/sources/view/tpl/match.tpl b/sources/view/tpl/match.tpl new file mode 100755 index 00000000..41587430 --- /dev/null +++ b/sources/view/tpl/match.tpl @@ -0,0 +1,16 @@ +
    +
    + + {{$name}} + +
    +
    +
    + {{$name}} +
    +
    + {{if $connlnk}} + + {{/if}} + +
    diff --git a/sources/view/tpl/menuedit.tpl b/sources/view/tpl/menuedit.tpl new file mode 100644 index 00000000..5c8734ef --- /dev/null +++ b/sources/view/tpl/menuedit.tpl @@ -0,0 +1,33 @@ +{{if $header}} +
    +
    + {{if $menu_edit_link}} + + {{/if}} +

    {{$header}}

    +
    +
    +{{/if}} + +{{if $header}} +
    +{{/if}} diff --git a/sources/view/tpl/menulist.tpl b/sources/view/tpl/menulist.tpl new file mode 100644 index 00000000..743165cc --- /dev/null +++ b/sources/view/tpl/menulist.tpl @@ -0,0 +1,40 @@ +
    +
    +
    + +
    +

    {{$title}}

    +
    +
    + + {{$create}} + + {{if $menus }} + + {{/if}} +
    diff --git a/sources/view/tpl/message_side.tpl b/sources/view/tpl/message_side.tpl new file mode 100755 index 00000000..3e32eae1 --- /dev/null +++ b/sources/view/tpl/message_side.tpl @@ -0,0 +1,14 @@ +
    +

    {{$title}}

    + + {{if $tabs}} + + {{/if}} +
    diff --git a/sources/view/tpl/micropro_img.tpl b/sources/view/tpl/micropro_img.tpl new file mode 100755 index 00000000..23b7bd28 --- /dev/null +++ b/sources/view/tpl/micropro_img.tpl @@ -0,0 +1 @@ +
    {{$name}}
    diff --git a/sources/view/tpl/micropro_txt.tpl b/sources/view/tpl/micropro_txt.tpl new file mode 100755 index 00000000..295e7940 --- /dev/null +++ b/sources/view/tpl/micropro_txt.tpl @@ -0,0 +1 @@ + diff --git a/sources/view/tpl/mitemedit.tpl b/sources/view/tpl/mitemedit.tpl new file mode 100644 index 00000000..f9dc4e2c --- /dev/null +++ b/sources/view/tpl/mitemedit.tpl @@ -0,0 +1,42 @@ +{{if $header}} +
    +
    +

    {{$header}}

    +
    +{{/if}} + +{{if $header}} +
    +{{/if}} diff --git a/sources/view/tpl/mitemlist.tpl b/sources/view/tpl/mitemlist.tpl new file mode 100644 index 00000000..8686d420 --- /dev/null +++ b/sources/view/tpl/mitemlist.tpl @@ -0,0 +1,34 @@ +
    +
    +
    + +
    +

    {{$title}} {{if $menudesc}}{{$menudesc}}{{else}}{{$menuname}}{{/if}}

    +
    +
    + + {{$create}} + + {{if $mlist }} +
    + + + + + + + + + {{foreach $mlist as $m }} + + + + + + + + {{/foreach}} +
    {{$nametitle}}{{$targettitle}}
    {{$m.mitem_desc}}{{$m.mitem_link}}
    +
    + {{/if}} +
    diff --git a/sources/view/tpl/mood_content.tpl b/sources/view/tpl/mood_content.tpl new file mode 100755 index 00000000..63eaa2d8 --- /dev/null +++ b/sources/view/tpl/mood_content.tpl @@ -0,0 +1,20 @@ +

    {{$title}}

    + +
    {{$desc}}
    + +
    +
    +
    + + + + +
    +
    + +
    + diff --git a/sources/view/tpl/msg-header.tpl b/sources/view/tpl/msg-header.tpl new file mode 100755 index 00000000..20d0dd91 --- /dev/null +++ b/sources/view/tpl/msg-header.tpl @@ -0,0 +1,126 @@ + + + + + diff --git a/sources/view/tpl/myapps.tpl b/sources/view/tpl/myapps.tpl new file mode 100755 index 00000000..1a591f9f --- /dev/null +++ b/sources/view/tpl/myapps.tpl @@ -0,0 +1,9 @@ +

    {{$title}}

    + +{{foreach $apps as $ap}} +
    +{{$ap}} +
    +{{/foreach}} +
    + diff --git a/sources/view/tpl/nav.tpl b/sources/view/tpl/nav.tpl new file mode 100755 index 00000000..3d6809c2 --- /dev/null +++ b/sources/view/tpl/nav.tpl @@ -0,0 +1,197 @@ +
    + + +
    diff --git a/sources/view/tpl/new_channel.tpl b/sources/view/tpl/new_channel.tpl new file mode 100755 index 00000000..ff201118 --- /dev/null +++ b/sources/view/tpl/new_channel.tpl @@ -0,0 +1,36 @@ +

    {{$title}}

    + +
    + +
    {{$desc}}
    + +
    {{$help_role}}
    + {{include file="field_select_grouped.tpl" field=$role}} +
    + + + + +
    + +
    + +
    {{$help_name}}
    + + + +
    + +
    + +
    {{$nick_desc}}
    + + + + +
    + + +
    + +
    diff --git a/sources/view/tpl/notes.tpl b/sources/view/tpl/notes.tpl new file mode 100644 index 00000000..0e8c8017 --- /dev/null +++ b/sources/view/tpl/notes.tpl @@ -0,0 +1,27 @@ +
    + + +

    {{$banner}}

    + +
    diff --git a/sources/view/tpl/notifications.tpl b/sources/view/tpl/notifications.tpl new file mode 100755 index 00000000..0b24da7c --- /dev/null +++ b/sources/view/tpl/notifications.tpl @@ -0,0 +1,11 @@ +
    + +

    {{$notif_header}}

    + +{{if $notifications_available}} +{{$notif_link_mark_seen}} +{{/if}} +
    + {{$notif_content}} +
    +
    diff --git a/sources/view/tpl/notify.tpl b/sources/view/tpl/notify.tpl new file mode 100755 index 00000000..d3c79be8 --- /dev/null +++ b/sources/view/tpl/notify.tpl @@ -0,0 +1,3 @@ + diff --git a/sources/view/tpl/oauth_authorize.tpl b/sources/view/tpl/oauth_authorize.tpl new file mode 100755 index 00000000..2b7afa80 --- /dev/null +++ b/sources/view/tpl/oauth_authorize.tpl @@ -0,0 +1,10 @@ +

    {{$title}}

    + +
    + +

    {{$app.name}}

    +
    +

    {{$authorize}}

    +
    +
    +
    diff --git a/sources/view/tpl/oauth_authorize_done.tpl b/sources/view/tpl/oauth_authorize_done.tpl new file mode 100755 index 00000000..2e91e012 --- /dev/null +++ b/sources/view/tpl/oauth_authorize_done.tpl @@ -0,0 +1,4 @@ +

    {{$title}}

    + +

    {{$info}}

    +{{$code}} diff --git a/sources/view/tpl/oembed_video.tpl b/sources/view/tpl/oembed_video.tpl new file mode 100755 index 00000000..b0cfed2e --- /dev/null +++ b/sources/view/tpl/oembed_video.tpl @@ -0,0 +1,4 @@ + + +
    +
    diff --git a/sources/view/tpl/oexchange_xrd.tpl b/sources/view/tpl/oexchange_xrd.tpl new file mode 100755 index 00000000..74ef2287 --- /dev/null +++ b/sources/view/tpl/oexchange_xrd.tpl @@ -0,0 +1,33 @@ + + + + {{$base}} + + Friendika + Friendika Social Network + Friendika + Send to Friendika + + + + + + + + diff --git a/sources/view/tpl/opensearch.tpl b/sources/view/tpl/opensearch.tpl new file mode 100755 index 00000000..8885c12b --- /dev/null +++ b/sources/view/tpl/opensearch.tpl @@ -0,0 +1,13 @@ + + + Hubzilla@{{$nodename}} + Search in The Hubzilla@{{$nodename}} + http://github.com/friendica/red/ + {{$baseurl}}/images/rm-16.png + {{$baseurl}}/images/rm-64.png + + + diff --git a/sources/view/tpl/page_display.tpl b/sources/view/tpl/page_display.tpl new file mode 100755 index 00000000..a320920c --- /dev/null +++ b/sources/view/tpl/page_display.tpl @@ -0,0 +1,14 @@ +
    +
    + {{if $title}} +
    +

    {{$title}}

    +
    + {{/if}} +
    + +
    {{$date}}
    +
    {{$body}}
    +
    +
    +
    diff --git a/sources/view/tpl/pdledit.tpl b/sources/view/tpl/pdledit.tpl new file mode 100644 index 00000000..9df93e4c --- /dev/null +++ b/sources/view/tpl/pdledit.tpl @@ -0,0 +1,21 @@ +

    {{$header}}

    + +

    {{$mname}} {{$module}}

    + +
    +{{$help}} +
    +
    + + + +
    + + + +
    + + +
    + + diff --git a/sources/view/tpl/peoplefind.tpl b/sources/view/tpl/peoplefind.tpl new file mode 100755 index 00000000..5d68cb2d --- /dev/null +++ b/sources/view/tpl/peoplefind.tpl @@ -0,0 +1,20 @@ +
    +

    {{$findpeople}}

    +
    + +
    +
    + +
    + +
    +
    +
    +
    + +
    diff --git a/sources/view/tpl/photo_album.tpl b/sources/view/tpl/photo_album.tpl new file mode 100755 index 00000000..0ce9c36a --- /dev/null +++ b/sources/view/tpl/photo_album.tpl @@ -0,0 +1,30 @@ +
    +
    +
    + +
    + {{if $album_edit.1}} + + {{/if}} + {{if $can_post}} + + {{/if}} +
    +
    + +

    {{$album}}

    + +
    +
    + {{$upload_form}} + {{$album_edit.1}} +
    + {{foreach $photos as $photo}} + {{include file="photo_top.tpl"}} + {{/foreach}} +
    +
    +
    +
    + +
    diff --git a/sources/view/tpl/photo_albums.tpl b/sources/view/tpl/photo_albums.tpl new file mode 100755 index 00000000..de1105bb --- /dev/null +++ b/sources/view/tpl/photo_albums.tpl @@ -0,0 +1,13 @@ + diff --git a/sources/view/tpl/photo_drop.tpl b/sources/view/tpl/photo_drop.tpl new file mode 100755 index 00000000..31b65437 --- /dev/null +++ b/sources/view/tpl/photo_drop.tpl @@ -0,0 +1,4 @@ +
    + +
    +
    diff --git a/sources/view/tpl/photo_item.tpl b/sources/view/tpl/photo_item.tpl new file mode 100755 index 00000000..2ea7aa9f --- /dev/null +++ b/sources/view/tpl/photo_item.tpl @@ -0,0 +1,27 @@ +
    +
    +
    +
    + + {{$name}} +
    +
    +
    +
    + {{$name}} +
    +
    {{$ago}}
    +
    +
    +
    {{$title}}
    +
    {{$body}}
    +
    + {{$drop}} +
    + + {{$comment}} + +
    +
    +
    + diff --git a/sources/view/tpl/photo_top.tpl b/sources/view/tpl/photo_top.tpl new file mode 100755 index 00000000..a86aa7f8 --- /dev/null +++ b/sources/view/tpl/photo_top.tpl @@ -0,0 +1,4 @@ + + {{if $photo.album.name}}{{$photo.album.name}}{{elseif $photo.desc}}{{$photo.desc}}{{elseif $photo.alt}}{{$photo.alt}}{{else}}{{$photo.unknown}}{{/if}} + + diff --git a/sources/view/tpl/photo_view.tpl b/sources/view/tpl/photo_view.tpl new file mode 100755 index 00000000..f5ff2370 --- /dev/null +++ b/sources/view/tpl/photo_view.tpl @@ -0,0 +1,157 @@ +
    +
    +
    +
    + {{if $tools}} + + {{/if}} + {{if $map}} +
    + +
    + {{/if}} + +
    + {{if $prevlink}} + + {{/if}} + {{if $nextlink}} + + {{/if}} +
    +
    +

    {{if $desc}}{{$desc}}{{elseif $filename}}{{$filename}}{{else}}{{$unknown}}{{/if}}

    +
    +
    +
    + {{$map}} +
    +
    +
    + +
    + + + {{if $edit.albums}} + + {{foreach $edit.albums as $al}} + {{if $al.text}} + + {{/if}} +
    +
    + + +
    +
    + + +
    +
    + + +
    + {{if $edit.adult_enabled}} +
    + {{include file="field_checkbox.tpl" field=$edit.adult}} +
    + {{/if}} + + {{$edit.aclselect}} + +
    + +
    +
    + {{if $edit.aclselect}} + + {{/if}} + +
    +
    +
    +
    +
    +
    +
    + {{if $tags}} +
    + {{$tag_hdr}} + {{foreach $tags as $t}} + {{$t.0}}{{if $edit}}  {{/if}} + {{/foreach}} +
    + {{/if}} +
    + {{if $responses.count }} +
    +
    + {{foreach $responses as $verb=>$response}} + {{if $response.count}} +
    + + {{if $response.list_part}} + + {{else}} + + {{/if}} + {{if $response.list_part}} + + {{/if}} +
    + {{/if}} + {{/foreach}} +
    +
    + {{/if}} + {{if $likebuttons}} +
    + + +
    +
    + {{/if}} +
    +
    +
    + {{$comments}} + {{if $commentbox}} +
    + {{$commentbox}} +
    + {{/if}} +
    +
    +{{$paginate}} + diff --git a/sources/view/tpl/photos_recent.tpl b/sources/view/tpl/photos_recent.tpl new file mode 100755 index 00000000..15faa4a3 --- /dev/null +++ b/sources/view/tpl/photos_recent.tpl @@ -0,0 +1,19 @@ +
    +
    + {{if $can_post}} + + {{/if}} +

    {{$title}}

    +
    +
    + {{$upload_form}} +
    + {{foreach $photos as $photo}} + {{include file="photo_top.tpl"}} + {{/foreach}} +
    +
    +
    +
    + +
    diff --git a/sources/view/tpl/photos_upload.tpl b/sources/view/tpl/photos_upload.tpl new file mode 100755 index 00000000..bf02c614 --- /dev/null +++ b/sources/view/tpl/photos_upload.tpl @@ -0,0 +1,56 @@ +
    +
    +
    + + +
    + + + + {{foreach $albums as $al}} + {{if $al.text}} + +
    + + {{$aclselect}} + + {{if $default}} +
    + +
    + {{include file="field_checkbox.tpl" field=$visible}} +
    +
    + {{if $lockstate}} + + {{/if}} + +
    + +
    + {{/if}} +
    + + {{if $uploader}} + + {{include file="field_checkbox.tpl" field=$visible}} +
    + {{if $lockstate}} + + {{/if}} +
    + {{$uploader}} +
    +
    + {{/if}} +
    +
    +
    +
    diff --git a/sources/view/tpl/photosajax.tpl b/sources/view/tpl/photosajax.tpl new file mode 100755 index 00000000..705cb6c7 --- /dev/null +++ b/sources/view/tpl/photosajax.tpl @@ -0,0 +1,4 @@ +{{foreach $photos as $photo}} +{{include file="photo_top.tpl"}} +{{/foreach}} + diff --git a/sources/view/tpl/poco_entry_xml.tpl b/sources/view/tpl/poco_entry_xml.tpl new file mode 100755 index 00000000..30b6268d --- /dev/null +++ b/sources/view/tpl/poco_entry_xml.tpl @@ -0,0 +1,8 @@ + +{{if $entry.id}}{{$entry.id}}{{/if}} +{{if $entry.displayName}}{{$entry.displayName}}{{/if}} +{{if $entry.preferredUsername}}{{$entry.preferredUsername}}{{/if}} +{{if $entry.rating}}{{$entry.rating}}{{/if}} +{{if $entry.urls}}{{foreach $entry.urls as $url}}{{$url.value}}{{$url.type}}{{/foreach}}{{/if}} +{{if $entry.photos}}{{foreach $entry.photos as $photo}}{{$photo.value}}{{$photo.type}}{{/foreach}}{{/if}} + diff --git a/sources/view/tpl/poco_xml.tpl b/sources/view/tpl/poco_xml.tpl new file mode 100755 index 00000000..0e38a692 --- /dev/null +++ b/sources/view/tpl/poco_xml.tpl @@ -0,0 +1,18 @@ + + +{{if $response.sorted}}{{$response.sorted}}{{/if}} +{{if $response.filtered}}{{$response.filtered}}{{/if}} +{{if $response.updatedSince}}{{$response.updatedSince}}{{/if}} +{{$response.startIndex}} +{{$response.itemsPerPage}} +{{$response.totalResults}} + + +{{if $response.totalResults}} +{{foreach $response.entry as $entry}} +{{include file="poco_entry_xml.tpl"}} +{{/foreach}} +{{else}} + +{{/if}} + diff --git a/sources/view/tpl/poke_content.tpl b/sources/view/tpl/poke_content.tpl new file mode 100755 index 00000000..22a0b291 --- /dev/null +++ b/sources/view/tpl/poke_content.tpl @@ -0,0 +1,32 @@ +

    {{$title}}

    + +
    {{$desc}}
    + +
    +
    +
    + +
    {{$clabel}}
    +
    + + + +
    +
    +
    {{$choice}}
    +
    +
    + +
    +
    +
    {{$prv_desc}}
    + +
    +
    + +
    + diff --git a/sources/view/tpl/posted_date_widget.tpl b/sources/view/tpl/posted_date_widget.tpl new file mode 100755 index 00000000..6298ca0a --- /dev/null +++ b/sources/view/tpl/posted_date_widget.tpl @@ -0,0 +1,46 @@ + + + +
    +

    {{$title}}

    + + + + + {{/if}} + +
    diff --git a/sources/view/tpl/prep.tpl b/sources/view/tpl/prep.tpl new file mode 100644 index 00000000..7bef7a41 --- /dev/null +++ b/sources/view/tpl/prep.tpl @@ -0,0 +1,34 @@ +

    {{$header}}

    + +{{if $site}} +

    {{$website}} {{$site}}

    +{{/if}} + + +{{if $raters}} +{{foreach $raters as $r}} + +
    + +
    +
    +{{$r.xchan_addr}} +
    +
    +
    +
    {{$r.xchan_name}}
    +
    {{$rating_lbl}} {{$r.xlink_rating}}
    +{{if $r.xlink_rating_text}} +
    {{$rating_text_label}} {{$r.xlink_rating_text}} +
    +{{/if}} +
    +
    +
    +{{/foreach}} +{{/if}} + + + + + diff --git a/sources/view/tpl/profdef_edit.tpl b/sources/view/tpl/profdef_edit.tpl new file mode 100644 index 00000000..bfe85314 --- /dev/null +++ b/sources/view/tpl/profdef_edit.tpl @@ -0,0 +1,16 @@ +

    {{$header}}

    + +
    + +{{if $id}} + +{{/if}} + +{{include file="field_input.tpl" field=$field_name}} +{{include file="field_input.tpl" field=$field_type}} +{{include file="field_input.tpl" field=$field_desc}} +{{include file="field_input.tpl" field=$field_help}} + + + +
    diff --git a/sources/view/tpl/profed_head.tpl b/sources/view/tpl/profed_head.tpl new file mode 100755 index 00000000..103960a7 --- /dev/null +++ b/sources/view/tpl/profed_head.tpl @@ -0,0 +1,36 @@ + + + diff --git a/sources/view/tpl/profile_advanced.tpl b/sources/view/tpl/profile_advanced.tpl new file mode 100755 index 00000000..1f99bf1a --- /dev/null +++ b/sources/view/tpl/profile_advanced.tpl @@ -0,0 +1,229 @@ +
    +
    + +

    {{$title}}

    +
    +
    +
    +
    +
    {{$profile.fullname.0}}
    +
    {{$profile.fullname.1}}
    +
    + + {{if $profile.gender}} +
    +
    {{$profile.gender.0}}
    +
    {{$profile.gender.1}}
    +
    + {{/if}} + + {{if $profile.birthday}} +
    +
    {{$profile.birthday.0}}
    +
    {{$profile.birthday.1}}
    +
    + {{/if}} + + {{if $profile.age}} +
    +
    {{$profile.age.0}}
    +
    {{$profile.age.1}}
    +
    + {{/if}} + + {{if $profile.marital}} +
    +
    {{$profile.marital.0}}
    +
    {{$profile.marital.1}}{{if $profile.marital.with}} ({{$profile.marital.with}}){{/if}}{{if $profile.howlong}} {{$profile.howlong}}{{/if}}
    +
    + {{/if}} + + {{if $profile.sexual}} +
    +
    {{$profile.sexual.0}}
    +
    {{$profile.sexual.1}}
    +
    + {{/if}} + + {{if $profile.keywords}} +
    +
    {{$profile.keywords.0}}
    +
    {{$profile.keywords.1}}
    +
    + {{/if}} + + {{if $profile.homepage}} +
    +
    {{$profile.homepage.0}}
    +
    {{$profile.homepage.1}}
    +
    + {{/if}} + + {{if $profile.hometown}} +
    +
    {{$profile.hometown.0}}
    +
    {{$profile.hometown.1}}
    +
    + {{/if}} + + {{if $profile.politic}} +
    +
    {{$profile.politic.0}}
    +
    {{$profile.politic.1}}
    +
    + {{/if}} + + {{if $profile.religion}} +
    +
    {{$profile.religion.0}}
    +
    {{$profile.religion.1}}
    +
    + {{/if}} + + {{if $profile.about}} +
    +
    {{$profile.about.0}}
    +
    {{$profile.about.1}}
    +
    + {{/if}} + + {{if $profile.interest}} +
    +
    {{$profile.interest.0}}
    +
    {{$profile.interest.1}}
    +
    + {{/if}} + + {{if $profile.likes}} +
    +
    {{$profile.likes.0}}
    +
    {{$profile.likes.1}}
    +
    + {{/if}} + + {{if $profile.dislikes}} +
    +
    {{$profile.dislikes.0}}
    +
    {{$profile.dislikes.1}}
    +
    + {{/if}} + + {{if $profile.contact}} +
    +
    {{$profile.contact.0}}
    +
    {{$profile.contact.1}}
    +
    + {{/if}} + + {{if $profile.channels}} +
    +
    {{$profile.channels.0}}
    +
    {{$profile.channels.1}}
    +
    + {{/if}} + + + {{if $profile.music}} +
    +
    {{$profile.music.0}}
    +
    {{$profile.music.1}}
    +
    + {{/if}} + + + {{if $profile.book}} +
    +
    {{$profile.book.0}}
    +
    {{$profile.book.1}}
    +
    + {{/if}} + + + {{if $profile.tv}} +
    +
    {{$profile.tv.0}}
    +
    {{$profile.tv.1}}
    +
    + {{/if}} + + + {{if $profile.film}} +
    +
    {{$profile.film.0}}
    +
    {{$profile.film.1}}
    +
    + {{/if}} + + + {{if $profile.romance}} +
    +
    {{$profile.romance.0}}
    +
    {{$profile.romance.1}}
    +
    + {{/if}} + + + {{if $profile.work}} +
    +
    {{$profile.work.0}}
    +
    {{$profile.work.1}}
    +
    + {{/if}} + + {{if $profile.education}} +
    +
    {{$profile.education.0}}
    +
    {{$profile.education.1}}
    +
    + {{/if}} + + {{foreach $profile.extra_fields as $f}} + {{if $profile.$f}} +
    +
    {{$profile.$f.0}}
    +
    {{$profile.$f.1}}
    +
    + {{/if}} + {{/foreach}} + + + {{if $things}} + {{foreach $things as $key => $items}} + {{$profile.fullname.1}} {{$key}} +
      + {{foreach $items as $item}} +
    • {{if $item.img}}{{$item.term}}{{/if}} + {{$item.term}} + {{if $profile.canlike}}
      + + {{/if}} + {{if $item.like_count}} +
      + + {{if $item.likes}} + + {{/if}} +
      + {{/if}} +
    • + {{/foreach}} +
    +
    + {{/foreach}} + {{/if}} +
    +
    diff --git a/sources/view/tpl/profile_edit.tpl b/sources/view/tpl/profile_edit.tpl new file mode 100755 index 00000000..535aa19d --- /dev/null +++ b/sources/view/tpl/profile_edit.tpl @@ -0,0 +1,367 @@ +
    {{if $is_default}} +

    {{$default}}

    +{{/if}} + +

    {{$banner}}

    + +
    + + + + + + + +
    + + +
    + +
    *
    +
    +
    + +
    + + +
    +
    + + +{{if $fields.pdesc}} +
    + + +
    +
    +{{/if}} + +{{if $fields.gender}} +
    + +{{if $advanced}} +{{$gender}} +{{else}} +{{$gender_min}} +{{/if}} +
    +
    +{{/if}} + +{{if $fields.dob}} +
    + +
    +{{$dob}} {{$age}} +
    +
    +
    +{{/if}} + +{{$hide_friends}} + +
    + +
    +
    + +{{if $fields.address}} +
    + + +
    +
    +{{/if}} + +{{if $fields.locality}} +
    + + +
    +
    +{{/if}} + +{{if $fields.postal_code}} +
    + + +
    +
    +{{/if}} + +{{if $fields.region}} +
    + + +
    +
    +{{/if}} + +{{if $fields.country_name}} +
    + + +
    +
    +{{/if}} + +{{if $fields.hometown}} +
    + + +
    +
    +{{/if}} + +
    + +
    +
    + +{{if $fields.marital }} +
    + +{{if $advanced}} +{{$marital}} +{{else}} +{{$marital_min}} +{{/if}} +
    +
    +{{if $fields.with}} + + +
    +{{/if}} +{{if $fields.howlong}} + + +
    +{{/if}} +
    +{{/if}} + +{{if $fields.homepage}} +
    + + +
    +
    +{{/if}} + +{{if $fields.sexual}} +
    + +{{$sexual}} +
    +
    +{{/if}} + +{{if $fields.politic}} +
    + + +
    +
    +{{/if}} + +{{if $fields.religion}} +
    + + +
    +
    +{{/if}} + +{{if $fields.keywords}} +
    + + +
    {{$lbl_pubdsc}}
    +
    +{{/if}} + + +{{if $fields.about}} +
    +

    +{{$lbl_about}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.contact}} +
    +

    +{{$lbl_social}} +

    + + + +
    +
    +{{/if}} + + +{{if $fields.interest}} +
    +

    +{{$lbl_hobbies}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.likes}} +
    +

    +{{$lbl_likes}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.dislikes}} +
    +

    +{{$lbl_dislikes}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.channels}} +
    +

    +{{$lbl_channels}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.music}} +
    +

    +{{$lbl_music}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.book}} +
    +

    +{{$lbl_book}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.tv}} +
    +

    +{{$lbl_tv}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.film}} +
    +

    +{{$lbl_film}} +

    + + + +
    +
    +{{/if}} + + +{{if $fields.romance}} +
    +

    +{{$lbl_love}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.work}} +
    +

    +{{$lbl_work}} +

    + + + +
    +
    +{{/if}} + +{{if $fields.education}} +
    +

    +{{$lbl_school}} +

    + + + +
    +
    +{{/if}} + +{{if $extra_fields}} +{{foreach $extra_fields as $field }} +{{include file="field_input.tpl" field=$field}} +{{/foreach}} +{{/if}} + +
    + +
    +
    + + + +
    +
    + diff --git a/sources/view/tpl/profile_entry.tpl b/sources/view/tpl/profile_entry.tpl new file mode 100755 index 00000000..ab81a7fb --- /dev/null +++ b/sources/view/tpl/profile_entry.tpl @@ -0,0 +1,11 @@ +
    +
    +
    +{{$alt}} +
    +
    + +
    {{$visible}}
    +
    +
    +
    diff --git a/sources/view/tpl/profile_hide_friends.tpl b/sources/view/tpl/profile_hide_friends.tpl new file mode 100644 index 00000000..4ed6782b --- /dev/null +++ b/sources/view/tpl/profile_hide_friends.tpl @@ -0,0 +1,20 @@ +{{include file="field_checkbox.tpl"}} + +{{* +

    +{{$desc}} +

    +
    + + + +
    +
    + +
    + + + +
    +
    +*}} diff --git a/sources/view/tpl/profile_listing_header.tpl b/sources/view/tpl/profile_listing_header.tpl new file mode 100755 index 00000000..09d00f98 --- /dev/null +++ b/sources/view/tpl/profile_listing_header.tpl @@ -0,0 +1,11 @@ +
    +

    {{$header}}

    +

    +{{$chg_photo}} +

    + +
    diff --git a/sources/view/tpl/profile_photo.tpl b/sources/view/tpl/profile_photo.tpl new file mode 100755 index 00000000..48a3c7f2 --- /dev/null +++ b/sources/view/tpl/profile_photo.tpl @@ -0,0 +1,29 @@ +

    {{$title}}

    + +
    + + +
    + + + +
    + + + +
    + +
    + +
    +
    + +
    + + diff --git a/sources/view/tpl/profile_vcard.tpl b/sources/view/tpl/profile_vcard.tpl new file mode 100755 index 00000000..bea0d894 --- /dev/null +++ b/sources/view/tpl/profile_vcard.tpl @@ -0,0 +1,63 @@ +
    +
    {{$profile.name}}
    + {{if $profile.edit}} + + {{/if}} + +
    {{$profile.name}}{{if $profile.online}} {{/if}}
    + {{if $reddress}}
    {{$profile.reddress}}
    {{/if}} + {{if $pdesc}}
    {{$profile.pdesc}}
    {{/if}} + + + + {{if $location}} +
    {{$location}}
    +
    + {{if $profile.address}}
    {{$profile.address}}
    {{/if}} + + {{$profile.locality}}{{if $profile.locality}}, {{/if}} + {{$profile.region}} + {{$profile.postal_code}} + + {{if $profile.country_name}}{{$profile.country_name}}{{/if}} +
    +
    + {{/if}} + + {{if $gender}}
    {{$gender}}
    {{$profile.gender}}
    {{/if}} + + + {{if $marital}}
    {{$marital}}
    {{$profile.marital}}
    {{/if}} + + {{if $homepage}}
    {{$homepage}}
    {{$profile.homepage}}
    {{/if}} + + {{if $diaspora}} + {{include file="diaspora_vcard.tpl"}} + {{/if}} + +{{if $connect}} + {{$connect}} +{{/if}} + +{{$rating}} + +
    +
    + + +{{$chanmenu}} + +{{$contact_block}} + + diff --git a/sources/view/tpl/prv_message.tpl b/sources/view/tpl/prv_message.tpl new file mode 100755 index 00000000..c6f393aa --- /dev/null +++ b/sources/view/tpl/prv_message.tpl @@ -0,0 +1,56 @@ +

    {{$header}}

    + +
    +
    + +{{$parent}} + +
    {{$to}}
    + +{{if $showinputs}} + + +{{else}} +{{$select}} +{{/if}} + + + + +
    {{$subject}}
    + + +
    {{$yourmessage}}
    + + + +
    + + + + + + + {{if $feature_expire}} + + {{/if}} + {{if $feature_encrypt}} + + {{/if}} +
    +
    +
    +
    +
    +
    +
    diff --git a/sources/view/tpl/pwdreset.tpl b/sources/view/tpl/pwdreset.tpl new file mode 100755 index 00000000..a9106343 --- /dev/null +++ b/sources/view/tpl/pwdreset.tpl @@ -0,0 +1,15 @@ +

    {{$lbl1}}

    + +

    +{{$lbl2}} +

    +

    +{{$lbl3}} +

    +

    {{$newpass}}

    +

    +{{$lbl4}} {{$lbl5}} +

    +

    +{{$lbl6}} +

    diff --git a/sources/view/tpl/rating_form.tpl b/sources/view/tpl/rating_form.tpl new file mode 100644 index 00000000..95c2eb03 --- /dev/null +++ b/sources/view/tpl/rating_form.tpl @@ -0,0 +1,22 @@ +

    {{$header}}

    + +
    {{if $site}}{{$website}} {{$site}}{{else}}{{$tgt_name}}{{/if}}
    + +

    {{$lbl_rating}}

    + +
    + +{{$rating}} + + + + + +

    {{$lbl_rating_txt}}

    + + +
    + + + +
    \ No newline at end of file diff --git a/sources/view/tpl/rating_slider.tpl b/sources/view/tpl/rating_slider.tpl new file mode 100644 index 00000000..4c36504e --- /dev/null +++ b/sources/view/tpl/rating_slider.tpl @@ -0,0 +1,19 @@ +
    + diff --git a/sources/view/tpl/rbmark.tpl b/sources/view/tpl/rbmark.tpl new file mode 100644 index 00000000..bead1de2 --- /dev/null +++ b/sources/view/tpl/rbmark.tpl @@ -0,0 +1,16 @@ +

    {{$header}}

    + + +
    + + + + +{{include file="field_input.tpl" field=$url}} +{{include file="field_input.tpl" field=$title}} +{{include file="field_select.tpl" field=$menus}} +{{include file="field_input.tpl" field=$menu_name}} + + + +
    diff --git a/sources/view/tpl/register.tpl b/sources/view/tpl/register.tpl new file mode 100755 index 00000000..ed673031 --- /dev/null +++ b/sources/view/tpl/register.tpl @@ -0,0 +1,51 @@ +

    {{$title}}

    + +
    + + + +{{if $reg_is}} +
    {{$reg_is}}
    +{{/if}} +{{if $registertext}}
    {{$registertext}}
    +{{/if}} +{{if $other_sites}}
    {{$other_sites}}
    +{{/if}} + +{{if $invitations}} +

    {{$invite_desc}}

    + + + +
    +
    +{{/if}} + + + +
    +
    + + + +
    +
    + + + +
    +
    + + {{if $enable_tos}} + + +
    +
    + {{else}} + + {{/if}} + + +
    + +
    diff --git a/sources/view/tpl/remote_friends_common.tpl b/sources/view/tpl/remote_friends_common.tpl new file mode 100755 index 00000000..d6d2fd21 --- /dev/null +++ b/sources/view/tpl/remote_friends_common.tpl @@ -0,0 +1,21 @@ +
    +
    {{$desc}}      {{if $linkmore}}{{$more}}{{/if}}
    + {{if $items}} + {{foreach $items as $item}} +
    +
    + + {{$item.xchan_name}} + +
    +
    + +
    +
    + {{/foreach}} + {{/if}} +
    +
    + diff --git a/sources/view/tpl/removeaccount.tpl b/sources/view/tpl/removeaccount.tpl new file mode 100644 index 00000000..aefcd51a --- /dev/null +++ b/sources/view/tpl/removeaccount.tpl @@ -0,0 +1,20 @@ +
    +
    +

    {{$title}}

    +
    +
    + {{$desc.0}}{{$desc.1}}{{$desc.2}} +
    +
    +
    + +
    + + +
    + {{include file="field_checkbox.tpl" field=$global}} + +
    +
    +
    + diff --git a/sources/view/tpl/removeme.tpl b/sources/view/tpl/removeme.tpl new file mode 100755 index 00000000..5b329dd6 --- /dev/null +++ b/sources/view/tpl/removeme.tpl @@ -0,0 +1,20 @@ +
    +
    +

    {{$title}}

    +
    +
    + {{$desc.0}}{{$desc.1}}{{$desc.2}} +
    +
    +
    + +
    + + +
    + {{include file="field_checkbox.tpl" field=$global}} + +
    +
    +
    + diff --git a/sources/view/tpl/rmagic.tpl b/sources/view/tpl/rmagic.tpl new file mode 100755 index 00000000..58df7171 --- /dev/null +++ b/sources/view/tpl/rmagic.tpl @@ -0,0 +1,11 @@ +

    {{$title}}

    + +
    + + + + + +
    + +
    diff --git a/sources/view/tpl/safesearch.tpl b/sources/view/tpl/safesearch.tpl new file mode 100644 index 00000000..58ce2274 --- /dev/null +++ b/sources/view/tpl/safesearch.tpl @@ -0,0 +1,6 @@ +
    +

    {{$safemode}}

    + +
    diff --git a/sources/view/tpl/saved_searches.tpl b/sources/view/tpl/saved_searches.tpl new file mode 100644 index 00000000..1f786107 --- /dev/null +++ b/sources/view/tpl/saved_searches.tpl @@ -0,0 +1,14 @@ +
    + + {{$searchbox}} + + +
    +
    diff --git a/sources/view/tpl/search_item.tpl b/sources/view/tpl/search_item.tpl new file mode 100755 index 00000000..256443b8 --- /dev/null +++ b/sources/view/tpl/search_item.tpl @@ -0,0 +1,63 @@ +
    + +
    +
    +
    +
    + {{$item.name}} +
    +
    +
    + {{if $item.title}} +

    {{$item.title}}

    + {{/if}} + {{if $item.lock}} + + {{/if}} +
    + {{$item.name}}{{if $item.owner_url}} {{$item.via}} {{$item.owner_name}}{{/if}} +
    +
    + {{if $item.verified}} {{elseif $item.forged}} {{/if}}{{if $item.location}}{{$item.location}}, {{/if}}{{$item.localtime}}{{if $item.editedtime}} {{$item.editedtime}}{{/if}}{{if $item.expiretime}} {{$item.expiretime}}{{/if}}{{if $item.editedtime}} {{/if}} {{if $item.app}}{{$item.str_app}}{{/if}} +
    +
    +
    +
    + {{$item.body}} +
    +
    +
    +
    + + +
    +
    + {{* we dont' use this do we? + {{if $item.drop.pagedrop}} + + {{/if}} + *}} +
    +
    +
    + {{if $item.conv}} + + {{/if}} +
    +
    +
    + diff --git a/sources/view/tpl/searchbox.tpl b/sources/view/tpl/searchbox.tpl new file mode 100644 index 00000000..f4301f0f --- /dev/null +++ b/sources/view/tpl/searchbox.tpl @@ -0,0 +1,12 @@ +
    + +
    + +
    + + {{if $savedsearch}} + + {{/if}} +
    +
    +
    diff --git a/sources/view/tpl/section_title.tpl b/sources/view/tpl/section_title.tpl new file mode 100644 index 00000000..338e5704 --- /dev/null +++ b/sources/view/tpl/section_title.tpl @@ -0,0 +1,5 @@ +
    +

    {{$title}}

    +
    +
    + diff --git a/sources/view/tpl/select_timezone.tpl b/sources/view/tpl/select_timezone.tpl new file mode 100644 index 00000000..2820a54f --- /dev/null +++ b/sources/view/tpl/select_timezone.tpl @@ -0,0 +1,11 @@ +{{* TODO: Make id configurabel *}} + + diff --git a/sources/view/tpl/sellpage_edit.tpl b/sources/view/tpl/sellpage_edit.tpl new file mode 100644 index 00000000..0a4726fb --- /dev/null +++ b/sources/view/tpl/sellpage_edit.tpl @@ -0,0 +1,23 @@ +

    {{$header}}

    +
    + +{{include file="field_checkbox.tpl" field=$premium}} + +
    {{$desc}}
    + +
    +

    +{{$lbl_about}} +

    + + + +
    +
    + + +
    {{$lbl2}}
    +
    {{$desc2}}
    + + +
    diff --git a/sources/view/tpl/sellpage_submit.tpl b/sources/view/tpl/sellpage_submit.tpl new file mode 100644 index 00000000..2bd735ea --- /dev/null +++ b/sources/view/tpl/sellpage_submit.tpl @@ -0,0 +1,3 @@ +
    + +
    \ No newline at end of file diff --git a/sources/view/tpl/sellpage_view.tpl b/sources/view/tpl/sellpage_view.tpl new file mode 100644 index 00000000..20a65ffb --- /dev/null +++ b/sources/view/tpl/sellpage_view.tpl @@ -0,0 +1,11 @@ +
    +

    {{$header}}

    + +
    {{$desc}}
    + +
    {{$text}}
    + +
    {{$desc2}}
    + +{{$submit}} +
    diff --git a/sources/view/tpl/settings.tpl b/sources/view/tpl/settings.tpl new file mode 100755 index 00000000..ab62ede4 --- /dev/null +++ b/sources/view/tpl/settings.tpl @@ -0,0 +1,167 @@ +
    +
    +  {{$removeme}} +

    {{$ptitle}}

    +
    +
    + {{$nickname_block}} +
    + +
    +
    + +
    +
    + {{include file="field_input.tpl" field=$username}} + {{include file="field_select_grouped.tpl" field=$timezone}} + {{include file="field_input.tpl" field=$defloc}} + {{include file="field_checkbox.tpl" field=$allowloc}} + {{include file="field_checkbox.tpl" field=$adult}} + {{include file="field_input.tpl" field=$photo_path}} + {{include file="field_input.tpl" field=$attach_path}} + +
    + +
    +
    +
    +
    +
    + +
    +
    + {{include file="field_select_grouped.tpl" field=$role}} +
    +
    + +
    + +
    + + {{$aclselect}} +
    + {{$group_select}} + {{include file="field_checkbox.tpl" field=$hide_presence}} + {{$profile_in_dir}} +
    +
    + {{$suggestme}} + {{include file="field_checkbox.tpl" field=$blocktags}} + {{include file="field_input.tpl" field=$expire}} +
    +
    + +
    +
    +
    +
    +
    + +
    +
    +
    +

    {{$activity_options}}

    +
    + {{*not yet implemented *}} + {{*include file="field_checkbox.tpl" field=$post_joingroup*}} + {{include file="field_checkbox.tpl" field=$post_newfriend}} + {{include file="field_checkbox.tpl" field=$post_profilechange}} +
    +

    {{$lbl_not}}

    +
    + {{include file="field_intcheckbox.tpl" field=$notify1}} + {{include file="field_intcheckbox.tpl" field=$notify2}} + {{include file="field_intcheckbox.tpl" field=$notify3}} + {{include file="field_intcheckbox.tpl" field=$notify4}} + {{include file="field_intcheckbox.tpl" field=$notify5}} + {{include file="field_intcheckbox.tpl" field=$notify6}} + {{include file="field_intcheckbox.tpl" field=$notify7}} + {{include file="field_intcheckbox.tpl" field=$notify8}} +
    +

    {{$lbl_vnot}}

    +
    + {{include file="field_intcheckbox.tpl" field=$vnotify1}} + {{include file="field_intcheckbox.tpl" field=$vnotify2}} + {{include file="field_intcheckbox.tpl" field=$vnotify3}} + {{include file="field_intcheckbox.tpl" field=$vnotify4}} + {{include file="field_intcheckbox.tpl" field=$vnotify5}} + {{include file="field_intcheckbox.tpl" field=$vnotify6}} + {{include file="field_intcheckbox.tpl" field=$vnotify10}} + {{include file="field_intcheckbox.tpl" field=$vnotify7}} + {{include file="field_intcheckbox.tpl" field=$vnotify8}} + {{include file="field_intcheckbox.tpl" field=$vnotify9}} + {{include file="field_intcheckbox.tpl" field=$vnotify11}} + {{include file="field_intcheckbox.tpl" field=$always_show_in_notices}} + {{include file="field_input.tpl" field=$evdays}} +
    +
    +
    + +
    +
    +
    +
    + {{if $menus}} +
    + +
    +
    +
    + + +
    +
    + +
    +
    +
    +
    + {{/if}} +
    +
    +
    diff --git a/sources/view/tpl/settings_account.tpl b/sources/view/tpl/settings_account.tpl new file mode 100755 index 00000000..9f550fe4 --- /dev/null +++ b/sources/view/tpl/settings_account.tpl @@ -0,0 +1,20 @@ +
    +
    +  {{$removeme}} +

    {{$title}}

    +
    +
    +
    + +
    + {{include file="field_input.tpl" field=$email}} + {{include file="field_password.tpl" field=$password1}} + {{include file="field_password.tpl" field=$password2}} +
    + +
    + {{$account_settings}} +
    +
    +
    + diff --git a/sources/view/tpl/settings_addons.tpl b/sources/view/tpl/settings_addons.tpl new file mode 100755 index 00000000..52f8d9d3 --- /dev/null +++ b/sources/view/tpl/settings_addons.tpl @@ -0,0 +1,11 @@ +
    +
    +

    {{$title}}

    +
    +
    + +
    + {{$settings_addons}} +
    +
    +
    diff --git a/sources/view/tpl/settings_connectors.tpl b/sources/view/tpl/settings_connectors.tpl new file mode 100755 index 00000000..8bea9ca6 --- /dev/null +++ b/sources/view/tpl/settings_connectors.tpl @@ -0,0 +1,10 @@ +
    +

    {{$title}}

    + +
    + + +{{$settings_connectors}} + +
    +
    diff --git a/sources/view/tpl/settings_display.tpl b/sources/view/tpl/settings_display.tpl new file mode 100755 index 00000000..02f67985 --- /dev/null +++ b/sources/view/tpl/settings_display.tpl @@ -0,0 +1,81 @@ +
    +
    +

    {{$ptitle}}

    +
    +
    + + +
    + {{if $theme || $mobile_theme}} +
    + +
    +
    + {{if $theme}} + {{include file="field_themeselect.tpl" field=$theme}} + {{/if}} + {{if $mobile_theme}} + {{include file="field_themeselect.tpl" field=$mobile_theme}} + {{/if}} +
    + +
    +
    +
    +
    + {{/if}} +
    + +
    +
    + {{if $theme_config}} + {{$theme_config}} + {{/if}} +
    +
    +
    +
    + +
    +
    + {{include file="field_input.tpl" field=$ajaxint}} + {{include file="field_input.tpl" field=$itemspage}} + {{include file="field_input.tpl" field=$channel_divmore_height}} + {{include file="field_input.tpl" field=$network_divmore_height}} + {{include file="field_checkbox.tpl" field=$nosmile}} + {{include file="field_checkbox.tpl" field=$title_tosource}} + {{include file="field_checkbox.tpl" field=$channel_list_mode}} + {{include file="field_checkbox.tpl" field=$network_list_mode}} + {{include file="field_checkbox.tpl" field=$user_scalable}} + {{if $expert}} + + {{/if}} +
    + +
    +
    +
    +
    +
    +
    +
    diff --git a/sources/view/tpl/settings_features.tpl b/sources/view/tpl/settings_features.tpl new file mode 100755 index 00000000..75eb34fb --- /dev/null +++ b/sources/view/tpl/settings_features.tpl @@ -0,0 +1,30 @@ +
    +
    +

    {{$title}}

    +
    +
    + +
    + {{foreach $features as $g => $f}} +
    + +
    +
    + {{foreach $f.1 as $fcat}} + {{include file="field_checkbox.tpl" field=$fcat}} + {{/foreach}} +
    + +
    +
    +
    +
    + {{/foreach}} +
    +
    diff --git a/sources/view/tpl/settings_nick_set.tpl b/sources/view/tpl/settings_nick_set.tpl new file mode 100755 index 00000000..2460952f --- /dev/null +++ b/sources/view/tpl/settings_nick_set.tpl @@ -0,0 +1,4 @@ + +
    diff --git a/sources/view/tpl/settings_oauth.tpl b/sources/view/tpl/settings_oauth.tpl new file mode 100755 index 00000000..20e8f458 --- /dev/null +++ b/sources/view/tpl/settings_oauth.tpl @@ -0,0 +1,33 @@ +
    +

    {{$title}}

    + + + + + + + + {{foreach $apps as $app}} +
    + + {{if $app.name}}

    {{$app.name}}

    {{else}}

    {{$noname}}

    {{/if}} + {{if $app.my}} + {{if $app.oauth_token}} +
    + {{/if}} + {{/if}} + {{if $app.my}} + + + {{/if}} +
    + {{/foreach}} + + +
    diff --git a/sources/view/tpl/settings_oauth_edit.tpl b/sources/view/tpl/settings_oauth_edit.tpl new file mode 100755 index 00000000..bf805363 --- /dev/null +++ b/sources/view/tpl/settings_oauth_edit.tpl @@ -0,0 +1,17 @@ +

    {{$title}}

    + +
    + + +{{include file="field_input.tpl" field=$name}} +{{include file="field_input.tpl" field=$key}} +{{include file="field_input.tpl" field=$secret}} +{{include file="field_input.tpl" field=$redirect}} +{{include file="field_input.tpl" field=$icon}} + +
    + + +
    + +
    diff --git a/sources/view/tpl/sharedwithme.tpl b/sources/view/tpl/sharedwithme.tpl new file mode 100644 index 00000000..4ffacc24 --- /dev/null +++ b/sources/view/tpl/sharedwithme.tpl @@ -0,0 +1,26 @@ +
    +
    +  {{$dropall}} +

    {{$header}}

    +
    +
    + + + + + + + + + {{foreach $items as $item}} + + + + + + + + {{/foreach}} +
    {{$name}}
    {{$item.objfilename}}{{if $item.unseen}} {{$label_new}}{{/if}}
    +
    +
    diff --git a/sources/view/tpl/show_thing.tpl b/sources/view/tpl/show_thing.tpl new file mode 100644 index 00000000..9aacc895 --- /dev/null +++ b/sources/view/tpl/show_thing.tpl @@ -0,0 +1,16 @@ +

    {{$header}}

    +{{if $thing}} +
    +{{if $thing.imgurl}}{{$thing.term}}{{/if}} +{{$thing.term}} +
    +{{if $canedit}} + + +{{/if}} + +{{/if}} + diff --git a/sources/view/tpl/siteinfo.tpl b/sources/view/tpl/siteinfo.tpl new file mode 100755 index 00000000..3b0c8841 --- /dev/null +++ b/sources/view/tpl/siteinfo.tpl @@ -0,0 +1,23 @@ +

    {{$title}}

    +

    +

    {{$description}}

    +{{if $version}} +

    {{$version}}{{if $commit}}+{{$commit}}{{/if}}

    +{{/if}} +{{if $tag}} +

    {{$tag_txt}} {{$tag}}

    +{{/if}} +{{if $polled}} +

    {{$polled}} {{$lastpoll}}

    +{{/if}} +

    {{$web_location}}

    +

    {{$visit}}

    +

    {{$bug_text}} {{$bug_link_text}}

    +

    {{$adminlabel}}

    +

    {{$admininfo}}

    +

    {{$contact}}

    +

    {{$plugins_text}}

    +{{if $plugins_list}} +
    {{$plugins_list}}
    +{{/if}} +

    {{$donate}}

    diff --git a/sources/view/tpl/sources_edit.tpl b/sources/view/tpl/sources_edit.tpl new file mode 100644 index 00000000..34023e03 --- /dev/null +++ b/sources/view/tpl/sources_edit.tpl @@ -0,0 +1,22 @@ +

    {{$title}}

    + +
    {{$desc}}
    + +
    + + +{{include file="field_input.tpl" field=$name}} +{{include file="field_textarea.tpl" field=$words}} + +
    + +
    +
    +
    +
    +{{$drop}} + + + + + diff --git a/sources/view/tpl/sources_list.tpl b/sources/view/tpl/sources_list.tpl new file mode 100644 index 00000000..5fe50ba9 --- /dev/null +++ b/sources/view/tpl/sources_list.tpl @@ -0,0 +1,15 @@ +

    {{$title}}

    + +
    {{$desc}}
    + + + +{{if $sources}} + +{{/if}} \ No newline at end of file diff --git a/sources/view/tpl/sources_new.tpl b/sources/view/tpl/sources_new.tpl new file mode 100644 index 00000000..3c6a4be3 --- /dev/null +++ b/sources/view/tpl/sources_new.tpl @@ -0,0 +1,15 @@ +

    {{$title}}

    + +
    {{$desc}}
    + +
    + +{{include file="field_input.tpl" field=$name}} +{{include file="field_textarea.tpl" field=$words}} + +
    + +
    +
    + + diff --git a/sources/view/tpl/suggest_friends.tpl b/sources/view/tpl/suggest_friends.tpl new file mode 100755 index 00000000..2008193f --- /dev/null +++ b/sources/view/tpl/suggest_friends.tpl @@ -0,0 +1,16 @@ +
    +
    + + {{$entry.name}} + +
    + +
    + +
    + {{if $entry.connlnk}} + + {{/if}} +
    diff --git a/sources/view/tpl/suggest_page.tpl b/sources/view/tpl/suggest_page.tpl new file mode 100755 index 00000000..97837c85 --- /dev/null +++ b/sources/view/tpl/suggest_page.tpl @@ -0,0 +1,9 @@ +

    {{$title}}

    + +{{if $entries}} +{{foreach $entries as $child}} +{{include file="suggest_friends.tpl" entry=$child}} +{{/foreach}} +{{/if}} + +
    diff --git a/sources/view/tpl/suggest_widget.tpl b/sources/view/tpl/suggest_widget.tpl new file mode 100644 index 00000000..7b9afa66 --- /dev/null +++ b/sources/view/tpl/suggest_widget.tpl @@ -0,0 +1,10 @@ +
    +

    {{$title}}

    +{{if $entries}} +{{foreach $entries as $child}} +{{include file="suggest_friends.tpl" entry=$child}} +{{/foreach}} +{{/if}} +
    + +
    diff --git a/sources/view/tpl/thing_edit.tpl b/sources/view/tpl/thing_edit.tpl new file mode 100644 index 00000000..b170f152 --- /dev/null +++ b/sources/view/tpl/thing_edit.tpl @@ -0,0 +1,33 @@ +

    {{$thing_hdr}}

    +
    + + +{{if $multiprof }} +
    {{$profile_lbl}}
    + +
    {{$profile_select}}
    +
    +{{/if}} + +
    {{$verb_lbl}}
    + +
    {{$verb_select}}
    +
    + + + + +
    + + +
    + + +
    + +{{include file="field_checkbox.tpl" field=$activity}} + +
    + + +
    diff --git a/sources/view/tpl/thing_input.tpl b/sources/view/tpl/thing_input.tpl new file mode 100644 index 00000000..e93a1aa6 --- /dev/null +++ b/sources/view/tpl/thing_input.tpl @@ -0,0 +1,33 @@ +

    {{$thing_hdr}}

    +
    + +{{if $multiprof }} +
    {{$profile_lbl}}
    + +
    {{$profile_select}}
    +
    +{{/if}} + + +
    {{$verb_lbl}}
    + +
    {{$verb_select}}
    +
    + + + + +
    + + +
    + + +
    + +{{include file="field_checkbox.tpl" field=$activity}} + +
    + + +
    diff --git a/sources/view/tpl/threaded_conversation.tpl b/sources/view/tpl/threaded_conversation.tpl new file mode 100755 index 00000000..ea5c3c28 --- /dev/null +++ b/sources/view/tpl/threaded_conversation.tpl @@ -0,0 +1,8 @@ +{{if $photo_item}} +{{$photo_item}} +{{/if}} +{{foreach $threads as $thread_item}} +{{include file="{{$thread_item.template}}" item=$thread_item}} +{{/foreach}} + +
    diff --git a/sources/view/tpl/toggle_mobile_footer.tpl b/sources/view/tpl/toggle_mobile_footer.tpl new file mode 100755 index 00000000..82c0197b --- /dev/null +++ b/sources/view/tpl/toggle_mobile_footer.tpl @@ -0,0 +1,2 @@ +{{$toggle_text}} + diff --git a/sources/view/tpl/uexport.tpl b/sources/view/tpl/uexport.tpl new file mode 100644 index 00000000..5de995ba --- /dev/null +++ b/sources/view/tpl/uexport.tpl @@ -0,0 +1,9 @@ +
    +

    {{$title}}

    +{{$basictitle}}

    +

    {{$basic}}

    + +

    {{$fulltitle}}

    +

    {{$full}}

    + +
    diff --git a/sources/view/tpl/usermenu.tpl b/sources/view/tpl/usermenu.tpl new file mode 100644 index 00000000..4ecf823d --- /dev/null +++ b/sources/view/tpl/usermenu.tpl @@ -0,0 +1,20 @@ +{{if $wrap}} +
    +{{/if}} + {{if $menu.menu_desc}} +

    {{$menu.menu_desc}}{{if $edit}} {{/if}}

    + {{/if}} + {{if $items}} + + {{/if}} +{{if $wrap}} +
    +
    +{{/if}} diff --git a/sources/view/tpl/viewcontact_template.tpl b/sources/view/tpl/viewcontact_template.tpl new file mode 100755 index 00000000..83cd8095 --- /dev/null +++ b/sources/view/tpl/viewcontact_template.tpl @@ -0,0 +1,15 @@ +
    +

    {{$title}}

    + + +
    +{{foreach $contacts as $contact}} + {{include file="contact_template.tpl"}} +{{/foreach}} +
    +
    +
    +{{$paginate}} +
    + +
    diff --git a/sources/view/tpl/viewcontactsajax.tpl b/sources/view/tpl/viewcontactsajax.tpl new file mode 100644 index 00000000..68be228b --- /dev/null +++ b/sources/view/tpl/viewcontactsajax.tpl @@ -0,0 +1,3 @@ +{{foreach $contacts as $contact}} +{{include file="contact_template.tpl"}} +{{/foreach}} diff --git a/sources/view/tpl/webpagelist.tpl b/sources/view/tpl/webpagelist.tpl new file mode 100644 index 00000000..86470512 --- /dev/null +++ b/sources/view/tpl/webpagelist.tpl @@ -0,0 +1,76 @@ +
    +
    + {{if $editor}} +
    + +
    + {{/if}} +

    {{$listtitle}}

    +
    +
    + {{if $editor}} +
    + {{$editor}} +
    + {{/if}} + {{if $pages}} +
    + + + + + + + + + + + + {{foreach $pages as $key => $items}} + {{foreach $items as $item}} + + + + + + + + + + + {{/foreach}} + {{/foreach}} +
    {{$pagelink_txt}}{{$title_txt}}
    + {{if $view}} + {{$item.pagetitle}} + {{else}} + {{$item.pagetitle}} + {{/if}} + + {{$item.title}} + + {{if $edit}} + + {{/if}} + + {{if $item.bb_element}} + + {{/if}} + + {{if $edit}} + + {{/if}} +
    +
    + {{/if}} +
    +
    diff --git a/sources/view/tpl/write_pages.tpl b/sources/view/tpl/write_pages.tpl new file mode 100644 index 00000000..53146ee3 --- /dev/null +++ b/sources/view/tpl/write_pages.tpl @@ -0,0 +1,3 @@ + diff --git a/sources/view/tpl/xchan_vcard.tpl b/sources/view/tpl/xchan_vcard.tpl new file mode 100755 index 00000000..2acbb24e --- /dev/null +++ b/sources/view/tpl/xchan_vcard.tpl @@ -0,0 +1,11 @@ +
    +
    {{$name}}
    +
    {{$name}}
    +
    + + +{{if $mode != 'mail'}} +{{if $connect}} + {{$connect}} +{{/if}} +{{/if}} diff --git a/sources/view/tpl/xrd_diaspora.tpl b/sources/view/tpl/xrd_diaspora.tpl new file mode 100644 index 00000000..aa0d8c74 --- /dev/null +++ b/sources/view/tpl/xrd_diaspora.tpl @@ -0,0 +1,3 @@ + + + diff --git a/sources/view/tpl/xrd_host.tpl b/sources/view/tpl/xrd_host.tpl new file mode 100755 index 00000000..57f38378 --- /dev/null +++ b/sources/view/tpl/xrd_host.tpl @@ -0,0 +1,11 @@ + + + + {{$zhost}} + + + + + diff --git a/sources/view/tpl/xrd_person.tpl b/sources/view/tpl/xrd_person.tpl new file mode 100755 index 00000000..631ed3f1 --- /dev/null +++ b/sources/view/tpl/xrd_person.tpl @@ -0,0 +1,26 @@ + + + + {{$accturi}} + + + + + + + + + + {{$dspr}} + +